Annotation of capa/capa51/CapaTools/capautils.1.1.pl, revision 1.3

1.1       albertel    1: #!/usr/local/bin/perl -I/usr/local/bin
                      2: 
1.2       albertel    3: # utilities for CAPA superseeded by Manager
                      4: #  Copyright (C) 1992-2000 Michigan State University
                      5: #
                      6: #  The CAPA system is free software; you can redistribute it and/or
1.3     ! albertel    7: #  modify it under the terms of the GNU General Public License as
1.2       albertel    8: #  published by the Free Software Foundation; either version 2 of the
                      9: #  License, or (at your option) any later version.
                     10: #
                     11: #  The CAPA system is distributed in the hope that it will be useful,
                     12: #  but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1.3     ! albertel   14: #  General Public License for more details.
1.2       albertel   15: #
1.3     ! albertel   16: #  You should have received a copy of the GNU General Public
1.2       albertel   17: #  License along with the CAPA system; see the file COPYING.  If not,
                     18: #  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
                     19: #  Boston, MA 02111-1307, USA.
                     20: #
                     21: #  As a special exception, you have permission to link this program
                     22: #  with the TtH/TtM library and distribute executables, as long as you
                     23: #  follow the requirements of the GNU GPL in regard to all of the
                     24: #  software in the executable aside from TtH/TtM.
1.1       albertel   25: # <==========================================================================>
                     26: # June 1997 version 1.0 Created by Isaac Tsai 
                     27: # September 24 1997 version 1.1 by Guy Albertelli II
                     28: #        -put in initialization loop in S_ScanSetDB (need to remove hardlimits)
                     29: #        -initialize Max_try in S_Average, before being used
                     30: #
                     31: # <==========================================================================>
                     32: use Cwd;
                     33: require('getopts.pl');
                     34: require('CAPAscreen.pl');
                     35: # =============================================================================
                     36: #  
                     37: # =============================================================================
                     38: $Days   = int( time / 86400);
                     39: @MonthName = ( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ); 
                     40: #
                     41: # produces a string  "ddMmm19xx"  to be used in timestamp or filename
                     42: #
                     43: sub  TodayString {
                     44:     local($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst);
                     45:     local($str);
                     46:  
                     47:   ($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst) = localtime(time);
                     48:    if ($mday > 9) {
                     49:      $str = "$mday$MonthName[$mth]19$yy";  # year 2000 problem!!
                     50:    } else {
                     51:      $str = "0$mday$MonthName[$mth]19$yy"; # year 2000 problem!!
                     52:    }
                     53:    return $str;
                     54:  }
                     55: #
                     56: # produces a string hhmmss-ddMon19xx for timestamps
                     57: #
                     58: sub  TimeString {
                     59:     local($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst);
                     60:     local($str);
                     61:  
                     62:   ($ss, $mm, $hh, $mday, $mth, $yy, $wday, $yday,$isdst) = localtime(time);
                     63:    $ss = "0" . "$ss" if $ss <= 9;
                     64:    $mm = "0" . "$mm" if $mm <= 9;
                     65:    $hh = "0" . "$hh" if $hh <= 9;
                     66:    if ($mday > 9) {
                     67:      $str = "$hh$mm$ss-$mday$MonthName[$mth]19$yy";  # year 2000 problem!!
                     68:    } else {
                     69:      $str = "$hh$mm$ss-0$mday$MonthName[$mth]19$yy"; # year 2000 problem!!
                     70:    }
                     71:    return $str;
                     72:  }
                     73: # =============================================================================
                     74: #  Read capa.config into global variables
                     75: #  
                     76: sub  S_ReadCAPAconfig {
                     77:      local($classpath)=@_;
                     78:      local($filename);
                     79:      local($filename2);
                     80:      local($tempfilename);
                     81:      local($input_line);
                     82:      local($done)=0;
                     83:      local($tmp);
                     84:      
                     85:      @MainPath=();
                     86:      push(@MainPath,$classpath);
                     87:      $ClassName = substr($classpath,-8,8);
                     88:      $filename="$classpath" . "/capa.config";
                     89:      $filename2="$classpath" . "/capautils.config";
                     90:      foreach $tempfilename ( $filename, $filename2 ) {
                     91:        if(-f $tempfilename) {
                     92:           open(IN, "<$tempfilename") || die "Cannot open file $tempfilename!";
                     93:           LINE: while( ($input_line = <IN>) && (! $done) ) {
                     94:              ## skip over comments
                     95:              if( $input_line =~ /^\#/ ) { next LINE; }  
                     96:              chop($input_line);
                     97:              #  collect _path information and create the corresponding global variable 
                     98:              if( ($input_line =~ /^(\w+)_path\s*=\s*["]([\.\d\+\-\w\s\/]+)["]$/) || 
                     99:                  ($input_line =~ /^(\w+)_path\s*=\s*(\S+)$/) ) {
                    100:                $tmp = ucfirst lc $1;
                    101:                $tmp = "$tmp" . "Path";
                    102:                push(@MainPath,$2);
                    103:                ${$tmp} = "$2";
                    104:              # collect printer_option information
                    105:              } elsif ( ($input_line =~ /^\s*printer_option\s*=\s*["]([\.\d\+\-\w\s\/\|\$]+)["]$/) ||
                    106:                        ($input_line =~ /^\s*printer_option\s*=\s*(\S+)$/ ) ) {
                    107:                push(@Printers,$1);
                    108:                ##   
                    109:              # collect _command information
                    110:              } elsif ( ($input_line =~ /^\s*(\w+)_command\s*=\s*["]([\.\d\+\-\w\s\/\|\$]+)["]$/) ||
                    111:                        ($input_line =~ /^\s*(\w+)_command\s*=\s*(\S+)$/ ) ) {
                    112:                $tmp = ucfirst lc $1;
                    113:                $tmp = "$tmp" . "CMD";
                    114:                ${$tmp} = "$2";
                    115:                ## print "CMD \$$tmp: [$2]\n";
                    116:                ## print "Press RETURN to continue"; $tmp = <>;
                    117:              # collect _file information
                    118:              } elsif ( ($input_line =~ /^\s*(\w+)_file\s*=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                    119:                        ($input_line =~ /^\s*(\w+)_file\s*=\s*(\S+)$/ ) ) {
                    120:                $tmp = ucfirst lc $1;
                    121:                $tmp = "$tmp" . "File";
                    122:                ${$tmp} = "$2"; 
                    123:              # var_ definition
                    124:              } elsif ( ($input_line =~ /^\s*var_(\w+)\s*:=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                    125:                        ($input_line =~ /^\s*var_(\w+)\s*:=\s*(\S+)$/ ) ) {
                    126:                # we defined a variable name with that value 
                    127:                $tmp = ucfirst lc $1;
                    128:                $Var_name{$tmp} = "$2";
                    129:                # two levels of indirection
                    130:                # the variable should be ${$2}
                    131:          
                    132:              # prefix_ definition
                    133:              } elsif ( ($input_line =~ /^\s*prefix_(\w+)\s*:=\s*["]([\.\d\+\-\w\s\/]+)["]$/) ||
                    134:                        ($input_line =~ /^\s*prefix_(\w+)\s*:=\s*(\S+)$/ ) ) {
                    135:                $tmp = ucfirst lc $1;
                    136:                $Prefix_name{$tmp} = "$2";
                    137:          
                    138:              # assigning an numerical value to a variable
                    139:              } elsif ( ($input_line =~ /^\s*(\w+)\s*=\s*([\.\d]+)/) ) {
                    140:                ${$1} = $2;
                    141:                # print "Assign \$$1: with $2\n";
                    142:                # print "Press RETURN to continue"; $tmp = <>;
                    143:              # assigning a variable to another variable
                    144:              } elsif ( ($input_line =~ /^\s*(\w+)\s*=\s*([\w]+)/) ) {
                    145:                $P_code{$1} = "\$$2";
                    146:                ## print "PERL $1: { $P_code{$1} }\n";
                    147:                ## print "Press RETURN to continue"; $tmp = <>;
                    148:              # perl code
                    149:              } elsif ( ($input_line =~ /^\s*(\w+)\s*::/) ) {
                    150:                $p_var_name = $1;
                    151:              } elsif ( ($input_line =~ /^\s*BEGIN_perl/) ) {
                    152:                $P_code{$p_var_name} = &E_CollectPerlCode;
                    153:                ## print "PERL $p_var_name: { $P_code{$p_var_name} }\n";
                    154:                ## print "Press RETURN to continue"; $tmp = <>;
                    155:              } elsif ($input_line =~ /[Bb][Aa][Ss][Ee][\s][Uu][Nn][Ii][Tt]/) {
                    156:                $done = 1;
                    157:              }
                    158:          
                    159:            }
                    160:            close(IN) || die "Cannot close file $tempfilename!";
                    161:        }
                    162:        # define some global variables if they are not defined properly in capa.config file
                    163:        $homework_scores_limit_set = 99 if $homework_scores_limit_set eq "";
                    164:        $exam_scores_limit_set     = 99 if $exam_scores_limit_set     eq "";
                    165:        $quiz_scores_limit_set     = 99 if $quiz_scores_limit_set     eq "";
                    166:        $supp_scores_limit_set     = 99 if $supp_scores_limit_set     eq "";
                    167:        $others_scores_limit_set   = 99 if $others_scores_limit_set   eq "";
                    168:        $display_score_row_limit   = 40 if $display_score_row_limit   eq "";
                    169:        ## print "Press RETURN to continue"; $tmp = <>;
                    170:      }
                    171:  }
                    172: #
                    173: #  Collect perl codes from <IN> until it encountered a 
                    174: #  END_perl statement
                    175: #  Skips over comments (begin with a # mark)
                    176: #  It then places all the codes withing a pair of '{' and '}'
                    177: #
                    178: sub  E_CollectPerlCode {
                    179:     local($input_line);
                    180:     local($p_code,$done);
                    181:     
                    182:     $p_code = "{ \n";   # begining of the code
                    183:     $done=0;
                    184:     while( ($input_line = <IN>) && (! $done) ) {
                    185:       if( $input_line =~ /^END_perl/ ) {
                    186:         $done = 1;
                    187:       } else {
                    188:         if( $input_line !~ /^\#/ ) {  # skip over comments
                    189:           $p_code = "$p_code" . "$input_line";
                    190:         }
                    191:       }
                    192:     }
                    193:     $p_code = "$p_code" . " }\n";  # ending of the code
                    194:     return ($p_code);
                    195: }
                    196: #
                    197: # Collects e-mail template code until it encountered 
                    198: # a END_template statement in the <IN> file
                    199: # It skips over comments that begin with a # mark
                    200: #
                    201: sub  E_CollectTemplateCode {
                    202:     local($input_line);
                    203:     local($p_code,$done);
                    204:     
                    205:     
                    206:     $done=0;
                    207:     while( ($input_line = <IN>) && (! $done) ) {
                    208:       if( $input_line =~ /^END_template/ ) {
                    209:         $done = 1;
                    210:       } else {
                    211:         if( $input_line !~ /^\#/ ) {  # skip over comments
                    212:           $p_code = "$p_code" . "$input_line";
                    213:         }
                    214:       }
                    215:     }
                    216:     
                    217:     return ($p_code);
                    218:  }
                    219: 
                    220: # 
                    221: # $MailCMD comes from the entry 'mail_command' in capa.config
                    222: # 
                    223: sub  S_Mailto {
                    224:     local($e_address,$e_file)=@_;
                    225:     local($m_subject);
                    226:     local($cmd);
                    227:     local($tmp);
                    228:     
                    229:   $m_subject = "Current Status on $ClassName";
                    230:   
                    231:   $cmd = "$MailCMD -s '$m_subject' $e_address < $e_file";
                    232:   print "Mail File $e_file To $e_address\n";
                    233:   system($cmd);
                    234:   # ??? How do we know this command successfully returns? 
                    235:   
                    236:  }
                    237: 
                    238: # TODO:: Check the validity of $e_addr
                    239: #        
                    240: # INPUT: a string represents the category to mail to
                    241: #        it could be "3" or "0" or "1,3,4"
                    242: #        "0"      means 1,2,3, and 4
                    243: #        "1,3,4"  means 1,3, and 4
                    244: #        anything greater than 4 is not valid in the input
                    245: #        therefore category 5 represent those that are 
                    246: #        falling through the gaps of *_high and *_low
                    247: #
                    248: sub  S_MailtoCategory {
                    249:     local($cat)=@_;
                    250:     local(@all_files);
                    251:     local(@a_cat);
                    252:     local($i,$j,$a_char);
                    253:     local($s_id,$s_name,$s_sec,$e_addr);
                    254:     local($orig_filename,$new_filename);
                    255:     local($tmp);
                    256:     
                    257:        opendir(EDIR, "$ClassPath/Mail") || die "cannot opendir $ClassPath/Mail!";
                    258:        @all_files = grep !/^\.\.?$/, readdir EDIR;
                    259:        closedir EDIR;
                    260:        
                    261:        if( ( $cat =~ /,/ ) || ( $cat == 0 )  ) {
                    262:          if( $cat =~ /,/ ) {
                    263:            @a_cat = split(/,/,$cat);
                    264:          } else {
                    265:            @a_cat = (1,2,3,4);
                    266:          }
                    267:          for( $i=0;$i<=$#all_files;$i++) {
                    268:            for( $j=0;$j<=$#a_cat;$j++) {
                    269:              $a_char = $a_cat[$j];
                    270:              if( $all_files[$i] =~ /([\w\d]+)\.[\w\d]+\.$a_char$/ ) {
                    271:                $s_id = $1;
                    272:                ($s_name,$s_sec,$e_addr) = S_Lookup_student_name("$s_id");
                    273:                if( $e_addr ne "" ) {
                    274:                  $orig_filename = "$ClassPath/Mail/$all_files[$i]";
                    275:                  S_Mailto("$e_addr","$orig_filename");
                    276:                  print "moving $all_files[$i] to $all_files[$i].done\n";
                    277:                  # move the completed file to *.done 
                    278:                  system("mv $orig_filename $orig_filename.done");
                    279:                }
                    280:              }
                    281:            }
                    282:          }
                    283:        } else {
                    284:          for( $i=0;$i<=$#all_files;$i++) {
                    285:            if( $all_files[$i] =~ /([\w\d]+)\.[\w\d]+\.$cat$/ ) {
                    286:              $s_id = $1;
                    287:              ($s_name,$s_sec,$e_addr) = S_Lookup_student_name("$s_id");
                    288:              print "Addr=$e_addr\n";
                    289:              print "Press RETURN to continue"; $tmp = <>;
                    290:              if( $e_addr ne "" ) {
                    291:                  $orig_filename = "$ClassPath/Mail/$all_files[$i]";
                    292:                  S_Mailto("$e_addr","$orig_filename");
                    293:                  print "moving $all_files[$i] to $all_files[$i].done\n";
                    294:                  system("mv $orig_filename $orig_filename.done");
                    295:              }
                    296:            }
                    297:          }
                    298:        }
                    299:        print "DONE Mail, press RETURN to continue"; $tmp = <>;
                    300: 
                    301:  }
                    302: #
                    303: # It prompts the user to enter an absolute path to a regular class
                    304: #
                    305: sub  S_Enterpath {
                    306:     local($set)=@_;
                    307:     local($notdone,$path,$cfgfullpath,$cfgutilsfullpath);
                    308:     local($cfullpath,$rfullpath,$sfullpath);
                    309:     
                    310:     $notdone = 1;
                    311:     while ($notdone) {
                    312:       print "Please enter the CLASS absolute path:\n";
                    313:       $path = <>; chomp($path);
                    314:       if( $path =~ /\/$/ ) {
                    315:         $cfullpath = "$path" . "classl";
                    316:         $rfullpath = "$path" . "records";
                    317:         $sfullpath = "$path" . "records/set$set.db";
                    318:         $cfgfullpath = "$path" . "capa.config";
                    319:         $cfgutilsfullpath = "$path" . "capautils.config";
                    320:       } else {
                    321:         $cfullpath = "$path" . "/classl";
                    322:         $rfullpath = "$path" . "/records";
                    323:         $sfullpath = "$path" . "/records/set$set.db";
                    324:         $cfgfullpath = "$path" . "/capa.config";
                    325:         $cfgutilsfullpath = "$path" . "/capautils.config";
                    326:       }
                    327:       if( -d $path ) {
                    328:         if( -d $rfullpath ) {
                    329:           if( -f $cfgfullpath ) {
                    330: 	      if( -f $cfgutilsfullpath ) {
                    331: 		  $notdone = 0;
                    332: 	      } else {
                    333: 		  print "File [$cfgutilsfullpath] does not exist!\n";
                    334: 	      }
                    335:           } else {
                    336:               print "File [$cfgfullpath] does not exist!\n";
                    337:           }
                    338:         } else {
                    339:           print "Directory [$rfullpath] does not exist!\n";
                    340:         }
                    341:       } else {
                    342:         print "Directory [$path] does not exist!\n";
                    343:       }
                    344:     
                    345:     }
                    346:     return ($path);
                    347:   }
                    348: # ----------------------------------------------------------
                    349: #      Global menu items to be selected by user
                    350: #
                    351: @Main_menu=(
                    352:   "Change class path", 
                    353:   "Run capastat", 
                    354:   "Log analysis on Y, N, S, U, and u", 
                    355:   "Student course profile", 
                    356:   "CAPA IDs for one student",
                    357:   "All CAPA IDs",
                    358:   "Item analysis",
                    359:   "Item correlation",
                    360:   "Email",
                    361:   "Print assignment(s) for a student",
                    362:   "View score file",
                    363:   "View submissions for a student",
                    364:   "Quit");
                    365: 
                    366: @Prof_menu=(
                    367:   "Student number",
                    368:   "Student name",
                    369:   "Cancel" );
                    370: 
                    371: @Email_menu=(
                    372:   "Create score file for all students",
                    373:   "Create individual e-mail files from the file in 1.",
                    374:   "Preview e-mail file randomly from among the files in 2.",
                    375:   "Send e-mail files in 2. to a group of students",
                    376:   "Cancel" );
                    377: 
                    378: @ScoreSortMsg=(
                    379:   "Sort by the order of: ", 
                    380:   " 1. Grade",
                    381:   " 2. Student number",
                    382:   " 3. Student name", 
                    383:   " 4. Section",
                    384:   " ",
                    385:   "3,2   means 'name' first, 'student number' second",
                    386:   "1,4,3 means sort by 'grade', 'section' and 'name'" );
                    387: 
                    388: 
                    389: @SpecifyCategoryMsg =  ("Which category?",
                    390:                         "  enter number(s) between 0 and 4",
                    391:                         "  1,2,4 : categories 1, 2 and 4",
                    392:                         "  3     : category 3",
                    393:                         "  0     : all categories" );
                    394: #
                    395: # Only accepts input of 0, 1, 2, 3, and 4, nothing else.
                    396: #
                    397: sub  S_EnterCategory {
                    398:     local($cat);
                    399:     local($done)=0;
                    400:     local(@a_cat,$i);
                    401:     
                    402:     while(! $done) {
                    403:       $cat = C_InputSetNum(4,10,45,"",12,,"CATEGORY:", @SpecifyCategoryMsg);
                    404:       if( $cat =~ /,/ ) {
                    405:         @a_cat = split(/,/,$cat);
                    406:         $done = 1;
                    407:         for( $i=0;$i<=$#a_cat;$i++) {
                    408:           if( ($a_cat[$i] < 0 || $a_cat[$i] > 4) && ($a_cat[$i] ne "" ) ) {
                    409:             $done = 0;
                    410:           }
                    411:           if( $a_cat[$i] == 0 ) {
                    412:             $done = 0;
                    413:           }
                    414:         }
                    415:         
                    416:       } else {
                    417:         if(  $cat>= 0 && $cat <= 4 ) {
                    418:           $done = 1;
                    419:         }
                    420:       }
                    421:     }
                    422:     return ($cat);
                    423: }
                    424: 
                    425: # Only allows input of 1, 2, 3, and 4, nothing more
                    426: sub  S_EnterSortKey {
                    427:     local($key);
                    428:     local($done)=0;
                    429:     local(@a_key,$i);
                    430:     
                    431:     while(! $done) {
                    432:       $key = C_InputSetNum(2,5,60,"",12,,"KEY:",@ScoreSortMsg);
                    433:       if( $key =~ /,/ ) {
                    434:         @a_key = split(/,/,$key);
                    435:         $done = 1;
                    436:         for( $i=0;$i<=$#a_key;$i++) {
                    437:           if( ($a_cat[$i] < 0 || $a_cat[$i] > 4) && ($a_key[$i] ne "" ) ) {
                    438:             $done = 0;
                    439:           }
                    440:           if( $a_key[$i] == 0 ) {
                    441:             $done = 0;
                    442:           }
                    443:         }
                    444:         
                    445:       } else {
                    446:         if(  $key> 0 && $key < 5 ) {
                    447:           $done = 1;
                    448:         }
                    449:       }
                    450:     }
                    451:     return ($key);
                    452: }
                    453: 
                    454: 
                    455: 
                    456: 
                    457: @EnterSetMsg =  ("Which set?");
                    458: @EnterSetsMsg = ("Which set(s)?",
                    459:                  " 3,7 : from set 3 to set 7 (both inclusive)",
                    460:                  " 4   : only set 4" );
                    461: 
                    462: sub  S_EnterSets {
                    463:     local($set);
                    464:     local($done)=0;
                    465:     local($s_from,$s_to);
                    466:     
                    467:     while(! $done) {
                    468:       $set = C_InputSetNum(4,10,45,"",6,,"SET:", @EnterSetsMsg);
                    469:       if( $set =~ /,/ ) {
                    470:         ($s_from,$s_to) = split(/,/,$set);
                    471:         if( $s_from <= 0 || $s_from >= 100 ) { $s_from = 1; }
                    472:         if( $s_to <= 0   || $s_to >= 100 )   { $s_to   = 1; }
                    473:         if( $s_from > $s_to) {
                    474:           $tmp = $s_from; $s_from = $s_to; $s_to = $tmp;
                    475:         }
                    476:         $done = 1;
                    477:       } else {
                    478:         if(  $set> 0 && $set < 100 ) {
                    479:           $s_to = $set;
                    480:           $s_from = $s_to;
                    481:           $done = 1;
                    482:         }
                    483:       }
                    484:     }
                    485:     return ($s_from,$s_to);
                    486: }
                    487: 
                    488: sub  S_InputSet {
                    489:     local($set);
                    490:     local($done)=0;
                    491:     
                    492:     while(! $done) {
                    493:       $set = C_InputSetNum(4,10,15,"",2,,"SET:", @EnterSetMsg);
                    494:       if( $set =~ /\d+/ && $set > 0 && $set < 100 ) { # check entered set 
                    495:         $done = 1;
                    496:       }
                    497:     }
                    498:     return ($set);
                    499: }
                    500: 
                    501: 
                    502: @EnterSSNMsg = ("Enter student number?", " (RETURN to exit)" );
                    503: @EnterSNMsg =  ("Enter student name (max 30 chars)?",
                    504:                 "Last, First (Middle)",
                    505:                 " (RETURN to exit)" );
                    506: 
                    507: sub  S_InputStudent {
                    508:     local($classpath)=@_;
                    509:     local($filename);
                    510:     local($select,$tmp_sn,$input_line);
                    511:     local($student_id,$student_name);
                    512:     local($found,$done,$s_name);
                    513:     local($match,@matched_entries,$tmp_line);
                    514:     
                    515:     $select = C_MultipleChoice(4,10,$DialogWidth,"Select student by:","$DisplayPath",@Prof_menu);
                    516:     if($select == 1 ) {  # specify student number
                    517:        while(! $done) {
                    518:          $student_id = C_InputStudentID(4,10,24,"",9,"INPUT:",@EnterSSNMsg);
                    519:          if($student_id eq "" ) {
                    520:            $done = 1; 
                    521:          } else {
                    522:            $student_id = uc($student_id);
                    523:            $filename = $classpath . "/classl";
                    524:            open(IN, "<$filename") || die "Cannot open file $filename!";
                    525:            $match = 0; @matched_entries = ();
                    526:            while(($input_line = <IN>)) {
                    527:              chomp($input_line);
                    528:              $tmp_sn = substr($input_line,14,9); $tmp_sn = uc($tmp_sn);
                    529:              if($tmp_sn =~ /^$student_id/ ) {
                    530:                $match++;
                    531:                # student name begins at column 24 and has 30 chars max
                    532:                $student_name = substr($input_line,24,30); 
                    533:                $tmp_line = "$tmp_sn " . "$student_name";
                    534:                push(@matched_entries,$tmp_line);
                    535:              }
                    536:            }
                    537:            close(IN) || die "Cannot close file $filename!";
                    538:            if($match > 1 && $match <= 12) {
                    539:              $select = C_MultipleChoice(4,10,$DialogWidth,"        Matched Student Records       ",
                    540:                           "$DisplayPath",@matched_entries);
                    541:              $student_id = substr($matched_entries[$select-1],0,9);
                    542:              $student_name = substr($matched_entries[$select-1],10,30);
                    543:              $done = 1;
                    544:            } elsif ($match == 1) {
                    545:              $student_id = substr($matched_entries[0],0,9);
                    546:              $student_name = substr($matched_entries[0],10,30);
                    547:              $done = 1;
                    548:            } elsif ($match > 12) {
                    549:              $tmp_line = "There are $match records found.";
                    550:              C_Warn(4,10,$DialogWidth,"Too many students matched",$tmp_line);
                    551:            } else {
                    552:              $tmp_line = "Please re-enter student number.";
                    553:              C_Warn(4,10,$DialogWidth,"No student found",$tmp_line);
                    554:            }
                    555:          }
                    556:          
                    557:        }
                    558:     } elsif ($select == 2) { # specify student name
                    559:        while(! $done) {
                    560:          $s_name = C_InputStudentID(4,10,40,"Enter student name",30,,"INPUT:", @EnterSNMsg);
                    561:          if($s_name eq "" ) {
                    562:            $done = 1;
                    563:          } else {
                    564:            $s_name = uc($s_name);
                    565:            $filename = $classpath . "/classl";
                    566:            open(IN, "<$filename") || die "Cannot open file $filename!";
                    567:            $match = 0; @matched_entries = ();
                    568:            while(($input_line = <IN>)) {
                    569:              chomp($input_line);
                    570:                $tmp_sn = substr($input_line,24,30); $tmp_sn = uc($tmp_sn);
                    571:              if( $tmp_sn =~ /^$s_name/ ) {
                    572:                $match++;
                    573:                $student_id = substr($input_line,14,9); # student number
                    574:                $tmp_line = "$student_id " . "$tmp_sn";
                    575:                push(@matched_entries,$tmp_line);
                    576:              }
                    577:            }
                    578:            close(IN) || die "Cannot close file $filename!";
                    579:            if($match > 1 && $match <= 12) {
                    580:              $select = C_MultipleChoice(4,10,$DialogWidth,"        Matched Student Records       ",
                    581:                             "$DisplayPath",@matched_entries);
                    582:              $student_id = substr($matched_entries[$select-1],0,9);
                    583:              $student_name = substr($matched_entries[$select-1],10,30);
                    584:              $done = 1;
                    585:            } elsif ($match == 1) {
                    586:              $student_id = substr($matched_entries[0],0,9);
                    587:              $student_name = substr($matched_entries[0],10,30);
                    588:              $done = 1;
                    589:            } elsif ($match > 12) {
                    590:              $tmp_line = "There are $match records found.";
                    591:              C_Warn(4,10,$DialogWidth,"Too many students matched",$tmp_line);
                    592:            } else {
                    593:              $tmp_line = "Please re-enter student name.";
                    594:              C_Warn(4,10,$DialogWidth,"No student found",$tmp_line);
                    595:            }
                    596:          }
                    597:        }
                    598:     } else {  # cancel 
                    599:       $student_id = "";
                    600:       $student_name = "";
                    601:     }
                    602:     return ($student_id,$student_name);
                    603: }
                    604: 
                    605: 
                    606: 
                    607: #
                    608: # INPUT: the class name with full path and the student number
                    609: # OUTPUT: total scores , total possible wights
                    610: 
                    611: sub S_CollectSetScores {
                    612:     local($classpath,$student_id,$on_screen,$s_limit)=@_;
                    613:     local($filename,$found,$classname);
                    614:     local($done)=0;
                    615:     local($line_cnt,$input_line);
                    616:     local(@weights);       # the wights array for individual set
                    617:     local($valid_weights); # the valid weights for a set
                    618:     local($total_weights); # the overall valid weights for all sets
                    619:     local(@set_weights);   # the array storing all set valid weights
                    620:     local($score);         # the valid score for a set
                    621:     local($total_scores);  # the overall valid scores for all sets
                    622:     local(@set_scores);    # the array storing all set scores
                    623:     local($set_idx);
                    624:     local($ii,$abscent_cnt,$present_cnt);
                    625:     local($s_num,$ans_str,$prefix,$rest);
                    626:     local(@ans_char,$ratio,$tmp,$summary_str);
                    627:     
                    628:     $student_id = uc($student_id);
                    629:     $total_scores = 0; $total_weights = 0; # initialize the overall results
                    630:     $set_idx = 0;
                    631:     
                    632:     while( ! $done ) {
                    633:       $set_idx++;    # start out as set1.db, then add one to it
                    634:       if($set_idx <= $s_limit ) {  # the limit set is inclusive
                    635:         $filename = $classpath . "/records/set" . "$set_idx" . ".db";
                    636:         if( -f $filename) { # file exists!
                    637:           open(IN, "<$filename") || die "Cannot open file $filename!";
                    638:           $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
                    639:           while ( ($input_line = <IN>) && !$found) { 
                    640:             $line_cnt++;       # add one to line count
                    641:             if( $line_cnt == 2 ) { # second line is the weight for each problem
                    642:               chomp();             # delete the trailing '\n' char
                    643:               (@weights) = split(/ */,$input_line);  # split the line into each individual chars
                    644:               $valid_weights = 0;
                    645:               for($ii=0;$ii<=$#weights;$ii++) {
                    646:                 $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
                    647:               }
                    648:             ## &C_ClearScreen;
                    649:             ## print "Second line, $input_line, total weight=$valid_weights\n";
                    650:             ## printf "Press RETURN to continue"; $tmp = <>;
                    651:             }
                    652:             if( $line_cnt > 3) {    # start from line 4 is the student data
                    653:               chomp($input_line);              # delete the trailing '\n' char
                    654:               ($prefix,$rest) = split(/,/,$input_line,2); # split the whole line into two parts
                    655:               ($s_num,$ans_str) = split(/ /,$prefix,2);   # split into two parts
                    656:               $s_num = uc($s_num); 
                    657:               if( $student_id eq $s_num ) { # found the student we want
                    658:               ## &C_ClearScreen;
                    659:               ## print "FOUND [$input_line] $s_num == $student_id: weight= $valid_weights,ANS=$ans_str\n";
                    660:               ## printf "Press RETURN to continue"; $tmp = <>;
                    661:                 $found = 1;         # so we can exit the search through while loop
                    662:                 (@ans_char) = split(/ */,$ans_str);  # split the answer string into individual ans chars
                    663:                 for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1, to last question -1
                    664:                   $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
                    665:                 }
                    666:                 if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
                    667:                   for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii
                    668:                   
                    669:                     if($ans_char[$ii] eq 'Y') {
                    670:                       $score += $weights[$ii];
                    671:                     }
                    672:                     if($ans_char[$ii] eq 'y') {
                    673:                       $score += $weights[$ii];
                    674:                     }
                    675:                     if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
                    676:                       $score += $ans_char[$ii];
                    677:                     }
                    678:                     if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                    679:                       $valid_weights -= $weights[$ii];
                    680:                     }
                    681:                   }
                    682:                   $total_scores += $score;  # add the calculated score to the overall sum
                    683:                 } else { # end of a valid line
                    684:                   $score = '-';
                    685:                 }
                    686:               } 
                    687:             }   # end $line_cnt > 3
                    688:           } # end while <IN>
                    689:           close(IN) || die "Cannot close file $filename!";
                    690:           $total_weights   += $valid_weights; # add the valid weights for a set to the overall sum
                    691:           $set_weights[$set_idx-1] = $valid_weights;
                    692:         
                    693:           if( $found ) {
                    694:           ## push(@set_scores, $score);          # push set score into array
                    695:           ## push(@set_weights, $valid_weights); # push valid weight for a set into the weight array
                    696:             $set_scores[$set_idx-1]  = $score;
                    697:           } else { # student not found in the setX.db file
                    698:             $set_scores[$set_idx-1]  = '-';
                    699:           }
                    700:         } else {  # $set_idx > $s_limit
                    701:           $done = 1;  # exit the $done while loop
                    702:         }
                    703:       } else {
                    704:         $done = 1;  # exit the $done while loop
                    705:       }
                    706:     } # end while ! $done
                    707:     # print out the report
                    708:     # &C_ClearScreen;
                    709:     $abscent_cnt=0;
                    710:     $present_cnt=0;
                    711:     $summary_str = "";
                    712:     print " " x 10 if $on_screen;
                    713:     for($ii=0;$ii<=$#set_scores;$ii++) {
                    714:       if( $set_scores[$ii] eq '-' || $set_scores[$ii] eq "" ) {
                    715:         print "  - " if $on_screen;
                    716:         $summary_str = "$summary_str" . "x/$set_weights[$ii] ";
                    717:         $abscent_cnt++;
                    718:       } else {
                    719:         printf " %3d", $set_scores[$ii] if $on_screen;
                    720:         $summary_str = "$summary_str" . "$set_scores[$ii]/$set_weights[$ii] ";
                    721:         $present_cnt++;
                    722:       }
                    723:     }
                    724:     if( $on_screen ) {
                    725:       $classname = substr($classpath,-8,8);
                    726:       print "\n $classname:";
                    727:       for($ii=0;$ii<=$#set_scores;$ii++) {
                    728:         print " ---";
                    729:       }
                    730:       print "\n          ";
                    731:       for($ii=0;$ii<=$#set_weights;$ii++) {
                    732:         printf " %3d", $set_weights[$ii];
                    733:       }
                    734:       print "\n";
                    735:       if($total_weights != 0 ) {
                    736:         $ratio = 100.0 * ($total_scores / $total_weights);
                    737:       } else {
                    738:         $ratio = '-';
                    739:       }
                    740:       printf "  %5d\n", $total_scores if $on_screen;
                    741:       printf  " ------- = %3.2f%%, scores abscent in %d/%d\n", $ratio, $abscent_cnt, $#set_scores+1;
                    742:       printf "  %5d\n", $total_weights;
                    743:     ## print "Press RETURN to continue"; $tmp = <>;
                    744:     }
                    745:     return ($total_scores,$total_weights,$abscent_cnt,$#set_scores+1,$summary_str);
                    746:  }
                    747: 
                    748: # 
                    749: #  similar to S_CollectSetScores
                    750: # 
                    751: sub S_CollectExamScores {
                    752:     local($classpath,$student_id)=@_;
                    753:     local($filename,$found,$classname);
                    754:     local($done)=0;
                    755:     local($line_cnt,$input_line);
                    756:     local(@weights);       # the wights array for individual set
                    757:     local($valid_weights); # the valid weights for a set
                    758:     local($total_weights); # the overall valid weights for all sets
                    759:     local(@set_weights);   # the array storing all set valid weights
                    760:     local($score);         # the valid score for a set
                    761:     local($total_scores);  # the overall valid scores for all sets
                    762:     local(@set_scores);    # the array storing all set scores
                    763:     local($set_idx);
                    764:     local($ii,$var_name);
                    765:     local($s_num,$ans_str,$prefix,$rest);
                    766:     local($midterm1,$midterm2,$midterm3,$f_score);
                    767:     local($m_max1,$m_max2,$m_max3,$f_max);
                    768:     local(@ans_char,$ratio,$tmp);
                    769:     
                    770:     $student_id = uc($student_id);
                    771:     $total_scores = 0; $total_weights = 0; # initialize the overall results
                    772:     $set_idx = 0;
                    773:     
                    774:     while( ! $done ) {
                    775:       $set_idx++;    # start out as set1.db, then add one to it
                    776:       if( $set_idx <= $exam_scores_limit_set ) { # $exam_scores_limit_set comes from capa.config
                    777:         $filename = $classpath . "/records/set" . "$set_idx" . ".db";
                    778:         if( -f $filename) { # file exists!
                    779:           open(IN, "<$filename") || die "Cannot open file $filename!";
                    780:           $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
                    781:           while ( ($input_line = <IN>) && !$found) { 
                    782:             $line_cnt++;       # add one to line count
                    783:             if( $line_cnt == 2 ) { # second line is the weight for each problem
                    784:               chomp();             # delete the trailing '\n' char
                    785:               (@weights) = split(/ */,$input_line);  # split the line into each individual chars
                    786:               $valid_weights = 0;
                    787:               for($ii=0;$ii<=$#weights;$ii++) {
                    788:                 $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
                    789:               }
                    790:             }
                    791:             if( $line_cnt > 3) {    # start from line 4 is the student data
                    792:               chomp($input_line);              # delete the trailing '\n' char
                    793:               ($prefix,$rest) = split(/,/,$input_line,2); # split the whole line into two parts
                    794:               ($s_num,$ans_str) = split(/ /,$prefix,2);   # split into two parts
                    795:               $s_num = uc($s_num); 
                    796:               if( $student_id eq $s_num ) { # found the student we want
                    797:                 $found = 1;         # so we can exit the search through while loop
                    798:                 (@ans_char) = split(/ */,$ans_str);  # split the answer string into individual ans chars
                    799:                 for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1, to last question -1
                    800:                   $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
                    801:                 }
                    802:                 if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
                    803:                   for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii
                    804:                   
                    805:                     if($ans_char[$ii] eq 'Y') {
                    806:                       $score += $weights[$ii];
                    807:                     }
                    808:                     if($ans_char[$ii] eq 'y') {
                    809:                       $score += $weights[$ii];
                    810:                       }
                    811:                     if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
                    812:                       $score += $ans_char[$ii];
                    813:                     }
                    814:                     if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                    815:                       $valid_weights -= $weights[$ii];
                    816:                     }
                    817:                   }
                    818:                   $total_scores += $score;  # add the calculated score to the overall sum
                    819:                 } else { # end of a valid line
                    820:                   $score = '-';
                    821:                 }
                    822:               } # end student number comparison
                    823:             }   # end $line_cnt > 3
                    824:           } # end while <IN>
                    825:           close(IN) || die "Cannot close file $filename!";
                    826:           $total_weights   += $valid_weights; # add the valid weights for a set to the overall sum
                    827:           $set_weights[$set_idx-1] = $valid_weights;
                    828:         # push(@set_scores, $score);          # push set score into array
                    829:         # push(@set_weights, $valid_weights); # push valid weight for a set into the weight array
                    830:           if( $found ) {
                    831:             $set_scores[$set_idx-1]  = $score;
                    832:           } else { # could not locate the student in the setX.db file
                    833:             $set_scores[$set_idx-1]  = '-';
                    834:           }
                    835:         } else {  # $set_idx > $exam_scores_limit_set
                    836:           $done = 1;
                    837:         }
                    838:       } else {
                    839:         $done = 1;  # exit the $done while loop
                    840:       }
                    841:     } # end while ! $done
                    842: 
                    843:     # put scores in the global variables: exam_raw1, exam_raw2 ...
                    844:     #     and maximum weights in variables: exam_raw_max1, exam_raw_max2,..
                    845:     # prefix is stored in :
                    846:     #    $Prefix_name{"Exam_raw_scores"}
                    847:     #    $Prefix_name{"Exam_raw_max"}
                    848:     # 
                    849:     $Prefix_name{'Exam_raw_scores'} = "exam_raw"     if ! defined $Prefix_name{'Exam_raw_scores'};
                    850:     $Prefix_name{'Exam_raw_max'}    = "exam_raw_max" if ! defined $Prefix_name{'Exam_raw_max'};
                    851:     for($ii=0;$ii<=$#set_scores;$ii++) {
                    852:       $set_idx = $ii+1;
                    853:       $var_name = "$Prefix_name{'Exam_raw_scores'}" . "$set_idx";
                    854:       ${$var_name} = $set_scores[$ii];
                    855:       $var_name = "$Prefix_name{'Exam_raw_max'}" . "$set_idx";
                    856:       ${$var_name} = $set_weights[$ii];
                    857:     }
                    858:     #
                    859:     # initialize these local variables 
                    860:     #
                    861:     $midterm1 = '-'; $m_max1 = '-';
                    862:     $midterm2 = '-'; $m_max2 = '-';
                    863:     $midterm3 = '-'; $m_max3 = '-';
                    864:     $f_score  = '-'; $f_max =  '-';
                    865:     # After we placed raw scores into the global variables exam_raw1, exam_raw2 ...
                    866:     #  we can then, evaluate the definitions of midterm1, midterm2 and midterm3 from capa.config
                    867:     if($#set_scores >= 1) {  # at least 2 sets
                    868:         $midterm1 = eval $P_code{'midterm1'};
                    869:         $var_name =  "$Prefix_name{'Exam_raw_max'}" . "1"; # for max possible scores, just pick a set
                    870:         $m_max1 = ${$var_name};
                    871:         if($#set_scores >= 3) { # at least 4 sets
                    872:           $midterm2 = eval $P_code{'midterm2'};
                    873:           $var_name =  "$Prefix_name{'Exam_raw_max'}" . "3"; # for max possible scores, just pick a set
                    874:           $m_max2 = ${$var_name};
                    875:           if($#set_scores >= 5) { # at least 6 sets
                    876:             $midterm3 = eval $P_code{'midterm3'};
                    877:             $var_name =  "$Prefix_name{'Exam_raw_max'}" . "5"; # for max possible scores, just pick a set
                    878:             $m_max3 = ${$var_name};
                    879:             if($#set_scores == 6 ) { # the 7th set
                    880:                                      # in capa.config a variable $final_exam is defined as 
                    881:                                      #    the same with $exam_raw7
                    882:               ## $var_name =  "$Prefix_name{'Exam_raw_scores'}" . "7";
                    883:               ## $f_score = ${$var_name};
                    884:               $f_score = eval $P_code{'final_exam'};
                    885:               $var_name =  "$Prefix_name{'Exam_raw_max'}" . "7";
                    886:               $f_max = ${$var_name};
                    887:             } else { # only 6 sets
                    888:               
                    889:             }
                    890:           } else { # 4 or 5 sets
                    891:             
                    892:           }
                    893:         } else { # 2 or 3 sets
                    894:           
                    895:         }
                    896:     } else { # 0 or 1 sets
                    897:       
                    898:     }  
                    899:     return ($midterm1,$m_max1,$midterm2,$m_max2,$midterm3,$m_max3,$f_score,$f_max,$#set_scores+1);
                    900:    
                    901:  }
                    902: 
                    903: #
                    904: # Menu item: capastat
                    905: #     ($Q_cnt,$L_cnt) =  &S_ScanSetDB($Sfullpath);
                    906: #     Percentage_Scores($Set);
                    907: #     S_Average($Q_cnt,$L_cnt);
                    908: #
                    909: # INPUT: the setX.db file name with full path 
                    910: #    
                    911: sub S_ScanSetDB  {
                    912:     local($filename)=@_;
                    913:     local($line_cnt)=0;
                    914:     local($valid_cnt)=0;
                    915:     local($valid);
                    916:     local($ii);
                    917:     local($s_num,$ans_str,$prefix,$rest);
                    918:     local(@ans_char,@tries);
                    919:     local($score);
                    920:     
                    921:     for($ii=0;$ii<=99;$ii++) {
                    922:         $Total_try[$ii]=0;
                    923: 	$Yes_cnt[$ii]=0;
                    924: 	$yes_cnt[$ii]=0;
                    925:         for($jj=0;$jj<=99;$jj++) {
                    926: 	    $Student_cnt[$ii][$jj]=0;
                    927:             $Student_try[$ii][$jj]=0;
                    928: 	}
                    929:     }
                    930:     $Total_weight=0;
                    931:     $Total_scores=0;
                    932: 
                    933:     open(IN, "<$filename") || die "Cannot open file $filename!";
                    934:     while (<IN>) {
                    935:       $line_cnt++;
                    936:       if( $line_cnt == 2 ) {
                    937:         chomp();
                    938:         (@Weight) = split(/ */);
                    939:       }
                    940:       if( $line_cnt > 3) {
                    941:         chomp();
                    942:         ($prefix,$rest) = split(/,/,$_,2);
                    943:         ($s_num,$ans_str) = split(/ /,$prefix,2);
                    944:         (@ans_char) = split(/ */,$ans_str);
                    945:         (@tries)    = split(/,/,$rest);
                    946:         for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {
                    947:             $valid = 'Y' if $ans_char[$ii] ne '-';
                    948:         }
                    949:         if( $valid eq 'Y' ) {
                    950:           for($score=0,$ii=0;$ii<=$#tries;$ii++) {
                    951:             $Student_cnt[$ii][$tries[$ii]]++;
                    952:             $Student_try[$valid_cnt][$ii] = $tries[$ii];
                    953:             $Total_try[$ii] += $tries[$ii];
                    954:             $Total_weight   += $Weight[$ii];
                    955:             if($ans_char[$ii] eq 'Y') {
                    956:               $Yes_cnt[$ii]++;
                    957:               $score += $Weight[$ii];
                    958:             }
                    959:             if($ans_char[$ii] eq 'y') {
                    960:               $yes_cnt[$ii]++;
                    961:               $score += $Weight[$ii];
                    962:             }
                    963:             if( $ans_char[$ii] ge '0' && $ans_char[$ii] le '9') {
                    964:               $score += $ans_char[$ii];
                    965:             }
                    966:           }
                    967:           $Total_scores += $score;
                    968:           $Entry{"$valid_cnt"} = "$s_num\n" . "$ans_str," . " $rest\n";
                    969:           $Score{"$valid_cnt"} = $score;
                    970:           $valid_cnt++;
                    971:         }
                    972:       }
                    973:     }
                    974:     close(IN) || die "Cannot close $filename file!";
                    975:     return ($#tries+1,$valid_cnt);
                    976:  }
                    977:  
                    978:  
                    979: $MAX_TRIES = 99;
                    980: 
                    981: sub  S_Average {
                    982:     local($q_cnt,$l_cnt)=@_;
                    983:     local($ii,$jj);
                    984:     local(@s_cnt,@avg);
                    985:     local(@sd, $sum);
                    986:     local($sq);
                    987:     local(@sd3,$tmp1,$tmp2,$done);
                    988:     
                    989:     for($ii=0;$ii<$q_cnt;$ii++) {
                    990:       $s_cnt[$ii] = 0;
                    991:       $avg[$ii]   = 0.0;
                    992:       $Max_try[$ii] = 0;
                    993:       for($jj=1;$jj<$MAX_TRIES;$jj++) {  # ignore the 0 try entry
                    994:         if( $Student_cnt[$ii][$jj] > 0 ) {
                    995:           $avg[$ii]   +=  $jj*$Student_cnt[$ii][$jj];
                    996:           $s_cnt[$ii] +=  $Student_cnt[$ii][$jj];
                    997:         }
                    998:       }
                    999:       if( $s_cnt[$ii] > 0 ) {      # avoid division by zero
                   1000:         $avg[$ii] = $avg[$ii] / $s_cnt[$ii];
                   1001:       }
                   1002:     }
                   1003:     
                   1004:     for($ii=0;$ii<$q_cnt;$ii++) {
                   1005:       $sd[$ii] = 0.0;
                   1006:       $sum = 0.0;
                   1007:       for($jj=0;$jj<$l_cnt;$jj++) {
                   1008:         $Max_try[$ii] = ($Student_try[$jj][$ii] > $Max_try[$ii]? $Student_try[$jj][$ii] : $Max_try[$ii]);
                   1009:         if( $Student_try[$jj][$ii] > 0 ) {
                   1010:           $sq  = ($Student_try[$jj][$ii] - $avg[$ii])*($Student_try[$jj][$ii] - $avg[$ii]);
                   1011:           $sum += $sq;
                   1012:         }
                   1013:         if( $s_cnt[$ii] > 1 ) {
                   1014:           $sd[$ii] = $sum / ($s_cnt[$ii] - 1.0 );
                   1015:         }
                   1016:         if( $sd[$ii] > 0 ) {
                   1017:           $sd[$ii] = sqrt( $sd[$ii] );
                   1018:         }
                   1019:       }
                   1020:     }
                   1021:     
                   1022:     for($ii=0;$ii<$q_cnt;$ii++) {
                   1023:       $sd3[$ii] = 0.0;
                   1024:       $sum = 0.0;
                   1025:       for($jj=0;$jj<$l_cnt;$jj++) {
                   1026:         if( $Student_try[$jj][$ii] > 0 ) {
                   1027:           $tmp1 = $Student_try[$jj][$ii] - $avg[$ii];
                   1028:           $tmp2 = $tmp1*$tmp1*$tmp1;
                   1029:           $sum  = $sum + $tmp2;
                   1030:         }
                   1031:         if( $s_cnt[$ii] > 0 && $sd[$ii] != 0.0 ) {
                   1032:           $sd3[$ii] = $sum/$s_cnt[$ii] ;
                   1033:           $sd3[$ii] = $sd3[$ii] / ($sd[$ii]*$sd[$ii]*$sd[$ii]);
                   1034:         }
                   1035:       }
                   1036:     }
                   1037:     
                   1038:     print "This is the statistics for each problem:\n";
                   1039:     print "Prob\#   MxTries   avg.     s.d.    s.k.   \#Stdnts ";
                   1040:     print "  \#Yes   \#yes   Tries  DoDiff\n";
                   1041:     for($ii=0;$ii<$q_cnt;$ii++) {
                   1042:       if( $Total_try[$ii] > 0 ) {
                   1043:         ## $dod = 1-($Yes_cnt[$ii] + $yes_cnt[$ii]) / $Total_try[$ii];
                   1044:         $dod = $Total_try[$ii]/(0.1 + $Yes_cnt[$ii] + $yes_cnt[$ii]);
                   1045:       }
                   1046:       printf "P %2d:",$ii+1;
                   1047:       printf "%7d  %8.2f  %7.2f  %6.2f   %5d   %5d  %5d    %5d   %5.1f\n",
                   1048:               $Max_try[$ii],$avg[$ii],$sd[$ii],$sd3[$ii],$s_cnt[$ii],$Yes_cnt[$ii],$yes_cnt[$ii],
                   1049:               $Total_try[$ii],$dod;
                   1050:      
                   1051:     }
                   1052:     printf "Press RETURN to continue"; $done = <>;
                   1053:   }
                   1054:   
                   1055: sub  Percentage_Scores {
                   1056:     local($set,$valid_cnt)=@_;
                   1057:     local($ratio);
                   1058:     local($done);
                   1059:     
                   1060:     if($Total_weight > 0 ) {
                   1061:       $ratio = $Total_scores / $Total_weight;
                   1062:       $ratio = $ratio * 100.0;
                   1063:     }
                   1064:     
                   1065:     printf "\nThe percentage score (total scores / total valid weights) for set%d.db is:\n %7.2f%%\n",$set,$ratio;
                   1066:     printf "The number of valid records for set%d.db is: %d\n", $set, $valid_cnt;
                   1067:     printf "Press RETURN to continue"; $done=<>;
                   1068:   }
                   1069: 
                   1070: 
                   1071: sub  Large_Tries {
                   1072:     local($t,$n,$q_cnt,$l_cnt)=@_;
                   1073:     local($ii);
                   1074:     
                   1075:     print "\nHere is a list of students who attempts $t tries more than $n times: \n\n";
                   1076: 
                   1077:     for ($i=0;$i<$l_cnt;$i++){
                   1078:        $count=0;
                   1079:        $credit=0;
                   1080:        for ($j=0;$j<$q_cnt;$j++){
                   1081:            if ($Student_try[$i][$j]>= $t){
                   1082:               $count++;
                   1083:            }
                   1084:        }
                   1085:        if ($count >= $n){
                   1086:           print "($Score{$i})  $Entry{$i} \n";
                   1087:        }
                   1088:     }
                   1089:   
                   1090:   }
                   1091: 
                   1092: 
                   1093: sub S_ScanLogDB  {
                   1094:     local($filename)=@_;
                   1095:     local($line_cnt)=0;
                   1096:     local($s_num,$dow,$mon,$sp,$day,$time,$yr,$ans_str);
                   1097:     local(@ans_char);
                   1098:     local($ii,$first,$done);
                   1099:     local($Yes_cnt[99],$No_cnt[99],$U_cnt[99],$S_cnt[99],$u_cnt[99]);
                   1100:     local($Y_total,$N_total,$U_total,$u_total,$S_total);
                   1101:     
                   1102:     $Y_total=0; $N_total=0; $U_total=0; $u_total=0; $S_total=0;
                   1103:     open(IN, "<$filename") || die "Cannot open file $filename!";
                   1104:     for($ii=0;$ii<=99;$ii++) {
                   1105:       $Yes_cnt[$ii] = 0; $No_cnt[$ii] = 0; 
                   1106:       $U_cnt[$ii]=0; $u_cnt[$ii]=0; $S_cnt[$ii]=0;
                   1107:     }
                   1108:     while (<IN>) {
                   1109:       $line_cnt++;
                   1110:       chomp();
                   1111:       $ans_str = substr($_,35);
                   1112:       ## ($first,$ans_str) = split(/1996 /);  # depends on this special pattern
                   1113:        # print "$ans_str\n";
                   1114:       (@ans_char) = split(/ */,$ans_str);
                   1115:        
                   1116:        for($ii=0;$ii<=$#ans_char;$ii++) {
                   1117:        
                   1118:          if($ans_char[$ii] eq 'Y') {
                   1119:            $Yes_cnt[$ii]++;
                   1120:            $Y_total++;
                   1121:          }
                   1122:          if($ans_char[$ii] eq 'N') {
                   1123:            $No_cnt[$ii]++;
                   1124:            $N_total++;
                   1125:          }
                   1126:          if($ans_char[$ii] eq 'U') {
                   1127:            $U_cnt[$ii]++;
                   1128:            $U_total++;
                   1129:          }
                   1130:          if($ans_char[$ii] eq 'u') {
                   1131:            $u_cnt[$ii]++;
                   1132:            $u_total++;
                   1133:          }
                   1134:          if($ans_char[$ii] eq 'S') {
                   1135:            $S_cnt[$ii]++;
                   1136:            $S_total++;
                   1137:          }
                   1138:        }
                   1139:      }
                   1140:      close(IN) || die "Cannot close file $filename!";
                   1141:      print "Prob #:     #Y     #N     #S     #U     #u\n";
                   1142:      for($ii=0;$ii<=$#ans_char;$ii++) {
                   1143:        printf "    %2d: %6d %6d %6d %6d %6d\n",
                   1144:               $ii+1, $Yes_cnt[$ii], $No_cnt[$ii], $S_cnt[$ii], $U_cnt[$ii], $u_cnt[$ii];
                   1145:      }
                   1146:      print  "=" x 45 . "\n";
                   1147:      printf  " Total: %6d %6d %6d %6d %6d\n", $Y_total, $N_total, $S_total, $U_total, $u_total;
                   1148:      printf "Press RETURN to continue"; $done = <>;
                   1149:      
                   1150:      return ($Y_total,$N_total,$S_total,$U_total,$u_total);
                   1151:   }
                   1152: 
                   1153: sub S_StudentLoginData {
                   1154:     local($filename,$student_id)=@_;
                   1155:     local($Y_total,$N_total,$S_total,$U_total,$u_total);
                   1156:     local($ans_str,@ans_char);
                   1157:     local($ii,$s_id);
                   1158:     
                   1159:     $Y_total=0; $N_total=0; $U_total=0; $u_total=0; $S_total=0;
                   1160:     open(IN, "<$filename") || die "Cannot open file $filename!";
                   1161:     while (<IN>) { 
                   1162:       chomp();
                   1163:       $s_id = substr($_,0,9); # student number begins at column 0 and has 9 chars
                   1164:       $s_id = uc($s_id);
                   1165:       $student_id = uc($student_id);
                   1166:       if( $student_id eq $s_id) {
                   1167:         $ans_str = substr($_,35);    # the answer string begins at column 35 (count from 0)
                   1168:         (@ans_char) = split(/ */,$ans_str);
                   1169:         for($ii=0;$ii<=$#ans_char;$ii++) {
                   1170:           if($ans_char[$ii] eq 'Y') {
                   1171:             $Y_total++;
                   1172:           }
                   1173:           if($ans_char[$ii] eq 'N') {
                   1174:             $N_total++;
                   1175:           }
                   1176:           if($ans_char[$ii] eq 'U') {
                   1177:             $U_total++;
                   1178:           }
                   1179:           if($ans_char[$ii] eq 'u') {
                   1180:             $u_total++;
                   1181:           }
                   1182:           if($ans_char[$ii] eq 'S') {
                   1183:             $S_total++;
                   1184:           }
                   1185:         } # end for each problem
                   1186:       } # end student number matches
                   1187:     } # end while 
                   1188:     close(IN) || die "Cannot close file $filename!";
                   1189:     return ($Y_total,$N_total,$S_total,$U_total,$u_total);
                   1190:  }
                   1191: 
                   1192: # 
                   1193: sub S_LoginAnalysis {
                   1194:     local($classpath,$student_id,$s_limit)=@_;
                   1195:     local($Y_set,$N_set,$S_set,$U_set,$u_set);
                   1196:     local($set_idx,$no_log,$no_weblog,$done,$tmp);
                   1197:     
                   1198:     print "Login analysis:  telnet session             web session\n\n";
                   1199:     print "   set #:   #Y   #N   #S   #U   #u     #Y   #N   #S   #U   #u\n";
                   1200:     $set_idx=0; $done=0;
                   1201:     while (! $done ) {
                   1202:       $set_idx++;
                   1203:       if( $set_idx <= $s_limit) {
                   1204:         printf "      %2d: ", $set_idx;
                   1205:         $filename= $classpath . "/records/log" . "$set_idx" . ".db";
                   1206:         if(-f $filename) {
                   1207:           ($Y_set,$N_set,$S_set,$U_set,$u_set)=S_StudentLoginData($filename,$student_id);
                   1208:           printf "%4d %4d %4d %4d %4d", $Y_set,$N_set,$S_set,$U_set,$u_set;
                   1209:           $no_log = 0;
                   1210:         } else {
                   1211:           print  "=" x 24;
                   1212:           $no_log = 1;
                   1213:         }
                   1214:         print " " x 4;
                   1215:         $filename= $classpath . "/records/weblog" . "$set_idx" . ".db";
                   1216:         if(-f $filename) {
                   1217:           ($Y_set,$N_set,$S_set,$U_set,$u_set)= S_StudentLoginData($filename,$student_id);
                   1218:           printf "%4d %4d %4d %4d %4d", $Y_set,$N_set,$S_set,$U_set,$u_set;
                   1219:           $no_weblog = 0;
                   1220:         } else {
                   1221:           print  "=" x 24;
                   1222:           $no_weblog = 1;
                   1223:         }
                   1224:         print "\n";
                   1225:         if( $no_log && $no_weblog ) { $done = 1; };
                   1226:       } else { # $set_idx > $s_limit
                   1227:         $done = 1;
                   1228:       }
                   1229:     }
                   1230:     
                   1231:     printf "Press RETURN to continue"; $tmp = <>;
                   1232:  }
                   1233: 
                   1234: # It pulls out the data base entry from setX.db files
                   1235: sub S_StudentSetAnalysis {
                   1236:     local($classpath,$student_id,$s_limit)=@_;
                   1237:     local($filename);
                   1238:     local($set_idx,$done);
                   1239:     local($line_cnt,$found,$input_line);
                   1240:     local($s_num,$data,$ans_str,$try_str,$tmp);
                   1241:     
                   1242:     $set_idx=0; $student_id = uc($student_id);
                   1243:     print " set #:\n";
                   1244:     while(! $done) {
                   1245:       $set_idx++;
                   1246:       if( $set_idx <= $s_limit) {
                   1247:         $filename= $classpath . "/records/set" . "$set_idx" . ".db";
                   1248:         if(-f $filename) {
                   1249:           printf "    %2d: ", $set_idx;
                   1250:           open(IN, "<$filename") || die "Cannot open file $filename!";
                   1251:           $line_cnt=0; $found = 0;  # for each file opened, initialize $line_cnt and $found
                   1252:           while ( ($input_line = <IN>) && !$found) { 
                   1253:             $line_cnt++;       # add one to line count
                   1254:             if( $line_cnt > 3) {    # start from line 4 is the student data
                   1255:               chomp($input_line);              # delete the trailing '\n' char
                   1256:               $s_num = substr($input_line,0,9);
                   1257:               $s_num = uc($s_num);
                   1258:               if( $student_id eq $s_num ) {
                   1259:                 $found = 1; 
                   1260:                 $data = substr($input_line,10);
                   1261:                 ($ans_str,$try_str) = split(/,/,$data,2);
                   1262:                 print "$ans_str\n          $try_str\n";
                   1263:               }
                   1264:             } # $line_cnt > 3 
                   1265:           } # end while $input_line and ! $found
                   1266:           close(IN) || die "Cannot close file $filename!";
                   1267:           if(! $found ) {  # student record entry not in the setX.db file ==> two empty lines
                   1268:             print "\n\n";  
                   1269:           }
                   1270:         } else { # $filename does not exist
                   1271:           $done = 1; 
                   1272:         }
                   1273:       } else { # $set_idx > $s_limit
                   1274:         $done = 1; 
                   1275:       }
                   1276:     }
                   1277:     printf "Press RETURN to continue"; $tmp = <>;
                   1278:  }
                   1279: 
                   1280: #
                   1281: # INPUTS: class name with full path, set number
                   1282: #
                   1283: sub S_ItemAnalysis {
                   1284:     local($classpath,$set)=@_;
                   1285:     local($filename,$found,$classname);
                   1286:     local($done)=0;
                   1287:     local($line_cnt,$input_line);
                   1288:     local($valid,$valid_cnt);
                   1289:     local(@weights);       # the wights array for individual set
                   1290:     local($valid_weights); # the valid weights for a set
                   1291:     local($total_weights); # the overall valid weights for all sets
                   1292:     local(@set_weights);   # the array storing all set valid weights
                   1293:     local($score);         # the valid score for a set
                   1294:     local($total_scores);  # the overall valid scores for all sets
                   1295:     local(@set_scores);    # the array storing all set scores
                   1296:     local($diff,$disc);
                   1297:     local($ii,$upper_percent,$lower_percent);
                   1298:     local($s_num,$ans_str,$prefix,$rest);
                   1299:     local(@ans_char,$ratio,$tmp);
                   1300:     local($Y_cnt[100],$N_cnt[100]);
                   1301:     local($Ycnt_upper[100],$Ycnt_lower[100],$tmp_total);
                   1302:     local($Y_total,$N_total);
                   1303:     local($upperpart_cnt,$lowerpart_limit);
                   1304:     local(%s_db);
                   1305:     
                   1306:     $total_scores = 0; $total_weights = 0; # initialize the overall results
                   1307:     $upper_percent = 0.0; $lower_percent = 0.0;
                   1308:     
                   1309:     for($ii=0;$ii<100;$ii++) {
                   1310:       $Y_cnt[$ii] = 0; $N_cnt[$ii] = 0; $Ycnt_upper[$ii] = 0.0; $Ycnt_lower[$ii] = 0.0;
                   1311:     }
                   1312:     $filename = $classpath . "/records/set" . "$set" . ".db";
                   1313:     if( -f $filename) { # file exists!
                   1314:       open(IN, "<$filename") || die "Cannot open file $filename!";
                   1315:       $valid_cnt = 0; # initialize $valid_cnt
                   1316:       $line_cnt=0;    # initialize $line_cnt
                   1317:       while (<IN>) {
                   1318:         $line_cnt++;       # add one to line count
                   1319:         if( $line_cnt == 2 ) { # second line is the weight for each problem
                   1320:           chomp();             # delete the trailing '\n' char
                   1321:           (@weights) = split(/ */);  # split the line into each individual chars
                   1322:           $valid_weights = 0;
                   1323:           for($ii=0;$ii<=$#weights;$ii++) {
                   1324:             $valid_weights += $weights[$ii];  # for now $valid_weights contains the sum
                   1325:           }
                   1326:         }
                   1327:         if( $line_cnt > 3) {    # start from line 4 is the student data
                   1328:           chomp();              # delete the trailing '\n' char
                   1329:           ($prefix,$rest) = split(/,/,$_,2);        # split the whole line into two parts
                   1330:           ($s_num,$ans_str) = split(/ /,$prefix,2); # split into two parts
                   1331:           $s_num = uc($s_num);
                   1332:           
                   1333:           ### print "$ans_str\n";
                   1334:           (@ans_char) = split(/ */,$ans_str);  # split the answer string into in dividual ans chars
                   1335:           for($valid = 'N', $ii=0;$ii<=$#ans_char;$ii++) {  # from question 0, 1 , to last question -1
                   1336:               $valid = 'Y' if $ans_char[$ii] ne '-';          # if ans char is different from '-', then
                   1337:           }
                   1338:           if( $valid eq 'Y' ) {   # don't bother with the record full of '-'s
                   1339:             $valid_cnt++;
                   1340:             for($score=0,$ii=0;$ii<=$#ans_char;$ii++) {  # initialize $score and index $ii
                   1341: 
                   1342:               if($ans_char[$ii] eq 'Y' || $ans_char[$ii] eq 'y') {
                   1343:                 $score += $weights[$ii];
                   1344:                 $Y_cnt[$ii]++;
                   1345:                 $Y_total++;
                   1346:               }
                   1347:               if( $ans_char[$ii] eq 'N' || $ans_char[$ii] eq 'n' || 
                   1348:                   $ans_char[$ii] eq '0' ) {
                   1349:                 $N_cnt[$ii]++;
                   1350:                 $N_total++;
                   1351:               }
                   1352:               if( $ans_char[$ii] gt '0' && $ans_char[$ii] le '9') {
                   1353:                 $score += $ans_char[$ii];
                   1354:                 if( $ans_char[$ii] eq $weights[$ii] ) {
                   1355:                   $Y_cnt[$ii]++;
                   1356:                   $Y_total++;
                   1357:                 } else {
                   1358:                   $N_cnt[$ii]++;
                   1359:                   $N_total++;
                   1360:                 }
                   1361:               } 
                   1362:               if($ans_char[$ii] eq 'E') { # subtract the weight from execused problem
                   1363:                 $valid_weights -= $weights[$ii];
                   1364:               }
                   1365:             } # end of score calculation
                   1366:             
                   1367:             $sort_key = sprintf "%05d%s", $score,$s_num;
                   1368:             $s_db{$sort_key} = "$ans_str";
                   1369:             
                   1370:           }
                   1371:         }   # end $line_cnt > 3
                   1372:       } # end while <IN>
                   1373:       close(IN) || die "Cannot close file $filename!";
                   1374: 
                   1375:       for($ii=0;$ii<100;$ii++) {
                   1376:         ## $Y_cnt[$ii]=0; $N_cnt[$ii]=0; 
                   1377:         $Ycnt_upper[$ii] = 0; $Ycnt_lower[$ii] = 0;
                   1378:       }
                   1379:       $upperpart_cnt   = int(0.27 * $valid_cnt);   # upper  27 percent
                   1380:       $lowerpart_limit = ($valid_cnt - $upperpart_cnt);   # beyond 73 percent
                   1381:       ### open(DBUG, ">/tmp/f.DBUG") || die "Cannot open /tmp/f.DBUG file!";
                   1382:       $line_cnt=0;
                   1383:       foreach $sort_key (reverse sort keys %s_db) {
                   1384:         $line_cnt++;
                   1385:         ### print DBUG "$sort_key\[$s_db{$sort_key}\]";
                   1386:         
                   1387:         $ans_str = "$s_db{$sort_key}";
                   1388:         (@ans_char) = split(/ */,$ans_str);
                   1389:         for($ii=0;$ii<=$#ans_char;$ii++) {
                   1390:           if( ($ans_char[$ii] eq 'Y') || ($ans_char[$ii] eq 'y') ||
                   1391:               ($ans_char[$ii] eq $weights[$ii] ) ) {  ## only if they got a full credit that 
                   1392:                                                       ## we count it as 'Y'
                   1393:            
                   1394:               if($line_cnt <= $upperpart_cnt) {
                   1395:                 $Ycnt_upper[$ii]++;
                   1396:               } elsif ( $line_cnt > $lowerpart_limit ) {
                   1397:                 $Ycnt_lower[$ii]++;
                   1398:               }
                   1399:           }
                   1400:           ### print DBUG " $Ycnt_upper[$ii]/$Ycnt_lower[$ii] ";
                   1401:         } # end for $ii
                   1402:         ### print DBUG "\n";
                   1403:       } #end foreach
                   1404:       ### close(DBUG);
                   1405:       print " There are $valid_cnt entries in file $filename\n";
                   1406:       printf "  The upper 27%% has %d records, the lower 27%% has %d records\n", $upperpart_cnt, $valid_cnt-$lowerpart_limit;
                   1407:       print " question \#     DoDiff.      Disc. Factor (%upper - %lower) [#records,#records]\n";
                   1408:       
                   1409:       for($ii=0;$ii<=$#ans_char;$ii++) {
                   1410:         $tmp_total = $N_cnt[$ii] + $Y_cnt[$ii];
                   1411:         if( $tmp_total > 0 ) {
                   1412:           $diff = 100.0*($N_cnt[$ii] / ($N_cnt[$ii] + $Y_cnt[$ii]));
                   1413:         } else {
                   1414:           $diff = '-';
                   1415:         }
                   1416:         $upper_percent =  100.0 * ($Ycnt_upper[$ii] /$upperpart_cnt);
                   1417:         $lower_percent =  100.0 * ($Ycnt_lower[$ii] /$upperpart_cnt);
                   1418:         $disc = $upper_percent  - $lower_percent;
                   1419:         printf "         %2d:    ", $ii+1;
                   1420:         printf "%6.1f         %5.1f (% 5.1f - % 5.1f) [%4d,%4d]\n", 
                   1421:                 $diff, $disc,$upper_percent,$lower_percent,$Ycnt_upper[$ii],$Ycnt_lower[$ii];
                   1422:       }
                   1423:       printf "Press RETURN to continue"; $tmp = <>;
                   1424:     } else { # file does not exist!
                   1425:       print "FILE: $filename does not exist!\n";
                   1426:       printf "Press RETURN to continue"; $tmp = <>;
                   1427:     }
                   1428:  }
                   1429: 
                   1430: #
                   1431: # INPUTS: class name with full path, set number
                   1432: #
                   1433: sub  S_SetCorrelation {
                   1434:      local($classpath,$set)=@_;
                   1435:      local($filename);
                   1436:      local($line_cnt);
                   1437:      local($data,$ans_str,@ans_char,$try_str);
                   1438:      local($ii,$jj,$question_cnt);
                   1439:      local($index_key,@weights);
                   1440:      local($first_char,$second_char);
                   1441:      local(%corr,%valid_cnt,$ratio,$tmp,$tmp_len,$ratio_str);
                   1442:      
                   1443:      $filename= $classpath . "/records/set" . "$set" . ".db";
                   1444: 
                   1445:      if(-f $filename) {
                   1446:        open(IN, "<$filename") || die "Cannot open file $filename!";
                   1447:        $line_cnt=0;
                   1448:        while(<IN>) {
                   1449:          $line_cnt++;
                   1450:          if( $line_cnt == 2 ) { # second line is the weight for each problem
                   1451:           chomp();             # delete the trailing '\n' char
                   1452:           (@weights) = split(/ */);  # split the line into each individual chars
                   1453:         }
                   1454:          if( $line_cnt > 3) {
                   1455:            chomp();
                   1456:            $data = substr($_,10);  # skip over student number
                   1457:            ($ans_str,$try_str) = split(/,/,$data,2);
                   1458:            (@ans_char) = split(/ */,$ans_str);
                   1459:            $question_cnt = $#ans_char;
                   1460:            for($ii=0;$ii<$#ans_char;$ii++) {
                   1461:              for($jj=$ii+1;$jj<=$#ans_char;$jj++) {
                   1462:                $index_key = "$ii" . "$jj";
                   1463:                if( $ans_char[$ii] eq '-' || $ans_char[$ii] eq 'E' ) {
                   1464:                  # do nothing
                   1465:                } else {
                   1466:                  if( $ans_char[$ii] gt '0' && $ans_char[$ii] le '9') {
                   1467:                    if( $ans_char[$ii] eq $weights[$ii] ) {
                   1468:                      $first_char = 'Y';
                   1469:                    } else {
                   1470:                      $first_char = 'N';
                   1471:                    }
                   1472:                  } elsif ($ans_char[$ii] eq '0') {
                   1473:                    $first_char = 'N';
                   1474:                  } elsif ($ans_char[$ii] eq 'y' || $ans_char[$ii] eq 'n') {
                   1475:                    $first_char = uc($ans_char[$ii]);
                   1476:                  } else {
                   1477:                    $first_char = $ans_char[$ii];
                   1478:                  }
                   1479:                  if( $ans_char[$jj] eq '-' || $ans_char[$jj] eq 'E' ) {
                   1480:                    # do nothing
                   1481:                  } else {
                   1482:                    if( $ans_char[$jj] gt '0' && $ans_char[$jj] le '9') {
                   1483:                      if( $ans_char[$jj] eq $weights[$jj] ) {
                   1484:                        $second_char = 'Y';
                   1485:                      } else {
                   1486:                        $second_char = 'N';
                   1487:                      }
                   1488:                    } elsif ($ans_char[$jj] eq '0') {
                   1489:                      $second_char = 'N';
                   1490:                    } elsif ($ans_char[$jj] eq 'y' || $ans_char[$jj] eq 'n') {
                   1491:                      $second_char = uc($ans_char[$jj]);
                   1492:                    } else {
                   1493:                      $second_char = $ans_char[$jj];
                   1494:                    }
                   1495:                    if( $first_char eq $second_char ) {
                   1496:                      if(defined $corr{$index_key} ) {
                   1497:                        $corr{$index_key}++;
                   1498:                      } else {
                   1499:                        $corr{$index_key} = 1;
                   1500:                      }
                   1501:                    } else {
                   1502:                      if(defined $corr{$index_key} ) {
                   1503:                        $corr{$index_key}--;
                   1504:                      } else {
                   1505:                        $corr{$index_key} = -1;
                   1506:                      }
                   1507:                    }
                   1508:                    # add one count to valid_count
                   1509:                    if(defined $valid_cnt{$index_key}) {
                   1510:                      $valid_cnt{$index_key}++;
                   1511:                    } else {
                   1512:                      $valid_cnt{$index_key} = 1;
                   1513:                    }
                   1514:                  }
                   1515:                }
                   1516:              } # end $jj loop
                   1517:            } # end $ii loop
                   1518:          } # end $line_cnt > 3
                   1519:        } # end while <IN>
                   1520:        close(IN) || die "Cannot close file $filename!";
                   1521:        # print out the correlation matrix
                   1522:        
                   1523:        print "  ";
                   1524:        for($ii=1;$ii<=$question_cnt;$ii++) {
                   1525:          print " " x 4;
                   1526:          printf "%2d", $ii+1;
                   1527:        }
                   1528:        print "\n";
                   1529:        # --------------------------------------
                   1530:        for($ii=0;$ii<$question_cnt;$ii++) {
                   1531:          printf " %2d:", $ii+1;
                   1532:          print  "      " x ($ii);
                   1533:          for($jj=$ii+1;$jj<=$question_cnt;$jj++) {
                   1534:            $index_key = "$ii" . "$jj";
                   1535:            if( defined $corr{$index_key} ) {
                   1536:              $ratio = $corr{$index_key} / $valid_cnt{$index_key};
                   1537:              printf " % .2f", $ratio;
                   1538:            } else {
                   1539:              print "  ----";
                   1540:            }
                   1541:          }
                   1542:          print "\n";
                   1543:        }
                   1544:        printf "Press RETURN to continue"; $tmp = <>;
                   1545:      } else { # file exists!
                   1546:        print "FILE: $filename does not exist!\n";
                   1547:        printf "Press RETURN to continue"; $tmp = <>;
                   1548:      }
                   1549:  }
                   1550: 
                   1551: # INPUTS: class name with full path, set number
                   1552: #
                   1553: # r = \frac{\sum{x_i y_i} - \frac{(\sum x_i)(\sum y_i)}{n}}{\sqrt{(\sum x_i^2 - \frac{}{}}}
                   1554: #
                   1555: # corr = (sum of prod_xy - (sum_x*sum_y / n) ) / sqrt( (sum of sqr_x - (sum_x*sum_x/n))*
                   1556: # 
                   1557: sub  S_SetCorrelationStatistics {
                   1558:      local($classpath,$set)=@_;
                   1559:      local($filename);
                   1560:      local($line_cnt);
                   1561:      local($data,$ans_str,@ans_char,$try_str);
                   1562:      local($ii,$jj,$question_cnt);
                   1563:      local($index_key,@weights);
                   1564:      local($x_data,$y_data);
                   1565:      local(%valid_cnt,$ratio,$tmp,$tmp_len,$ratio_str);
                   1566:      local(%prod_xy,%sum_x,%sum_y,%sum_x2,%sum_y2);
                   1567:      local($upper_part,$lower_part);
                   1568:      
                   1569:      $filename= $classpath . "/records/set" . "$set" . ".db";
                   1570: 
                   1571:      if(-f $filename) {
                   1572:        open(IN, "<$filename") || die "Cannot open file $filename!";
                   1573:        $line_cnt=0;
                   1574:        while(<IN>) {
                   1575:          $line_cnt++;
                   1576:          if( $line_cnt == 2 ) { # second line is the weight for each problem
                   1577:           chomp();             # delete the trailing '\n' char
                   1578:           (@weights) = split(/ */);  # split the line into each individual chars
                   1579:         }
                   1580:          if( $line_cnt > 3) {
                   1581:            chomp();
                   1582:            $data = substr($_,10);  # skip over student number
                   1583:            ($ans_str,$try_str) = split(/,/,$data,2);
                   1584:            (@ans_char) = split(/ */,$ans_str);
                   1585:            $question_cnt = $#ans_char;
                   1586:            for($ii=0;$ii<$#ans_char;$ii++) {
                   1587:              for($jj=$ii+1;$jj<=$#ans_char;$jj++) {
                   1588:                $index_key = "$ii" . "$jj";
                   1589:                if( $ans_char[$ii] eq '-' || $ans_char[$ii] eq 'E' ) {
                   1590:                  # do nothing
                   1591:                } else { ## $ans_char[$ii] is one of 0 .. 9, Y, y, N, n
                   1592:                  if( $ans_char[$jj] eq '-' || $ans_char[$jj] eq 'E' ) {
                   1593:                    # do nothing
                   1594:                  } else {
                   1595:                    if( $ans_char[$ii] eq 'Y' || $ans_char[$ii] eq 'y' ) {
                   1596:                      $x_data = $weights[$ii];
                   1597:                    } elsif ( $ans_char[$ii] eq 'N' || $ans_char[$ii] eq 'n' ) {
                   1598:                      $x_data = 0;
                   1599:                    } else { ## must be in 0 .. 9
                   1600:                      $x_data = $ans_char[$ii];
                   1601:                    }
                   1602:                    if( $ans_char[$jj] eq 'Y' || $ans_char[$jj] eq 'y' ) {
                   1603:                      $y_data = $weights[$jj];
                   1604:                    } elsif ( $ans_char[$jj] eq 'N' || $ans_char[$jj] eq 'n' ) {
                   1605:                      $y_data = 0;
                   1606:                    } else { ## must be in 0 .. 9
                   1607:                      $y_data = $ans_char[$jj];
                   1608:                    }
                   1609:                    if(defined $prod_xy{$index_key}) {
                   1610: 		     if ( $ii == 3 && $jj == 7 ) {
                   1611: 		       printf "%f %f %f\n",$x_data,$y_data,$prod_xy{$index_key}
                   1612: 		     }
                   1613:                      $prod_xy{$index_key} += ($x_data * $y_data);
                   1614: 		   } else {
                   1615: 		     if ( $ii == 3 && $jj == 7 ) {
                   1616: 		       printf "%f %f %f\n",$x_data,$y_data,0.0
                   1617: 		     }
                   1618:                      $prod_xy{$index_key} = 0.0;
                   1619:                    }
                   1620:                    if(defined $sum_x{$index_key} ) {
                   1621:                      $sum_x{$index_key}  += $x_data;
                   1622:                    } else {
                   1623:                      $sum_x{$index_key} = 0;
                   1624:                    }
                   1625:                    if(defined $sum_y{$index_key}) {
                   1626:                      $sum_y{$index_key}  += $y_data;
                   1627:                    } else {
                   1628:                      $sum_y{$index_key} = 0;
                   1629:                    }
                   1630:                    if(defined $sum_x2{$index_key} ) {
                   1631:                      $sum_x2{$index_key} += ($x_data * $x_data);
                   1632:                    } else {
                   1633:                      $sum_x2{$index_key} = 0;
                   1634:                    }
                   1635:                    if(defined $sum_y2{$index_key} ) {
                   1636:                      $sum_y2{$index_key} += ($y_data * $y_data);
                   1637:                    } else {
                   1638:                      $sum_y2{$index_key} = 0;
                   1639:                    }
                   1640:                    # add one count to valid_count
                   1641:                    if(defined $valid_cnt{$index_key}) {
                   1642:                      $valid_cnt{$index_key}++;
                   1643:                    } else {
                   1644:                      $valid_cnt{$index_key} = 1;
                   1645:                    }
                   1646:                  }
                   1647:                }
                   1648:              } # end $jj loop
                   1649:            } # end $ii loop
                   1650:          } # end $line_cnt > 3
                   1651:        } # end while <IN>
                   1652:        close(IN) || die "Cannot close file $filename!";
                   1653:        # print out the correlation matrix
                   1654:        
                   1655:        print "  ";
                   1656:        for($ii=1;$ii<=$question_cnt;$ii++) {
                   1657:          print " " x 4;
                   1658:          printf "%2d", $ii+1;
                   1659:        }
                   1660:        print "\n";
                   1661:        # --------------------------------------
                   1662:        for($ii=0;$ii<$question_cnt;$ii++) {
                   1663:          printf " %2d:", $ii+1;
                   1664:          print  "      " x ($ii);
                   1665:          for($jj=$ii+1;$jj<=$question_cnt;$jj++) {
                   1666:            $index_key = "$ii" . "$jj";
                   1667:            if( defined  $valid_cnt{$index_key}) {  ## there are at least one valid data
                   1668:              $upper_part = $prod_xy{$index_key} - ( ($sum_x{$index_key} * $sum_y{$index_key}) / $valid_cnt{$index_key} );
                   1669:              $lower_part = $sum_x2{$index_key} - ($sum_x{$index_key} * $sum_x{$index_key} / $valid_cnt{$index_key} );
                   1670:              $lower_part = $lower_part * ( $sum_y2{$index_key} - ($sum_y{$index_key} * $sum_y{$index_key} / $valid_cnt{$index_key} ));
                   1671:              $lower_part = sqrt($lower_part);
                   1672: 	     if ($ii == 3 && $jj==7) {
                   1673: 	       printf "%f %f %f %f",$prod_xy{$index_key},$sum_x{$index_key},$sum_y{$index_key},$valid_cnt{$index_key};
                   1674: 	     }
                   1675:              if( $lower_part != 0.0 ) {
                   1676:                $ratio = $upper_part / $lower_part;
                   1677:                printf " % .2f", $ratio;
                   1678:              } else {
                   1679:                print "  inf ";
                   1680:              }
                   1681:            } else {
                   1682:              print "  ----";
                   1683:            }
                   1684:          }
                   1685:          print "\n";
                   1686:        }
                   1687:        printf "Press RETURN to continue"; $tmp = <>;
                   1688:      } else { # file exists!
                   1689:        print "FILE: $filename does not exist!\n";
                   1690:        print "Press RETURN to continue"; $tmp = <>;
                   1691:      }
                   1692:  }
                   1693: # -------------------------- Create a file contains all scores ----
                   1694: #   it will 
                   1695: sub   S_CreateScores {
                   1696:      local($sfilename)=@_;
                   1697:      local($filename);
                   1698:      local($c_scores,$c_max_scores,$c_abscent,$c_count,$c_summary);
                   1699:      local($q_scores,$q_max_scores,$q_abscent,$q_count,$q_summary);
                   1700:      local($e_scores,$e_max_scores,$e_abscent,$e_count,$e_summary);
                   1701:      local($s_scores,$s_max_scores,$s_abscent,$s_count,$s_summary);
                   1702:      local($o_scores,$o_max_scores,$o_abscent,$o_count,$o_summary);
                   1703:      local($c_ratio,$q_ratio,$e_ratio,$s_ratio,$o_ratio);
                   1704:      local($m_1,$m_2,$m_3,$f_score);
                   1705:      local($m_max1,$m_max2,$m_max3,$f_max);
                   1706:      local($mt1_ratio,$mt2_ratio,$mt3_ratio,$f_ratio);
                   1707:      local($var_name);
                   1708:      local($total_score,$day_str);
                   1709:      local($e_entry);
                   1710:      local($s_key,%f_entry,$pre_entry,$whole_entry,$tail_entry,$score_str);
                   1711:      local($tmp);
                   1712:     
                   1713:     $day_str = &TimeString;
                   1714:     
                   1715:     $filename = "$ClassPath" . "/classl";
                   1716:     
                   1717:     open(CIN, "<$filename") || die "Cannot open file $filename!";
                   1718:     while(<CIN>) {
                   1719:       chomp();
                   1720:       $s_id = substr($_,14,9); $s_id = uc($s_id);
                   1721:       
                   1722:       # $homework_scores_limit_set comes from capa.config
                   1723:       ($c_scores,$c_max_scores,$c_abscent,$c_count,$c_summary) =
                   1724:        &S_CollectSetScores($ClassPath,"$s_id",0,$homework_scores_limit_set);
                   1725:        
                   1726:       $c_ratio = $c_scores/$c_max_scores if $c_max_scores != 0;
                   1727:       ## print "$c_scores/$c_max_scores,$c_abscent/$c_count\n";
                   1728:       
                   1729:       # $quiz_scores_limit_set comes from capa.config
                   1730:       ($q_scores,$q_max_scores,$q_abscent,$q_count,$q_summary) = 
                   1731:         &S_CollectSetScores($QuizPath,"$s_id",0,$quiz_scores_limit_set) if -d "$QuizPath";
                   1732:       $q_ratio = $q_scores/$q_max_scores if $q_max_scores != 0;
                   1733:       ## print "$q_scores/$q_max_scores,$q_abscent/$q_count\n";
                   1734:       
                   1735:       # exam has different formula
                   1736:       
                   1737:       ($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";
                   1738:       
                   1739:       # we can evaluate midterm1 when $e_count > 2 
                   1740:       #  the perl code for midterm1 is stored in $P_code{'midterm1'}
                   1741:       # FORMULA for exam scores
                   1742:       if( $e_count < 1 ) { # 0  set, no extrapolated scores
                   1743:         $e_scores = 0;
                   1744:         $tail_entry = "     --/--      --/--      --/--   --/--    ";
                   1745:                       
                   1746:       } elsif ( ($e_count == 1) || ($e_count == 2) ) {
                   1747:         $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
                   1748:         $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt1_ratio + $mt3_percent * $mt1_ratio + $final_percent * $mt1_ratio;
                   1749:         $e_entry = sprintf " %6.2f/%3d     --/--      --/--   --/--    ", $m_1,$m_max1;
                   1750:       } elsif ( ($e_count == 3) || ($e_count == 4) ) {
                   1751:         $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
                   1752:         $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
                   1753:         $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + 
                   1754:                     (($mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio)*0.5) + 
                   1755:                     $final_percent * (($m_1 + $m_2)/($m_max1 + $m_max2));
                   1756:         $e_entry = sprintf " %6.2f/%3d %6.2f/%3d     --/--   --/--    ", $m_1,$m_max1,$m_2,$m_max2;
                   1757:       } elsif ( ($e_count == 5) || ($e_count == 6) ) {
                   1758:         $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
                   1759:         $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
                   1760:         $mt3_ratio = $m_3/$m_max3 if $m_max3 != 0;
                   1761:         $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + $mt3_percent * $mt3_ratio +
                   1762:                     $final_percent * (($m_1+$m_2+$m_3)/($m_max1+$m_max2+$m_max3));
                   1763:         $e_entry = sprintf " %6.2f/%3d %6.2f/%3d %6.2f/%3d  --/--    ", $m_1,$m_max1,$m_2,$m_max2,$m_3,$m_max3;
                   1764:       } else { # suppose to be 7
                   1765:         $mt1_ratio = $m_1/$m_max1 if $m_max1 != 0;
                   1766:         $mt2_ratio = $m_2/$m_max2 if $m_max2 != 0;
                   1767:         $mt3_ratio = $m_3/$m_max3 if $m_max3 != 0;
                   1768:         $f_ratio   = $f_score/$f_max if $f_max != 0;
                   1769:         $e_scores = $mt1_percent * $mt1_ratio + $mt2_percent*$mt2_ratio + $mt3_percent * $mt3_ratio + $final_percent * $f_ratio;
                   1770:         $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;
                   1771:       }
                   1772:       
                   1773:       # $supp_scores_limit_set comes from capa.config
                   1774:       ($s_scores,$s_max_scores,$s_abscent,$s_count,$s_summary) = 
                   1775:         &S_CollectSetScores($SuppPath,"$s_id",0,$supp_scores_limit_set) if -d "$SuppPath";
                   1776:       $s_ratio = $s_scores/$s_max_scores if $s_max_scores != 0;
                   1777:       ## print "$s_scores/$s_max_scores,$s_abscent/$s_count\n";
                   1778:       
                   1779:       # $others_scores_limit_set comes from capa.config
                   1780:       ($o_scores,$o_max_scores,$o_abscent,$o_count,$o_summary) = 
                   1781:         &S_CollectSetScores($OthersPath,"$s_id",0,$others_scores_limit_set) if -d "$OthersPath";
                   1782:        $o_ratio = $o_scores/$o_max_scores if $o_max_scores != 0;
                   1783:       ## print "$o_scores/$o_max_scores,$o_abscent/$o_count\n";
                   1784:       
                   1785:       
                   1786:       $total_score = $hw_percent*$c_ratio + $qz_percent*$q_ratio + $e_scores;
                   1787: 
                   1788:       $score_str = sprintf "% 6.2f", $total_score;
                   1789:       $s_key = sprintf "%06.2f %s", $total_score,$s_id;
                   1790:       # #            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total
                   1791:       #
                   1792:       # A12345678 123/123 123/123 123/123 123/123 123.45/123 123.45/123 123.45/123 123/123   123.45
                   1793:       #
                   1794:       # A23546721 335/341  45/ 45   0/ 15  76/ 81  30.00/ 30  28.60/ 30  30.00/ 30  56/ 57   100.39
                   1795:       # A23778965 333/341  34/ 45   1/ 15  79/ 81  27.90/ 30  28.60/ 30  28.60/ 30  55/ 57    96.72
                   1796:       # A11111111   0/341   0/ 45  14/ 15   0/ 81   0.00/ 30   0.00/ 30   0.00/ 30   0/ 57     0.00
                   1797:       # 173533390   0/341   0/ 45  15/ 15   0/ 81   0.00/ 30   0.00/ 30   0.00/ 30   0/ 57     0.00
                   1798: 
                   1799:       $pre_entry = sprintf "%3d/%3d %3d/%3d %3d/%3d %3d/%3d",
                   1800:        $c_scores,$c_max_scores,$q_scores,$q_max_scores,$q_abscent,$q_count,$s_scores,$s_max_scores;
                   1801:       
                   1802:       
                   1803:       $tail_entry = sprintf "%6.2f", $total_score;
                   1804:       
                   1805:       
                   1806:       $whole_entry = "$s_id " . "$pre_entry" . "$e_entry" . "$tail_entry\n";
                   1807:       
                   1808:       $f_entry{$s_key} = $whole_entry;
                   1809:       print " $s_id $score_str \[$pre_entry\]\n";
                   1810:       print "\t\t\[$e_entry $tail_entry\]\n";
                   1811:     }
                   1812:     close(CIN) || die "Cannot close file $filename!";
                   1813:     # close the classl file and
                   1814: 
                   1815:     # open the set score report file
                   1816:      if(-f $sfilename) {  # if there is already a scores file, move it to something else
                   1817:        system("mv $sfilename $sfilename.prior.$day_str");
                   1818:      }
                   1819:      open(OUT, ">$sfilename") || die "Cannot open file $sfilename!";
                   1820:      print OUT "\#            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total\n";
                   1821:      foreach $s_key (reverse sort keys %f_entry) {
                   1822:        print OUT "$f_entry{$s_key}";
                   1823:      }
                   1824:      close(OUT) || die "Cannot close file $sfilename!";
                   1825:  }
                   1826:  
                   1827: #
                   1828: #  create all emails in the Mail/ directory
                   1829: #  input is the master scores file name
                   1830: sub    S_CreateEmails {
                   1831:     local($sfilename)=@_;
                   1832:     local($efilename);
                   1833:     local($s_id);
                   1834:     local($var_name,$s_sec,$email);
                   1835:     local($q_scores,$q_max_scores,$q_absent,$q_count,$q_summary);
                   1836:     local($last_n,$first_n,$first_part,$middle_n);
                   1837:     local($day_str,$cat,$tmp);
                   1838:     
                   1839:     # variable $Email_templateFile comes from capa.config entry email_template_file 
                   1840:     &ScanMailTemplate("$Email_templateFile");
                   1841:     
                   1842:     # after scanning the email template file, $P_code{'email_perl'} and $P_code{'template'} are defined
                   1843:     #  in the code $P_code{'email_perl'}, we need to define 
                   1844:     #     $final_grade and 
                   1845:     #   $category_one_high, $category_one_low, .. comes from capa.config
                   1846:     #   output $Summary_sentence
                   1847:     
                   1848:     #  in the code $P_code{'template'}
                   1849:     $day_str = &TodayString;
                   1850:     
                   1851:     if(-f $sfilename) {
                   1852:       open(SIN, "<$sfilename") || die "Cannot open file $sfilename!";
                   1853:       while(<SIN>) {
                   1854:       #           1         2         3         4         5         6         7         8         9
                   1855:       # 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
                   1856:       # #            HW      QZ     QZ-N    SUPP    Mid 1      Mid 2      Mid 3     Final     Total
                   1857:       # A23546721 335/341  45/ 45   0/ 15  76/ 81  30.00/ 30  28.60/ 30  30.00/ 30  56/ 57   100.39
                   1858:         if(! /^\#/) {  # non comments line
                   1859:           $s_id = substr($_,0,9); $s_id = uc($s_id);
                   1860:           $var_name = $Var_name{'Homework_total_score'};
                   1861:           ${$var_name} = int( substr($_,10,3) );  # homework total score
                   1862:           $var_name = $Var_name{'Homework_total_max'};
                   1863:           ${$var_name} = int( substr($_,14,3) );  # max score
                   1864:           $var_name = $Var_name{'Quiz_total_score'};
                   1865:           ${$var_name} = int( substr($_,18,3) );  # quiz score
                   1866:           $var_name = $Var_name{'Quiz_total_max'};
                   1867:           ${$var_name} = int( substr($_,22,3) );  # quiz max
                   1868:           
                   1869:           $var_name = $Var_name{'Quiz_absent'};
                   1870:           ${$var_name} = int( substr($_,26,3) );  # quiz absent
                   1871:           
                   1872:           $var_name = $Var_name{'Quiz_count'};
                   1873:           ${$var_name} = int( substr($_,30,3) );  # quiz count
                   1874:           
                   1875:           # need to take care of '--'
                   1876:           
                   1877:           $midterm1 = substr($_,42,6);
                   1878:           $midterm_max1 = int( substr($_,49,3));
                   1879:           
                   1880:           $midterm2 = substr($_,53,6);
                   1881:           $midterm_max2 = int( substr($_,60,3));
                   1882:           
                   1883:           $midterm3 = substr($_,64,6);
                   1884:           $midterm_max3 = int( substr($_,71,3));
                   1885:           
                   1886:           $final_exam = substr($_,75,3);
                   1887:           $final_exam_max = int( substr($_,79,3));
                   1888:           
                   1889:           $final_grade = substr($_,85,6);  # server as input to $P_code{'email_perl'}
                   1890:           
                   1891:           $final_grade = $final_grade * 1.0;
                   1892:           
                   1893:           ## print "PERL: $P_code{'email_perl'}\n";
                   1894:           ## print "Press RETURN to continue"; $tmp = <>;
                   1895:           
                   1896:           ## print "SUMMARY: $Summary_sentence\n";
                   1897:           ## print "Press RETURN to continue"; $tmp = <>;
                   1898:           
                   1899:           # now we know $Exam_sentence and $Summary_sentence
                   1900:           
                   1901:     # for $P_code{'template'}, we need to find
                   1902:     #   Global input
                   1903:     #         $student_name, $ClassName, there is already a $ClassName global variable
                   1904:     #         ${$Var_name{'Homework_total_score'}} ==> $HWtotal_scp
                   1905:     #         ${$Var_name{'Homework_total_max'}}   ==> $HWtotal_max_scp
                   1906:     #         ${$Var_name{'Quiz_count'}}           ==> $QZcount_scp
                   1907:     #         ${$Var_name{'Quiz_total_score'}}     ==> $QZtotal_scp 
                   1908:     #         ${$Var_name{'Quiz_total_max'}}       ==> $QZtotal_max_scp
                   1909:     
                   1910:     #         ${$Var_name{'Quiz_summary_string'}}  ==> $QZsummary <-- must read from the qz/records/*.db files
                   1911:     
                   1912:     #         $midterm1, $midterm2, $midterm3 and $final_exam
                   1913:     #     
                   1914:     ##  How to allow the format of $student_name customizable from capa.config file?
                   1915:     ##
                   1916:           ($student_name,$s_sec,$email) = S_Lookup_student_name("$s_id");
                   1917:           ($last_n,$first_part) = split(/,/,$student_name);
                   1918:           $first_part =~ s/^\s//g;
                   1919:           ($first_n,$middle_n) = split(/ /,$first_part);
                   1920:           $student_name = "$first_n" . " $last_n";
                   1921:           
                   1922:           # $quiz_scores_limit_set comes from capa.config
                   1923:           ($q_scores,$q_max_scores,$q_absent,$q_count,$q_summary) = 
                   1924:             &S_CollectSetScores($QuizPath,"$s_id",0,$quiz_scores_limit_set) if -d "$QuizPath";
                   1925:           ${$Var_name{'Quiz_summary_string'}} = "$q_summary";
                   1926:           ${$Var_name{'Quiz_absent'}} = $q_absent;
                   1927:           ${$Var_name{'Quiz_count'}}  = $q_count;
                   1928:           eval "$P_code{'email_perl'}";
                   1929:           if( ($final_grade <= $category_one_high) && ($final_grade >= $category_one_low)) {
                   1930:             $cat = 1;
                   1931:           } elsif ( ($final_grade <= $category_two_high)&&($final_grade >= $category_two_low) ) {
                   1932: 
                   1933:             $cat = 2;
                   1934:   
                   1935:           } elsif ( ($final_grade <= $category_three_high)&&($final_grade >= $category_three_low)  ) {
                   1936: 
                   1937:             $cat = 3;
                   1938:   
                   1939:           } elsif( ($final_grade <= $category_four_high)&&($final_grade >= $category_four_low) ) {
                   1940: 
                   1941:             $cat = 4;
                   1942:   
                   1943:           } else { # not in above category
                   1944: 
                   1945:             $cat = 5;
                   1946:           }
                   1947:           
                   1948:           $efilename = "$ClassPath" . "/Mail/$s_id.$day_str.$cat";
                   1949:           
                   1950:           if(-f $efilename) {  # remove the file with the same name, no warning!!
                   1951:             system("rm $efilename");
                   1952:           }
                   1953:           open(EOUT,">$efilename") || die "Cannot create file $efilename!";
                   1954:           eval "print EOUT \"$P_code{'template'}\" ";
                   1955:           close(EOUT) || die "Cannot close file $efilename!";
                   1956:           
                   1957:           print " $s_id\t$final_grade,\tcategory $cat\n";
                   1958:           
                   1959:         }
                   1960:       }
                   1961:       close(SIN) || die "Cannot close file $sfilename!";
                   1962:       print "=" x 45 . "\n";
                   1963:       print "DONE creating all email files in $ClassPath/Mail/ directory.\n";
                   1964:       print "Press RETURN to continue"; $tmp = <>;
                   1965:     } else {  # the master scores file does not exist
                   1966:       print "File $sfilename does not exist!\n";
                   1967:       print "Press RETURN to continue"; $tmp = <>;
                   1968:     }
                   1969:        
                   1970:  }
                   1971: # ----------------------------------------------------------------
                   1972: sub    ScanMailTemplate {
                   1973:   local($filename) = @_;
                   1974:   local($input_line);
                   1975:   local($tmp);
                   1976:   
                   1977:   
                   1978:   if(-f $filename) {
                   1979:     open(IN, "<$filename") || die "Cannot open $filename\n";
                   1980:     LINE: while( $input_line = <IN> ) {
                   1981:        chomp($input_line);
                   1982:        if($input_line =~ m|^//| )   { next LINE; }          ## ignore comments
                   1983:        if($input_line =~ m|^\#| )   { next LINE; }          ## ignore comments
                   1984:        if($input_line =~ m|^\s*BEGIN_perl| ) { ## Perl code
                   1985:          $P_code{'email_perl'} = &E_CollectPerlCode;
                   1986:          ## print "email_perl=$P_code{'email_perl'}";
                   1987:          next LINE; 
                   1988:        }
                   1989:        if($input_line =~ m|^\s*BEGIN_template| )  { ## template code
                   1990:          $P_code{'template'} = &E_CollectTemplateCode;
                   1991:          ## print "template = $P_code{'template'}";
                   1992:          next LINE; 
                   1993:        }
                   1994:        next LINE;
                   1995:     }
                   1996:     close(IN) || die "Cannot close $filename\n";
                   1997:     
                   1998:   } else {
                   1999:     printf "File $filename does not exist!"; $tmp = <>;
                   2000:   }
                   2001: 
                   2002:  }
                   2003: 
                   2004: # 
                   2005: #  Randomly pick a file in Mail/ directory and display 
                   2006: #   it on screen
                   2007: #  
                   2008: sub    S_RandomlyPreview {
                   2009:     local($filename);
                   2010:     local(@all_files);
                   2011:     local($upper_bound);
                   2012:     local($pick_idx,$pick_filename);
                   2013:     local($tmp);
                   2014:     
                   2015:     opendir(EDIR, "$ClassPath/Mail") || die "cannot opendir $ClassPath/Mail!";
                   2016:     @all_files = grep !/^\.\.?$/, readdir EDIR;
                   2017:     closedir EDIR;
                   2018:        ## srand(time() ^ ($$+( $$ << 15)) );
                   2019:        
                   2020:     $upper_bound = $#all_files + 1;
                   2021:     if( $upper_bound > 0 ) { # something to preview   
                   2022:        $pick_idx = ((rand $$) * 1000.0) % $upper_bound;
                   2023:        
                   2024:        # print "PICK: $pick_idx among $upper_bound\n";
                   2025:        
                   2026:        $pick_filename = $all_files[$pick_idx];
                   2027:        print "Preview File: $pick_filename\n";
                   2028:        print "Press RETURN to continue"; $tmp = <>;     &C_ClearScreen;
                   2029:        $filename = "$ClassPath/Mail/$pick_filename";
                   2030:        open(IN,"<$filename") ||  die "Cannot open file $filename!";
                   2031:        while(<IN>) {
                   2032:          print;
                   2033:        }
                   2034:        close(IN) || die "cannot close file $filename!";
                   2035:        print "Press RETURN to continue"; $tmp = <>;
                   2036:     } else {
                   2037:        print "No file in directory $ClassPath/Mail\n";
                   2038:        
                   2039:        print "Press RETURN to continue"; $tmp = <>;
                   2040:     
                   2041:     }
                   2042: 
                   2043:  }
                   2044:  
                   2045: 
                   2046: # The format of a classl file                                                                  
                   2047: # 
                   2048: #          1         2         3         4         5         6         7         8         9         0
                   2049: #0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
                   2050: #PHY 183   001 A23745301 Abraham, Christopher Wil            FS96
                   2051: #phy 111   001 A12345678 BUMSTEAD, Blondie                   blondie4@pilot.msu.edu            12345678
                   2052: #PHY 183   003 A24469315 Costigan, Timothy Patric            costiga3@pilot.msu.edu            costiga3
                   2053: #PHY 183   002 A25425738 Cacossa, Andrew Vincent             cacossaa@pilot.msu.edu            cacossaa
                   2054: 
                   2055: # lookup the student id supplied in variable $student_id
                   2056: # and return the student name and the e-mail address if available
                   2057: sub    S_Lookup_student_name {
                   2058:      local($student_id)=@_;
                   2059:      local($filename);
                   2060:      local($found,$input_line);
                   2061:      local($tmp_sn,$student_name);
                   2062:      local($len,$s_sec,$email);
                   2063:      
                   2064:   $student_id = uc($student_id);
                   2065:   $filename = $ClassPath . "/classl";
                   2066:   open(CIN, "<$filename") || die "Cannot open file $filename!";
                   2067:   $found = 0;
                   2068:   while( ($input_line = <CIN>) && (! $found) ) {
                   2069:     chomp($input_line);
                   2070:     $tmp_sn = substr($input_line,14,9); $tmp_sn = uc($tmp_sn);
                   2071:     if($tmp_sn =~ /^$student_id/ ) {
                   2072:       $found=1;
                   2073:        # student name begins at column 24 and has 30 chars max
                   2074:       $s_sec = substr($input_line,10,3);
                   2075:       $student_name = substr($input_line,24,30);
                   2076:       $len = length($input_line);
                   2077:       $email = "";
                   2078:       if($len > 55 ) {
                   2079:         $email = substr($input_line,55,32);
                   2080:         $email =~ s/\s+//g;
                   2081:         if( $email !~ /\@|\./ ) {
                   2082:           $email = "";
                   2083:         }
                   2084:       }
                   2085:     }
                   2086:   }
                   2087:   close(CIN) || die "Cannot close file $filename!";
                   2088:   return ($student_name,$s_sec,$email);
                   2089:  }
                   2090: 
                   2091: #  This routine accepts a string represent an absolute path to a class
                   2092: #   it checks to see if 
                   2093: #      the directory specified by this path did actually exist
                   2094: #      the records/ sub-directory did exist
                   2095: #      the records/setX.db  file exists
                   2096: #      the classl file exists
                   2097: 
                   2098: sub    S_CheckClassPath {
                   2099:     local($path)=@_;
                   2100:     local($cfullpath,$rfullpath,$sfullpath);
                   2101:     local($correct,$cfgfullpath,$cfgutilsfullpath);
                   2102:     
                   2103:     $correct = 0;
                   2104:     if( $path =~ /\/$/ ) {
                   2105:         $cfullpath = "$path" . "classl";
                   2106:         $rfullpath = "$path" . "records";
                   2107:         $sfullpath = "$path" . "records/set$set.db";
                   2108:         $cfgfullpath = "$path" . "capa.config";
                   2109:         $cfgutilsfullpath = "$path" . "capautils.config";
                   2110:     } else {
                   2111:         $cfullpath = "$path" . "/classl";
                   2112:         $rfullpath = "$path" . "/records";
                   2113:         $sfullpath = "$path" . "/records/set$set.db";
                   2114:         $cfgfullpath = "$path" . "/capa.config";
                   2115:         $cfgutilsfullpath = "$path" . "/capautils.config";
                   2116:     }
                   2117:     if( -d $path ) {
                   2118:         if( -d $rfullpath ) {
                   2119:           if(-f $cfgfullpath ) {
                   2120: 	      if(-f $cfgutilsfullpath ) {
                   2121: 		  $correct = 1;
                   2122: 	      } else {
                   2123: 		  print "File [$cfgutilsfullpath] does not exist!\n";
                   2124: 	      }
                   2125:           } else {
                   2126:             print "File [$cfgfullpath] does not exist!\n";
                   2127:           }
                   2128:         } else {
                   2129:           print "Directory [$rfullpath] does not exist!\n";
                   2130:         }
                   2131:     } else {
                   2132:         print "Directory [$path] does not exist!\n";
                   2133:     }
                   2134:     return ($correct);
                   2135:  }
                   2136:  
                   2137: ##
                   2138: # display score file according to the order specified 
                   2139: #  by $key_str and the direction in $dir
                   2140: #  $dir = 1 means ascending
                   2141: #         2 means descending
                   2142: #
                   2143: sub   S_DisplayScoreFile {
                   2144:     local($key_str,$dir,$sfilename)=@_;
                   2145:     local(@a_keyidx);
                   2146:     local($key_seq);
                   2147:     local($s_id,$final_grade,$s_name,$s_sec,$s_email);
                   2148:     local($sort_key,$s_display_name,$first_n,$first_part,$middle_n,$last_n);
                   2149:     local(%sf_entry);
                   2150:     local($line_cnt,$line_total,$len,$pad_len);
                   2151:     local($tmp);
                   2152:     
                   2153:     $key_str =~ s/,//g;
                   2154:     $key_str =~ s/1/\$final_grade/g;
                   2155:     $key_str =~ s/2/\$s_id/g;
                   2156:     if( $key_str =~ /3/ ) { 
                   2157:       $key_str =~ s/3/\$s_name/g;
                   2158:     }
                   2159:     if( $key_str =~ /4/ ) { 
                   2160:       $key_str =~ s/4/\$s_sec/g;
                   2161:     }
                   2162:     $key_seq = '"' . "$key_str" . '"';
                   2163:     
                   2164:     if(-f $sfilename) {
                   2165:       open(SIN, "<$sfilename") || die "Cannot open file $sfilename!";
                   2166:       $line_cnt = 0;
                   2167:       while(<SIN>) {
                   2168:         if(! /^\#/) {  # non comments line
                   2169:           chomp();
                   2170:           $line_cnt++;
                   2171:           $s_id = substr($_,0,9); $s_id = uc($s_id);
                   2172:           $final_grade = substr($_,85,6);  #
                   2173:           
                   2174:           $whole_entry = $_;
                   2175:           ($s_name,$s_sec,$s_email) = S_Lookup_student_name("$s_id");
                   2176:           # evaluate the code to a real key
                   2177:           $sort_key = eval $key_seq;
                   2178:           
                   2179:           ($last_n,$first_part) = split(/,/,$s_name);
                   2180:           $last_n = uc($last_n);
                   2181:           $first_part =~ s/^\s//g;
                   2182:           ($first_n,$middle_n) = split(/ /,$first_part);
                   2183:           $s_display_name = "$last_n" . ", $first_n";
                   2184:           $len = length($s_display_name);
                   2185:           if( $len < 25 ) {
                   2186:             $pad_len = 25 - $len;
                   2187:             $s_display_name = "$s_display_name" . " " x $pad_len;
                   2188:           } else {
                   2189:             $s_display_name = substr($s_display_name,0,25);
                   2190:           }
                   2191:           $sf_entry{"$sort_key"} = "$s_display_name $s_sec $whole_entry";
                   2192:           ### print "KEY:[$sort_key]:$whole_entry\n";
                   2193:         } # end of if not comments
                   2194:       } # end while <SIN>
                   2195:       close(SIN) || die "Cannot close file $sfilename!";
                   2196:       $line_total = $line_cnt; $line_cnt = 0;
                   2197:       if($dir == 1 ) {
                   2198:         foreach $sort_key (sort keys %sf_entry) {
                   2199:           $line_cnt++;
                   2200:           print $sf_entry{"$sort_key"} . "\n";
                   2201:           if( ($line_cnt % $display_score_row_limit) == 0 ) { # $display_score_row_limit from capa.config
                   2202:             print " --$line_cnt/$line_total-- Press RETURN to continue"; $tmp = <>;
                   2203:           }
                   2204:         }
                   2205:       } else {
                   2206:         foreach $sort_key (reverse sort keys %sf_entry) {
                   2207:           $line_cnt++;
                   2208:           print $sf_entry{"$sort_key"} . "\n";
                   2209:           if( ($line_cnt % $display_score_row_limit) == 0 ) {
                   2210:             print " --$line_cnt/$line_total-- Press RETURN to continue"; $tmp = <>;
                   2211:           }
                   2212:         }
                   2213:       }
                   2214:     } else {
                   2215:       print "File [$sfilename] does not exist!";
                   2216:     }
                   2217:     
                   2218:  }
                   2219: 
                   2220: ##
                   2221: ##   Input: file name to be printed through lpr command
                   2222: ##
                   2223: ##
                   2224: sub  S_LPRFile {
                   2225:      local($file)=@_;
                   2226:      local($go_on)=0;
                   2227:      local($select);
                   2228:      local($printer_selected);
                   2229:      local($emp);
                   2230:      local($cmd);
                   2231:      local($PS_file);
                   2232:  
                   2233:      print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2234:      $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2235:      $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2236:      
                   2237:       if( $go_on ) { # run lpr -P.... on the .ps file
                   2238:         $select = C_MultipleChoice(4,10,$DialogWidth,"           Printers Available         ",
                   2239:                           "Printer Name",@Printers);
                   2240:         $Printer_selected = $Printers[$select-1];
                   2241:         
                   2242:         $go_on = 0;
                   2243:         while( ! $go_on ) {
                   2244:           print "Enter 1 for one sided or 2 for two sided printing (RETURN = 1 sided): ";
                   2245:           $tmp=<>; 
                   2246:           if( ($tmp == 1) || ($tmp == 2) || ($tmp eq "\n") ) {
                   2247:             $tmp = 1 if $tmp eq "\n";
                   2248:             $go_on = 1;
                   2249:           }
                   2250:         }
                   2251:         if( $tmp == 1 ) {
                   2252:           $LpronesidedCMD =~ s/\$Printer_selected/$Printer_selected/e;
                   2253:           $cmd = "$LpronesidedCMD $file";
                   2254:         } else {  # should be 2
                   2255:           $PS_file = $file;
                   2256:           print "$LprtwosidedCMD\n";
                   2257:           $LprtwosidedCMD =~ s/\$Printer_selected/$Printer_selected/e;
                   2258:           $LprtwosidedCMD =~ s/\$PS_file/$PS_file/e;
                   2259:           $cmd = "$LprtwosidedCMD";
                   2260:         }
                   2261:         $go_on = 0;
                   2262:         print "=" x 70 . "\n";
                   2263:         print "CMD: $cmd\n";
                   2264:         print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2265:         $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2266:         $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2267:         if($go_on) {
                   2268:           open(IN,"$cmd|");
                   2269:           while($input_line = <IN>) {
                   2270:             print "$input_line";
                   2271:           }
                   2272:           close(IN);
                   2273:           print "=" x 70 . "\n";
                   2274:           print " Your job has been sent to the print spooler. Press RETURN to continue"; $tmp = <>;
                   2275:         }
                   2276:       }
                   2277:  }
                   2278: 
                   2279: 
                   2280: 
                   2281: # <========================= Main program =======================>
                   2282: 
                   2283: Getopts('c:s');
                   2284: 
                   2285: if (! $opt_c) {  ## class path option
                   2286:   print "USAGE: capatools.pl -c Full_path_to_class\n";
                   2287:   $ClassPath = &S_Enterpath;
                   2288: } else {  # need to check the path entered by option -c
                   2289:   if( S_CheckClassPath("$opt_c") ) {
                   2290:     $ClassPath = $opt_c;
                   2291:     if( $opt_s ) {
                   2292:       S_ReadCAPAconfig($ClassPath);
                   2293:       S_CreateScores("$Master_scoresFile");
                   2294:       # print "run score report in silent background\n";
                   2295:       # print "The $Master_scoresFile\n";
                   2296:       
                   2297:       exit (1);
                   2298:     }
                   2299:   } else {
                   2300:     $ClassPath = &S_Enterpath;
                   2301:   }
                   2302: }
                   2303: 
                   2304: $DialogWidth = 48;
                   2305: $Quit = 0;
                   2306: 
                   2307: 
                   2308: $len = length($ClassPath);
                   2309: if(  $len > ($DialogWidth-6) ) {  ## class path too long, display the last portion instead
                   2310:     $offset = $len - $DialogWidth +6;
                   2311:     $DisplayPath = "-..." . substr($ClassPath, $offset,$DialogWidth-6);
                   2312: } else {
                   2313:     $DisplayPath = $ClassPath;
                   2314: }
                   2315: 
                   2316: S_ReadCAPAconfig($ClassPath);
                   2317: 
                   2318: while(! $Quit ) {
                   2319:   $What = C_MultipleChoice(1,8,$DialogWidth,"        Welcome to CAPA Utilities Ver 1.1   ",
                   2320:                           "$DisplayPath",@Main_menu);
                   2321: 
                   2322:   if( $What ==  1 ) {        # change class path
                   2323:      $ClassPath = &S_Enterpath;
                   2324:      $len = length($ClassPath);
                   2325:      if(  $len > ($DialogWidth-6) ) {
                   2326:        $offset = $len - $DialogWidth +6;
                   2327:        $DisplayPath = "-..." . substr($ClassPath, $offset,$DialogWidth-6);
                   2328:      } else {
                   2329:        $DisplayPath = $ClassPath;
                   2330:      }
                   2331:      S_ReadCAPAconfig($ClassPath);
                   2332:   } elsif ($What ==  2 ) {   # run capastat.pl
                   2333:      $Set  = &S_InputSet;
                   2334:      $Sfullpath = $ClassPath . "/records/set" . "$Set" . ".db";
                   2335:      ## print "Running capastat.pl on $Sfullpath\n";
                   2336:      ($Q_cnt,$L_cnt) =  &S_ScanSetDB($Sfullpath);
                   2337:      Percentage_Scores($Set,$L_cnt);
                   2338:      S_Average($Q_cnt,$L_cnt);
                   2339:      
                   2340:      ## Large_Tries($opt_t,$opt_n,$Q_cnt,$L_cnt);
                   2341:   } elsif ($What == 3 ) {   # log analysis on S, U, 
                   2342:      $Set  = &S_InputSet;
                   2343:      
                   2344:      $Lfullpath = $ClassPath . "/records/log" . "$Set" . ".db";
                   2345:      if(-f $Lfullpath) {
                   2346:        print "Log analysis for telnet session log$Set.db\n";
                   2347:        print " This may take a while to calculate, please wait ...\n";
                   2348:        ($Y_l,$N_l,$S_l,$U_l,$u_l) = S_ScanLogDB($Lfullpath);
                   2349:      }
                   2350:      $Wfullpath = $ClassPath . "/records/weblog" . "$Set" . ".db";
                   2351:      if(-f $Wfullpath ) {
                   2352:        print "=" x 79 . "\n";
                   2353:        print "Log analysis for web session weblog$Set.db\n";
                   2354:        print " This may take a while to calculate, please wait ...\n";
                   2355:        ($Y_w,$N_w,$S_w,$U_w,$u_w) = S_ScanLogDB($Wfullpath);
                   2356:      }
                   2357:      $Telnet_total = $Y_l+$N_l+$S_l+$U_l+$u_l;
                   2358:      $Web_total    = $Y_w+$N_w+$S_w+$U_w+$u_w;
                   2359:      
                   2360:      print "============== SUMMARY ====================\n";
                   2361:      print "            #Y     #N     #S     #U     #u    Total\n";
                   2362:      printf  "telnet: %6d %6d %6d %6d %6d   %6d\n", $Y_l, $N_l, $S_l, $U_l, $u_l,$Telnet_total;
                   2363:      printf  "   web: %6d %6d %6d %6d %6d   %6d\n", $Y_w, $N_w, $S_w, $U_w, $u_w,$Web_total;
                   2364:      $Y_sum = $Y_l + $Y_w;
                   2365:      $Ratio_Y = 100.0 * ($Y_w / $Y_sum) if $Y_sum > 0;
                   2366:      $N_sum = $N_l + $N_w;
                   2367:      $Ratio_N = 100.0 * ($N_w / $N_sum) if $N_sum > 0;
                   2368:      $S_sum = $S_l + $S_w;
                   2369:      $Ratio_S = 100.0 * ($S_w / $S_sum) if $S_sum > 0;
                   2370:      $U_sum = $U_l + $U_w;
                   2371:      $Ratio_U = 100.0 * ($U_w / $U_sum) if $U_sum > 0;
                   2372:      $u_sum = $u_l + $u_w;
                   2373:      $Ratio_u = 100.0 * ($u_w / $u_sum) if $u_sum > 0;
                   2374:      $overall_entries = $Telnet_total+$Web_total;
                   2375:      $Ratio_web = 100.0*($Web_total/$overall_entries) if $overall_entries > 0;
                   2376:      printf  "  %%web: % 6.1f % 6.1f % 6.1f % 6.1f % 6.1f   % 6.1f\n", 
                   2377:        $Ratio_Y, $Ratio_N, $Ratio_S, $Ratio_U, $Ratio_u, $Ratio_web;
                   2378:      printf "Press RETURN to continue"; $tmp = <>;
                   2379:      
                   2380:   } elsif ($What ==  4 ) {   # Student course profile
                   2381:     # select either use student name or student number
                   2382:     # if there are more than two students, display them in a table to select
                   2383:     #    by the user
                   2384:     # use student id to find the scores
                   2385:     # display set scores in each class, regular class goes first.
                   2386:     # S_InputStudent;
                   2387:     ($s_id,$s_nm) = S_InputStudent($ClassPath);
                   2388:     if($s_id ne "" ) {
                   2389:       print "$s_nm\n";
                   2390:       &S_CollectSetScores($ClassPath,"$s_id",1,$homework_scores_limit_set);
                   2391:       &S_CollectSetScores($QuizPath,"$s_id",1,$quiz_scores_limit_set)   if -d "$QuizPath";
                   2392:       &S_CollectSetScores($ExamPath,"$s_id",1,$exam_scores_limit_set)   if -d "$ExamPath";
                   2393:       &S_CollectSetScores($SuppPath,"$s_id",1,$supp_scores_limit_set)   if -d "$SuppPath";
                   2394:       &S_CollectSetScores($OthersPath,"$s_id",1,$others_scores_limit_set) if -d "$OthersPath";
                   2395:       
                   2396:       
                   2397:       print "\nEnter Y or <RETURN> for Login analysis (may take a while)\n";
                   2398:       print "Enter N => return to main menu: ";
                   2399:       $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2400:       $go_on = 0;
                   2401:       $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2402:       
                   2403:       if($go_on) {
                   2404:         # $homework_scores_limit_set comes from capa.config
                   2405:         &S_LoginAnalysis($ClassPath,"$s_id",$homework_scores_limit_set);
                   2406:         &S_StudentSetAnalysis($ClassPath,"$s_id",$homework_scores_limit_set);
                   2407:       }
                   2408:       
                   2409:     }
                   2410:   } elsif ($What ==  5 ) {   # CAPA IDs for one student
                   2411:     ($s_id,$s_nm) = S_InputStudent($ClassPath);
                   2412:     if($s_id ne "" ) {
                   2413:       $go_on = 0;
                   2414:       print "$s_nm, $Allcapaid\n";
                   2415:       ($S_from, $S_to) = S_EnterSets;
                   2416:       
                   2417:       print "\nCMD: $AllcapaidCMD -i -stu $s_id -s $S_from -e $S_to\n";
                   2418:       print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2419:       $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2420:       $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2421:       if( $go_on ) {
                   2422:         open(IN,"$AllcapaidCMD -i -stu $s_id -s $S_from -e $S_to -c $ClassPath|");
                   2423:         while($input_line = <IN>) {
                   2424:           print "$input_line";
                   2425:         }
                   2426:         close(IN);
                   2427:         printf "Press RETURN to continue"; $tmp = <>;
                   2428:       }
                   2429:     }
                   2430:   } elsif ($What ==  6 ) {   # All CAPA IDs
                   2431:      $go_on = 0;
                   2432:      ($S_from, $S_to) = S_EnterSets;
                   2433:      print "\nCMD: $AllcapaidCMD -s $S_from -e $S_to\n";
                   2434:      print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2435:      $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2436:      $go_on = 1 if $tmp =~ /^Y/ || $tmp eq "\n";
                   2437:      if( $go_on ) { 
                   2438:        open(IN,"$AllcapaidCMD -s $S_from -e $S_to -c $ClassPath|");
                   2439:        while($input_line = <IN>) {
                   2440:          print "$input_line";
                   2441:        }
                   2442:        close(IN);
                   2443:        print "Press RETURN to continue"; $tmp = <>;
                   2444:      }
                   2445:      
                   2446:   } elsif ($What ==  7 ) {   # Item analysis
                   2447:      $u_path = C_MultipleChoice(4,10,$DialogWidth,"Select a Class path","",@MainPath);
                   2448:      
                   2449:      $Set  = &S_InputSet;
                   2450:      print "Item analysis for $MainPath[$u_path-1], Set $Set\n";
                   2451:      print "This may take a while to calculate, please wait ...\n";
                   2452:      S_ItemAnalysis($MainPath[$u_path-1],$Set);
                   2453:   } elsif ($What ==  8 ) {   # Correlation chart
                   2454:   ## TO DO:
                   2455:   ##         Let user specify how many categories to calculate correlation
                   2456:   ##             For each category, the user can specify problem numbers to 
                   2457:   ##             be in that category
                   2458:   ##         Then, the correlations between each category is calculated
                   2459:   ##
                   2460:      $u_path = C_MultipleChoice(4,10,$DialogWidth,"Select a Class path","",@MainPath);
                   2461:      $Set  = &S_InputSet;
                   2462:      print "Correlation calculation for $MainPath[$u_path-1], Set $Set\n";
                   2463:      print "This may take a while to calculate, please wait ...\n";
                   2464:      S_SetCorrelationStatistics($MainPath[$u_path-1],$Set);
                   2465:   } elsif ($What ==  9 ) {   # E-Mail
                   2466:      $done_email = 0;
                   2467:      while(! $done_email ) {
                   2468:        $select = C_MultipleChoice(2,10,$DialogWidth+15,"    CAPA E-mail facilities       ",
                   2469:                           "$DisplayPath",@Email_menu);
                   2470:       if($select == 1 ) {  # Create scores file
                   2471:         # the variable $Master_scoresFile comes from capa.config entry master_scores_file = ...
                   2472:         print "Create a file containing scores of all students:\n";
                   2473:         print " $Master_scoresFile\n";
                   2474:         print "This may take a while to complete, please wait ...\n";
                   2475:         S_CreateScores("$Master_scoresFile");
                   2476:       } elsif ($select == 2 ) { # create all e-mail files in Mail/ dir
                   2477:         print "Create e-mail files in $ClassPath/Mail/ directory\n";
                   2478:         print " based on scores file $Master_scoresFile\n";
                   2479:         print "This action will REPLACE the original file(s) in the Mail/ directory!\n";
                   2480:         $go_on = 0;
                   2481:         print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2482:         $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2483:         $go_on = 1 if $tmp =~ /^Y/ || $tmp eq "\n";
                   2484:         if( $go_on ) {
                   2485:           print "This may take a while to complete, please wait ...\n";
                   2486:         
                   2487:           S_CreateEmails("$Master_scoresFile");
                   2488:         }
                   2489:       } elsif ($select == 3 ) { # Preview e-mail
                   2490:        # randomly pick a student 
                   2491:        # 
                   2492:        &S_RandomlyPreview;
                   2493:        
                   2494:       } elsif ($select == 4 ) { # Send e-mail to a group of students
                   2495:        $entered_cat = &S_EnterCategory;
                   2496:        
                   2497:        $go_on = 0;
                   2498:        print "Entered category: $entered_cat\n";
                   2499:        print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2500:        $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2501:        $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2502:        
                   2503:        if( $go_on ) {
                   2504:          S_MailtoCategory($entered_cat);
                   2505:        }
                   2506:          
                   2507:       
                   2508:        # 1. Whole class
                   2509:        # 2. Category ---> specify 1, 2, 3, or 4
                   2510:       } else { # 4. Cancel
                   2511:          $done_email = 1;
                   2512:       }
                   2513:     }
                   2514:   } elsif ($What == 10 ) {  # Print one assignment for a student
                   2515:     ($s_id,$s_nm) = S_InputStudent($ClassPath);
                   2516:     if($s_id ne "" ) {   # non-empty student id
                   2517:       $s_id = uc($s_id); # uppercase
                   2518:       
                   2519:       ## $Set  = &S_InputSet;
                   2520:       ($From_set,$To_set) = &S_EnterSets;
                   2521:       print "Printing Set(s) $From_set to $To_set for STUDENT: $s_nm\n";
                   2522:       $go_on = 0;
                   2523:       print "\nEnter Y or <RETURN> to continue or N to cancel the operation: ";
                   2524:       $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2525:       $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2526:       
                   2527:       if($go_on) {
                   2528:         $go_on = 0;
                   2529:         print "CMD: $QzparseCMD -c $ClassPath -set $From_set:$To_set -stu $s_id\n";
                   2530:         open(IN,"$QzparseCMD -c $ClassPath -set $From_set:$To_set -stu $s_id|");
                   2531:         while($input_line = <IN>) {
                   2532:           print "$input_line";
                   2533:         }
                   2534:         close(IN);
                   2535:         print "=" x 70 . "\n";
                   2536:         $tex_file = "$ClassPath" . "/TeX/" . "$s_id" . ".tex";
                   2537:         print "CMD: $LatexCMD $tex_file\n";
                   2538:         print "Enter Y or <RETURN> to continue or N to cancel the operation: ";
                   2539:         $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2540:         $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2541:         
                   2542:       }
                   2543:       # run qzparse on the student and the set
                   2544:       #     qzparse -c $path -set $set -stu $s_id
                   2545:       if( $go_on ) { # run latex on the .tex file, latex will create a .dvi file in cwd()
                   2546:         $dir = cwd();
                   2547:         $go_on = 0;
                   2548:         
                   2549:         open(IN,"$LatexCMD $tex_file|");
                   2550:         while($input_line = <IN>) {
                   2551:           print "$input_line";
                   2552:         }
                   2553:         close(IN);
                   2554:         $cwd_dvi_file     = "$dir/" . "$s_id" . ".dvi";
                   2555:         $dvi_file = "$ClassPath" . "/TeX/" . "$s_id" . ".dvi";
                   2556:         $cmd = "mv $cwd_dvi_file $dvi_file";
                   2557:         system($cmd);
                   2558:         print "=" x 70 . "\n";
                   2559:         $ps_file  = "$ClassPath" . "/TeX/" . "$s_id" . ".ps";
                   2560:         print "CMD: $DvipsCMD $dvi_file -o $ps_file\n";
                   2561:         print "\nEnter Y or <RETURN> to continue or N to cancel the operation: ";
                   2562:         $tmp=<>; $tmp =~ tr/A-Z/a-z/;
                   2563:         $go_on = 1 if $tmp =~ /^y/ || $tmp eq "\n";
                   2564:       }
                   2565:       if( $go_on ) {  # run dvips on the .dvi file
                   2566:         
                   2567: 
                   2568:         open(IN,"$DvipsCMD $dvi_file -o $ps_file|");
                   2569:         while($input_line = <IN>) {
                   2570:           print "$input_line";
                   2571:         }
                   2572:         close(IN);
                   2573:         print "=" x 70 . "\n";
                   2574:         
                   2575:         S_LPRFile($ps_file);
                   2576:         
                   2577:       }
                   2578:     }
                   2579:   
                   2580:   } elsif ($What == 11 ) {  # view score file
                   2581:     $entered_key = S_EnterSortKey;
                   2582:     
                   2583:     $display_key = $entered_key;
                   2584:     $display_key =~ s/,/, /g;
                   2585:     $display_key =~ s/1/Grade/g;
                   2586:     $display_key =~ s/2/Student number/g;
                   2587:     $display_key =~ s/3/Student name/g;
                   2588:     $display_key =~ s/4/Section/g;
                   2589:     print "Entered sorting key: $display_key\n";
                   2590:     $go_on = 0;
                   2591:     while(! $go_on) {
                   2592:       print "Enter 1 for ascending or 2 for decending order (RETURN = 1 ascending): ";
                   2593:       $tmp=<>; 
                   2594:       if( ($tmp == 1) || ($tmp == 2) || ($tmp eq "\n") ) {
                   2595:             $tmp = 1 if $tmp eq "\n";
                   2596:             $go_on = 1;
                   2597:       }
                   2598:     }
                   2599:     
                   2600:     S_DisplayScoreFile($entered_key,$tmp,$Master_scoresFile);
                   2601:     print "Finish displaying score file. Press RETURN to continue"; $tmp = <>;
                   2602:   } elsif ($What == 12 ) {  # list student responses
                   2603:     ($s_id,$s_nm) = S_InputStudent($ClassPath);
                   2604:     if($s_id ne "" ) {
                   2605:       $go_on = 0;
                   2606:       print "$s_nm, grepping submissions\n";
                   2607:       ($S_from, $S_to) = S_EnterSets;
                   2608:       for( $i=$S_from;$i<=$S_to;$i++) {
                   2609: 	print "Telnet Submissions for $s_nm for set $i\n";
                   2610: 	open(IN,"grep -i $s_id $ClassPath/records/submissions$i.db |"); 
                   2611: 	while($input_line = <IN>) {
                   2612: 	  print "$input_line";
                   2613: 	}
                   2614: 	close(IN);
                   2615: 	printf "Press RETURN to continue"; $tmp = <>;
                   2616: 	print "WWW Submissions for $s_nm for set $i\n";
                   2617: 	open(IN,"grep -i $s_id $ClassPath/records/websubmissions$i.db|"); 
                   2618: 	while($input_line = <IN>) {
                   2619: 	  print "$input_line";
                   2620: 	}
                   2621: 	close(IN);
                   2622: 	printf "Press RETURN to continue"; $tmp = <>;
                   2623:       }
                   2624:     }
                   2625:   } elsif ($What == 13 ) {  # quit
                   2626:     $Quit = 1;
                   2627:   }
                   2628: }
                   2629: 
                   2630: 
                   2631: 
                   2632: 

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