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