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

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

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