Annotation of loncom/interface/statistics/lonproblemstatistics.pm, revision 1.1

1.1     ! stredwic    1: # The LearningOnline Network with CAPA
        !             2: # (Publication Handler
        !             3: #
        !             4: # $Id: lonstatistics.pm,v 1.29 2002/07/22 20:35:05 stredwic Exp $
        !             5: #
        !             6: # Copyright Michigan State University Board of Trustees
        !             7: #
        !             8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
        !             9: #
        !            10: # LON-CAPA is free software; you can redistribute it and/or modify
        !            11: # it under the terms of the GNU General Public License as published by
        !            12: # the Free Software Foundation; either version 2 of the License, or
        !            13: # (at your option) any later version.
        !            14: #
        !            15: # LON-CAPA is distributed in the hope that it will be useful,
        !            16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            18: # GNU General Public License for more details.
        !            19: #
        !            20: # You should have received a copy of the GNU General Public License
        !            21: # along with LON-CAPA; if not, write to the Free Software
        !            22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
        !            23: #
        !            24: # /home/httpd/html/adm/gpl.txt
        !            25: #
        !            26: # http://www.lon-capa.org/
        !            27: #
        !            28: # (Navigate problems for statistical reports
        !            29: # YEAR=2001
        !            30: # 5/5,7/9,7/25/1,8/11,9/13,9/26,10/5,10/9,10/22,10/26 Behrouz Minaei
        !            31: # 11/1,11/4,11/16,12/14,12/16,12/18,12/20,12/31 Behrouz Minaei
        !            32: # YEAR=2002
        !            33: # 1/22,2/1,2/6,2/25,3/2,3/6,3/17,3/21,3/22,3/26,4/7,5/6 Behrouz Minaei
        !            34: # 5/12,5/14,5/15,5/19,5/26,7/16  Behrouz Minaei
        !            35: #
        !            36: ###
        !            37: 
        !            38: package Apache::lonproblemstatistics; 
        !            39: 
        !            40: use strict;
        !            41: use Apache::lonnet();
        !            42: use Apache::lonhtmlcommon;
        !            43: use Apache::loncoursedata;
        !            44: use GDBM_File;
        !            45: 
        !            46: my $r;
        !            47: my %DoDiff;
        !            48: my %Discuss;
        !            49: my %mapsort;
        !            50: my %hash;
        !            51: my %CachData;
        !            52: my %color;
        !            53: my %GraphDat;
        !            54: 
        !            55: sub BuildProblemStatisticsPage {
        !            56:     my ($cacheDB, $students, $courseID, $c, $jr)=@_;
        !            57: 
        !            58:     $r = $jr;
        !            59:     my %cache;
        !            60:     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
        !            61:         return '<html><body>Unable to tie database.</body></html>';
        !            62:     }
        !            63: 
        !            64:     my $Ptr = '';
        !            65:     $Ptr .= '<table border="0"><tbody>';
        !            66:     $Ptr .= '<tr><td align="right"><b>Select Map</b></td>'."\n";
        !            67:     $Ptr .= '<td align="left">';
        !            68:     $Ptr .= &Apache::lonhtmlcommon::MapOptions(\%cache, 'ProblemStatistics');
        !            69:     $Ptr .= '</td></tr>'."\n";
        !            70:     $Ptr .= &AscendOrderOptions($cache{'Ascend'});
        !            71:     $Ptr .= &ProblemStatisticsButtons($cache{'DisplayFormat'});
        !            72:    $Ptr .= '</table>';
        !            73: 
        !            74:     $Ptr .= &ProblemStatisticsLegend();
        !            75: 
        !            76:     untie(%cache);
        !            77:     foreach (@$students) {
        !            78:         my $courseData = 
        !            79:             &Apache::loncoursedata::DownloadCourseInformation($_, $courseID);
        !            80:         last if ($c->aborted());
        !            81:         if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_WRCREAT,0640)) {
        !            82:             &Apache::loncoursedata::ProcessStudentData(\%cache, 
        !            83:                                                        $courseData, $_);
        !            84:             untie(%cache);
        !            85:         }
        !            86:     }
        !            87:     if($c->aborted()) { return $Ptr; }
        !            88: 
        !            89:     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER,0640)) {
        !            90:         return '<html><body>Unable to tie database.</body></html>';
        !            91:     }
        !            92:     my $discriminantFactor;
        !            93:     my @list=();
        !            94:     foreach (@$students) {
        !            95:         $discriminantFactor = &ExtractStudentData(\%cache, $_, \@list);
        !            96:     }
        !            97:     return $Ptr;
        !            98:     my ($upper, $lower) = &Discriminant($discriminantFactor);
        !            99:     my %Header = (0,"Homework Sets Order",1,"#Stdnts",2,"Tries",3,"Mod",
        !           100:                   4,"Mean",5,"#YES",6,"#yes",7,"%Wrng",8,"DoDiff",
        !           101:                   9,"S.D.",10,"Skew.",11,"D.F.1st",12,"D.F.2nd", 13, "Disc.");
        !           102:     &Apache::loncoursedata::LoadDiscussion($courseID, $courseID, \%Discuss);
        !           103:     &BuildStatisticsTable(\%cache, $discriminantFactor, \@list, \%Header, 
        !           104:                            $students);
        !           105: 
        !           106:     untie(%cache);
        !           107: 
        !           108:     return $Ptr;
        !           109: }
        !           110: 
        !           111: sub BuildDiffGraph {
        !           112:     my ($courseID)=@_;
        !           113: 
        !           114:     my $graphData = &GetGraphData('DiffGraph', $courseID);
        !           115:     return '<IMG src="/cgi-bin/graph.gif?'.$graphData.'" />';
        !           116: }
        !           117: 
        !           118: sub BuildWrongGraph {
        !           119:     my ($courseID)=@_;
        !           120: 
        !           121:     my $graphData = &GetGraphData('WrongGraph', $courseID);
        !           122:     return '<IMG src="/cgi-bin/graph.gif?'.$graphData.'" />';
        !           123: }
        !           124: 
        !           125: #---- Activity log -------------------------------------------------------
        !           126: 
        !           127: sub LoadDoDiffFile {
        !           128:     my $file="/home/minaeibi/183d.txt";
        !           129:     open(FILEID, "<$file");
        !           130:     my $line=<FILEID>;
        !           131:     my %DoDiff=();
        !           132:     my @Act=split('&',$line);
        !           133:     
        !           134: #    $r->print('<br>'.$#Act);
        !           135:     for(my $n=0;$n<=$#Act;$n++){
        !           136:        my ($res,$Degree)=split('@',$Act[$n]);
        !           137:       $DoDiff{$res}=$Degree;
        !           138:     }
        !           139: 
        !           140:     return \%DoDiff;
        !           141: }
        !           142: 
        !           143: sub LoadClassFile {
        !           144:     my $file="/home/minaeibi/class.txt";
        !           145:     open(FILEID, "<$file");
        !           146:     my $line;
        !           147:     my %Grade=();
        !           148:     while ($line=<FILEID>) {
        !           149:         my ($id,$ex1,$ex2,$ex3,$ex4,$hw,$final,$grade)=split(' ',$line);
        !           150:         $Grade{$id}=$grade;
        !           151:     }
        !           152:     return \%Grade;
        !           153: }
        !           154: 
        !           155: #------- Classification  
        !           156: sub Classify {
        !           157:     my ($DiscFac, $students)=@_;
        !           158:     my ($fileGrade) = &LoadClassFile();
        !           159:     my $Count=0;
        !           160:     my @List=();
        !           161:     my @LS=();
        !           162:     my @LF=();
        !           163:     my @LM=();
        !           164:     my $cf=0;
        !           165:     my $cs=0;
        !           166:     my $cm=0;
        !           167:     foreach (keys(%$DiscFac)){  
        !           168: 	my @l=split(/\:/,$_);
        !           169: 	if (!($students->{$l[1]})) {next;}
        !           170: 	my $Grade=$fileGrade->{$students->{$l[1]}};
        !           171: 	if( $Grade > 3 ) {
        !           172: 	    $cs++;
        !           173: 	    push(@LS,("$l[6],$l[5],$l[4],$l[7],$l[8],$l[9],Successful"));
        !           174: 	} elsif ( $Grade > 2 ) {
        !           175: 	    $cm++;
        !           176: 	    push(@LM,("$l[6],$l[5],$l[4],$l[7],$l[8],$l[9],Average"));
        !           177: 	} else {
        !           178: 	    $cf++;
        !           179: 	    push(@LF,("$l[6],$l[5],$l[4],$l[7],$l[8],$l[9],Failed"));
        !           180: 	}
        !           181:     }
        !           182:     my $Str = '';
        !           183:     for(my $n=0;$n<$cs;$n++){$Str .= '<br>'.$LS[$n];}
        !           184:     for(my $n=0;$n<$cm;$n++){$Str .= '<br>'.$LM[$n];}  
        !           185:     for(my $n=0;$n<$cf;$n++){$Str .= '<br>'.$LF[$n];}
        !           186: 
        !           187:     return $Str;
        !           188: } 
        !           189: 
        !           190: sub ProcAct {
        !           191:     # return;
        !           192:     my ($Act,$Submit)=@_;
        !           193:     my @Act=split(/\@/,$Act);
        !           194:     @Act = sort(@Act);
        !           195: 
        !           196:     ##$r->print('<br>'.$#Act);
        !           197:     ##for(my $n=0;$n<=$#Act;$n++){
        !           198: ##	$r->print('<br>n='.$n.')'.$Act[$n]);
        !           199: ##    }
        !           200: 
        !           201: #    my $Beg=$Act[0];
        !           202:     my $Dif=$Submit-$Act[0];
        !           203:     $Dif = ($Dif>0) ? ($Dif/3600) : 0; 
        !           204: 
        !           205: #    $r->print('<br>Access Number = '.$#Act.'<br>Submit Time='.$Submit.'<br>First Access='.$Act[0].'<br>Last Access='.$Act[$#Act].'<br> Submit - First = <b>'.$Dif.'</b>');
        !           206: 
        !           207: 
        !           208: #time spent for solving the problem           
        !           209: #    $r->print('<br>Def'.($Act[$#Act-1]-$Act[0]));
        !           210: 
        !           211:     return $Dif;
        !           212: }
        !           213: 
        !           214: sub LoadActivityLog {
        !           215: #    my $CacheDB = "/home/minaeibi/act183.log.cache";
        !           216:     my $CacheDB = "/home/httpd/perl/tmp/act183.log.cache";
        !           217: 
        !           218:     my %Activity;
        !           219:     if (-e "$CacheDB") {
        !           220: 	if (tie(%Activity,'GDBM_File',"$CacheDB",&GDBM_READER,0640)) {
        !           221: 	    return;
        !           222:         }
        !           223:         else {
        !           224: #	    $r->print("Unable to tie log Cache hash to db file");
        !           225:         }
        !           226:     }
        !           227:     else {
        !           228: 	if (tie(%Activity,'GDBM_File',$CacheDB,&GDBM_WRCREAT,0640)) {
        !           229: 	    foreach (keys %Activity) {delete $Activity{$_};}
        !           230: 	    &Build_log(\%Activity); 
        !           231: 	}
        !           232:         else {
        !           233: #	    $r->print("Unable to tie log Build hash to db file");
        !           234:         }
        !           235:     }
        !           236:     return \%Activity;
        !           237: }
        !           238: 
        !           239: sub Build_log {
        !           240:     my ($Activity)=@_;
        !           241:     my $file="/home/minaeibi/act183.log";
        !           242:     open(FILEID, "<$file");
        !           243:     my $line;
        !           244:     my $count=0;
        !           245:     while ($line=<FILEID>) {
        !           246: 	my ($time,$machine,$what)=split(':',$line);
        !           247: 	$what=&Apache::lonnet::unescape($what);
        !           248: 	my @accesses=split('&',$what);
        !           249: 	           
        !           250: 	foreach my $access (@accesses) {
        !           251: 
        !           252: 	    $count++;
        !           253: 
        !           254: 	    my ($date,$resource,$who,$domain,$post,@posts)=split(':',$access);
        !           255: 	    if (!$resource) { next; }
        !           256: 	    my $res=&Apache::lonnet::unescape($resource);
        !           257: 	    if (($res =~ /\.problem/)) {
        !           258: 		$Activity->{$who.':'.$res}.=$date.'@';
        !           259:                 #$r->print('<br>'.$time.':'.$who.'---'.$res);
        !           260: 		&Update_PrgInit($count);
        !           261: 
        !           262: 	    }
        !           263: 	}
        !           264:     }
        !           265: 
        !           266: # my $c=1;
        !           267: # foreach (sort keys %Activity) {
        !           268: #     $r->print('<br>'.$c.')'.$_.' ... '.$Activity{$_});
        !           269: #     $c++;
        !           270: # }
        !           271: 
        !           272: }
        !           273: 
        !           274: sub Activity {
        !           275: #    $rid=~/(\d+)\.(\d+)/;
        !           276: #    my $MapId=$1;
        !           277: #    my $PrbId=$2;
        !           278: #    my $MapOrg = $hash{'map_id_'.$MapId};
        !           279: #    my $Map = &Apache::lonnet::declutter($MapOrg);
        !           280: #    my $URI = $hash{'src_'.$rid};
        !           281: #    my $Symb = $Map.'___'.$PrbId.'___'.&Apache::lonnet::declutter($URI);
        !           282:     my $file="/home/minaeibi/activity.log";
        !           283:     my $userid='adamsde1';
        !           284:     $r->print("<br>Using $file");
        !           285:     $r->rflush();
        !           286:     open(FILEID, "<$file");
        !           287:     my $line;
        !           288:     my @allaccess;
        !           289:     my $Count=0;
        !           290:     while ($line=<FILEID>) {
        !           291: 	my ($time,$machine,$what)=split(':',$line);
        !           292: 	$what=&Apache::lonnet::unescape($what);
        !           293: 	my @accesses=split('&',$what);
        !           294: 	foreach my $access (@accesses) {
        !           295: 	    my ($date,$resource,$who,$domain,$post,@posts)=split(':',$access);
        !           296: 	    #if ($who ne $userid) { next; }
        !           297: 	    if (!$resource) { next; }
        !           298: 	    my $res=&Apache::lonnet::unescape($resource);
        !           299: 	    if (($res =~ /\.(sequence|problem|htm|html|page)/)) {
        !           300: 	    	$Count++;
        !           301: 		$r->print("<br>$Count) ".localtime($date).": $who --> $res");
        !           302: #	        if ($post) { 
        !           303: #		    $Count++;
        !           304: #		    $r->print("<br><b>$Count) Sent data ".join(':',
        !           305: #                              &Apache::lonnet::unescape(@posts)).'</b>');
        !           306: #		}
        !           307: 		$r->rflush();
        !           308: 	    }
        !           309: 	    #push (@allaccess,unescape($access));
        !           310: 	    #print $machine;
        !           311: 	}
        !           312:     }
        !           313: #    @allaccess=sort(@allaccess);
        !           314: #    $Count=0;
        !           315: #    foreach my $access (@allaccess) {
        !           316: #	my ($date,$resource,$who,$domain,$post,@posts)=split(':',$access);
        !           317: #	$Count++;
        !           318: #	$r->print("<br>$Count) $date: $who --> $resource");
        !           319: #	$r->rflush();
        !           320: #	if ($post) { 
        !           321: #	    $r->print("<br><b>Sent data ".join(':',unescape(@posts)).'</b>');
        !           322: #	}
        !           323: #    }
        !           324: }
        !           325: 
        !           326: #---- END Activity log ---------------------------------------------------
        !           327: 
        !           328: #---- Problem Statistics Web Page ---------------------------------------
        !           329: 
        !           330: #------- Processing upperlist and lowerlist according to each problem
        !           331: sub ProcessDiscriminant {
        !           332:     my ($List) = @_;
        !           333:     my @sortedList = sort (@$List);
        !           334:     my $Count = scalar @sortedList;
        !           335:     my $Problem;
        !           336:     my @Dis;
        !           337:     my $Slvd=0;
        !           338:     my $tmp;
        !           339:     my $Sum1=0;
        !           340:     my $Sum2=0;
        !           341:     my $nIndex=0;
        !           342:     my $nStudent=0;
        !           343:     my %Proc=undef;
        !           344:     while ($nIndex<$Count) {
        !           345: 	($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
        !           346: 	@Dis=split(/\+/,$tmp);
        !           347: 	my $Temp = $Problem;
        !           348: 	do {
        !           349: 	    $nIndex++;
        !           350: 	    $nStudent++;
        !           351: 	    $Sum1 += $Dis[0];
        !           352: 	    $Sum2 += $Dis[1];
        !           353: 	    ($Problem,$tmp)=split(/\=/,$sortedList[$nIndex]);
        !           354: 	    @Dis=split(/\+/,$tmp);
        !           355: 	} while ( $Problem eq $Temp && $nIndex < $Count );
        !           356: #	$Proc{$Temp}=($Sum1/$nStudent).':'.$nStudent;
        !           357: 	$Proc{$Temp}=($Sum1/$nStudent).':'.($Sum2/$nStudent);
        !           358: #       $r->print("$nIndex) $Temp --> ($nStudent) $Proc{$Temp} <br>");
        !           359: 	$Sum1=0;
        !           360: 	$Sum2=0;
        !           361: 	$nStudent=0;
        !           362:     }
        !           363: 
        !           364:     return %Proc;
        !           365: }
        !           366: 
        !           367: #------- Creating Discimination factor   
        !           368: sub Discriminant {
        !           369:     my ($discriminantFactor)=@_;
        !           370:     my @discriminantKeys=keys(%$discriminantFactor);
        !           371:     my $Count = scalar @discriminantKeys;
        !           372: 
        !           373:     my $UpCnt = int(0.27*$Count);
        !           374:     my $low=0;
        !           375:     my $up=$Count-$UpCnt;
        !           376:     my @UpList=();
        !           377:     my @LowList=();
        !           378: 
        !           379:     $Count=0;
        !           380:     foreach my $key (sort(@discriminantKeys)) { 
        !           381: 	$Count++;    
        !           382: 	if($low < $UpCnt || $Count > $up) {
        !           383:             $low++;
        !           384:             my $str=$discriminantFactor->{$key};
        !           385:             foreach(split(/\:/,$str)){
        !           386:                 if($_) {
        !           387:                     if($low<$UpCnt) { push(@LowList,$_); }
        !           388:                     else            { push(@UpList,$_);  }
        !           389:                 }
        !           390:             }
        !           391:         }
        !           392:     }
        !           393:     my %DisUp =  &ProcessDiscriminant(\@UpList);
        !           394:     my %DisLow = &ProcessDiscriminant(\@LowList);
        !           395: 
        !           396:     return (\%DisUp, \%DisLow);
        !           397: }
        !           398: 
        !           399:    
        !           400: sub NumericSort {          
        !           401:     $a <=> $b;
        !           402: }
        !           403: 
        !           404: 
        !           405: sub CreateProblemStatisticsTableHeading {
        !           406:     my ($displayFormat,$sequenceSource,$sequenceTitle,$headings)=@_;
        !           407:     if($displayFormat eq 'Display CSV Format') {
        !           408:         $r->print('<br>"'.$sequenceTitle.'","');
        !           409:         $r->print($sequenceSource.'"');
        !           410: 	return;
        !           411:     }
        !           412: 
        !           413:     $r->print('<br><a href="'.$sequenceSource.
        !           414:               '" target="_blank">'.$sequenceTitle.'</a>');
        !           415: 
        !           416:     my $Result = "\n".'<table border=2><tr><th>P#</th>'."\n";
        !           417:     for(my $nIndex=0; $nIndex < (scalar (keys %$headings)); $nIndex++) { 
        !           418: 	$Result .= '<th>'.'<input type="submit" name="';
        !           419:         $Result .= 'ProblemStatisticsHeading" value="';
        !           420:         $Result .= $headings->{$nIndex}.'" />'.'</th>'."\n";
        !           421:     }
        !           422:     $Result .= "\n".'</tr>'."\n";    
        !           423:     $r->print($Result);
        !           424:     $r->rflush();
        !           425: }
        !           426: 
        !           427: sub CloseTable {
        !           428:     my ($cache)=@_;
        !           429:     if($cache->{'DisplayFormat'} eq 'Display CSV Format') {
        !           430: 	return;
        !           431:     }    
        !           432:     $r->print("\n".'</table>'."\n");
        !           433:     $r->rflush();
        !           434: }
        !           435: 
        !           436: 
        !           437:  
        !           438: # ------ Dump the Student's DB file and handling the data for statistics table 
        !           439: sub ExtractStudentData {
        !           440:     my ($cache,$name,$list)=@_;
        !           441:     my %discriminantFactor;
        !           442: 
        !           443:     my $totalTries = 0;
        !           444:     my $totalAwarded = 0;
        !           445:     my $tempProblemOrder=0;
        !           446:     my $spent=0;
        !           447:     my $spent_yes=0;
        !           448:     my $TotDiscuss=0;
        !           449:     my $TotalOpend = 0;
        !           450:     my $ProbSolved = 0;
        !           451:     my $ProbTot = 0;
        !           452:     my $TotFirst = 0;
        !           453:     my $TimeTot = 0;
        !           454:     my $Discussed=0;
        !           455: 
        !           456:     foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
        !           457:         if($cache->{'ProblemStatisticsMap'} ne 'All Maps'  &&
        !           458:            $cache->{'ProblemStatisticsMap'} ne $cache->{$sequence.':title'}) {
        !           459:             next;
        !           460:         }
        !           461: 
        !           462:         my $Dis = '';
        !           463:         foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
        !           464:             my $problem = $cache->{$problemID.':problem'};
        !           465:             my $LatestVersion = $cache->{$name.':version:'.$problem};
        !           466: 
        !           467:             # Output dashes for all the parts of this problem if there
        !           468:             # is no version information about the current problem.
        !           469:             #if(!$LatestVersion) {
        !           470:             #    foreach my $part (split(/\:/,$cache->{$sequence.':'.
        !           471:             #                                          $problemID.
        !           472:             #                                          ':parts'})) {
        !           473:             #        $codes    .= "-,";
        !           474:             #        $attempts .= "0,"; 
        !           475:             #    }
        !           476:             #    next;
        !           477:             #}
        !           478: 
        !           479:             my %partData=undef;
        !           480:             # Initialize part data, display skips correctly
        !           481:             # Skip refers to when a student made no submissions on that
        !           482:             # part/problem.
        !           483:             foreach my $part (split(/\:/,$cache->{$sequence.':'.
        !           484:                                                   $problemID.
        !           485:                                                   ':parts'})) {
        !           486:                 $partData{$part.':tries'}=0;
        !           487:                 $partData{$part.':code'}='-';
        !           488:             }
        !           489: 
        !           490:             # Looping through all the versions of each part, starting with the
        !           491:             # oldest version.  Basically, it gets the most recent 
        !           492:             # set of grade data for each part.
        !           493: 	    for(my $Version=1; $Version<=$LatestVersion; $Version++) {
        !           494:                 foreach my $part (split(/\:/,$cache->{$sequence.':'.
        !           495:                                                       $problemID.
        !           496:                                                       ':parts'})) {
        !           497: 
        !           498:                     if(!defined($cache->{$name.":$Version:$problem".
        !           499:                                                ":resource.$part.solved"})) {
        !           500:                         # No grade for this submission, so skip
        !           501:                         next;
        !           502:                     }
        !           503: 
        !           504:                     my $tries=0;
        !           505:                     my $time=0;
        !           506:                     my $awarded=0;
        !           507: 		    $Discussed=0;
        !           508:                     my $code='U';
        !           509: 
        !           510:                     $awarded = $cache->{$name.
        !           511:                                         "$Version:$problem:resource.".
        !           512:                                         "$part.awarded"};
        !           513:                     $partData{$part.':awarded'} = ($awarded) ? $awarded : 0;
        !           514:                     $totalAwarded += $awarded;
        !           515: 
        !           516:                     $tries = $cache->{$name.":$Version:$problem".
        !           517:                                       ":resource.$part.tries"};
        !           518:                     $partData{$part.':tries'} = ($tries) ? $tries : 0;
        !           519:                     $partData{$part.':wrong'} = $partData{$part.':tries'};
        !           520:                     $totalTries += $tries;
        !           521: 
        !           522:                     my $val = $cache->{$name.":$Version:$problem".
        !           523:                                        ":resource.$part.solved"};
        !           524:                     if    ($val eq 'correct_by_student')   {$code = 'C';} 
        !           525:                     elsif ($val eq 'correct_by_override')  {$code = 'O';}
        !           526:                     elsif ($val eq 'incorrect_attempted')  {$code = 'I';} 
        !           527:                     elsif ($val eq 'incorrect_by_override'){$code = 'I';}
        !           528:                     elsif ($val eq 'excused')              {$code = 'x';}
        !           529:                     $partData{$part.':code'}=$code;
        !           530: 
        !           531:                     if($partData{$part.':wrong'} ne 0 && 
        !           532:                        ($code eq 'C' || $code eq 'O')) {
        !           533:                         $partData{$part.':wrong'}--;
        !           534:                     }
        !           535:                 }
        !           536:             }
        !           537: 
        !           538:             # Loop through all the parts for the current problem in the 
        !           539:             # correct order and prepare the output
        !           540:             foreach (split(/\:/,$cache->{$sequence.':'.$problemID.
        !           541:                                          ':parts'})) {
        !           542:                 my $Yes = 0;
        !           543:                 if($partData{$_.':code'} eq 'C' || 
        !           544:                    $partData{$_.':code'} eq 'O') {
        !           545:                     $Yes=1;
        !           546:                 }
        !           547:                 #my $ptr = "$hash{'title_'.$ResId}";
        !           548:                 my $ptr = $tempProblemOrder.'&'.$problemID;
        !           549: 
        !           550:                 if($_ > 1) {
        !           551:                     $ptr .= "*(part $_)";
        !           552:                     $Dis .= '&';
        !           553:                 }
        !           554: 
        !           555: 		my ($pr_no,$dod)=split('&',$ptr);
        !           556: #		my $DoDiff=$DoDiff->{$dod};
        !           557: #               $r->print('<br>'.$name.'---'.$ptr.'==='.$DoDiff);
        !           558: 
        !           559:                 my $Fac = ($partData{$_.':Tries'}) ? 
        !           560:                     ($partData{$_.':awarded'}/$partData{$_.':tries'}) : 0;
        !           561:                 my $DisF;
        !           562:                 if($Fac > 0 &&  $Fac < 1) { 
        !           563:                     $DisF = sprintf( "%.4f", $Fac );
        !           564:                 } else {
        !           565:                     $DisF = $Fac;
        !           566:                 }
        !           567: 
        !           568:                 if ($Discuss{"$name:$problem"}) {
        !           569: 		    $TotDiscuss++;
        !           570:                     $Discussed=1;
        !           571:                 }
        !           572:                 my $time = $cache->{"$name:$LatestVersion:$problem:timestamp"};
        !           573:                 $Dis .= $tempProblemOrder.'='.$DisF.'+'.$Yes;
        !           574:                 $ptr .= '&'.$partData{$_.'.Tries'}.
        !           575:                         '&'.$partData{$_.'.Wrongs'}.
        !           576:                         '&'.$partData{$_.'.Code'};
        !           577:                 push (@$list, $ptr."&$Discussed");
        !           578: 
        !           579: ####		if ($DoDiff>0.85) {
        !           580: 
        !           581:                 $TimeTot += $time;
        !           582: 
        !           583:                 if ($Yes==1 && $partData{$_.'.Tries'}==1) {
        !           584: 		    $TotFirst++;
        !           585:                 }
        !           586: #		my $Acts= $Activity->{$name.':'.$problem};
        !           587: #		if ($Acts) {
        !           588: #		    my $Pt=&ProcAct( $Acts, $time );
        !           589: 		    #my ($spe,$beg) = split(/\+/,$Pt);
        !           590: #                    my $spe= $Pt;
        !           591: #		    if ($Yes==1) {$spent_yes += $spe;}
        !           592: #		    $spent += $spe;
        !           593: 		    #$Beg += $beg;
        !           594: #                   $r->print('<br>'.$name.'---'.$problem.'---'.$spe);
        !           595: #		}
        !           596: 		$TotalOpend++;
        !           597: 		$ProbTot++;
        !           598: 
        !           599:                 $tempProblemOrder++;
        !           600:             }
        !           601:         }
        !           602: 	my $pstr;
        !           603:         if($totalTries) {
        !           604: 	    my $DisFac = ($totalAwarded/$totalTries);
        !           605: 	    my $DisFactor = sprintf( "%.4f", $DisFac );
        !           606:             my $TS = sprintf( "%.2f", $spent );
        !           607:             my $TS_yes = sprintf( "%.2f", $spent_yes );
        !           608: 	   # $DiscFac{$DisFactor}=$Dis;
        !           609: 	    $pstr=$DisFactor.':'.$name.':'.$ProbTot.':'.$TotalOpend.':'.
        !           610:                   $totalTries.':'.$ProbSolved.':'.$TotFirst.':'.
        !           611:                   $TS_yes.':'.$TS.':'.$TotDiscuss;
        !           612: 	    $discriminantFactor{$pstr}=$Dis;
        !           613: 	}
        !           614:     }
        !           615: 
        !           616:     return (\%discriminantFactor);
        !           617: }
        !           618: 
        !           619: 
        !           620: =pod
        !           621: sub MySort {          
        !           622:     if ( $Pos > 0 ) {
        !           623: 	if ($ENV{'form.order'} eq 'Descending') {$b <=> $a;}
        !           624: 	else { $a <=> $b; }
        !           625:     }
        !           626:     else {
        !           627: 	if ($ENV{'form.order'} eq 'Descending') {$b cmp $a;}
        !           628: 	else { $a cmp $b; }
        !           629:     }
        !           630: }
        !           631: =cut
        !           632: 
        !           633: sub BuildStatisticsTable {
        !           634:     my ($cache,$discriminantFactor,$list,$headings,$students)=@_;
        !           635: 
        !           636: #6666666
        !           637: #    my $file="/home/httpd/perl/tmp/183d.txt";
        !           638: #    open(OUT, ">$file");
        !           639: #6666666
        !           640:     &Create_PrgWin();
        !           641: ##777777
        !           642: ##    my (%Activity) = &LoadActivityLog();
        !           643: ##    $r->print('<script>popwin.document.popremain.remaining.value="'.
        !           644: ##              'Loading Discussion...";</script>');
        !           645: ##    my ($doDiffFile) = &LoadDoDiffFile();
        !           646: 
        !           647:     my $p_count = 0;
        !           648:     my $nIndex = 0;
        !           649:     my $dummy;
        !           650:     my $p_val;
        !           651:     my $ResId;
        !           652:     my $NoElements = scalar @$list;
        !           653: 
        !           654:     foreach my $sequence (split(':', $cache->{'orderedSequences'})) {
        !           655:         if($cache->{'ProblemStatisticsMap'} ne 'All Maps'  &&
        !           656:            $cache->{'ProblemStatisticsMap'} ne $cache->{$sequence.':title'}) {
        !           657:             next;
        !           658:         }
        !           659: 
        !           660: 	&CreateProblemStatisticsTableHeading($cache->{'DisplayFormat'},
        !           661:                                              $cache->{$sequence.':source'}, 
        !           662:                                              $cache->{$sequence.':title'},
        !           663:                                              $headings);
        !           664: 
        !           665: ##777777
        !           666: ##    $Str .= &Classify($discriminantFactor, $students);
        !           667: 
        !           668: 
        !           669: 	my ($Hid,$pr)=split(/\:/,$mapsort{$_});
        !           670: 	my @lpr=split(/\&/,$pr);
        !           671: 	for (my $i=1; $i<=$#lpr; $i++) {
        !           672: 	    my %storestats=();
        !           673: 	    my ($PrOrd,$Prob,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,$list->[$nIndex]);
        !           674: 	    my $Temp = $Prob;
        !           675: 	    my $MxTries = 0;
        !           676: 	    my $TotalTries = 0;
        !           677: 	    my $YES = 0;
        !           678: 	    my $Incorrect = 0;
        !           679: 	    my $Override = 0;
        !           680: 	    my $StdNo = 0;
        !           681: 	    my $DiscNo=0;
        !           682: 	    my @StdLst;
        !           683: 	    while ( $PrOrd == $lpr[$i] ) 
        !           684: 	    {
        !           685: 		$nIndex++;
        !           686: 		$StdNo++;
        !           687: 		$StdLst[ $StdNo ] = $Tries;
        !           688: 		$TotalTries += $Tries;
        !           689: 		if ( $MxTries < $Tries ) { $MxTries = $Tries; } 
        !           690: 		if ( $Code eq 'C' ){ $YES++; }
        !           691: 		elsif( $Code eq 'I' ) { $Incorrect++; }
        !           692: 		elsif( $Code eq 'O' ) { $Override++; }
        !           693: 		elsif( $Code eq 'U' ) { $StdNo--; }
        !           694: 		($PrOrd,$Prob,$Tries,$Wrongs,$Code,$Disc)=split(/\&/,$list->[$nIndex]);
        !           695: 	    }	
        !           696: 
        !           697: 	    $p_count++;
        !           698: 	    my $Dummy;
        !           699: 	    ($ResId,$Dummy)=split(/\*/,$Temp);
        !           700: 
        !           701: 	    $Temp = '<a href="'.$hash{'src_'.$ResId}.
        !           702:                 '" target="_blank">'.$hash{'title_'.$ResId}.$Dummy.'</a>';
        !           703: 
        !           704: 	    my $res = &Apache::lonnet::declutter($hash{'src_'.$ResId});
        !           705: 	    my $urlres=$res;
        !           706: 
        !           707: 	    $ResId=~/(\d+)\.(\d+)/;
        !           708: 	    my $Map = &Apache::lonnet::declutter( $hash{'map_id_'.$1} );
        !           709: 	    $urlres=$Map;
        !           710:  
        !           711: 	    $res = '<a href="'.$hash{'src_'.$ResId}.'">'.$res.'</a>';
        !           712: 	    #$Map = '<a href="'.$Map.'">'.$res.'</a>';
        !           713: 
        !           714: #------------------------ Compute the Average of Tries about one problem
        !           715: 	    my $Average = ($StdNo) ? $TotalTries/$StdNo : 0;
        !           716: 
        !           717: 	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___timestamp'}=time;       
        !           718: 	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___stdno'}=$StdNo;
        !           719: 	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___avetries'}=$Average;
        !           720:    
        !           721: #-------------------------------- Compute percentage of Wrong tries
        !           722: 	    my $Wrong = ( $StdNo ) ? 100 * ( $Incorrect / $StdNo ) : 0;
        !           723: 
        !           724: #-------------------------------- Compute Standard Deviation
        !           725: 	    my $StdDev = 0; 
        !           726: 	    if ( $StdNo > 1 ) {
        !           727: 		for ( my $n = 0; $n < $StdNo; $n++ ) {
        !           728: 		    my $Dif = $StdLst[ $n ]-$Average;
        !           729: 		    $StdDev += $Dif*$Dif;
        !           730: 		} 
        !           731: 		$StdDev /= ( $StdNo - 1 );
        !           732: 		$StdDev = sqrt( $StdDev );
        !           733: 	    }
        !           734: 
        !           735: #-------------------------------- Compute Degree of Difficulty
        !           736: 	    my $DoDiff = 0;
        !           737: 	    if( $TotalTries > 0 ) {
        !           738: 		$DoDiff = 1 - ( ( $YES + $Override ) / $TotalTries );
        !           739: #	    $DoDiff =  ($TotalTries)/($YES + $Override+ 0.1);	    
        !           740: 	    }
        !           741:        
        !           742: 	    $storestats{$ENV{'request.course.id'}.'___'.$urlres.'___difficulty'}=$DoDiff;
        !           743: 
        !           744: #-------------------------------- Compute the Skewness
        !           745: 	    my $Skewness = 0;
        !           746: 	    my $Sum = 0; 
        !           747: 	    if ( $StdNo > 0 && $StdDev > 0 ) {
        !           748: 		for ( my $n = 0; $n < $StdNo; $n++ ) {
        !           749: 		    my $Dif = $StdLst[ $n ]-$Average;
        !           750: 		    $Skewness += $Dif*$Dif*$Dif;
        !           751: 		} 
        !           752: 		$Skewness /= $StdNo;
        !           753: 		$Skewness /= $StdDev*$StdDev*$StdDev;
        !           754: 	    }
        !           755: 
        !           756: #--------------------- Compute the Discrimination Factors
        !           757:             my ($Up1,$Up2)=split(/\:/,':');#jason$DisUp->{$lpr[$i]});
        !           758: 	    my ($Lw1,$Lw2)=split(/\:/,':');#jason$DisLow->{$lpr[$i]});
        !           759: 	    my $Dis1 = $Up1 - $Lw1;
        !           760: 	    my $Dis2 = $Up2 - $Lw2;
        !           761: 	    my $_D1 = sprintf("%.2f", $Dis1);
        !           762: 	    my $_D2 = sprintf("%.2f", $Dis2);
        !           763: 
        !           764: #-----------------  Some restition in presenting the float numbers
        !           765: 	    my $Avg = sprintf( "%.2f", $Average );
        !           766: 	    my $Wrng = sprintf( "%.1f", $Wrong );
        !           767: 	    my $SD = sprintf( "%.1f", $StdDev );
        !           768: 	    my $DoD = sprintf( "%.2f", $DoDiff );
        !           769: 	    my $Sk = sprintf( "%.1f", $Skewness );
        !           770: 	    my $join = $lpr[$i].'&'.$Temp.'&'.$StdNo.'&'.
        !           771:                        $TotalTries.'&'.$MxTries.'&'.$Avg.'&'.
        !           772:                        $YES.'&'.$Override.'&'.$Wrng.'&'.$DoD.'&'.
        !           773: 		       $SD.'&'.$Sk.'&'.$_D1.'&'.$_D2.'&'.
        !           774:                        $DiscNo.'&'.$Prob;
        !           775: 	    $CachData{($p_count-1)}=$join;
        !           776: 
        !           777: #6666666
        !           778: #	    $r->print('<br>'.$out.'&'.$DoD);
        !           779: #            print (OUT $out.'@'.$DoD.'&');
        !           780: #6666666
        !           781: 
        !           782: 	    $urlres=~/^(\w+)\/(\w+)/;
        !           783: 	    if ($StdNo) { 
        !           784: 		&Apache::lonnet::put('resevaldata',\%storestats,$1,$2); 
        !           785: 	    }
        !           786: #-------------------------------- Row of statistical table
        !           787:             &TableRow($cache,$join,$i,($p_count-1));
        !           788: 	}
        !           789: 	&CloseTable($cache);
        !           790:     }
        !           791:     &Close_PrgWin();
        !           792: #666666
        !           793: #    close( OUT );
        !           794: #666666
        !           795: }
        !           796: 
        !           797: =pod
        !           798: sub Cache_Statistics {
        !           799:     my ($cache)=@_;
        !           800:     my @list = ();
        !           801:     my $Useful;
        !           802:     my $UnUseful;
        !           803: #    $r->print('<input type="hidden" name="show" value="excel" />'."\n"); 
        !           804:     my %myHeader = reverse( %Header );
        !           805:     $Pos = $myHeader{$ENV{'form.sort'}};
        !           806:     if ($Pos > 0) {$Pos++;}
        !           807:     my $p_count = 0;
        !           808:     foreach my $key( keys %CachData) { 
        !           809: 	my @Temp=split(/\&/,$CachData{$key});
        !           810: 	if ( $Pos == 0 ) {
        !           811: 	    ($UnUseful,$Useful)=split(/\>/,$Temp[$Pos]);
        !           812: 	}
        !           813: 	else {
        !           814: 	    $Useful = $Temp[$Pos];
        !           815: 	}   
        !           816: 	$list[$p_count]=$Useful.'@'.$CachData{$key};
        !           817:         $p_count++;
        !           818:     }
        !           819: 
        !           820:     @list = sort MySort (@list);
        !           821: 
        !           822:     my $nIndex=0;
        !           823: 
        !           824:     if ( $Pos == 0 ) {
        !           825: 	foreach (sort keys %mapsort) {
        !           826: 	    my ($Hid,$pr)=split(/\:/,$mapsort{$_});
        !           827: 	    &CreateProblemStatisticsTableHeading($cache,1,$Hid);
        !           828: 	    my @lpr=split(/\&/,$pr);
        !           829: 	    for (my $i=1; $i<=$#lpr; $i++) {
        !           830: 		my($Pre, $Post) = split(/\@/,$list[$nIndex]); 
        !           831: 		#$r->print('<br>'.$Pre.'---'.$Post);
        !           832: 		&TableRow($cache,$Post,$i,$nIndex);
        !           833: 		$nIndex++;
        !           834: 	    }
        !           835: 	    &CloseTable($cache);
        !           836: 	}
        !           837:     }
        !           838:     else {
        !           839: 	&CreateProblemStatisticsTableHeading($cache,0);
        !           840: 	for ( my $nIndex = 0; $nIndex < $p_count; $nIndex++ ) {
        !           841: 	    my($Pre, $Post) = split(/\@/,$list[$nIndex]); 
        !           842: 	    &TableRow($cache,$Post,$nIndex,$nIndex);
        !           843: 	} 
        !           844: 	&CloseTable($cache);
        !           845:     }
        !           846: }
        !           847: =cut 
        !           848: 
        !           849: sub TableRow {
        !           850:     my ($Str,$Idx,$RealIdx)=@_;
        !           851:     my($PrOrd,$Temp,$StdNo,$TotalTries,$MxTries,$Avg,$YES,$Override,
        !           852:        $Wrng,$DoD,$SD,$Sk,$_D1,$_D2,$DiscNo,$Prob)=split(/\&/,$Str);	
        !           853:     if ($ENV{'form.showcsv'}) {
        !           854:         my ($ResId,$Dummy)=split(/\*/,$Prob);
        !           855:         my $Ptr =  "\n".'<br>'.
        !           856:                "\n".'"'.($RealIdx+1).'",'.
        !           857:                "\n".'"'.$hash{'title_'.$ResId}.$Dummy.'",'.
        !           858:                "\n".'"'.$hash{'src_'.$ResId}.'",'.
        !           859:                "\n".'"'.$StdNo.'",'.
        !           860:                "\n".'"'.$TotalTries.'",'.
        !           861:                "\n".'"'.$MxTries.'",'.
        !           862:                "\n".'"'.$Avg.'",'.
        !           863:                "\n".'"'.$YES.'",'.
        !           864:                "\n".'"'.$Override.'",'.
        !           865:                "\n".'"'.$Wrng.'",'.
        !           866:                "\n".'"'.$DoD.'",'.
        !           867:                "\n".'"'.$SD.'",'.
        !           868:                "\n".'"'.$Sk.'",'.
        !           869:                "\n".'"'.$_D1.'",'.
        !           870: 	       "\n".'"'.$_D2.'"'.
        !           871: 	       "\n".'"'.$DiscNo.'"';
        !           872: 
        !           873:         $r->print("\n".$Ptr);
        !           874:     }
        !           875:     else{
        !           876:         my $Ptr =  "\n".'<tr>'.
        !           877:                "\n".'<td>'.($RealIdx+1).'</td>'.
        !           878:           #     "\n".'<td>'.$PrOrd.$Temp.'</td>'.
        !           879:                "\n".'<td>'.$Temp.'</td>'.
        !           880:                "\n".'<td bgcolor='.$color{"yellow"}.'> '.$StdNo.'</td>'.
        !           881:                "\n".'<td bgcolor='.$color{"yellow"}.'>'.$TotalTries.'</td>'.
        !           882:                "\n".'<td bgcolor='.$color{"yellow"}.'>'.$MxTries.'</td>'.
        !           883:                "\n".'<td bgcolor='.$color{"gb"}.'>'.$Avg.'</td>'.
        !           884:                "\n".'<td bgcolor='.$color{"gb"}.'> '.$YES.'</td>'.
        !           885:                "\n".'<td bgcolor='.$color{"gb"}.'> '.$Override.'</td>'.
        !           886:                "\n".'<td bgcolor='.$color{"red"}.'> '.$Wrng.'</td>'.
        !           887:                "\n".'<td bgcolor='.$color{"red"}.'> '.$DoD.'</td>'.
        !           888:                "\n".'<td bgcolor='.$color{"green"}.'> '.$SD.'</td>'.
        !           889:                "\n".'<td bgcolor='.$color{"green"}.'> '.$Sk.'</td>'.
        !           890:                "\n".'<td bgcolor='.$color{"purple"}.'> '.$_D1.'</td>'.
        !           891: 	       "\n".'<td bgcolor='.$color{"purple"}.'> '.$_D2.'</td>'.
        !           892:                "\n".'<td bgcolor='.$color{"yellow"}.'> '.$DiscNo.'</td>';
        !           893:         $r->print("\n".$Ptr.'</tr>' );
        !           894:     }
        !           895:     $GraphDat{$RealIdx}=$DoD.':'.$Wrng;
        !           896: }
        !           897: 
        !           898: sub StatusOptions {
        !           899:     my ($cache)=@_;
        !           900: 
        !           901:     my $Status = $cache->{'Status'};
        !           902:     my $OpSel1 = '';
        !           903:     my $OpSel2 = '';
        !           904:     my $OpSel3 = '';
        !           905: 
        !           906:     if($Status eq 'Any')         { $OpSel3 = ' selected'; }
        !           907:     elsif($Status eq 'Expired' ) { $OpSel2 = ' selected'; }
        !           908:     else                         { $OpSel1 = ' selected'; }
        !           909: 
        !           910:     my $Ptr = '';
        !           911:     $Ptr .= '<tr><td align="right"><b>Student Status:</b></td>'."\n";
        !           912:     $Ptr .= '<td align="left"><select name="Status">';
        !           913:     $Ptr .= '<option'.$OpSel1.'>Active</option>'."\n";
        !           914:     $Ptr .= '<option'.$OpSel2.'>Expired</option>'."\n";
        !           915:     $Ptr .= '<option'.$OpSel3.'>Any</option>'."\n";
        !           916:     $Ptr .= '</select></td></tr>'."\n";
        !           917: 
        !           918:     return $Ptr;
        !           919: }
        !           920: 
        !           921: sub AscendOrderOptions {
        !           922:     my ($order)=@_;
        !           923: 
        !           924:     my $OpSel1 = '';
        !           925:     my $OpSel2 = '';
        !           926: 
        !           927:     if($order eq 'Ascending') {
        !           928:         $OpSel1 = ' selected';
        !           929:     } else {
        !           930:         $OpSel2 = ' selected';
        !           931:     }
        !           932: 
        !           933:     my $Ptr = '';
        !           934:     $Ptr .= '<tr><td align="right"><b>Sorting Type:</b></td>'."\n";
        !           935:     $Ptr .= '<td align="left"><select name="Ascend">'."\n";
        !           936:     $Ptr .= '<option'.$OpSel1.'>Ascending</option>'."\n".
        !           937: 	    '<option'.$OpSel2.'>Descending</option>'."\n";
        !           938:     $Ptr .= '</select></td></tr>'."\n";
        !           939: 
        !           940:     return $Ptr;
        !           941: }
        !           942: 
        !           943: sub ProblemStatisticsButtons {
        !           944:     my ($displayFormat)=@_;
        !           945: 
        !           946:     my $Ptr = '<tr><td></td><td align="left">';
        !           947:     $Ptr .= '<input type=submit name="ProblemStatisticsRecalculate" ';
        !           948:     $Ptr .= 'value="Recalculate Statistics"/>'."\n";
        !           949:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
        !           950:     $Ptr .= '<input type="submit" name="DoDiffGraph" ';
        !           951:     $Ptr .= 'value="DoDiff Graph" />'."\n";
        !           952:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
        !           953:     $Ptr .= '<input type="submit" name="PercentWrongGraph" ';
        !           954:     $Ptr .= 'value="%Wrong Graph" />'."\n";
        !           955:     $Ptr .= '&nbsp;&nbsp;&nbsp;';
        !           956:     $Ptr .= '<input type="submit" name="DisplayCSVFormat" ';
        !           957:     if($displayFormat eq 'Display CSV Format') {
        !           958:         $Ptr .= 'value="Display CSV Format" />'."\n";
        !           959:     } else {
        !           960:         $Ptr .= 'value="Display Table Format" />'."\n";
        !           961:     }
        !           962:     $Ptr .= '</td></tr>';
        !           963: 
        !           964:     return $Ptr;
        !           965: }
        !           966: 
        !           967: sub ProblemStatisticsLegend {
        !           968:     my $Ptr = '';
        !           969:     $Ptr = '<table border="0">';
        !           970:     $Ptr .= '<tr><td>';
        !           971:     $Ptr .= '<b>#Stdnts</b>:</td>';
        !           972:     $Ptr .= '<td>Total Number of Students opened the problem.';
        !           973:     $Ptr .= '</td></tr><tr><td>';
        !           974:     $Ptr .= '<b>Tries</b>:</td>';
        !           975:     $Ptr .= '<td>Total Number of Tries for solving the problem.';
        !           976:     $Ptr .= '</td></tr><tr><td>';
        !           977:     $Ptr .= '<b>Mod</b>:</td>';
        !           978:     $Ptr .= '<td>Maximunm Number of Tries for solving the problem.';
        !           979:     $Ptr .= '</td></tr><tr><td>';
        !           980:     $Ptr .= '<b>Mean</b>:</td>';
        !           981:     $Ptr .= '<td>Average Number of the tries. [ Tries / #Stdnts ]';
        !           982:     $Ptr .= '</td></tr><tr><td>';
        !           983:     $Ptr .= '<b>#YES</b>:</td>';
        !           984:     $Ptr .= '<td>Number of students solved the problem correctly.';
        !           985:     $Ptr .= '</td></tr><tr><td>';
        !           986:     $Ptr .= '<b>#yes</b>:</td>';
        !           987:     $Ptr .= '<td>Number of students solved the problem by override.';
        !           988:     $Ptr .= '</td></tr><tr><td>';
        !           989:     $Ptr .= '<b>%Wrng</b>:</td>';
        !           990:     $Ptr .= '<td>Percentage of students tried to solve the problem ';
        !           991:     $Ptr .= 'but still incorrect. [ 100*((#Stdnts-(#YES+#yes))/#Stdnts) ]';
        !           992:     $Ptr .= '</td></tr><tr><td>';
        !           993: #    Kashy formula
        !           994: #    '<b>  DoDiff </b>: Degree of Difficulty of the problem.<br>'.
        !           995: #    '[ Tries/(#YES+#yes+0.1) ]<br>'.
        !           996:     #Gerd formula
        !           997:     $Ptr .= '<b>DoDiff</b>:</td>';
        !           998:     $Ptr .= '<td>Degree of Difficulty of the problem.  ';
        !           999:     $Ptr .= '[ 1 - ((#YES+#yes) / Tries) ]';
        !          1000:     $Ptr .= '</td></tr><tr><td>';
        !          1001:     $Ptr .= '<b>S.D.</b>:</td>';
        !          1002:     $Ptr .= '<td>Standard Deviation of the tries.  ';
        !          1003:     $Ptr .= '[ sqrt(sum((Xi - Mean)^2)) / (#Stdnts-1) ';
        !          1004:     $Ptr .= 'where Xi denotes every student\'s tries ]';
        !          1005:     $Ptr .= '</td></tr><tr><td>';
        !          1006:     $Ptr .= '<b>Skew.</b>:</td>';
        !          1007:     $Ptr .= '<td>Skewness of the students tries.';
        !          1008:     $Ptr .= '[(sqrt( sum((Xi - Mean)^3) / #Stdnts)) / (S.D.^3)]';
        !          1009:     $Ptr .= '</td></tr><tr><td>';
        !          1010:     $Ptr .= '<b>Dis.F.</b>:</td>';
        !          1011:     $Ptr .= '<td>Discrimination Factor: A Standard for evaluating the ';
        !          1012:     $Ptr .= 'problem according to a Criterion<br>';
        !          1013:     $Ptr .= '<b>[Applied Criterion in %27 Upper Students - ';
        !          1014:     $Ptr .= 'Applied the same Criterion in %27 Lower Students]</b><br>';
        !          1015:     $Ptr .= '<b>1st Criterion</b> for Sorting the Students: ';
        !          1016:     $Ptr .= '<b>Sum of Partial Credit Awarded / Total Number of Tries</b><br>';
        !          1017:     $Ptr .= '<b>2nd Criterion</b> for Sorting the Students: ';
        !          1018:     $Ptr .= '<b>Total number of Correct Answers / Total Number of Tries</b>';
        !          1019:     $Ptr .= '</td></tr>';
        !          1020:     $Ptr .= '<tr><td><b>Disc.</b></td>';
        !          1021:     $Ptr .= '<td>Number of Students had at least one discussion.';
        !          1022:     $Ptr .= '</td></tr></table>';
        !          1023: 
        !          1024:     return $Ptr;
        !          1025: }
        !          1026: 
        !          1027: #---- END Problem Statistics Web Page ----------------------------------------
        !          1028: 
        !          1029: #---- Problem Statistics Graph Web Page --------------------------------------
        !          1030: 
        !          1031: # ------------------------------------------- Prepare data for Graphical chart
        !          1032: 
        !          1033: sub GetGraphData {
        !          1034:     my $ylab = shift;
        !          1035:     my $Col;
        !          1036:     my $data='';
        !          1037:     my $count = 0;
        !          1038:     my $Max = 0;
        !          1039:     my $cid=$ENV{'request.course.id'};
        !          1040:     my $GraphDB = "/home/httpd/perl/tmp/$ENV{'user.name'}".
        !          1041:                   "_$ENV{'user.domain'}_$cid\_graph.db";
        !          1042:     foreach (keys %GraphDat) {delete $GraphDat{$_};}
        !          1043:     if (-e "$GraphDB") {
        !          1044: 	if (tie(%GraphDat,'GDBM_File',"$GraphDB",&GDBM_READER,0640)) {
        !          1045: 	    if ( $ylab eq 'DoDiff Graph' ) {
        !          1046: 		$ylab = 'Degree-of-Difficulty';
        !          1047: 		$Col = 0;
        !          1048: 	    }
        !          1049: 	    else {
        !          1050: 		$ylab = 'Wrong-Percentage';
        !          1051: 		$Col = 1;
        !          1052: 	    }
        !          1053: 	    foreach (sort NumericSort keys %GraphDat) { 
        !          1054: 		my @Temp=split(/\:/,$GraphDat{$_});
        !          1055:                 my $inf = $Temp[$Col]; 
        !          1056: 		if ( $Max < $inf ) {$Max = $inf;}
        !          1057: 		$data .= $inf.',';
        !          1058: 		$count++;
        !          1059: 	    }
        !          1060: 	    if ( $Max > 1 ) { 
        !          1061: 		$Max += (10 - $Max % 10);
        !          1062: 		$Max = int($Max);
        !          1063: 	    }
        !          1064: 	    else { $Max = 1; }
        !          1065:             untie(%GraphDat);
        !          1066: 	    my $Course = $ENV{'course.'.$cid.'.description'};
        !          1067: 	    $Course =~ s/\ /"_"/eg;
        !          1068: 	    my $GData=$Course.'&'.'Problems'.'&'.$ylab.'&'.$Max.'&'.$count.'&'.$data;
        !          1069: 	}
        !          1070: 	else {
        !          1071: 	    $r->print("Unable to tie hash to db file");
        !          1072: 	}
        !          1073:     }
        !          1074: }
        !          1075: 1;
        !          1076: __END__

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