File:  [LON-CAPA] / capa / capa51 / CapaTools / capautils.1.1.pl
Revision 1.1: download - view: text, annotated - select for diffs
Tue Sep 28 21:25:35 1999 UTC (24 years, 10 months ago) by albertel
Branches: MAIN
CVS tags: HEAD
Initial revision

    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>