--- loncom/interface/domainprefs.pm	2011/10/03 02:26:22	1.138.2.10
+++ loncom/interface/domainprefs.pm	2012/08/14 15:45:06	1.163
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.138.2.10 2011/10/03 02:26:22 raeburn Exp $
+# $Id: domainprefs.pm,v 1.163 2012/08/14 15:45:06 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -86,8 +86,8 @@ $dom,$settings,$rowtotal,$action.
 
 $dom is the domain, $settings is a reference to a hash of current settings for
 the current context, $rowtotal is a reference to the scalar used to record the 
-number of rows displayed on the page, and $action is the context (either quotas 
-or requestcourses).
+number of rows displayed on the page, and $action is the context (quotas,  
+requestcourses or requestauthor).
 
 The print_quotas routine was orginally created to display/store information
 about default quota sizes for portfolio spaces for the different types of 
@@ -204,18 +204,24 @@ sub handler {
     if ( exists($env{'form.phase'}) ) {
         $phase = $env{'form.phase'};
     }
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %domconfig =
       &Apache::lonnet::get_dom('configuration',['login','rolecolors',
                 'quotas','autoenroll','autoupdate','autocreate',
                 'directorysrch','usercreation','usermodification',
                 'contacts','defaults','scantron','coursecategories',
-                'serverstatuses','requestcourses','coursedefaults',
-                'usersessions'],$dom);
+                'serverstatuses','requestcourses','helpsettings',
+                'coursedefaults','usersessions','loadbalancing',
+                'requestauthor'],$dom);
     my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll',
                        'autoupdate','autocreate','directorysrch','contacts',
                        'usercreation','usermodification','scantron',
-                       'requestcourses','coursecategories','serverstatuses',
+                       'requestcourses','requestauthor','coursecategories',
+                       'serverstatuses','helpsettings',
                        'coursedefaults','usersessions');
+    if (keys(%servers) > 1) {
+        push(@prefs_order,'loadbalancing');
+    }
     my %prefs = (
         'rolecolors' =>
                    { text => 'Default color schemes',
@@ -243,7 +249,7 @@ sub handler {
                                   col2 => 'Value'}],
                     },
         'quotas' => 
-                    { text => 'User blogs, personal information pages, portfolios',
+                    { text => 'Blogs, personal web pages, webDAV, portfolios',
                       help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',
@@ -319,6 +325,14 @@ sub handler {
                              {col1 => 'Setting',
                               col2 => 'Value'}],
                  },
+        'requestauthor' =>
+                 {text => 'Request authoring space',
+                  help => 'Domain_Configuration_Request_Author',
+                  header => [{col1 => 'User affiliation',
+                              col2 => 'Availability/Processing of requests',},
+                             {col1 => 'Setting',
+                              col2 => 'Value'}],
+                 },
         'coursecategories' =>
                   { text => 'Cataloging of courses/communities',
                     help => 'Domain_Configuration_Cataloging_Courses',
@@ -344,11 +358,13 @@ sub handler {
                              {col1 => 'Unauthenticated Help Settings',
                               col2 => ''}],
                  },
-        'coursedefaults' =>
+        'coursedefaults' => 
                  {text => 'Course/Community defaults',
                   help => 'Domain_Configuration_Course_Defaults',
-                  header => [{col1 => 'Defaults which can be overridden for each course by a DC',
-                              col2 => 'Value',}],
+                  header => [{col1 => 'Defaults which can be overridden in each course by a CC',
+                              col2 => 'Value',},
+                             {col1 => 'Defaults which can be overridden for each course by a DC',
+                              col2 => 'Value',},],
                  },
         'privacy' => 
                  {text   => 'User Privacy',
@@ -356,16 +372,26 @@ sub handler {
                   header => [{col1 => 'Setting',
                               col2 => 'Value',}],
                  },
-         'usersessions' =>
-                 {text  => 'User session hosting',
+        'usersessions' =>
+                 {text  => 'User session hosting/offloading',
                   help  => 'Domain_Configuration_User_Sessions',
-                  header => [{col1 => 'Hosting of users from other domains',
+                  header => [{col1 => 'Domain server',
+                              col2 => 'Servers to offload sessions to when busy'},
+                             {col1 => 'Hosting of users from other domains',
                               col2 => 'Rules'},
                              {col1 => "Hosting domain's own users elsewhere",
                               col2 => 'Rules'}],
                  },
+         'loadbalancing' =>
+                 {text  => 'Dedicated Load Balancer',
+                  help  => 'Domain_Configuration_Load_Balancing',
+                  header => [{col1 => 'Server',
+                              col2 => 'Default destinations',
+                              col3 => 'User affliation',
+                              col4 => 'Overrides'},
+                            ],
+                 },
     );
-    my %servers = &dom_servers($dom);
     if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',
                              help   => 'Domain_Configuration_Login_Page',
@@ -384,7 +410,16 @@ sub handler {
     if ($phase eq 'process') {
         &Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,\@roles);
     } elsif ($phase eq 'display') {
-        &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname);
+        my $js;
+        if (keys(%servers) > 1) {
+            my ($othertitle,$usertypes,$types) =
+                &Apache::loncommon::sorted_inst_types($dom);
+            $js = &lonbalance_targets_js($dom,$types,\%servers).
+                  &new_spares_js().
+                  &common_domprefs_js().
+                  &Apache::loncommon::javascript_array_indexof();
+        }
+        &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js);
     } else {
         if (keys(%domconfig) == 0) {
             my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
@@ -462,10 +497,16 @@ sub process_changes {
         $output = &modify_serverstatuses($dom,%domconfig);
     } elsif ($action eq 'requestcourses') {
         $output = &modify_quotas($dom,$action,%domconfig);
+    } elsif ($action eq 'requestauthor') {
+        $output = &modify_quotas($dom,$action,%domconfig);
+    } elsif ($action eq 'helpsettings') {
+        $output = &modify_helpsettings($r,$dom,$confname,%domconfig);
     } elsif ($action eq 'coursedefaults') {
         $output = &modify_coursedefaults($dom,%domconfig);
     } elsif ($action eq 'usersessions') {
         $output = &modify_usersessions($dom,%domconfig);
+    } elsif ($action eq 'loadbalancing') {
+        $output = &modify_loadbalancing($dom,%domconfig);
     }
     return $output;
 }
@@ -491,16 +532,20 @@ sub print_config_box {
     }
     if ($numheaders > 1) {
         my $colspan = '';
+        my $rightcolspan = '';
         if (($action eq 'rolecolors') || ($action eq 'coursecategories') || ($action eq 'helpsettings')) {
             $colspan = ' colspan="2"';
         }
+        if ($action eq 'usersessions') {
+            $rightcolspan = ' colspan="3"'; 
+        }
         $output .= '
           <tr>
            <td>
             <table class="LC_nested">
              <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[0]->{'col1'}).'</td>
-              <td class="LC_right_item">'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
+              <td class="LC_right_item"'.$rightcolspan.'>'.&mt($item->{'header'}->[0]->{'col2'}).'</td>
              </tr>';
         $rowtotal ++;
         if ($action eq 'autoupdate') {
@@ -516,12 +561,16 @@ sub print_config_box {
             $colspan = ' colspan="2"';
         } elsif ($action eq 'requestcourses') {
             $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
+        } elsif ($action eq 'requestauthor') {
+            $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
         } elsif ($action eq 'helpsettings') {
             $output .= &print_helpsettings('top',$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'usersessions') {
-            $output .= &print_usersessions('top',$dom,$settings,\$rowtotal);
+            $output .= &print_usersessions('top',$dom,$settings,\$rowtotal); 
         } elsif ($action eq 'rolecolors') {
             $output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal);
+        } elsif ($action eq 'coursedefaults') {
+            $output .= &print_coursedefaults('top',$dom,$settings,\$rowtotal);
         }
         $output .= '
            </table>
@@ -580,11 +629,26 @@ sub print_config_box {
         } elsif ($action eq 'login') {
             $output .= &print_login('bottom',$dom,$confname,$phase,$settings,\$rowtotal);
         } elsif ($action eq 'requestcourses') {
-            $output .= &print_courserequestmail($dom,$settings,\$rowtotal);
+            $output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
+        } elsif ($action eq 'requestauthor') {
+            $output .= &print_requestmail($dom,$action,$settings,\$rowtotal);
         } elsif ($action eq 'helpsettings') {
             $output .= &print_helpsettings('bottom',$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'usersessions') {
-            $output .= &print_usersessions('bottom',$dom,$settings,\$rowtotal);
+            $output .= &print_usersessions('middle',$dom,$settings,\$rowtotal).'
+           </table>
+          </td>
+         </tr>
+         <tr>
+           <td>
+            <table class="LC_nested">
+             <tr class="LC_info_row">
+              <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
+              <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>      </tr>'.
+                       &print_usersessions('bottom',$dom,$settings,\$rowtotal);
+            $rowtotal ++;
+        } elsif ($action eq 'coursedefaults') {
+            $output .= &print_coursedefaults('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'rolecolors') {
             $output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).'
            </table>
@@ -643,13 +707,22 @@ sub print_config_box {
         }
         $output .= '</td>';
         if ($item->{'header'}->[0]->{'col3'}) {
-            $output .= '<td class="LC_right_item" valign="top">'.
-                       &mt($item->{'header'}->[0]->{'col3'});
+            if (defined($item->{'header'}->[0]->{'col4'})) {
+                $output .= '<td class="LC_left_item" valign="top">'.
+                            &mt($item->{'header'}->[0]->{'col3'});
+            } else {
+                $output .= '<td class="LC_right_item" valign="top">'.
+                           &mt($item->{'header'}->[0]->{'col3'});
+            }
             if ($action eq 'serverstatuses') {
                 $output .= '<br />(<tt>'.&mt('IP1,IP2 etc.').'</tt>)';
             }
             $output .= '</td>';
         }
+        if ($item->{'header'}->[0]->{'col4'}) {
+            $output .= '<td class="LC_right_item" valign="top">'.
+                       &mt($item->{'header'}->[0]->{'col4'});
+        }
         $output .= '</tr>';
         $rowtotal ++;
         if ($action eq 'login') {
@@ -671,8 +744,10 @@ sub print_config_box {
             $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal);
         } elsif ($action eq 'serverstatuses') {
             $output .= &print_serverstatuses($dom,$settings,\$rowtotal);
-        } elsif ($action eq 'coursedefaults') {
-            $output .= &print_coursedefaults('bottom',$dom,$settings,\$rowtotal);
+        } elsif ($action eq 'helpsettings') {
+            $output .= &print_helpsettings('top',$dom,$confname,$settings,\$rowtotal);
+        } elsif ($action eq 'loadbalancing') {
+            $output .= &print_loadbalancing($dom,$settings,\$rowtotal);
         }
     }
     $output .= '
@@ -689,7 +764,7 @@ sub print_login {
     my %choices = &login_choices();
 
     if ($position eq 'top') {
-        my %servers = &dom_servers($dom);
+        my %servers = &Apache::lonnet::internet_dom_servers($dom);
         my $choice = $choices{'disallowlogin'};
         $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
@@ -999,6 +1074,7 @@ sub print_rolecolors {
 sub display_color_options {
     my ($dom,$confname,$phase,$role,$itemcount,$choices,$is_custom,$defaults,$designs,
         $images,$bgs,$links,$alt_text,$rowtotal,$logintext) = @_;
+    my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
     my $css_class = $itemcount%2?' class="LC_odd_row"':'';
     my $datatable = '<tr'.$css_class.'>'.
         '<td>'.$choices->{'font'}.'</td>';
@@ -1076,11 +1152,11 @@ sub display_color_options {
                 $showfile = $imgfile;
                 my $imgdir = $1;
                 my $filename = $2;
-                if (-e "/home/httpd/html/$imgdir/tn-".$filename) {
+                if (-e "$londocroot/$imgdir/tn-".$filename) {
                     $showfile = "/$imgdir/tn-".$filename;
                 } else {
-                    my $input = "/home/httpd/html".$imgfile;
-                    my $output = '/home/httpd/html/'.$imgdir.'/tn-'.$filename;
+                    my $input = $londocroot.$imgfile;
+                    my $output = "$londocroot/$imgdir/tn-".$filename;
                     if (!-e $output) {
                         my ($width,$height) = &thumb_dimensions();
                         my ($fullwidth,$fullheight) = &check_dimensions($input);
@@ -1088,7 +1164,7 @@ sub display_color_options {
                             if ($fullwidth > $width && $fullheight > $height) { 
                                 my $size = $width.'x'.$height;
                                 system("convert -sample $size $input $output");
-                                $showfile = '/'.$imgdir.'/tn-'.$filename;
+                                $showfile = "/$imgdir/tn-".$filename;
                             }
                         }
                     }
@@ -1316,14 +1392,19 @@ sub print_quotas {
         @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();
+    } elsif ($context eq 'requestauthor') {
+        @usertools = ('author');
+        @options = ('norequest','approval','automatic');
+        %titles = &authorrequest_titles(); 
     } else {
-        @usertools = ('aboutme','blog','portfolio');
+        @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();
     }
     if (ref($types) eq 'ARRAY') {
         foreach my $type (@{$types}) {
             my $currdefquota;
-            unless ($context eq 'requestcourses') {
+            unless (($context eq 'requestcourses') ||
+                    ($context eq 'requestauthor')) {
                 if (ref($settings) eq 'HASH') {
                     if (ref($settings->{defaultquota}) eq 'HASH') {
                         $currdefquota = $settings->{defaultquota}->{$type}; 
@@ -1393,6 +1474,28 @@ sub print_quotas {
                                 $cell{$item} .= $titles{'unlimited'};
                             }
                         }
+                    } elsif ($context eq 'requestauthor') {
+                        my $curroption;
+                        if (ref($settings) eq 'HASH') {
+                            $curroption = $settings->{$type};
+                        }
+                        if (!$curroption) {
+                            $curroption = 'norequest';
+                        }
+                        foreach my $option (@options) {
+                            my $val = $option;
+                            if ($option eq 'norequest') {
+                                $val = 0;
+                            }
+                            my $checked = '';
+                            if ($option eq $curroption) {
+                                $checked = ' checked="checked"';
+                            }
+                            $datatable .= '<span class="LC_nobreak"><label>'.
+                                  '<input type="radio" name="authorreq_'.$type.
+                                  '" value="'.$val.'"'.$checked.' />'.
+                                  $titles{$option}.'</label></span>&nbsp; ';
+                        }
                     } else {
                         my $checked = 'checked="checked" ';
                         if (ref($settings) eq 'HASH') {
@@ -1418,7 +1521,8 @@ sub print_quotas {
                     $datatable .= '</tr></table>';
                 }
                 $datatable .= '</td>';
-                unless ($context eq 'requestcourses') {
+                unless (($context eq 'requestcourses') ||
+                        ($context eq 'requestauthor')) {
                     $datatable .= 
                               '<td class="LC_right_item"><span class="LC_nobreak">'.
                               '<input type="text" name="quota_'.$type.
@@ -1429,7 +1533,7 @@ sub print_quotas {
             }
         }
     }
-    unless ($context eq 'requestcourses') {
+    unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $defaultquota = '20';
         if (ref($settings) eq 'HASH') {
             if (ref($settings->{'defaultquota'}) eq 'HASH') {
@@ -1499,6 +1603,30 @@ sub print_quotas {
                     $defcell{$item} .= $titles{'unlimited'};
                 }
             }
+        } elsif ($context eq 'requestauthor') {
+            my $curroption;
+            if (ref($settings) eq 'HASH') {
+                if (ref($settings->{'requestauthor'}) eq 'HASH') {
+                    $curroption = $settings->{'requestauthor'};
+                }
+            }
+            if (!$curroption) {
+                $curroption = 'norequest';
+            }
+            foreach my $option (@options) {
+                my $val = $option;
+                if ($option eq 'norequest') {
+                    $val = 0;
+                }
+                my $checked = '';
+                if ($option eq $curroption) {
+                    $checked = ' checked="checked"';
+                }
+                $datatable .= '<span class="LC_nobreak"><label>'.
+                              '<input type="radio" name="authorreq_default"'.
+                              ' value="'.$val.'"'.$checked.' />'.
+                              $titles{$option}.'</label></span>&nbsp; ';
+            }
         } else {
             my $checked = 'checked="checked" ';
             if (ref($settings) eq 'HASH') {
@@ -1524,7 +1652,7 @@ sub print_quotas {
         $datatable .= '</tr></table>';
     }
     $datatable .= '</td>';
-    unless ($context eq 'requestcourses') {
+    unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $datatable .= '<td class="LC_right_item"><span class="LC_nobreak">'.
                       '<input type="text" name="defaultquota" value="'.
                       $defaultquota.'" size="5" /> Mb</span></td>';
@@ -1602,6 +1730,33 @@ sub print_quotas {
                     $advcell{$item} .= $titles{'unlimited'};
                 }
             }
+        } elsif ($context eq 'requestauthor') {
+            my $curroption;
+            if (ref($settings) eq 'HASH') {
+                $curroption = $settings->{'_LC_adv'};
+            }
+            my $checked = '';
+            if ($curroption eq '') {
+                $checked = ' checked="checked"';
+            }
+            $datatable .= '<span class="LC_nobreak"><label>'.
+                          '<input type="radio" name="authorreq__LC_adv"'.
+                          ' value=""'.$checked.' />'.
+                          &mt('No override set').'</label></span>&nbsp; ';
+            foreach my $option (@options) {
+                my $val = $option;
+                if ($option eq 'norequest') {
+                    $val = 0;
+                }
+                my $checked = '';
+                if ($val eq $curroption) {
+                    $checked = ' checked="checked"';
+                }
+                $datatable .= '<span class="LC_nobreak"><label>'.
+                              '<input type="radio" name="crsreq_'.$item.
+                              '__LC_adv" value="'.$val.'"'.$checked.' />'.
+                              $titles{$option}.'</label></span>&nbsp; ';
+            }
         } else {
             my $checked = 'checked="checked" ';
             if (ref($settings) eq 'HASH') {
@@ -1631,8 +1786,8 @@ sub print_quotas {
     return $datatable;
 }
 
-sub print_courserequestmail {
-    my ($dom,$settings,$rowtotal) = @_;
+sub print_requestmail {
+    my ($dom,$action,$settings,$rowtotal) = @_;
     my ($now,$datatable,%dompersonnel,@domcoord,@currapproval,$rows);
     $now = time;
     $rows = 0;
@@ -1663,9 +1818,14 @@ sub print_courserequestmail {
     my $numinrow = 4;
     my $numdc = @domcoord;
     my $css_class = 'class="LC_odd_row"';
-    $datatable = '<tr'.$css_class.'>'.
-                 ' <td>'.&mt('Receive notification of course requests requiring approval.').
-                 ' </td>'.
+    my $text;
+    if ($action eq 'requestcourses') {
+        $text = &mt('Receive notification of course requests requiring approval');
+    } else {
+        $text = &mt('Receive notification of authoring space requests requiring approval')
+    }
+    $datatable = '<tr '.$css_class.'>'.
+                 ' <td>'.$text.'</td>'.
                  ' <td class="LC_left_item">';
     if (@domcoord > 0) {
         $datatable .= '<table>';
@@ -1896,7 +2056,7 @@ sub print_autocreate {
     my ($numdc,$dctable) = &active_dc_picker($dom,$curr_dc);
     if ($numdc > 1) {
         $datatable .= '</td></tr><tr class="LC_odd_row"><td>'.
-                      &mt('Course creation processed as: (choose Dom. Coord.)'). 
+                      &mt('Course creation processed as: (choose Dom. Coord.)').
                       '</td><td class="LC_left_item">'.$dctable.'</td></tr>';
         $$rowtotal ++ ;
     } else {
@@ -2286,118 +2446,132 @@ sub print_usersessions {
     my ($css_class,$datatable,%checked,%choices);
     my (%by_ip,%by_location,@intdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);
-    if (keys(%by_location) == 0) {
-        if ($position eq 'top') {
-            $datatable .= '<tr'.$css_class.'><td colspan="2">'.
-                          &mt('Nothing to set here, as the cluster to which this domain belongs only contains this institution.');
-        }
-    }
-    my %lt = &usersession_titles();
+
+    my @alldoms = &Apache::lonnet::all_domains();
+    my %serverhomes = %Apache::lonnet::serverhomeIDs;
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my %altids = &id_for_thisdom(%servers);
     my $itemcount = 1;
-    my $numinrow = 5;
-    my $prefix;
-    my @types;
     if ($position eq 'top') {
-        $prefix = 'hosted';
-        @types = ('excludedomain','includedomain');
+        if (keys(%serverhomes) > 1) {
+            my %spareid = &current_offloads_to($dom,$settings,\%servers);
+            $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$rowtotal);
+        } else {
+            $datatable .= '<tr'.$css_class.'><td colspan="2">'.
+                          &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.');
+        }
     } else {
-        $prefix = 'remote';
-        @types = ('version','excludedomain','includedomain');
-    }
-    my (%current,%checkedon,%checkedoff);
-    my @lcversions = &Apache::lonnet::all_loncaparevs();
-    my @locations = sort(keys(%by_location));
-    foreach my $type (@types) {
-        $checkedon{$type} = '';
-        $checkedoff{$type} = ' checked="checked"';
-    }
-    if (ref($settings) eq 'HASH') {
-        if (ref($settings->{$prefix}) eq 'HASH') {
-            foreach my $key (keys(%{$settings->{$prefix}})) {
-                $current{$key} = $settings->{$prefix}{$key};
-                if ($key eq 'version') {
-                    if ($current{$key} ne '') {
-                        $checkedon{$key} = ' checked="checked"';
-                        $checkedoff{$key} = '';
-                    }
-                } elsif (ref($current{$key}) eq 'ARRAY') {
-                    $checkedon{$key} = ' checked="checked"';
-                    $checkedoff{$key} = '';
-                }
+        if (keys(%by_location) == 0) {
+            $datatable .= '<tr'.$css_class.'><td colspan="2">'.
+                          &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.');
+        } else {
+            my %lt = &usersession_titles();
+            my $numinrow = 5;
+            my $prefix;
+            my @types;
+            if ($position eq 'bottom') {
+                $prefix = 'remote';
+                @types = ('version','excludedomain','includedomain');
+            } else {
+                $prefix = 'hosted';
+                @types = ('excludedomain','includedomain');
             }
-        }
-    }
-    foreach my $type (@types) {
-        next if ($type ne 'version' && !@locations);
-        $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
-        $datatable .= '<tr'.$css_class.'>
-                       <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />
-                           <span class="LC_nobreak">&nbsp;
-                           <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
-                           <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
-        if ($type eq 'version') {
-            my $selector = '<select name="'.$prefix.'_version">';
-            foreach my $version (@lcversions) {
-                my $selected = '';
-                if ($current{'version'} eq $version) {
-                    $selected = ' selected="selected"';
+            my (%current,%checkedon,%checkedoff);
+            my @lcversions = &Apache::lonnet::all_loncaparevs();
+            my @locations = sort(keys(%by_location));
+            foreach my $type (@types) {
+                $checkedon{$type} = '';
+                $checkedoff{$type} = ' checked="checked"';
+            }
+            if (ref($settings) eq 'HASH') {
+                if (ref($settings->{$prefix}) eq 'HASH') {
+                    foreach my $key (keys(%{$settings->{$prefix}})) {
+                        $current{$key} = $settings->{$prefix}{$key};
+                        if ($key eq 'version') {
+                            if ($current{$key} ne '') {
+                                $checkedon{$key} = ' checked="checked"';
+                                $checkedoff{$key} = '';
+                            }
+                        } elsif (ref($current{$key}) eq 'ARRAY') {
+                            $checkedon{$key} = ' checked="checked"';
+                            $checkedoff{$key} = '';
+                        }
+                    }
                 }
-                $selector .= ' <option value="'.$version.'"'.
-                             $selected.'>'.$version.'</option>';
             }
-            $selector .= '</select> ';
-            $datatable .= &mt('remote server must be version: [_1] or later',$selector);
-        } else {
-            $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
-                         'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
-                         ' />'.('&nbsp;'x2).
-                         '<input type="button" value="'.&mt('uncheck all').'" '.
-                         'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
-                         "\n".
-                         '</div><div><table>';
-            my $rem;
-            for (my $i=0; $i<@locations; $i++) {
-                my ($showloc,$value,$checkedtype);
-                if (ref($by_location{$locations[$i]}) eq 'ARRAY') {
-                    my $ip = $by_location{$locations[$i]}->[0];
-                    if (ref($by_ip{$ip}) eq 'ARRAY') {
-                        $value = join(':',@{$by_ip{$ip}});
-                        $showloc = join(', ',@{$by_ip{$ip}});
-                        if (ref($current{$type}) eq 'ARRAY') {
-                            foreach my $loc (@{$by_ip{$ip}}) {  
-                                if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
-                                    $checkedtype = ' checked="checked"';
-                                    last;
+            foreach my $type (@types) {
+                next if ($type ne 'version' && !@locations);
+                $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+                $datatable .= '<tr'.$css_class.'>
+                               <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />
+                               <span class="LC_nobreak">&nbsp;
+                               <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
+                               <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
+                if ($type eq 'version') {
+                    my $selector = '<select name="'.$prefix.'_version">';
+                    foreach my $version (@lcversions) {
+                        my $selected = '';
+                        if ($current{'version'} eq $version) {
+                            $selected = ' selected="selected"';
+                        }
+                        $selector .= ' <option value="'.$version.'"'.
+                                     $selected.'>'.$version.'</option>';
+                    }
+                    $selector .= '</select> ';
+                    $datatable .= &mt('remote server must be version: [_1] or later',$selector);
+                } else {
+                    $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
+                                 'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
+                                 ' />'.('&nbsp;'x2).
+                                 '<input type="button" value="'.&mt('uncheck all').'" '.
+                                 'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
+                                 "\n".
+                                 '</div><div><table>';
+                    my $rem;
+                    for (my $i=0; $i<@locations; $i++) {
+                        my ($showloc,$value,$checkedtype);
+                        if (ref($by_location{$locations[$i]}) eq 'ARRAY') {
+                            my $ip = $by_location{$locations[$i]}->[0];
+                            if (ref($by_ip{$ip}) eq 'ARRAY') {
+                                 $value = join(':',@{$by_ip{$ip}});
+                                $showloc = join(', ',@{$by_ip{$ip}});
+                                if (ref($current{$type}) eq 'ARRAY') {
+                                    foreach my $loc (@{$by_ip{$ip}}) {  
+                                        if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
+                                            $checkedtype = ' checked="checked"';
+                                            last;
+                                        }
+                                    }
                                 }
                             }
                         }
+                        $rem = $i%($numinrow);
+                        if ($rem == 0) {
+                            if ($i > 0) {
+                                $datatable .= '</tr>';
+                            }
+                            $datatable .= '<tr>';
+                        }
+                        $datatable .= '<td class="LC_left_item">'.
+                                      '<span class="LC_nobreak"><label>'.
+                                      '<input type="checkbox" name="'.$prefix.'_'.$type.
+                                      '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
+                                      '</label></span></td>';
                     }
-                }
-                $rem = $i%($numinrow);
-                if ($rem == 0) {
-                    if ($i > 0) {
-                        $datatable .= '</tr>';
+                    $rem = @locations%($numinrow);
+                    my $colsleft = $numinrow - $rem;
+                    if ($colsleft > 1 ) {
+                        $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
+                                      '&nbsp;</td>';
+                    } elsif ($colsleft == 1) {
+                        $datatable .= '<td class="LC_left_item">&nbsp;</td>';
                     }
-                    $datatable .= '<tr>';
+                    $datatable .= '</tr></table>';
                 }
-                $datatable .= '<td class="LC_left_item">'.
-                              '<span class="LC_nobreak"><label>'.
-                              '<input type="checkbox" name="'.$prefix.'_'.$type.
-                              '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
-                              '</label></span></td>';
+                $datatable .= '</td></tr>';
+                $itemcount ++;
             }
-            $rem = @locations%($numinrow);
-            my $colsleft = $numinrow - $rem;
-            if ($colsleft > 1 ) {
-                $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
-                              '&nbsp;</td>';
-            } elsif ($colsleft == 1) {
-                $datatable .= '<td class="LC_left_item">&nbsp;</td>';
-            }
-            $datatable .= '</tr></table>';
         }
-        $datatable .= '</td></tr>';
-        $itemcount ++;
     }
     $$rowtotal += $itemcount;
     return $datatable;
@@ -2451,6 +2625,465 @@ sub build_location_hashes {
     return;
 }
 
+sub current_offloads_to {
+    my ($dom,$settings,$servers) = @_;
+    my (%spareid,%otherdomconfigs);
+    if (ref($servers) eq 'HASH') {
+        foreach my $lonhost (sort(keys(%{$servers}))) {
+            my $gotspares;
+            if (ref($settings) eq 'HASH') {
+                if (ref($settings->{'spares'}) eq 'HASH') {
+                    if (ref($settings->{'spares'}{$lonhost}) eq 'HASH') {
+                        $spareid{$lonhost}{'primary'} = $settings->{'spares'}{$lonhost}{'primary'};
+                        $spareid{$lonhost}{'default'} = $settings->{'spares'}{$lonhost}{'default'};
+                        $gotspares = 1;
+                    }
+                }
+            }
+            unless ($gotspares) {
+                my $gotspares;
+                my $serverhomeID =
+                    &Apache::lonnet::get_server_homeID($servers->{$lonhost});
+                my $serverhomedom =
+                    &Apache::lonnet::host_domain($serverhomeID);
+                if ($serverhomedom ne $dom) {
+                    if (ref($otherdomconfigs{$serverhomedom} eq 'HASH')) {
+                        if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') {
+                            if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') {
+                                $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'};
+                                $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'};
+                                $gotspares = 1;
+                            }
+                        }
+                    } else {
+                        $otherdomconfigs{$serverhomedom} =
+                            &Apache::lonnet::get_dom('configuration',['usersessions'],$serverhomedom);
+                        if (ref($otherdomconfigs{$serverhomedom}) eq 'HASH') {
+                            if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') {
+                                if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') {
+                                    if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{$lonhost}) eq 'HASH') {
+                                        $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'};
+                                        $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'};
+                                        $gotspares = 1;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            unless ($gotspares) {
+                if ($lonhost eq $Apache::lonnet::perlvar{'lonHostID'}) {
+                    $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'};
+                    $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'};
+               } else {
+                    my $server_hostname = &Apache::lonnet::hostname($lonhost);
+                    my $server_homeID = &Apache::lonnet::get_server_homeID($server_hostname);
+                    if ($server_homeID eq $Apache::lonnet::perlvar{'lonHostID'}) {
+                        $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'};
+                        $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'};
+                    } else {
+                        my %what = (
+                             spareid => 1,
+                        );
+                        my ($result,$returnhash) = 
+                            &Apache::lonnet::get_remote_globals($lonhost,\%what);
+                        if ($result eq 'ok') { 
+                            if (ref($returnhash) eq 'HASH') {
+                                if (ref($returnhash->{'spareid'}) eq 'HASH') {
+                                    $spareid{$lonhost}{'primary'} = $returnhash->{'spareid'}->{'primary'};
+                                    $spareid{$lonhost}{'default'} = $returnhash->{'spareid'}->{'default'};
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return %spareid;
+}
+
+sub spares_row {
+    my ($dom,$servers,$spareid,$serverhomes,$altids,$rowtotal) = @_;
+    my $css_class;
+    my $numinrow = 4;
+    my $itemcount = 1;
+    my $datatable;
+    my %typetitles = &sparestype_titles();
+    if ((ref($servers) eq 'HASH') && (ref($spareid) eq 'HASH') && (ref($altids) eq 'HASH')) {
+        foreach my $server (sort(keys(%{$servers}))) {
+            my $serverhome = &Apache::lonnet::get_server_homeID($servers->{$server});
+            my ($othercontrol,$serverdom);
+            if ($serverhome ne $server) {
+                $serverdom = &Apache::lonnet::host_domain($serverhome);
+                $othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>');
+            } else {
+                $serverdom = &Apache::lonnet::host_domain($server);
+                if ($serverdom ne $dom) {
+                    $othercontrol = &mt('Session offloading controlled by domain: [_1]','<b>'.$serverdom.'</b>');
+                }
+            }
+            next unless (ref($spareid->{$server}) eq 'HASH');
+            $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
+            $datatable .= '<tr'.$css_class.'>
+                           <td rowspan="2">
+                            <span class="LC_nobreak"><b>'.$server.'</b> when busy, offloads to:</span></td>'."\n";
+            my (%current,%canselect);
+            my @choices = 
+                &possible_newspares($server,$spareid->{$server},$serverhomes,$altids);
+            foreach my $type ('primary','default') {
+                if (ref($spareid->{$server}) eq 'HASH') {
+                    if (ref($spareid->{$server}{$type}) eq 'ARRAY') {
+                        my @spares = @{$spareid->{$server}{$type}};
+                        if (@spares > 0) {
+                            if ($othercontrol) {
+                                $current{$type} = join(', ',@spares);
+                            } else {
+                                $current{$type} .= '<table>';
+                                my $numspares = scalar(@spares);
+                                for (my $i=0;  $i<@spares; $i++) {
+                                    my $rem = $i%($numinrow);
+                                    if ($rem == 0) {
+                                        if ($i > 0) {
+                                            $current{$type} .= '</tr>';
+                                        }
+                                        $current{$type} .= '<tr>';
+                                    }
+                                    $current{$type} .= '<td><label><input type="checkbox" name="spare_'.$type.'_'.$server.'" id="spare_'.$type.'_'.$server.'_'.$i.'" checked="checked" value="'.$spareid->{$server}{$type}[$i].'" onclick="updateNewSpares(this.form,'."'$server'".');" />&nbsp;'.
+                                                       $spareid->{$server}{$type}[$i].
+                                                       '</label></td>'."\n";
+                                }
+                                my $rem = @spares%($numinrow);
+                                my $colsleft = $numinrow - $rem;
+                                if ($colsleft > 1 ) {
+                                    $current{$type} .= '<td colspan="'.$colsleft.
+                                                       '" class="LC_left_item">'.
+                                                       '&nbsp;</td>';
+                                } elsif ($colsleft == 1) {
+                                    $current{$type} .= '<td class="LC_left_item">&nbsp;</td>'."\n";
+                                }
+                                $current{$type} .= '</tr></table>';
+                            }
+                        }
+                    }
+                    if ($current{$type} eq '') {
+                        $current{$type} = &mt('None specified');
+                    }
+                    if ($othercontrol) {
+                        if ($type eq 'primary') {
+                            $canselect{$type} = $othercontrol;
+                        }
+                    } else {
+                        $canselect{$type} = 
+                            &mt('Add new [_1]'.$type.'[_2]:','<i>','</i>').'&nbsp;'.
+                            '<select name="newspare_'.$type.'_'.$server.'" '.
+                            'id="newspare_'.$type.'_'.$server.'" onchange="checkNewSpares('."'$server','$type'".');">'."\n".
+                            '<option value="" selected ="selected">'.&mt('Select').'</option>'."\n";
+                        if (@choices > 0) {
+                            foreach my $lonhost (@choices) {
+                                $canselect{$type} .= '<option value="'.$lonhost.'">'.$lonhost.'</option>'."\n";
+                            }
+                        }
+                        $canselect{$type} .= '</select>'."\n";
+                    }
+                } else {
+                    $current{$type} = &mt('Could not be determined');
+                    if ($type eq 'primary') {
+                        $canselect{$type} =  $othercontrol;
+                    }
+                }
+                if ($type eq 'default') {
+                    $datatable .= '<tr'.$css_class.'>';
+                }
+                $datatable .= '<td><i>'.$typetitles{$type}.'</i></td>'."\n".
+                              '<td>'.$current{$type}.'</td>'."\n".
+                              '<td>'.$canselect{$type}.'</td></tr>'."\n";
+            }
+            $itemcount ++;
+        }
+    }
+    $$rowtotal += $itemcount;
+    return $datatable;
+}
+
+sub possible_newspares {
+    my ($server,$currspares,$serverhomes,$altids) = @_;
+    my $serverhostname = &Apache::lonnet::hostname($server);
+    my %excluded;
+    if ($serverhostname ne '') {
+        %excluded = (
+                       $serverhostname => 1,
+                    );
+    }
+    if (ref($currspares) eq 'HASH') {
+        foreach my $type (keys(%{$currspares})) {
+            if (ref($currspares->{$type}) eq 'ARRAY') {
+                if (@{$currspares->{$type}} > 0) {
+                    foreach my $curr (@{$currspares->{$type}}) {
+                        my $hostname = &Apache::lonnet::hostname($curr);
+                        $excluded{$hostname} = 1;
+                    }
+                }
+            }
+        }
+    }
+    my @choices;
+    if ((ref($serverhomes) eq 'HASH') && (ref($altids) eq 'HASH')) {
+        if (keys(%{$serverhomes}) > 1) {
+            foreach my $name (sort(keys(%{$serverhomes}))) {
+                unless ($excluded{$name}) {
+                    if (exists($altids->{$serverhomes->{$name}})) {
+                        push(@choices,$altids->{$serverhomes->{$name}});
+                    } else {
+                        push(@choices,$serverhomes->{$name});
+                    }
+                }
+            }
+        }
+    }
+    return sort(@choices);
+}
+
+sub print_loadbalancing {
+    my ($dom,$settings,$rowtotal) = @_;
+    my $primary_id = &Apache::lonnet::domain($dom,'primary');
+    my $intdom = &Apache::lonnet::internet_dom($primary_id);
+    my $numinrow = 1;
+    my $datatable;
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my ($currbalancer,$currtargets,$currrules);
+    if (keys(%servers) > 1) {
+        if (ref($settings) eq 'HASH') {
+            $currbalancer = $settings->{'lonhost'};
+            $currtargets = $settings->{'targets'};
+            $currrules = $settings->{'rules'};
+        } else {
+            ($currbalancer,$currtargets) = 
+                &Apache::lonnet::get_lonbalancer_config(\%servers);
+        }
+    } else {
+        return;
+    }
+    my ($othertitle,$usertypes,$types) =
+        &Apache::loncommon::sorted_inst_types($dom);
+    my $rownum = 6;
+    if (ref($types) eq 'ARRAY') {
+        $rownum += scalar(@{$types});
+    }
+    my $css_class = ' class="LC_odd_row"';
+    my $targets_div_style = 'display: none';
+    my $disabled_div_style = 'display: block';
+    my $homedom_div_style = 'display: none';
+    $datatable = '<tr'.$css_class.'>'.
+                 '<td rowspan="'.$rownum.'" valign="top">'.
+                 '<p><select name="loadbalancing_lonhost" onchange="toggleTargets();">'."\n".
+                 '<option value=""';
+    if (($currbalancer eq '') || (!grep(/^\Q$currbalancer\E$/,keys(%servers)))) {
+        $datatable .= ' selected="selected"';
+    } else {
+        $targets_div_style = 'display: block';
+        $disabled_div_style = 'display: none';
+        if ($dom eq &Apache::lonnet::host_domain($currbalancer)) {
+            $homedom_div_style = 'display: block'; 
+        }
+    }
+    $datatable .= '>'.&mt('None').'</option>'."\n";
+    foreach my $lonhost (sort(keys(%servers))) {
+        my $selected;
+        if ($lonhost eq $currbalancer) {
+            $selected .= ' selected="selected"';
+        }
+        $datatable .= '<option value="'.$lonhost.'"'.$selected.'>'.$lonhost.'</option>'."\n";
+    }
+    $datatable .= '</select></p></td><td rowspan="'.$rownum.'" valign="top">'.
+                  '<div id="loadbalancing_disabled" style="'.$disabled_div_style.'">'.&mt('No dedicated Load Balancer').'</div>'."\n".
+                  '<div id="loadbalancing_targets" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
+    my ($numspares,@spares) = &count_servers($currbalancer,%servers);
+    my @sparestypes = ('primary','default');
+    my %typetitles = &sparestype_titles();
+    foreach my $sparetype (@sparestypes) {
+        my $targettable;
+        for (my $i=0; $i<$numspares; $i++) {
+            my $checked;
+            if (ref($currtargets) eq 'HASH') {
+                if (ref($currtargets->{$sparetype}) eq 'ARRAY') {
+                    if (grep(/^\Q$spares[$i]\E$/,@{$currtargets->{$sparetype}})) {
+                        $checked = ' checked="checked"';
+                    }
+                }
+            }
+            my $chkboxval;
+            if (($currbalancer ne '') && (grep((/^\Q$currbalancer\E$/,keys(%servers))))) {
+                $chkboxval = $spares[$i];
+            }
+            $targettable .= '<td><label><input type="checkbox" name="loadbalancing_target_'.$sparetype.'"'.
+                      $checked.' value="'.$chkboxval.'" id="loadbalancing_target_'.$sparetype.'_'.$i.'" onclick="checkOffloads('."this,'$sparetype'".');" /><span id="loadbalancing_targettxt_'.$sparetype.'_'.$i.'">&nbsp;'.$chkboxval.
+                      '</span></label></td>';
+            my $rem = $i%($numinrow);
+            if ($rem == 0) {
+                if ($i > 0) {
+                    $targettable .= '</tr>';
+                }
+                $targettable .= '<tr>';
+            }
+        }
+        if ($targettable ne '') {
+            my $rem = $numspares%($numinrow);
+            my $colsleft = $numinrow - $rem;
+            if ($colsleft > 1 ) {
+                $targettable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
+                                '&nbsp;</td>';
+            } elsif ($colsleft == 1) {
+                $targettable .= '<td class="LC_left_item">&nbsp;</td>';
+            }
+            $datatable .=  '<i>'.$typetitles{$sparetype}.'</i><br />'.
+                           '<table><tr>'.$targettable.'</table><br />';
+        }
+    }
+    $datatable .= '</div></td></tr>'.
+                  &loadbalancing_rules($dom,$intdom,$currrules,$othertitle,
+                                       $usertypes,$types,\%servers,$currbalancer,
+                                       $targets_div_style,$homedom_div_style,$css_class);
+    $$rowtotal += $rownum;
+    return $datatable;
+}
+
+sub loadbalancing_rules {
+    my ($dom,$intdom,$currrules,$othertitle,$usertypes,$types,$servers,
+        $currbalancer,$targets_div_style,$homedom_div_style,$css_class) = @_;
+    my $output;
+    my ($alltypes,$othertypes,$titles) = 
+        &loadbalancing_titles($dom,$intdom,$usertypes,$types);
+    if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH'))  {
+        foreach my $type (@{$alltypes}) {
+            my $current;
+            if (ref($currrules) eq 'HASH') {
+                $current = $currrules->{$type};
+            }
+            if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) {
+                if ($dom ne &Apache::lonnet::host_domain($currbalancer)) {
+                    $current = '';
+                }
+            }
+            $output .= &loadbalance_rule_row($type,$titles->{$type},$current,
+                                             $servers,$currbalancer,$dom,
+                                             $targets_div_style,$homedom_div_style,$css_class);
+        }
+    }
+    return $output;
+}
+
+sub loadbalancing_titles {
+    my ($dom,$intdom,$usertypes,$types) = @_;
+    my %othertypes = (
+           '_LC_adv'         => &mt('Advanced users from [_1]',$dom),
+           '_LC_author'      => &mt('Users from [_1] with author role',$dom),
+           '_LC_internetdom' => &mt('Users not from [_1], but from [_2]',$dom,$intdom),
+           '_LC_external'    => &mt('Users not from [_1]',$intdom),
+                     );
+    my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external');
+    if (ref($types) eq 'ARRAY') {
+        unshift(@alltypes,@{$types},'default');
+    }
+    my %titles;
+    foreach my $type (@alltypes) {
+        if ($type =~ /^_LC_/) {
+            $titles{$type} = $othertypes{$type};
+        } elsif ($type eq 'default') {
+            $titles{$type} = &mt('All users from [_1]',$dom);
+            if (ref($types) eq 'ARRAY') {
+                if (@{$types} > 0) {
+                    $titles{$type} = &mt('Other users from [_1]',$dom);
+                }
+            }
+        } elsif (ref($usertypes) eq 'HASH') {
+            $titles{$type} = $usertypes->{$type};
+        }
+    }
+    return (\@alltypes,\%othertypes,\%titles);
+}
+
+sub loadbalance_rule_row {
+    my ($type,$title,$current,$servers,$currbalancer,$dom,$targets_div_style,
+        $homedom_div_style,$css_class) = @_;
+    my @rulenames = ('default','homeserver');
+    my %ruletitles = &offloadtype_text();
+    if ($type eq '_LC_external') {
+        push(@rulenames,'externalbalancer');
+    } else {
+        push(@rulenames,'specific');
+    }
+    push(@rulenames,'none');
+    my $style = $targets_div_style;
+    if (($type eq '_LC_external') || ($type eq '_LC_internetdom')) {
+        $style = $homedom_div_style;
+    }
+    my $output = 
+        '<tr'.$css_class.'><td valign="top"><div id="balanceruletitle_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
+        '<td><div id="balancerule_'.$type.'" style="'.$style.'">'."\n";
+    for (my $i=0; $i<@rulenames; $i++) {
+        my $rule = $rulenames[$i];
+        my ($checked,$extra);
+        if ($rulenames[$i] eq 'default') {
+            $rule = '';
+        }
+        if ($rulenames[$i] eq 'specific') {
+            if (ref($servers) eq 'HASH') {
+                my $default;
+                if (($current ne '') && (exists($servers->{$current}))) {
+                    $checked = ' checked="checked"';
+                }
+                unless ($checked) {
+                    $default = ' selected="selected"';
+                }
+                $extra = ':&nbsp;<select name="loadbalancing_singleserver_'.$type.
+                         '" id="loadbalancing_singleserver_'.$type.
+                         '" onchange="singleServerToggle('."'$type'".')">'."\n".
+                         '<option value=""'.$default.'></option>'."\n";
+                foreach my $lonhost (sort(keys(%{$servers}))) {
+                    next if ($lonhost eq $currbalancer);
+                    my $selected;
+                    if ($lonhost eq $current) {
+                        $selected = ' selected="selected"';
+                    }
+                    $extra .= '<option value="'.$lonhost.'"'.$selected.'>'.$lonhost.'</option>';
+                }
+                $extra .= '</select>';
+            }
+        } elsif ($rule eq $current) {
+            $checked = ' checked="checked"';
+        }
+        $output .= '<span class="LC_nobreak"><label>'.
+                   '<input type="radio" name="loadbalancing_rules_'.$type.
+                   '" id="loadbalancing_rules_'.$type.'_'.$i.'" value="'.
+                   $rule.'" onclick="balanceruleChange('."this.form,'$type'".
+                   ')"'.$checked.' />&nbsp;'.$ruletitles{$rulenames[$i]}.
+                   '</label>'.$extra.'</span><br />'."\n";
+    }
+    $output .= '</div></td></tr>'."\n";
+    return $output;
+}
+
+sub offloadtype_text {
+    my %ruletitles = &Apache::lonlocal::texthash (
+           'default'          => 'Offloads to default destinations',
+           'homeserver'       => "Offloads to user's home server",
+           'externalbalancer' => "Offloads to Load Balancer in user's domain",
+           'specific'         => 'Offloads to specific server',
+           'none'             => 'No offload',
+    );
+    return %ruletitles;
+}
+
+sub sparestype_titles {
+    my %typestitles = &Apache::lonlocal::texthash (
+                          'primary' => 'primary',
+                          'default' => 'default',
+                      );
+    return %typestitles;
+}
+
 sub contact_titles {
     my %titles = &Apache::lonlocal::texthash (
                    'supportemail' => 'Support E-mail address',
@@ -2470,8 +3103,9 @@ sub contact_titles {
 
 sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (
-                     aboutme    => 'Personal Information Page',
+                     aboutme    => 'Personal web page',
                      blog       => 'Blog',
+                     webdav     => 'WebDAV',
                      portfolio  => 'Portfolio',
                      official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',
@@ -2494,6 +3128,15 @@ sub courserequest_titles {
     return %titles;
 }
 
+sub authorrequest_titles {
+    my %titles = &Apache::lonlocal::texthash (
+                                   norequest  => 'Not allowed',
+                                   approval   => 'Approval by Dom. Coord.',
+                                   automatic  => 'Automatic approval',
+                 );
+    return %titles;
+} 
+
 sub courserequest_conditions {
     my %conditions = &Apache::lonlocal::texthash (
        approval    => '(Processing of request subject to approval by Domain Coordinator).',
@@ -3336,7 +3979,7 @@ sub print_serverstatuses {
 sub serverstatus_pages {
     return ('userstatus','lonstatus','loncron','server-status','codeversions',
             'clusterstatus','metadata_keywords','metadata_harvest',
-            'takeoffline','takeonline','showenv','toggledebug');
+            'takeoffline','takeonline','showenv','toggledebug','ping','domconf');
 }
 
 sub coursecategories_javascript {
@@ -3809,7 +4452,7 @@ sub modify_login {
                                          \%loginhash);
     }
 
-    my %servers = &dom_servers($dom);
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my @loginvia_attribs = ('serverpath','custompath','exempt');
     if (keys(%servers) > 1) {
         foreach my $lonhost (keys(%servers)) {
@@ -4404,7 +5047,7 @@ sub publishlogo {
 # See if there is anything left
     unless ($fname) { return ('error: no uploaded file'); }
     $fname="$subdir/$fname";
-    my $filepath='/home/'.$confname.'/public_html';
+    my $filepath=$r->dir_config('lonDocRoot')."/priv/$dom/$confname";
     my ($fnamepath,$file,$fetchthumb);
     $file=$fname;
     if ($fname=~m|/|) {
@@ -4484,7 +5127,7 @@ $env{'user.name'}.':'.$env{'user.domain'
                 $output = 'ok';
                 $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname;
                 push(@{$modified_urls},[$copyfile,$source]);
-                my $metaoutput =
+                my $metaoutput = 
                     &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile);
                 unless ($registered_cleanup) {
                     my $handlers = $r->get_handlers('PerlCleanupHandler');
@@ -4508,7 +5151,7 @@ $env{'user.name'}.':'.$env{'user.domain'
                             my $copyfile=$targetdir.'/tn-'.$file;
                             if (copy($outfile,$copyfile)) {
                                 print $logfile "\nCopied source to ".$copyfile."\n";
-                                my $thumb_metaoutput =
+                                my $thumb_metaoutput = 
                                     &write_metadata($dom,$confname,$formname,
                                                     $targetdir,'tn-'.$file,$logfile);
                                 push(@{$modified_urls},[$copyfile,$outfile]);
@@ -4602,7 +5245,6 @@ sub write_metadata {
             $output = 'ok';
             print $logfile "\nWrote metadata";
             close($mfh);
-            }
         } else {
             print $logfile "\nFailed to open metadata file";
             $output = &mt('Could not write metadata');
@@ -4632,7 +5274,7 @@ sub notifysubscribed {
                     print $logfh $reply;
                 }
                 print $logfh "\n============ Done ============\n";
-                close(logfh);
+                close($logfh);
             }
         }
     }
@@ -4678,7 +5320,7 @@ sub modify_quotas {
         %limithash,$toolregexp,%conditions,$resulttext,%changes);
     if ($action eq 'quotas') {
         $context = 'tools'; 
-    } else { 
+    } else {
         $context = $action;
     }
     if ($context eq 'requestcourses') {
@@ -4688,8 +5330,11 @@ sub modify_quotas {
         %titles = &courserequest_titles();
         $toolregexp = join('|',@usertools);
         %conditions = &courserequest_conditions();
+    } elsif ($context eq 'requestauthor') {
+        @usertools = ('author');
+        %titles = &authorrequest_titles();
     } else {
-        @usertools = ('aboutme','blog','portfolio');
+        @usertools = ('aboutme','blog','webdav','portfolio');
         %titles = &tool_titles();
     }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
@@ -4705,6 +5350,10 @@ sub modify_quotas {
                     $confhash{$item}{$type} = $env{$key};
                 }
             }
+        } elsif ($context eq 'requestauthor') {
+            if ($key =~ /^\Qform.authorreq_\E(.+)$/) {
+                $confhash{$1} = $env{$key};
+            }
         } else {
             if ($key =~ /^form\.quota_(.+)$/) {
                 $confhash{'defaultquota'}{$1} = $env{$key};
@@ -4714,7 +5363,7 @@ sub modify_quotas {
             }
         }
     }
-    if ($context eq 'requestcourses') {
+    if (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.reqapprovalnotify');
         @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',',@approvalnotify);
@@ -4750,6 +5399,11 @@ sub modify_quotas {
                         $confhash{$item}{$type} .= $limithash{$item}{$type};
                     }
                 }
+            } elsif ($context eq 'requestauthor') {
+                $unset = '0';
+                if ($type eq '_LC_adv') {
+                    $unset = '';
+                }
             } else {
                 if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) {
                     $confhash{$item}{$type} = 1;
@@ -4758,7 +5412,11 @@ sub modify_quotas {
                 }
             }
             if (ref($domconfig{$action}) eq 'HASH') {
-                if (ref($domconfig{$action}{$item}) eq 'HASH') {
+                if ($action eq 'requestauthor') {
+                    if ($domconfig{$action}{$type} ne $confhash{$type}) {
+                        $changes{$type} = 1;
+                    }
+                } elsif (ref($domconfig{$action}{$item}) eq 'HASH') {
                     if ($domconfig{$action}{$item}{$type} ne $confhash{$item}{$type}) {
                         $changes{$item}{$type} = 1;
                     }
@@ -4778,6 +5436,10 @@ sub modify_quotas {
                     if ($confhash{$item}{$type} ne $unset) {
                         $changes{$item}{$type} = 1;
                     }
+                } elsif ($context eq 'requestauthor') {
+                    if ($confhash{$type} ne $unset) {
+                        $changes{$type} = 1;
+                    }
                 } else {
                     if (!$confhash{$item}{$type}) {
                         $changes{$item}{$type} = 1;
@@ -4786,7 +5448,7 @@ sub modify_quotas {
             }
         }
     }
-    unless ($context eq 'requestcourses') {
+    unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         if (ref($domconfig{'quotas'}) eq 'HASH') {
             if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') {
                 foreach my $key (keys(%{$domconfig{'quotas'}{'defaultquota'}})) {
@@ -4829,10 +5491,14 @@ sub modify_quotas {
         }
     }
 
-    foreach my $key (keys(%confhash)) {
-        $domdefaults{$key} = $confhash{$key};
+    if ($context eq 'requestauthor') {
+        $domdefaults{'requestauthor'} = \%confhash;
+    } else {
+        foreach my $key (keys(%confhash)) {
+            $domdefaults{$key} = $confhash{$key};
+        }
     }
-   
+
     my %quotahash = (
                       $action => { %confhash }
                     );
@@ -4844,7 +5510,8 @@ sub modify_quotas {
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
 
             $resulttext = &mt('Changes made:').'<ul>';
-            unless ($context eq 'requestcourses') {
+            unless (($context eq 'requestcourses') || 
+                    ($context eq 'requestauthor')) {
                 if (ref($changes{'defaultquota'}) eq 'HASH') {
                     $resulttext .= '<li>'.&mt('Portfolio default quotas').'<ul>';
                     foreach my $type (@{$types},'default') {
@@ -4861,12 +5528,25 @@ sub modify_quotas {
             }
             my %newenv;
             foreach my $item (@usertools) {
-                if (ref($changes{$item}) eq 'HASH') {
+                my (%haschgs,%inconf);
+                if ($context eq 'requestauthor') {
+                    %haschgs = %changes;
+                    %inconf = %confhash; 
+                } else {
+                    if (ref($changes{$item}) eq 'HASH') {
+                        %haschgs = %{$changes{$item}};
+                    }
+                    if (ref($confhash{$item}) eq 'HASH') {
+                        %inconf = %{$confhash{$item}};
+                    }
+                }
+                if (keys(%haschgs) > 0) {
                     my $newacc = 
                         &Apache::lonnet::usertools_access($env{'user.name'},
                                                           $env{'user.domain'},
                                                           $item,'reload',$context);
-                    if ($context eq 'requestcourses') {
+                    if (($context eq 'requestcourses') || 
+                        ($context eq 'requestauthor')) {
                         if ($env{'environment.canrequest.'.$item} ne $newacc) {
                             $newenv{'environment.canrequest.'.$item} = $newacc;
                         }
@@ -4875,26 +5555,28 @@ sub modify_quotas {
                             $newenv{'environment.availabletools.'.$item} = $newacc;
                         }
                     }
-                    $resulttext .= '<li>'.$titles{$item}.'<ul>';
+                    unless ($context eq 'requestauthor') {
+                        $resulttext .= '<li>'.$titles{$item}.'<ul>';
+                    }
                     foreach my $type (@{$types},'default','_LC_adv') {
-                        if ($changes{$item}{$type}) {
+                        if ($haschgs{$type}) {
                             my $typetitle = $usertypes->{$type};
                             if ($type eq 'default') {
                                 $typetitle = $othertitle;
                             } elsif ($type eq '_LC_adv') {
                                 $typetitle = 'LON-CAPA Advanced Users'; 
                             }
-                            if ($confhash{$item}{$type}) {
+                            if ($inconf{$type}) {
                                 if ($context eq 'requestcourses') {
                                     my $cond;
-                                    if ($confhash{$item}{$type} =~ /^autolimit=(\d*)$/) {
+                                    if ($inconf{$type} =~ /^autolimit=(\d*)$/) {
                                         if ($1 eq '') {
                                             $cond = &mt('(Automatic processing of any request).');
                                         } else {
                                             $cond = &mt('(Automatic processing of requests up to limit of [quant,_1,request] per user).',$1);
                                         }
                                     } else { 
-                                        $cond = $conditions{$confhash{$item}{$type}};
+                                        $cond = $conditions{$inconf{$type}};
                                     }
                                     $resulttext .= '<li>'.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'</li>';
                                 } else {
@@ -4902,7 +5584,7 @@ sub modify_quotas {
                                 }
                             } else {
                                 if ($type eq '_LC_adv') {
-                                    if ($confhash{$item}{$type} eq '0') {
+                                    if ($inconf{$type} eq '0') {
                                         $resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>';
                                     } else { 
                                         $resulttext .= '<li>'.&mt('No override set for [_1]',$typetitle).'</li>';
@@ -4913,17 +5595,19 @@ sub modify_quotas {
                             }
                         }
                     }
-                    $resulttext .= '</ul></li>';
+                    unless ($context eq 'requestauthor') {
+                        $resulttext .= '</ul></li>';
+                    }
                 }
             }
-            if ($action eq 'requestcourses') {
+            if (($action eq 'requestcourses') || ($action eq 'requestauthor')) {
                 if (ref($changes{'notify'}) eq 'HASH') {
                     if ($changes{'notify'}{'approval'}) {
                         if (ref($confhash{'notify'}) eq 'HASH') {
                             if ($confhash{'notify'}{'approval'}) {
                                 $resulttext .= '<li>'.&mt('Notification of requests requiring approval will be sent to: ').$confhash{'notify'}{'approval'}.'</li>';
                             } else {
-                                $resulttext .= '<li>'.&mt('No Domain Coordinators will receive notification of course requests requiring approval.').'</li>';
+                                $resulttext .= '<li>'.&mt('No Domain Coordinators will receive notification of requests requiring approval.').'</li>';
                             }
                         }
                     }
@@ -4936,6 +5620,8 @@ sub modify_quotas {
         } else {
             if ($context eq 'requestcourses') {
                 $resulttext = &mt('No changes made to rights to request creation of courses.');
+            } elsif ($context eq 'requestauthor') {
+                $resulttext = &mt('No changes made to rights to request author space.');
             } else {
                 $resulttext = &mt('No changes made to availability of personal information pages, blogs, portfolios or default quotas');
             }
@@ -6752,7 +7438,7 @@ sub modify_coursedefaults {
     my ($resulttext,$errors,%changes,%defaultshash);
     my %defaultchecked = ('canuse_pdfforms' => 'off');
     my @offon = ('off','on');
-    my @toggles = ();
+    my @toggles = ('canuse_pdfforms');
 
     $defaultshash{'coursedefaults'} = {};
 
@@ -6829,8 +7515,14 @@ sub modify_coursedefaults {
 
 sub modify_usersessions {
     my ($dom,%domconfig) = @_;
-    my @types = ('version','excludedomain','includedomain');
-    my @prefixes = ('remote','hosted');
+    my @hostingtypes = ('version','excludedomain','includedomain');
+    my @offloadtypes = ('primary','default');
+    my %types = (
+                  remote => \@hostingtypes,
+                  hosted => \@hostingtypes,
+                  spares => \@offloadtypes,
+                );
+    my @prefixes = ('remote','hosted','spares');
     my @lcversions = &Apache::lonnet::all_loncaparevs();
     my (%by_ip,%by_location,@intdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);
@@ -6843,7 +7535,8 @@ sub modify_usersessions {
     my $resulttext;
     my %iphost = &Apache::lonnet::get_iphost();
     foreach my $prefix (@prefixes) {
-        foreach my $type (@types) {
+        next if ($prefix eq 'spares');
+        foreach my $type (@{$types{$prefix}}) {
             my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
             if ($type eq 'version') {
                 my $value = $env{'form.'.$prefix.'_'.$type};
@@ -6935,7 +7628,72 @@ sub modify_usersessions {
             }
         }
     }
-    if (keys(%changes) > 0) {
+
+    my @alldoms = &Apache::lonnet::all_domains();
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my %spareid = &current_offloads_to($dom,$domconfig{'usersessions'},\%servers);
+    my $savespares;
+
+    foreach my $lonhost (sort(keys(%servers))) {
+        my $serverhomeID =
+            &Apache::lonnet::get_server_homeID($servers{$lonhost});
+        my $serverhostname = &Apache::lonnet::hostname($lonhost);
+        $defaultshash{'usersessions'}{'spares'}{$lonhost} = {};
+        my %spareschg;
+        foreach my $type (@{$types{'spares'}}) {
+            my @okspares;
+            my @checked = &Apache::loncommon::get_env_multiple('form.spare_'.$type.'_'.$lonhost);
+            foreach my $server (@checked) {
+                if (&Apache::lonnet::hostname($server) ne '') {
+                    unless (&Apache::lonnet::hostname($server) eq $serverhostname) {
+                        unless (grep(/^\Q$server\E$/,@okspares)) {
+                            push(@okspares,$server);
+                        }
+                    }
+                }
+            }
+            my $new = $env{'form.newspare_'.$type.'_'.$lonhost};
+            my $newspare;
+            if (($new ne '') && (&Apache::lonnet::hostname($new))) {
+                unless (&Apache::lonnet::hostname($new) eq $serverhostname) {
+                    $newspare = $new;
+                }
+            }
+            my @spares;
+            if (($newspare ne '') && (!grep(/^\Q$newspare\E$/,@okspares))) {
+                @spares = sort(@okspares,$newspare);
+            } else {
+                @spares = sort(@okspares);
+            }
+            $defaultshash{'usersessions'}{'spares'}{$lonhost}{$type} = \@spares;
+            if (ref($spareid{$lonhost}) eq 'HASH') {
+                if (ref($spareid{$lonhost}{$type}) eq 'ARRAY') {
+                    my @diffs = &Apache::loncommon::compare_arrays($spareid{$lonhost}{$type},\@spares);
+                    if (@diffs > 0) {
+                        $spareschg{$type} = 1;
+                    }
+                }
+            }
+        }
+        if (keys(%spareschg) > 0) {
+            $changes{'spares'}{$lonhost} = \%spareschg;
+        }
+    }
+
+    if (ref($domconfig{'usersessions'}) eq 'HASH') {
+        if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {
+            if (ref($changes{'spares'}) eq 'HASH') {
+                if (keys(%{$changes{'spares'}}) > 0) {
+                    $savespares = 1;
+                }
+            }
+        } else {
+            $savespares = 1;
+        }
+    }
+
+    my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.');
+    if ((keys(%changes) > 0) || ($savespares)) {
         my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                  $dom);
         if ($putresult eq 'ok') {
@@ -6949,49 +7707,271 @@ sub modify_usersessions {
             }
             my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
-            my %lt = &usersession_titles();
-            $resulttext = &mt('Changes made:').'<ul>';
-            foreach my $prefix (@prefixes) {
-                if (ref($changes{$prefix}) eq 'HASH') {
-                    $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
-                    foreach my $type (@types) {
-                        if (defined($changes{$prefix}{$type})) {
-                            my $newvalue;
-                            if (ref($defaultshash{'usersessions'}) eq 'HASH') {
-                                if (ref($defaultshash{'usersessions'}{$prefix})) {
-                                    if ($type eq 'version') {
-                                        $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
-                                    } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
-                                        if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
-                                            $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
+            if (keys(%changes) > 0) {
+                my %lt = &usersession_titles();
+                $resulttext = &mt('Changes made:').'<ul>';
+                foreach my $prefix (@prefixes) {
+                    if (ref($changes{$prefix}) eq 'HASH') {
+                        $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
+                        if ($prefix eq 'spares') {
+                            if (ref($changes{$prefix}) eq 'HASH') {
+                                foreach my $lonhost (sort(keys(%{$changes{$prefix}}))) {
+                                    $resulttext .= '<li><b>'.$lonhost.'</b> ';
+                                    my $lonhostdom = &Apache::lonnet::host_domain($lonhost);
+                                    &Apache::lonnet::remote_devalidate_cache($lonhost,'spares',$lonhostdom);
+                                    if (ref($changes{$prefix}{$lonhost}) eq 'HASH') {
+                                        foreach my $type (@{$types{$prefix}}) {
+                                            if ($changes{$prefix}{$lonhost}{$type}) {
+                                                my $offloadto = &mt('None');
+                                                if (ref($defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}) eq 'ARRAY') {
+                                                    if (@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}} > 0) {   
+                                                        $offloadto = join(', ',@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}});
+                                                    }
+                                                }
+                                                $resulttext .= &mt('[_1] set to: [_2].','<i>'.$lt{$type}.'</i>',$offloadto).('&nbsp;'x3);
+                                            }
                                         }
                                     }
+                                    $resulttext .= '</li>';
                                 }
                             }
-                            if ($newvalue eq '') {
-                                if ($type eq 'version') {
-                                    $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
-                                } else {
-                                    $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
+                        } else {
+                            foreach my $type (@{$types{$prefix}}) {
+                                if (defined($changes{$prefix}{$type})) {
+                                    my $newvalue;
+                                    if (ref($defaultshash{'usersessions'}) eq 'HASH') {
+                                        if (ref($defaultshash{'usersessions'}{$prefix})) {
+                                            if ($type eq 'version') {
+                                                $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
+                                            } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
+                                                if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
+                                                    $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
+                                                }
+                                            }
+                                        }
+                                    }
+                                    if ($newvalue eq '') {
+                                        if ($type eq 'version') {
+                                            $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
+                                        } else {
+                                            $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
+                                        }
+                                    } else {
+                                        if ($type eq 'version') {
+                                            $newvalue .= ' '.&mt('(or later)'); 
+                                        }
+                                        $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
+                                    }
                                 }
-                            } else {
-                                if ($type eq 'version') {
-                                    $newvalue .= ' '.&mt('(or later)'); 
-                                } 
-                                $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>'; 
                             }
                         }
+                        $resulttext .= '</ul>';
                     }
-                    $resulttext .= '</ul>';
                 }
+                $resulttext .= '</ul>';
+            } else {
+                $resulttext = $nochgmsg;
             }
-            $resulttext .= '</ul>';
         } else {
             $resulttext = '<span class="LC_error">'.
                           &mt('An error occurred: [_1]',$putresult).'</span>';
         }
     } else {
-        $resulttext =  &mt('No changes made to settings for user session hosting.');
+        $resulttext = $nochgmsg;
+    }
+    return $resulttext;
+}
+
+sub modify_loadbalancing {
+    my ($dom,%domconfig) = @_;
+    my $primary_id = &Apache::lonnet::domain($dom,'primary');
+    my $intdom = &Apache::lonnet::internet_dom($primary_id);
+    my ($othertitle,$usertypes,$types) =
+        &Apache::loncommon::sorted_inst_types($dom);
+    my %servers = &Apache::lonnet::internet_dom_servers($dom);
+    my @sparestypes = ('primary','default');
+    my %typetitles = &sparestype_titles();
+    my $resulttext;
+    if (keys(%servers) > 1) {
+        my ($currbalancer,$currtargets,$currrules);
+        if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+            $currbalancer = $domconfig{'loadbalancing'}{'lonhost'};
+            $currtargets = $domconfig{'loadbalancing'}{'targets'};
+            $currrules = $domconfig{'loadbalancing'}{'rules'};
+        } else {
+            ($currbalancer,$currtargets) = 
+                &Apache::lonnet::get_lonbalancer_config(\%servers);
+        }
+        my ($saveloadbalancing,%defaultshash,%changes);
+        my ($alltypes,$othertypes,$titles) =
+            &loadbalancing_titles($dom,$intdom,$usertypes,$types);
+        my %ruletitles = &offloadtype_text();
+        my $balancer = $env{'form.loadbalancing_lonhost'};
+        if (!$servers{$balancer}) {
+            undef($balancer);
+        }
+        if ($currbalancer ne $balancer) {
+            $changes{'lonhost'} = 1;
+        }
+        $defaultshash{'loadbalancing'}{'lonhost'} = $balancer;
+        if ($balancer ne '') {
+            unless (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+                $saveloadbalancing = 1;
+            }
+            foreach my $sparetype (@sparestypes) {
+                my @targets = &Apache::loncommon::get_env_multiple('form.loadbalancing_target_'.$sparetype);
+                my @offloadto;
+                foreach my $target (@targets) {
+                    if (($servers{$target}) && ($target ne $balancer)) {
+                        if ($sparetype eq 'default') {
+                            if (ref($defaultshash{'loadbalancing'}{'targets'}{'primary'}) eq 'ARRAY') {
+                                next if (grep(/^\Q$target\E$/,@{$defaultshash{'loadbalancing'}{'targets'}{'primary'}}));
+                            }
+                        }
+                        unless(grep(/^\Q$target\E$/,@offloadto)) {
+                            push(@offloadto,$target);
+                        }
+                    }
+                    $defaultshash{'loadbalancing'}{'targets'}{$sparetype} = \@offloadto;
+                }
+            }
+        } else {
+            foreach my $sparetype (@sparestypes) {
+                $defaultshash{'loadbalancing'}{'targets'}{$sparetype} = [];
+            }
+        }
+        if (ref($currtargets) eq 'HASH') {
+            foreach my $sparetype (@sparestypes) {
+                if (ref($currtargets->{$sparetype}) eq 'ARRAY') {
+                    my @targetdiffs = &Apache::loncommon::compare_arrays($currtargets->{$sparetype},$defaultshash{'loadbalancing'}{'targets'}{$sparetype});
+                    if (@targetdiffs > 0) {
+                        $changes{'targets'} = 1;
+                    }
+                } elsif (ref($defaultshash{'loadbalancing'}{'targets'}{$sparetype}) eq 'ARRAY') {
+                    if (@{$defaultshash{'loadbalancing'}{'targets'}{$sparetype}} > 0) {
+                        $changes{'targets'} = 1;
+                    }
+                }
+            }
+        } else {
+            foreach my $sparetype (@sparestypes) {
+                if (ref($defaultshash{'loadbalancing'}{'targets'}{$sparetype}) eq 'ARRAY') {
+                    if (@{$defaultshash{'loadbalancing'}{'targets'}{$sparetype}} > 0) {
+                        $changes{'targets'} = 1;  
+                    }
+                }
+            }  
+        }
+        my $ishomedom;
+        if ($balancer ne '') {
+            if (&Apache::lonnet::host_domain($balancer) eq $dom) {
+                $ishomedom = 1;
+            }
+        }
+        if (ref($alltypes) eq 'ARRAY') {
+            foreach my $type (@{$alltypes}) {
+                my $rule;
+                if ($balancer ne '') {
+                    unless ((($type eq '_LC_external') || ($type eq '_LC_internetdom')) && 
+                         (!$ishomedom)) {
+                        $rule = $env{'form.loadbalancing_rules_'.$type};
+                    }
+                    if ($rule eq 'specific') {
+                        $rule = $env{'form.loadbalancing_singleserver_'.$type};
+                    }
+                }
+                $defaultshash{'loadbalancing'}{'rules'}{$type} = $rule;
+                if (ref($currrules) eq 'HASH') {
+                    if ($rule ne $currrules->{$type}) {
+                        $changes{'rules'}{$type} = 1;
+                    }
+                } elsif ($rule ne '') {
+                    $changes{'rules'}{$type} = 1;
+                }
+            }
+        }
+        my $nochgmsg = &mt('No changes made to Load Balancer settings.');
+        if ((keys(%changes) > 0) || ($saveloadbalancing)) {
+            my $putresult = &Apache::lonnet::put_dom('configuration',
+                                                     \%defaultshash,$dom);
+            if ($putresult eq 'ok') {
+                if (keys(%changes) > 0) {
+                    if ($changes{'lonhost'}) {
+                        if ($currbalancer ne '') {
+                            &Apache::lonnet::remote_devalidate_cache($currbalancer,'loadbalancing',$dom);
+                        }
+                        if ($balancer eq '') {
+                            $resulttext .= '<li>'.&mt('Load Balancing with dedicated server discontinued').'</li>'; 
+                        } else {
+                            &Apache::lonnet::remote_devalidate_cache($balancer,'loadbalancing',$dom);
+                            $resulttext .= '<li>'.&mt('Dedicated Load Balancer server set to [_1]',$balancer);
+                        }
+                    } else {
+                        &Apache::lonnet::remote_devalidate_cache($balancer,'loadbalancing',$dom);
+                    }
+                    if (($changes{'targets'}) && ($balancer ne '')) {
+                        my %offloadstr;
+                        foreach my $sparetype (@sparestypes) {
+                            if (ref($defaultshash{'loadbalancing'}{'targets'}{$sparetype}) eq 'ARRAY') {
+                                if (@{$defaultshash{'loadbalancing'}{'targets'}{$sparetype}} > 0) {
+                                    $offloadstr{$sparetype} = join(', ',@{$defaultshash{'loadbalancing'}{'targets'}{$sparetype}});
+                                }
+                            }
+                        }
+                        if (keys(%offloadstr) == 0) {
+                            $resulttext .= '<li>'.&mt("Servers to which Load Balance server offloads set to 'None', by default").'</li>';
+                        } else {
+                            my $showoffload;
+                            foreach my $sparetype (@sparestypes) {
+                                $showoffload .= '<i>'.$typetitles{$sparetype}.'</i>:&nbsp;';
+                                if (defined($offloadstr{$sparetype})) {
+                                    $showoffload .= $offloadstr{$sparetype};
+                                } else {
+                                    $showoffload .= &mt('None');
+                                }
+                                $showoffload .= ('&nbsp;'x3);
+                            }
+                            $resulttext .= '<li>'.&mt('By default, Load Balancer server set to offload to: [_1]',$showoffload).'</li>';
+                        }
+                    }
+                    if ((ref($changes{'rules'}) eq 'HASH') && ($balancer ne '')) {
+                        if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) {
+                            foreach my $type (@{$alltypes}) {
+                                if ($changes{'rules'}{$type}) {
+                                    my $rule = $defaultshash{'loadbalancing'}{'rules'}{$type};
+                                    my $balancetext;
+                                    if ($rule eq '') {
+                                        $balancetext =  $ruletitles{'default'};
+                                    } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer')) {
+                                        $balancetext =  $ruletitles{$rule};
+                                    } else {
+                                        $balancetext = &mt('offload to [_1]',$defaultshash{'loadbalancing'}{'rules'}{$type});
+                                    }
+                                    $resulttext .= '<li>'.&mt('Load Balancing for [_1] set to: [_2]',$titles->{$type},$balancetext).'</li>';     
+                                }
+                            }
+                        }
+                    }
+                    if ($resulttext ne '') {
+                        $resulttext = &mt('Changes made:').'<ul>'.$resulttext.'</ul>';
+                    } else {
+                        $resulttext = $nochgmsg;
+                    }
+                } else {
+                    $resulttext = $nochgmsg;
+                    if ($balancer ne '') {
+                        &Apache::lonnet::remote_devalidate_cache($balancer,'loadbalancing',$dom);
+                    }
+                }
+            } else {
+                $resulttext = '<span class="LC_error">'.
+                              &mt('An error occurred: [_1]',$putresult).'</span>';
+            }
+        } else {
+            $resulttext = $nochgmsg;
+        }
+    } else {
+        $resulttext =  &mt('Load Balancing unavailable as this domain only has one server.');
     }
     return $resulttext;
 }
@@ -7036,39 +8016,6 @@ sub recurse_cat_deletes {
     return;
 }
 
-sub dom_servers {
-    my ($dom) = @_;
-    my (%uniqservers,%servers);
-    my $primaryserver = &Apache::lonnet::hostname(&Apache::lonnet::domain($dom,'primary'));
-    my @machinedoms = &Apache::lonnet::machine_domains($primaryserver);
-    foreach my $mdom (@machinedoms) {
-        my %currservers = %servers;
-        my %server = &Apache::lonnet::get_servers($mdom);
-        %servers = (%currservers,%server);
-    }
-    my %by_hostname;
-    foreach my $id (keys(%servers)) {
-        push(@{$by_hostname{$servers{$id}}},$id);
-    }
-    foreach my $hostname (sort(keys(%by_hostname))) {
-        if (@{$by_hostname{$hostname}} > 1) {
-            my $match = 0;
-            foreach my $id (@{$by_hostname{$hostname}}) {
-                if (&Apache::lonnet::host_domain($id) eq $dom) {
-                    $uniqservers{$id} = $hostname;
-                    $match = 1;
-                }
-            }
-            unless ($match) {
-                $uniqservers{$by_hostname{$hostname}[0]} = $hostname;
-            }
-        } else {
-            $uniqservers{$by_hostname{$hostname}[0]} = $hostname;
-        }
-    }
-    return %uniqservers;
-}
-
 sub get_active_dcs {
     my ($dom) = @_;
     my %dompersonnel = &Apache::lonnet::get_domain_roles($dom,['dc']);
@@ -7142,12 +8089,336 @@ sub active_dc_picker {
 sub usersession_titles {
     return &Apache::lonlocal::texthash(
                hosted => 'Hosting of sessions for users from other domains on servers in this domain',
-
                remote => 'Hosting of sessions for users in this domain on servers in other domains',
+               spares => 'Servers offloaded to, when busy',
                version => 'LON-CAPA version requirement',
                excludedomain => 'Allow all, but exclude specific domains',
                includedomain => 'Deny all, but include specific domains',
+               primary => 'Primary (checked first)',
+               default => 'Default',
            );
 }
 
+sub id_for_thisdom {
+    my (%servers) = @_;
+    my %altids;
+    foreach my $server (keys(%servers)) {
+        my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server});
+        if ($serverhome ne $server) {
+            $altids{$serverhome} = $server;
+        }
+    }
+    return %altids;
+}
+
+sub count_servers {
+    my ($currbalancer,%servers) = @_;
+    my (@spares,$numspares);
+    foreach my $lonhost (sort(keys(%servers))) {
+        next if ($currbalancer eq $lonhost);
+        push(@spares,$lonhost);
+    }
+    if ($currbalancer) {
+        $numspares = scalar(@spares);
+    } else {
+        $numspares = scalar(@spares) - 1;
+    }
+    return ($numspares,@spares);
+}
+
+sub lonbalance_targets_js {
+    my ($dom,$types,$servers) = @_;
+    my $select = &mt('Select');
+    my ($alltargets,$allishome,$allinsttypes,@alltypes);
+    if (ref($servers) eq 'HASH') {
+        $alltargets = join("','",sort(keys(%{$servers})));
+        my @homedoms;
+        foreach my $server (sort(keys(%{$servers}))) {
+            if (&Apache::lonnet::host_domain($server) eq $dom) {
+                push(@homedoms,'1');
+            } else {
+                push(@homedoms,'0');
+            }
+        }
+        $allishome = join("','",@homedoms);
+    }
+    if (ref($types) eq 'ARRAY') {
+        if (@{$types} > 0) {
+            @alltypes = @{$types};
+        }
+    }
+    push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external');
+    $allinsttypes = join("','",@alltypes);
+    return <<"END";
+
+<script type="text/javascript">
+// <![CDATA[
+
+function toggleTargets() {
+    var balancer = document.display.loadbalancing_lonhost.options[document.display.loadbalancing_lonhost.selectedIndex].value;
+    if (balancer == '') {
+        hideSpares();
+    } else {
+        var homedoms = new Array('$allishome');
+        var ishomedom = homedoms[document.display.loadbalancing_lonhost.selectedIndex];
+        showSpares(balancer,ishomedom);
+    }
+    return;
+}
+
+function showSpares(balancer,ishomedom) {
+    var alltargets = new Array('$alltargets');
+    var insttypes = new Array('$allinsttypes');
+    var offloadtypes = new Array('primary','default');
+
+    document.getElementById('loadbalancing_targets').style.display='block';
+    document.getElementById('loadbalancing_disabled').style.display='none';
+ 
+    for (var i=0; i<offloadtypes.length; i++) {
+        var count = 0;
+        for (var j=0; j<alltargets.length; j++) {
+            if (alltargets[j] != balancer) {
+                document.getElementById('loadbalancing_target_'+offloadtypes[i]+'_'+count).value = alltargets[j];
+                document.getElementById('loadbalancing_targettxt_'+offloadtypes[i]+'_'+count).style.textAlign='left';
+                document.getElementById('loadbalancing_targettxt_'+offloadtypes[i]+'_'+count).style.textFace='normal';
+                document.getElementById('loadbalancing_targettxt_'+offloadtypes[i]+'_'+count).innerHTML = alltargets[j];
+                count ++;
+            }
+        }
+    }
+    for (var k=0; k<insttypes.length; k++) {
+        if ((insttypes[k] == '_LC_external') || (insttypes[k] == '_LC_internetdom')) {
+            if (ishomedom == 1) {
+                document.getElementById('balanceruletitle_'+insttypes[k]).style.display='block';
+                document.getElementById('balancerule_'+insttypes[k]).style.display='block';
+            } else {
+                document.getElementById('balanceruletitle_'+insttypes[k]).style.display='none';
+                document.getElementById('balancerule_'+insttypes[k]).style.display='none';
+
+            }
+        } else {
+            document.getElementById('balanceruletitle_'+insttypes[k]).style.display='block';
+            document.getElementById('balancerule_'+insttypes[k]).style.display='block';
+        }
+        if ((insttypes[k] != '_LC_external') && 
+            ((insttypes[k] != '_LC_internetdom') ||
+             ((insttypes[k] == '_LC_internetdom') && (ishomedom == 1)))) {
+            document.getElementById('loadbalancing_singleserver_'+insttypes[k]).options[0] = new Option("","",true,true);
+            for (var m=0; m<alltargets.length; m++) {
+                var idx = m+1;
+                if (alltargets[m] != balancer) {
+                    document.getElementById('loadbalancing_singleserver_'+insttypes[k]).options[idx] = new Option(alltargets[m],alltargets[m],false,false);
+                }
+            }
+        }
+    }
+    return;
+}
+
+function hideSpares() {
+    var alltargets = new Array('$alltargets');
+    var insttypes = new Array('$allinsttypes');
+    var offloadtypes = new Array('primary','default');
+
+    document.getElementById('loadbalancing_targets').style.display='none';
+    document.getElementById('loadbalancing_disabled').style.display='block';
+
+    var total = alltargets.length - 1;
+    for (var i=0; i<offloadtypes; i++) {
+        for (var j=0; j<total; j++) {
+           document.getElementById('loadbalancing_target_'+offloadtypes[i]+'_'+j).checked = false;
+           document.getElementById('loadbalancing_target_'+offloadtypes[i]+'_'+j).value = '';
+           document.getElementById('loadbalancing_targettxt_'+offloadtypes[i]+'_'+j).innerHTML = '';
+        }
+    }
+    for (var k=0; k<insttypes.length; k++) {
+        document.getElementById('balanceruletitle_'+insttypes[k]).style.display='none';
+        document.getElementById('balancerule_'+insttypes[k]).style.display='none';
+        if (insttypes[k] != '_LC_external') {
+            document.getElementById('loadbalancing_singleserver_'+insttypes[k]).length = 0;
+            document.getElementById('loadbalancing_singleserver_'+insttypes[k]).options[0] = new Option("","",true,true);
+        }
+    }
+    return;
+}
+
+function checkOffloads(item,type) {
+    var alltargets = new Array('$alltargets');
+    var offloadtypes = new Array('primary','default');
+    if (item.checked) {
+        var total = alltargets.length - 1;
+        var other;
+        if (type == offloadtypes[0]) {
+            other = offloadtypes[1];
+        } else {
+            other = offloadtypes[0];
+        }
+        for (var i=0; i<total; i++) {
+            var server = document.getElementById('loadbalancing_target_'+other+'_'+i).value;
+            if (server == item.value) {
+                if (document.getElementById('loadbalancing_target_'+other+'_'+i).checked) {
+                    document.getElementById('loadbalancing_target_'+other+'_'+i).checked = false;
+                }
+            }
+        }
+    }
+    return;
+}
+
+function singleServerToggle(type) {
+    var offloadtoSelIdx = document.getElementById('loadbalancing_singleserver_'+type).selectedIndex;
+    if (offloadtoSelIdx == 0) {
+        document.getElementById('loadbalancing_rules_'+type+'_0').checked = true;
+        document.getElementById('loadbalancing_singleserver_'+type).options[0].text = '';
+
+    } else {
+        document.getElementById('loadbalancing_rules_'+type+'_2').checked = true;
+        document.getElementById('loadbalancing_singleserver_'+type).options[0].text = '$select';
+    }
+    return;
+}
+
+function balanceruleChange(formname,type) {
+    if (type == '_LC_external') {
+        return; 
+    }
+    var typesRules = getIndicesByName(formname,'loadbalancing_rules_'+type);
+    for (var i=0; i<typesRules.length; i++) {
+        if (formname.elements[typesRules[i]].checked) {
+            if (formname.elements[typesRules[i]].value != 'specific') {
+                document.getElementById('loadbalancing_singleserver_'+type).selectedIndex = 0;
+                document.getElementById('loadbalancing_singleserver_'+type).options[0].text = '';
+            } else {
+                document.getElementById('loadbalancing_singleserver_'+type).options[0].text = '$select';
+            }
+        }
+    }
+    return;
+}
+
+// ]]>
+</script>
+
+END
+}
+
+sub new_spares_js {
+    my @sparestypes = ('primary','default');
+    my $types = join("','",@sparestypes);
+    my $select = &mt('Select');
+    return <<"END";
+
+<script type="text/javascript">
+// <![CDATA[
+
+function updateNewSpares(formname,lonhost) {
+    var types = new Array('$types');
+    var include = new Array();
+    var exclude = new Array();
+    for (var i=0; i<types.length; i++) {
+        var spareboxes = getIndicesByName(formname,'spare_'+types[i]+'_'+lonhost);
+        for (var j=0; j<spareboxes.length; j++) {
+            if (formname.elements[spareboxes[j]].checked) {
+                exclude.push(formname.elements[spareboxes[j]].value);
+            } else {
+                include.push(formname.elements[spareboxes[j]].value);
+            }
+        }
+    }
+    for (var i=0; i<types.length; i++) {
+        var newSpare = document.getElementById('newspare_'+types[i]+'_'+lonhost);
+        var selIdx = newSpare.selectedIndex;
+        var currnew = newSpare.options[selIdx].value;
+        var okSpares = new Array();
+        for (var j=0; j<newSpare.options.length; j++) {
+            var possible = newSpare.options[j].value;
+            if (possible != '') {
+                if (exclude.indexOf(possible) == -1) {
+                    okSpares.push(possible);
+                } else {
+                    if (currnew == possible) {
+                        selIdx = 0;
+                    }
+                }
+            }
+        }
+        for (var k=0; k<include.length; k++) {
+            if (okSpares.indexOf(include[k]) == -1) {
+                okSpares.push(include[k]);
+            }
+        }
+        okSpares.sort();
+        newSpare.options.length = 0;
+        if (selIdx == 0) {
+            newSpare.options[0] = new Option("$select","",true,true);
+        } else {
+            newSpare.options[0] = new Option("$select","",false,false);
+        }
+        for (var m=0; m<okSpares.length; m++) {
+            var idx = m+1;
+            var selThis = 0;
+            if (selIdx != 0) {
+                if (okSpares[m] == currnew) {
+                    selThis = 1;
+                }
+            }
+            if (selThis == 1) {
+                newSpare.options[idx] = new Option(okSpares[m],okSpares[m],true,true);
+            } else {
+                newSpare.options[idx] = new Option(okSpares[m],okSpares[m],false,false);
+            }
+        }
+    }
+    return;
+}
+
+function checkNewSpares(lonhost,type) {
+    var newSpare = document.getElementById('newspare_'+type+'_'+lonhost);
+    var chosen =  newSpare.options[newSpare.selectedIndex].value;
+    if (chosen != '') { 
+        var othertype;
+        var othernewSpare;
+        if (type == 'primary') {
+            othernewSpare = document.getElementById('newspare_default_'+lonhost);
+        }
+        if (type == 'default') {
+            othernewSpare = document.getElementById('newspare_primary_'+lonhost);
+        }
+        if (othernewSpare.options[othernewSpare.selectedIndex].value == chosen) {
+            othernewSpare.selectedIndex = 0;
+        }
+    }
+    return;
+}
+
+// ]]>
+</script>
+
+END
+
+}
+
+sub common_domprefs_js {
+    return <<"END";
+
+<script type="text/javascript">
+// <![CDATA[
+
+function getIndicesByName(formname,item) {
+    var group = new Array();
+    for (var i=0;i<formname.elements.length;i++) {
+        if (formname.elements[i].name == item) {
+            group.push(formname.elements[i].id);
+        }
+    }
+    return group;
+}
+
+// ]]>
+</script>
+
+END
+
+}
+
 1;