--- loncom/homework/grades.pm	2005/01/16 08:28:32	1.238
+++ loncom/homework/grades.pm	2005/02/12 02:37:00	1.243
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.238 2005/01/16 08:28:32 albertel Exp $
+# $Id: grades.pm,v 1.243 2005/02/12 02:37:00 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2655,15 +2655,17 @@ sub csvupload_javascript_reverse_associa
   function verify(vf) {
     var foundsomething=0;
     var founduname=0;
+    var foundID=0;
     var founddomain=0;
     for (i=0;i<=vf.nfields.value;i++) {
       tw=eval('vf.f'+i+'.selectedIndex');
-      if (i==0 && tw!=0) { founduname=1; }
-      if (i==1 && tw!=0) { founddomain=1; }
-      if (i!=0 && i!=1 && tw!=0) { foundsomething=1; }
+      if (i==0 && tw!=0) { foundID=1; }
+      if (i==1 && tw!=0) { founduname=1; }
+      if (i==2 && tw!=0) { founddomain=1; }
+      if (i!=0 && i!=1 && i!=2 && tw!=0) { foundsomething=1; }
     }
-    if (founduname==0 || founddomain==0) {
-      alert('You need to specify at both the username and domain');
+    if ((founduname==0 && foundID==0) || founddomain==0) {
+      alert('You need to specify the domain and either the username or ID');
       return;
     }
     if (foundsomething==0) {
@@ -2693,15 +2695,17 @@ sub csvupload_javascript_forward_associa
   function verify(vf) {
     var foundsomething=0;
     var founduname=0;
+    var foundID=0;
     var founddomain=0;
     for (i=0;i<=vf.nfields.value;i++) {
       tw=eval('vf.f'+i+'.selectedIndex');
-      if (tw==1) { founduname=1; }
-      if (tw==2) { founddomain=1; }
-      if (tw>2) { foundsomething=1; }
+      if (tw==1) { foundID=1; }
+      if (tw==2) { founduname=1; }
+      if (tw==3) { founddomain=1; }
+      if (tw>3) { foundsomething=1; }
     }
-    if (founduname==0 || founddomain==0) {
-      alert('You need to specify at both the username and domain');
+    if ((founduname==0 && foundID==0) || founddomain==0) {
+      alert('You need to specify the domain and either the username or ID');
       return;
     }
     if (foundsomething==0) {
@@ -2768,7 +2772,9 @@ ENDPICK
 sub csvupload_fields {
     my ($url,$symb) = @_;
     my (@parts) = &getpartlist($url,$symb);
-    my @fields=(['username','Student Username'],['domain','Student Domain']);
+    my @fields=(['ID','Student ID'],
+		['username','Student Username'],
+		['domain','Student Domain']);
     foreach my $part (sort(@parts)) {
 	my @datum;
 	my $display=&Apache::lonnet::metadata($url,$part.'.display');
@@ -2899,10 +2905,15 @@ sub csvuploadassign {
     my $countdone=0;
     foreach my $grade (@gradedata) {
 	my %entries=&Apache::loncommon::record_sep($grade);
-	my $username=$entries{$fields{'username'}};
-	$username=~s/\s//g;
 	my $domain=$entries{$fields{'domain'}};
 	$domain=~s/\s//g;
+	my $username=$entries{$fields{'username'}};
+	$username=~s/\s//g;
+	if (!$username) {
+	    my $id=$entries{$fields{'ID'}};
+	    my %ids=&Apache::lonnet::idget($domain,$id);
+	    $username=$ids{$id};
+	}
 	if (!exists($$classlist{"$username:$domain"})) {
 	    push(@skipped,"$username:$domain");
 	    next;
@@ -3060,7 +3071,8 @@ sub getSymbMap {
     my $minder = 0;
 
     # Gather every sequence that has problems.
-    my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); }, 1);
+    my @sequences = $navmap->retrieveResources(undef, sub { shift->is_map(); },
+					       1,0,1);
     for my $sequence ($navmap->getById('0.0'), @sequences) {
 	if ($navmap->hasResource($sequence, sub { shift->is_problem(); }, 0) ) {
 	    my $title = $minder.'.'.$sequence->compTitle();
@@ -3796,25 +3808,49 @@ sub scantron_parse_scanline {
 	my $currentquest=substr($questions,0,$$scantron_config{'Qlength'});
 	substr($questions,0,$$scantron_config{'Qlength'})='';
 	if (length($currentquest) < $$scantron_config{'Qlength'}) { next; }
-	my @array=split($$scantron_config{'Qon'},$currentquest,-1);
-	if (length($array[0]) eq $$scantron_config{'Qlength'}) {
-	    $record{"scantron.$questnum.answer"}='';
-	    if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
-		push(@{$record{"scantron.missingerror"}},$questnum);
- 	    }
+	if ($$scantron_config{'Qon'} eq 'letter') {
+	    if (!$currentquest || $currentquest eq $$scantron_config{'Qoff'} ||
+		$currentquest !~ /^[A-Z]$/) {
+		$record{"scantron.$questnum.answer"}='';
+		if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
+		    push(@{$record{"scantron.missingerror"}},$questnum);
+		}
+	    } else {
+		$record{"scantron.$questnum.answer"}=$currentquest;
+	    }
+	} elsif ($$scantron_config{'Qon'} eq 'number') {
+	    if (!$currentquest || $currentquest eq $$scantron_config{'Qoff'} ||
+		$currentquest !~ /^\d$/) {
+		$record{"scantron.$questnum.answer"}='';
+		if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
+		    push(@{$record{"scantron.missingerror"}},$questnum);
+		}
+	    } else {
+		$record{"scantron.$questnum.answer"}=
+		    $alphabet[$currentquest-1];
+	    }
 	} else {
-	    $record{"scantron.$questnum.answer"}=$alphabet[length($array[0])];
+	    my @array=split($$scantron_config{'Qon'},$currentquest,-1);
+	    if (length($array[0]) eq $$scantron_config{'Qlength'}) {
+		$record{"scantron.$questnum.answer"}='';
+		if (!&scan_data($scan_data,"$whichline.no_bubble.$questnum")) {
+		    push(@{$record{"scantron.missingerror"}},$questnum);
+		}
+	    } else {
+		$record{"scantron.$questnum.answer"}=
+		    $alphabet[length($array[0])];
+	    }
+	    if (scalar(@array) gt 2) {
+		push(@{$record{'scantron.doubleerror'}},$questnum);
+		my @ans=@array;
+		my $i=length($ans[0]);shift(@ans);
+		while ($#ans) {
+		    $i+=length($ans[0])+1;
+		    $record{"scantron.$questnum.answer"}.=$alphabet[$i];
+		    shift(@ans);
+		}
+	    }
 	}
- 	if (scalar(@array) gt 2) {
- 	    push(@{$record{'scantron.doubleerror'}},$questnum);
- 	    my @ans=@array;
- 	    my $i=length($ans[0]);shift(@ans);
-	    while ($#ans) {
- 		$i+=length($ans[0])+1;
- 		$record{"scantron.$questnum.answer"}.=$alphabet[$i];
- 		shift(@ans);
- 	    }
- 	}
     }
     $record{'scantron.maxquest'}=$questnum;
     return \%record;
@@ -4301,6 +4337,12 @@ sub scantron_get_correction {
 	$r->print(" in scanline $i <pre>".
 		  $line."</pre> \n");
     }
+    my $message="<p>The ID on the form is  <tt>".
+	$$scan_record{'scantron.ID'}."</tt><br />\n".
+	"The name on the paper is ".
+	$$scan_record{'scantron.LastName'}.",".
+	$$scan_record{'scantron.FirstName'}."</p>";
+
     $r->print('<input type="hidden" name="scantron_corrections" value="'.$error.'" />'."\n");
     $r->print('<input type="hidden" name="scantron_line" value="'.$i.'" />'."\n");
     if ($error =~ /ID$/) {
@@ -4309,11 +4351,7 @@ sub scantron_get_correction {
 	} elsif ($error eq 'duplicateID') {
 	    $r->print("The encoded ID has also been used by a previous paper $arg</p>\n");
 	}
-	$r->print("<p>The ID on the form is  <tt>".
-		  $$scan_record{'scantron.ID'}."</tt><br />\n");
-	$r->print("The name on the paper is ".
-		  $$scan_record{'scantron.LastName'}.",".
-		  $$scan_record{'scantron.FirstName'}."</p>");
+	$r->print($message);
 	$r->print("<p>How should I handle this? <br /> \n");
 	$r->print("\n<ul><li> ");
 	#FIXME it would be nice if this sent back the user ID and
@@ -4333,11 +4371,7 @@ sub scantron_get_correction {
 	}
 	$r->print("<p>The CODE on the form is  <tt>'".
 		  $$scan_record{'scantron.CODE'}."'</tt><br />\n");
-	$r->print("<p>The ID on the form is  <tt>".
-		  $$scan_record{'scantron.ID'}."</tt><br />\n");
-	$r->print("The name on the paper is ".
-		  $$scan_record{'scantron.LastName'}.",".
-		  $$scan_record{'scantron.FirstName'}."</p>");
+	$r->print($message);
 	$r->print("<p>How should I handle this? <br /> \n");
 	$r->print("\n<br /> ");
 	my $i=0;
@@ -4380,6 +4414,7 @@ ENDSCRIPT
 	$r->print("<p>There have been multiple bubbles scanned for a some question(s)</p>\n");
 	$r->print('<input type="hidden" name="scantron_questions" value="'.
 		  join(',',@{$arg}).'" />');
+	$r->print($message);
 	$r->print("<p>Please indicate which bubble should be used for grading</p>");
 	foreach my $question (@{$arg}) {
 	    my $selected=$$scan_record{"scantron.$question.answer"};
@@ -4387,6 +4422,7 @@ ENDSCRIPT
 	}
     } elsif ($error eq 'missingbubble') {
 	$r->print("<p>There have been <b>no</b> bubbles scanned for some question(s)</p>\n");
+	$r->print($message);
 	$r->print("<p>Please indicate which bubble should be used for grading</p>");
 	$r->print("Some questions have no scanned bubbles\n");
 	$r->print('<input type="hidden" name="scantron_questions" value="'.