#!/usr/bin/perl # # Source File: likert_wall_106.pl # # use strict; # Get config require 'sitecfg.pl'; require 'testlib.pl'; require 'tstatlib.pl'; require 'questionslib.pl'; use Data::Dumper; require bargraph_multi ; use vars qw(%FORM %SESSION %CLIENT %TEST_SESSION %SUBTEST_QUESTIONS %TEST %SUBTEST_SUMMARY %CANDIDATE %SUBTEST_ANSWERS %SYSTEM %REPORT %GRPFIELD %SUBTEST_RESPONSES @xlatphrase); use vars qw($testcomplete $cgiroot $pathsep $dataroot @rptparams ); use vars qw($testinprog $testpending) ; my $last_index, $HBI_Debug ; $HBI_Debug = 0 ; # Controls output of Debugging Data. my $HBI_Debug_Sample_Numbers = 0 ; $FORM{'frm'}=""; my %Month_Full = ("Jan" => "January", "Feb" => "February", "Mar" => "March", "Apr" => "April", "May" => "May", "Jun" => "June", "Jul" => "July", "Aug" => "August", "Sep" => "September", "Oct" => "October", "Nov" => "November", "Dec" => "December") ; &app_initialize; if ($HBI_Debug) {warn "INFO: " . __FILE__ . " running frm IS $FORM{'frm'} " ;} # Frames # Row-Col-Name -frm- Description and new data field(s) # * - * - - 0 - Display blank frame. # 1 - 1 - rptindx003 - 1 - Pick Candidate - FORM{'cndid'} # 2 - 1 - rpttidx003 - 2 - Pick first Test ID - FORM{'tstid', 'multiple'} # 2 - 2 - rptdtl003 - 3 - Pick Execution date of first test - ? # 3 - 1 - rpttidx004 - 4 - Pick follow up Test ID - ? # 3 - 2 - rptdtl004 - 5 - Pick Execution date of follow up test - ? # X - X - XXXXXXXXX - 6 - Print Automated Report - None # frm == 6 code will print all Content info, # and pick its own content type. unless ($FORM{'frm'} == '6') { print "Content-Type: text/html\n\n"; $bDisplay = 1; } # LIKERT Scale Test Reports by Candidate if (&get_session($FORM{'tid'})) { &LanguageSupportInit(); $REPORT{'rptid'}=""; @rptdefs = &get_data("reports.$SESSION{'clid'}"); @lbls = split(/&/, $rptdefs[0]); foreach $rptdef (@rptdefs) { chomp ($rptdef); @flds = split(/&/, $rptdef); if ($flds[0] eq $FORM{'rptno'}) { for $i (0 .. $#lbls) { $REPORT{$lbls[$i]} = $flds[$i]; $i++; } } } if ($FORM{'frm'} == '1') { &show_index_candidates; } elsif ($FORM{'frm'} == '2') { &show_index_tests; } elsif ($FORM{'frm'} == '3') { &show_filter_options; } elsif ($FORM{'frm'} == '4') { &show_2nd_index_tests ; } elsif ($FORM{'frm'} == '5') { &show_2nd_filter_options; } elsif ($FORM{'frm'} == '6') { &show_detail; } else { print "\n"; # Most likely, this is frm == 0 print "\n"; print " \n"; print "\n"; } } else { warn __FILE__ . " running without a SESSION." ; &show_illegal_access_warning() ; } # ($FORM{'frm'} == '1') sub show_index_candidates { # This shows all of the candidates, even if they have not completed a relevant test. &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Exec Report $FORM{'rptno'}"); &get_client_profile($SESSION{'clid'}); print " $REPORT{'rptid'} - $REPORT{'rptdesc'}
$REPORT{'rptid'} - $REPORT{'rptdesc'}
"; my @clrecs = &get_client_cnd_list($CLIENT{'clid'}); my @clnamesort=(); my @clidsort=(); my $namesort; my $idsort; my $mycreator; my $imaregistrar = &get_a_key("cnd.$SESSION{'clid'}", $SESSION{'uid'}, "registrar"); for (1 .. $#clrecs) { $clrecs[$_] =~ s/\n//g; @cndrecs = split(/&/, $clrecs[$_]); $id = $cndrecs[0]; $nmf = $cndrecs[3]; $nmm = $cndrecs[4]; $nml = $cndrecs[5]; $mycreator = $cndrecs[15]; unless (($id eq '') || ($nml eq '')) { $namesort=join('&',$nml,$nmf,$nmm,$id); if ($imaregistrar eq 'Y') { if ($SESSION{'uid'} eq $mycreator) { push @clnamesort, $namesort; } } else { push @clnamesort, $namesort; } } } @clrecs = sort @clnamesort; @clnamesort=(); print "Name:\n"; @clrecs = sort @clidsort; @clidsort=(); print "\ ID:\n"; @clrecs=(); print "
"; } # ($FORM{'frm'} == '2') sub show_index_tests { &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Exec Report $FORM{'rptno'}"); &get_client_profile($SESSION{'clid'}); &get_candidate_profile( $SESSION{'clid'}, $FORM{'cndid'}); my $style = "SELECT {\"width: 200px;height: 200px;font-size: 8pt;\"}"; print " $REPORT{'rptid'} - $REPORT{'rptdesc'}
$CANDIDATE{'nml'}, $CANDIDATE{'nmf'} $CANDIDATE{'nmm'}
"; my @trecs = &get_test_list($CLIENT{'clid'}); my @tmptrecs = (); for (1 .. $#trecs) { ($id, $desc) = split(/&/, $trecs[$_]); $trecs[$_] = join('&', "$desc", "$id"); push @tmptrecs, $trecs[$_]; } @trecs = sort @tmptrecs; print "\t\t
"; &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "3", "Exec Report $FORM{'rptno'} completed"); } # ($FORM{'frm'} == '3') sub show_filter_options { my $cndid; my $cndname; my @testdates; my $iopt; my $optval; my $optdesc; my $lstdates; my $qcor; my $qinc; my $tscore; my $trash; my $j; my $i; my @tests; my @tmpdates; my $jscript; my $colspan; &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Report Options $FORM{'rptno'}"); &get_client_profile($SESSION{'clid'}); &get_candidate_profile( $SESSION{'clid'}, $FORM{'cndid'}); @tests = split(/\,/,$FORM{'tstid'}); $cndname = join('', $CANDIDATE{'nml'}, ", ", $CANDIDATE{'nmf'}, " ", $CANDIDATE{'nmm'}); $cndid = $CANDIDATE{'uid'}; $lstdates = "\n"); $styles = "SELECT {\"font-size: 8pt;\"}\n"; $styles = join('',$styles,"INPUT {\"font-size: 8pt;height: 20px;\"}\n"); print " $REPORT{'rptid'} - $REPORT{'rptdesc'}
$testdescriptions
"; if ($TEST{'seq'} eq 'std') { print " "; $colspan="colspan=2"; } else { print " "; $colspan=""; } print "
$xlatphrase[687]
$lstdates
$xlatphrase[687]
$lstdates
"; $testspending = CountTestFilesByCnd($testpending, $CLIENT{'clid'},$id,$FORM{'cndid'}); if ($testspending > 0) { print " Print\ \; Master/Key"; } print "\ 

"; } # ($FORM{'frm'} == '4') sub show_2nd_index_tests { &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Exec Report $FORM{'rptno'}"); &get_client_profile($SESSION{'clid'}); &get_candidate_profile( $SESSION{'clid'}, $FORM{'cndid'}); my $style = "SELECT {\"width: 200px;height: 200px;font-size: 8pt;\"}"; print " $REPORT{'rptid'} - $REPORT{'rptdesc'}
$CANDIDATE{'nml'}, $CANDIDATE{'nmf'} $CANDIDATE{'nmm'}
"; my @trecs = &get_test_list($CLIENT{'clid'}); my @tmptrecs = (); for (1 .. $#trecs) { ($id, $desc) = split(/&/, $trecs[$_]); $trecs[$_] = join('&', "$desc", "$id"); push @tmptrecs, $trecs[$_]; } @trecs = sort @tmptrecs; print "\t\t
"; &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "3", "Exec Report $FORM{'rptno'} completed"); } # ($FORM{'frm'} == '5') sub show_2nd_filter_options { my $cndid; my $cndname; my @testdates; my $iopt; my $optval; my $optdesc; my $lstdates; my $qcor; my $qinc; my $tscore; my $trash; my $j; my $i; my @tests; my @tmpdates; my $jscript; my $colspan; &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Report Options $FORM{'rptno'}"); &get_client_profile($SESSION{'clid'}); &get_candidate_profile( $SESSION{'clid'}, $FORM{'cndid'}); @tests = split(/\,/,$FORM{'tstid2'}); $cndname = join('', $CANDIDATE{'nml'}, ", ", $CANDIDATE{'nmf'}, " ", $CANDIDATE{'nmm'}); $cndid = $CANDIDATE{'uid'}; $lstdates = "\n"); $styles = "SELECT {\"font-size: 8pt;\"}\n"; $styles = join('',$styles,"INPUT {\"font-size: 8pt;height: 20px;\"}\n"); print " $REPORT{'rptid'} - $REPORT{'rptdesc'}
$testdescriptions
"; if ($TEST{'seq'} eq 'std') { print " "; $colspan="colspan=2"; } else { print " "; $colspan=""; } print "
$xlatphrase[687]
$lstdates
$xlatphrase[687]
$lstdates
"; $testspending = CountTestFilesByCnd($testpending, $CLIENT{'clid'},$id,$FORM{'cndid'}); if ($testspending > 0) { print " Print\ \; Master/Key"; } print "\ 

"; } # elsif ($FORM{'frm'} == '6') sub show_detail { my @tentries; my @tcols; my $i; my $j; my $k; my $loidx; my $hiidx; my $loscore; my $hiscore; my $avgscore; my $avgcount; my @testdates; my @found; my $sgrepfor; my $bDisplay; my $timetaken; my $testtitle; my $tstdate; my $testid; my @tmparray; my @tmpdates; my $RTF_PNG_Begin ; my $RTF_PNG_Close ; &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "2", "Exec Report $FORM{'rptno'}"); if ($HBI_Debug) { print "Content-Type: text/html\n\n"; print "\\n" ; print "\\SESSION HASH ARRAY\\n" ; foreach $key (sort keys (%SESSION)) { print "KEY $key VAL $SESSION{$key}\\n" ; } print "\\FORM HASH ARRAY\\n" ; foreach $key (sort keys (%FORM)) { print "KEY $key VAL $FORM{$key}\\n" ; } print "\Dumper of \$FORM\{idlist\} " ; print Dumper($FORM{'idlist'}) ; print "\\\n" ; my $lookatit = $FORM{'idlist'} ; $lookatit =~ tr/\000/,/ ; print Dumper($lookatit) ; print "\\\n" ; } unless ($SESSION{'clid'}) { warn "No Client ID in the session.\n" ; warn "Client ID in the FORM is $FORM{'clid'}\n" ; unless ($HBI_Debug) { print "Content-Type: text/html\n\n"; &show_illegal_access_warning() ; exit 0 ; } print "No Client ID in the session.\n" ; print "\\n" ; print "\n"; print "\n"; exit 0 ; } &get_client_profile($SESSION{'clid'}); # populates the Assoc. array %CLIENT with data for the client id. if ($HBI_Debug) { print "\\CLIENT HASH ARRAY\\n" ; foreach $key (sort keys (%CLIENT)) { print "KEY $key VAL $CLIENT{$key}\\n" ; } } unless ($FORM{'cndid'}) { warn "No Candidate ID in the form.\n" ; unless ($HBI_Debug) { print "Content-Type: text/html\n\n"; &show_illegal_access_warning() ; exit 0 ; } print "No Candidate ID in the form.\n" ; print "\\n" ; print "\n"; print "\n"; exit 0 ; } &get_candidate_profile( $SESSION{'clid'}, $FORM{'cndid'}); $CANDIDATE{'full_name'} = $CANDIDATE{'nmf'} . " " ; $CANDIDATE{'full_name'} .= $CANDIDATE{'nmm'} . ". " if ($CANDIDATE{'nmm'}) ; $CANDIDATE{'full_name'} .= $CANDIDATE{'nml'} ; $CANDIDATE{'File_Name'} = $CANDIDATE{'full_name'} ; # warn "INFO: full name is X$CANDIDATE{'full_name'}X\n" ; $CANDIDATE{'full_name'} = &RTFize($CANDIDATE{'full_name'}) ; # warn "INFO: full name is X$CANDIDATE{'full_name'}X\n" ; if ($HBI_Debug) { print "\\CANDIDATE HASH ARRAY\\n" ; foreach $key (sort keys (%CANDIDATE)) { print "KEY $key VAL $CANDIDATE{$key}\\n" ; } } # populates the Assoc. array %CANDIDATE with data for the candidate/user/student who took the test/survey. # HBI - Go find the format of the test results. # The original code supported multiple selected tests. # This report does not support multiple tests. unless ($CLIENT{'clid'}) { warn "No Client ID in the CLIENT data.\n" ; print "No Client ID in the CLIENT data.\n" ; print "\\n" ; exit 0 ; } unless ($FORM{'tstid'}) { warn "No Test ID in the form.\n" ; print "No Test ID in the form.\n" ; print "\\n" ; exit 0 ; } unless ($FORM{'tstid2'}) { warn "No Follow Up related Test ID in the form.\n" ; print "No Follow Up related Test ID in the form.\n" ; print "\\n" ; exit 0 ; } &get_test_profile($CLIENT{'clid'}, $FORM{'tstid'}); # populates the Assoc. array %TEST with the characteristics of the test (but not the questions or answers). unless ($FORM{'cndid'}) { warn "No Candidate ID in the form.\n" ; print "No Candidate ID in the form.\n" ; print "\\n" ; exit 0 ; } $foo = &get_test_sequence_for_reports($CLIENT{'clid'},$FORM{'cndid'}, $FORM{'tstid'}); # populates the Assoc. arrays %TEST_SESSION, %SUBTEST_QUESTIONS, %SUBTEST_ANSWERS, %SUBTEST_RESPONSES, # and %SUBTEST_SUMMARY. # Alternate ??? # $foo = &get_test_sequence_from_history($CLIENT{'clid'},$FORM{'cndid'}, $FORM{'tstid'},$FORM{'tdatesel'}); if ($HBI_Debug) { print "\\SYSTEM HASH ARRAY\\n" ; foreach $key (sort keys (%SYSTEM)) { print "KEY $key VAL $SYSTEM{$key}\\n" ; } print "\\CLIENT HASH ARRAY\\n" ; foreach $key (sort keys (%CLIENT)) { print "KEY $key VAL $CLIENT{$key}\\n" ; } print "\\TEST HASH ARRAY\\n" ; foreach $key (sort keys (%TEST)) { print "KEY $key VAL $TEST{$key}\\n" ; } print "\\TEST_SESSION HASH ARRAY\\n" ; foreach $key (sort keys (%TEST_SESSION)) { print "KEY $key VAL $TEST_SESSION{$key}\\n" ; } print "\\SUBTEST_QUESTIONS HASH ARRAY\\n" ; foreach $key (sort keys (%SUBTEST_QUESTIONS)) { print "KEY $key VAL $SUBTEST_QUESTIONS{$key}\\n" ; } print "\\SUBTEST_ANSWERS HASH ARRAY\\n" ; foreach $key (sort keys (%SUBTEST_ANSWERS)) { print "KEY $key VAL $SUBTEST_ANSWERS{$key}\\n" ; } print "\\SUBTEST_RESPONSES HASH ARRAY\\n" ; foreach $key (sort keys (%SUBTEST_RESPONSES)) { print "KEY $key VAL $SUBTEST_RESPONSES{$key}\\n" ; } print "\\SUBTEST_SUMMARY XXX HASH ARRAY\\n" ; foreach $key (sort keys (%SUBTEST_SUMMARY)) { print "KEY $key VAL $SUBTEST_SUMMARY{$key}\\n" ; } } # end of if $HBI_Debug my %supercat_total = () ; # Total points available for a category. my %supercat_earned = () ; # Points earned for a category. my %TGWall_Comments = () ; # Collected Text for questions and comments in a category. my %TGWall_Comments_fnd = () ; # Collected Text for questions and comments in a category. # The following values have a similar name, and are logically connected. my $SUPERCAT_TOTAL = 0 ; # Total points available in all categories. my $SUPERCAT_EARNED = 0 ; # Total points earned in all categories. my $points, $weight, @scores, @correct_ans, @incorrect_ans, @all_ans ; my $ques_type, $supercat, $scores, @responses, $responses ; my @individ, $individ, @img_labels, @img_data , @Response_parts; my $client = $SESSION{'clid'} ; my $testid = $FORM{'tstid'} ; my $candidate = $FORM{'cndid'} ; my $testid2 = $FORM{'tstid2'} ; my $PreSeminarTestDate = $FORM{'tdatesel'} ; my $PostSeminarTestDate = $FORM{'tdatesel2'} ; $SYSTEM{'FeedBackDate'} = "Date UNK" ; $FeedBackDateTime = $PostSeminarTestDate ; # Get the feed back date. if ($FeedBackDateTime) { my $date_ascii = gmtime($FeedBackDateTime) ; chomp $date_ascii ; my @date_parts = split (/ +/, $date_ascii) ; my $mon_name = $date_parts[1] ; if (exists $Month_Full{$mon_name}) { $mon_name = $Month_Full{$mon_name} ; } else { warn "ERROR: Did not find full month name for $mon_name.\n" ; } my $year = $date_parts[4] ; $SYSTEM{'FeedBackDate'} = $mon_name . " " . $year ; } else { warn "ERROR: FeedBackDateTime is unknown. Field in Automated Report is bogus." ; } # Get the current year for the copyright. my $date_ascii = localtime ; chomp $date_ascii ; my @date_parts = split (/ +/, $date_ascii) ; $SYSTEM{'CopyRightYear'} = $date_parts[4] ; my ($ret1, $ret2) ; ($ret1, $QUESTIONS_AH) = &GetLikertData_from_preloaded_Globals($SESSION{'clid'}, $FORM{'tstid'}, 1 ) ; &get_test_profile($CLIENT{'clid'}, $FORM{'tstid2'}); # populates the Assoc. array %TEST with the characteristics of the test (but not the questions or answers). $foo = &get_test_sequence_for_reports($CLIENT{'clid'},$FORM{'cndid'}, $FORM{'tstid2'}); # populates the Assoc. arrays %TEST_SESSION, %SUBTEST_QUESTIONS, %SUBTEST_ANSWERS, %SUBTEST_RESPONSES, # and %SUBTEST_SUMMARY. # Alternate ??? # $foo = &get_test_sequence_from_history($CLIENT{'clid'},$FORM{'cndid'}, $FORM{'tstid'},$FORM{'tdatesel'}); ($ret2, $QUESTIONS_AG) = &GetLikertData_from_preloaded_Globals($SESSION{'clid'}, $FORM{'tstid2'}, 1 ) ; # # Build a bar chart for Candidates self evaluation vs the groups evaluation. # my $HBI_Debug_Graph_Data = 0 ; my $Data1 = [] ; # The data for the chart. my $Category_ARef = [] ; my $category ; my $Legend1 = [] ; # The legends for the chart. # load the labels for the x-axis. # Now we are going to format the date the test was taken. <%=FORM.tdatesel%> # Original text is like 05-Jul-2013_19:37:35_GMT my $given_date_str = $FORM{'tdatesel'} ; my $new_fmt_date ; my ($day_month, $month_str, $cent_year) ; if ($given_date_str =~ m/^(\d+)\-([^\-]+)\-(\d+)/ ) { $day_month = $1 ; $month_str = $2 ; $cent_year = $3 ; $month_str = $Month_Full{$month_str} if ($Month_Full{$month_str}) ; $FORM{'tdatesel'} = &RTFize("$month_str $day_month, $cent_year") ; } $SYSTEM{'FeedBackDate'} = &RTFize($SYSTEM{'FeedBackDate'}) ; if ($HBI_Debug) { print "\\n" ; print "full name\\n" ; print $CANDIDATE{'full_name'} ; print "\\n" ; print "Test Date\\n" ; print $FORM{'tdatesel'} ; print "\\n" ; print "FeedBack Date\\n" ; print $SYSTEM{'FeedBackDate'} ; print "\\n" ; print "Graphic Text\\n" ; print $SYSTEM{'Graphic_Text'} ; print "\\n" ; print "Comments\\n" ; print $SYSTEM{'ALL_Comments'} ; print "\\n" ; print "SYSTEM First Barchart\\n" ; print $SYSTEM{'Bargraph1'} ; print "\\n" ; print "SYSTEM Second Barchart\\n" ; print $SYSTEM{'Bargraph2'} ; print "\\n" ; print "\n"; print "\n"; exit 0 ; } &log_entry($SESSION{'clid'}, $SESSION{'uid'}, "3", "Exec Report $FORM{'rptno'} completed"); $OUTPUT_Format = "RTF" ; print "Content-Type: text/rtf\n" ; my $FName = $CANDIDATE{'File_Name'} ; $FName =~ s/\W/_/g ; print "Content-Disposition: attachment;filename=${FName}_360_report.rtf\n\n"; &show_template("TGWall_KPSS_Follow_Up_Report.rtf") ; $OUTPUT_Format = "HTML" ; } ################################################################################ # # Subroutine Name # GetTestHeader # # Description # This subroutine returns the header of the test file # # Inputs # $clientId -- The id of the client to search through # # Outputs # None # # Returns # @testFields -- An array of fields in the header # #adt080401############################################################################### sub GetTestHeader { my $clientId = $_[0]; my @testList = &get_data("tests.$clientId"); my $testHdr = $testList[0]; my $testFields; chop( $testHdr ); @testFields = split( /&/, $testHdr ); return @testFields; } #adt080401############################################################################### # # Subroutine Name # GetTestsByOwner # # Description # This subroutine searches through the test definition file of the given # client for all the tests that are owned by the given user id or are public # # Inputs # $clientId -- The id of the client to search through # $ownedBy -- The name of the owner of the test to search for # # Outputs # None # # Returns # @tests -- An array of tests owned by the given user id # ################################################################################ sub GetTestsByOwner { my $clientId = $_[0]; my $ownedBy = $_[1]; my %currHash; my @testList = &get_data("tests.$clientId"); my @currField; my @tests; my $testHdr = $testList[0]; my $testFields; my $testCntr; @testFields = &GetTestHeader( $clientId ); for( $testCntr = 1; $testCntr < $#testList; $testCntr++ ) { #print "$testList[$testCntr]
\n"; chop( $testList[$testCntr] ); @currField = split( '&', $testList[$testCntr] ); for( 0 .. $#testFields ) { $currHash{$testFields[$_]} = $currField[$_]; } #print "$currHash{'ownedby'} - $ownedBy

"; if( ( $currHash{'ownedby'} eq $ownedBy ) || ( $currHash{'ownedby'} eq "" ) ) { push( @tests, $testList[$testCntr] ); #print "$testList[$testCntr]
\n"; } } return @tests; } # # Return: Count of test result files in $dir matching regex with $clid # and $testid, OR -1 if there was an error. # sub CountTestFilesByCnd { my ($dir, $clid, $testid, $cndid) = @_; if ( ! defined($dir) ) { &logger::logerr("Undefined directory for client ID '$clid', testid '$testid'"); return -1; } if ( ! defined($clid) ) { &logger::logerr("Undefined client ID for directory '$dir', testid '$testid'"); return -1; } if ( ! defined($testid) ) { &logger::logerr("Undefined test ID for directory '$dir', client ID '$clid'"); return -1; } my $tstcount = scalar(get_matching_files($dir, "^$clid".'\.'."$cndid".'\.'."$testid\$")); return $tstcount; } # # Return: Count of test result files in $dir matching regex with $clid # and $testid, OR -1 if there was an error. # sub CountHistoricTests { my ($dir, $clid, $testid, $cndid) = @_; if ( ! defined($dir) ) { &logger::logerr("Undefined directory for client ID '$clid', testid '$testid'"); return -1; } if ( ! defined($clid) ) { &logger::logerr("Undefined client ID for directory '$dir', testid '$testid'"); return -1; } if ( ! defined($testid) ) { &logger::logerr("Undefined test ID for directory '$dir', client ID '$clid'"); return -1; } my $historyfile = join($pathsep,$dir,"$clid.$testid.history"); open (HISTFILE,"<$historyfile") or return 0; my @histentries = ; close HISTFILE; my $sgrepfor=join('&',"\<\<\>\>$clid","$cndid","$testid",""); my @cndidentries = grep( /$sgrepfor/,@histentries); my $tstcount = $#cndidentries + 1; return $tstcount; } # # Return: Count of cnd result files in $dir matching regex with $clid # and $cndid, OR -1 if there was an error. # sub CountCndFiles { my ($dir, $clid, $cndid) = @_; if ( ! defined($dir) ) { &logger::logerr("Undefined directory for client ID '$clid', cndid '$cndid'"); return -1; } if ( ! defined($clid) ) { &logger::logerr("Undefined client ID for directory '$dir', cndid '$cndid'"); return -1; } if ( ! defined($cndid) ) { &logger::logerr("Undefined cnd ID for directory '$dir', client ID '$clid'"); return -1; } return scalar(get_matching_files($dir, "^$clid".'\.'."$cndid".'\.\S+$')); } # # Return: Sum of times taken during a test in seconds. # sub computeTestTime { my ($dir, $clid, $testid, $cndid, $tstkey) = @_; if ( ! defined($dir) ) { &logger::logerr("Undefined directory for client ID '$clid', testid '$testid'"); return -1; } if ( ! defined($clid) ) { &logger::logerr("Undefined client ID for directory '$dir', testid '$testid'"); return -1; } if ( ! defined($testid) ) { &logger::logerr("Undefined test ID for directory '$dir', client ID '$clid'"); return -1; } my $timefile = join($pathsep,$dir,"$clid.$cndid.$testid.tim"); open (TLOGFILE,"<$timefile") or return 0; my @tlogentries = ; close TLOGFILE; my $sgrepfor="^$tstkey\&(1)\.(2)\.(.*)\&$clid\&$cndid\&$testid\&(.*)"; my @cndidentries = grep( /$sgrepfor/,@tlogentries); @tlogentries = (); my $iidx; my @tentrycols; my $tottime; $tottime = 0; for $iidx (0 .. $#cndidentries) { @tentrycols = split(/&/,$cndidentries[$iidx]); $tottime += $tentrycols[7]; } @tentrycols = (); return $tottime; } sub formatTimeFromSeconds { my ($t, $fmt) = @_; my $h; my $m; my $s; my $r; my $j; $m = int($t/60); $s = $t - ($m * 60); $h = int($m/60); $m = $m - ($h * 60); if ($fmt =~ m/h/i) { $r = "00000$h"; $j=length($r)-2; $r = substr($r,$j,2); $fmt =~ s/h/$r/g; } if ($fmt =~ m/m/i) { $r = "00000$m"; $j=length($r)-2; $r = substr($r,$j,2); $fmt =~ s/m/$r/g; } if ($fmt =~ m/s/i) { $r = "00000$s"; $j=length($r)-2; $r = substr($r,$j,2); $fmt =~ s/s/$r/g; } return $fmt; } # Normally xdim was 400 and ydim was 100. sub BuildBarGraph { # This subroutine builds the HTML to get an image from an URL. # The URL is a cgi-bin PERL script, with several parameters. # The list parameters are: labels, values, and values2. # The scalar parameters are: xdim, ydim, hbar, title, xlabel, ylabel, ymax, ymin, yticknum, colorscheme, $t_margin, $b_margin, $l_margin, $r_margin # The first 3 parameters are references to three lists, which are mandatory. # The values2 list may be an empty list. (and ignored.) # The rest of the parameters are optional, but are order specific. # Any parameter that is an empty string will be effectively ignored, # but may be required to fill the list of parameters to a needed parm. my @label_names, @value_points, @value2_points ; my $labels_ref, $values_ref, $values2_ref ; my $xdim, $ydim, $hbar, $title, $xlabel, $ylabel, $ymax, $ymin, $yticknum ; my $colorscheme ; my $t_margin, $b_margin, $l_margin, $r_margin ; $labels_ref = $_[0] ; @label_names = @{$labels_ref} ; # @label_names is an array of character strings of the names of the bars on the graph. $values_ref = $_[1] ; @value_points = @{$values_ref} ; # @value_points is an array of numeric values for each of the names in the first array. # The sizes of the two arrays should be the same. $values2_ref = $_[2] ; @value2_points = @{$values2_ref} ; shift ; shift ; shift ; # Remove the first 3 parms, to set up the next statement. my ($xdim, $ydim, $hbar, $title, $xlabel, $ylabel, $ymax, $ymin, $yticknum, $colorscheme, $t_margin, $b_margin, $l_margin, $r_margin) = @_ ; my $labels, $values, $values2 ; # print '
label_names ' . "@label_names" . '
' ; # print '
value_points ' . "@value_points" . '
' ; if ($#label_names != $#value_points) { print '
ERROR BuildBarGraph has different number of labels and data values.
' ; } $labels = join (":", map {munge($_)} @label_names ) ; $values = join (":", map {munge($_)} @value_points ) ; $values2 = join (":", map {munge($_)} @value2_points ) ; # my $baseurl = "/cgi-bin/bargraph.pl?labels=$labels&title=Trust%20Level&ylabel=Respondents"; my $baseurl = "/cgi-bin/bargraph.pl?labels=$labels&values=$values" ; if ($xdim or $xdim == 0) { $baseurl .= "&xdim=" . $xdim ; } if ($ydim or $ydim == 0) { $baseurl .= "&ydim=" . $ydim ; } if ($hbar or $hbar == 0) { $baseurl .= "&hbar=" . $hbar ; } if ($title or $title == 0) { $baseurl .= "&title=" . munge( $title) ; } if ($xlabel or $xlabel == 0) { $baseurl .= "&xlabel=" . munge( $xlabel) ; } if ($ylabel or $ylabel == 0) { $baseurl .= "&ylabel=" . munge( $ylabel) ; } if ($ymax or $ymax == 0) { $baseurl .= "&ymax=" . $ymax ; } if ($ymin or $ymin == 0) { $baseurl .= "&ymin=" . $ymin ; } if ($t_margin or $t_margin == 0) { $baseurl .= "&t_margin=" . $t_margin ; } if ($b_margin or $b_margin == 0) { $baseurl .= "&b_margin=" . $b_margin ; } if ($l_margin or $l_margin == 0) { $baseurl .= "&l_margin=" . $l_margin ; } if ($r_margin or $r_margin == 0) { $baseurl .= "&r_margin=" . $r_margin ; } if ($colorscheme) { $baseurl .= "&colorscheme=" . $colorscheme ; } if ($yticknum or $yticknum == 0) { $baseurl .= "&yticknum=" . $yticknum ; } return ""; } ############################################################################ # # Function: munge( $string ) # Description: Do the normal munging to replace non-normal chars with %XX. # Returns: a modified string with %XX patterns inserted # Author: HBI, 2008/09/30 # # The process is performed on strings that are sent as literal text, # as part of an URL to be re-analyzed by a WEB server. The higher # level application must do this once, and only once. This function # assumes that the character string contains only 7 or 8 bit characters. # This function cannot deal with multi-byte UTF-8 characters. # ############################################################################ sub munge( $ ) { my ($string) = @_; $string =~ s/([^a-zA-Z0-9])/join('', '%', uc(unpack("H*",$1)))/eg; return $string; } ############################################################################ # # Function: unmunge( $string ) # Description: Inverse operation of munge(), replace %XX with the real ascii. # Returns: a modified string with %XX patterns replaced # Author: efl, 11/2001 # ############################################################################ sub unmunge( $ ) { my ($string) = @_; $string =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; return $string; } sub HTMLHeader { return "\n\n$_[0]\n". "\n\n". "\n"; } sub HTMLHeaderPlain { return "\n\n$_[0]\n". "\n\n". "\n"; } sub HTMLFooter { my $year = `date +%Y`; my $ionline; if ($ENV{'SERVER_NAME'} =~ "integroonline.com") { $ionline = "
Copyright (c) $year, Integro Learning Company"; } return "

Copyright (c) $year, ACTS Corporation$ionline
\n\n"; } sub get_full_history { # Parameters # $dir # $clientID # $testID # Side Effect # All of the data is placed into the global variable %FULL_HISTORY # Returned Value # $ret - 0 implies failure, 1 implies success. # %FULL_HISTORY format. # Key is the Client ID. # value is an anon. hash. # Its key is the Test ID. # value is an anon. hash. # Its key is the Candidate ID. # value is an anon. hash. # Its key is the time of the test in seconds for the GMT time zone. # value is the raw character string of the data. # To access a single test's data: # $FULL_HISTORY->{$clientID}->{$testID}->{$candidateID}->{$GMTsec} my ($dir,$clientID,$testID) = @_; my $trash = join($pathsep, $dir, "$clientID.$testID.history"); my $HBI_Debug_get_full_history = 0 ; my $Open_state = 1 ; open(TESTFILE, "<$trash") or $Open_state = 0 ; unless ($Open_state) { # The open failed. warn "ERROR: Failed to open $trash " ; return 0 ; } # The open succeeded. my @seqlines = (); @seqlines = ; close TESTFILE; if ($HBI_Debug_get_full_history) { warn "INFO: History file $clientID.$testID.history line count is " . ($#seqlines + 1) . " \n" ; } my $testline ; my $Line_cnt = 0 ; foreach $testline (@seqlines) { my $match_state ; $Line_cnt ++ ; if ($testline =~ m/^([^\<]+)\<\<\>\>([^\&]+)&([^\&]+)&([^\&]+)&/) { my $time_ascii = $1 ; my $Client_id_str = $2 ; my $candidateID = $3 ; my $Test_id_str = $4 ; if ($Client_id_str ne $clientID) { warn "ERROR: Bad test history file data ${clientID}.${testID}.history " . "line $Line_cnt has mismatched client id.\n" ; } if ($Test_id_str ne $testID) { warn "ERROR: Bad test history file data ${clientID}.${testID}.history " . "line $Line_cnt has mismatched test id.\n" ; } my $timestamp = &toGMSeconds($time_ascii) ; unless ($timestamp) { warn "ERROR: Bad test history file data ${clientID}.${testID}.history " . "line $Line_cnt has bad time stamp.\n" ; $timestamp = "UNK $Line_cnt" ; # Unique value for the file. } if ($HBI_Debug_get_full_history and ($Line_cnt <= 4 )) { warn "INFO: History file $clientID.$testID.history time_ascii $time_ascii timestamp $timestamp\n" ; } $FULL_HISTORY->{$clientID}->{$testID}->{$candidateID}->{$timestamp} = $testline ; } else { warn "ERROR: get_full_history failed to match a valid format in a test history file.\n" ; warn "ERROR: get_full_history file ${clientID}.${testID}.history line $Line_cnt \n" ; next ; } } if ($HBI_Debug_get_full_history) { warn "INFO: History file $clientID.$testID.history RETURN 1, line_cnt $Line_cnt \n" ; } return 1 ; } sub get_group_hash { # Parameters # $client - Client ID string. # Returned value. # $Group_hash - A scalar reference to an anonymous hash. # The keys of the hash are the group ids. # The values are another hash of data for the group. # The keys are the field ids: grpowner, grpid, grpnme, grplist, validfrom, validto # and GroupMembersA. # The value of GroupMembersA is an anon array of the candidate ids of the members. # The other values are the raw data of the fields in the group file. my ($clientID) = @_ ; my $HBI_Debug_get_group_hash = 0 ; my @GroupData = &get_client_groups($clientID); my $GroupID_HREF = {} ; my $idxid = $GRPFIELD{'grpid'}; my @GroupFieldIDs = keys %GRPFIELD ; warn "INFO: idxid $idxid Field IDS " . (join(" ", @GroupFieldIDs)) . "\n" if ($HBI_Debug_get_group_hash) ; my ($FieldID, $GroupID ) ; my $orig_data ; my @split_orig_data ; my $raw_data ; foreach $orig_data (@GroupData) { chomp $orig_data ; @split_orig_data = split(/&/, $orig_data) ; $GroupID = $split_orig_data[$idxid] ; warn "INFO: Simple group ID $GroupID raw data $raw_data\n" if ($HBI_Debug_get_group_hash) ; # Populate the raw data. foreach $FieldID (@GroupFieldIDs) { $GroupID_HREF->{$GroupID}->{$FieldID} = $split_orig_data[$GRPFIELD{$FieldID}] ; warn "INFO: group ID $GroupID FieldID $FieldID " . "Value " . $GroupID_HREF->{$GroupID}->{$FieldID} . "\n" if ($HBI_Debug_get_group_hash) ; } $candidates = $GroupID_HREF->{$GroupID}->{'grplist'} ; chomp $candidates ; $GroupID_HREF->{$GroupID}->{'GroupMembersA'} = [ split (/\,/, $candidates) ] ; warn "INFO: group ID $GroupID Candidates " . join (" ", $GroupID_HREF->{$GroupID}->{'GroupMembersA'} ) . "\n" if ($HBI_Debug_get_group_hash) ; } return $GroupID_HREF ; } sub RTFHexEscape { # Return the RTF Hex Escape of the first character in $_. my $oldstr = shift(@_) ; my $retstr = unpack ("H*", substr($oldstr, 0, 1)) ; if ($retstr) { return "\\\'" . $retstr ; } else { return "" ; } } sub RTFize { # Parameter # $textStr - An ASCII text string, not to be modified. # Returned value # $retStr - the $textStr with all special characters converted to special RTF sequences. # Control Characters 0-31, or 0x00 to 0x1F # tab, 0x09, becomes "\tab ". # carriage returns, 0x0D; and line feeds, 0x0A; are left alone. # Other control characters are deleted. # Left Curly Brace becomes \'7b. # Right Curly Brace becomes \'7d. # Back slash becomes \'5c. # Characters 128 to 255 become the hex escaped equivalent. my ($retStr) = @_ ; # Delete special control characters. $retStr =~ s/[\x00-\x08\x0B\x0C\x0E-\x1F]//g ; # Convert the back slash. $retStr =~ s/\\/\\\'5C/g ; # Convert tab. $retStr =~ s/\x09/\\tab /g ; # Convert characters that become the hex escaped value. $retStr =~ s/([\x7b\x7d\x80-\xFF])/&RTFHexEscape($1)/ge ; return $retStr ; } sub GetLikertData_from_preloaded_Globals { # Parameters # $ClientID - required # $TestID - required # $respRequired - optional, default false, Response is required to count as available points. # The routines assume that the following hashs are already loaded. # %TEST, TEST_SESSION, SUBTEST_QUESTIONS, SUBTEST_ANSWERS, SUBTEST_RESPONSES, and SUBTEST_SUMMARY # Returned value. # $ret - reference to a Hash of a Hash. The keys of the first hash are the supercategories # of the likert questions in the test. The keys of the second hash are 'PointsAvail', # 'Responses', 'NoResponses', 'PointsEarned', and 'ScoreCount'. The values of the first # four keys are numeric counts, or score totals. The value of the 'ScoreCount' is # another hash. Its keys are the scores, and the values are the counts of the number # of times each score was a response. # $QUESTIONS - Reference to an array of hash data on questions. my ($ClientID, $TestID, $respRequired ) ; $respRequired = 0 ; ($ClientID, $TestID, $respRequired ) = @_ ; my $ret = {} ; my %supercat_found = () ; # hash of categories found and initialized in the hash of hashes. my $inact_ques = 0 ; # This is an offset for the inactive questions. # The inactive questions are still listed, but without an answer. my $QUESTIONS_ZZ = &get_question_definitions ($ClientID, $TestID); # Populates an array of hashs that contains all of the questions and the answers. # $QUESTIONS_ZZ is a reference to the arrays of hashs. my $last_index = $#{$QUESTIONS_ZZ} ; # Last index of the Array of Hashs of the Q&A. my $points, $weight, @scores, @correct_ans, @incorrect_ans, @all_ans ; my $ques_type, $supercat, $scores, @responses, $responses ; $responses = $SUBTEST_RESPONSES{2} ; # warn "user $user testid $testid resp $responses .\n" ; @responses = split (/\&/, $responses) ; shift @responses ; # Drop the empty element in front of the list. foreach $index1 (0 .. $last_index) { # Skip the question if it is inactive. if (${$QUESTIONS_ZZ}[$index1]->{'qil'} eq "Y") {$inact_ques++ ; next ;} # Get the data for a single question. $points = ${$QUESTIONS_ZZ}[$index1]->{'pts'} ; $weight = ${$QUESTIONS_ZZ}[$index1]->{'wght'} ; $ques_type = ${$QUESTIONS_ZZ}[$index1]->{'qtp'} ; $scores = ${$QUESTIONS_ZZ}[$index1]->{'scores'} ; unless ($ques_type eq "lik") {next ;} @scores = split (/\,/ , $scores) ; $supercat = ${$QUESTIONS_ZZ}[$index1]->{'supercat'} ; unless ($supercat_found{$supercat}) { # Initialize counters. $ret->{$supercat}->{'PointsAvail'} = 0 ; $ret->{$supercat}->{'NoResponses'} = 0 ; $ret->{$supercat}->{'Responses'} = 0 ; $ret->{$supercat}->{'PointsEarned'} = 0 ; $ret->{$supercat}->{'ScoreCount'} = {} ; $supercat_found{$supercat} = 1 ; } $responses = $responses[$index1-$inact_ques] ; @individ = split(/\?/, $responses) ; shift @individ ; my $no_response = 1 ; $ret->{$supercat}->{'PointsAvail'} += $points ; foreach $index2 (0 .. $#scores) { # Add the key for the score count to the hash. unless (exists $ret->{$supercat}->{'ScoreCount'}->{$scores[$index2]}) { $ret->{$supercat}->{'ScoreCount'}->{$scores[$index2]} = 0 ; } } foreach $index2 (0 .. $#scores) { # warn "index2 $index2 individ $individ[$index2] .\n" ; if ($individ[$index2] ne "xxx" and $individ[$index2] ne "" and $individ[$index2] == $index2) { # Answered this question. $ret->{$supercat}->{'PointsEarned'} += $scores[$index2] ; $ret->{$supercat}->{'ScoreCount'}->{$scores[$index2]} ++ ; # warn "Likert Answer supercat $supercat index2 $index2 scores $scores[$index2] \n" ; $no_response = 0 ; } # If answered. } # foreach $index2 if ($no_response) { # Add to the no response count. $ret->{$supercat}->{'NoResponses'} ++ ; # If the response is required, and there is none. Take out the points available. if ($respRequired) {$ret->{$supercat}->{'PointsAvail'} -= $points ;} # warn "Likert Answer supercat $supercat No Response \n" ; } else { # Add to the response count. $ret->{$supercat}->{'Responses'} ++ ; # warn "Likert Answer supercat $supercat Response \n" ; } } # foreach question. return ($ret, $QUESTIONS_ZZ) ; # Return reference. } # End of GetLikertData_from_preloaded_Globals