--- loncom/interface/lonhelper.pm	2005/01/16 08:20:38	1.93
+++ loncom/interface/lonhelper.pm	2006/05/18 01:08:51	1.151
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # .helper XML handler to implement the LON-CAPA helper
 #
-# $Id: lonhelper.pm,v 1.93 2005/01/16 08:20:38 albertel Exp $
+# $Id: lonhelper.pm,v 1.151 2006/05/18 01:08:51 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -25,10 +25,6 @@
 #
 # http://www.lon-capa.org/
 #
-# (Page Handler
-#
-# (.helper handler
-#
 
 =pod
 
@@ -186,6 +182,9 @@ use Apache::Constants qw(:common);
 use Apache::File;
 use Apache::lonxml;
 use Apache::lonlocal;
+use Apache::lonnet;
+use Apache::longroup;
+use Apache::lonselstudent;
 
 # Register all the tags with the helper, so the helper can 
 # push and pop them
@@ -255,7 +254,7 @@ sub real_handler {
     my $r = shift;
     my $uri = shift;
     if (!defined($uri)) { $uri = $r->uri(); }
-    $ENV{'request.uri'} = $uri;
+    $env{'request.uri'} = $uri;
     my $filename = '/home/httpd/html' . $uri;
     my $fh = Apache::File->new($filename);
     my $file;
@@ -263,7 +262,7 @@ sub real_handler {
 
 
     # Send header, don't cache this page
-    if ($ENV{'browser.mathml'}) {
+    if ($env{'browser.mathml'}) {
 	&Apache::loncommon::content_type($r,'text/xml');
     } else {
 	&Apache::loncommon::content_type($r,'text/html');
@@ -278,7 +277,7 @@ sub real_handler {
 
     my $allowed = $helper->allowedCheck();
     if (!$allowed) {
-        $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
+        $env{'user.error.msg'} = $env{'request.uri'}.':'.$helper->{REQUIRED_PRIV}.
             ":0:0:Permission denied to access this helper.";
         return HTTP_NOT_ACCEPTABLE;
     }
@@ -363,6 +362,7 @@ use HTML::Entities();
 use Apache::loncommon;
 use Apache::File;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 sub new {
     my $proto = shift;
@@ -374,16 +374,16 @@ sub new {
     
     # If there is a state from the previous form, use that. If there is no
     # state, use the start state parameter.
-    if (defined $ENV{"form.CURRENT_STATE"})
+    if (defined $env{"form.CURRENT_STATE"})
     {
-	$self->{STATE} = $ENV{"form.CURRENT_STATE"};
+	$self->{STATE} = $env{"form.CURRENT_STATE"};
     }
     else
     {
 	$self->{STATE} = "START";
     }
 
-    $self->{TOKEN} = $ENV{'form.TOKEN'};
+    $self->{TOKEN} = $env{'form.TOKEN'};
     # If a token was passed, we load that in. Otherwise, we need to create a 
     # new storage file
     # Tried to use standard Tie'd hashes, but you can't seem to take a 
@@ -416,16 +416,16 @@ sub new {
             return undef;
         }
         # Must create the storage
-        $self->{TOKEN} = md5_hex($ENV{'user.name'} . $ENV{'user.domain'} .
+        $self->{TOKEN} = md5_hex($env{'user.name'} . $env{'user.domain'} .
                                  time() . rand());
         $self->{FILENAME} = $Apache::lonnet::tmpdir . md5_hex($self->{TOKEN});
     }
 
     # OK, we now have our persistent storage.
 
-    if (defined $ENV{"form.RETURN_PAGE"})
+    if (defined $env{"form.RETURN_PAGE"})
     {
-	$self->{RETURN_PAGE} = $ENV{"form.RETURN_PAGE"};
+	$self->{RETURN_PAGE} = $env{"form.RETURN_PAGE"};
     }
     else
     {
@@ -486,11 +486,11 @@ sub declareVar {
     }
 
     my $envname = 'form.' . $var . '.forminput';
-    if (defined($ENV{$envname})) {
-        if (ref($ENV{$envname})) {
-            $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}});
+    if (defined($env{$envname})) {
+        if (ref($env{$envname})) {
+            $self->{VARS}->{$var} = join('|||', @{$env{$envname}});
         } else {
-            $self->{VARS}->{$var} = $ENV{$envname};
+            $self->{VARS}->{$var} = $env{$envname};
         }
     }
 }
@@ -502,7 +502,7 @@ sub allowedCheck {
         return 1;
     }
 
-    return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'});
+    return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $env{'request.course.id'});
 }
 
 sub changeState {
@@ -524,7 +524,7 @@ sub process {
     # Phase 1: Post processing for state of previous screen (which is actually
     # the "current state" in terms of the helper variables), if it wasn't the 
     # beginning state.
-    if ($self->{STATE} ne "START" || $ENV{"form.SUBMIT"} eq &mt("Next ->")) {
+    if ($self->{STATE} ne "START" || $env{"form.SUBMIT"} eq &mt("Next ->")) {
 	my $prevState = $self->{STATES}{$self->{STATE}};
         $prevState->postprocess();
     }
@@ -576,21 +576,19 @@ sub display {
 
     # Phase 4: Display.
     my $stateTitle=&mt($state->title());
-    my $helperTitle = &mt($self->{TITLE});
-    my $bodytag = &Apache::loncommon::bodytag($helperTitle,'','');
+    my $browser_searcher_js = 
+	'<script type="text/javascript">'."\n".
+	&Apache::loncommon::browser_and_searcher_javascript().
+	"\n".'</script>';
+
+    $result .= &Apache::loncommon::start_page($self->{TITLE},
+					      $browser_searcher_js);
+    
     my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
     my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
     # FIXME: This should be parameterized, not concatenated - Jeremy
-    my $loncapaHelper = &mt("LON-CAPA Helper:");
 
-    $result .= <<HEADER;
-<html>
-    <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-        <title>$loncapaHelper: $helperTitle</title>
-    </head>
-    $bodytag
-HEADER
+
     if (!$state->overrideForm()) { $result.="<form name='helpform' method='POST'>"; }
     $result .= <<HEADER;
         <table border="0" width='100%'><tr><td>
@@ -653,10 +651,9 @@ HEADER
             </tr>
           </table>
         </form>
-    </body>
-</html>
 FOOTER
 
+    $result .= &Apache::loncommon::end_page();
     # Handle writing out the vars to the file
     my $file = Apache::File->new('>'.$self->{FILENAME});
     print $file $self->_varsInFile();
@@ -1074,6 +1071,16 @@ will be the state transistioned to if th
 the choice is not multichoice. This will override the nextstate
 passed to the parent C<choices> tag.
 
+<choice> may optionally contain a 'relatedvalue' attribute, which
+if present will cause a text entry to appear to the right of the
+selection.  The value of the relatedvalue attribute is a variable
+into which the text entry will be stored e.g.:
+<choice computer='numberprovided" relatedvalue="num">Type the number in:</choice>
+
+<choice> may contain a relatededefault atribute which, if the
+relatedvalue attribute is present will be the initial value of the input
+box.
+
 =back
 
 To create the choices programmatically, either wrap the choices in 
@@ -1115,6 +1122,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::choices',
@@ -1163,10 +1171,12 @@ sub start_choice {
     my $computer = $token->[2]{'computer'};
     my $human = &mt(&Apache::lonxml::get_all_text('/choice',
                                               $parser));
-    my $nextstate = $token->[2]{'nextstate'};
-    my $evalFlag = $token->[2]{'eval'};
-    push @{$paramHash->{CHOICES}}, [$human, $computer, $nextstate, 
-                                    $evalFlag];
+    my $nextstate  = $token->[2]{'nextstate'};
+    my $evalFlag   = $token->[2]{'eval'};
+    my $relatedVar = $token->[2]{'relatedvalue'}; 
+    my $relatedDefault = $token->[2]{'relateddefault'};
+    push @{$paramHash->{CHOICES}}, [&mtn($human), $computer, $nextstate, 
+                                    $evalFlag, $relatedVar, $relatedDefault];
     return '';
 }
 
@@ -1189,7 +1199,8 @@ sub render {
 
     if ($self->{'multichoice'}) {
         $result .= <<SCRIPT;
-<script>
+<script type="text/javascript">
+// <!--
     function checkall(value, checkName) {
 	for (i=0; i<document.forms.helpform.elements.length; i++) {
             ele = document.forms.helpform.elements[i];
@@ -1198,6 +1209,7 @@ sub render {
             }
         }
     }
+// -->
 </script>
 SCRIPT
     }
@@ -1266,22 +1278,28 @@ BUTTONS
         my $id = &new_id();
         $result .= "<tr>\n<td width='20'>&nbsp;</td>\n";
         $result .= "<td valign='top'><input type='$type' name='$var.forminput'"
-            . "' value='" . 
+            . " value='" . 
             HTML::Entities::encode($choice->[1],"<>&\"'") 
             . "'";
         if ($checkedChoices{$choice->[1]}) {
-            $result .= " checked ";
+            $result .= " checked='checked' ";
         }
-        $result .= qq{id="$id"};
+        $result .= qq{id="id$id"};
         my $choiceLabel = $choice->[0];
-        if ($choice->[4]) {  # if we need to evaluate this choice
+        if ($choice->[3]) {  # if we need to evaluate this choice
             $choiceLabel = "sub { my $helper = shift; my $state = shift;" .
                 $choiceLabel . "}";
             $choiceLabel = eval($choiceLabel);
             $choiceLabel = &$choiceLabel($helper, $self);
         }
-        $result .= "/></td><td> ".qq{<label for="$id">}.
-            &mtn($choiceLabel). "</label></td></tr>\n";
+        $result .= "/></td><td> ".qq{<label for="id$id">}.
+            $choiceLabel. "</label></td>";
+	if ($choice->[4]) {
+	    $result .='<td><input type="text" size="5" name="'
+		.$choice->[4].'.forminput" value="'
+                .$choice->[5].'" /></td>';
+	}
+	$result .= "</tr>\n";
     }
     $result .= "</table>\n\n\n";
     $result .= $buttons;
@@ -1293,7 +1311,7 @@ BUTTONS
 # given, switch to it
 sub postprocess {
     my $self = shift;
-    my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'};
 
     if (!defined($chosenValue) && !$self->{'allowempty'}) {
         $self->{ERROR_MSG} = 
@@ -1315,6 +1333,10 @@ sub postprocess {
                 $helper->changeState($choice->[2]);
             }
         }
+	if ($choice->[4]) {
+	    my $varname = $choice->[4];
+	    $helper->{'VARS'}->{$varname} = $env{'form.'."$varname.forminput"};
+	}
     }
     return 1;
 }
@@ -1347,6 +1369,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::dropdown',
@@ -1427,7 +1450,7 @@ sub render {
             HTML::Entities::encode($choice->[1],"<>&\"'") 
             . "'";
         if ($checkedChoices{$choice->[1]}) {
-            $result .= " selected";
+            $result .= " selected='selected' ";
         }
         my $choiceLabel = $choice->[0];
         if ($choice->[4]) {  # if we need to evaluate this choice
@@ -1436,7 +1459,7 @@ sub render {
             $choiceLabel = eval($choiceLabel);
             $choiceLabel = &$choiceLabel($helper, $self);
         }
-        $result .= ">" . &mtn($choiceLabel) . "\n";
+        $result .= ">" . &mtn($choiceLabel) . "</option>\n";
     }
     $result .= "</select>\n";
 
@@ -1447,7 +1470,7 @@ sub render {
 # given, switch to it
 sub postprocess {
     my $self = shift;
-    my $chosenValue = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $chosenValue = $env{'form.' . $self->{'variable'} . '.forminput'};
 
     if (!defined($chosenValue) && !$self->{'allowempty'}) {
         $self->{ERROR_MSG} = "You must choose one or more choices to" .
@@ -1506,7 +1529,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal; # A localization nightmare
-
+use Apache::lonnet;
 use Time::localtime;
 
 BEGIN {
@@ -1534,6 +1557,7 @@ sub start_date {
     $paramHash->{'variable'} = $token->[2]{'variable'};
     $helper->declareVar($paramHash->{'variable'});
     $paramHash->{'hoursminutes'} = $token->[2]{'hoursminutes'};
+    $paramHash->{'anytime'} = $token->[2]{'anytime'};
 }
 
 sub end_date {
@@ -1552,10 +1576,45 @@ sub render {
     my $var = $self->{'variable'};
 
     my $date;
-    
+
+    my $time=time;
+    my ($anytime,$onclick);
+
+
+    # first check VARS for a valid new value from the user
+    # then check DEFAULT_VALUE for a valid default time value
+    # otherwise pick now as reasonably good time
+
+    if (defined($helper->{VARS}{$var})
+	&&  $helper->{VARS}{$var} > 0) {
+	$date = localtime($helper->{VARS}{$var});
+    } elsif (defined($self->{DEFAULT_VALUE})) {
+        my $valueFunc = eval($self->{DEFAULT_VALUE});
+        die('Error in default value code for variable ' . 
+            $self->{'variable'} . ', Perl said: ' . $@) if $@;
+        $time = &$valueFunc($helper, $self);
+	if (lc($time) eq 'anytime') {
+	    $anytime=1;
+	    $date = localtime(time);
+	    $date->min(0);
+	} elsif (defined($time) && $time ne 0) {
+	    $date = localtime($time);
+	} else {
+	    # leave date undefined so it'll default to now
+	}
+    }
+
+    if (!defined($date)) {
+	$date = localtime(time);
+	$date->min(0);
+    }
+
+    &Apache::lonnet::logthis("date mode ");
+
+    if ($anytime) {
+	$onclick = "onclick=\"javascript:updateCheck(this.form,'${var}anytime',false)\"";
+    }
     # Default date: The current hour.
-    $date = localtime();
-    $date->min(0);
 
     if (defined $self->{ERROR_MSG}) {
         $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
@@ -1563,10 +1622,10 @@ sub render {
 
     # Month
     my $i;
-    $result .= "<select name='${var}month'>\n";
+    $result .= "<select $onclick name='${var}month'>\n";
     for ($i = 0; $i < 12; $i++) {
         if ($i == $date->mon) {
-            $result .= "<option value='$i' selected>";
+            $result .= "<option value='$i' selected='selected'>";
         } else {
             $result .= "<option value='$i'>";
         }
@@ -1575,10 +1634,10 @@ sub render {
     $result .= "</select>\n";
 
     # Day
-    $result .= "<select name='${var}day'>\n";
+    $result .= "<select $onclick name='${var}day'>\n";
     for ($i = 1; $i < 32; $i++) {
         if ($i == $date->mday) {
-            $result .= '<option selected>';
+            $result .= '<option selected="selected">';
         } else {
             $result .= '<option>';
         }
@@ -1587,10 +1646,10 @@ sub render {
     $result .= "</select>,\n";
 
     # Year
-    $result .= "<select name='${var}year'>\n";
+    $result .= "<select $onclick name='${var}year'>\n";
     for ($i = 2000; $i < 2030; $i++) { # update this after 64-bit dates
         if ($date->year + 1900 == $i) {
-            $result .= "<option selected>";
+            $result .= "<option selected='selected'>";
         } else {
             $result .= "<option>";
         }
@@ -1604,22 +1663,22 @@ sub render {
 	my $am = &mt('a.m.');
 	my $pm = &mt('p.m.');
         # Build hour
-        $result .= "<select name='${var}hour'>\n";
-        $result .= "<option " . ($date->hour == 0 ? 'selected ':'') .
+        $result .= "<select $onclick name='${var}hour'>\n";
+        $result .= "<option " . ($date->hour == 0 ? 'selected="selected" ':'') .
             " value='0'>" . &mt('midnight') . "</option>\n";
         for ($i = 1; $i < 12; $i++) {
             if ($date->hour == $i) {
-                $result .= "<option selected value='$i'>$i $am</option>\n";
+                $result .= "<option selected='selected' value='$i'>$i $am</option>\n";
             } else {
                 $result .= "<option value='$i'>$i $am</option>\n";
             }
         }
-        $result .= "<option " . ($date->hour == 12 ? 'selected ':'') .
+        $result .= "<option " . ($date->hour == 12 ? 'selected="selected" ':'') .
             " value='12'>" . &mt('noon') . "</option>\n";
         for ($i = 13; $i < 24; $i++) {
             my $printedHour = $i - 12;
             if ($date->hour == $i) {
-                $result .= "<option selected value='$i'>$printedHour $pm</option>\n";
+                $result .= "<option selected='selected' value='$i'>$printedHour $pm</option>\n";
             } else {
                 $result .= "<option value='$i'>$printedHour $pm</option>\n";
             }
@@ -1627,14 +1686,16 @@ sub render {
 
         $result .= "</select> :\n";
 
-        $result .= "<select name='${var}minute'>\n";
-        for ($i = 0; $i < 60; $i++) {
+        $result .= "<select $onclick name='${var}minute'>\n";
+	my $selected=0;
+        for my $i ((0,15,30,45,59,undef,0..59)) {
             my $printedMinute = $i;
-            if ($i < 10) {
+            if (defined($i) && $i < 10) {
                 $printedMinute = "0" . $printedMinute;
             }
-            if ($date->min == $i) {
-                $result .= "<option selected>";
+            if (!$selected && $date->min == $i) {
+                $result .= "<option selected='selected'>";
+		$selected=1;
             } else {
                 $result .= "<option>";
             }
@@ -1642,7 +1703,23 @@ sub render {
         }
         $result .= "</select>\n";
     }
-
+    if ($self->{'anytime'}) {
+	$result.=(<<CHECK);
+<script type="text/javascript">
+// <!--
+    function updateCheck(form,name,value) {
+	var checkbox=form[name];
+	checkbox.checked = value;
+    }
+// -->
+</script>
+CHECK
+	$result.="&nbsp;or&nbsp;<label><input type='checkbox' ";
+	if ($anytime) {
+	    $result.=' checked="checked" '
+	}
+	$result.="name='${var}anytime'/>".&mt('Any time').'</label>'
+    }
     return $result;
 
 }
@@ -1650,40 +1727,53 @@ sub render {
 sub postprocess {
     my $self = shift;
     my $var = $self->{'variable'};
-    my $month = $ENV{'form.' . $var . 'month'}; 
-    my $day = $ENV{'form.' . $var . 'day'}; 
-    my $year = $ENV{'form.' . $var . 'year'}; 
-    my $min = 0; 
-    my $hour = 0;
-    if ($self->{'hoursminutes'}) {
-        $min = $ENV{'form.' . $var . 'minute'};
-        $hour = $ENV{'form.' . $var . 'hour'};
-    }
+    if ($env{'form.' . $var . 'anytime'}) {
+	$helper->{VARS}->{$var} = undef;
+    } else {
+	my $month = $env{'form.' . $var . 'month'}; 
+	my $day = $env{'form.' . $var . 'day'}; 
+	my $year = $env{'form.' . $var . 'year'}; 
+	my $min = 0; 
+	my $hour = 0;
+	if ($self->{'hoursminutes'}) {
+	    $min = $env{'form.' . $var . 'minute'};
+	    $hour = $env{'form.' . $var . 'hour'};
+	}
+
+	my $chosenDate;
+	eval {$chosenDate = Time::Local::timelocal(0, $min, $hour, $day, $month, $year);};
+	my $error = $@;
+
+	# Check to make sure that the date was not automatically co-erced into a 
+	# valid date, as we want to flag that as an error
+	# This happens for "Feb. 31", for instance, which is coerced to March 2 or
+	# 3, depending on if it's a leap year
+	my $checkDate = localtime($chosenDate);
+	
+	if ($error || $checkDate->mon != $month || $checkDate->mday != $day ||
+	    $checkDate->year + 1900 != $year) {
+	    unless (Apache::lonlocal::current_language()== ~/^en/) {
+		$self->{ERROR_MSG} = &mt("Invalid date entry");
+		return 0;
+	    }
+	    # LOCALIZATION FIXME: Needs to be parameterized
+	    $self->{ERROR_MSG} = "Can't use " . $months[$month] . " $day, $year as a "
+		. "date because it doesn't exist. Please enter a valid date.";
 
-    my $chosenDate;
-    eval {$chosenDate = Time::Local::timelocal(0, $min, $hour, $day, $month, $year);};
-    my $error = $@;
-
-    # Check to make sure that the date was not automatically co-erced into a 
-    # valid date, as we want to flag that as an error
-    # This happens for "Feb. 31", for instance, which is coerced to March 2 or
-    # 3, depending on if it's a leap year
-    my $checkDate = localtime($chosenDate);
-
-    if ($error || $checkDate->mon != $month || $checkDate->mday != $day ||
-        $checkDate->year + 1900 != $year) {
-	unless (Apache::lonlocal::current_language()== ~/^en/) {
-	    $self->{ERROR_MSG} = &mt("Invalid date entry");
 	    return 0;
 	}
-	# LOCALIZATION FIXME: Needs to be parameterized
-        $self->{ERROR_MSG} = "Can't use " . $months[$month] . " $day, $year as a "
-            . "date because it doesn't exist. Please enter a valid date.";
-
-        return 0;
+	$helper->{VARS}->{$var} = $chosenDate;
     }
 
-    $helper->{VARS}->{$var} = $chosenDate;
+    if (defined($self->{VALIDATOR})) {
+	my $validator = eval($self->{VALIDATOR});
+	die 'Died during evaluation of validator code; Perl said: ' . $@ if $@;
+	my $invalid = &$validator($helper, $state, $self, $self->getValue());
+	if ($invalid) {
+	    $self->{ERROR_MSG} = $invalid;
+	    return 0;
+	}
+    }
 
     if (defined($self->{NEXTSTATE})) {
         $helper->changeState($self->{NEXTSTATE});
@@ -1715,7 +1805,9 @@ to false. The "suppressEmptySequences" a
 suppressEmptySequences argument to the render routine, which will cause
 folders that have all of their contained resources filtered out to also
 be filtered out. The 'addstatus' attribute, if true, will add the icon
-and long status display columns to the display.
+and long status display columns to the display. The 'addparts'
+attribute will add in a part selector beside problems that have more
+than 1 part.
 
 =head3 SUB-TAGS
 
@@ -1755,6 +1847,7 @@ and long status display columns to the d
 no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::resource',
@@ -1782,6 +1875,10 @@ sub start_resource {
     $paramHash->{'suppressEmptySequences'} = $token->[2]{'suppressEmptySequences'};
     $paramHash->{'toponly'} = $token->[2]{'toponly'};
     $paramHash->{'addstatus'} = $token->[2]{'addstatus'};
+    $paramHash->{'addparts'} = $token->[2]{'addparts'};
+    if ($paramHash->{'addparts'}) {
+	$helper->declareVar($paramHash->{'variable'}.'_part');
+    }
     $paramHash->{'closeallpages'} = $token->[2]{'closeallpages'};
     return '';
 }
@@ -1923,7 +2020,8 @@ sub render {
 
     if ($self->{'multichoice'}) {
         $result = <<SCRIPT;
-<script>
+<script type="text/javascript">
+// <!--
     function checkall(value, checkName) {
 	for (i=0; i<document.forms.helpform.elements.length; i++) {
             ele = document.forms.helpform.elements[i];
@@ -1932,6 +2030,7 @@ sub render {
             }
         }
     }
+// -->
 </script>
 SCRIPT
         my %lt=&Apache::lonlocal::texthash(
@@ -1955,9 +2054,10 @@ BUTTONS
     my $filterFunc     = $self->{FILTER_FUNC};
     my $choiceFunc     = $self->{CHOICE_FUNC};
     my $valueFunc      = $self->{VALUE_FUNC};
-    my $multichoice   = $self->{'multichoice'};
+    my $multichoice    = $self->{'multichoice'};
     my $option_vars    = $self->{OPTION_VARS};
     my $option_texts   = $self->{OPTION_TEXTS};
+    my $addparts       = $self->{'addparts'};
     my $headings_done  = 0;
 
     # Evaluate the map url as needed
@@ -1970,6 +2070,19 @@ BUTTONS
 	$mapUrl = $self->{MAP_URL};
     }
 
+    my %defaultSymbs;
+    if (defined($self->{DEFAULT_VALUE})) {
+        my $valueFunc = eval($self->{DEFAULT_VALUE});
+        die 'Error in default value code for variable ' . 
+            $self->{'variable'} . ', Perl said: ' . $@ if $@;
+        my @defaultSymbs = &$valueFunc($helper, $self);
+	if (!$multichoice && @defaultSymbs) { # only allowed 1
+	    @defaultSymbs = ($defaultSymbs[0]);
+	}
+	%defaultSymbs = map { if ($_) {($_,1) } } @defaultSymbs;
+	delete($defaultSymbs{''});
+    }
+
     # Create the composite function that renders the column on the nav map
     # have to admit any language that lets me do this can't be all bad
     #  - Jeremy (Pythonista) ;-)
@@ -1998,33 +2111,89 @@ BUTTONS
             return $result;
         } else {
 	    my $col = "";
+	    my $raw_name = &$valueFunc($resource);
 	    my $resource_name =   
-                   HTML::Entities::encode(&$valueFunc($resource),"<>&\"'");
+                   HTML::Entities::encode($raw_name,"<>&\"'");
 	    if($option_vars) {
 		foreach my $option_var (@$option_vars) {
+		    my $var_value = "\|\|\|" . $helper->{VARS}->{$option_var} . 
+			"\|\|\|";
+		    my $checked ="";
+		    if($var_value =~ /\Q|||$raw_name|||\E/) {
+			$checked = "checked='checked'";
+		    }
 		    $col .= 
                         "<td align='center'><input type='checkbox' name ='$option_var".
 			".forminput' value='".
-			$resource_name . "' /> </td>";
+			$resource_name . "' $checked /> </td>";
 		}
 	    }
 
             $col .= "<td align='center'><input type='$inputType' name='${var}.forminput' ";
-            if (!$checked && !$multichoice) {
-                $col .= "checked ";
-                $checked = 1;
-            }
-	    if ($multichoice) { # all resources start checked; see bug 1174
-		$col .= "checked ";
-		$checked = 1;
+	    if (%defaultSymbs) {
+		my $symb=$resource->symb();
+		if (exists($defaultSymbs{$symb})) {
+		    $col .= "checked='checked' ";
+		    $checked = 1;
+		}
+	    } else {
+		if (!$checked && !$multichoice) {
+		    $col .= "checked='checked' ";
+		    $checked = 1;
+		}
+		if ($multichoice) { # all resources start checked; see bug 1174
+		    $col .= "checked='checked' ";
+		    $checked = 1;
+		}
 	    }
             $col .= "value='" . $resource_name  . "' /></td>";
+
             return $result.$col;
         }
     };
+    my $renderPartsFunc = sub {
+        my ($resource, $part, $params) = @_;
+	my $col= "<td>";
+	my $id=$resource->{ID};
+	my $resource_name =   
+	    &HTML::Entities::encode(&$valueFunc($resource),"<>&\"'");
+	if ($addparts && (scalar(@{$resource->parts}) > 1)) {
+	    $col .= "<select onclick=\"javascript:updateRadio(this.form,'${var}.forminput','$resource_name');updateHidden(this.form,'$id','${var}');\" name='part_$id.forminput'>\n";
+	    $col .= "<option value=\"$part\">All Parts</option>\n";
+	    foreach my $part (@{$resource->parts}) {
+		$col .= "<option value=\"$part\">Part: $part</option>\n";
+	    }
+	    $col .= "</select>";
+	}
+	$col .= "</td>";
+    };
+    $result.=(<<RADIO);
+<script type="text/javascript">
+// <!--
+    function updateRadio(form,name,value) {
+	var radiobutton=form[name];
+	for (var i=0; i<radiobutton.length; i++) {
+	    if (radiobutton[i].value == value) {
+		radiobutton[i].checked = true;
+		break;
+	    }
+	}
+    }
+    function updateHidden(form,id,name) {
+	var select=form['part_'+id+'.forminput'];
+	var hidden=form[name+'_part.forminput'];
+	var which=select.selectedIndex;
+	hidden.value=select.options[which].value;
+    }
+// -->
+</script>
+<input type="hidden" name="${var}_part.forminput" />
 
-    $ENV{'form.condition'} = !$self->{'toponly'};
-    my $cols = [$renderColFunc, Apache::lonnavmaps::resource()];
+RADIO
+    $env{'form.condition'} = !$self->{'toponly'};
+    my $cols = [$renderColFunc];
+    if ($self->{'addparts'}) { push(@$cols, $renderPartsFunc); }
+    push(@$cols, Apache::lonnavmaps::resource());
     if ($self->{'addstatus'}) {
 	push @$cols, (Apache::lonnavmaps::part_status_summary());
 	
@@ -2093,6 +2262,10 @@ selection. Defaults to false.
 If true, only active students and course personnel will be
 shown. Defaults to false.
 
+=item * B<emptyallowed>:
+
+If true, the selection of no users is allowed. Defaults to false.
+
 =back
 
 =cut
@@ -2101,7 +2274,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
-
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::student',
@@ -2128,6 +2301,7 @@ sub start_student {
     if (defined($token->[2]{'nextstate'})) {
         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
     }
+    $paramHash->{'emptyallowed'} = $token->[2]{'emptyallowed'};
     
 }    
 
@@ -2146,181 +2320,91 @@ sub render {
     my $buttons = '';
     my $var = $self->{'variable'};
 
-    if ($self->{'multichoice'}) {
-        $result = <<SCRIPT;
-<script>
-    function checkall(value, checkName) {
-	for (i=0; i<document.forms.helpform.elements.length; i++) {
-            ele = document.forms.helpform.elements[i];
-            if (ele.name == checkName + '.forminput') {
-                document.forms.helpform.elements[i].checked=value;
-            }
-        }
-    }
-    function checksec(value) {
-	for (i=0; i<document.forms.helpform.elements.length; i++) {
-	    comp = document.forms.helpform.elements.chksec.value;
-            if (document.forms.helpform.elements[i].value.indexOf(':'+comp+':') != -1) {
-		if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) {
-		    document.forms.helpform.elements[i].checked=value;
-		}
-            }
-        }
-    }
-    function checkactive() {
-	for (i=0; i<document.forms.helpform.elements.length; i++) {
-            if (document.forms.helpform.elements[i].value.indexOf(':Active') != -1) {
-                document.forms.helpform.elements[i].checked=true;
-            } 
-        }
-    }
-    function uncheckexpired() {
-	for (i=0; i<document.forms.helpform.elements.length; i++) {
-            if (document.forms.helpform.elements[i].value.indexOf(':Expired') != -1) {
-                document.forms.helpform.elements[i].checked=false;
-            } 
-        }
-    }
-</script>
-SCRIPT
-
-        my %lt=&Apache::lonlocal::texthash(
-                    'ocs'  => "Select Only Current Students",
-                    'ues'  => "Unselect Expired Students",
-                    'sas'  => "Select All Students",
-                    'uas'  => "Unselect All Students",
-                    'sfsg' => "Select Current Students for Section/Group",
-		    'ufsg' => "Unselect for Section/Group");
- 
-        $buttons = <<BUTTONS;
-<br />
-<table>
-  <tr>
-  
-    <td><input type="button" onclick="checkactive()" value="$lt{'ocs'}" /></td>
-    <td><input type="button" onclick="uncheckexpired()" value="$lt{'ues'}" /><br /></td>
-  </tr>
-  <tr>
-     <td><input type="button" onclick="checkall(true, '$var')" value="$lt{'sas'}" /></td>
-     <td> <input type="button" onclick="checkall(false, '$var')" value="$lt{'uas'}" /><br /></td>
-  </tr>
-  <tr>
-      <td><input type="button" onclick="checksec(true)" value="$lt{'sfsg'}"></td>
-      <td><input type="text" size="5" name="chksec">&nbsp;</td>
-  </tr>
-  <tr>
-      <td><input type="button" onclick="checksec(false)" value="$lt{'ufsg'}"></td>
-      <td></td>
-  </tr>
-</table>
-<br />
-BUTTONS
-    }
 
     if (defined $self->{ERROR_MSG}) {
         $result .= '<font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
     }
 
-    my $choices = [];
+    my %defaultUsers;
+    if (defined($self->{DEFAULT_VALUE})) {
+        my $valueFunc = eval($self->{DEFAULT_VALUE});
+        die 'Error in default value code for variable ' . 
+            $self->{'variable'} . ', Perl said: ' . $@ if $@;
+        my @defaultUsers = &$valueFunc($helper, $self);
+	if (!$self->{'multichoice'} && @defaultUsers) { # only allowed 1
+	    @defaultUsers = ($defaultUsers[0]);
+	}
+	%defaultUsers = map { if ($_) {($_,1) } } @defaultUsers;
+	delete($defaultUsers{''});
+    }
+
+
+    my ($course_personnel, 
+	$current_members, 
+	$expired_members, 
+	$future_members) = &Apache::lonselstudent::get_people_in_class();
+
+
 
     # Load up the non-students, if necessary
+
     if ($self->{'coursepersonnel'}) {
-	my %coursepersonnel = Apache::lonnet::get_course_adv_roles();
-	for (sort keys %coursepersonnel) {
-	    for my $role (split /,/, $coursepersonnel{$_}) {
-		# extract the names so we can sort them
-		my @people;
-		
-		for (split /,/, $role) {
-		    push @people, [split /:/, $role];
-		}
-		
-		@people = sort { $a->[0] cmp $b->[0] } @people;
-		
-		for my $person (@people) {
-		    push @$choices, [join(':', @$person), $person->[0], '', $_];
-		}
-	    }
-	}
+	unshift @$current_members, (@$course_personnel);
     }
 
-    # Constants
-    my $section = Apache::loncoursedata::CL_SECTION();
-    my $fullname = Apache::loncoursedata::CL_FULLNAME();
-    my $status = Apache::loncoursedata::CL_STATUS();
 
-    # Load up the students
-    my $classlist = &Apache::loncoursedata::get_classlist();
-    my @keys = keys %{$classlist};
-    # Sort by: Section, name
-    @keys = sort {
-        if ($classlist->{$a}->[$section] ne $classlist->{$b}->[$section]) {
-            return $classlist->{$a}->[$section] cmp $classlist->{$b}->[$section];
-        }
-        return $classlist->{$a}->[$fullname] cmp $classlist->{$b}->[$fullname];
-    } @keys;
-
-    # username, fullname, section, type
-    for (@keys) {
-	# Filter out inactive students if we've set "activeonly"
-	if (!$self->{'activeonly'} || $classlist->{$_}->[$status] eq
-	    'Active') {
-	    push @$choices, [$_, $classlist->{$_}->[$fullname], 
-			     $classlist->{$_}->[$section],
-			     $classlist->{$_}->[$status], 'Student'];
-	}
-    }
+    #   Current personel
 
-    my $name = $self->{'coursepersonnel'} ? &mt('Name') : &mt('Student Name');
-    my $type = 'radio';
-    if ($self->{'multichoice'}) { $type = 'checkbox'; }
-    $result .= "<table cellspacing='2' cellpadding='2' border='0'>\n";
-    $result .= "<tr><td></td><td align='center'><b>$name</b></td>".
-        "<td align='center'><b>" . &mt('Section') . "</b></td>" . 
-	"<td align='center'><b>".&mt('Status')."</b></td>" . 
-	"<td align='center'><b>" . &mt("Role") . "</b></td>" .
-	"<td align='center'><b>".&mt('Username').":".&mt('Domain')."</b></td></tr>";
+    $result .= &Apache::lonselstudent::render_student_list( $current_members,
+							    "helpform",
+							    "current", 
+							    \%defaultUsers,
+							    $self->{'multichoice'},
+							    $self->{'variable'},
+							    1);
 
-    my $checked = 0;
-    for my $choice (@$choices) {
-        $result .= "<tr><td><input type='$type' name='" .
-            $self->{'variable'} . '.forminput' . "'";
-            
-        if (!$self->{'multichoice'} && !$checked) {
-            $result .= " checked ";
-            $checked = 1;
-        }
-        $result .=
-            " value='" . HTML::Entities::encode($choice->[0] . ':' 
-						.$choice->[2] . ':' 
-						.$choice->[1] . ':' 
-						.$choice->[3], "<>&\"'")
-            . "' /></td><td>"
-            . HTML::Entities::encode($choice->[1],'<>&"')
-            . "</td><td align='center'>" 
-            . HTML::Entities::encode($choice->[2],'<>&"')
-            . "</td>\n<td>" 
-	    . HTML::Entities::encode($choice->[3],'<>&"')
-            . "</td>\n<td>" 
-	    . HTML::Entities::encode($choice->[4],'<>&"')
-            . "</td>\n<td>" 
-	    . HTML::Entities::encode($choice->[0],'<>&"')
-	    . "</td></tr>\n";
+
+    # If activeonly is not set then we can also give the expired students:
+    #
+    if (!$self->{'activeonly'} && ((scalar @$expired_members) > 0)) {
+
+	# And future.
+
+	$result .= &Apache::lonselstudent::render_student_list( $future_members,
+								"helpform",
+								"future",
+								\%defaultUsers,
+								$self->{'multichoice'},
+								$self->{'variable'},
+								0);
+	# Past 
+
+	$result .= &Apache::lonselstudent::render_student_list($expired_members,
+							       "helpform",
+							       "past",
+							       \%defaultUsers,
+							       $self->{'multichoice'},
+							       $self->{'variable'},
+							       0);
     }
 
-    $result .= "</table>\n\n";
-    $result .= $buttons;    
-    
+
+
     return $result;
 }
 
 sub postprocess {
     my $self = shift;
 
-    my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
-    if (!$result) {
-        $self->{ERROR_MSG} = 
-	    &mt('You must choose at least one student to continue.');
+    my $result = $env{'form.' . $self->{'variable'} . '.forminput'};
+    if (!$result && !$self->{'emptyallowed'}) {
+	if ($self->{'coursepersonnel'}) {
+	    $self->{ERROR_MSG} = 
+		&mt('You must choose at least one user to continue.');
+	} else {
+	    $self->{ERROR_MSG} = 
+		&mt('You must choose at least one student to continue.');
+	}
         return 0;
     }
 
@@ -2387,7 +2471,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
-
+use Apache::lonnet;
 use Apache::lonpubdir; # for getTitleString
 
 BEGIN {
@@ -2492,7 +2576,8 @@ sub render {
 
     if ($self->{'multichoice'}) {
         $result = <<SCRIPT;
-<script>
+<script type="text/javascript">
+// <!--
     function checkall(value, checkName) {
 	for (i=0; i<document.forms.helpform.elements.length; i++) {
             ele = document.forms.helpform.elements[i];
@@ -2510,6 +2595,7 @@ sub render {
             }
         }
     }
+// -->
 </script>
 SCRIPT
        my %lt=&Apache::lonlocal::texthash(
@@ -2539,19 +2625,21 @@ BUTTONS
     # If the subdirectory is in local CSTR space
     my $metadir;
     if ($subdir =~ m|/home/([^/]+)/public_html/(.*)|) {
-        my $user = $1;
-        my $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
+	my ($user,$domain)= 
+	    &Apache::loncacc::constructaccess($subdir,
+				     $Apache::lonnet::perlvar{'lonDefDomain'});
 	$metadir='/res/'.$domain.'/'.$user.'/'.$2;
         @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, '');
     } elsif ($subdir =~ m|^~([^/]+)/(.*)$|) {
 	$subdir='/home/'.$1.'/public_html/'.$2;
-        my $user = $1;
-        my $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
+	my ($user,$domain)= 
+	    &Apache::loncacc::constructaccess($subdir,
+				     $Apache::lonnet::perlvar{'lonDefDomain'});
 	$metadir='/res/'.$domain.'/'.$user.'/'.$2;
         @fileList = &Apache::lonnet::dirlist($subdir, $domain, $user, '');
     } else {
         # local library server resource space
-        @fileList = &Apache::lonnet::dirlist($subdir, $ENV{'user.domain'}, $ENV{'user.name'}, '');
+        @fileList = &Apache::lonnet::dirlist($subdir, $env{'user.domain'}, $env{'user.name'}, '');
     }
 
     # Sort the fileList into order
@@ -2613,7 +2701,7 @@ BUTTONS
             . ".forminput' ".qq{id="$id"}." value='" . HTML::Entities::encode($fileName,"<>&\"'").
                 "'";
             if (!$self->{'multichoice'} && $choices == 0) {
-                $result .= ' checked';
+                $result .= ' checked="checked"';
             }
             $result .= "/></td><td bgcolor='$color'>".
                 qq{<label for="$id">}. $file . "</label></td>" .
@@ -2644,9 +2732,9 @@ sub fileState {
     my $constructionSpaceDir = shift;
     my $file = shift;
     
-    my ($uname,$udom)=($ENV{'user.name'},$ENV{'user.domain'});
-    if ($ENV{'request.role'}=~/^ca\./) {
-	(undef,$udom,$uname)=split(/\//,$ENV{'request.role'});
+    my ($uname,$udom)=($env{'user.name'},$env{'user.domain'});
+    if ($env{'request.role'}=~/^ca\./) {
+	(undef,$udom,$uname)=split(/\//,$env{'request.role'});
     }
     my $docroot = $Apache::lonnet::perlvar{'lonDocRoot'};
     my $subdirpart = $constructionSpaceDir;
@@ -2671,7 +2759,7 @@ sub fileState {
 
 sub postprocess {
     my $self = shift;
-    my $result = $ENV{'form.' . $self->{'variable'} . '.forminput'};
+    my $result = $env{'form.' . $self->{'variable'} . '.forminput'};
     if (!$result) {
         $self->{ERROR_MSG} = 'You must choose at least one file '.
             'to continue.';
@@ -2696,8 +2784,12 @@ package Apache::lonhelper::section;
 <section> allows the user to choose one or more sections from the current
 course.
 
-It takes the standard attributes "variable", "multichoice", and
-"nextstate", meaning what they do for most other elements.
+It takes the standard attributes "variable", "multichoice",
+"allowempty" and "nextstate", meaning what they do for most other
+elements.
+
+also takes a boolean 'onlysections' whcih will restrict this to only
+have sections and not include groups
 
 =cut
 
@@ -2727,6 +2819,7 @@ sub start_section {
     $paramHash->{'variable'} = $token->[2]{'variable'};
     $helper->declareVar($paramHash->{'variable'});
     $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
+    $paramHash->{'allowempty'} = $token->[2]{'allowempty'};
     if (defined($token->[2]{'nextstate'})) {
         $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
     }
@@ -2736,18 +2829,29 @@ sub start_section {
 
     my $section = Apache::loncoursedata::CL_SECTION();
     my $classlist = Apache::loncoursedata::get_classlist();
-    foreach (keys %$classlist) {
-        my $sectionName = $classlist->{$_}->[$section];
-        if (!$sectionName) {
+    foreach my $user (keys(%$classlist)) {
+        my $section_name = $classlist->{$user}[$section];
+        if (!$section_name) {
             $choices{"No section assigned"} = "";
         } else {
-            $choices{$sectionName} = $sectionName;
+            $choices{$section_name} = $section_name;
         }
     } 
    
-    for my $sectionName (sort(keys(%choices))) {
-        
-        push @{$paramHash->{CHOICES}}, [$sectionName, $sectionName];
+    if (exists($choices{"No section assigned"})) {
+	push(@{$paramHash->{CHOICES}}, 
+	     ['No section assigned','No section assigned']);
+	delete($choices{"No section assigned"});
+    }
+    for my $section_name (sort {lc($a) cmp lc($b) } (keys(%choices))) {
+	push @{$paramHash->{CHOICES}}, [$section_name, $section_name];
+    }
+    return if ($token->[2]{'onlysections'});
+
+    # add in groups to the end of the list
+    my %curr_groups = &Apache::longroup::coursegroups();
+    foreach my $group_name (sort(keys(%curr_groups))) {
+	push(@{$paramHash->{CHOICES}}, [$group_name, $group_name]);
     }
 }    
 
@@ -2761,6 +2865,70 @@ sub end_section {
 }    
 1;
 
+package Apache::lonhelper::group;
+
+=pod
+ 
+=head2 Element: groupX<group, helper element>
+ 
+<group> allows the user to choose one or more groups from the current course.
+
+It takes the standard attributes "variable", "multichoice",
+ "allowempty" and "nextstate", meaning what they do for most other
+ elements.
+
+=cut
+
+no strict;
+@ISA = ("Apache::lonhelper::choices");
+use strict;
+
+BEGIN {
+    &Apache::lonhelper::register('Apache::lonhelper::group',
+                                 ('group'));
+}
+
+sub new {
+    my $ref = Apache::lonhelper::choices->new();
+    bless($ref);
+}
+ 
+sub start_group {
+    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
+ 
+    if ($target ne 'helper') {
+        return '';
+    }
+
+    $paramHash->{CHOICES} = [];
+
+    $paramHash->{'variable'} = $token->[2]{'variable'};
+    $helper->declareVar($paramHash->{'variable'});
+    $paramHash->{'multichoice'} = $token->[2]{'multichoice'};
+    $paramHash->{'allowempty'} = $token->[2]{'allowempty'};
+    if (defined($token->[2]{'nextstate'})) {
+        $paramHash->{NEXTSTATE} = $token->[2]{'nextstate'};
+    }
+
+    # Populate the CHOICES element
+    my %choices;
+
+    my %curr_groups = &Apache::longroup::coursegroups();
+    foreach my $group_name (sort {lc($a) cmp lc($b)} (keys(%curr_groups))) {
+	push(@{$paramHash->{CHOICES}}, [$group_name, $group_name]);
+    }
+}
+
+sub end_group {
+    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
+
+    if ($target ne 'helper') {
+        return '';
+    }
+    Apache::lonhelper::group->new();
+}
+1;
+
 package Apache::lonhelper::string;
 
 =pod
@@ -2824,7 +2992,7 @@ sub render {
     my $result = '';
 
     if (defined $self->{ERROR_MSG}) {
-        $result .= '<br /><font color="#FF0000">' . $self->{ERROR_MSG} . '</font><br /><br />';
+        $result .= '<p><font color="#FF0000">' . $self->{ERROR_MSG} . '</font></p>';
     }
 
     $result .= '<input type="string" name="' . $self->{'variable'} . '.forminput"';
@@ -2854,7 +3022,7 @@ sub postprocess {
 
     if (defined($self->{VALIDATOR})) {
 	my $validator = eval($self->{VALIDATOR});
-	die 'Died during evaluation of evaulation code; Perl said: ' . $@ if $@;
+	die 'Died during evaluation of validator code; Perl said: ' . $@ if $@;
 	my $invalid = &$validator($helper, $state, $self, $self->getValue());
 	if ($invalid) {
 	    $self->{ERROR_MSG} = $invalid;
@@ -2878,7 +3046,7 @@ package Apache::lonhelper::general;
 =head2 General-purpose tag: <exec>X<exec, helper tag>
 
 The contents of the exec tag are executed as Perl code, B<not> inside a 
-safe space, so the full range of $ENV and such is available. The code
+safe space, so the full range of $env and such is available. The code
 will be executed as a subroutine wrapped with the following code:
 
 "sub { my $helper = shift; my $state = shift;" and
@@ -2900,6 +3068,7 @@ be able to call methods on it.
 =cut
 
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::general',
@@ -3031,6 +3200,7 @@ no strict;
 @ISA = ("Apache::lonhelper::element");
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::final',
                                  ('final', 'exitpage'));
@@ -3126,26 +3296,29 @@ sub render {
     my $targetURL = '';
     my $finish=&mt('Finish');
     if ($self->{'restartCourse'}) {
-	my $actionURL = '/adm/roles';
+	$actionURL = '/adm/roles';
 	$targetURL = '/adm/menu';
-	if ($ENV{'course.'.$ENV{'request.course.id'}.'.url'}=~/^uploaded/) {
+	if ($env{'course.'.$env{'request.course.id'}.'.url'}=~/^uploaded/) {
 	    $targetURL = '/adm/coursedocs';
 	} else {
 	    $targetURL = '/adm/navmaps';
 	}
-	if ($ENV{'course.'.$ENV{'request.course.id'}.'.clonedfrom'}) {
+	if ($env{'course.'.$env{'request.course.id'}.'.clonedfrom'}) {
 	    $targetURL = '/adm/parmset?overview=1';
 	}
 	my $finish=&mt('Finish Course Initialization');
     }
     my $previous = HTML::Entities::encode(&mt("<- Previous"), '<>&"');
     my $next = HTML::Entities::encode(&mt("Next ->"), '<>&"');
+    my $target = " target='loncapaclient'";
+    if (($env{'browser.interface'} eq 'textual') ||
+        ($env{'environment.remote'} eq 'off')) {  $target='';  }
     $result .= "<center>\n" .
-	"<form action='".$actionURL."' method='post' target='loncapaclient'>\n" .
+	"<form action='".$actionURL."' method='post' $target>\n" .
 	"<input type='button' onclick='history.go(-1)' value='$previous' />" .
 	"<input type='hidden' name='orgurl' value='$targetURL' />" .
 	"<input type='hidden' name='selectrole' value='1' />\n" .
-	"<input type='hidden' name='" . $ENV{'request.role'} . 
+	"<input type='hidden' name='" . $env{'request.role'} . 
 	"' value='1' />\n<input type='submit' value='" . $finish . "' />\n" .
 	"</form></center>";
 
@@ -3169,6 +3342,7 @@ no strict;
 @ISA = ('Apache::lonhelper::element');
 use strict;
 use Apache::lonlocal;
+use Apache::lonnet;
 
 BEGIN {
     &Apache::lonhelper::register('Apache::lonhelper::parmwizfinal',
@@ -3210,6 +3384,11 @@ sub render {
                         'answer_date' => "0_answerdate",
 			'tries' => '0_maxtries',
 			'weight' => '0_weight' );
+    my %realParmName = ('open_date' => "opendate",
+                        'due_date' => "duedate",
+                        'answer_date' => "answerdate",
+			'tries' => 'maxtries',
+			'weight' => 'weight' );
     
     my $affectedResourceId = "";
     my $parm_name = $parmTypeHash{$vars->{ACTION_TYPE}};
@@ -3217,11 +3396,19 @@ sub render {
     my $resourceString;
     my $symb;
     my $paramlevel;
-
+    
     # Print the granularity, depending on the action
     if ($vars->{GRANULARITY} eq 'whole_course') {
         $resourceString .= '<li>'.&mt('for <b>all resources in the course</b>').'</li>';
-        $level = 9; # general course, see lonparmset.pm perldoc
+	if ($vars->{TARGETS} eq 'course') {
+	    $level = 14; # general course, see lonparmset.pm perldoc
+	} elsif ($vars->{TARGETS} eq 'section') {
+	    $level = 9;
+	} elsif ($vars->{TARGETS} eq 'group') {
+	    $level = 6;
+	} else {
+	    $level = 3;
+	}
         $affectedResourceId = "0.0";
         $symb = 'a';
         $paramlevel = 'general';
@@ -3231,21 +3418,55 @@ sub render {
         my $title = $res->compTitle();
         $symb = $res->symb();
         $resourceString .= '<li>'.&mt('for the map named [_1]',"<b>$title</b>").'</li>';
-        $level = 8;
+	if ($vars->{TARGETS} eq 'course') {
+	    $level = 13; # general course, see lonparmset.pm perldoc
+	} elsif ($vars->{TARGETS} eq 'section') {
+	    $level = 8;
+	} elsif ($vars->{TARGETS} eq 'group') {
+	    $level = 5;
+	} else {
+	    $level = 2;
+	}
         $affectedResourceId = $vars->{RESOURCE_ID};
         $paramlevel = 'map';
     } else {
         my $navmap = Apache::lonnavmaps::navmap->new();
         my $res = $navmap->getById($vars->{RESOURCE_ID});
+        my $part = $vars->{RESOURCE_ID_part};
+	if ($part ne 'All Parts' && $part) { $parm_name=~s/^0/$part/; } else { $part=&mt('All Parts'); }
         $symb = $res->symb();
         my $title = $res->compTitle();
-        $resourceString .= '<li>'.&mt('for the resource named [_1]',"<b>$title</b>").'</li>';
-        $level = 7;
+        $resourceString .= '<li>'.&mt('for the resource named [_1] part [_2]',"<b>$title</b>","<b>$part</b>").'</li>';
+	if ($vars->{TARGETS} eq 'course') {
+	    $level = 10; # general course, see lonparmset.pm perldoc
+	} elsif ($vars->{TARGETS} eq 'section') {
+	    $level = 7;
+	} elsif ($vars->{TARGETS} eq 'group') {
+	    $level = 4;
+	} else {
+	    $level = 1;
+	}
         $affectedResourceId = $vars->{RESOURCE_ID};
         $paramlevel = 'full';
     }
 
-    my $result = "<form name='helpform' method='get' action='/adm/parmset#$affectedResourceId&$parm_name&$level'>\n";
+    my $result = "<form name='helpform' method='POST' action='/adm/parmset#$affectedResourceId&$parm_name&$level'>\n";
+    $result .= "<input type='hidden' name='action' value='settable' />\n";
+    $result .= "<input type='hidden' name='dis' value='helper' />\n";
+    $result .= "<input type='hidden' name='pscat' value='".
+	$realParmName{$vars->{ACTION_TYPE}}."' />\n";
+    if ($vars->{GRANULARITY} eq 'resource') {
+	$result .= "<input type='hidden' name='symb' value='".
+	    HTML::Entities::encode($symb,"'<>&\"") . "' />\n";
+    } elsif ($vars->{GRANULARITY} eq 'map') {
+	$result .= "<input type='hidden' name='pschp' value='".
+	    $affectedResourceId."' />\n";
+    }
+    my $part = $vars->{RESOURCE_ID_part};
+    if ($part eq 'All Parts' || !$part) { $part=0; }
+    $result .= "<input type='hidden' name='psprt' value='".
+	HTML::Entities::encode($part,"'<>&\"") . "' />\n";
+
     $result .= '<p>'.&mt('Confirm that this information is correct, then click &quot;Finish Helper&quot; to complete setting the parameter.').'<ul>';
     
     # Print the type of manipulation:
@@ -3283,6 +3504,8 @@ sub render {
     } elsif ($vars->{ACTION_TYPE} eq 'tries') {
 	$result .= "<input type='hidden' name='pres_value' " .
 	    "value='" . $vars->{TRIES} . "' />\n";
+        $result .= "<input type='hidden' name='pres_type' " .
+            "value='int_pos' />\n";
     } elsif ($vars->{ACTION_TYPE} eq 'weight') {
 	$result .= "<input type='hidden' name='pres_value' " .
 	    "value='" . $vars->{WEIGHT} . "' />\n";
@@ -3296,19 +3519,19 @@ sub render {
     } elsif ($vars->{TARGETS} eq 'section') {
         my $section = $vars->{SECTION_NAME};
         $result .= '<li>'.&mt('for section [_1]',"<b>$section</b>").'</li>';
-        $level -= 3;
-        $result .= "<input type='hidden' name='csec' value='" .
+	$result .= "<input type='hidden' name='csec' value='" .
             HTML::Entities::encode($section,"'<>&\"") . "' />\n";
+    } elsif ($vars->{TARGETS} eq 'group') {
+        my $group = $vars->{GROUP_NAME};
+        $result .= '<li>'.&mt('for group [_1]',"<b>$group</b>").'</li>';
+        $result .= "<input type='hidden' name='cgroup' value='" .
+            HTML::Entities::encode($group,"'<>&\"") . "' />\n";
     } else {
         # FIXME: This is probably wasteful! Store the name!
         my $classlist = Apache::loncoursedata::get_classlist();
-        my $username = $vars->{USER_NAME};
-        # Chop off everything after the last colon (section)
-        $username = substr($username, 0, rindex($username, ':'));
-        my $name = $classlist->{$username}->[6];
+	my ($uname,$udom)=split(':',$vars->{USER_NAME});
+        my $name = $classlist->{$uname.':'.$udom}->[6];
         $result .= '<li>'.&mt('for [_1]',"<b>$name</b>").'</li>';
-        $level -= 6;
-        my ($uname, $udom) = split /:/, $vars->{USER_NAME};
         $result .= "<input type='hidden' name='uname' value='".
             HTML::Entities::encode($uname,"'<>&\"") . "' />\n";
         $result .= "<input type='hidden' name='udom' value='".
@@ -3326,7 +3549,6 @@ sub render {
     
     # Make the table appear
     $result .= "\n<input type='hidden' value='true' name='prevvisit' />";
-    $result .= "\n<input type='hidden' value='all' name='pschp' />";
     $result .= "\n<input type='hidden' value='$symb' name='pssymb' />";
     $result .= "\n<input type='hidden' value='$paramlevel' name='parmlev' />";