File:  [LON-CAPA] / capa / capa51 / CapaTools / capautils.1.1.pl
Revision 1.3: download - view: text, annotated - select for diffs
Mon Aug 7 20:47:28 2000 UTC (23 years, 8 months ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_12_X, version_2_11_X, version_2_11_4_uiuc, version_2_11_4_msu, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, version_1_3_X, version_1_3_3, version_1_3_2, version_1_3_1, version_1_3_0, version_1_2_X, version_1_2_99_1, version_1_2_99_0, version_1_2_1, version_1_2_0, version_1_1_X, version_1_1_99_5, version_1_1_99_4, version_1_1_99_3, version_1_1_99_2, version_1_1_99_1, version_1_1_99_0, version_1_1_3, version_1_1_2, version_1_1_1, version_1_1_0, version_1_0_99_3, version_1_0_99_2, version_1_0_99_1, version_1_0_99, version_1_0_3, version_1_0_2, version_1_0_1, version_1_0_0, version_0_99_5, version_0_99_4, version_0_99_3, version_0_99_2, version_0_99_1, version_0_99_0, version_0_6_2, version_0_6, version_0_5_1, version_0_5, version_0_4, stable_2002_spring, stable_2002_july, stable_2002_april, stable_2001_fall, release_5-1-3, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, conference_2003, bz6209-base, bz6209, STABLE, HEAD, GCI_3, GCI_2, GCI_1, CAPA_5-1-6, CAPA_5-1-5, CAPA_5-1-4_RC1, BZ4492-merge, BZ4492-feature_horizontal_radioresponse, BZ4492-feature_Support_horizontal_radioresponse, BZ4492-Support_horizontal_radioresponse
- fixed license notices the reference the GNU GPL rather than the GNU LGPL

#!/usr/local/bin/perl -I/usr/local/bin

# utilities for CAPA superseeded by Manager
#  Copyright (C) 1992-2000 Michigan State University
#
#  The CAPA system is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  The CAPA system is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public
#  License along with the CAPA system; see the file COPYING.  If not,
#  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.
#
#  As a special exception, you have permission to link this program
#  with the TtH/TtM library and distribute executables, as long as you
#  follow the requirements of the GNU GPL in regard to all of the
#  software in the executable aside from TtH/TtM.
# <==========================================================================>
# June 1997 version 1.0 Created by Isaac Tsai 
# September 24 1997 version 1.1 by Guy Albertelli II
#        -put in initialization loop in S_ScanSetDB (need to remove hardlimits)
#        -initialize Max_try in S_Average, before being used
#
# <==========================================================================>
use Cwd;
require('getopts.pl');
require('CAPAscreen.pl');
# =============================================================================
#  
# =============================================================================
$Days   = int( time / 86400);
@MonthName = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ); 
#
# produces a string  "ddMmm19xx"  to be used in timestamp or filename
#
sub  TodayString {
    local($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst);
    local($str);
 
  ($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst) = localtime(time);
   if ($mday > 9) {
     $str = "$mday$MonthName[$mth]19$yy";  # year 2000 problem!!
   } else {
     $str = "0$mday$MonthName[$mth]19$yy"; # year 2000 problem!!
   }
   return $str;
 }
#
# produces a string hhmmss-ddMon19xx for timestamps
#
sub  TimeString {
    local($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst);
    local($str);
 
  ($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst) = localtime(time);
   $ss = "0" . "$ss" if $ss <= 9;
   $mm = "0" . "$mm" if $mm <= 9;
   $hh = "0" . "$hh" if $hh <= 9;
   if ($mday > 9) {
     $str = "$hh$mm$ss-$mday$MonthName[$mth]19$yy";  # year 2000 problem!!
   } else {
     $str = "$hh$mm$ss-0$mday$MonthName[$mth]19$yy"; # year 2000 problem!!
   }
   return $str;
 }
# =============================================================================
#  Read capa.config into global variables
#  
sub  S_ReadCAPAconfig {
     local($classpath)=@_;
     local($filename);
     local($filename2);
     local($tempfilename);
     local($input_line);
     local($done)=0;
     local($tmp);
     
     @MainPath=();
     push(@MainPath,$classpath);
     $ClassName = substr($classpath,-8,8);
     $filename="$classpath" . "/capa.config";
     $filename2="$classpath" . "/capautils.config";
     foreach $tempfilename ( $filename, $filename2 ) {
       if(-f $tempfilename) {
          open(IN, "<$tempfilename") || die "Cannot open file $tempfilename!";
          LINE: while( ($input_line = <IN>) && (! $done) ) {
             ## skip over comments
             if( $input_line =~ /^\#/ ) { next LINE; }  
             chop($input_line);
             #  collect _path information and create the corresponding global variable 
             if( ($input_line =~ /^(\w+)_path\s*=\s*["]([\.\d\+\-\w\s\/]+)["]$/) || 
                 ($input_line =~ /^(\w+)_path\s*=\s*(\S+)$/) ) {
               $tmp = ucfirst lc $1;
               $tmp = "$tmp" . "Path";
               push(@MainPath,$2);
               ${$tmp} = "$2";
             # collect printer_option information
             } elsif ( ($input_line =~ /^\s*printer_option\s*=\s*["]([\.\d\+\-\w\s\/\|\$]+)["]$/) ||
                       ($input_line =~ /^\s*printer_option\s*=\s*(\S+)$/ ) ) {
               push(@Printers,$1);
               ##   
             # collect _command information
             } elsif ( ($input_line =~ /^\s*(\w+)_command\s*=\s*["]([\.\d\+\-\w\s\/\|\$]+)["]$/) ||
                       ($input_line =~ /^\s*(\w+)_command\s*=\s*(\S+)$/ ) ) {
               $tmp = ucfirst lc $1;
               $tmp = "$tmp" . "CMD";
               ${$tmp} = "$2";
               ## print "CMD \$$tmp: [$2]\n";
               ## print "Press RETURN to continue"; $tmp = <>;
             # collect _file information
             } elsif ( ($input_line =~ /^\s*(\w+)_file\s*=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                       ($input_line =~ /^\s*(\w+)_file\s*=\s*(\S+)$/ ) ) {
               $tmp = ucfirst lc $1;
               $tmp = "$tmp" . "File";
               ${$tmp} = "$2"; 
             # var_ definition
             } elsif ( ($input_line =~ /^\s*var_(\w+)\s*:=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                       ($input_line =~ /^\s*var_(\w+)\s*:=\s*(\S+)$/ ) ) {
               # we defined a variable name with that value 
               $tmp = ucfirst lc $1;
               $Var_name{$tmp} = "$2";
               # two levels of indirection
               # the variable should be ${$2}
         
             # prefix_ definition
             } elsif ( ($input_line =~ /^\s*prefix_(\w+)\s*:=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                       ($input_line =~ /^\s*prefix_(\w+)\s*:=\s*(\S+)$/ ) ) {
               $tmp = ucfirst lc $1;
               $Prefix_name{$tmp} = "$2";
         
             # assigning an numerical value to a variable
             } elsif ( ($input_line =~ /^\s*(\w+)\s*=\s*([\.\d]+)/) ) {
               ${$1} = $2;
               # print "Assign \$$1: with $2\n";
               # print "Press RETURN to continue"; $tmp = <>;
             # assigning a variable to another variable
             } elsif ( ($input_line =~ /^\s*(\w+)\s*=\s*([\w]+)/) ) {
               $P_code{$1} = "\$$2";
               ## print "PERL $1: { $P_code{$1} }\n";
               ## print "Press RETURN to continue"; $tmp = <>;
             # perl code
             } elsif ( ($input_line =~ /^\s*(\w+)\s*::/) ) {
               $p_var_name = $1;
             } elsif ( ($input_line =~ /^\s*BEGIN_perl/) ) {
               $P_code{$p_var_name} = &E_CollectPerlCode;
               ## print "PERL $p_var_name: { $P_code{$p_var_name} }\n";
               ## print "Press RETURN to continue"; $tmp = <>;
             } elsif ($input_line =~ /[Bb][Aa][Ss][Ee][\s][Uu][Nn][Ii][Tt]/) {
               $done = 1;
             }
         
           }
           close(IN) || die "Cannot close file $tempfilename!";
       }
       # define some global variables if they are not defined properly in capa.config file
       $homework_scores_limit_set = 99 if $homework_scores_limit_set eq "";
       $exam_scores_limit_set     = 99 if $exam_scores_limit_set     eq "";
       $quiz_scores_limit_set     = 99 if $quiz_scores_limit_set     eq "";
       $supp_scores_limit_set     = 99 if $supp_scores_limit_set     eq "";
       $others_scores_limit_set   = 99 if $others_scores_limit_set   eq "";
       $display_score_row_limit   = 40 if $display_score_row_limit   eq "";
       ## print "Press RETURN to continue"; $tmp = <>;
     }
 }
#
#  Collect perl codes from <IN> until it encountered a 
#  END_perl statement
#  Skips over comments (begin with a # mark)
#  It then places all the codes withing a pair of '{' and '}'
#
sub  E_CollectPerlCode {
    local($input_line);
    local($p_code,$done);
    
    $p_code = "{ \n";   # begining of the code
    $done=0;
    while( ($input_line = <IN>) && (! $done) ) {
      if( $input_line =~ /^END_perl/ ) {
        $done = 1;
      } else {
        if( $input_line !~ /^\#/ ) {  # skip over comments
          $p_code = "$p_code" . "$input_line";
        }
      }
    }
    $p_code = "$p_code" . " }\n";  # ending of the code
    return ($p_code);
}
#
# Collects e-mail template code until it encountered 
# a END_template statement in the <IN> file
# It skips over comments that begin with a # mark
#
sub  E_CollectTemplateCode {
    local($input_line);
    local($p_code,$done);
    
    
    $done=0;
    while( ($input_line = <IN>) && (! $done) ) {
      if( $input_line =~ /^END_template/ ) {
        $done = 1;
      } else {
        if( $input_line !~ /^\#/ ) {  # skip over comments
          $p_code = "$p_code" . "$input_line";
        }
      }
    }
    
    return ($p_code);
 }

# 
# $MailCMD comes from the entry 'mail_command' in capa.config
# 
sub  S_Mailto {
    local($e_address,$e_file)=@_;
    local($m_subject);
    local($cmd);
    local($tmp);
    
  $m_subject = "Current Status on $ClassName";
  
  $cmd = "$MailCMD -s '$m_subject' $e_address < $e_file";
  print "Mail File $e_file To $e_address\n";
  system($cmd);
  # ??? How do we know this command successfully returns? 
  
 }

# TODO:: Check the validity of $e_addr
#        
# INPUT: a string represents the category to mail to
#        it could be "3" or "0" or "1,3,4"
#        "0"      means 1,2,3, and 4
#        "1,3,4"  means 1,3, and 4
#        anything greater than 4 is not valid in the input
#        therefore category 5 represent those that are 
#        falling through the gaps of *_high and *_low
#
sub  S_MailtoCategory {
    local($cat)=@_;
    local(@all_files);
    local(@a_cat);
    local($i,$j,$a_char);
    local($s_id,$s_name,$s_sec,$e_addr);
    local($orig_filename,$new_filename);
    local($tmp);
    
       opendir(EDIR, "$ClassPath/Mail") || die "cannot opendir $ClassPath/Mail!";
       @all_files = grep !/^\.\.?$/, readdir EDIR;
       closedir EDIR;
       
       if( ( $cat =~ /,/ ) || ( $cat == 0 )  ) {
         if( $cat =~ /,/ ) {
           @a_cat = split(/,/,$cat);
         } else {
           @a_cat = (1,2,3,4);
         }
         for( $i=0;$i<=$#all_files;$i++) {
           for( $j=0;$j<=$#a_cat;$j++) {
             $a_char = $a_cat[$j];
             if( $all_files[$i] =~ /([\w\d]+)\.[\w\d]+\.$a_char$/ ) {
               $s_id = $1;
               ($s_name,$s_sec,$e_addr) = S_Lookup_student_name("$s_id");
               if( $e_addr ne "" ) {
                 $orig_filename = "$ClassPath/Mail/$all_files[$i]";
                 S_Mailto("$e_addr","$orig_filename");
                 print "moving $all_files[$i] to $all_files[$i].done\n";
                 # move the completed file to *.done 
                 system("mv $orig_filename $orig_filename.done");
               }
             }
           }
         }
       } else {
         for( $i=0;$i<=$#all_files;$i++) {
           if( $all_files[$i] =~ /([\w\d]+)\.[\w\d]+\.$cat$/ ) {
             $s_id = $1;
             ($s_name,$s_sec,$e_addr) = S_Lookup_student_name("$s_id");
             print "Addr=$e_addr\n";
             print "Press RETURN to continue"; $tmp = <>;
             if( $e_addr ne "" ) {
                 $orig_filename = "$ClassPath/Mail/$all_files[$i]";
                 S_Mailto("$e_addr","$orig_filename");
                 print "moving $all_files[$i] to $all_files[$i].done\n";
                 system("mv $orig_filename $orig_filename.done");
             }
           }
         }
       }
       print "DONE Mail, press RETURN to continue"; $tmp = <>;

 }
#
# It prompts the user to enter an absolute path to a regular class
#
sub  S_Enterpath {
    local($set)=@_;
    local($notdone,$path,$cfgfullpath,$cfgutilsfullpath);
    local($cfullpath,$rfullpath,$sfullpath);
    
    $notdone = 1;
    while ($notdone) {
      print "Please enter the CLASS absolute path:\n";
      $path = <>; chomp($path);
      if( $path =~ /\/$/ ) {
        $cfullpath = "$path" . "classl";
        $rfullpath = "$path" . "records";
        $sfullpath = "$path" . "records/set$set.db";
        $cfgfullpath = "$path" . "capa.config";
        $cfgutilsfullpath = "$path" . "capautils.config";
      } else {
        $cfullpath = "$path" . "/classl";
        $rfullpath = "$path" . "/records";
        $sfullpath = "$path" . "/records/set$set.db";
        $cfgfullpath = "$path" . "/capa.config";
        $cfgutilsfullpath = "$path" . "/capautils.config";
      }
      if( -d $path ) {
        if( -d $rfullpath ) {
          if( -f $cfgfullpath ) {
	      if( -f $cfgutilsfullpath ) {
		  $notdone = 0;
	      } else {
		  print "File [$cfgutilsfullpath] does not exist!\n";
	      }
          } else {
              print "File [$cfgfullpath] does not exist!\n";
          }
        } else {
          print "Directory [$rfullpath] does not exist!\n";
        }
      } else {
        print "Directory [$path] does not exist!\n";
      }
    
    }
    return ($path);
  }
# ----------------------------------------------------------
#      Global menu items to be selected by user
#
@Main_menu=(
  "Change class path", 
  "Run capastat", 
  "Log analysis on Y, N, S, U, and u", 
  "Student course profile", 
  "CAPA IDs for one student",
  "All CAPA IDs",
  "Item analysis",
  "Item correlation",
  "Email",
  "Print assignment(s) for a student",
  "View score file",
  "View submissions for a student",
  "Quit");

@Prof_menu=(
  "Student number",
  "Student name",
  "Cancel" );

@Email_menu=(
  "Create score file for all students",
  "Create individual e-mail files from the file in 1.",
  "Preview e-mail file randomly from among the files in 2.",
  "Send e-mail files in 2. to a group of students",
  "Cancel" );

@ScoreSortMsg=(
  "Sort by the order of: ", 
  " 1. Grade",
  " 2. Student number",
  " 3. Student name", 
  " 4. Section",
  " ",
  "3,2   means 'name' first, 'student number' second",
  "1,4,3 means sort by 'grade', 'section' and 'name'" );


@SpecifyCategoryMsg =  ("Which category?",
                        "  enter number(s) between 0 and 4",
                        "  1,2,4 : categories 1, 2 and 4",
                        "  3     : category 3",
                        "  0     : all categories" );
#
# Only accepts input of 0, 1, 2, 3, and 4, nothing else.
#
sub  S_EnterCategory {
    local($cat);
    local($done)=0;
    local(@a_cat,$i);
    
    while(! $done) {
      $cat = C_InputSetNum(4,10,45,"",12,,"CATEGORY:", @SpecifyCategoryMsg);
      if( $cat =~ /,/ ) {
        @a_cat = split(/,/,$cat);
        $done = 1;
        for( $i=0;$i<=$#a_cat;$i++) {
          if( ($a_cat[$i] < 0 || $a_cat[$i] > 4) && ($a_cat[$i] ne "" ) ) {
            $done = 0;
          }
          if( $a_cat[$i] == 0 ) {
            $done = 0;
          }
        }
        
      } else {
        if(  $cat>= 0 && $cat <= 4 ) {
          $done = 1;
        }
      }
    }
    return ($cat);
}

# Only allows input of 1, 2, 3, and 4, nothing more
sub  S_EnterSortKey {
    local($key);
    local($done)=0;
    local(@a_key,$i);
    
    while(! $done) {
      $key = C_InputSetNum(2,5,60,"",12,,"KEY:",@ScoreSortMsg);
      if( $key =~ /,/ ) {
        @a_key = split(/,/,$key);
        $done = 1;
        for( $i=0;$i<=$#a_key;$i++) {
          if( ($a_cat[$i] < 0 || $a_cat[$i] > 4) && ($a_key[$i] ne "" ) ) {
            $done = 0;
          }
          if( $a_key[$i] == 0 ) {
            $done = 0;
          }
        }
        
      } else {
        if(  $key> 0 && $key < 5 ) {
          $done = 1;
        }
      }
    }
    return ($key);
}




@EnterSetMsg =  ("Which set?");
@EnterSetsMsg = ("Which set(s)?",
                 " 3,7 : from set 3 to set 7 (both inclusive)",
                 " 4   : only set 4" );

sub  S_EnterSets {
    local($set);
    local($done)=0;
    local($s_from,$s_to);
    
    while(! $done) {
      $set = C_InputSetNum(4,10,45,"",6,,"SET:", @EnterSetsMsg);
      if( $set =~ /,/ ) {
        ($s_from,$s_to) = split(/,/,$set);
        if( $s_from <= 0 || $s_from >= 100 ) { $s_from = 1; }
        if( $s_to <= 0   || $s_to >= 100 )   { $s_to   = 1; }
        if( $s_from > $s_to) {
          $tmp = $s_from; $s_from = $s_to; $s_to = $tmp;
        }
        $done = 1;
      } else {
        if(  $set> 0 && $set < 100 ) {
          $s_to = $set;
          $s_from = $s_to;
          $done = 1;
        }
      }
    }
    return ($s_from,$s_to);
}

sub  S_InputSet {
    local($set);
    local($done)=0;
    
    while(! $done) {
      $set = C_InputSetNum(4,10,15,"",2,,"SET:", @EnterSetMsg);
      if( $set =~ /\d+/ && $set > 0 && $set < 100 ) { # check entered set 
        $done = 1;
      }
    }
    return ($set);
}


@EnterSSNMsg = ("Enter student number?", " (RETURN to exit)" );
@EnterSNMsg =  ("Enter student name (max 30 chars)?",
                "Last, First (Middle)",
                " (RETURN to exit)" );

sub  S_InputStudent {
    local($classpath)=@_;
    local($filename);
    local($select,$tmp_sn,$input_line);
    local($student_id,$student_name);
    local($found,$done,$s_name);
    local($match,@matched_entries,$tmp_line);
    
    $select = C_MultipleChoice(4,10,$DialogWidth,"Select student by:","$DisplayPath",@Prof_menu);
    if($select == 1 ) {  # specify student number
       while(! $done) {
         $student_id = C_InputStudentID(4,10,24,"",9,"INPUT:",@EnterSSNMsg);
         if($student_id eq "" ) {
           $done = 1; 
         } else {
           $student_id = uc($student_id);
           $filename = $classpath . "/classl";
           open(IN, "<$filename") || die "Cannot open file $filename!";
           $match = 0; @matched_entries = ();
           while(($input_line = <IN>)) {
             chomp($input_line);
             $tmp_sn = substr($input_line,14,9); $tmp_sn = uc($tmp_sn);
             if($tmp_sn =~ /^$student_id/ ) {
               $match++;
               # student name begins at column 24 and has 30 chars max
               $student_name = substr($input_line,24,30); 
               $tmp_line = "$tmp_sn " . "$student_name";
               push(@matched_entries,$tmp_line);
             }
           }
           close(IN) || die "Cannot close file $filename!";
           if($match > 1 && $match <= 12) {
             $select = C_MultipleChoice(4,10,$DialogWidth,"        Matched Student Records       ",
                          "$DisplayPath",@matched_entries);
             $student_id = substr($matched_entries[$select-1],0,9);
             $student_name = substr($matched_entries[$select-1],10,30);
             $done = 1;
           } elsif ($match == 1) {
             $student_id = substr($matched_entries[0],0,9);
             $student_name = substr($matched_entries[0],10,30);
             $done = 1;
           } elsif ($match > 12) {
             $tmp_line = "There are $match records found.";
             C_Warn(4,10,$DialogWidth,"Too many students matched",$tmp_line);
           } else {
             $tmp_line = "Please re-enter student number.";
             C_Warn(4,10,$DialogWidth,"No student found",$tmp_line);
           }
         }
         
       }
    } elsif ($select == 2) { # specify student name
       while(! $done) {
         $s_name = C_InputStudentID(4,10,40,"Enter student name",30,,"INPUT:", @EnterSNMsg);
         if($s_name eq "" ) {
           $done = 1;
         } else {
           $s_name = uc($s_name);
           $filename = $classpath . "/classl";
           open(IN, "<$filename") || die "Cannot open file $filename!";
           $match = 0; @matched_entries = ();
           while(($input_line = <IN>)) {
             chomp($input_line);
               $tmp_sn = substr($input_line,24,30); $tmp_sn = uc($tmp_sn);
             if( $tmp_sn =~ /^$s_name/ ) {
               $match++;
               $student_id = substr($input_line,14,9); # student number
               $tmp_line = "$student_id " . "$tmp_sn";
               push(@matched_entries,$tmp_line);
             }
           }
           close(IN) || die "Cannot close file $filename!";
           if($match > 1 && $match <= 12) {
             $select = C_MultipleChoice(4,10,$DialogWidth,"        Matched Student Records       ",
                            "$DisplayPath",@matched_entries);
             $student_id = substr($matched_entries[$select-1],0,9);
             $student_name = substr($matched_entries[$select-1],10,30);
             $done = 1;
           } elsif ($match == 1) {
             $student_id = substr($matched_entries[0],0,9);
             $student_name = substr($matched_entries[0],10,30);
             $done = 1;
           } elsif ($match > 12) {
             $tmp_line = "There are $match records found.";
             C_Warn(4,10,$DialogWidth,"Too many students matched",$tmp_line);
           } else {
             $tmp_line = "Please re-enter student name.";
             C_Warn(4,10,$DialogWidth,"No student found",$tmp_line);
           }
         }
       }
    } else {  # cancel 
      $student_id = "";
      $student_name = "";
    }
    return ($student_id,$student_name);
}



#
# INPUT: the class name with full path and the student number
# OUTPUT: total scores , total possible wights

sub S_CollectSetScores {
    local($classpath,$student_id,$on_screen,$s_limit)=@_;
    local($filename,$found,$classname);
    local($done)=0;
    local($line_cnt,$input_line);
    local(@weights);       # the wights array for individual set
    local($valid_weights); # the valid weights for a set
    local($total_weights); # the overall valid weights for all sets
    local(@set_weights);   # the array storing all set valid weights
    local($score);         # the valid score for a set
    local($total_scores);  # the overall valid scores for all sets
    local(@set_scores);    # the array storing all set scores
    local($set_idx);
    local($ii,$abscent_cnt,$present_cnt);
    local($s_num,$ans_str,$prefix,$rest);
    local(@ans_char,$ratio,$tmp,$summary_str);
    
    $student_id = uc($student_id);
    $total_scores = 0; $total_weights = 0; # initialize the overall results
    $set_idx = 0;
    
    while( ! $done ) {
      $set_idx++;    # start out as set1.db, then add one to it
      if($set_idx <= $s_limit ) {  # the limit set is inclusive
        $filename = $classpath . "/records/set" . "$set_idx" . ".db";
        if( -f $filename) { # file exists!
          open(IN, "<$filename") || die "Cannot open file $filename!";
          $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
          while ( ($input_line = <IN>) && !$found) { 
            $line_cnt++;       # add one to line count
            if( $line_cnt == 2 ) { # second line is the weight for each problem
              chomp();             # delete the trailing '\n' char
              (@weights) = split(/ */,$input_line);  # split the line into each individual chars
              $valid_weights = 0;
              for($ii=0;$ii<=$#weights;$ii++) {
                $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
              }
            ## &C_ClearScreen;
            ## print "Second line, $input_line, total weight=$valid_weights\n";
            ## printf "Press RETURN to continue"; $tmp = <>;
            }
            if( $line_cnt > 3) {    # start from line 4 is the student data
              chomp($input_line);              # delete the trailing '\n' char
              ($prefix,$rest) = split(/,/,$input_line,2); # split the whole line into two parts
              ($s_num,$ans_str) = split(/ /,$prefix,2);   # split into two parts
              $s_num = uc($s_num); 
              if( $student_id eq $s_num ) { # found the student we want
              ## &C_ClearScreen;
              ## print "FOUND [$input_line] $s_num == $student_id: weight= $valid_weights,ANS=$ans_str\n";
              ## printf "Press RETURN to continue"; $tmp = <>;
                $found = 1;         # so we can exit the search through while loop
                (@ans_char) = split(/ */,$ans_str);  # split the answer string into individual ans chars
                for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1, to last question -1
                  $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
                }
                if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
                  for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii
                  
                    if($ans_char[$ii] eq 'Y') {
                      $score += $weights[$ii];
                    }
                    if($ans_char[$ii] eq 'y') {
                      $score += $weights[$ii];
                    }
                    if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
                      $score += $ans_char[$ii];
                    }
                    if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                      $valid_weights -= $weights[$ii];
                    }
                  }
                  $total_scores += $score;  # add the calculated score to the overall sum
                } else { # end of a valid line
                  $score = '-';
                }
              } 
            }   # end $line_cnt > 3
          } # end while <IN>
          close(IN) || die "Cannot close file $filename!";
          $total_weights   += $valid_weights; # add the valid weights for a set to the overall sum
          $set_weights[$set_idx-1] = $valid_weights;
        
          if( $found ) {
          ## push(@set_scores, $score);          # push set score into array
          ## push(@set_weights, $valid_weights); # push valid weight for a set into the weight array
            $set_scores[$set_idx-1]  = $score;
          } else { # student not found in the setX.db file
            $set_scores[$set_idx-1]  = '-';
          }
        } else {  # $set_idx > $s_limit
          $done = 1;  # exit the $done while loop
        }
      } else {
        $done = 1;  # exit the $done while loop
      }
    } # end while ! $done
    # print out the report
    # &C_ClearScreen;
    $abscent_cnt=0;
    $present_cnt=0;
    $summary_str = "";
    print " " x 10 if $on_screen;
    for($ii=0;$ii<=$#set_scores;$ii++) {
      if( $set_scores[$ii] eq '-' || $set_scores[$ii] eq "" ) {
        print "  - " if $on_screen;
        $summary_str = "$summary_str" . "x/$set_weights[$ii] ";
        $abscent_cnt++;
      } else {
        printf " %3d", $set_scores[$ii] if $on_screen;
        $summary_str = "$summary_str" . "$set_scores[$ii]/$set_weights[$ii] ";
        $present_cnt++;
      }
    }
    if( $on_screen ) {
      $classname = substr($classpath,-8,8);
      print "\n $classname:";
      for($ii=0;$ii<=$#set_scores;$ii++) {
        print " ---";
      }
      print "\n          ";
      for($ii=0;$ii<=$#set_weights;$ii++) {
        printf " %3d", $set_weights[$ii];
      }
      print "\n";
      if($total_weights != 0 ) {
        $ratio = 100.0 * ($total_scores / $total_weights);
      } else {
        $ratio = '-';
      }
      printf "  %5d\n", $total_scores if $on_screen;
      printf  " ------- = %3.2f%%, scores abscent in %d/%d\n", $ratio, $abscent_cnt, $#set_scores+1;
      printf "  %5d\n", $total_weights;
    ## print "Press RETURN to continue"; $tmp = <>;
    }
    return ($total_scores,$total_weights,$abscent_cnt,$#set_scores+1,$summary_str);
 }

# 
#  similar to S_CollectSetScores
# 
sub S_CollectExamScores {
    local($classpath,$student_id)=@_;
    local($filename,$found,$classname);
    local($done)=0;
    local($line_cnt,$input_line);
    local(@weights);       # the wights array for individual set
    local($valid_weights); # the valid weights for a set
    local($total_weights); # the overall valid weights for all sets
    local(@set_weights);   # the array storing all set valid weights
    local($score);         # the valid score for a set
    local($total_scores);  # the overall valid scores for all sets
    local(@set_scores);    # the array storing all set scores
    local($set_idx);
    local($ii,$var_name);
    local($s_num,$ans_str,$prefix,$rest);
    local($midterm1,$midterm2,$midterm3,$f_score);
    local($m_max1,$m_max2,$m_max3,$f_max);
    local(@ans_char,$ratio,$tmp);
    
    $student_id = uc($student_id);
    $total_scores = 0; $total_weights = 0; # initialize the overall results
    $set_idx = 0;
    
    while( ! $done ) {
      $set_idx++;    # start out as set1.db, then add one to it
      if( $set_idx <= $exam_scores_limit_set ) { # $exam_scores_limit_set comes from capa.config
        $filename = $classpath . "/records/set" . "$set_idx" . ".db";
        if( -f $filename) { # file exists!
          open(IN, "<$filename") || die "Cannot open file $filename!";
          $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
          while ( ($input_line = <IN>) && !$found) { 
            $line_cnt++;       # add one to line count
            if( $line_cnt == 2 ) { # second line is the weight for each problem
              chomp();             # delete the trailing '\n' char
              (@weights) = split(/ */,$input_line);  # split the line into each individual chars
              $valid_weights = 0;
              for($ii=0;$ii<=$#weights;$ii++) {
                $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
              }
            }
            if( $line_cnt > 3) {    # start from line 4 is the student data
              chomp($input_line);              # delete the trailing '\n' char
              ($prefix,$rest) = split(/,/,$input_line,2); # split the whole line into two parts
              ($s_num,$ans_str) = split(/ /,$prefix,2);   # split into two parts
              $s_num = uc($s_num); 
              if( $student_id eq $s_num ) { # found the student we want
                $found = 1;         # so we can exit the search through while loop
                (@ans_char) = split(/ */,$ans_str);  # split the answer string into individual ans chars
                for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1, to last question -1
                  $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
                }
                if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
                  for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii
                  
                    if($ans_char[$ii] eq 'Y') {
                      $score += $weights[$ii];
                    }
                    if($ans_char[$ii] eq 'y') {
                      $score += $weights[$ii];
                      }
                    if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
                      $score += $ans_char[$ii];
                    }
                    if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                      $valid_weights -= $weights[$ii];
                    }
                  }
                  $total_scores += $score;  # add the calculated score to the overall sum
                } else { # end of a valid line
                  $score = '-';
                }
              } # end student number comparison
            }   # end $line_cnt > 3
          } # end while <IN>
          close(IN) || die "Cannot close file $filename!";
          $total_weights   += $valid_weights; # add the valid weights for a set to the overall sum
          $set_weights[$set_idx-1] = $valid_weights;
        # push(@set_scores, $score);          # push set score into array
        # push(@set_weights, $valid_weights); # push valid weight for a set into the weight array
          if( $found ) {
            $set_scores[$set_idx-1]  = $score;
          } else { # could not locate the student in the setX.db file
            $set_scores[$set_idx-1]  = '-';
          }
        } else {  # $set_idx > $exam_scores_limit_set
          $done = 1;
        }
      } else {
        $done = 1;  # exit the $done while loop
      }
    } # end while ! $done

    # put scores in the global variables: exam_raw1, exam_raw2 ...
    #     and maximum weights in variables: exam_raw_max1, exam_raw_max2,..
    # prefix is stored in :
    #    $Prefix_name{"Exam_raw_scores"}
    #    $Prefix_name{"Exam_raw_max"}
    # 
    $Prefix_name{'Exam_raw_scores'} = "exam_raw"     if ! defined $Prefix_name{'Exam_raw_scores'};
    $Prefix_name{'Exam_raw_max'}    = "exam_raw_max" if ! defined $Prefix_name{'Exam_raw_max'};
    for($ii=0;$ii<=$#set_scores;$ii++) {
      $set_idx = $ii+1;
      $var_name = "$Prefix_name{'Exam_raw_scores'}" . "$set_idx";
      ${$var_name} = $set_scores[$ii];
      $var_name = "$Prefix_name{'Exam_raw_max'}" . "$set_idx";
      ${$var_name} = $set_weights[$ii];
    }
    #
    # initialize these local variables 
    #
    $midterm1 = '-'; $m_max1 = '-';
    $midterm2 = '-'; $m_max2 = '-';
    $midterm3 = '-'; $m_max3 = '-';
    $f_score  = '-'; $f_max =  '-';
    # After we placed raw scores into the global variables exam_raw1, exam_raw2 ...
    #  we can then, evaluate the definitions of midterm1, midterm2 and midterm3 from capa.config
    if($#set_scores >= 1) {  # at least 2 sets
        $midterm1 = eval $P_code{'midterm1'};
        $var_name =  "$Prefix_name{'Exam_raw_max'}" . "1"; # for max possible scores, just pick a set
        $m_max1 = ${$var_name};
        if($#set_scores >= 3) { # at least 4 sets
          $midterm2 = eval $P_code{'midterm2'};
          $var_name =  "$Prefix_name{'Exam_raw_max'}" . "3"; # for max possible scores, just pick a set
          $m_max2 = ${$var_name};
          if($#set_scores >= 5) { # at least 6 sets
            $midterm3 = eval $P_code{'midterm3'};
            $var_name =  "$Prefix_name{'Exam_raw_max'}" . "5"; # for max possible scores, just pick a set
            $m_max3 = ${$var_name};
            if($#set_scores == 6 ) { # the 7th set
                                     # in capa.config a variable $final_exam is defined as 
                                     #    the same with $exam_raw7
              ## $var_name =  "$Prefix_name{'Exam_raw_scores'}" . "7";
              ## $f_score = ${$var_name};
              $f_score = eval $P_code{'final_exam'};
              $var_name =  "$Prefix_name{'Exam_raw_max'}" . "7";
              $f_max = ${$var_name};
            } else { # only 6 sets
              
            }
          } else { # 4 or 5 sets
            
          }
        } else { # 2 or 3 sets
          
        }
    } else { # 0 or 1 sets
      
    }  
    return ($midterm1,$m_max1,$midterm2,$m_max2,$midterm3,$m_max3,$f_score,$f_max,$#set_scores+1);
   
 }

#
# Menu item: capastat
#     ($Q_cnt,$L_cnt) =  &S_ScanSetDB($Sfullpath);
#     Percentage_Scores($Set);
#     S_Average($Q_cnt,$L_cnt);
#
# INPUT: the setX.db file name with full path 
#    
sub S_ScanSetDB  {
    local($filename)=@_;
    local($line_cnt)=0;
    local($valid_cnt)=0;
    local($valid);
    local($ii);
    local($s_num,$ans_str,$prefix,$rest);
    local(@ans_char,@tries);
    local($score);
    
    for($ii=0;$ii<=99;$ii++) {
        $Total_try[$ii]=0;
	$Yes_cnt[$ii]=0;
	$yes_cnt[$ii]=0;
        for($jj=0;$jj<=99;$jj++) {
	    $Student_cnt[$ii][$jj]=0;
            $Student_try[$ii][$jj]=0;
	}
    }
    $Total_weight=0;
    $Total_scores=0;

    open(IN, "<$filename") || die "Cannot open file $filename!";
    while (<IN>) {
      $line_cnt++;
      if( $line_cnt == 2 ) {
        chomp();
        (@Weight) = split(/ */);
      }
      if( $line_cnt > 3) {
        chomp();
        ($prefix,$rest) = split(/,/,$_,2);
        ($s_num,$ans_str) = split(/ /,$prefix,2);
        (@ans_char) = split(/ */,$ans_str);
        (@tries)    = split(/,/,$rest);
        for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {
            $valid = 'Y' if $ans_char[$ii] ne '-';
        }
        if( $valid eq 'Y' ) {
          for($score=0,$ii=0;$ii<=$#tries;$ii++) {
            $Student_cnt[$ii][$tries[$ii]]++;
            $Student_try[$valid_cnt][$ii] = $tries[$ii];
            $Total_try[$ii] += $tries[$ii];
            $Total_weight   += $Weight[$ii];
            if($ans_char[$ii] eq 'Y') {
              $Yes_cnt[$ii]++;
              $score += $Weight[$ii];
            }
            if($ans_char[$ii] eq 'y') {
              $yes_cnt[$ii]++;
              $score += $Weight[$ii];
            }
            if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
              $score += $ans_char[$ii];
            }
          }
          $Total_scores += $score;
          $Entry{"$valid_cnt"} = "$s_num\n" . "$ans_str," . " $rest\n";
          $Score{"$valid_cnt"} = $score;
          $valid_cnt++;
        }
      }
    }
    close(IN) || die "Cannot close $filename file!";
    return ($#tries+1,$valid_cnt);
 }
 
 
$MAX_TRIES = 99;

sub  S_Average {
    local($q_cnt,$l_cnt)=@_;
    local($ii,$jj);
    local(@s_cnt,@avg);
    local(@sd, $sum);
    local($sq);
    local(@sd3,$tmp1,$tmp2,$done);
    
    for($ii=0;$ii<$q_cnt;$ii++) {
      $s_cnt[$ii] = 0;
      $avg[$ii]   = 0.0;
      $Max_try[$ii] = 0;
      for($jj=1;$jj<$MAX_TRIES;$jj++) {  # ignore the 0 try entry
        if( $Student_cnt[$ii][$jj] > 0 ) {
          $avg[$ii]   +=  $jj*$Student_cnt[$ii][$jj];
          $s_cnt[$ii] +=  $Student_cnt[$ii][$jj];
        }
      }
      if( $s_cnt[$ii] > 0 ) {      # avoid division by zero
        $avg[$ii] = $avg[$ii] / $s_cnt[$ii];
      }
    }
    
    for($ii=0;$ii<$q_cnt;$ii++) {
      $sd[$ii] = 0.0;
      $sum = 0.0;
      for($jj=0;$jj<$l_cnt;$jj++) {
        $Max_try[$ii] = ($Student_try[$jj][$ii] > $Max_try[$ii]? $Student_try[$jj][$ii] : $Max_try[$ii]);
        if( $Student_try[$jj][$ii] > 0 ) {
          $sq  = ($Student_try[$jj][$ii] - $avg[$ii])*($Student_try[$jj][$ii] - $avg[$ii]);
          $sum += $sq;
        }
        if( $s_cnt[$ii] > 1 ) {
          $sd[$ii] = $sum / ($s_cnt[$ii] - 1.0 );
        }
        if( $sd[$ii] > 0 ) {
          $sd[$ii] = sqrt( $sd[$ii] );
        }
      }
    }
    
    for($ii=0;$ii<$q_cnt;$ii++) {
      $sd3[$ii] = 0.0;
      $sum = 0.0;
      for($jj=0;$jj<$l_cnt;$jj++) {
        if( $Student_try[$jj][$ii] > 0 ) {
          $tmp1 = $Student_try[$jj][$ii] - $avg[$ii];
          $tmp2 = $tmp1*$tmp1*$tmp1;
          $sum  = $sum + $tmp2;
        }
        if( $s_cnt[$ii] > 0 && $sd[$ii] != 0.0 ) {
          $sd3[$ii] = $sum/$s_cnt[$ii] ;
          $sd3[$ii] = $sd3[$ii] / ($sd[$ii]*$sd[$ii]*$sd[$ii]);
        }
      }
    }
    
    print "This is the statistics for each problem:\n";
    print "Prob\#   MxTries   avg.     s.d.    s.k.   \#Stdnts ";
    print "  \#Yes   \#yes   Tries  DoDiff\n";
    for($ii=0;$ii<$q_cnt;$ii++) {
      if( $Total_try[$ii] > 0 ) {
        ## $dod = 1-($Yes_cnt[$ii] + $yes_cnt[$ii]) / $Total_try[$ii];
        $dod = $Total_try[$ii]/(0.1 + $Yes_cnt[$ii] + $yes_cnt[$ii]);
      }
      printf "P %2d:",$ii+1;
      printf "%7d  %8.2f  %7.2f  %6.2f   %5d   %5d  %5d    %5d   %5.1f\n",
              $Max_try[$ii],$avg[$ii],$sd[$ii],$sd3[$ii],$s_cnt[$ii],$Yes_cnt[$ii],$yes_cnt[$ii],
              $Total_try[$ii],$dod;
     
    }
    printf "Press RETURN to continue"; $done = <>;
  }
  
sub  Percentage_Scores {
    local($set,$valid_cnt)=@_;
    local($ratio);
    local($done);
    
    if($Total_weight > 0 ) {
      $ratio = $Total_scores / $Total_weight;
      $ratio = $ratio * 100.0;
    }
    
    printf "\nThe percentage score (total scores / total valid weights) for set%d.db is:\n %7.2f%%\n",$set,$ratio;
    printf "The number of valid records for set%d.db is: %d\n", $set, $valid_cnt;
    printf "Press RETURN to continue"; $done=<>;
  }


sub  Large_Tries {
    local($t,$n,$q_cnt,$l_cnt)=@_;
    local($ii);
    
    print "\nHere is a list of students who attempts $t tries more than $n times: \n\n";

    for ($i=0;$i<$l_cnt;$i++){
       $count=0;
       $credit=0;
       for ($j=0;$j<$q_cnt;$j++){
           if ($Student_try[$i][$j]>= $t){
              $count++;
           }
       }
       if ($count >= $n){
          print "($Score{$i})  $Entry{$i} \n";
       }
    }
  
  }


sub S_ScanLogDB  {
    local($filename)=@_;
    local($line_cnt)=0;
    local($s_num,$dow,$mon,$sp,$day,$time,$yr,$ans_str);
    local(@ans_char);
    local($ii,$first,$done);
    local($Yes_cnt[99],$No_cnt[99],$U_cnt[99],$S_cnt[99],$u_cnt[99]);
    local($Y_total,$N_total,$U_total,$u_total,$S_total);
    
    $Y_total=0; $N_total=0; $U_total=0; $u_total=0; $S_total=0;
    open(IN, "<$filename") || die "Cannot open file $filename!";
    for($ii=0;$ii<=99;$ii++) {
      $Yes_cnt[$ii] = 0; $No_cnt[$ii] = 0; 
      $U_cnt[$ii]=0; $u_cnt[$ii]=0; $S_cnt[$ii]=0;
    }
    while (<IN>) {
      $line_cnt++;
      chomp();
      $ans_str = substr($_,35);
      ## ($first,$ans_str) = split(/1996 /);  # depends on this special pattern
       # print "$ans_str\n";
      (@ans_char) = split(/ */,$ans_str);
       
       for($ii=0;$ii<=$#ans_char;$ii++) {
       
         if($ans_char[$ii] eq 'Y') {
           $Yes_cnt[$ii]++;
           $Y_total++;
         }
         if($ans_char[$ii] eq 'N') {
           $No_cnt[$ii]++;
           $N_total++;
         }
         if($ans_char[$ii] eq 'U') {
           $U_cnt[$ii]++;
           $U_total++;
         }
         if($ans_char[$ii] eq 'u') {
           $u_cnt[$ii]++;
           $u_total++;
         }
         if($ans_char[$ii] eq 'S') {
           $S_cnt[$ii]++;
           $S_total++;
         }
       }
     }
     close(IN) || die "Cannot close file $filename!";
     print "Prob #:     #Y     #N     #S     #U     #u\n";
     for($ii=0;$ii<=$#ans_char;$ii++) {
       printf "    %2d: %6d %6d %6d %6d %6d\n",
              $ii+1, $Yes_cnt[$ii], $No_cnt[$ii], $S_cnt[$ii], $U_cnt[$ii], $u_cnt[$ii];
     }
     print  "=" x 45 . "\n";
     printf  " Total: %6d %6d %6d %6d %6d\n", $Y_total, $N_total, $S_total, $U_total, $u_total;
     printf "Press RETURN to continue"; $done = <>;
     
     return ($Y_total,$N_total,$S_total,$U_total,$u_total);
  }

sub S_StudentLoginData {
    local($filename,$student_id)=@_;
    local($Y_total,$N_total,$S_total,$U_total,$u_total);
    local($ans_str,@ans_char);
    local($ii,$s_id);
    
    $Y_total=0; $N_total=0; $U_total=0; $u_total=0; $S_total=0;
    open(IN, "<$filename") || die "Cannot open file $filename!";
    while (<IN>) { 
      chomp();
      $s_id = substr($_,0,9); # student number begins at column 0 and has 9 chars
      $s_id = uc($s_id);
      $student_id = uc($student_id);
      if( $student_id eq $s_id) {
        $ans_str = substr($_,35);    # the answer string begins at column 35 (count from 0)
        (@ans_char) = split(/ */,$ans_str);
        for($ii=0;$ii<=$#ans_char;$ii++) {
          if($ans_char[$ii] eq 'Y') {
            $Y_total++;
          }
          if($ans_char[$ii] eq 'N') {
            $N_total++;
          }
          if($ans_char[$ii] eq 'U') {
            $U_total++;
          }
          if($ans_char[$ii] eq 'u') {
            $u_total++;
          }
          if($ans_char[$ii] eq 'S') {
            $S_total++;
          }
        } # end for each problem
      } # end student number matches
    } # end while 
    close(IN) || die "Cannot close file $filename!";
    return ($Y_total,$N_total,$S_total,$U_total,$u_total);
 }

# 
sub S_LoginAnalysis {
    local($classpath,$student_id,$s_limit)=@_;
    local($Y_set,$N_set,$S_set,$U_set,$u_set);
    local($set_idx,$no_log,$no_weblog,$done,$tmp);
    
    print "Login analysis:  telnet session             web session\n\n";
    print "   set #:   #Y   #N   #S   #U   #u     #Y   #N   #S   #U   #u\n";
    $set_idx=0; $done=0;
    while (! $done ) {
      $set_idx++;
      if( $set_idx <= $s_limit) {
        printf "      %2d: ", $set_idx;
        $filename= $classpath . "/records/log" . "$set_idx" . ".db";
        if(-f $filename) {
          ($Y_set,$N_set,$S_set,$U_set,$u_set)=S_StudentLoginData($filename,$student_id);
          printf "%4d %4d %4d %4d %4d", $Y_set,$N_set,$S_set,$U_set,$u_set;
          $no_log = 0;
        } else {
          print  "=" x 24;
          $no_log = 1;
        }
        print " " x 4;
        $filename= $classpath . "/records/weblog" . "$set_idx" . ".db";
        if(-f $filename) {
          ($Y_set,$N_set,$S_set,$U_set,$u_set)= S_StudentLoginData($filename,$student_id);
          printf "%4d %4d %4d %4d %4d", $Y_set,$N_set,$S_set,$U_set,$u_set;
          $no_weblog = 0;
        } else {
          print  "=" x 24;
          $no_weblog = 1;
        }
        print "\n";
        if( $no_log && $no_weblog ) { $done = 1; };
      } else { # $set_idx > $s_limit
        $done = 1;
      }
    }
    
    printf "Press RETURN to continue"; $tmp = <>;
 }

# It pulls out the data base entry from setX.db files
sub S_StudentSetAnalysis {
    local($classpath,$student_id,$s_limit)=@_;
    local($filename);
    local($set_idx,$done);
    local($line_cnt,$found,$input_line);
    local($s_num,$data,$ans_str,$try_str,$tmp);
    
    $set_idx=0; $student_id = uc($student_id);
    print " set #:\n";
    while(! $done) {
      $set_idx++;
      if( $set_idx <= $s_limit) {
        $filename= $classpath . "/records/set" . "$set_idx" . ".db";
        if(-f $filename) {
          printf "    %2d: ", $set_idx;
          open(IN, "<$filename") || die "Cannot open file $filename!";
          $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
          while ( ($input_line = <IN>) && !$found) { 
            $line_cnt++;       # add one to line count
            if( $line_cnt > 3) {    # start from line 4 is the student data
              chomp($input_line);              # delete the trailing '\n' char
              $s_num = substr($input_line,0,9);
              $s_num = uc($s_num);
              if( $student_id eq $s_num ) {
                $found = 1; 
                $data = substr($input_line,10);
                ($ans_str,$try_str) = split(/,/,$data,2);
                print "$ans_str\n          $try_str\n";
              }
            } # $line_cnt > 3 
          } # end while $input_line and ! $found
          close(IN) || die "Cannot close file $filename!";
          if(! $found ) {  # student record entry not in the setX.db file ==> two empty lines
            print "\n\n";  
          }
        } else { # $filename does not exist
          $done = 1; 
        }
      } else { # $set_idx > $s_limit
        $done = 1; 
      }
    }
    printf "Press RETURN to continue"; $tmp = <>;
 }

#
# INPUTS: class name with full path, set number
#
sub S_ItemAnalysis {
    local($classpath,$set)=@_;
    local($filename,$found,$classname);
    local($done)=0;
    local($line_cnt,$input_line);
    local($valid,$valid_cnt);
    local(@weights);       # the wights array for individual set
    local($valid_weights); # the valid weights for a set
    local($total_weights); # the overall valid weights for all sets
    local(@set_weights);   # the array storing all set valid weights
    local($score);         # the valid score for a set
    local($total_scores);  # the overall valid scores for all sets
    local(@set_scores);    # the array storing all set scores
    local($diff,$disc);
    local($ii,$upper_percent,$lower_percent);
    local($s_num,$ans_str,$prefix,$rest);
    local(@ans_char,$ratio,$tmp);
    local($Y_cnt[100],$N_cnt[100]);
    local($Ycnt_upper[100],$Ycnt_lower[100],$tmp_total);
    local($Y_total,$N_total);
    local($upperpart_cnt,$lowerpart_limit);
    local(%s_db);
    
    $total_scores = 0; $total_weights = 0; # initialize the overall results
    $upper_percent = 0.0; $lower_percent = 0.0;
    
    for($ii=0;$ii<100;$ii++) {
      $Y_cnt[$ii] = 0; $N_cnt[$ii] = 0; $Ycnt_upper[$ii] = 0.0; $Ycnt_lower[$ii] = 0.0;
    }
    $filename = $classpath . "/records/set" . "$set" . ".db";
    if( -f $filename) { # file exists!
      open(IN, "<$filename") || die "Cannot open file $filename!";
      $valid_cnt = 0; # initialize $valid_cnt
      $line_cnt=0;    # initialize $line_cnt
      while (<IN>) {
        $line_cnt++;       # add one to line count
        if( $line_cnt == 2 ) { # second line is the weight for each problem
          chomp();             # delete the trailing '\n' char
          (@weights) = split(/ */);  # split the line into each individual chars
          $valid_weights = 0;
          for($ii=0;$ii<=$#weights;$ii++) {
            $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
          }
        }
        if( $line_cnt > 3) {    # start from line 4 is the student data
          chomp();              # delete the trailing '\n' char
          ($prefix,$rest) = split(/,/,$_,2);        # split the whole line into two parts
          ($s_num,$ans_str) = split(/ /,$prefix,2); # split into two parts
          $s_num = uc($s_num);
          
          ### print "$ans_str\n";
          (@ans_char) = split(/ */,$ans_str);  # split the answer string into in dividual ans chars
          for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1 , to last question -1
              $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
          }
          if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
            $valid_cnt++;
            for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii

              if($ans_char[$ii] eq 'Y' || $ans_char[$ii] eq 'y') {
                $score += $weights[$ii];
                $Y_cnt[$ii]++;
                $Y_total++;
              }
              if( $ans_char[$ii] eq 'N' || $ans_char[$ii] eq 'n' || 
                  $ans_char[$ii] eq '0' ) {
                $N_cnt[$ii]++;
                $N_total++;
              }
              if( $ans_char[$ii] gt '0' && $ans_char[$ii] le '9') {
                $score += $ans_char[$ii];
                if( $ans_char[$ii] eq $weights[$ii] ) {
                  $Y_cnt[$ii]++;
                  $Y_total++;
                } else {
                  $N_cnt[$ii]++;
                  $N_total++;
                }
              } 
              if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                $valid_weights -= $weights[$ii];
              }
            } # end of score calculation
            
            $sort_key = sprintf "%05d%s", $score,$s_num;
            $s_db{$sort_key} = "$ans_str";
            
          }
        }   # end $line_cnt > 3
      } # end while <IN>
      close(IN) || die "Cannot close file $filename!";

      for($ii=0;$ii<100;$ii++) {
        ## $Y_cnt[$ii]=0; $N_cnt[$ii]=0; 
        $Ycnt_upper[$ii] = 0; $Ycnt_lower[$ii] = 0;
      }
      $upperpart_cnt   = int(0.27 * $valid_cnt);   # upper  27 percent
      $lowerpart_limit = ($valid_cnt - $upperpart_cnt);   # beyond 73 percent
      ### open(DBUG, ">/tmp/f.DBUG") || die "Cannot open /tmp/f.DBUG file!";
      $line_cnt=0;
      foreach $sort_key (reverse sort keys %s_db) {
        $line_cnt++;
        ### print DBUG "$sort_key\[$s_db{$sort_key}\]";
        
        $ans_str = "$s_db{$sort_key}";
        (@ans_char) = split(/ */,$ans_str);
        for($ii=0;$ii<=$#ans_char;$ii++) {
          if( ($ans_char[$ii] eq 'Y') || ($ans_char[$ii] eq 'y') ||
              ($ans_char[$ii] eq $weights[$ii] ) ) {  ## only if they got a full credit that 
                                                      ## we count it as 'Y'
           
              if($line_cnt <= $upperpart_cnt) {
                $Ycnt_upper[$ii]++;
              } elsif ( $line_cnt > $lowerpart_limit ) {
                $Ycnt_lower[$ii]++;
              }
          }
          ### print DBUG " $Ycnt_upper[$ii]/$Ycnt_lower[$ii] ";
        } # end for $ii
        ### print DBUG "\n";
      } #end foreach
      ### close(DBUG);
      print " There are $valid_cnt entries in file $filename\n";
      printf "  The upper 27%% has %d records, the lower 27%% has %d records\n", $upperpart_cnt, $valid_cnt-$lowerpart_limit;
      print " question \#     DoDiff.      Disc. Factor (%upper - %lower) [#records,#records]\n";
      
      for($ii=0;$ii<=$#ans_char;$ii++) {
        $tmp_total = $N_cnt[$ii] + $Y_cnt[$ii];
        if( $tmp_total > 0 ) {
          $diff = 100.0*($N_cnt[$ii] / ($N_cnt[$ii] + $Y_cnt[$ii]));
        } else {
          $diff = '-';
        }
        $upper_percent =  100.0 * ($Ycnt_upper[$ii] /$upperpart_cnt);
        $lower_percent =  100.0 * ($Ycnt_lower[$ii] /$upperpart_cnt);
        $disc = $upper_percent  - $lower_percent;
        printf "         %2d:    ", $ii+1;
        printf "%6.1f         %5.1f (% 5.1f - % 5.1f) [%4d,%4d]\n", 
                $diff, $disc,$upper_percent,$lower_percent,$Ycnt_upper[$ii],$Ycnt_lower[$ii];
      }
      printf "Press RETURN to continue"; $tmp = <>;
    } else { # file does not exist!
      print "FILE: $filename does not exist!\n";
      printf "Press RETURN to continue"; $tmp = <>;
    }
 }

#
# INPUTS: class name with full path, set number
#
sub  S_SetCorrelation {
     local($classpath,$set)=@_;
     local($filename);
     local($line_cnt);
     local($data,$ans_str,@ans_char,$try_str);
     local($ii,$jj,$question_cnt);
     local($index_key,@weights);
     local($first_char,$second_char);
     local(%corr,%valid_cnt,$ratio,$tmp,$tmp_len,$ratio_str);
     
     $filename= $classpath . "/records/set" . "$set" . ".db";

     if(-f $filename) {
       open(IN, "<$filename") || die "Cannot open file $filename!";
       $line_cnt=0;
       while(<IN>) {
         $line_cnt++;
         if( $line_cnt == 2 ) { # second line is the weight for each problem
          chomp();             # delete the trailing '\n' char
          (@weights) = split(/ */);  # split the line into each individual chars
        }
         if( $line_cnt > 3) {
           chomp();
           $data = substr($_,10);  # skip over student number
           ($ans_str,$try_str) = split(/,/,$data,2);
           (@ans_char) = split(/ */,$ans_str);
           $question_cnt = $#ans_char;
           for($ii=0;$ii<$#ans_char;$ii++) {
             for($jj=$ii+1;$jj<=$#ans_char;$jj++) {
               $index_key = "$ii" . "$jj";
               if( $ans_char[$ii] eq '-' || $ans_char[$ii] eq 'E' ) {
                 # do nothing
               } else {
                 if( $ans_char[$ii] gt '0' && $ans_char[$ii] le '9') {
                   if( $ans_char[$ii] eq $weights[$ii] ) {
                     $first_char = 'Y';
                   } else {
                     $first_char = 'N';
                   }
                 } elsif ($ans_char[$ii] eq '0') {
                   $first_char = 'N';
                 } elsif ($ans_char[$ii] eq 'y' || $ans_char[$ii] eq 'n') {
                   $first_char = uc($ans_char[$ii]);
                 } else {
                   $first_char = $ans_char[$ii];
                 }
                 if( $ans_char[$jj] eq '-' || $ans_char[$jj] eq 'E' ) {
                   # do nothing
                 } else {
                   if( $ans_char[$jj] gt '0' && $ans_char[$jj] le '9') {
                     if( $ans_char[$jj] eq $weights[$jj] ) {
                       $second_char = 'Y';
                     } else {
                       $second_char = 'N';
                     }
                   } elsif ($ans_char[$jj] eq '0') {
                     $second_char = 'N';
                   } elsif ($ans_char[$jj] eq 'y' || $ans_char[$jj] eq 'n') {
                     $second_char = uc($ans_char[$jj]);
                   } else {
                     $second_char = $ans_char[$jj];
                   }
                   if( $first_char eq $second_char ) {
                     if(defined $corr{$index_key} ) {
                       $corr{$index_key}++;
                     } else {
                       $corr{$index_key} = 1;
                     }
                   } else {
                     if(defined $corr{$index_key} ) {
                       $corr{$index_key}--;
                     } else {
                       $corr{$index_key} = -1;
                     }
                   }
                   # add one count to valid_count
                   if(defined $valid_cnt{$index_key}) {
                     $valid_cnt{$index_key}++;
                   } else {
                     $valid_cnt{$index_key} = 1;
                   }
                 }
               }
             } # end $jj loop
           } # end $ii loop
         } # end $line_cnt > 3
       } # end while <IN>
       close(IN) || die "Cannot close file $filename!";
       # print out the correlation matrix
       
       print "  ";
       for($ii=1;$ii<=$question_cnt;$ii++) {
         print " " x 4;
         printf "%2d", $ii+1;
       }
       print "\n";
       # --------------------------------------
       for($ii=0;$ii<$question_cnt;$ii++) {
         printf " %2d:", $ii+1;
         print  "      " x ($ii);
         for($jj=$ii+1;$jj<=$question_cnt;$jj++) {
           $index_key = "$ii" . "$jj";
           if( defined $corr{$index_key} ) {
             $ratio = $corr{$index_key} / $valid_cnt{$index_key};
             printf " % .2f", $ratio;
           } else {
             print "  ----";
           }
         }
         print "\n";
       }
       printf "Press RETURN to continue"; $tmp = <>;
     } else { # file exists!
       print "FILE: $filename does not exist!\n";
       printf "Press RETURN to continue"; $tmp = <>;
     }
 }

# INPUTS: class name with full path, set number
#
# r = \frac{\sum{x_i y_i} - \frac{(\sum x_i)(\sum y_i)}{n}}{\sqrt{(\sum x_i^2 - \frac{}{}}}
#
# corr = (sum of prod_xy - (sum_x*sum_y / n) ) / sqrt( (sum of sqr_x - (sum_x*sum_x/n))*
# 
sub  S_SetCorrelationStatistics {
     local($classpath,$set)=@_;
     local($filename);
     local($line_cnt);
     local($data,$ans_str,@ans_char,$try_str);
     local($ii,$jj,$question_cnt);
     local($index_key,@weights);
     local($x_data,$y_data);
     local(%valid_cnt,$ratio,$tmp,$tmp_len,$ratio_str);
     local(%prod_xy,%sum_x,%sum_y,%sum_x2,%sum_y2);
     local($upper_part,$lower_part);
     
     $filename= $classpath . "/records/set" . "$set" . ".db";

     if(-f $filename) {
       open(IN, "<$filename") || die "Cannot open file $filename!";
       $line_cnt=0;
       while(<IN>) {
         $line_cnt++;
         if( $line_cnt == 2 ) { # second line is the weight for each problem
          chomp();             # delete the trailing '\n' char
          (@weights) = split(/ */);  # split the line into each individual chars
        }
         if( $line_cnt > 3) {
           chomp();
           $data = substr($_,10);  # skip over student number
           ($ans_str,$try_str) = split(/,/,$data,2);
           (@ans_char) = split(/ */,$ans_str);
           $question_cnt = $#ans_char;
           for($ii=0;$ii<$#ans_char;$ii++) {
             for($jj=$ii+1;$jj<=$#ans_char;$jj++) {
               $index_key = "$ii" . "$jj";
               if( $ans_char[$ii] eq '-' || $ans_char[$ii] eq 'E' ) {
                 # do nothing
               } else { ## $ans_char[$ii] is one of 0 .. 9, Y, y, N, n
                 if( $ans_char[$jj] eq '-' || $ans_char[$jj] eq 'E' ) {
                   # do nothing
                 } else {
                   if( $ans_char[$ii] eq 'Y' || $ans_char[$ii] eq 'y' ) {
                     $x_data = $weights[$ii];
                   } elsif ( $ans_char[$ii] eq 'N' || $ans_char[$ii] eq 'n' ) {
                     $x_data = 0;
                   } else { ## must be in 0 .. 9
                     $x_data = $ans_char[$ii];
                   }
                   if( $ans_char[$jj] eq 'Y' || $ans_char[$jj] eq 'y' ) {
                     $y_data = $weights[$jj];
                   } elsif ( $ans_char[$jj] eq 'N' || $ans_char[$jj] eq 'n' ) {
                     $y_data = 0;
                   } else { ## must be in 0 .. 9
                     $y_data = $ans_char[$jj];
                   }
                   if(defined $prod_xy{$index_key}) {
		     if ( $ii == 3 && $jj == 7 ) {
		       printf "%f %f %f\n",$x_data,$y_data,$prod_xy{$index_key}
		     }
                     $prod_xy{$index_key} += ($x_data * $y_data);
		   } else {
		     if ( $ii == 3 && $jj == 7 ) {
		       printf "%f %f %f\n",$x_data,$y_data,0.0
		     }
                     $prod_xy{$index_key} = 0.0;
                   }
                   if(defined $sum_x{$index_key} ) {
                     $sum_x{$index_key}  += $x_data;
                   } else {
                     $sum_x{$index_key} = 0;
                   }
                   if(defined $sum_y{$index_key}) {
                     $sum_y{$index_key}  += $y_data;
                   } else {
                     $sum_y{$index_key} = 0;
                   }
                   if(defined $sum_x2{$index_key} ) {
                     $sum_x2{$index_key} += ($x_data * $x_data);
                   } else {
                     $sum_x2{$index_key} = 0;
                   }
                   if(defined $sum_y2{$index_key} ) {
                     $sum_y2{$index_key} += ($y_data * $y_data);
                   } else {
                     $sum_y2{$index_key} = 0;
                   }
                   # add one count to valid_count
                   if(defined $valid_cnt{$index_key}) {
                     $valid_cnt{$index_key}++;
                   } else {
                     $valid_cnt{$index_key} = 1;
                   }
                 }
               }
             } # end $jj loop
           } # end $ii loop
         } # end $line_cnt > 3
       } # end while <IN>
       close(IN) || die "Cannot close file $filename!";
       # print out the correlation matrix
       
       print "  ";
       for($ii=1;$ii<=$question_cnt;$ii++) {
         print " " x 4;
         printf "%2d", $ii+1;
       }
       print "\n";
       # --------------------------------------
       for($ii=0;$ii<$question_cnt;$ii++) {
         printf " %2d:", $ii+1;
         print  "      " x ($ii);
         for($jj=$ii+1;$jj<=$question_cnt;$jj++) {
           $index_key = "$ii" . "$jj";
           if( defined  $valid_cnt{$index_key}) {  ## there are at least one valid data
             $upper_part = $prod_xy{$index_key} - ( ($sum_x{$index_key} * $sum_y{$index_key}) / $valid_cnt{$index_key} );
             $lower_part = $sum_x2{$index_key} - ($sum_x{$index_key} * $sum_x{$index_key} / $valid_cnt{$index_key} );
             $lower_part = $lower_part * ( $sum_y2{$index_key} - ($sum_y{$index_key} * $sum_y{$index_key} / $valid_cnt{$index_key} ));
             $lower_part = sqrt($lower_part);
	     if ($ii == 3 && $jj==7) {
	       printf "%f %f %f %f",$prod_xy{$index_key},$sum_x{$index_key},$sum_y{$index_key},$valid_cnt{$index_key};
	     }
             if( $lower_part != 0.0 ) {
               $ratio = $upper_part / $lower_part;
               printf " % .2f", $ratio;
             } else {
               print "  inf ";
             }
           } else {
             print "  ----";
           }
         }
         print "\n";
       }
       printf "Press RETURN to continue"; $tmp = <>;
     } else { # file exists!
       print "FILE: $filename does not exist!\n";
       print "Press RETURN to continue"; $tmp = <>;
     }
 }
# -------------------------- Create a file contains all scores ----
#   it will 
sub   S_CreateScores {
     local($sfilename)=@_;
     local($filename);
     local($c_scores,$c_max_scores,$c_abscent,$c_count,$c_summary);
     local($q_scores,$q_max_scores,$q_abscent,$q_count,$q_summary);
     local($e_scores,$e_max_scores,$e_abscent,$e_count,$e_summary);
     local($s_scores,$s_max_scores,$s_abscent,$s_count,$s_summary);
     local($o_scores,$o_max_scores,$o_abscent,$o_count,$o_summary);
     local($c_ratio,$q_ratio,$e_ratio,$s_ratio,$o_ratio);
     local($m_1,$m_2,$m_3,$f_score);
     local($m_max1,$m_max2,$m_max3,$f_max);
     local($mt1_ratio,$mt2_ratio,$mt3_ratio,$f_ratio);
     local($var_name);
     local($total_score,$day_str);
     local($e_entry);
     local($s_key,%f_entry,$pre_entry,$whole_entry,$tail_entry,$score_str);
     local($tmp);
    
    $day_str = &TimeString;
    
    $filename = "$ClassPath" . "/classl";
    
    open(CIN, "<$filename") || die "Cannot open file $filename!";
    while(<CIN>) {
      chomp();
      $s_id = substr($_,14,9); $s_id = uc($s_id);
      
      # $homework_scores_limit_set comes from capa.config
      ($c_scores,$c_max_scores,$c_abscent,$c_count,$c_summary) =
       &S_CollectSetScores($ClassPath,"$s_id",0,$homework_scores_limit_set);
       
      $c_ratio = $c_scores/$c_max_scores if $c_max_scores != 0;
      ## print "$c_scores/$c_max_scores,$c_abscent/$c_count\n";
      
      # $quiz_scores_limit_set comes from capa.config
      ($q_scores,$q_max_scores,$q_abscent,$q_count,$q_summary) = 
        &S_CollectSetScores($QuizPath,"$s_id",0,$quiz_scores_limit_set) if -d "$QuizPath";
      $q_ratio = $q_scores/$q_max_scores if $q_max_scores != 0;
      ## print "$q_scores/$q_max_scores,$q_abscent/$q_count\n";
      
      # exam has different formula
      
      ($m_1,$m_max1,$m_2,$m_max2,$m_3,$m_max3,$f_score,$f_max,$e_count) = S_CollectExamScores($ExamPath,"$s_id") if -d "$ExamPath";
      
      # we can evaluate midterm1 when $e_count > 2 
      #  the perl code for midterm1 is stored in $P_code{'midterm1'}
      # FORMULA for exam scores
      if( $e_count < 1 ) { # 0  set, no extrapolated scores
        $e_scores = 0;
        $tail_entry = "     --/--      --/--      --/--   --/--    ";
                      
      } elsif ( ($e_count == 1) || ($e_count == 2) ) {
        $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
        $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt1_ratio + $mt3_percent * $mt1_ratio + $final_percent * $mt1_ratio;
        $e_entry = sprintf " %6.2f/%3d     --/--      --/--   --/--    ", $m_1,$m_max1;
      } elsif ( ($e_count == 3) || ($e_count == 4) ) {
        $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
        $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
        $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + 
                    (($mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio)*0.5) + 
                    $final_percent * (($m_1 + $m_2)/($m_max1 + $m_max2));
        $e_entry = sprintf " %6.2f/%3d %6.2f/%3d     --/--   --/--    ", $m_1,$m_max1,$m_2,$m_max2;
      } elsif ( ($e_count == 5) || ($e_count == 6) ) {
        $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
        $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
        $mt3_ratio = $m_3/$m_max3 if $m_max3 != 0;
        $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + $mt3_percent * $mt3_ratio +
                    $final_percent * (($m_1+$m_2+$m_3)/($m_max1+$m_max2+$m_max3));
        $e_entry = sprintf " %6.2f/%3d %6.2f/%3d %6.2f/%3d  --/--    ", $m_1,$m_max1,$m_2,$m_max2,$m_3,$m_max3;
      } else { # suppose to be 7
        $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
        $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
        $mt3_ratio = $m_3/$m_max3 if $m_max3 != 0;
        $f_ratio   = $f_score/$f_max if $f_max != 0;
        $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + $mt3_percent * $mt3_ratio + $final_percent * $f_ratio;
        $e_entry = sprintf " %6.2f/%3d %6.2f/%3d %6.2f/%3d %3d/%3d   ",$m_1,$m_max1,$m_2,$m_max2,$m_3,$m_max3,$f_score,$f_max;
      }
      
      # $supp_scores_limit_set comes from capa.config
      ($s_scores,$s_max_scores,$s_abscent,$s_count,$s_summary) = 
        &S_CollectSetScores($SuppPath,"$s_id",0,$supp_scores_limit_set) if -d "$SuppPath";
      $s_ratio = $s_scores/$s_max_scores if $s_max_scores != 0;
      ## print "$s_scores/$s_max_scores,$s_abscent/$s_count\n";
      
      # $others_scores_limit_set comes from capa.config
      ($o_scores,$o_max_scores,$o_abscent,$o_count,$o_summary) = 
        &S_CollectSetScores($OthersPath,"$s_id",0,$others_scores_limit_set) if -d "$OthersPath";
       $o_ratio = $o_scores/$o_max_scores if $o_max_scores != 0;
      ## print "$o_scores/$o_max_scores,$o_abscent/$o_count\n";
      
      
      $total_score = $hw_percent*$c_ratio + $qz_percent*$q_ratio + $e_scores;

      $score_str = sprintf "% 6.2f", $total_score;
      $s_key = sprintf "%06.2f %s", $total_score,$s_id;
      # #            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total
      #
      # A12345678 123/123 123/123 123/123 123/123 123.45/123 123.45/123 123.45/123 123/123   123.45
      #
      # A23546721 335/341  45/ 45   0/ 15  76/ 81  30.00/ 30  28.60/ 30  30.00/ 30  56/ 57   100.39
      # A23778965 333/341  34/ 45   1/ 15  79/ 81  27.90/ 30  28.60/ 30  28.60/ 30  55/ 57    96.72
      # A11111111   0/341   0/ 45  14/ 15   0/ 81   0.00/ 30   0.00/ 30   0.00/ 30   0/ 57     0.00
      # 173533390   0/341   0/ 45  15/ 15   0/ 81   0.00/ 30   0.00/ 30   0.00/ 30   0/ 57     0.00

      $pre_entry = sprintf "%3d/%3d %3d/%3d %3d/%3d %3d/%3d",
       $c_scores,$c_max_scores,$q_scores,$q_max_scores,$q_abscent,$q_count,$s_scores,$s_max_scores;
      
      
      $tail_entry = sprintf "%6.2f", $total_score;
      
      
      $whole_entry = "$s_id " . "$pre_entry" . "$e_entry" . "$tail_entry\n";
      
      $f_entry{$s_key} = $whole_entry;
      print " $s_id $score_str \[$pre_entry\]\n";
      print "\t\t\[$e_entry $tail_entry\]\n";
    }
    close(CIN) || die "Cannot close file $filename!";
    # close the classl file and

    # open the set score report file
     if(-f $sfilename) {  # if there is already a scores file, move it to something else
       system("mv $sfilename $sfilename.prior.$day_str");
     }
     open(OUT, ">$sfilename") || die "Cannot open file $sfilename!";
     print OUT "\#            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total\n";
     foreach $s_key (reverse sort keys %f_entry) {
       print OUT "$f_entry{$s_key}";
     }
     close(OUT) || die "Cannot close file $sfilename!";
 }
 
#
#  create all emails in the Mail/ directory
#  input is the master scores file name
sub    S_CreateEmails {
    local($sfilename)=@_;
    local($efilename);
    local($s_id);
    local($var_name,$s_sec,$email);
    local($q_scores,$q_max_scores,$q_absent,$q_count,$q_summary);
    local($last_n,$first_n,$first_part,$middle_n);
    local($day_str,$cat,$tmp);
    
    # variable $Email_templateFile comes from capa.config entry email_template_file 
    &ScanMailTemplate("$Email_templateFile");
    
    # after scanning the email template file, $P_code{'email_perl'} and $P_code{'template'} are defined
    #  in the code $P_code{'email_perl'}, we need to define 
    #     $final_grade and 
    #   $category_one_high, $category_one_low, .. comes from capa.config
    #   output $Summary_sentence
    
    #  in the code $P_code{'template'}
    $day_str = &TodayString;
    
    if(-f $sfilename) {
      open(SIN, "<$sfilename") || die "Cannot open file $sfilename!";
      while(<SIN>) {
      #           1         2         3         4         5         6         7         8         9
      # 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
      # #            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total
      # A23546721 335/341  45/ 45   0/ 15  76/ 81  30.00/ 30  28.60/ 30  30.00/ 30  56/ 57   100.39
        if(! /^\#/) {  # non comments line
          $s_id = substr($_,0,9); $s_id = uc($s_id);
          $var_name = $Var_name{'Homework_total_score'};
          ${$var_name} = int( substr($_,10,3) );  # homework total score
          $var_name = $Var_name{'Homework_total_max'};
          ${$var_name} = int( substr($_,14,3) );  # max score
          $var_name = $Var_name{'Quiz_total_score'};
          ${$var_name} = int( substr($_,18,3) );  # quiz score
          $var_name = $Var_name{'Quiz_total_max'};
          ${$var_name} = int( substr($_,22,3) );  # quiz max
          
          $var_name = $Var_name{'Quiz_absent'};
          ${$var_name} = int( substr($_,26,3) );  # quiz absent
          
          $var_name = $Var_name{'Quiz_count'};
          ${$var_name} = int( substr($_,30,3) );  # quiz count
          
          # need to take care of '--'
          
          $midterm1 = substr($_,42,6);
          $midterm_max1 = int( substr($_,49,3));
          
          $midterm2 = substr($_,53,6);
          $midterm_max2 = int( substr($_,60,3));
          
          $midterm3 = substr($_,64,6);
          $midterm_max3 = int( substr($_,71,3));
          
          $final_exam = substr($_,75,3);
          $final_exam_max = int( substr($_,79,3));
          
          $final_grade = substr($_,85,6);  # server as input to $P_code{'email_perl'}
          
          $final_grade = $final_grade * 1.0;
          
          ## print "PERL: $P_code{'email_perl'}\n";
          ## print "Press RETURN to continue"; $tmp = <>;
          
          ## print "SUMMARY: $Summary_sentence\n";
          ## print "Press RETURN to continue"; $tmp = <>;
          
          # now we know $Exam_sentence and $Summary_sentence
          
    # for $P_code{'template'}, we need to find
    #   Global input
    #         $student_name, $ClassName, there is already a $ClassName global variable
    #         ${$Var_name{'Homework_total_score'}} ==> $HWtotal_scp
    #         ${$Var_name{'Homework_total_max'}}   ==> $HWtotal_max_scp
    #         ${$Var_name{'Quiz_count'}}           ==> $QZcount_scp
    #         ${$Var_name{'Quiz_total_score'}}     ==> $QZtotal_scp 
    #         ${$Var_name{'Quiz_total_max'}}       ==> $QZtotal_max_scp
    
    #         ${$Var_name{'Quiz_summary_string'}}  ==> $QZsummary <-- must read from the qz/records/*.db files
    
    #         $midterm1, $midterm2, $midterm3 and $final_exam
    #     
    ##  How to allow the format of $student_name customizable from capa.config file?
    ##
          ($student_name,$s_sec,$email) = S_Lookup_student_name("$s_id");
          ($last_n,$first_part) = split(/,/,$student_name);
          $first_part =~ s/^\s//g;
          ($first_n,$middle_n) = split(/ /,$first_part);
          $student_name = "$first_n" . " $last_n";
          
          # $quiz_scores_limit_set comes from capa.config
          ($q_scores,$q_max_scores,$q_absent,$q_count,$q_summary) = 
            &S_CollectSetScores($QuizPath,"$s_id",0,$quiz_scores_limit_set) if -d "$QuizPath";
          ${$Var_name{'Quiz_summary_string'}} = "$q_summary";
          ${$Var_name{'Quiz_absent'}} = $q_absent;
          ${$Var_name{'Quiz_count'}}  = $q_count;
          eval "$P_code{'email_perl'}";
          if( ($final_grade <= $category_one_high) && ($final_grade >= $category_one_low)) {
            $cat = 1;
          } elsif ( ($final_grade <= $category_two_high)&&($final_grade >= $category_two_low) ) {

            $cat = 2;
  
          } elsif ( ($final_grade <= $category_three_high)&&($final_grade >= $category_three_low)  ) {

            $cat = 3;
  
          } elsif( ($final_grade <= $category_four_high)&&($final_grade >= $category_four_low) ) {

            $cat = 4;
  
          } else { # not in above category

            $cat = 5;
          }
          
          $efilename = "$ClassPath" . "/Mail/$s_id.$day_str.$cat";
          
          if(-f $efilename) {  # remove the file with the same name, no warning!!
            system("rm $efilename");
          }
          open(EOUT,">$efilename") || die "Cannot create file $efilename!";
          eval "print EOUT \"$P_code{'template'}\" ";
          close(EOUT) || die "Cannot close file $efilename!";
          
          print " $s_id\t$final_grade,\tcategory $cat\n";
          
        }
      }
      close(SIN) || die "Cannot close file $sfilename!";
      print "=" x 45 . "\n";
      print "DONE creating all email files in $ClassPath/Mail/ directory.\n";
      print "Press RETURN to continue"; $tmp = <>;
    } else {  # the master scores file does not exist
      print "File $sfilename does not exist!\n";
      print "Press RETURN to continue"; $tmp = <>;
    }
       
 }
# ----------------------------------------------------------------
sub    ScanMailTemplate {
  local($filename) = @_;
  local($input_line);
  local($tmp);
  
  
  if(-f $filename) {
    open(IN, "<$filename") || die "Cannot open $filename\n";
    LINE: while( $input_line = <IN> ) {
       chomp($input_line);
       if($input_line =~ m|^//| )   { next LINE; }          ## ignore comments
       if($input_line =~ m|^\#| )   { next LINE; }          ## ignore comments
       if($input_line =~ m|^\s*BEGIN_perl| ) { ## Perl code
         $P_code{'email_perl'} = &E_CollectPerlCode;
         ## print "email_perl=$P_code{'email_perl'}";
         next LINE; 
       }
       if($input_line =~ m|^\s*BEGIN_template| )  { ## template code
         $P_code{'template'} = &E_CollectTemplateCode;
         ## print "template = $P_code{'template'}";
         next LINE; 
       }
       next LINE;
    }
    close(IN) || die "Cannot close $filename\n";
    
  } else {
    printf "File $filename does not exist!"; $tmp = <>;
  }

 }

# 
#  Randomly pick a file in Mail/ directory and display 
#   it on screen
#  
sub    S_RandomlyPreview {
    local($filename);
    local(@all_files);
    local($upper_bound);
    local($pick_idx,$pick_filename);
    local($tmp);
    
    opendir(EDIR, "$ClassPath/Mail") || die "cannot opendir $ClassPath/Mail!";
    @all_files = grep !/^\.\.?$/, readdir EDIR;
    closedir EDIR;
       ## srand(time() ^ ($$+( $$ << 15)) );
       
    $upper_bound = $#all_files + 1;
    if( $upper_bound > 0 ) { # something to preview   
       $pick_idx = ((rand $$) * 1000.0) % $upper_bound;
       
       # print "PICK: $pick_idx among $upper_bound\n";
       
       $pick_filename = $all_files[$pick_idx];
       print "Preview File: $pick_filename\n";
       print "Press RETURN to continue"; $tmp = <>;     &C_ClearScreen;
       $filename = "$ClassPath/Mail/$pick_filename";
       open(IN,"<$filename") ||  die "Cannot open file $filename!";
       while(<IN>) {
         print;
       }
       close(IN) || die "cannot close file $filename!";
       print "Press RETURN to continue"; $tmp = <>;
    } else {
       print "No file in directory $ClassPath/Mail\n";
       
       print "Press RETURN to continue"; $tmp = <>;
    
    }

 }
 

# The format of a classl file                                                                  
# 
#          1         2         3         4         5         6         7         8         9         0
#0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
#PHY 183   001 A23745301 Abraham, Christopher Wil            FS96
#phy 111   001 A12345678 BUMSTEAD, Blondie                   blondie4@pilot.msu.edu            12345678
#PHY 183   003 A24469315 Costigan, Timothy Patric            costiga3@pilot.msu.edu            costiga3
#PHY 183   002 A25425738 Cacossa, Andrew Vincent             cacossaa@pilot.msu.edu            cacossaa

# lookup the student id supplied in variable $student_id
# and return the student name and the e-mail address if available
sub    S_Lookup_student_name {
     local($student_id)=@_;
     local($filename);
     local($found,$input_line);
     local($tmp_sn,$student_name);
     local($len,$s_sec,$email);
     
  $student_id = uc($student_id);
  $filename = $ClassPath . "/classl";
  open(CIN, "<$filename") || die "Cannot open file $filename!";
  $found = 0;
  while( ($input_line = <CIN>) && (! $found) ) {
    chomp($input_line);
    $tmp_sn = substr($input_line,14,9); $tmp_sn = uc($tmp_sn);
    if($tmp_sn =~ /^$student_id/ ) {
      $found=1;
       # student name begins at column 24 and has 30 chars max
      $s_sec = substr($input_line,10,3);
      $student_name = substr($input_line,24,30);
      $len = length($input_line);
      $email = "";
      if($len > 55 ) {
        $email = substr($input_line,55,32);
        $email =~ s/\s+//g;
        if( $email !~ /\@|\./ ) {
          $email = "";
        }
      }
    }
  }
  close(CIN) || die "Cannot close file $filename!";
  return ($student_name,$s_sec,$email);
 }

#  This routine accepts a string represent an absolute path to a class
#   it checks to see if 
#      the directory specified by this path did actually exist
#      the records/ sub-directory did exist
#      the records/setX.db  file exists
#      the classl file exists

sub    S_CheckClassPath {
    local($path)=@_;
    local($cfullpath,$rfullpath,$sfullpath);
    local($correct,$cfgfullpath,$cfgutilsfullpath);
    
    $correct = 0;
    if( $path =~ /\/$/ ) {
        $cfullpath = "$path" . "classl";
        $rfullpath = "$path" . "records";
        $sfullpath = "$path" . "records/set$set.db";
        $cfgfullpath = "$path" . "capa.config";
        $cfgutilsfullpath = "$path" . "capautils.config";
    } else {
        $cfullpath = "$path" . "/classl";
        $rfullpath = "$path" . "/records";
        $sfullpath = "$path" . "/records/set$set.db";
        $cfgfullpath = "$path" . "/capa.config";
        $cfgutilsfullpath = "$path" . "/capautils.config";
    }
    if( -d $path ) {
        if( -d $rfullpath ) {
          if(-f $cfgfullpath ) {
	      if(-f $cfgutilsfullpath ) {
		  $correct = 1;
	      } else {
		  print "File [$cfgutilsfullpath] does not exist!\n";
	      }
          } else {
            print "File [$cfgfullpath] does not exist!\n";
          }
        } else {
          print "Directory [$rfullpath] does not exist!\n";
        }
    } else {
        print "Directory [$path] does not exist!\n";
    }
    return ($correct);
 }
 
##
# display score file according to the order specified 
#  by $key_str and the direction in $dir
#  $dir = 1 means ascending
#         2 means descending
#
sub   S_DisplayScoreFile {
    local($key_str,$dir,$sfilename)=@_;
    local(@a_keyidx);
    local($key_seq);
    local($s_id,$final_grade,$s_name,$s_sec,$s_email);
    local($sort_key,$s_display_name,$first_n,$first_part,$middle_n,$last_n);
    local(%sf_entry);
    local($line_cnt,$line_total,$len,$pad_len);
    local($tmp);
    
    $key_str =~ s/,//g;
    $key_str =~ s/1/\$final_grade/g;
    $key_str =~ s/2/\$s_id/g;
    if( $key_str =~ /3/ ) { 
      $key_str =~ s/3/\$s_name/g;
    }
    if( $key_str =~ /4/ ) { 
      $key_str =~ s/4/\$s_sec/g;
    }
    $key_seq = '"' . "$key_str" . '"';
    
    if(-f $sfilename) {
      open(SIN, "<$sfilename") || die "Cannot open file $sfilename!";
      $line_cnt = 0;
      while(<SIN>) {
        if(! /^\#/) {  # non comments line
          chomp();
          $line_cnt++;
          $s_id = substr($_,0,9); $s_id = uc($s_id);
          $final_grade = substr($_,85,6);  #
          
          $whole_entry = $_;
          ($s_name,$s_sec,$s_email) = S_Lookup_student_name("$s_id");
          # evaluate the code to a real key
          $sort_key = eval $key_seq;
          
          ($last_n,$first_part) = split(/,/,$s_name);
          $last_n = uc($last_n);
          $first_part =~ s/^\s//g;
          ($first_n,$middle_n) = split(/ /,$first_part);
          $s_display_name = "$last_n" . ", $first_n";
          $len = length($s_display_name);
          if( $len < 25 ) {
            $pad_len = 25 - $len;
            $s_display_name = "$s_display_name" . " " x $pad_len;
          } else {
            $s_display_name = substr($s_display_name,0,25);
          }
          $sf_entry{"$sort_key"} = "$s_display_name $s_sec $whole_entry";
          ### print "KEY:[$sort_key]:$whole_entry\n";
        } # end of if not comments
      } # end while <SIN>
      close(SIN) || die "Cannot close file $sfilename!";
      $line_total = $line_cnt; $line_cnt = 0;
      if($dir == 1 ) {
        foreach $sort_key (sort keys %sf_entry) {
          $line_cnt++;
          print $sf_entry{"$sort_key"} . "\n";
          if( ($line_cnt % $display_score_row_limit) == 0 ) { # $display_score_row_limit from capa.config
            print " --$line_cnt/$line_total-- Press RETURN to continue"; $tmp = <>;
          }
        }
      } else {
        foreach $sort_key (reverse sort keys %sf_entry) {
          $line_cnt++;
          print $sf_entry{"$sort_key"} . "\n";
          if( ($line_cnt % $display_score_row_limit) == 0 ) {
            print " --$line_cnt/$line_total-- Press RETURN to continue"; $tmp = <>;
          }
        }
      }
    } else {
      print "File [$sfilename] does not exist!";
    }
    
 }

##
##   Input: file name to be printed through lpr command
##
##
sub  S_LPRFile {
     local($file)=@_;
     local($go_on)=0;
     local($select);
     local($printer_selected);
     local($emp);
     local($cmd);
     local($PS_file);
 
     print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
     $tmp=<>; $tmp =~ tr/A-Z/a-z/;
     $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
     
      if( $go_on ) { # run lpr -P.... on the .ps file
        $select = C_MultipleChoice(4,10,$DialogWidth,"           Printers Available         ",
                          "Printer Name",@Printers);
        $Printer_selected = $Printers[$select-1];
        
        $go_on = 0;
        while( ! $go_on ) {
          print "Enter 1 for one sided or 2 for two sided printing (RETURN = 1 sided): ";
          $tmp=<>; 
          if( ($tmp == 1) || ($tmp == 2) || ($tmp eq "\n") ) {
            $tmp = 1 if $tmp eq "\n";
            $go_on = 1;
          }
        }
        if( $tmp == 1 ) {
          $LpronesidedCMD =~ s/\$Printer_selected/$Printer_selected/e;
          $cmd = "$LpronesidedCMD $file";
        } else {  # should be 2
          $PS_file = $file;
          print "$LprtwosidedCMD\n";
          $LprtwosidedCMD =~ s/\$Printer_selected/$Printer_selected/e;
          $LprtwosidedCMD =~ s/\$PS_file/$PS_file/e;
          $cmd = "$LprtwosidedCMD";
        }
        $go_on = 0;
        print "=" x 70 . "\n";
        print "CMD: $cmd\n";
        print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
        $tmp=<>; $tmp =~ tr/A-Z/a-z/;
        $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
        if($go_on) {
          open(IN,"$cmd|");
          while($input_line = <IN>) {
            print "$input_line";
          }
          close(IN);
          print "=" x 70 . "\n";
          print " Your job has been sent to the print spooler. Press RETURN to continue"; $tmp = <>;
        }
      }
 }



# <========================= Main program =======================>

Getopts('c:s');

if (! $opt_c) {  ## class path option
  print "USAGE: capatools.pl -c Full_path_to_class\n";
  $ClassPath = &S_Enterpath;
} else {  # need to check the path entered by option -c
  if( S_CheckClassPath("$opt_c") ) {
    $ClassPath = $opt_c;
    if( $opt_s ) {
      S_ReadCAPAconfig($ClassPath);
      S_CreateScores("$Master_scoresFile");
      # print "run score report in silent background\n";
      # print "The $Master_scoresFile\n";
      
      exit (1);
    }
  } else {
    $ClassPath = &S_Enterpath;
  }
}

$DialogWidth = 48;
$Quit = 0;


$len = length($ClassPath);
if(  $len > ($DialogWidth-6) ) {  ## class path too long, display the last portion instead
    $offset = $len - $DialogWidth +6;
    $DisplayPath = "-..." . substr($ClassPath, $offset,$DialogWidth-6);
} else {
    $DisplayPath = $ClassPath;
}

S_ReadCAPAconfig($ClassPath);

while(! $Quit ) {
  $What = C_MultipleChoice(1,8,$DialogWidth,"        Welcome to CAPA Utilities Ver 1.1   ",
                          "$DisplayPath",@Main_menu);

  if( $What ==  1 ) {        # change class path
     $ClassPath = &S_Enterpath;
     $len = length($ClassPath);
     if(  $len > ($DialogWidth-6) ) {
       $offset = $len - $DialogWidth +6;
       $DisplayPath = "-..." . substr($ClassPath, $offset,$DialogWidth-6);
     } else {
       $DisplayPath = $ClassPath;
     }
     S_ReadCAPAconfig($ClassPath);
  } elsif ($What ==  2 ) {   # run capastat.pl
     $Set  = &S_InputSet;
     $Sfullpath = $ClassPath . "/records/set" . "$Set" . ".db";
     ## print "Running capastat.pl on $Sfullpath\n";
     ($Q_cnt,$L_cnt) =  &S_ScanSetDB($Sfullpath);
     Percentage_Scores($Set,$L_cnt);
     S_Average($Q_cnt,$L_cnt);
     
     ## Large_Tries($opt_t,$opt_n,$Q_cnt,$L_cnt);
  } elsif ($What == 3 ) {   # log analysis on S, U, 
     $Set  = &S_InputSet;
     
     $Lfullpath = $ClassPath . "/records/log" . "$Set" . ".db";
     if(-f $Lfullpath) {
       print "Log analysis for telnet session log$Set.db\n";
       print " This may take a while to calculate, please wait ...\n";
       ($Y_l,$N_l,$S_l,$U_l,$u_l) = S_ScanLogDB($Lfullpath);
     }
     $Wfullpath = $ClassPath . "/records/weblog" . "$Set" . ".db";
     if(-f $Wfullpath ) {
       print "=" x 79 . "\n";
       print "Log analysis for web session weblog$Set.db\n";
       print " This may take a while to calculate, please wait ...\n";
       ($Y_w,$N_w,$S_w,$U_w,$u_w) = S_ScanLogDB($Wfullpath);
     }
     $Telnet_total = $Y_l+$N_l+$S_l+$U_l+$u_l;
     $Web_total    = $Y_w+$N_w+$S_w+$U_w+$u_w;
     
     print "============== SUMMARY ====================\n";
     print "            #Y     #N     #S     #U     #u    Total\n";
     printf  "telnet: %6d %6d %6d %6d %6d   %6d\n", $Y_l, $N_l, $S_l, $U_l, $u_l,$Telnet_total;
     printf  "   web: %6d %6d %6d %6d %6d   %6d\n", $Y_w, $N_w, $S_w, $U_w, $u_w,$Web_total;
     $Y_sum = $Y_l + $Y_w;
     $Ratio_Y = 100.0 * ($Y_w / $Y_sum) if $Y_sum > 0;
     $N_sum = $N_l + $N_w;
     $Ratio_N = 100.0 * ($N_w / $N_sum) if $N_sum > 0;
     $S_sum = $S_l + $S_w;
     $Ratio_S = 100.0 * ($S_w / $S_sum) if $S_sum > 0;
     $U_sum = $U_l + $U_w;
     $Ratio_U = 100.0 * ($U_w / $U_sum) if $U_sum > 0;
     $u_sum = $u_l + $u_w;
     $Ratio_u = 100.0 * ($u_w / $u_sum) if $u_sum > 0;
     $overall_entries = $Telnet_total+$Web_total;
     $Ratio_web = 100.0*($Web_total/$overall_entries) if $overall_entries > 0;
     printf  "  %%web: % 6.1f % 6.1f % 6.1f % 6.1f % 6.1f   % 6.1f\n", 
       $Ratio_Y, $Ratio_N, $Ratio_S, $Ratio_U, $Ratio_u, $Ratio_web;
     printf "Press RETURN to continue"; $tmp = <>;
     
  } elsif ($What ==  4 ) {   # Student course profile
    # select either use student name or student number
    # if there are more than two students, display them in a table to select
    #    by the user
    # use student id to find the scores
    # display set scores in each class, regular class goes first.
    # S_InputStudent;
    ($s_id,$s_nm) = S_InputStudent($ClassPath);
    if($s_id ne "" ) {
      print "$s_nm\n";
      &S_CollectSetScores($ClassPath,"$s_id",1,$homework_scores_limit_set);
      &S_CollectSetScores($QuizPath,"$s_id",1,$quiz_scores_limit_set)   if -d "$QuizPath";
      &S_CollectSetScores($ExamPath,"$s_id",1,$exam_scores_limit_set)   if -d "$ExamPath";
      &S_CollectSetScores($SuppPath,"$s_id",1,$supp_scores_limit_set)   if -d "$SuppPath";
      &S_CollectSetScores($OthersPath,"$s_id",1,$others_scores_limit_set) if -d "$OthersPath";
      
      
      print "\nEnter Y or <RETURN> for Login analysis (may take a while)\n";
      print "Enter N => return to main menu: ";
      $tmp=<>; $tmp =~ tr/A-Z/a-z/;
      $go_on = 0;
      $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
      
      if($go_on) {
        # $homework_scores_limit_set comes from capa.config
        &S_LoginAnalysis($ClassPath,"$s_id",$homework_scores_limit_set);
        &S_StudentSetAnalysis($ClassPath,"$s_id",$homework_scores_limit_set);
      }
      
    }
  } elsif ($What ==  5 ) {   # CAPA IDs for one student
    ($s_id,$s_nm) = S_InputStudent($ClassPath);
    if($s_id ne "" ) {
      $go_on = 0;
      print "$s_nm, $Allcapaid\n";
      ($S_from, $S_to) = S_EnterSets;
      
      print "\nCMD: $AllcapaidCMD -i -stu $s_id -s $S_from -e $S_to\n";
      print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
      $tmp=<>; $tmp =~ tr/A-Z/a-z/;
      $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
      if( $go_on ) {
        open(IN,"$AllcapaidCMD -i -stu $s_id -s $S_from -e $S_to -c $ClassPath|");
        while($input_line = <IN>) {
          print "$input_line";
        }
        close(IN);
        printf "Press RETURN to continue"; $tmp = <>;
      }
    }
  } elsif ($What ==  6 ) {   # All CAPA IDs
     $go_on = 0;
     ($S_from, $S_to) = S_EnterSets;
     print "\nCMD: $AllcapaidCMD -s $S_from -e $S_to\n";
     print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
     $tmp=<>; $tmp =~ tr/A-Z/a-z/;
     $go_on = 1 if $tmp =~ /^Y/ || $tmp eq "\n";
     if( $go_on ) { 
       open(IN,"$AllcapaidCMD -s $S_from -e $S_to -c $ClassPath|");
       while($input_line = <IN>) {
         print "$input_line";
       }
       close(IN);
       print "Press RETURN to continue"; $tmp = <>;
     }
     
  } elsif ($What ==  7 ) {   # Item analysis
     $u_path = C_MultipleChoice(4,10,$DialogWidth,"Select a Class path","",@MainPath);
     
     $Set  = &S_InputSet;
     print "Item analysis for $MainPath[$u_path-1], Set $Set\n";
     print "This may take a while to calculate, please wait ...\n";
     S_ItemAnalysis($MainPath[$u_path-1],$Set);
  } elsif ($What ==  8 ) {   # Correlation chart
  ## TO DO:
  ##         Let user specify how many categories to calculate correlation
  ##             For each category, the user can specify problem numbers to 
  ##             be in that category
  ##         Then, the correlations between each category is calculated
  ##
     $u_path = C_MultipleChoice(4,10,$DialogWidth,"Select a Class path","",@MainPath);
     $Set  = &S_InputSet;
     print "Correlation calculation for $MainPath[$u_path-1], Set $Set\n";
     print "This may take a while to calculate, please wait ...\n";
     S_SetCorrelationStatistics($MainPath[$u_path-1],$Set);
  } elsif ($What ==  9 ) {   # E-Mail
     $done_email = 0;
     while(! $done_email ) {
       $select = C_MultipleChoice(2,10,$DialogWidth+15,"    CAPA E-mail facilities       ",
                          "$DisplayPath",@Email_menu);
      if($select == 1 ) {  # Create scores file
        # the variable $Master_scoresFile comes from capa.config entry master_scores_file = ...
        print "Create a file containing scores of all students:\n";
        print " $Master_scoresFile\n";
        print "This may take a while to complete, please wait ...\n";
        S_CreateScores("$Master_scoresFile");
      } elsif ($select == 2 ) { # create all e-mail files in Mail/ dir
        print "Create e-mail files in $ClassPath/Mail/ directory\n";
        print " based on scores file $Master_scoresFile\n";
        print "This action will REPLACE the original file(s) in the Mail/ directory!\n";
        $go_on = 0;
        print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
        $tmp=<>; $tmp =~ tr/A-Z/a-z/;
        $go_on = 1 if $tmp =~ /^Y/ || $tmp eq "\n";
        if( $go_on ) {
          print "This may take a while to complete, please wait ...\n";
        
          S_CreateEmails("$Master_scoresFile");
        }
      } elsif ($select == 3 ) { # Preview e-mail
       # randomly pick a student 
       # 
       &S_RandomlyPreview;
       
      } elsif ($select == 4 ) { # Send e-mail to a group of students
       $entered_cat = &S_EnterCategory;
       
       $go_on = 0;
       print "Entered category: $entered_cat\n";
       print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
       $tmp=<>; $tmp =~ tr/A-Z/a-z/;
       $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
       
       if( $go_on ) {
         S_MailtoCategory($entered_cat);
       }
         
      
       # 1. Whole class
       # 2. Category ---> specify 1, 2, 3, or 4
      } else { # 4. Cancel
         $done_email = 1;
      }
    }
  } elsif ($What == 10 ) {  # Print one assignment for a student
    ($s_id,$s_nm) = S_InputStudent($ClassPath);
    if($s_id ne "" ) {   # non-empty student id
      $s_id = uc($s_id); # uppercase
      
      ## $Set  = &S_InputSet;
      ($From_set,$To_set) = &S_EnterSets;
      print "Printing Set(s) $From_set to $To_set for STUDENT: $s_nm\n";
      $go_on = 0;
      print "\nEnter Y or <RETURN> to continue or N to cancel the operation: ";
      $tmp=<>; $tmp =~ tr/A-Z/a-z/;
      $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
      
      if($go_on) {
        $go_on = 0;
        print "CMD: $QzparseCMD -c $ClassPath -set $From_set:$To_set -stu $s_id\n";
        open(IN,"$QzparseCMD -c $ClassPath -set $From_set:$To_set -stu $s_id|");
        while($input_line = <IN>) {
          print "$input_line";
        }
        close(IN);
        print "=" x 70 . "\n";
        $tex_file = "$ClassPath" . "/TeX/" . "$s_id" . ".tex";
        print "CMD: $LatexCMD $tex_file\n";
        print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
        $tmp=<>; $tmp =~ tr/A-Z/a-z/;
        $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
        
      }
      # run qzparse on the student and the set
      #     qzparse -c $path -set $set -stu $s_id
      if( $go_on ) { # run latex on the .tex file, latex will create a .dvi file in cwd()
        $dir = cwd();
        $go_on = 0;
        
        open(IN,"$LatexCMD $tex_file|");
        while($input_line = <IN>) {
          print "$input_line";
        }
        close(IN);
        $cwd_dvi_file     = "$dir/" . "$s_id" . ".dvi";
        $dvi_file = "$ClassPath" . "/TeX/" . "$s_id" . ".dvi";
        $cmd = "mv $cwd_dvi_file $dvi_file";
        system($cmd);
        print "=" x 70 . "\n";
        $ps_file  = "$ClassPath" . "/TeX/" . "$s_id" . ".ps";
        print "CMD: $DvipsCMD $dvi_file -o $ps_file\n";
        print "\nEnter Y or <RETURN> to continue or N to cancel the operation: ";
        $tmp=<>; $tmp =~ tr/A-Z/a-z/;
        $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
      }
      if( $go_on ) {  # run dvips on the .dvi file
        

        open(IN,"$DvipsCMD $dvi_file -o $ps_file|");
        while($input_line = <IN>) {
          print "$input_line";
        }
        close(IN);
        print "=" x 70 . "\n";
        
        S_LPRFile($ps_file);
        
      }
    }
  
  } elsif ($What == 11 ) {  # view score file
    $entered_key = S_EnterSortKey;
    
    $display_key = $entered_key;
    $display_key =~ s/,/, /g;
    $display_key =~ s/1/Grade/g;
    $display_key =~ s/2/Student number/g;
    $display_key =~ s/3/Student name/g;
    $display_key =~ s/4/Section/g;
    print "Entered sorting key: $display_key\n";
    $go_on = 0;
    while(! $go_on) {
      print "Enter 1 for ascending or 2 for decending order (RETURN = 1 ascending): ";
      $tmp=<>; 
      if( ($tmp == 1) || ($tmp == 2) || ($tmp eq "\n") ) {
            $tmp = 1 if $tmp eq "\n";
            $go_on = 1;
      }
    }
    
    S_DisplayScoreFile($entered_key,$tmp,$Master_scoresFile);
    print "Finish displaying score file. Press RETURN to continue"; $tmp = <>;
  } elsif ($What == 12 ) {  # list student responses
    ($s_id,$s_nm) = S_InputStudent($ClassPath);
    if($s_id ne "" ) {
      $go_on = 0;
      print "$s_nm, grepping submissions\n";
      ($S_from, $S_to) = S_EnterSets;
      for( $i=$S_from;$i<=$S_to;$i++) {
	print "Telnet Submissions for $s_nm for set $i\n";
	open(IN,"grep -i $s_id $ClassPath/records/submissions$i.db |"); 
	while($input_line = <IN>) {
	  print "$input_line";
	}
	close(IN);
	printf "Press RETURN to continue"; $tmp = <>;
	print "WWW Submissions for $s_nm for set $i\n";
	open(IN,"grep -i $s_id $ClassPath/records/websubmissions$i.db|"); 
	while($input_line = <IN>) {
	  print "$input_line";
	}
	close(IN);
	printf "Press RETURN to continue"; $tmp = <>;
      }
    }
  } elsif ($What == 13 ) {  # quit
    $Quit = 1;
  }
}





FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>