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

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

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