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