[LON-CAPA-cvs] cvs: loncom /homework grades.pm

albertel lon-capa-cvs-allow@mail.lon-capa.org
Tue, 24 Jul 2007 21:21:33 -0000


This is a MIME encoded message

--albertel1185312093
Content-Type: text/plain

albertel		Tue Jul 24 17:21:33 2007 EDT

  Modified files:              
    /loncom/homework	grades.pm 
  Log:
  - first pass at documenting the scantron process plenty more to do
  
  
--albertel1185312093
Content-Type: text/plain
Content-Disposition: attachment; filename="albertel-20070724172133.txt"

Index: loncom/homework/grades.pm
diff -u loncom/homework/grades.pm:1.422 loncom/homework/grades.pm:1.423
--- loncom/homework/grades.pm:1.422	Thu Jul 19 05:52:59 2007
+++ loncom/homework/grades.pm	Tue Jul 24 17:21:31 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.422 2007/07/19 09:52:59 foxr Exp $
+# $Id: grades.pm,v 1.423 2007/07/24 21:21:31 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -3827,7 +3827,7 @@
 
     $result.='<form action="/adm/grades" method="post" name="displayPage">'."\n";
     $result.='&nbsp;<b>Problems from:</b> <select name="selectpage">'."\n";
-    my ($titles,$symbx) = &getSymbMap($request);
+    my ($titles,$symbx) = &getSymbMap();
     my ($curpage) =&Apache::lonnet::decode_symb($symb); 
 #    my ($curpage,$mapId) =&Apache::lonnet::decode_symb($symb); 
 #    my $type=($curpage =~ /\.(page|sequence)/);
@@ -3909,7 +3909,6 @@
 }
 
 sub getSymbMap {
-    my ($request) = @_;
     my $navmap = Apache::lonnavmaps::navmap->new();
 
     my %symbx = ();
@@ -4354,7 +4353,29 @@
 #
 #------ start of section for handling grading by page/sequence ---------
 
-# Create the hidden field entries used to hold context/default values.
+=pod
+
+=head1 Bubble sheet grading routines
+
+  (For this documentation 'scanline' refers to the full line of characters
+   from the file that we are parsing 'bubble line' refers to the data
+   representing the line of bubbles that are on the physical bubble sheet)
+
+=over 4
+
+=cut
+
+
+=pod 
+
+=item defaultFormData
+
+  Returns html hidden inputs used to hold context/default values.
+
+ Arguments:
+  $symb - $symb of the current resource 
+
+=cut
 
 sub defaultFormData {
     my ($symb)=@_;
@@ -4364,12 +4385,21 @@
      '<input type="hidden" name="probTitle" value="'.$env{'form.probTitle'}.'" />'."\n";
 }
 
-# Make a drop down of the sequences
+=pod 
+
+=item getSequenceDropDown
+
+   Return html dropdown of possible sequences to grade
+ 
+ Arguments:
+   $symb - $symb of the current resource 
+
+=cut
 
 sub getSequenceDropDown {
-    my ($request,$symb)=@_;
+    my ($symb)=@_;
     my $result='<select name="selectpage">'."\n";
-    my ($titles,$symbx) = &getSymbMap($request);
+    my ($titles,$symbx) = &getSymbMap();
     my ($curpage)=&Apache::lonnet::decode_symb($symb); 
     my $ctr=0;
     foreach (@$titles) {
@@ -4383,7 +4413,14 @@
     return $result;
 }
 
-# Returns a list of the scantron files that have been uploaded to date.
+
+=pod 
+
+=item scantron_filenames
+
+   Returns a list of the scantron files in the current course 
+
+=cut
 
 sub scantron_filenames {
     my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -4400,8 +4437,16 @@
     return @possiblenames;
 }
 
-# Returns the html required for a drop-down list of scantron
-# files that have been uploaded.
+=pod 
+
+=item scantron_uploads
+
+   Returns  html drop-down list of scantron files in current course.
+
+ Arguments:
+   $file2grade - filename to set as selected in the dropdown
+
+=cut
 
 sub scantron_uploads {
     my ($file2grade) = @_;
@@ -4414,8 +4459,14 @@
     return $result;
 }
 
-# Returns the html for a drop down list of the scantron formats in the
-# scantronformat.tab file.
+=pod 
+
+=item scantron_scantab
+
+  Returns html drop down of the scantron formats in the scantronformat.tab
+  file.
+
+=cut
 
 sub scantron_scantab {
     my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.'/scantronformat.tab');
@@ -4431,8 +4482,14 @@
     return $result;
 }
 
-#  Returns the html for the options in the
-#  saved codes dropdown.
+=pod 
+
+=item scantron_CODElist
+
+  Returns html drop down of the saved CODE lists from current course,
+  generated from earlier printings.
+
+=cut
 
 sub scantron_CODElist {
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -4448,30 +4505,48 @@
     return $namechoice;
 }
 
-# Returns the HTML for "Each CODE to be used once" radio.
+=pod 
+
+=item scantron_CODEunique
+
+  Returns the html for "Each CODE to be used once" radio.
+
+=cut
 
 sub scantron_CODEunique {
     my $result='<span style="white-space: nowrap;">
                  <label><input type="radio" name="scantron_CODEunique"
-                        value="yes" checked="checked" /> Yes </label>
+                        value="yes" checked="checked" />'.&mt('Yes').' </label>
                 </span>
                 <span style="white-space: nowrap;">
                  <label><input type="radio" name="scantron_CODEunique"
-                        value="no" /> No </label>
+                        value="no" />'.&mt('No').' </label>
                 </span>';
     return $result;
 }
-#
-#    Display the first scantron file selection form.
-# Paramters:
-#    r           - The apache request object
-#    file2grade  - The name of the scantron file to be graded(?).
+
+=pod 
+
+=item scantron_selectphase
+
+  Generates the initial screen to start the bubble sheet process.
+  Allows for - starting a grading run.
+             - downloading exisiting scan data (original, corrected
+                                                or skipped info)
+
+             - uploading new scan data
+
+ Arguments:
+  $r          - The Apache request object
+  $file2grade - name of the file that contain the scanned data to score
+
+=cut
 
 sub scantron_selectphase {
     my ($r,$file2grade) = @_;
     my ($symb)=&get_symb($r);
     if (!$symb) {return '';}
-    my $sequence_selector=&getSequenceDropDown($r,$symb);
+    my $sequence_selector=&getSequenceDropDown($symb);
     my $default_form_data=&defaultFormData($symb);
     my $grading_menu_button=&show_grading_menu_form($symb);
     my $file_selector=&scantron_uploads($file2grade);
@@ -4479,8 +4554,6 @@
     my $CODE_selector=&scantron_CODElist();
     my $CODE_unique=&scantron_CODEunique();
     my $result;
-    #FIXME allow instructor to be able to download the scantron file
-    # and to upload it,
 
     # Chunk of form to prompt for a file to grade and how:
 
@@ -4621,13 +4694,61 @@
     return
 }
 
-# Parse and return the scantron configuration line selected as a
-# hash of configuration file fields.
-#
-# Parameters:
-#   which - the name of the configuration to parse from the file.
-#           If the named configuration is not in the file, an empty
-#           hash is returned.
+=pod
+
+=item get_scantron_config
+
+   Parse and return the scantron configuration line selected as a
+   hash of configuration file fields.
+
+ Arguments:
+    which - the name of the configuration to parse from the file.
+
+
+ Returns:
+            If the named configuration is not in the file, an empty
+            hash is returned.
+    a hash with the fields
+      name         - internal name for the this configuration setup
+      description  - text to display to operator that describes this config
+      CODElocation - if 0 or the string 'none'
+                          - no CODE exists for this config
+                     if -1 || the string 'letter'
+                          - a CODE exists for this config and is
+                            a string of letters
+                     Unsupported value (but planned for future support)
+                          if a positive integer
+                               - The CODE exists as the first n items from
+                                 the question section of the form
+                          if the string 'number'
+                               - The CODE exists for this config and is
+                                 a string of numbers
+      CODEstart   - (only matter if a CODE exists) column in the line where
+                     the CODE starts
+      CODElength  - length of the CODE
+      IDstart     - column where the student ID number starts
+      IDlength    - length of the student ID info
+      Qstart      - column where the information from the bubbled
+                    'questions' start
+      Qlength     - number of columns comprising a single bubble line from
+                    the sheet. (usually either 1 or 10)
+      Qon         - either a single charater representing the character used
+                    to signal a bubble was chosen in the positional setup, or
+                    the string 'letter' if the letter of the chosen bubble is
+                    in the final, or 'number' if a number representing the
+                    chosen bubble is in the file (1->A 0->J)
+      Qoff        - the character used to represent that a buble was left blank
+      PaperID     - if the scanning process generates a unique number for each
+                    sheet scanned the column that this ID number starts in
+      PaperIDlength - number of columns that comprise the unique ID number
+                      for the sheet of paper
+      FirstName   - column that the firs tname starts in
+      FirstNameLength - number of columns that the first name spans
+ 
+      LastName    - column that the last name starts in
+      LastNameLength - number of columns that the last name spans
+
+=cut
 
 sub get_scantron_config {
     my ($which) = @_;
@@ -4661,15 +4782,25 @@
     return %config;
 }
 
-#  creates a hash keyed by student id that conains
-#  the corresponding student username:domain.
-# Parameters:
-#   reference to the class list hash. This is a hash
-#   keyed by student name:domain  whose elements are references
-#   to arrays containng various chunks of information
-#   about the student. (See loncoursedata for more info).
-#
-# 
+=pod 
+
+=item username_to_idmap
+
+    creates a hash keyed by student id with values of the corresponding
+    student username:domain.
+
+  Arguments:
+
+    $classlist - reference to the class list hash. This is a hash
+                 keyed by student name:domain  whose elements are references
+                 to arrays containng various chunks of information
+                 about the student. (See loncoursedata for more info).
+
+  Returns
+    %idmap - the constructed hash
+
+=cut
+
 sub username_to_idmap {
     my ($classlist)= @_;
     my %idmap;
@@ -4679,22 +4810,51 @@
     }
     return %idmap;
 }
-#
-# Make a correction in a scantron line?
-# Parameters:
-#   scantron_config    - Format of the scantron file
-#   scan_data          - Hash of line by line info about the scan(?).
-#   line               - Scantron line to edit?
-#   whichline
-#   field  
-#   args               - Keyword/value hash of additional parameters.
-#
+
+=pod
+
+=item scatron_fixup_scanline
+
+   Process a requested correction to a scanline.
+
+  Arguments:
+    $scantron_config   - hash from &get_scantron_config()
+    $scan_data         - hash of correction information 
+                          (see &scantron_getfile())
+    $line              - existing scanline
+    $whichline         - line number of the passed in scanline
+    $field             - type of change to process 
+                         (either 
+                          'ID'     -> correct the student ID number
+                          'CODE'   -> correct the CODE
+                          'answer' -> fixup the submitted answers)
+    
+   $args               - hash of additional info,
+                          - 'ID' 
+                               'newid' -> studentID to use in replacement
+                                          of exisiting one
+                          - 'CODE' 
+                               'CODE_ignore_dup' - set to true if duplicates
+                                                   should be ignored.
+	                       'CODE' - is new code or 'use_unfound'
+                                        if the exisitng unfound code should
+                                        be used as is
+                          - 'answer'
+                               'response' - new answer or 'none' if blank
+                               'question' - the bubble line to change
+
+  Returns:
+    $line - the modified scanline
+
+  Side effects: 
+    $scan_data - may be updated
+
+=cut
+
 
 sub scantron_fixup_scanline {
     my ($scantron_config,$scan_data,$line,$whichline,$field,$args)=@_;
-    #
-    # ID field, args->{'newid'} is the new value of the ID field.
-    #
+
     if ($field eq 'ID') {
 	if (length($args->{'newid'}) > $$scantron_config{'IDlength'}) {
 	    return ($line,1,'New value too large');
@@ -4709,11 +4869,6 @@
 	    &scan_data($scan_data,"$whichline.user",
 		       $args->{'username'}.':'.$args->{'domain'});
 	}
-	# CODE Field, 
-	#   args->{CODE_ignore_dup} is true if duplicates should be ignored.
-	#   args->{CODE} is new code or 'use_unfound' if an unfound code should
-	#                be used as is?
-	#
     } elsif ($field eq 'CODE') {
 	if ($args->{'CODE_ignore_dup'}) {
 	    &scan_data($scan_data,"$whichline.CODE_ignore_dup",'1');
@@ -4729,11 +4884,6 @@
 	    substr($line,$$scantron_config{'CODEstart'}-1,
 		   $$scantron_config{'CODElength'})=$args->{'CODE'};
 	}
-	#
-	# Edit the answer field.
-	#     args->{'response'} - new answer or 'none' if blank.
-	#     args->{'question'} - the question (number?)?.
-	#
     } elsif ($field eq 'answer') {
 	my $length=$scantron_config->{'Qlength'};
 	my $off=$scantron_config->{'Qoff'};
@@ -4760,16 +4910,26 @@
     }
     return $line;
 }
-# Edit or look up  an item in the scan_data hash.
-# Parameters:
-#   scan_data   - The hash.
-#   key         - shorthand of the key to edit (actual key is
-#                 scatronfilename_key.
-#   data        - New value of the hash entry.
-#   delete      - If defined, the entry is removed from the table.
-# Returns:
-#   The new value of the hash table field (undefined if deleted).
-#
+
+=pod
+
+=item scan_data
+
+    Edit or look up  an item in the scan_data hash.
+
+  Arguments:
+    $scan_data  - The hash (see scantron_getfile)
+    $key        - shorthand of the key to edit (actual key is
+                  scatronfilename_key).
+    $data        - New value of the hash entry.
+    $delete      - If true, the entry is removed from the hash.
+
+  Returns:
+    The new value of the hash table field (undefined if deleted).
+
+=cut
+
+
 sub scan_data {
     my ($scan_data,$key,$value,$delete)=@_;
     my $filename=$env{'form.scantron_selectfile'};
@@ -4779,20 +4939,61 @@
     if ($delete) { delete($scan_data->{$filename.'_'.$key}); }
     return $scan_data->{$filename.'_'.$key};
 }
-#
-#  Decode a line on the uploaded scantron file:
-#  Arguments:
-#    line             - The text of the  scantron file line to process
-#    whichline        - Line number(?)
-#    scantron_config  - Hash describing the format of the scantron lines.
-#    scan_data        - Hash being built up of the entire scantron file.
-#    justHeader       - True if should not process question answers but only
-#                       the stuff to the left of the answers.
-# Returns:
-#   Hash of data from the line?
-#
+
+=pod 
+
+=item scantron_parse_scanline
+
+  Decodes a scanline from the selected scantron file
+
+ Arguments:
+    line             - The text of the scantron file line to process
+    whichline        - Line number
+    scantron_config  - Hash describing the format of the scantron lines.
+    scan_data        - Hash of extra information about the scanline
+                       (see scantron_getfile for more information)
+    just_header      - True if should not process question answers but only
+                       the stuff to the left of the answers.
+ Returns:
+   Hash containing the result of parsing the scanline
+
+   Keys are all proceeded by the string 'scantron.'
+
+       CODE    - the CODE in use for this scanline
+       useCODE - 1 if the CODE is invalid but it usage has been forced
+                 by the operator
+       CODE_ignore_dup - 1 if the CODE is a duplicated use when unique
+                            CODEs were selected, but the usage has been
+                            forced by the operator
+       ID  - student ID
+       PaperID - if used, the ID number printed on the sheet when the 
+                 paper was scanned
+       FirstName - first name from the sheet
+       LastName  - last name from the sheet
+
+     if just_header was not true these key may also exist
+
+       missingerror - a list of bubbled line numbers that had a blank bubble
+                      that is considered an error (if the operator had already
+                      okayed a blank bubble line as really being blank then
+                      that bubble line number won't appear here.
+       doubleerror  - a list of bubbled line numbers that had more than one
+                      bubble filled in and has not been corrected by the
+                      operator
+       maxquest     - the number of the last bubble line that was parsed
+
+       (<number> starts at 1)
+       <number>.answer - zero or more letters representing the selected
+                         letters from the scanline for the bubble line 
+                         <number>.
+                         if blank there was either no bubble or there where
+                         multiple bubbles, (consult the keys missingerror and
+                         doubleerror if this is an error condition)
+
+=cut
+
 sub scantron_parse_scanline {
-    my ($line,$whichline,$scantron_config,$scan_data,$justHeader)=@_;
+    my ($line,$whichline,$scantron_config,$scan_data,$just_header)=@_;
     my %record;
     my $questions=substr($line,$$scantron_config{'Qstart'}-1);  # Answers
     my $data=substr($line,0,$$scantron_config{'Qstart'}-1);     # earlier stuff
@@ -4825,7 +5026,7 @@
     $record{'scantron.LastName'}=
 	substr($data,$$scantron_config{'LastName'}-1,
 	       $$scantron_config{'LastNamelength'});
-    if ($justHeader) { return \%record; }
+    if ($just_header) { return \%record; }
 
     my @alphabet=('A'..'Z');
     my $questnum=0;
@@ -4898,6 +5099,24 @@
     return \%record;
 }
 
+=pod
+
+=item scantron_add_delay
+
+   Adds an error message that occurred during the grading phase to a
+   queue of messages to be shown after grading pass is complete
+
+ Arguments:
+   $delayqueue  - arrary ref of hash ref of erro messages
+   $scanline    - the scanline that caused the error
+   $errormesage - the error message
+   $errorcode   - a numeric code for the error
+
+ Side Effects:
+   updates the $dealyqueue to have a new hash ref of the error
+
+=cut
+
 sub scantron_add_delay {
     my ($delayqueue,$scanline,$errormessage,$errorcode)=@_;
     push(@$delayqueue,
@@ -4906,6 +5125,12 @@
 	 );
 }
 
+=pod
+
+=item scantron_find_student
+
+=cut
+
 sub scantron_find_student {
     my ($scantron_record,$scan_data,$idmap,$line)=@_;
     my $scanID=$$scantron_record{'scantron.ID'};
@@ -4920,6 +5145,12 @@
     return undef;
 }
 
+=pod
+
+=item scantron_filter
+
+=cut
+
 sub scantron_filter {
     my ($curres)=@_;
 
@@ -4936,6 +5167,12 @@
     return 0;
 }
 
+=pod
+
+=item scantron_process_corrections
+
+=cut
+
 sub scantron_process_corrections {
     my ($r) = @_;
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
@@ -4993,12 +5230,24 @@
     }
 }
 
+=pod
+
+=item reset_skipping_status
+
+=cut
+
 sub reset_skipping_status {
     my ($scanlines,$scan_data)=&scantron_getfile();
     &scan_data($scan_data,'remember_skipping',undef,1);
     &scantron_putfile(undef,$scan_data);
 }
 
+=pod
+
+=item start_skipping
+
+=cut
+
 sub start_skipping {
     my ($scan_data,$i)=@_;
     my %remembered=split(':',&scan_data($scan_data,'remember_skipping'));
@@ -5010,6 +5259,12 @@
     &scan_data($scan_data,'remember_skipping',join(':',%remembered));
 }
 
+=pod
+
+=item should_be_skipped
+
+=cut
+
 sub should_be_skipped {
     my ($scanlines,$scan_data,$i)=@_;
     if ($env{'form.scantron_options_redo'} !~ /^redo_/) {
@@ -5025,6 +5280,12 @@
     return 1;
 }
 
+=pod
+
+=item remember_current_skipped
+
+=cut
+
 sub remember_current_skipped {
     my ($scanlines,$scan_data)=&scantron_getfile();
     my %to_remember;
@@ -5038,6 +5299,12 @@
     &scantron_putfile(undef,$scan_data);
 }
 
+=pod
+
+=item check_for_error
+
+=cut
+
 sub check_for_error {
     my ($r,$result)=@_;
     if ($result ne 'ok' && $result ne 'not_found' ) {
@@ -5045,6 +5312,12 @@
     }
 }
 
+=pod
+
+=item scantron_warning_screen
+
+=cut
+
 sub scantron_warning_screen {
     my ($button_text)=@_;
     my $title=&Apache::lonnet::gettitle($env{'form.selectpage'});
@@ -5077,6 +5350,12 @@
 STUFF
 }
 
+=pod
+
+=item scantron_do_warning
+
+=cut
+
 sub scantron_do_warning {
     my ($r)=@_;
     my ($symb)=&get_symb($r);
@@ -5108,6 +5387,12 @@
     return '';
 }
 
+=pod
+
+=item scantron_form_start
+
+=cut
+
 sub scantron_form_start {
     my ($max_bubble)=@_;
     my $result= <<SCANTRONFORM;
@@ -5125,6 +5410,12 @@
     return $result;
 }
 
+=pod
+
+=item scantron_validate_file
+
+=cut
+
 sub scantron_validate_file {
     my ($r) = @_;
     my ($symb)=&get_symb($r);
@@ -5208,6 +5499,13 @@
     return '';
 }
 
+
+=pod
+
+=item scantron_remove_file
+
+=cut
+
 sub scantron_remove_file {
     my ($which)=@_;
     my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
@@ -5222,6 +5520,13 @@
     return &Apache::lonnet::removeuserfile($cname,$cdom,$file);
 }
 
+
+=pod
+
+=item scantron_remove_scan_data
+
+=cut
+
 sub scantron_remove_scan_data {
     my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
@@ -5244,6 +5549,13 @@
     return $result;
 }
 
+
+=pod
+
+=item scantron_getfile
+
+=cut
+
 sub scantron_getfile {
     #FIXME really would prefer a scantron directory
     my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
@@ -5276,6 +5588,12 @@
     return (\%scanlines,\%scan_data);
 }
 
+=pod
+
+=item lonnet_putfile
+
+=cut
+
 sub lonnet_putfile {
     my ($contents,$filename)=@_;
     my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'};
@@ -5285,6 +5603,12 @@
 
 }
 
+=pod
+
+=item scantron_putfile
+
+=cut
+
 sub scantron_putfile {
     my ($scanlines,$scan_data) = @_;
     #FIXME really would prefer a scantron directory
@@ -5305,6 +5629,12 @@
     &Apache::lonnet::put('nohist_scantrondata',$scan_data,$cdom,$cname);
 }
 
+=pod
+
+=item scantron_get_line
+
+=cut
+
 sub scantron_get_line {
     my ($scanlines,$scan_data,$i)=@_;
     if (&should_be_skipped($scanlines,$scan_data,$i)) { return undef; }
@@ -5313,6 +5643,12 @@
     return $scanlines->{'orig'}[$i]; 
 }
 
+=pod
+
+=item scantron_todo_count
+
+=cut
+
 sub get_todo_count {
     my ($scanlines,$scan_data)=@_;
     my $count=0;
@@ -5324,6 +5660,12 @@
     return $count;
 }
 
+=pod
+
+=item scantron_put_line
+
+=cut
+
 sub scantron_put_line {
     my ($scanlines,$scan_data,$i,$newline,$skip)=@_;
     if ($skip) {
@@ -5334,6 +5676,12 @@
     $scanlines->{'corrected'}[$i]=$newline;
 }
 
+=pod
+
+=item scantron_clear_skip
+
+=cut
+
 sub scantron_clear_skip {
     my ($scanlines,$scan_data,$i)=@_;
     if (exists($scanlines->{'skipped'}[$i])) {
@@ -5343,6 +5691,12 @@
     return 0;
 }
 
+=pod
+
+=item scantron_filter_not_exam
+
+=cut
+
 sub scantron_filter_not_exam {
     my ($curres)=@_;
     
@@ -5359,6 +5713,12 @@
     return 0;
 }
 
+=pod
+
+=item scantron_validate_sequence
+
+=cut
+
 sub scantron_validate_sequence {
     my ($r,$currentphase) = @_;
 
@@ -5382,6 +5742,12 @@
     return (0,$currentphase+1);
 }
 
+=pod
+
+=item scantron_validate_ID
+
+=cut
+
 sub scantron_validate_ID {
     my ($r,$currentphase) = @_;
     
@@ -5444,6 +5810,12 @@
     return (0,$currentphase+1);
 }
 
+=pod
+
+=item scantron_get_correction
+
+=cut
+
 sub scantron_get_correction {
     my ($r,$i,$scan_record,$scan_config,$line,$error,$arg)=@_;
 
@@ -5567,15 +5939,23 @@
     $r->print("\n</li></ul>");
 
 }
-#
-#  Ask the grader to select the actual bubble
-#  
-# Arguments:
-#    r           - Apache request.
-#    scan_config - Hash of the scantron format selected.
-#    quest       - Question being evaluated
-#    selected    - array of selected bubbles
-#    lines       - if present, number of bubble lines in questions.
+
+=pod
+
+=item scantron_bubble_selector
+  
+   Generates the html radiobuttons to correct a single bubble line
+   possibly showing the exisiting the selected bubbles if known
+
+ Arguments:
+    $r           - Apache request object
+    $scan_config - hash from &get_scantron_config()
+    $quest       - number of the bubble line to make a corrector for
+    $selected    - array of letters of previously selected bubbles
+    $lines       - if present, number of bubble lines to show
+
+=cut
+
 sub scantron_bubble_selector {
     my ($r,$scan_config,$quest,@selected, $lines)=@_;
     my $max=$$scan_config{'Qlength'};
@@ -5637,6 +6017,12 @@
     $r->print('</table>');
 }
 
+=pod
+
+=item num_matches
+
+=cut
+
 sub num_matches {
     my ($orig,$code) = @_;
     my @code=split(//,$code);
@@ -5648,6 +6034,12 @@
     return $same;
 }
 
+=pod
+
+=item scantron_get_closely_matching_CODEs
+
+=cut
+
 sub scantron_get_closely_matching_CODEs {
     my ($allcodes,$CODE)=@_;
     my @CODEs;
@@ -5658,6 +6050,12 @@
     return ($#CODEs,$CODEs[-1]);
 }
 
+=pod
+
+=item get_codes
+
+=cut
+
 sub get_codes {
     my ($old_name, $cdom, $cnum) = @_;
     if (!$old_name) {
@@ -5680,6 +6078,12 @@
     return %allcodes;
 }
 
+=pod
+
+=item scantron_validate_CODE
+
+=cut
+
 sub scantron_validate_CODE {
     my ($r,$currentphase) = @_;
     my %scantron_config=&get_scantron_config($env{'form.scantron_format'});
@@ -5731,6 +6135,12 @@
     return (0,$currentphase+1);
 }
 
+=pod
+
+=item scantron_validate_doublebubble
+
+=cut
+
 sub scantron_validate_doublebubble {
     my ($r,$currentphase) = @_;
     #get student info
@@ -5754,6 +6164,12 @@
     return (0,$currentphase+1);
 }
 
+=pod
+
+=item scantron_get_maxbubble
+
+=cut
+
 sub scantron_get_maxbubble {    
     if (defined($env{'form.scantron_maxbubble'}) &&
 	$env{'form.scantron_maxbubble'}) {
@@ -5780,6 +6196,12 @@
     return $env{'form.scantron_maxbubble'};
 }
 
+=pod
+
+=item scantron_validate_missingbubbles
+
+=cut
+
 sub scantron_validate_missingbubbles {
     my ($r,$currentphase) = @_;
     #get student info
@@ -5812,6 +6234,30 @@
     return (0,$currentphase+1);
 }
 
+=pod
+
+=item scantron_process_students
+
+   Routine that does the actual grading of the bubble sheet information.
+
+   The parsed scanline hash is added to %env 
+
+   Then foreach unskipped scanline it does an &Apache::lonnet::ssi()
+   foreach resource , with the form data of
+
+	'submitted'     =>'scantron' 
+	'grade_target'  =>'grade',
+	'grade_username'=> username of student
+	'grade_domain'  => domain of student
+	'grade_courseid'=> of course
+	'grade_symb'    => symb of resource to grade
+
+    This triggers a grading pass. The problem grading code takes care
+    of converting the bubbled letter information (now in %env) into a
+    valid submission.
+
+=cut
+
 sub scantron_process_students {
     my ($r) = @_;
     my (undef,undef,$sequence)=&Apache::lonnet::decode_symb($env{'form.selectpage'});
@@ -5916,6 +6362,14 @@
     return '';
 }
 
+=pod
+
+=item scantron_upload_scantron_data
+
+    Creates the screen for adding a new bubble sheet data file to a course.
+
+=cut
+
 sub scantron_upload_scantron_data {
     my ($r)=@_;
     $r->print(&Apache::loncommon::coursebrowser_javascript($env{'request.role.domain'}));
@@ -5952,6 +6406,15 @@
     return '';
 }
 
+=pod
+
+=item scantron_upload_scantron_data_save
+
+   Adds a provided bubble information data file to the course if user
+   has the correct privileges to do so.  
+
+=cut
+
 sub scantron_upload_scantron_data_save {
     my($r)=@_;
     my ($symb)=&get_symb($r,1);
@@ -6007,6 +6470,14 @@
     return '';
 }
 
+=pod
+
+=item valid_file
+
+   Vaildates that the requested bubble data file has exists in the course.
+
+=cut
+
 sub valid_file {
     my ($requested_file)=@_;
     foreach my $filename (sort(&scantron_filenames())) {
@@ -6015,6 +6486,16 @@
     return 0;
 }
 
+=pod
+
+=item scantron_download_scantron_data
+
+   Shows a list of the three internal files (original, corrected,
+   skipped) for a specific bubble sheet data file that exists in the
+   course.
+
+=cut
+
 sub scantron_download_scantron_data {
     my ($r)=@_;
     my $default_form_data=&defaultFormData(&get_symb($r,1));
@@ -6051,6 +6532,12 @@
     return '';
 }
 
+=pod
+
+=back
+
+=cut
+
 #-------- end of section for handling grading scantron forms -------
 #
 #-------------------------------------------------------------------

--albertel1185312093--