File:  [LON-CAPA] / capa / capa51 / GUITools / capastats.tcl
Revision 1.18: download - view: text, annotated - select for diffs
Tue Oct 17 18:28:24 2000 UTC (23 years, 7 months ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_12_X, version_2_11_X, version_2_11_4_uiuc, version_2_11_4_msu, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, version_1_3_X, version_1_3_3, version_1_3_2, version_1_3_1, version_1_3_0, version_1_2_X, version_1_2_99_1, version_1_2_99_0, version_1_2_1, version_1_2_0, version_1_1_X, version_1_1_99_5, version_1_1_99_4, version_1_1_99_3, version_1_1_99_2, version_1_1_99_1, version_1_1_99_0, version_1_1_3, version_1_1_2, version_1_1_1, version_1_1_0, version_1_0_99_3, version_1_0_99_2, version_1_0_99_1, version_1_0_99, version_1_0_3, version_1_0_2, version_1_0_1, version_1_0_0, version_0_99_5, version_0_99_4, version_0_99_3, version_0_99_2, version_0_99_1, version_0_99_0, version_0_6_2, version_0_6, version_0_5_1, version_0_5, version_0_4, stable_2002_spring, stable_2002_july, stable_2002_april, stable_2001_fall, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, conference_2003, bz6209-base, bz6209, STABLE, HEAD, GCI_3, GCI_2, GCI_1, CAPA_5-1-6, CAPA_5-1-5, CAPA_5-1-4_RC1, BZ4492-merge, BZ4492-feature_horizontal_radioresponse, BZ4492-feature_Support_horizontal_radioresponse, BZ4492-Support_horizontal_radioresponse
- changed "Profile" to a less loaded term "Report"

# capastatistics generator
#  Copyright (C) 1992-2000 Michigan State University
#
#  The CAPA system is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation; either version 2 of the
#  License, or (at your option) any later version.
#
#  The CAPA system is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public
#  License along with the CAPA system; see the file COPYING.  If not,
#  write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.
#
#  As a special exception, you have permission to link this program
#  with the TtH/TtM library and distribute executables, as long as you
#  follow the requirements of the GNU GPL in regard to all of the
#  software in the executable aside from TtH/TtM.

###########################################################
# runCapaTools
###########################################################
###########################################################
###########################################################
proc runCapaTools { classDirConfigFile } {
    global gUniqueNumber gWindowMenu gFile gCT
    
    set num [incr gUniqueNumber]
    
    set classDir [file dirname $classDirConfigFile]
    set gFile($num) $classDir

    set utilsMenu [menu .utilsMenu$num -tearoff 0 -type tearoff -font 8x13bold \
		       -disabledforeground grey85 ]
    set gCT($num) $utilsMenu

    set pathLength [string length $gFile($num)]
    if { $pathLength > 22 } {
	set pathSubset ...[string range $gFile($num) [expr $pathLength - 22 ] end]
    } else {
	set pathSubset $gFile($num)
    }
    $utilsMenu add command -label "CapaUtils Ver 1.1" -foreground grey85 -background \
	black -state disabled 
    $utilsMenu add command -label $pathSubset -foreground white -background \
	grey30 -state disabled 

    $utilsMenu add command -label "Change Class path" -command "CTchangePath $num"
    $utilsMenu add command -label "Run capastat" -command "CTcapaStat $num"
    $utilsMenu add command -label "Time Range capastat" -command "CTcapaStat2 $num"
    $utilsMenu add command -label "Summarize Log files" -command "CTlogAnalysis $num"
    $utilsMenu add command -label "Student Course Record" -command \
	"CTstartStudentCourseProfile $num"
    $utilsMenu add command -label "CAPA IDs for one student" \
	-command "CToneStudentCapaID $num"
    $utilsMenu add command -label "All CAPA IDs" -command "CTclassCapaID $num"
    $utilsMenu add command -label "Item Analysis" -command "CTitemAnalysisStart $num"
    $utilsMenu add command -label "Item Correlation" \
	-command "CTitemCorrelationStart $num"
#    $utilsMenu add command -label "Email" -command ""
#    $utilsMenu add command -label "View Score File" -command ""
    $utilsMenu add command -label "View Submissions" -command "CTsubmissions $num"
    $utilsMenu add command -label "Create a Class Report" -command "CTcreateReport $num"
    $utilsMenu add command -label "Analyze Class Report" -command "CTanalyzeReport $num"
    $utilsMenu add command -label "Analyze Responses" -command "CTanalyzeScorer $num"
    $utilsMenu add command -label "Graph a Responses Analysis" -command "CTgraphAnalyzeScorer $num"
    $utilsMenu add command -label "Discussion Stats" -command "CTdiscussStats $num"
    $utilsMenu add command -label "Quit" -command "CTquit $num"
    $utilsMenu post 0 0
    Centre_Dialog $utilsMenu default
    set geometry [wm geometry $utilsMenu]
    wm geometry $utilsMenu +0+[lindex [split $geometry +] end]
    parseCapaConfig $num $gFile($num)
    parseCapaUtilsConfig $num $gFile($num)
}

#menu commands

###########################################################
# CTchangePath
###########################################################
###########################################################
###########################################################
#FIXME need to wait unit all running commands are done
proc CTchangePath { num } {
    global gFile gCapaConfig 
    set path [tk_getOpenFile -title "Please select a capa.config file" -filetypes \
		 { { {Capa Config} {capa.config} } }]
    if { $path == "" } { return }
    set gFile($num) [file dirname $path]
    foreach temp [array names gCapaConfig "$num.*"] { unset gCapaConfig($temp) }
    parseCapaConfig $num $gFile($num)
    parseCapaUtilsConfig $num $gFile($num)
    set pathLength [string length $gFile($num)]
    if { $pathLength > 22 } {
	set pathSubset ...[string range $gFile($num) [expr $pathLength - 22 ] end]
    } else {
	set pathSubset $gFile($num)
    }
    .utilsMenu$num entryconfigure 1 -label $pathSubset
}

###########################################################
# CTcapaStat2
###########################################################
###########################################################
###########################################################
proc CTcapaStat2 { num } {
    global gFile gCT gUniqueNumber
   # if { [set setId [getOneSet $gCT($num) $gFile($num)]] == "" } { return }
    if {[set setId [pickSets [CTsetList $gFile($num)] single "Pick A Set" \
			$gCT($num)]] == "Cancel" } { return }
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) capastat
    if { [
	  catch {
	      CTdatestamp $cmdnum
	      if { [set day [CTgetWhen $num $cmdnum $setId]] != ""} { 
		  set start [lindex $day 0]
		  set startf [clock format [lindex $day 0] -format "%b %d %R %Y"]
		  set end [lindex $day 1]
		  set endf [clock format [lindex $day 1] -format "%b %d %R %Y"]
		  set file [file join $gFile($num) records "subset$setId.db"]
		  displayStatus "Generating [file tail $file]" both $cmdnum    
		  CTcreateSubset $num $cmdnum $start $end $setId
		  updateStatusBar 0.0 $cmdnum
		  updateStatusMessage "Generating Stats [file tail $file]" $cmdnum
		  CTscanSetDB $cmdnum $file Q_cnt L_cnt
		  updateStatusBar 0.0 $cmdnum
		  updateStatusMessage "Generating Averages [file tail $file]" $cmdnum
		  CTpercentageScores $cmdnum $setId $L_cnt 1
		  CTaverage $cmdnum $Q_cnt $L_cnt faillist dodifflist numyes
		  if { $L_cnt != 0 } {
		      CTbargraph $gCT($num) $num [incr gUniqueNumber] $faillist \
			  $gFile($num) \
	     "Not-Yet-Correct, set $setId, for $startf -> $endf" \
			  "Problem \#" "%Wrong"
		      CTbargraph $gCT($num) $num [incr gUniqueNumber] $dodifflist \
			  $gFile($num) \
             "Degree of Difficulty, set $setId, for $startf-$endf" \
			  "Problem \#" "Deg. Of Diff."
		      CTbargraph $gCT($num) $num [incr gUniqueNumber] $numyes \
			  $gFile($num) \
             "Number of Yeses, set $setId, for $startf -> $endf" \
			  "Problem \#" "\#Students"
		  }
		  CToutput $num $cmdnum
		  removeStatus $cmdnum
	      }
	  } errors ] } {
	global errorCode errorInfo
	displayError "$errors\n$errorCode\n$errorInfo"
	unset gCT(cmd.$cmdnum)
    } else {
	unset gCT(cmd.$cmdnum)
    }
}

###########################################################
# CTcapaStat
###########################################################
###########################################################
###########################################################
proc CTcapaStat { num } {
    global gFile gCT gUniqueNumber
#    if { [set setId [getOneSet $gCT($num) $gFile($num)]] == "" } { return }
    if {[set setId [pickSets [CTsetList $gFile($num)] single "Pick A Set" \
			$gCT($num)]] == "Cancel" } { return }
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) capastat
    if { [
	  catch {
	      CTdatestamp $cmdnum
	      set file [file join $gFile($num) records "set$setId.db"]
	      displayStatus "Generating Stats [file tail $file]" both $cmdnum    
	      CTscanSetDB $cmdnum $file Q_cnt L_cnt
	      updateStatusBar 0.0 $cmdnum
	      updateStatusMessage "Generating Averages [file tail $file]" $cmdnum
	      CTpercentageScores $cmdnum $setId $L_cnt
	      CTaverage $cmdnum $Q_cnt $L_cnt faillist dodifflist numyes
	      CTbargraph $gCT($num) $num [incr gUniqueNumber] $faillist $gFile($num) "Not-Yet-Correct Distribution for set $setId" "Problem \#" "%Wrong"
	      CTbargraph $gCT($num) $num [incr gUniqueNumber] $dodifflist $gFile($num) "Degree of Difficulty Distribution for set $setId" "Problem \#" "Degree Of Diff."
	      CTbargraph $gCT($num) $num [incr gUniqueNumber] $numyes $gFile($num) "Number of Yeses received for set $setId" "Problem \#" "\#Students"
	      removeStatus $cmdnum
	      CToutput $num $cmdnum
	  } errors ] } {
	global errorCode errorInfo
	displayError "$errors\n$errorCode\n$errorInfo"
	unset gCT(cmd.$cmdnum)
    } else {
	unset gCT(cmd.$cmdnum)
    }
}

###########################################################
# CTlogAnalysis
###########################################################
###########################################################
###########################################################
proc CTlogAnalysis { num } {
    global gFile gUniqueNumber gCT
    #if { [set setId [getOneSet $gCT($num) $gFile($num)]] == "" } { return }
    if {[set setId [pickSets [CTsetList $gFile($num)] single "Pick A Set" \
			$gCT($num)]] == "Cancel" } { return }
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) loganalysis
    CTdatestamp $cmdnum
    if { [ catch { CTlogAnalysis2 $num $cmdnum $setId } errors ] } {
	displayError $errors
	unset gCT(cmd.$cmdnum)
    } else {
	unset gCT(cmd.$cmdnum) 
    }
    CToutput $num $cmdnum
}

###########################################################
# CTstartStudentCourseProfile
###########################################################
###########################################################
###########################################################
proc CTstartStudentCourseProfile { num } {
    global gFile gCT
    getOneStudent $gCT($num) $gFile($num) s_id s_name
    if { $s_id == "" } { return }
    CTstudentCourseProfile $num $s_id $s_name
}

###########################################################
# CTstudentCourseProfile
###########################################################
###########################################################
###########################################################
proc CTstudentCourseProfile { num s_id s_name {loginAnalysis 2} } {
    global gFile gUniqueNumber gCapaConfig gCT

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) studentcourseprofile
    displayStatus "Collecting homework scores for $s_name" both $cmdnum
    CTdatestamp $cmdnum
    CTputs $cmdnum "$s_name\n"
    if { [ catch { CTcollectSetScores $cmdnum $gFile($num) $s_id 1 \
		      $gCapaConfig($num.homework_scores_limit_set) } error ] } {
	global errorCode errorInfo
	displayError "$error \n $errorCode \n $errorInfo"
    }
    foreach type { quiz exam supp others } {
	updateStatusMessage "Collecting $type scores for $s_name" $cmdnum
	catch { 
	    if { [file isdirectory $gCapaConfig($num.[set type]_path)] } {
		CTcollectSetScores $cmdnum $gCapaConfig($num.[set type]_path) $s_id 1 \
		    $gCapaConfig($num.[set type]_scores_limit_set)
	    } 	    
	}
    }
    removeStatus $cmdnum
    if { ($loginAnalysis == 2 && "Yes" == [makeSure \
		       "Do you wish to do a Login Analysis? It may take a while." ])
	 || ($loginAnalysis == 1) } {
	displayStatus "Analyzing login data." both $cmdnum
	if { [catch { CTloginAnalysis $cmdnum $gFile($num) $s_id \
			  $gCapaConfig($num.homework_scores_limit_set) } error] } {
	    displayError error
	}
	if { [catch { CTstudentSetAnalysis $cmdnum $gFile($num) $s_id \
			  $gCapaConfig($num.homework_scores_limit_set) } error] } {
	    displayError error
	}
	removeStatus $cmdnum
    }
    CTdisplayStudent $cmdnum $gCT($num) $gFile($num) $s_id
    unset gCT(cmd.$cmdnum)
    CToutput $num $cmdnum
}

###########################################################
# CToneStudentCapaID
###########################################################
###########################################################
###########################################################
proc CToneStudentCapaID { num } {
    global gFile gUniqueNumber gCapaConfig gCT

    getOneStudent $gCT($num) $gFile($num) s_id s_name
    if { $s_id == "" } { return }

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) onestudentcapaid
    set setlist [getSetRange $gCT($num) $gFile($num)]
    set command "$gCapaConfig($num.allcapaid_command) -i -stu $s_id -s [lindex $setlist 0] -e [lindex $setlist 1] -c $gFile($num)"
    if { "Yes" == [makeSure "CMD: $command\n Do you wish to execute this command?"] } {
	CTdatestamp $cmdnum
	CTputs $cmdnum "CapaIDs for: $s_id, $s_name\n"
	displayStatus "Getting CapaIDs" spinner $cmdnum
	set fileId [open "|$command" "r"]
	fconfigure $fileId -blocking 0
	fileevent $fileId readable "CTrunCommand $num $cmdnum $fileId"
    }
}

###########################################################
# CTclassCapaID
###########################################################
###########################################################
###########################################################
proc CTclassCapaID { num } {
    global gFile gUniqueNumber gCapaConfig gCT

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) classcapaid
    set setlist [getSetRange $gCT($num) $gFile($num)]
    if { $setlist == "" } { return }
    set command "$gCapaConfig($num.allcapaid_command) -i -s [lindex $setlist 0] -e [lindex $setlist 1] -c $gFile($num)"
    if { "Yes" == [makeSure "CMD: $command\n Do you wish to execute this command?"] } {
	CTdatestamp $cmdnum
	displayStatus "Getting all CapaIDs" spinner $cmdnum
	set fileId [open "|$command" "r"]
	fconfigure $fileId -blocking 0
	fileevent $fileId readable "CTrunCommand $num $cmdnum $fileId"
    }
}

###########################################################
# CTitemAnalysisStart
###########################################################
###########################################################
###########################################################
proc CTitemAnalysisStart { num } {
    global gFile gUniqueNumber gCapaConfig gCT
    
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) itemanalysis
    set paths ""
    lappend paths [list "classpath" $gFile($num)]
    foreach path [lsort [array names gCapaConfig "$num.*_path"]] {
	lappend paths [list [lindex [split $path "."] 1] $gCapaConfig($path) ] 
    }
    if {[set select [multipleChoice $gCT($num) "Select a class path" $paths ] ] == ""} {
    	unset gCT(cmd.$cmdnum)
	return
    }
#    if { [set sets [getSetRange $gCT($num) [lindex $select 1]]] == "" } \{
    if { [set sets [pickSets [CTsetList [lindex $select 1]] \
			"extended" "Select Sets" $gCT($num)]] == "Cancel" } {
	unset gCT(cmd.$cmdnum)
	return 
    }
    CTdatestamp $cmdnum
    if { [ catch {CTitemAnalysisRange $cmdnum [lindex $select 1] $sets } errors ] } { 
	displayError $errors 
    }
    unset gCT(cmd.$cmdnum)
    CToutput $num $cmdnum
}

###########################################################
# CTitemCorrelationStart
###########################################################
###########################################################
###########################################################
proc CTitemCorrelationStart { num } {
    global gFile gUniqueNumber gCapaConfig gCT

    ## FIXME:
    ##         Let user specify how many categories to calculate correlation
    ##             For each category, the user can specify problem numbers to 
    ##             be in that category
    ##         Then, the correlations between each category is calculated
    ##
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) itemanalysis
    set paths ""
    lappend paths [list "classpath" $gFile($num)]
    foreach path [lsort [array names gCapaConfig "$num.*_path"]] {
	lappend paths [list [lindex [split $path "."] 1] $gCapaConfig($path) ] 
    }
    if {[set select [multipleChoice $gCT($num) "Select a class path" $paths]] == ""} {
    	unset gCT(cmd.$cmdnum)
	return
    }
    #if { [set setId [getOneSet $gCT($num) [lindex $select 1]]] == "" } \{ 
    if {[set setId [pickSets [CTsetList [lindex $select 1]] single "Pick A Set" \
			$gCT($num)]] == "Cancel" } {
	unset gCT(cmd.$cmdnum)
	return 
    }
    CTdatestamp $cmdnum
    if { [ catch { CTitemCorrelation $cmdnum [lindex $select 1] \
		       $setId } errors ] } { displayError $errors }
    unset gCT(cmd.$cmdnum)
    CToutput $num $cmdnum    
}

###########################################################
# CTsubmissions
###########################################################
###########################################################
###########################################################
proc CTsubmissions { num } {
    global gCT gFile gUniqueNumber gCapaConfig
    
    getOneStudent $gCT($num) $gFile($num) s_id s_name
    if { $s_id == "" } { return }

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) submissions
    if { [set sets [pickSets [CTsetList $gFile($num)] \
			"extended" "Select Sets" $gCT($num)]] == "Cancel" } { return }
#    if { "" == [set setlist [getSetRange $gCT($num) $gFile($num)]] } { return }
    CTdatestamp $cmdnum
    CTputs $cmdnum "Submissions for: $s_id, $s_name\n"
    displayStatus "Getting submissions" spinner $cmdnum
    CTsubmissionsLaunch $num $cmdnum telnet $s_id $s_name 0 $sets
}

###########################################################
# CTcreateReport
###########################################################
###########################################################
###########################################################
proc CTcreateReport { num } {
    global gUniqueNumber gCT gFile

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) createreport
    CTcreateReportDialog $num $cmdnum
}

###########################################################
# CTanalyzeReport
###########################################################
###########################################################
###########################################################
proc CTanalyzeReport { num } {
    global gUniqueNumber gCT gFile

    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) analyzereport
    
    set reportFile [tk_getOpenFile -title "Please select the Report file" \
			-filetypes  { {{Capa Reports} {*.rpt}} {{All Files} {*}} }]
    if { $reportFile == "" } { return }
    set percentage [tk_dialog $gCT($num).dialog "How would you like scores displayed?" \
		    "How would you like scores displayed?" "" "" "Points Earned" \
		    "Percentage" "Cancel"]
    if { $percentage == 2 } { return }
    set pwd [pwd];cd $gFile($num)
    set sectionList [pickSections [getExistingSections] "Select Sections To Analyze:" $gCT($num) ]
    CTdatestamp $cmdnum
    CTputs $cmdnum "Analyzing Report File $reportFile\n"
    CTputs $cmdnum "   For Sections $sectionList\n"
    CTputs $cmdnum "   Report Created at [clock format [file mtime $reportFile]]\n"
    cd $pwd
    set scorelist [CTreportDist $cmdnum $reportFile $percentage $sectionList]
    set label [lindex "{Grade} {Grade(%)}" $percentage]
    set ptsearned 0
    set totalnumstu 0
    foreach element $scorelist {
	set numstu [lindex $element 0]
	set score [lindex $element 1]
	set ptsearned [expr $ptsearned + ($numstu*$score)]
	incr totalnumstu $numstu
    }
    set average [expr $ptsearned / double($totalnumstu)]
    set avgmsg [format "Average: %.2f" $average]
    CTputs $cmdnum $avgmsg\n
    CTbargraph $gCT($num) $num $cmdnum $scorelist $gFile($num) "Score Distribution for [file tail $reportFile] $avgmsg" $label "\# Students" SCP
    unset gCT(cmd.$cmdnum)
    CToutput $num $cmdnum
}

###########################################################
# CTanalyzeScorer
###########################################################
###########################################################
###########################################################
proc CTanalyzeScorer { num } {
    global gFile gUniqueNumber gCapaConfig gCT    
    set cmdnum [incr gUniqueNumber]
#    puts "CTanalyzeScorer $cmdnum"
    set gCT(cmd.$cmdnum) analyzescorer
    if { "" == [set file [tk_getOpenFile -title "Pick a scorer.output file" -filetypes { { {scorer.output} {scorer.output.*} } { {Submissions File} {*submissions*.db} } { {All Files} {*} } }]] } { return }
    set path [file dirname [file dirname $file]]
    if { "" == [set gCT($cmdnum.questNum) [getString $gCT($num) "Which questions?"]]} {
	return
    }
    set gCT($cmdnum.max) [lindex [exec wc -l $file] 0]
    set gCT($cmdnum.done) 1
    set gCT($cmdnum.graphup) 0
    set gCT($cmdnum.num) $num
    displayStatus "Getting student reponses" both $cmdnum
    set gCT($cmdnum.fileId) [open $file r]
    if { [regexp {scorer\.output\.([0-9]|([0-9][0-9]))} $file] } {
	set gCT($cmdnum.setId) [string range [file extension $file] 1 end]
	set gCT($cmdnum.parse) CTparseScorerOutputLine
	set aline [gets $gCT($cmdnum.fileId)]
    } else {
	set gCT($cmdnum.setId) [lindex [split [file tail $file] s.] 4]
	set gCT($cmdnum.parse) CTparseSubmissionsLine
    }
    set aline [gets $gCT($cmdnum.fileId)]
    $gCT($cmdnum.parse) $aline $cmdnum 
    set pwd [pwd];cd $path
    getSet $gCT($cmdnum.question) $gCT($cmdnum.setId) "CTcontinueAnalyze $cmdnum $path"
    cd $pwd
}

proc CTcontinueAnalyze { cmdnum path arrayData } {
#    puts "CTcontinueAnalyze $cmdnum"
    global gCT gResponse gGetSet
    array set question $arrayData
    while {1} {
	CTgetQuestions $cmdnum question
	set numAdded 0
	foreach which $gCT($cmdnum.questNum) {
	    #	puts $gCT($cmdnum.response)
	    incr numAdded [CTgetStudentResponses $cmdnum [lindex $gCT($cmdnum.response) \
							      [expr $which-1]] $which \
			       question]
	    #	puts $numAdded
	}
	#    puts "end"
	updateStatusBar [expr $gCT($cmdnum.done)/double($gCT($cmdnum.max))] $cmdnum
	if { $numAdded > 0 } { CTupdateAnalyzeScorer $cmdnum }
	set interesting 0
	while {!$interesting} {
	    incr gCT($cmdnum.done)
	    set stunum $gCT($cmdnum.question)
	    set aline [gets $gCT($cmdnum.fileId)]
	    if { [eof $gCT($cmdnum.fileId)] } { CTfinishAnalyzeScorer $cmdnum; return }
	    set interesting [$gCT($cmdnum.parse) $aline $cmdnum]
	}
	if { $stunum != $gCT($cmdnum.question) } {
	    set pwd [pwd];cd $path
	    getSet $gCT($cmdnum.question) $gCT($cmdnum.setId) \
		"CTcontinueAnalyze $cmdnum $path"
	    cd $pwd
	    break
	} 
    }
#    puts "After Continue Analyze"
}

proc CTupdateAnalyzeScorer { cmdnum } {
#    puts "CTupdateAnalyzeScorer $cmdnum"
    global gCT gResponse gUniqueNumber gFile
    set num $gCT($cmdnum.num)
    set i 0
    foreach correct [array names gResponse "$cmdnum.correct.*"] {
	set probnum [lindex [split $correct .] 2]
	set answer [join [lrange [split $correct .] 3 end] .]
	if { $gResponse($correct) } {
	    set color($probnum.$answer) grey90
	    set color($probnum.$answer.unpicked) grey10
	} else {
	    set color($probnum.$answer) grey30
	    set color($probnum.$answer.unpicked) grey70
	}
    }
    set results ""
    foreach response [lsort -dictionary [array names gResponse $cmdnum.\[0-9\]*]] {
        incr i
	set responselm [split $response .]
	set probnum [lindex $responselm 1]
	if { [lindex $responselm 2] == "unpicked" } {
	    set answerfull [join [lrange $responselm 3 end] .]
	    set colorstring "$probnum.$answerfull.unpicked"
	    append answerfull " - Unpicked"
	    set answertemp [split [join [lrange $responselm 3 end] .] -]
	    set picked 0
	} else {
	    set answerfull [join [lrange $responselm 2 end] .]
	    set colorstring "$probnum.$answerfull"
	    append answerfull " - Picked"
	    set answertemp [split [join [lrange $responselm 2 end] .] -]
	    set picked 1
	}
	set answernum [llength $answertemp]
	set answer [join [lrange $answertemp 0 [expr $answernum - 2]] -]
	if { " Correct" == [lindex $answertemp end] } {
	    if { $picked } { set pos 0 } { set pos 3 }
	} { if { $picked } { set pos 2 } { set pos 1 } }
	
	if { [catch {set resultsAr($probnum.$answer.y)} ] } {
	    set resultsAr($probnum.$answer.y) "0 0 0 0"
	    set resultsAr($probnum.$answer.description) "{} {} {} {}"
	    set resultsAr($probnum.$answer.color) "green green green green"
	} 
	set resultsAr($probnum.$answer.y) [lreplace $resultsAr($probnum.$answer.y) \
					       $pos $pos $gResponse($response)]
	set resultsAr($probnum.$answer.description) [lreplace \
					$resultsAr($probnum.$answer.description) \
					$pos $pos $answerfull]
	set resultsAr($probnum.$answer.color) [lreplace \
                                        $resultsAr($probnum.$answer.color) $pos $pos \
					$color($colorstring)]
    }
    set i 0
    set oldprobnum ""
    foreach name [lsort -dictionary [array names resultsAr "*.y"]] {
	incr i
	set name [split $name .]
	set namelength [llength $name]
	set answer [join [lrange $name 1 [expr $namelength - 2]] .]
	set probnum [lindex $name 0]
	if { $probnum > $oldprobnum } {
	    if { $oldprobnum != "" } {
		lappend results [list 0 0 "Problem Divider" white]
	    }
	    set oldprobnum $probnum
	}
	lappend results [list $resultsAr($probnum.$answer.y) $i $resultsAr($probnum.$answer.description) $resultsAr($probnum.$answer.color)]
    }
    if { $results == "" } { return }
    if { $gCT($cmdnum.graphup)} {
	CTchangeBargraphData $cmdnum $results
    } else {
	CTbargraph $gCT($num) $num $cmdnum $results $gFile($num) "Reponse Distribution" "Which Response" "\#Picked" "Showresponse"
	set gCT($cmdnum.graphup) 1
    }
    
    update idletasks
}

proc CTsaveAnalyzeScorer { num cmdnum } {
    global gResponse gCT gFile

    if { $gCT(spinlock) } { after 50 "CTsaveAnalyzeScorer $num $cmdnum"; return } 

    set gCT(spinlock) 1
    if { "Yes" ==[makeSure "Would you like to save the results to a file?"] } {
	set file [tk_getSaveFile -initialdir $gFile($num)]
	set fileId [open $file w]
	puts $fileId [array get gResponse "$cmdnum.*"]
	close $fileId
    }
    set gCT(spinlock) 0
    unset gCT(cmd.$cmdnum)
    CToutput $num $cmdnum

}

proc CTfinishAnalyzeScorer { cmdnum } {
    global gCT gResponse gUniqueNumber gFile

    set num $gCT($cmdnum.num)
    set i 0
    removeStatus $cmdnum
    foreach correct [array names gResponse "$cmdnum.correct.*"] {
	set probnum [lindex [split $correct .] 2]
	set answer [join [lrange [split $correct .] 3 end] .]
	if { $gResponse($correct) } {
	    set color($probnum.$answer) green
	    set color($probnum.$answer.unpicked) orange
	} else {
	    set color($probnum.$answer) red
	    set color($probnum.$answer.unpicked) blue
	}
    }
    foreach response [lsort -dictionary [array names gResponse $cmdnum.\[0-9\]*]] {
        incr i
	set responselm [split $response .]
	set probnum [lindex $responselm 1]
	if { [lindex $responselm 2] == "unpicked" } {
	    set answerfull [join [lrange $responselm 3 end] .]
	    set colorstring "$probnum.$answerfull.unpicked"
	    append answerfull " - Unpicked"
	    set answertemp [split [join [lrange $responselm 3 end] .] -]
	    set picked 0
	} else {
	    set answerfull [join [lrange $responselm 2 end] .]
	    set colorstring "$probnum.$answerfull"
	    append answerfull " - Picked"
	    set answertemp [split [join [lrange $responselm 2 end] .] -]
	    set picked 1
	}
	set answernum [llength $answertemp]
	set answer [join [lrange $answertemp 0 [expr $answernum - 2]] -]
	if { " Correct" == [lindex $answertemp end] } {
	    if { $picked } { set pos 0 } { set pos 3 }
	} { if { $picked } { set pos 2 } { set pos 1 } }
	
	if { [catch {set resultsAr($probnum.$answer.y)} ] } {
	    set resultsAr($probnum.$answer.y) "0 0 0 0"
	    set resultsAr($probnum.$answer.description) "{} {} {} {}"
	    set resultsAr($probnum.$answer.color) "green green green green"
	} 
	set resultsAr($probnum.$answer.y) [lreplace $resultsAr($probnum.$answer.y) \
					       $pos $pos $gResponse($response)]
	set resultsAr($probnum.$answer.description) [lreplace \
					$resultsAr($probnum.$answer.description) \
					$pos $pos $answerfull]
	set resultsAr($probnum.$answer.color) [lreplace \
                                        $resultsAr($probnum.$answer.color) $pos $pos \
					$color($colorstring)]
    }
    set i 0
    foreach name [array names resultsAr "*.y"] {
	incr i
	set name [split $name .]
	set namelength [llength $name]
	set answer [join [lrange $name 1 [expr $namelength - 2]] .]
	set probnum [lindex $name 0]
	lappend results($probnum) [list $resultsAr($probnum.$answer.y) $i $resultsAr($probnum.$answer.description) $resultsAr($probnum.$answer.color)]
    }
    foreach probnum [lsort -dictionary [array names results]] {
	CTputs $cmdnum "\nFor Problem $probnum #, Responses:\n"
	foreach response $results($probnum) {
	    CTputs $cmdnum "[lindex $response 0], [lindex $response 2]\n"
	}
    }
    if { [catch {set gCT(spinlock)}] } { set gCT(spinlock) 0 }
    CTsaveAnalyzeScorer $num $cmdnum
}

proc CTparseScorerOutputLine { aline num } {
#    puts "CTparseScorerOutputLine $num"
    global gCT
    set gCT($num.stunum) [lindex $aline 0]
    set aline [string range $aline 40 end]
    set length  [llength [split [lrange $aline 3 end] ,] ]
    set gCT($num.response) [lrange [split [lrange $aline 3 end] ,] 0 \
				   [expr {$length-2}]]
    set gCT($num.question) [lindex [lindex [split $aline ,] end] 0]
    return 1
}

proc CTparseSubmissionsLine { aline num } {
#    puts "CTparseSubmissionsLine $num"
    global gCT
    set aline [split $aline \t]
    set gCT($num.stunum) [lindex $aline 0]
    set gCT($num.question) $gCT($num.stunum)
    set gCT($num.response) ""
    set interesting 0
    set current 1
    foreach element [lrange $aline 2 end] {
	set quest [lindex [split $element " "] 0]
	set response [lindex [split $element " "] 1]
	if { $quest == "" } break
	while { $quest > $current } {
	    lappend gCT($num.response) {}
	    incr current
	}
	if { [lsearch $gCT($num.questNum) $quest] != -1} { set interesting 1 }
	lappend gCT($num.response) [string toupper $response]
	incr current
    }
    return $interesting
}

proc CTgetQuestions { num questionVar } {
#    puts "CTgetQuestions $num"
    global gCT
    upvar $questionVar question
#    parray question
    foreach quest $gCT($num.questNum) {
	foreach line $question($quest.quest) {
	    if { [regexp {^ *([A-Z])\)(.*)} $line temp letter rest] } {
		set question($quest.$letter) $rest
		if { [string first $letter $question($quest.ans)] != -1} {
		    set question($quest.correct.$letter) 1
		    set question($quest.$letter) "$rest - Correct"
		} else {
		    set question($quest.correct.$letter) 0
		    set question($quest.$letter) "$rest - Incorrect"
		}
	    }
	}
    }
}

proc CTgetStudentResponses2 { num responses which questionVar } {
    global gCT gResponse
    upvar $questionVar question
#    parray question
    set i 0
    foreach response [split $responses {}] {
	if { $response == "" || $response == " "} { continue } 
	incr i
	if { [catch {incr gResponse($num.$which.$question($which.$response))}] } {
	    if {[catch {set gResponse($num.$which.$question($which.$response)) 1}]} {
                #set gResponse($num.$which.Illegal\ Bubble) 1
#		puts "not an option $response $which"
		continue
            }	    
	}
	if { $question($which.correct.$response) } {
	    set gResponse($num.correct.$which.$question($which.$response)) 1
	} else {
	    set gResponse($num.correct.$which.$question($which.$response)) 0
	}
    }
    return $i
}

proc CTgetStudentResponses { num responses which questionVar } {
#    puts "CTgetStudentResponses $num"
    global gCT gResponse
    upvar $questionVar question
#    parray question
    set i 0
    if {$responses == ""} { return 0 } 
    if { [string toupper $responses] == "NONE" } { set responses "" }
    set response [split $responses {}]
    foreach letter {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
	if { [catch {set question($which.correct.$letter)}]} { 
#	    puts "skipping out on $letter"
	    break 
	}
	incr i
	if { [lsearch $response $letter] == -1 } {
	    # unpicked
	    if { [catch {incr gResponse($num.$which.unpicked.$question($which.$letter))}] } {
		if {[catch {set gResponse($num.$which.unpicked.$question($which.$letter)) 1}]} {
		    #set gResponse($num.$which.Illegal\ Bubble) 1
#		    puts "not an option $letter $which"
		    continue
		}	    
	    }
	} else {
	    # picked
	    if { [catch {incr gResponse($num.$which.$question($which.$letter))}] } {
		if {[catch {set gResponse($num.$which.$question($which.$letter)) 1}]} {
		    #set gResponse($num.$which.Illegal\ Bubble) 1
#		    puts "not an option $letter $which"
		    continue
		}	    
	    }
	}
	if { $question($which.correct.$letter) } {
	    set gResponse($num.correct.$which.$question($which.$letter)) 1
	} else {
	    set gResponse($num.correct.$which.$question($which.$letter)) 0
	}
    }
    return $i
}

###########################################################
# CTgraphAnalyzeScorer
###########################################################
###########################################################
###########################################################
proc CTgraphAnalyzeScorer { num } {
    global gFile gUniqueNumber gCapaConfig gCT gResponse
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) graphanalyzescorer
    if { "" == [set file [tk_getOpenFile -title "Pick a Output file" -filetypes { { {All Files} {*} } } -initialdir $gFile($num)]] } { return }
    set fileId [open $file r]
    set temp [read $fileId [file size $file]]
    close $fileId
    foreach {name value} $temp {
	set name [join "$cmdnum [lrange [split $name .] 1 end]" .]
	set gResponse($name) $value
    }
    unset temp
    foreach name [array names gResponse $cmdnum.\[0-9\]*] {
	lappend probnums [lindex [split $name .] 1]
    } 
    set probnums [lsort [lunique $probnums]]
    event generate . <1> -x 1 -y 1
    event generate . <ButtonRelease-1>
    if { "" == [set probnums [multipleChoice $gCT($num) "Select which problems" $probnums 0]] } { return }
    foreach name [array names gResponse $cmdnum.\[0-9\]*] {
	set probnum [lindex [split $name .] 1]
	if { -1 == [lsearch $probnums $probnum] } {
	    set answer [join [lrange [split $name .] 2 end] .]
	    catch {unset gResponse($name)}
	    catch {unset gResponse($cmdnum.correct.$probnum.$answer)}
	}
    }
    set gCT($cmdnum.num) $num
    set gCT($cmdnum.graphup) 0
    CTupdateAnalyzeScorer $cmdnum
    unset gCT(cmd.$cmdnum)
}

###########################################################
# CTdiscussStats
###########################################################
###########################################################
###########################################################
proc CTdiscussStats { num } {
    global gCT gUniqueNumber gFile
    set cmdnum [incr gUniqueNumber]
    set gCT(cmd.$cmdnum) discussstats
    set file [file join $gFile($num) discussion logs access.log]
    displayStatus "Generating discussion Stats" both $cmdnum    
    CTdiscussForum $cmdnum $file $gFile($num) discussData 0
    CTputsDiscussResults $cmdnum discussData
    CToutput $num $cmdnum
    removeStatus $cmdnum
    unset gCT(cmd.$cmdnum)
}

###########################################################
# CTquit
###########################################################
###########################################################
###########################################################
proc CTquit { num } {
    global gCT
    destroy $gCT($num)
}

#menu command helpers
###########################################################
# CTscanSetDB
###########################################################
###########################################################
###########################################################
proc CTscanSetDB { num file Q_cntVar L_cntVar } {
    global gMaxSet gTotal_try gYes_cnt gyes_cnt gStudent_cnt gStudent_try \
	gTotal_weight gTotal_scores gEntry gScore gNewStudent_cnt
    upvar $Q_cntVar Q_cnt 
    upvar $L_cntVar L_cnt

    set line_cnt 0
    set valid_cnt 0
    
    for { set ii 0 } { $ii <= $gMaxSet } { incr ii } {
	set gTotal_try($num.$ii) 0
	set gYes_cnt($num.$ii) 0
	set gyes_cnt($num.$ii) 0
	for { set jj 0 } { $jj <= $gMaxSet } { incr jj } {
	    set gStudent_cnt($num.$ii.$jj) 0
	    set gStudent_try($num.$ii.$jj) 0
	}
	set gNewStudent_cnt($num.$ii) 0
    }
    set gTotal_weight($num) 0
    set gTotal_scores($num) 0

    set maxLine [lindex [exec wc $file] 0]
    set tries ""
    set fileId [open $file "r"]
    set aline [gets $fileId]
    while { ! [eof $fileId] } {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	if { $line_cnt == 2 } {
	    set aline [string trim $aline]
	    set weight [split $aline {}]
	}
	if { $line_cnt > 3 } {
	    catch {
		set aline [string trim $aline]
		set prefix [lindex [split $aline ,] 0]
		set s_num [lindex [split $aline " "] 0]
		set ans_str [lindex [split $prefix " "] 1]
		set ans_char [split $ans_str {} ]
		set tries [lrange [split $aline ,] 1 end]
		for { set valid 0; set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		    if {([lindex $ans_char $ii] != "-")&&([lindex $ans_char $ii] != "E") 
			 && ([lindex $ans_char $ii] != "e") } { set valid 1 }
		}
		if { $valid } {
		    for {set score 0; set ii 0} { $ii < [llength $tries] } { incr ii } {
			set triesii 0
			incr gTotal_weight($num) [lindex $weight $ii]
			if { [lindex $ans_char $ii] == "Y" } {
			    set triesii [string trim [lindex $tries $ii]]
			    incr gYes_cnt($num.$ii)
			    incr score [lindex $weight $ii]
			    incr gNewStudent_cnt($num.$ii)
			} elseif { [lindex $ans_char $ii] == "y" } {
			    set triesii [string trim [lindex $tries $ii]]
			    incr triesii
			    incr gyes_cnt($num.$ii)
			    incr score [lindex $weight $ii]
			    incr gNewStudent_cnt($num.$ii)
			} elseif { ( [lindex $ans_char $ii] > 0 ) && \
			     ( [lindex $ans_char $ii] <= 9) } {
			    set triesii [string trim [lindex $tries $ii]]
			    incr score [lindex $ans_char $ii]
			    incr gYes_cnt($num.$ii)
			    incr gNewStudent_cnt($num.$ii)
			} elseif { ( [lindex $ans_char $ii] == 0 ) } {
			    set triesii [string trim [lindex $tries $ii]]
			    incr gNewStudent_cnt($num.$ii)
			} elseif {([lindex $ans_char $ii]=="n") || \
				      ([lindex $ans_char $ii]=="N")} {
			    set triesii [string trim [lindex $tries $ii]]
			    if { [lindex $ans_char $ii] == "n"  } { incr triesii }
			    incr gNewStudent_cnt($num.$ii)
			}
			set gStudent_try($num.$valid_cnt.$ii) $triesii
			incr gTotal_try($num.$ii) $triesii
			incr gStudent_cnt($num.$ii.$triesii)
		    }
		    incr gTotal_scores($num) $score
		    set gEntry($num.$valid_cnt) "$aline"
		    set gScore($num.$valid_cnt) $score
		    incr valid_cnt
		}
	    } 
	}
	set aline [gets $fileId]
    }
    close $fileId
    set Q_cnt [llength $tries]
    set L_cnt $valid_cnt
    return
}

###########################################################
# CTpercentageScores
###########################################################
###########################################################
###########################################################
proc CTpercentageScores { num setId valid_cnt {subset 0}} {
    global gTotal_weight gTotal_scores 

    if { $subset } { set setstr "subset" } else { set setstr "set" }
    if { $gTotal_weight($num) > 0 } {
	set ratio [expr double($gTotal_scores($num)) / double($gTotal_weight($num))]
	set ratio [expr $ratio * 100.0 ]
	CTputs $num "\nScore (total scores / total valid weights) for $setstr$setId.db: [format %7.2f%% $ratio]\n" 
    }
    CTputs $num "The number of valid records for $setstr$setId.db is: $valid_cnt\n"
}

###########################################################
# CTaverage
###########################################################
###########################################################
###########################################################
proc CTaverage { num q_cnt l_cnt faillistVar dodifflistVar numyesVar} {
    upvar $faillistVar faillist $dodifflistVar dodifflist $numyesVar numyes
    global gMaxTries gStudent_cnt gStudent_try gTotal_try gYes_cnt gyes_cnt \
	gNewStudent_cnt

    set maxIter [expr $q_cnt * 4]
    
    for { set ii 0 } { $ii < $q_cnt } { incr ii } {
	updateStatusBar [expr $ii/double($maxIter)] $num 
	set s_cnt($ii) 0
	set avg($ii) 0.0
	set max_try($ii) 0
	for { set jj 1 } { $jj < $gMaxTries } { incr jj } {
	    if { $gStudent_cnt($num.$ii.$jj) > 0 } {
		set avg($ii) [expr $avg($ii) + ($jj * $gStudent_cnt($num.$ii.$jj))]
		incr s_cnt($ii) $gStudent_cnt($num.$ii.$jj)
	    }
	}
	set s_cnt($ii) $gNewStudent_cnt($num.$ii)
	if { $s_cnt($ii) > 0 } { set avg($ii) [expr $avg($ii) / $s_cnt($ii)] }
    }
    
    for { set ii 0 } { $ii < $q_cnt } { incr ii } {
	updateStatusBar [expr ($ii+$q_cnt)/double($maxIter)] $num
	set sd($ii) 0.0
	set sum 0.0
	for { set jj 0 } { $jj < $l_cnt } { incr jj } {
	    if { $gStudent_try($num.$jj.$ii) > $max_try($ii) } {
		set max_try($ii) $gStudent_try($num.$jj.$ii) 
	    }
	    if { $gStudent_try($num.$jj.$ii) > 0 } {
		set sq [expr ( $gStudent_try($num.$jj.$ii) - $avg($ii) ) * \
			    ( $gStudent_try($num.$jj.$ii) - $avg($ii)) ]
		set sum [expr $sum + $sq]
	    }
	    if { $s_cnt($ii) > 1  } {
		set sd($ii) [expr  $sum / ( $s_cnt($ii) - 1.0 )]
	    }
	    if { $sd($ii) > 0 } { set sd($ii) [ expr sqrt($sd($ii)) ] }
	}
    }

    for { set ii 0 } { $ii < $q_cnt } { incr ii } {
	updateStatusBar [expr ($ii+(2*$q_cnt))/double($maxIter)] $num
	set sd3($ii) 0.0
	set sum 0.0
	for { set jj 0 } { $jj < $l_cnt } { incr jj } {
	    if { $gStudent_try($num.$jj.$ii) > 0 } {
		set tmp1 [expr $gStudent_try($num.$jj.$ii) - $avg($ii)]
		set tmp2 [expr $tmp1 * $tmp1 * $tmp1]
		set sum [expr $sum + $tmp2]
	    }
	    if { ( $s_cnt($ii) > 0 ) && ( $sd($ii) != 0.0 ) } {
		set sd3($ii) [expr $sum / $s_cnt($ii) ]
		set sd3($ii) [expr $sd3($ii) / ($sd($ii) * $sd($ii) * $sd($ii)) ]
	    }
	}
    }
    CTputs $num "This is the statistics for each problem: \n"
    CTputs $num "Prob\#  MxTries  avg.    s.d.   s.k.  \#Stdnts"
    CTputs $num " \#Yes  \#yes Tries   DoDiff %Wrong\n"
    set numyes [set dodifflist [set faillist ""]]
#    parray s_cnt
    for { set ii 0 } { $ii < $q_cnt } { incr ii } {
	updateStatusBar [expr ($ii+(3*$q_cnt))/double($maxIter)] $num
	if { $gTotal_try($num.$ii) > 0 } {
	    set dod [expr $gTotal_try($num.$ii)/(0.1 + $gYes_cnt($num.$ii) \
						     + $gyes_cnt($num.$ii))]
	} else {
	    set dod 0.0
	}
	if {[catch {set success [expr 100.0*($s_cnt($ii)-($gYes_cnt($num.$ii)+ \
				$gyes_cnt($num.$ii)))/$s_cnt($ii)]}]} {
	    set success 0.0
	    set s_cnt($ii) 0
	}
	CTputs $num [format "P %2d" [expr int($ii + 1)] ]
	CTputs $num [format "%6d  %8.2f %7.2f %6.2f  %5d  %5d %5d %5d  %5.1f  %6.2f\n"\
			  $max_try($ii) $avg($ii) $sd($ii) $sd3($ii) $s_cnt($ii) \
			 $gYes_cnt($num.$ii) $gyes_cnt($num.$ii)  \
			 $gTotal_try($num.$ii) $dod $success]
	if { $success < 0 } { set success 0 }
	lappend faillist [list $success [expr int($ii + 1)]]
	lappend dodifflist [list $dod [expr int($ii + 1)]]
	lappend numyes [list [expr $gYes_cnt($num.$ii)+$gyes_cnt($num.$ii)] \
				[expr int($ii + 1)]]
    }
}

###########################################################
# CTlogAnalysis2
###########################################################
###########################################################
###########################################################
proc CTlogAnalysis2 { num cmdnum setId } {
    global gFile
    set logFile [file join $gFile($num) records "log$setId.db"]
    if { [file exists $logFile] } {
	CTputs $cmdnum "Log analysis for telnet session log$setId.db\n" 
	CTscanLogDB $cmdnum $logFile l(Y) l(N) l(S) l(U) l(u) l(A) l(F)
    } else {
	set l(Y) [set l(N) [set l(S) [set l(U) [set l(u) [set l(A) [set l(F) 0]]]]]]
    }
    set webLogFile [file join $gFile($num) records "weblog$setId.db" ]
    if { [file exists $webLogFile] } {
	CTputs $cmdnum "===============================================\n"
	CTputs $cmdnum "Log analysis for web session weblog$setId.db\n"
	CTscanLogDB $cmdnum $webLogFile w(Y) w(N) w(S) w(U) w(u) w(A) w(F)
    } else {
	set w(Y) [set w(N) [set w(S) [set w(U) [set w(u) [set w(A) [set w(F) 0]]]]]]
    }
    set telnet_total [expr $l(Y)+$l(N)+$l(S)+$l(U)+$l(u)+$l(A)+$l(F)]
    set web_total [expr $w(Y)+$w(N)+$w(S)+$w(U)+$w(u)+$w(A)+$w(F)]
    CTputs $cmdnum "============== SUMMARY ====================\n"
    CTputs $cmdnum "            #Y     #N     #S     #U     #u    #A     #F     Total\n"
    CTputs $cmdnum [format "telnet: %6d %6d %6d %6d %6d %6d %6d   %6d\n" \
			       $l(Y) $l(N) $l(S) $l(U) $l(u) $l(A) $l(F) $telnet_total ]
    CTputs $cmdnum [format "   web: %6d %6d %6d %6d %6d %6d %6d   %6d\n" \
			       $w(Y) $w(N) $w(S) $w(U) $w(u) $w(A) $w(F) $web_total]
    foreach v { Y N S U u A F} {
	set sum($v) [expr $l($v) + $w($v)]
	if { $sum($v) > 0 } { 
	    set ratio($v) [expr 100.0*$w($v)/double($sum($v))] 
	} else {
	    set ratio($v) 0.0
	}
    }
    set overall_entries [expr $telnet_total + $web_total]
    if { $overall_entries > 0 } { 
	set ratio(web) [expr 100.0*(double($web_total)/double($overall_entries))]
    } else {
	set ratio(web) 0.0
    }
    CTputs $cmdnum [format "  %%web: % 6.1f % 6.1f % 6.1f % 6.1f % 6.1f % 6.1f % 6.1f   % 6.1f\n" \
			$ratio(Y) $ratio(N) $ratio(S) $ratio(U) $ratio(u) $ratio(A) $ratio(F) $ratio(web) ]
}


###########################################################
# CTscanLogDB
###########################################################
###########################################################
###########################################################
proc CTscanLogDB { num file Y_lVar N_lVar S_lVar U_lVar u_lVar A_lVar F_lVar } {
    upvar $Y_lVar Y_l
    upvar $N_lVar N_l
    upvar $S_lVar S_l
    upvar $U_lVar U_l
    upvar $u_lVar u_l
    upvar $A_lVar A_l
    upvar $F_lVar F_l
    
    set line_cnt 0
    
    displayStatus "Analyzing [file tail $file]" both $num
    set maxLine [lindex [exec wc $file] 0]
    set fileId [open $file "r"]
    
    set aline [gets $fileId]
    while { ! [eof $fileId] } {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	set aline [string trim $aline]
	set ans_str [string range $aline 35 end]
	set ans_char [split $ans_str {}]
	if { ! [info exists count] } {
	    for { set i 0 } { $i < [llength $ans_char] } { incr i } {
		set count(Y.$i) 0; set count(N.$i) 0; set count(S.$i) 0
		set count(U.$i) 0; set count(u.$i) 0; set count(A.$i) 0
		set count(F.$i) 0
	    }
	    set count(Y.total) 0; set count(N.total) 0; set count(S.total) 0
	    set count(U.total) 0; set count(u.total) 0; set count(A.total) 0
	    set count(F.total) 0
	}
	set i -1
	foreach char $ans_char {
	    incr i
	    if { $char == "-" } { continue }
	    if { [catch {incr count($char.$i)}] } {
		set count(Y.$i) 0; set count(N.$i) 0; set count(S.$i) 0
		set count(U.$i) 0; set count(u.$i) 0; set count(A.$i) 0
		set count(F.$i) 0
		incr count($char.$i)
	    }
	    incr count($char.total)
	}
	set aline [gets $fileId]
    }
    close $fileId
    removeStatus $num
    CTputs $num "Prob #:     #Y     #N     #S     #U     #u     #A     #F\n"
    for { set i 0 } { $i < [llength $ans_char] } { incr i } {
	CTputs $num [format "    %2d: %6d %6d %6d %6d %6d %6d %6d\n"  [expr $i + 1] \
                     $count(Y.$i) $count(N.$i) $count(S.$i) $count(U.$i) $count(u.$i) \
			 $count(A.$i) $count(F.$i) ]
    }
    CTputs $num "===========================================\n"
    CTputs $num [format " Total: %6d %6d %6d %6d %6d %6d %6d\n" $count(Y.total) \
		     $count(N.total) $count(S.total) $count(U.total) $count(u.total) \
		     $count(A.total) $count(F.total) ]
    set Y_l $count(Y.total)
    set N_l $count(N.total)
    set S_l $count(S.total)
    set U_l $count(U.total)
    set u_l $count(u.total)
    set A_l $count(A.total)
    set F_l $count(F.total)
    return
}

###########################################################
# CTcollectSetScores
###########################################################
###########################################################
###########################################################
proc CTcollectSetScores { num path id on_screen limit } {
    set id [ string toupper $id ]
    set total_scores 0
    set total_weights 0
    set set_idx 0
    set done 0
    while { ! $done } {
	incr set_idx
	if { $set_idx > $limit } { set done 1; continue }
	updateStatusBar [expr $set_idx/double($limit)] $num
	set filename [file join $path records "set$set_idx.db"]
	if { ![file readable $filename ] } { continue }
	set fileId [open $filename "r"]
	set line_cnt 0
	set found 0
	set aline [ gets $fileId ]
	while { ! [eof $fileId] && ! $found } {
	    incr line_cnt
	    if { $line_cnt > 3 } {
		set aline [string trim $aline]
		set prefix [lindex [split $aline ","] 0]
		set s_num [string toupper [lindex [split $aline " "] 0] ]
		set ans_str [lindex [split $prefix " "] 1]
		if { $id == $s_num } {
		    set ans_char [split $ans_str {} ]
		    set valid 0
		    foreach char $ans_char { if { $char != "-" } { set valid 1; break } }
		    if { ! $valid } {
			set score "-"
		    } else {
			set score 0
			for {set i 0} { $i < [llength $ans_char] } { incr i } {
			    set char [lindex $ans_char $i]
			    if { $char == "N" || $char == "n"} { set found 1 }
			    if { $char == "Y" || $char == "y"} { 
				catch {incr score [lindex $weights $i]}
				set found 1
			    }
			    if { $char >= 0 && $char <= 9 } { 
				incr score $char;set found 1
			    }
			    if { $char == "E" } {
				catch {incr valid_weights "-[lindex $weights $i]"}
			    }
			}
			incr total_scores $score
		    }
		}
	    } elseif { $line_cnt == 2 } {
		set aline [string trim $aline]
		set weights [split $aline {} ]
		set valid_weights 0
		foreach weight $weights { incr valid_weights $weight }
	    } else {
		#do nothing for line 1 and 3
	    }
	    set aline [ gets $fileId ]
	}
	close $fileId
	incr total_weights $valid_weights
	set set_weights([expr $set_idx - 1]) $valid_weights
	if { $found } {
	    set set_scores([expr $set_idx - 1]) $score
	} else {
	    set set_scores([expr $set_idx - 1]) "-"
	}
    }
    set abscent_cnt 0
    set present_cnt 0
    set summary_str ""
    if { $on_screen } { CTputs $num "          " }
    foreach i [lsort -integer [array names set_scores]] {
	if { $set_scores($i) == "-" || $set_scores($i) == "" } {
	    if { $on_screen } { CTputs $num "  - " } 
	    append summary_str "x/$set_weights($i) "
	    incr abscent_cnt
	} else {
	    if { $on_screen } { CTputs $num [format " %3d" $set_scores($i)] } 
	    append summary_str "$set_scores($i)/$set_weights($i) "
	    incr present_cnt
	}
    }
    if { $on_screen } {
	CTputs $num "\n [file tail $path]:"
	foreach i [lsort -integer [array names set_scores]] { CTputs $num " ---" }
	CTputs $num "\n          "
	if { [info exists set_weights] } {
	    set num_set_weights [llength [array names set_weights]]
	} else {
	    set num_set_weights 0
	}
	for {set i 0} {$i < $num_set_weights} {incr i} {
	    if { [info exists set_weights($i)] } {
		CTputs $num [format " %3d" $set_weights($i)]
	    } else {
		set num_set_weights $i
	    }
	}
	CTputs $num "\n"
	if { $total_weights != 0 } { 
	    set ratio [expr 100.0 * $total_scores / double($total_weights) ]
	    CTputs $num [format "  %5d\n" $total_scores]
	    if { [info exists set_scores] } {
		CTputs $num [format " ------- = %3.2f%%, scores absent in %d/%d\n" \
				 $ratio $abscent_cnt [llength [array names set_scores]]]
	    } else {
		CTputs $num [format " ------- = %3.2f%%, scores absent in %d/%d\n" \
				 $ratio $abscent_cnt 0 ]
	    }
	} else {
	    set ratio "-"
	    CTputs $num [format "  %5d\n" $total_scores]
	    if { [info exists set_scores] } {
		CTputs $num [format " ------- =     %s%%, scores absent in %d/%d\n" \
				 $ratio $abscent_cnt [llength [array names set_scores]]]
	    } else {
		CTputs $num [format " ------- =     %s%%, scores absent in %d/%d\n" \
				 $ratio $abscent_cnt 0 ]
	    }
	}

	CTputs $num [format "  %5d\n" $total_weights]
    }
    return [list $total_scores $total_weights $abscent_cnt \
	    [llength [array names set_scores] ] $summary_str]
}

###########################################################
# CTloginAnalysis
###########################################################
###########################################################
###########################################################
proc CTloginAnalysis { num path id limit } {

    CTputs $num "Login analysis:  telnet session             web session\n\n"
    CTputs $num "   set #:   #Y   #N   #S   #U   #u     #Y   #N   #S   #U   #u\n"
    set set_idx 0
    set done 0
    while { ! $done } {
	incr set_idx
	if { $set_idx > $limit } { set done 1; continue }
	CTputs $num [format "      %2d: " $set_idx]
	set filename [file join $path records "log$set_idx.db"]
	updateStatusMessage "Analyzing [file tail $filename]" $num
	updateStatusBar 0.0 $num
	if { [file readable $filename] } {
	    set result [CTstudentLoginData $num $filename $id]
	    CTputs $num [eval format \"%4d %4d %4d %4d %4d\" $result]
	    set no_log 0
	} else {
	    CTputs $num "========================"
	    set no_log 1
	}
	CTputs $num "    "
	set filename [file join $path records "weblog$set_idx.db"]
	updateStatusMessage "Analyzing [file tail $filename]" $num
	updateStatusBar 0.0 $num
	if { [file readable $filename] } {
	    set result [CTstudentLoginData $num $filename $id]
	    CTputs $num [eval format \"%4d %4d %4d %4d %4d\" $result]
	    set no_weblog 0
	} else {
	    CTputs $num "========================"
	    set no_weblog 1
	}
	CTputs $num "\n"
	if { $no_log && $no_weblog } { set done 1 }
    }
}

###########################################################
# CTstudentSetAnalysis
###########################################################
###########################################################
###########################################################
proc CTstudentSetAnalysis { num path id limit } {
    set set_idx 0
    set id [string toupper $id]
    CTputs $num " set \#:\n"
    set done 0
    while { ! $done } {
	incr set_idx
	if { $set_idx > $limit } { set done 1; continue }
	set filename [file join $path records "set$set_idx.db"]
	updateStatusMessage "Analyzing [file tail $filename]" $num
	if { ![file readable $filename] } { continue }
	CTputs $num [format "    %2d: " $set_idx]
	set fileId [open $filename "r"]
	set line_cnt 0
	set found 0
	set aline [gets $fileId]
	while { ! [eof $fileId] && !$found } {
	    incr line_cnt
	    if { $line_cnt > 3 } { 
		set aline [string trim $aline]
		set s_id [string toupper [string range $aline 0 8]]
		if {$id == $s_id} {
		    set found 1
		    set breakpt [string first "," $aline]
		    set data [list [string range $aline 10 [expr $breakpt - 1] ] \
				  [string range $aline [expr $breakpt + 1] end ] ]
		    CTputs $num "[lindex $data 0]\n          [lindex $data 1]\n"
		}
	    }
	    set aline [gets $fileId]
	}
	close $fileId
	if { ! $found } { CTputs $num "\n\n" }
    }
}

###########################################################
# CTstudentLoginData
###########################################################
###########################################################
###########################################################
proc CTstudentLoginData { num filename id } {

    set Y_total 0
    set N_total 0
    set U_total 0 
    set u_total 0 
    set S_total 0
    set s_total 0
    set maxLine [expr double([lindex [exec wc $filename] 0])]
    set line_cnt 0
    set fileId [open $filename "r"]
    set aline [gets $fileId]
    while { ![eof $fileId] } {
	incr line_cnt
	if { $line_cnt%300 == 0 } {
	    updateStatusBar [expr $line_cnt/$maxLine] $num
	}
	set aline [string trim $aline]
	set s_id [string toupper [string range $aline 0 8]]
	set id [string toupper $id]
	if {$id == $s_id} {
	    set ans_char [split [string range $aline 35 end] {} ]
	    for {set i 0} {$i< [llength $ans_char]} {incr i} {
		if {[lindex $ans_char $i] == "Y"} { incr Y_total 
		} elseif {[lindex $ans_char $i] == "N"} { incr N_total 
		} elseif {[lindex $ans_char $i] == "U"} { incr U_total 
		} elseif {[lindex $ans_char $i] == "u"} { incr u_total 
		} elseif {[lindex $ans_char $i] == "s"} { incr s_total 
		} elseif {[lindex $ans_char $i] == "S"} { incr S_total }
	    }
	}
	set aline [gets $fileId]
    }
    close $fileId
    return [list $Y_total $N_total $S_total $U_total $u_total]
}

###########################################################
# CTrunCommand
###########################################################
###########################################################
###########################################################
proc CTrunCommand { num cmdnum fileId {followup "" }} {
    global gCT

    set data [read $fileId]
    updateStatusSpinner $cmdnum
    if { $data != "" } {
	CTputs $cmdnum $data
    }
    if { [eof $fileId] } {
	fileevent $fileId readable ""
	catch {close $fileId}
	if { $followup == "" } {
	    CToutput $num $cmdnum
	    removeStatus $cmdnum
	    unset gCT(cmd.$cmdnum)
	} else {
	    eval $followup
	}
    }
}

###########################################################
# CTitemAnalysisRange
###########################################################
###########################################################
###########################################################
proc CTitemAnalysisRange { num classpath sets } {
    foreach i $sets {
	if { [ catch { CTitemAnalysis $num $classpath $i } errors ] } { 
	    displayError $errors 
	}
    }
}

###########################################################
# CTitemAnalysis
###########################################################
###########################################################
###########################################################
proc CTitemAnalysis { num classpath setId } {
    global gMaxSet
    set done 0
    
    set total_scores 0
    set total_weights 0
    set upper_percent 0.0
    set lower_percent 0.0
    
    set Y_total 0
    set N_total 0
    for { set ii 0} { $ii<$gMaxSet } {incr ii} {
	set Y_cnt($ii) 0
	set N_cnt($ii) 0
	set Ycnt_upper($ii) 0.0
	set Ycnt_lower($ii) 0.0
    }

    set filename [file join $classpath records "set$setId.db"]
    if { ! [file readable $filename] } { 
	CTputs $num "FILE: $filename does not exist!\n"
	return
    }
    
    displayStatus "Analyzing [file tail $filename]" both $num
    set maxLine [lindex [exec wc $filename] 0]
    
    set fileId [open "$filename" "r"]
    set valid_cnt 0
    set line_cnt 0
    set ans_char ""
    set aline [gets $fileId]
    while {![eof $fileId]} {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	if { $line_cnt == 2 } { 
	    set aline [string trim $aline]
	    set weights [split $aline {}]
#	    set valid_weights 0
#	    for { set ii 0 } { $ii < [llength $weights] } { incr ii } {
#		incr valid_weights [lindex $weights $ii]
#	    }
	} elseif { $line_cnt > 3} {
	    set aline [string trim $aline]
	    set prefix [lindex [split $aline ","] 0]
	    set s_num [string toupper [lindex [split $aline " " ] 0 ] ]
	    set ans_str [lindex [split $prefix " "] 1]
	    set ans_char [split $ans_str {} ]
	    set valid 0
	    for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		if { [lindex $ans_char $ii] != "-"} { set valid 1 }
	    }
	    if { $valid } {
		incr valid_cnt
		set score 0
		for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		    #Can't use incr because the numbers might be doubles
		    if { [lindex $ans_char $ii] == "Y" || \
			     [lindex $ans_char $ii] == "y" } {
			catch {incr score [lindex $weights $ii]}
			set Y_cnt($ii) [expr {$Y_cnt($ii) + 1}]
			set Y_total [expr {$Y_total + 1}]
		    }
		    if { [lindex $ans_char $ii] == "N" || \
			     [lindex $ans_char $ii] == "n" } {
			set N_cnt($ii) [expr {$N_cnt($ii) + 1}]
			set N_total  [expr {$N_total + 1}]
		    }
		    if { [lindex $ans_char $ii] >= 0 && \
			     [lindex $ans_char $ii] <= 9 } {
			incr score [lindex $ans_char $ii]
			if {[catch {set yes_part [expr [lindex $ans_char $ii] / \
						      double([lindex $weights $ii])]}]} {
			    set yes_part 1
			}
			set no_part [expr 1.0 - $yes_part]
			set Y_cnt($ii) [expr $Y_cnt($ii) + $yes_part]
			set Y_total    [expr $Y_total + $yes_part]
			set N_cnt($ii) [expr $N_cnt($ii) + $no_part]
			set N_total    [expr $N_total + $no_part]
		    }
#		    if { [lindex $ans_char $ii] == "E"} { 
#			incr valid_weights -[lindex $weights $ii]
#		    }
		}
		set s_db([format "%08d%s" $score $s_num]) $ans_str
	    }
	}
	set aline [gets $fileId]
    } 
    close $fileId
    removeStatus $num
    for { set ii 0 } { $ii < $gMaxSet } { incr ii } {
	set Ycnt_upper($ii) 0
	set Ycnt_lower($ii) 0
    }
    displayStatus "Pondering data . . ." spinner $num
    set upperpart_cnt [expr int(0.27 * double($valid_cnt))]
    set lowerpart_limit [expr $valid_cnt - $upperpart_cnt]
    set line_cnt 0
    foreach sort_key [lsort -decreasing [array names s_db]] {
	incr line_cnt
	if { ($line_cnt%20) == 0 } { updateStatusSpinner $num }
	set ans_str $s_db($sort_key)
	set ans_char [split $ans_str {} ]
	for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
	    if { [lindex $ans_char $ii] == "Y" || \
		     [lindex $ans_char $ii] == "y" || \
		     [lindex $ans_char $ii] == [lindex $weights $ii] } {
		if { $line_cnt <= $upperpart_cnt } {
		    incr Ycnt_upper($ii)
		} elseif { $line_cnt > $lowerpart_limit } {
		    incr Ycnt_lower($ii)
		}
	    }
	}
    }
    CTputs $num " There are $valid_cnt entries in file $filename\n"
    CTputs $num [format "  The upper 27%% has %d records, the lower 27%% has %d records\n"\
		     $upperpart_cnt [expr $valid_cnt - $lowerpart_limit] ]
    CTputs $num " question \#     DoDiff.      Disc. Factor (%upper - %lower) \[\#records,\#records\]\n";
    
    for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
	updateStatusSpinner $num 
	set tmp_total [expr $N_cnt($ii) + $Y_cnt($ii)]
	if { $tmp_total > 0 } {
	    set diff [expr 100.0*($N_cnt($ii) / double($N_cnt($ii) + $Y_cnt($ii)))]
	} else {
	    set diff "-"
	}
	set upper_percent [expr 100.0 * ($Ycnt_upper($ii) /double($upperpart_cnt))]
	set lower_percent [expr 100.0 * ($Ycnt_lower($ii) /double($upperpart_cnt))]
	set disc [expr $upper_percent  - $lower_percent]
	CTputs $num [format "         %2d:    "  [expr $ii + 1]]
	CTputs $num [format "%6.1f         %5.1f      (%6.1f - %6.1f) \[%8d,%8d\]\n" \
		     $diff $disc $upper_percent $lower_percent $Ycnt_upper($ii) \
			 $Ycnt_lower($ii) ]
    }
    removeStatus $num
}

###########################################################
# CTitemCorrelation
###########################################################
# INPUTS: class name with full path, set number
#
# r = \frac{\sum{x_i y_i} - \frac{(\sum x_i)(\sum y_i)}{n}}
#                                {\sqrt{(\sum x_i^2 - \frac{}{}}}
#
# corr = (sum of prod_xy - (sum_x*sum_y / n) ) / sqrt( (sum of sqr_x - (sum_x*sum_x/n))*
# 
###########################################################
###########################################################
proc CTitemCorrelation { num classpath setId } {
    global gMaxSet
     
    set filename [file join $classpath records "set$setId.db"]
    if { ! [file readable $filename] } { 
	CTputs $num "FILE: $filename does not exist!\n"
	return
    }

    displayStatus "Analyzing [file tail $filename]" both $num
    set maxLine [lindex [exec wc $filename] 0]
    
    set initialized 0
    set question_cnt 0
    set fileId [open "$filename" "r"]
    set line_cnt 0
    set aline [gets $fileId]
    while {![eof $fileId]} {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr {$line_cnt/double($maxLine)}] $num
	}
	if { $line_cnt == 2 } { 
	    set aline [string trimright $aline]
	    set weights [split $aline {}]
	} 
	if { $line_cnt > 3} {
	    set aline [string trimright $aline]
	    set data  [string range $aline 10 end]
	    set ans_str [lindex [split $data ","] 0]
	    set ans_char_list [split $ans_str {} ]
	    set try_str [string range $aline [expr {[string first "," $data] +1}] end ]
	    set question_cnt [llength $ans_char_list]
	    for { set ii 0 } { $ii < $question_cnt } { incr ii } { 
		set ans_char($ii) [lindex $ans_char_list $ii]
	    }
	    if { $question_cnt > $initialized } {
		for {set ii 0} {$ii < [expr {$question_cnt - 1}]} {incr ii} {
		    set start [expr {($initialized>($ii+1)) ? $initialized : ($ii+1)}]
		    for { set jj $start } { $jj < $question_cnt } { incr jj } {
			set index_key "$ii.$jj"
			set prod_xy($index_key) 0.0
			set sum_x($index_key) 0
			set sum_y($index_key) 0
			set sum_x2($index_key) 0
			set sum_y2($index_key) 0
			set valid_cnt($index_key) 0
		    }
		}
		set initialized $question_cnt
	    }
	    for { set ii 0 } { $ii < [expr {$question_cnt - 1}] } { incr ii } {
		for { set jj [expr {$ii+1}] } { $jj < $question_cnt } { incr jj } {
		    set index_key "$ii.$jj"
		    if { $ans_char($ii) != "-" && $ans_char($ii) != "E" && \
			 $ans_char($jj) != "-" && $ans_char($jj) != "E" } {
			## $ans_char($ii) is one of 0 .. 9, Y, y, N, n
			## $ans_char($jj) is one of 0 .. 9, Y, y, N, n
			if { $ans_char($ii) == "Y" || $ans_char($ii) == "y" } {
			    if {[set x_data [lindex $weights $ii]]==""} {set x_data 0}
			} elseif { $ans_char($ii) == "N" || $ans_char($ii) == "n" } {
			    set x_data 0
			} else { ## must be in 0 .. 9
			    set x_data $ans_char($ii)
			}
			if { $ans_char($jj) == "Y" || $ans_char($jj) == "y" } {
			    if {[set y_data [lindex $weights $jj]]==""} {set y_data 0}
			} elseif { $ans_char($jj) == "N" || $ans_char($jj) == "n" } {
			    set y_data 0
			} else { ## must be in 0 .. 9
			    set y_data $ans_char($jj)
			}
			set prod_xy($index_key)  [expr {$x_data * $y_data + 
							$prod_xy($index_key)} ]
			incr sum_x($index_key)  $x_data
			incr sum_y($index_key)  $y_data
			incr sum_x2($index_key) [expr {$x_data * $x_data}]
			incr sum_y2($index_key) [expr {$y_data * $y_data}]
			incr valid_cnt($index_key) 1
		    }
		} 
	    } 
	} 
	set aline [gets $fileId]
    } 
    close $fileId
    removeStatus $num
    # print out the correlation matrix
    #parray sum_x
    #parray sum_y
    #parray prod_xy
    #puts $question_cnt
    CTputs $num "   "
    for { set ii 1 } { $ii < $question_cnt } { incr ii } {
	CTputs $num [format "    %2d" [expr {$ii+1}] ]
    }
    CTputs $num "\n"
    # --------------------------------------
    for { set ii 0 } { $ii < [expr {$question_cnt -1}] } { incr ii } {
	CTputs $num [format " %2d:" [expr {$ii+1}] ]
	for { set jj 0 } { $jj < $ii } { incr jj } { CTputs $num "      " }
	for { set jj [expr {$ii+1}] } { $jj < $question_cnt } { incr jj } {
	    set index_key "$ii.$jj"
	    if { $valid_cnt($index_key) != "0" } {
		set upper_part [ expr { $prod_xy($index_key) - 
				    ( ($sum_x($index_key) * $sum_y($index_key)) 
					  / double($valid_cnt($index_key)))}]
		set lower_part [expr {$sum_x2($index_key) - 
				      ($sum_x($index_key) * $sum_x($index_key) 
				       / double($valid_cnt($index_key)))} ]
		set lower_part [expr {$lower_part * ($sum_y2($index_key) - 
						     ($sum_y($index_key) * 
						      $sum_y($index_key) 
						      /double($valid_cnt($index_key))))}]
		set lower_part [expr {sqrt($lower_part)}]
		if { $lower_part != 0.0 } {
		    set ratio [expr {$upper_part / double($lower_part)}]
		    CTputs $num [format " % .2f" $ratio]
		} else {
		    CTputs $num "  INF "
		}
	    } else {
		CTputs $num "  ----"
	    }
	}
	CTputs $num "\n"
    }
}

###########################################################
# CTsubmissionsLaunch
###########################################################
###########################################################
###########################################################
proc CTsubmissionsLaunch { num cmdnum type s_id s_nm index setlist } {
    global gCT gFile gUniqueNumber gCapaConfig

    set curset [lindex $setlist $index]
    CTputs $cmdnum "$type submissions for $s_nm for set $curset\n"
    if { $type == "telnet" } {
	set command "grep -i $s_id [file join $gFile($num) records submissions$curset.db]"
	set followtype web
    } else {
	set command "grep -i $s_id [file join $gFile($num) \
                       records websubmissions$curset.db]"
	set followtype telnet
	incr index
    }
    set done 0
    set followcmd ""
    while { !$done && ($index <= [llength $setlist]) } {
	if { [lindex $setlist $index] != "" } {
	    set followcmd "CTsubmissionsLaunch $num $cmdnum $followtype $s_id {$s_nm} \
                            $index \"$setlist\""
	}
	if { ![catch {set fileId [open "|$command" "r"]} error ] } { set done 1 } 
    }
    fconfigure $fileId -blocking 0
    fileevent $fileId readable "CTrunCommand $num $cmdnum $fileId {$followcmd}"
}

###########################################################
# CTreportDist
###########################################################
###########################################################
###########################################################
proc CTreportDist { num file percentage sectionlist } {
    set fileId [open $file "r"]
    set aline [gets $fileId]
    set which [expr [llength [split $aline "\t"]] - 2]
    set maximum [lindex [lrange [split $aline "\t"] $which end] 1]
    if { $percentage } {
	for {set i 0} {$i<=100} {incr i} {
	    set totals($i.score) 0
	    set totals($i.stunum) ""
	}
    } else {
	for { set i 0 } { $i <= $maximum } { incr i } { 
	    set totals($i.score) 0 
	    set totals($i.stunum) ""
	}
    }
    while { ![eof $fileId]} {
	set temp [lrange [split $aline "\t"] $which end]
	set score [lindex $temp 0]
	regsub -- "-" $score "0" score
	set max [lindex $temp 1]
	set temp [lindex [split $aline "\t"] 1]
	set section [lindex $temp 1]
	set stunum [lindex $temp 0]
	if { ([lsearch $sectionlist $section] != -1) && ($max!=0) } {
	    if { $percentage } {
		set percent [expr int($score/double($max)*100)]
		incr totals($percent.score)
		lappend totals($percent.stunum) $stunum
	    } else {
		if { $max > $maximum } {
		    for {set i [expr $maximum+1]} {$i<=$max} {incr i} {set totals($i) 0}
		    set maximum $max
		}
		set score [string trim $score]
		incr totals($score.score)
		lappend totals($score.stunum) $stunum
	    }
	}
	set aline [gets $fileId]
    }
    CTputs $num "Scores #achieved\n"
    set scorelist ""
    set templist [array names totals *.score]
    foreach temp $templist {lappend possiblescores [lindex [split $temp .] 0]}
    foreach score [lsort -integer $possiblescores] {
	CTputs $num [format "%5d:%6d\n" $score $totals($score.score)]
	lappend scorelist [list $totals($score.score) $score $totals($score.stunum)]
    } 
    return $scorelist
}

###########################################################
# CTgradeDistribution
###########################################################
###########################################################
###########################################################
proc CTgradeDistribution { num classpath setId } {
    set filename [file join $classpath records "set$setId.db"]
    if { ! [file readable $filename] } { 
	CTputs $num "FILE: $filename does not exist!\n"
	return
    }
    
    displayStatus "Analyzing [file tail $filename]" both $num
    set maxLine [lindex [exec wc $filename] 0]
    set fileId [open "$filename" "r"]
    set valid_cnt 0
    set line_cnt 0
    set aline [gets $fileId]
    while {![eof $fileId]} {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	if { $line_cnt == 2 } { 
	    set aline [string trim $aline]
	    set weights [split $aline {}]	
	    set valid_weights 0	
	    foreach weight $weights { incr valid_weights $weight }
	    for { set i 0 } { $i <= $valid_weights } { incr i } { 
		set total_score($i) 0
	    }
	} elseif { $line_cnt > 3} {
	    set aline [string trim $aline]
	    set prefix [lindex [split $aline ","] 0]
	    set s_num [string toupper [lindex [split $aline " " ] 0 ] ]
	    set ans_str [lindex [split $prefix " "] 1]
	    set ans_char [split $ans_str {} ]
	    set valid 0
	    for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		if { [lindex $ans_char $ii] != "-"} { set valid 1 }
	    }
	    if { $valid } { 
		incr valid_cnt
		set score 0
		for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		    if { [lindex $ans_char $ii] == "Y" || \
			 [lindex $ans_char $ii] == "y" } {
			incr score [lindex $weights $ii]
		    }
		    if { [lindex $ans_char $ii] >= 0 && \
			     [lindex $ans_char $ii] <= 9 } {
			incr score [lindex $ans_char $ii]
		    }
		}
		if { [catch {incr total_score($score)} ] } {
		    puts "$aline:$prefix:$s_num:$ans_str:$ans_char"
		}
		
	    }
	}
	set aline [gets $fileId]
    }
    close $fileId
    removeStatus $num
    displayStatus "Pondering data . . ." spinner $num
    CTputs $num " There are $valid_cnt entries in file $filename\n"
    CTputs $num "Score #achieved\n"
    set scorelist ""
    foreach score [lsort -integer [array names total_score]] {
	CTputs $num [format "%5d:%6d\n" $score $total_score($score)]
	lappend scorelist [list $total_score($score) $score]
    }
    removeStatus $num
    return $scorelist
}

###########################################################
# CTgetStudentScores
###########################################################
###########################################################
###########################################################
proc CTgetStudentScores { studentScoresVar classpath setId num } {
    upvar $studentScoresVar studentScores

    set filename [file join $classpath records "set$setId.db"]
    if { ! [file readable $filename] } { 
	CTputs $num "FILE: $filename does not exist!\n"
	error
    }
    
    displayStatus "Analyzing [file tail $filename]" both $num
    set maxLine [lindex [exec wc $filename] 0]
    set fileId [open "$filename" "r"]
    set valid_cnt 0
    set line_cnt 0
    set aline [gets $fileId]
    set aline [gets $fileId]
    set weights [split [string trim $aline] {}]
    set valid_weights 0	
    foreach weight $weights { incr valid_weights $weight }
    set aline [gets $fileId]
    set aline [gets $fileId]
    while {![eof $fileId]} {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	set aline [string trim $aline]
	set prefix [lindex [split $aline ","] 0]
	set s_num [string toupper [lindex [split $aline " " ] 0 ] ]
	set ans_str [lindex [split $prefix " "] 1]
	set ans_char [split $ans_str {} ]
	set valid 0
	for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
	    if { [lindex $ans_char $ii] != "-"} { set valid 1 }
	}
	if { $valid } { 
	    incr valid_cnt
	    if {[array names studentScores $s_num] == ""} {set studentScores($s_num) 0}
	    for { set ii 0 } { $ii < [llength $ans_char] } { incr ii } {
		if { [lindex $ans_char $ii] == "Y" || [lindex $ans_char $ii] == "y" } {
		    incr studentScores($s_num) [lindex $weights $ii]
		}
		if { [lindex $ans_char $ii] >= 0 && [lindex $ans_char $ii] <= 9 } {
		    incr studentScores($s_num) [lindex $ans_char $ii]
		}
	    }
	}
	set aline [gets $fileId]
    }
    close $fileId
    removeStatus $num
    return $valid_weights
}

###########################################################
# CTgradeDistributionRange
###########################################################
###########################################################
###########################################################
proc CTgradeDistributionRange { num classpath setIdstart setIdend } {
    set totalpoints 0
    for {set setId $setIdstart} {$setId <= $setIdend} {incr setId} {
	set points [CTgetStudentScores studentScores $classpath $setId $num]
	incr totalpoints $points 
#	parray studentScores
    }

    displayStatus "Pondering data . . ." spinner $num
    for { set i 0 } { $i <= $totalpoints } { incr i } { 
	set total_score($i) 0
    }
    foreach sNum [array names studentScores] { incr total_score($studentScores($sNum)) }
    CTputs $num "Scores #achieved\n"
    set scorelist ""
    foreach score [lsort -integer [array names total_score]] {
	CTputs $num [format "%5d:%6d\n" $score $total_score($score)]
	lappend scorelist [list $total_score($score) $score]
    }
    removeStatus $num
    return $scorelist
}

#common Input dialogs

#common output methods
proc CTdatestamp { cmdnum } {
    CTputs $cmdnum [clock format [clock seconds]]\n
}

###########################################################
# CTputs
###########################################################
###########################################################
###########################################################
proc CTputs { num message {tag normal} } {
    global gCT

    lappend gCT(output.$num) [list $message $tag]
}

###########################################################
# CToutputWrap
###########################################################
###########################################################
###########################################################
proc CToutputWrap { num } {
    global gCT 
    if { $gCT($num.wrap) } {
	$gCT($num.output) configure -wrap char
    } else {
	$gCT($num.output) configure -wrap none
    }
}

###########################################################
# CToutput
###########################################################
###########################################################
###########################################################
proc CToutput { num cmdnum } {
    global gCT 
    
    if { ![winfo exists $gCT($num).output] } {
	set outputWin [toplevel $gCT($num).output]
	
	set buttonFrame [frame $outputWin.button]
	set textFrame [frame $outputWin.text]
	set bottomFrame [frame $outputWin.bottom]
	pack $buttonFrame $textFrame $bottomFrame
	pack configure $buttonFrame -anchor e -expand 0 -fill x
	pack configure $textFrame -expand 1 -fill both
	pack configure $bottomFrame -expand 0 -fill x

	set gCT($num.output) [text $textFrame.text \
				  -yscrollcommand "$textFrame.scroll set" \
				  -xscrollcommand "$bottomFrame.scroll set"]
	scrollbar $textFrame.scroll -command "$textFrame.text yview"
	pack $gCT($num.output) $textFrame.scroll -side left
	pack configure $textFrame.text -expand 1 -fill both
	pack configure $textFrame.scroll -expand 0 -fill y

	scrollbar $bottomFrame.scroll -command "$textFrame.text xview" -orient h
	pack $bottomFrame.scroll -expand 0 -fill x

	set gCT($num.wrap) 1
	checkbutton $buttonFrame.wrap -text "Wrap" -command "CToutputWrap $num" \
	    -variable gCT($num.wrap) 
	button $buttonFrame.save -text "Save Text" -command "CTsaveText $num"
	button $buttonFrame.print -text "Print Text" -command "CTprintText $num"
	button $buttonFrame.dismiss -text "Dismiss" -command "destroy $outputWin"
	pack $buttonFrame.wrap $buttonFrame.save $buttonFrame.print \
	    $buttonFrame.dismiss -side left
    }
    set index [$gCT($num.output) index end-1c]
    foreach line $gCT(output.$cmdnum) {
	eval $gCT($num.output) insert end $line
    }
    unset gCT(output.$cmdnum)
    raise $gCT($num).output
    $gCT($num.output) see $index
    update idletasks
}

###########################################################
# CTsaveText
###########################################################
# saves the contents of a text window
###########################################################
# Arguments: num (the unique number of the path, and window)
# Returns  : nothing
# Globals  :
###########################################################
proc CTsaveText { num } {
    global gFile gCT

    set window $gCT($num.output) 
    if {![winfo exists $window]} { return }
    set dir $gFile($num)
    set file ""
    
    if { $dir == "" || $dir == "."} { set dir [pwd] }
    set file [tk_getSaveFile -title "Enter the name to Save As" \
		  -initialdir "$dir" ]
    if { $file == "" } {
	displayError "File not saved"
	return
    }
    set fileId [open $file w]
    puts -nonewline $fileId [$window get 0.0 end-1c]
    close $fileId
}

###########################################################
# CTprintText
###########################################################
# prints the contents of the text window, creates a temp file named
# quiztemp.txt
###########################################################
# Arguments: num (the unique number of the path, and window)
# Returns  : nothing
# Globals  : gFile gCT
###########################################################
proc CTprintText { num } {
    global gFile gCT

    set window $gCT($num.output) 
    if { ![winfo exists $window]} { return }
    catch {parseCapaConfig $num $gFile($num)}
    set lprCommand [getLprCommand [file join $gFile($num) managertemp.txt] $num]
    if {$lprCommand == "Cancel"} { return }
  
    set fileId [open [file join $gFile($num) managertemp.txt] w]
    puts -nonewline $fileId [$window get 0.0 end-1c]
    close $fileId

    set errorMsg ""
    if { [catch {set output [ eval "exec $lprCommand" ] } errorMsg ]} {
        displayError "An error occurred while printing: $errorMsg"
    } else {
	displayMessage "Print job sent to the printer.\n $output"
    }
    exec rm -f [file join $gFile($num) mangertemp.txt]
}

###########################################################
# CTprintCanvas
###########################################################
###########################################################
###########################################################
proc CTprintCanvas { num window path } {

    if { ![winfo exists $window]} { return }
    catch {parseCapaConfig $num $gFile($num)}
    set lprCommand [getLprCommand [file join $path managertemp.txt] $num]
    if {$lprCommand == "Cancel"} { return }
  
    set rotate 0
    if { [tk_messageBox -title "Print in landscape mode" -message "Would you like to print in landscape mode?" -icon question -type yesno] == "yes" } { set rotate 1 }
    $window postscript -file [file join $path managertemp.txt] -rotate $rotate

    set errorMsg ""
    if { [catch {set output [ eval "exec $lprCommand" ] } errorMsg ]} {
        displayError "An error occurred while printing: $errorMsg"
    } else {
	displayMessage "Print job sent to the printer.\n $output"
    }
    exec rm -f [file join $path mangertemp.txt]
}

###########################################################
# CTsaveCanvas
###########################################################
###########################################################
###########################################################
proc CTsaveCanvas { window path } {
    if { ![winfo exists $window] } { return }
    set dir $path
    set file ""
    
    if { $dir == "" } { set dir [pwd] }
    set file [tk_getSaveFile -title "Enter the name to Save As" \
		  -initialdir "$dir" ]
    if { $file == "" } {
	displayError "File not saved"
	return
    }
    $window postscript -file $file
}

###########################################################
# CTbargraph
###########################################################
###########################################################
###########################################################
proc CTbargraph {window num barnum data {path ""} {title "" } {xlabel ""} {ylabel ""}
		 {suffix ""} } {
    global gBarGraph
    set height 300
    set width 500
    
    global gWindowMenu

    set bargraph [toplevel $window.bargraph$barnum]
    if { $title != "" } { wm title $bargraph $title }
    $gWindowMenu add command -label "$title $barnum" -command "capaRaise $bargraph"

    set buttonFrame [frame $bargraph.buttons]
    set canvasFrame [frame $bargraph.canvas]
    pack $buttonFrame $canvasFrame -side top
    pack configure $canvasFrame -expand 1 -fill both

    set canvas [canvas $canvasFrame.canvas -height $height -width $width -background white]
    pack $canvas -expand 1 -fill both
    bind $canvas <Configure> "CTdrawBargraph $barnum"

    button $buttonFrame.change -text "Change Graph" -command "CTchangeBargraph $window $barnum"
    button $buttonFrame.save -text "Save Graph" -command "CTsaveCanvas $canvas $path"
    button $buttonFrame.print -text "Print Graph" -command "CTprintCanvas $num $canvas $path"
    button $buttonFrame.dismiss -text "Dismiss" -command "CTdestroyBargraph $barnum"
    pack $buttonFrame.change $buttonFrame.save $buttonFrame.print \
	$buttonFrame.dismiss -side left
    bind $bargraph <Destroy> "CTdestroyBargraph $barnum"

    set gBarGraph($barnum.num) $num
    set gBarGraph($barnum.suffix) $suffix
    set gBarGraph($barnum) $data
    set gBarGraph($barnum.canvas) $canvas
    set gBarGraph($barnum.title) $title
    set gBarGraph($barnum.xlabel) $xlabel
    set gBarGraph($barnum.ylabel) $ylabel
    set gBarGraph($barnum.color) green
    set gBarGraph($barnum.bucketscores) 0
    set gBarGraph($barnum.ymax) [CTautoscaleBargraph $barnum]
    set gBarGraph($barnum.ymaxold) $gBarGraph($barnum.ymax)
    CTdrawBargraph $barnum
}

###########################################################
# CTmaxBargraph
###########################################################
###########################################################
###########################################################
proc CTmaxBargraph { barnum } {
    global gBarGraph

    set data $gBarGraph($barnum)
    set total [llength $data]
    set howoften $gBarGraph($barnum.xoften)
    set when [expr ($total-1)%$howoften]
    set max 0
    set i 0
    set value 0
    if { $gBarGraph($barnum.bucketscores) } {
	foreach datum $data {
	    set value [expr {$value + [lindex $datum 0]}]
	    if { $i % $howoften == $when } {
		if { $value > $max } { set max $value }
		set value 0
	    }
	    incr i
	}
    } else {
	set max [lindex [lindex [lsort -decreasing -index 0 -real $data] 0] 0]
    }
    if { $max > int($max) } { set max [expr int($max+1)] }
    set gBarGraph($barnum.ymaxold) [set gBarGraph($barnum.ymax) $max]
    return $max
}

proc CTsort { arg1 arg2 } {
    set arg1 [eval expr [join [lindex $arg1 0] +]]
    set arg2 [eval expr [join [lindex $arg2 0] +]]
    if { $arg1 < $arg2 } { return -1 }
    if { $arg1 > $arg2 } { return 1 }
    return 0
}

###########################################################
# CTautoscaleBargraph
###########################################################
###########################################################
###########################################################
proc CTautoscaleBargraph { barnum } {
    global gBarGraph
    set data $gBarGraph($barnum)
    if { [catch {set max [lindex [lindex [lsort -decreasing -index 0 -real $data] 0] 0]}] } {
	set max [lindex [lindex [lsort -decreasing -command CTsort $data] 0] 0]
	set max [eval expr [join $max +]]
    }
    if { $max > int($max) } { set max [expr int($max+1)] }
    set gBarGraph($barnum.yoften) [expr int([format "%1.e" [expr $max/10.0]])]
    if { $gBarGraph($barnum.yoften) == 0 } { set gBarGraph($barnum.yoften) 1 }
    set total [llength $data]
    set gBarGraph($barnum.xoften) [expr ($total/25) + 1]
    return $max
}

###########################################################
# CTchangeBargraphData
###########################################################
###########################################################
###########################################################
proc CTchangeBargraphData { barnum data } {
    global gBarGraph
    set gBarGraph($barnum) $data
    set gBarGraph($barnum.ymax) [CTautoscaleBargraph $barnum]
    set gBarGraph($barnum.ymaxold) $gBarGraph($barnum.ymax)
    CTdrawBargraph $barnum
}

###########################################################
# CTdestroyBargraph
###########################################################
###########################################################
###########################################################
proc CTdestroyBargraph { num } {
    global gBarGraph
    
    if { [catch {set window [winfo toplevel $gBarGraph($num.canvas)]}]} { return }
    set window2 [file rootname $window].changeBarGraph$num
    foreach name [array names gBarGraph "$num.*" ] {
	unset gBarGraph($name)
    }
    unset gBarGraph($num)
    destroy $window 
    catch {destroy $window2}
}

###########################################################
# CTdrawBargraph
###########################################################
###########################################################
###########################################################
proc CTdrawBargraph { num } {
    global gBarGraph

    set data $gBarGraph($num)
    set canvas $gBarGraph($num.canvas)
    set suffix $gBarGraph($num.suffix)

    set height [winfo height $canvas]
    set width [winfo width $canvas]
    set titleoffset 0
    set titleheight 15
    set labelheight 15
    set tickheight 15
    set textheight [expr $labelheight+$tickheight]
    set textwidth 40
    set graphheight [expr $height - $textheight - $titleheight]
    set graphwidth [expr $width - $textwidth]
    $canvas delete all

    #draw data
    set total [llength $data]
    set eachwidth [expr $graphwidth/$total]
#    set howoften [expr ($total/$gBarGraph($num.numlabels)) + 1]
    set howoften $gBarGraph($num.xoften)
    set when [expr ($total-1)%$howoften]
    set max 0
    set i 0
    set value 0
    if { $gBarGraph($num.bucketscores) } {
	foreach datum $data {
	    set value [eval expr $value + [join [lindex $datum 0] +]]
	    if { $i % $howoften == $when } {
		if { $value > $max } { set max $value }
		set value 0
	    }
	    incr i
	}
    } else {
	if { [catch {set max [lindex [lindex [lsort -decreasing -index 0 -real $data] 0] 0]}] } {
	    set max [lindex [lindex [lsort -decreasing -command CTsort $data] 0] 0]
	    set max [eval expr [join $max +]]
	}
    }
    if { $max > int($max) } { set max [expr int($max+1)] }
    if { $gBarGraph($num.ymaxold) != $gBarGraph($num.ymax) } { 
	set max $gBarGraph($num.ymax)
    }
    if { [catch {set pixelvalue [expr ($graphheight-1)/double($max)]} ] } {
	set pixelvalue 10
    }

    set i 0
    set value 0
    foreach datum $data {
#	puts ":$datum:"
	if { [llength [lindex $datum 0]] == 1 } {
	    set value [expr {$value + [lindex $datum 0]}]
	    CTdrawBargraphBar
	    incr i
	} else {
	    set value [eval expr $value + [join [lindex $datum 0] +]]
	    CTdrawBargraphBarN
	    incr i
	}
    }
#    puts "value:$value:"

    #draw title
    $canvas create text [expr $textwidth+$titleoffset+($graphwidth/2)] 1 -anchor n\
	-text $gBarGraph($num.title)
    #draw axis
    $canvas create line $textwidth [expr {$graphheight + $titleheight}] \
	$textwidth [expr {$titleheight + 1}]
    #label xaxis
    $canvas create text [expr ($textwidth+($graphwidth/2))] \
	[expr $titleheight+$graphheight+$tickheight+($labelheight/2)] \
	-text $gBarGraph($num.xlabel)
    #label yaxis
    $canvas create text 1 1 -anchor nw -text $gBarGraph($num.ylabel)
    #draw tickmarks
#    set delta [format "%1.e" [expr ($max)/double($gBarGraph($num.numticks))]]
    set delta $gBarGraph($num.yoften)
    set start 0.0
    while { $start < $max } {
	set center [expr {($graphheight-1)*(($start)/$max)+$titleheight+1}]
	$canvas create line $textwidth $center [expr $textwidth - 20] $center
	$canvas create text [expr $textwidth-3] $center -anchor ne -text [expr int($max-$start)]
	set start [expr $start + $delta]
    }
    if { [llength [lindex $data 0]] > 2} {
	$canvas bind current <1> "CTbargraphClick$suffix $num"
	bind $canvas <Enter> "CTbargraphDisplayCreate $num"
	bind $canvas <Leave> "CTbargraphDisplayRemove $num"
	bind $canvas <Motion> "CTbargraphDisplayMove $num"
	$canvas bind all <Enter> "CTbargraphDisplay$suffix $num"
    }
}

proc CTdrawBargraphBar { } {
    global gBarGraph
    uplevel 1 {
	set canvas $gBarGraph($num.canvas)
	
	set which [lindex $datum 1]
	set y1 [expr {$graphheight + $titleheight}]
	set x2 [expr {$eachwidth * ($i+1) + $textwidth}] 
	set y2 [expr {($graphheight-1) + $titleheight - $value * $pixelvalue}]
	set tag bar.$which.[expr $which-$howoften]
	if { [set color [lindex $datum 3]] == "" } {set color $gBarGraph($num.color)}
	if { $gBarGraph($num.bucketscores) && ($i % $howoften == $when) } {
	    if { $i == $when } {
		#		puts "$value-$which-$howoften"
		$canvas create rectangle $textwidth \
		    $y1 $x2 $y2 -fill $color -tag $tag
	    } else {
		#		puts "$value:$which:$howoften"
		$canvas create rectangle [expr {$eachwidth*($i-$howoften+1)+$textwidth}]\
		    $y1 $x2 $y2 -fill $color -tag $tag
	    }
	} elseif { !$gBarGraph($num.bucketscores) } {
	    $canvas create rectangle [expr {$eachwidth * $i + $textwidth}] \
		$y1 $x2 $y2 -fill $color -tag bar.$which.[expr $which-1]
	    set value 0
	}
	if { $i % $howoften == $when } {
	    $canvas create text [expr {$eachwidth * $i + $textwidth + $eachwidth/2}] \
		[expr $graphheight+(($tickheight)/2)+$titleheight] -text $which
	    set value 0
	}
    }
}

proc CTdrawBargraphBarN { } {
    global gBarGraph
    uplevel 1 {
	set canvas $gBarGraph($num.canvas)
	
	set which [lindex $datum 1]
	set y1 [expr {$graphheight + $titleheight}]
	set x2 [expr {$eachwidth * ($i+1) + $textwidth}] 
	set tag bar.$which.[expr $which-$howoften]
	set subpoint 0
	for {set j 0} {$j < [llength [lindex $datum 0]]} {incr j} {
	    set subpointincr [lindex [lindex $datum 0] $j]
	    if { $subpointincr == 0 } { continue }
	    incr subpoint $subpointincr
	    set y2 [expr {($graphheight-1) + $titleheight - $subpoint * $pixelvalue}]
	    set tag bar.$which.[expr $which-$howoften].$j
	    if { [set color [lindex [lindex $datum 3] $j]] == ""}  {
		set color $gBarGraph($num.color)
	    }
	    if { $gBarGraph($num.bucketscores) && ($i % $howoften == $when) } {
		if { $i == $when } {
		    #		puts "$value-$which-$howoften"
		    $canvas create rectangle $textwidth \
			$y1 $x2 $y2 -fill $color -tag $tag
		} else {
		    #		puts "$value:$which:$howoften"
		    $canvas create rectangle [expr {$eachwidth*($i-$howoften+1)+$textwidth}]\
			$y1 $x2 $y2 -fill $color -tag $tag
		}
	    } elseif { !$gBarGraph($num.bucketscores) } {
		set x1 [expr {$eachwidth * $i + $textwidth}]
#		puts "y:$y1:$y2:x:$x1:$x2:subpoint:$subpoint"
		$canvas create rectangle [expr {$eachwidth * $i + $textwidth}] \
		    $y1 $x2 $y2 -fill $color -tag bar.$which.[expr $which-1].$j
		set value 0
	    } else {
		break
	    }
	    set y1 $y2
	}
	if { $i % $howoften == $when } {
	    $canvas create text [expr {$eachwidth * $i + $textwidth + $eachwidth/2}] \
		[expr $graphheight+(($tickheight)/2)+$titleheight] -text $which
	    set value 0
	}
    }
}

###########################################################
# CTbargraphDisplayCreate
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplayCreate { barnum } {
    global gBarGraph gCT gFile
    set canvas $gBarGraph($barnum.canvas)
    if {[winfo exists $canvas.bubble$barnum]} { return }
    set bubble [toplevel $canvas.bubble$barnum]
    wm overrideredirect $bubble 1
    wm positionfrom $bubble program
    wm withdraw $bubble
    pack [label $bubble.l -highlightthickness 0 -relief raised -bd 1 -background yellow]
}
###########################################################
# CTbargraphDisplayRemove
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplayRemove { barnum } {
    global gBarGraph gCT gFile
    set canvas $gBarGraph($barnum.canvas)
    catch {destroy $canvas.bubble$barnum}
}
###########################################################
# CTbargraphDisplayBlank
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplayBlank { barnum } {
    global gBarGraph gCT gFile
    set canvas $gBarGraph($barnum.canvas)
    catch {$canvas.bubble$barnum.l configure -text ""}
}
###########################################################
# CTbargraphDisplayMove
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplayMove { barnum } {
    global gBarGraph gCT gFile
    set canvas $gBarGraph($barnum.canvas)
    catch {wm geometry $canvas.bubble$barnum +[expr 20+[winfo pointerx .]]+[expr 20+[winfo pointery .]]}
    if {[$canvas gettags current] == ""} {CTbargraphDisplayRemove $barnum}
}
###########################################################
# CTbargraphDisplayShowresponse
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplayShowresponse { barnum } {
    global gBarGraph gCT gFile
    set num $gBarGraph($barnum.num)
    set canvas $gBarGraph($barnum.canvas)
    
    set tags [split [lindex [$canvas gettags current] 0] .]
    set high [lindex $tags 1]
    set subpoint [lindex $tags 3]
    foreach datum $gBarGraph($barnum) {
	set bar [lindex $datum 1]
	if { $bar != $high } { continue }
	if {![winfo exists $canvas.bubble$barnum.l]} {CTbargraphDisplayCreate $barnum}
	if { [llength [lindex $datum 0]] == 1 } {
	    $canvas.bubble$barnum.l configure -text "[lindex $datum 0] - \"[splitline [lindex $datum 2] 35]\""
	} else {
	    set point [lindex [lindex $datum 0] $subpoint]
	    set text [lindex [lindex $datum 2] $subpoint]
	    $canvas.bubble$barnum.l configure -text "$point - \"[splitline $text 35]\""
	}
	wm geometry $canvas.bubble$barnum +[expr 20+[winfo pointerx .]]+[expr 20+[winfo pointery .]]
	wm deiconify $canvas.bubble$barnum
	return
    }
    CTbargraphDisplayRemove $barnum
}
###########################################################
# CTbargraphDisplaySCP
###########################################################
###########################################################
###########################################################
proc CTbargraphDisplaySCP { barnum } {
    global gBarGraph gCT gFile
    set num $gBarGraph($barnum.num)
    set canvas $gBarGraph($barnum.canvas)
    
    set high [lindex [split [lindex [$canvas gettags current] 0] .] 1]
    foreach datum $gBarGraph($barnum) {
	set bar [lindex $datum 1]
	if { $bar != $high } { continue }
	if {![winfo exists $canvas.bubble$barnum.l]} {CTbargraphDisplayCreate $barnum}
	$canvas.bubble$barnum.l configure -text "[lindex $datum 0]"
	wm geometry $canvas.bubble$barnum +[expr 20+[winfo pointerx .]]+[expr 20+[winfo pointery .]]
	wm deiconify $canvas.bubble$barnum
	return
    }
    CTbargraphDisplayRemove $barnum
}

###########################################################
# CTbargraphClickSCP
###########################################################
###########################################################
###########################################################
proc CTbargraphClickSCP { barnum } {
    global gBarGraph gCT gFile

    set num $gBarGraph($barnum.num)
    set canvas $gBarGraph($barnum.canvas)
    set bucket $gBarGraph($barnum.bucketscores)
    
    set high [lindex [split [lindex [$canvas gettags current] 0] .] 1]
    set low [lindex [split [lindex [$canvas gettags current] 0] .] 2]
    set stunums ""
    if { $high == "" || $low == "" } { return }
    foreach datum $gBarGraph($barnum) {
	set bar [lindex $datum 1]
	if { $bar > $high || $bar <= $low } { continue }
	set stunums [concat $stunums [lindex $datum 2]]
    }
    if { $stunums == "" } { return }
    if {"" == [set stuSCP [multipleChoice $gCT($num) "Select a student" $stunums 0]]} {
	return 
    }
    set loginAnalysis [expr {"Yes" == [makeSure "Do you wish to do a Login Analysis? It may take a while." ]}]
    foreach s_id $stuSCP {
	CTstudentCourseProfile $num $s_id \
	    [findByStudentNumber $s_id $gFile($num)] $loginAnalysis
    }
}

###########################################################
# CTbargraphClickShowresponse
###########################################################
###########################################################
###########################################################
proc CTbargraphClickShowresponse { barnum } {
    global gBarGraph gCT gFile gUniqueNumber

    set num $gBarGraph($barnum.num)
    set canvas $gBarGraph($barnum.canvas)
    set bucket $gBarGraph($barnum.bucketscores)
    
    if { [catch {set datanum $gBarGraph($barnum.shownum1)}] } {
	set datanum [set gBarGraph($barnum.shownum1) [incr gUniqueNumber]]
	set winnum [set gBarGraph($barnum.shownum2) [incr gUniqueNumber]]
    } else {
	set winnum $gBarGraph($barnum.shownum2) 
    }
    set gCT($winnum) ""
    set high [lindex [split [lindex [$canvas gettags current] 0] .] 1]
    foreach datum $gBarGraph($barnum) {
	set bar [lindex $datum 1]
	if { $bar != $high } { continue }
	CTputs $datanum "[lindex $datum 0] responses \"[lindex $datum 2]\"\n"
    }    
    CToutput $winnum $datanum
} 

###########################################################
# CTchangeBargraph
###########################################################
###########################################################
###########################################################
proc CTchangeBargraph { window num } {
    global gBarGraph
    
    set change [toplevel $window.changeBarGraph$num]
    
    set infoFrame [frame $change.info]
    set buttonFrame [frame $change.button]
    set title [frame $change.title]
    set xlabel [frame $change.xlabel]
    set ylabel [frame $change.ylabel]
    set xoften [frame $change.xoften]
    set yoften [frame $change.yoften]
    set ymax   [frame $change.ymax]
    set color [frame $change.color]
    set bucket [frame $change.bucket]
    set font [frame $change.font]
    pack $infoFrame $buttonFrame $title $xlabel $ylabel $xoften $yoften $ymax \
	$color $bucket
    pack configure $title $xlabel $ylabel $xoften $yoften -anchor e -expand 1 -fill both
    button $buttonFrame.update -text Update -command "CTdrawBargraph $num"
    bind $change <Return> "CTdrawBargraph $num"
    button $buttonFrame.dismiss -text Dismiss -command "destroy $change"
    pack $buttonFrame.update $buttonFrame.dismiss -side left

    foreach {frame label var
    } "$title     {              Title} title 
       $xlabel    {       X-Axis Label} xlabel 
       $ylabel    {       Y-Axis Label} ylabel 
       $xoften    {Increment on X-Axis} xoften 
       $yoften    {Increment on Y-Axis} yoften
       $ymax      {        Max Y-Value} ymax" {
	label $frame.label -text $label
	set entryFrame [frame $frame.entry]
	pack $frame.label $entryFrame -side left
	pack configure $entryFrame -expand 1 -fill both
	entry $entryFrame.entry -textvariable gBarGraph($num.$var) \
	    -xscrollcommand "$entryFrame.scroll set"
	scrollbar $entryFrame.scroll -orient h -command \
	    "$entryFrame.entry xview"
	pack $entryFrame.entry $entryFrame.scroll -fill x
    }

    label $color.label -text "Color of Bars"
    label $color.color -relief ridge -background $gBarGraph($num.color) \
	-text "        "
    button $color.change -text "Change" -command "CTchangeBargraphColor $color $num"
    pack $color.label $color.color $color.change -side left
    
    checkbutton $bucket.bucket -text "Bucket Scores" -variable \
	gBarGraph($num.bucketscores) -command "CTmaxBargraph $num;CTdrawBargraph $num"
    pack $bucket.bucket
}

###########################################################
# CTchangeBargraphColor
###########################################################
###########################################################
###########################################################
proc CTchangeBargraphColor { color num } {
    global gBarGraph
    set temp [tk_chooseColor -initialcolor $gBarGraph($num.color)]
    if { $temp != "" } {
	$color.color configure -background [set gBarGraph($num.color) $temp]
    }
    CTdrawBargraph $num
}

###########################################################
# CTdisplayStudent
###########################################################
###########################################################
###########################################################
proc CTdisplayStudent { num window path id } {
    
    if { ![file exists [file join $path photo gif $id.gif]] } {
	if { [file exists [file join $path photo jpg $id.jpg]] } {
	    exec /usr/local/bin/djpeg -outfile [file join $path photo gif $id.gif] \
		[file join $path photo jpg $id.jpg]
	} else {
	    return
	}
    }
    set image [image create photo]
    $image read [file join $path photo gif $id.gif]

    set imageWin [toplevel $window.image$num]
    
    set buttonFrame [frame $imageWin.button]
    set infoFrame [frame $imageWin.info]
    set imageFrame [frame $imageWin.image]
    pack $buttonFrame $infoFrame $imageFrame

    button $buttonFrame.dismiss -command "destroy $imageWin" -text Dismiss
    pack $buttonFrame.dismiss

    label $infoFrame.label -text $id
    pack $infoFrame.label
    
    set height [image height $image]
    set width [image width $image]
    set canvas [canvas $imageFrame.canvas -height $height -width $width]
    pack $canvas
    $canvas create image 1 1 -image $image -anchor nw
}

proc updateDate { type cmdnum args } {
    global gDateStart gDateEnd
    switch $type {
	start { set gDateStart($cmdnum.text) [clock format $gDateStart($cmdnum) -format "%a %b %d %R %Y"] }
	end { set gDateEnd($cmdnum.text) [clock format $gDateEnd($cmdnum) -format "%a %b %d %R %Y"] }
    }
}

###########################################################
# CTgetWhen
###########################################################
###########################################################
###########################################################
proc CTgetWhen { num cmdnum setId } {
    global gFile gCT gPromptGDR

    catch {set firstsection [exec head [file join $gFile($num) records log$setId.db]]}
    catch {append firstsection [exec head [file join $gFile($num) records weblog$setId.db]]}
    catch {set lastsection [exec tail [file join $gFile($num) records log$setId.db]]}
    catch {append lastsection [exec tail [file join $gFile($num) records weblog$setId.db]]}

    set earliest -1
    foreach line [split $firstsection \n] {
	if { [catch {set date [clock scan [string range $line 10 33]]}]} {set date -1}
	#puts "$date $earliest"
	if { $earliest == -1 } { set earliest $date }
	if { $date < $earliest } { set earliest $date }
    }
    if { $earliest == -1 } { 
	catch {
	    file stat [file join $gFile($num) records log$setId.db] stat
	    set earliest $stat(ctime)
	}
	catch {
	    file stat [file join $gFile($num) records log$setId.db] stat
	    if {($earliest ==-1) || ($stat(ctime) < $earliest)} {
		set earliest $stat(ctime)
	    }
	}
    }
    set latest 0 
    foreach line [split $lastsection \n] {
	if { [catch {set date [clock scan [string range $line 10 33]]}]} {set date 0}
	#puts "$date $latest"
	if { $latest == 0 } { set latest $date }
	if { $date > $latest } { set latest $date }
    }
    if { $latest == 0 } { 
	catch {
	    file stat [file join $gFile($num) records log$setId.db] stat
	    set latest $stat(mtime)
	}
	catch {
	    file stat [file join $gFile($num) records log$setId.db] stat
	    if { $latest == 0 } { set latest $date }
	    if { $stat(mtime) > $latest } { set latest $date }
	}
    }
    #puts "$latest $earliest"

    set window $gCT($num)
    set setWin [toplevel $window.setselect]
    
    set msgFrame [frame $setWin.msgFrame]
    set valFrame [frame $setWin.calFrame]
    set buttonFrame [frame $setWin.buttonFrame]
    pack $msgFrame $valFrame $buttonFrame

    message $msgFrame.msg -text "Please select a date range:" -aspect 1000
    pack $msgFrame.msg
    
    global gDateStart gDateEnd
    trace variable gDateStart($cmdnum) w "updateDate start $cmdnum"
    trace variable gDateEnd($cmdnum) w "updateDate end $cmdnum"
    label $valFrame.l1 -textvariable gDateStart($cmdnum.text)
    scale $valFrame.start -from $earliest -to $latest -variable gDateStart($cmdnum) -orient h -showvalue 0 -resolution 600 -bigincrement 6000 -length 300
    label $valFrame.l2 -textvariable gDateEnd($cmdnum.text)
    scale $valFrame.end -from $earliest -to $latest -variable gDateEnd($cmdnum) -orient h -showvalue 0 -resolution 600 -bigincrement 6000 -length 300
    pack $valFrame.l1 $valFrame.start $valFrame.l2 $valFrame.end

    button $buttonFrame.select -text "Select" -command { set gPromptGDR(ok) 1 }
    button $buttonFrame.cancel -text "Cancel" -command { set gPromptGDR(ok) 0 }
    pack $buttonFrame.select $buttonFrame.cancel -side left

    bind $setWin <Return> "set gPromptGDR(ok) 1"
    Centre_Dialog $setWin default
    update idletasks
    focus $setWin
    capaRaise $setWin
    capaGrab $setWin
    vwait gPromptGDR(ok)
    capaGrab release $setWin
    destroy $setWin
    if { $gPromptGDR(ok) == 1 } {
	set dateStart $gDateStart($cmdnum)
	set dateEnd $gDateEnd($cmdnum)
	if { $dateStart > $dateEnd } { 
	    set temp $dateStart
	    set dateStart $dateEnd
	    set dateEnd $temp 
	}
	unset gDateStart
	unset gDateEnd
	return [list $dateStart $dateEnd]
    } else {
	unset gDateStart
	unset gDateEnd
	return ""
    }
}

###########################################################
# CTscanDB
###########################################################
###########################################################
###########################################################
proc CTscanDB { num file outId startdate enddate } {
    global answerArray exist
    if {[catch {set fileId [open $file r]}]} { return 0 }
    set Yes_cnt 0 
    set No_cnt 0
    set line_cnt 0
    set prob_cnt 0
    set maxLine [lindex [exec wc $file] 0]
    #puts "maxLine: $maxLine"
    set aline [gets $fileId]
    while { ! [eof $fileId] } {
	incr line_cnt
	if { ($line_cnt%20) == 0 } {
	    #puts $curdate
	    updateStatusBar [expr $line_cnt/double($maxLine)] $num
	}
	set length [llength $aline]
	set date [lrange $aline 1 [expr $length - 2]]
	#puts $date
	set curdate [clock scan $date]
	if { $curdate < $startdate } { set aline [gets $fileId]; continue }
	if { $curdate > $enddate } { break }
	set s_num [string toupper [lindex $aline 0]]
	set ans_char [split [lindex $aline end] ""]
	set usr_ans "$s_num.ans"
	set usr_try "$s_num.try"
	if {$prob_cnt == 0} { set prob_cnt [llength $ans_char] }
	if { [catch {set exist($s_num)}] } {
	    for {set ii 0} { $ii <= $prob_cnt } { incr ii} {
		set answerArray($usr_ans.$ii) "-"
		set answerArray($usr_try.$ii) 0
	    }
	}
	for {set ii 0} { $ii <= $prob_cnt } { incr ii} {
	    switch -- [lindex $ans_char $ii] {
		Y - y {
		    set answerArray($usr_ans.$ii) "Y"
		    incr answerArray($usr_try.$ii)    
		}
		N {
		    if {$answerArray($usr_ans.$ii) != "Y"} {
			set answerArray($usr_ans.$ii) "N"
		    }
		    incr answerArray($usr_try.$ii)
		}
		default {}
	    }
	}
	if { [array names exist $s_num] == "" } { set exist($s_num) 1 }
	set aline [gets $fileId]
    }
    close $fileId
    return $prob_cnt
}

###########################################################
# CTcreateSubset
###########################################################
###########################################################
###########################################################
proc CTcreateSubset { num cmdnum startdate enddate setId } {
    global gFile gCT answerArray exist

    set outId [open [file join $gFile($num) records "subset$setId.db"] w]
    set inId [open [file join $gFile($num) records "set$setId.db"] r]
    
    #puts $startdate:$enddate
    #puts [file join $gFile($num) records log$setId.db]
    updateStatusMessage "Genearting subset1.db from telnet data." $cmdnum
    set prob_cntt [CTscanDB $cmdnum [file join $gFile($num) records log$setId.db] $outId $startdate $enddate]
    #puts $prob_cntt
    #puts $startdate:$enddate
    updateStatusMessage "Genearting subset1.db from web data." $cmdnum
    set prob_cntw [CTscanDB $cmdnum [file join $gFile($num) records weblog$setId.db] $outId $startdate $enddate]
    #puts $prob_cntw
    #puts $startdate:$enddate
#    puts "$day 12:00 AM : $day 11:59 PM"
    if { $prob_cntt > $prob_cntw } {
	set prob_cnt $prob_cntt 
    } else { 
	set prob_cnt $prob_cntw 
    }

    puts $outId [gets $inId]
    puts $outId [gets $inId]
    puts $outId [gets $inId]
    foreach s_num [lsort [array names exist]] {
	set usr_ans $s_num.ans
	set usr_try $s_num.try
	puts -nonewline $outId "$s_num "
	for { set ii 0 } { $ii< $prob_cnt } { incr ii } {
	    puts -nonewline $outId $answerArray($usr_ans.$ii)
	}
	for { set ii 0 } { $ii< $prob_cnt } { incr ii } {
	    puts -nonewline $outId [format ",%2d" $answerArray($usr_try.$ii)]
	}
	puts $outId ""
    }
    close $outId
    close $inId
    catch {unset answerArray}
    catch {unset exist}
}

###########################################################
# CTdiscussForum
###########################################################
###########################################################
###########################################################
proc CTdiscussForum { num file dir resultVar {specificSet 0}} {
    global gCT
    upvar $resultVar result

    if { $specificSet == 0 } {
	set start 1
    } else {
	set start $specificSet
    }
    set fileId [open $file r]
    set maxLine [lindex [exec wc $file] 0]
    set aline [gets $fileId]
    set last 0
    set line_cnt 0
    while {![eof $fileId]} {
	incr line_cnt
	if { ($line_cnt%20) == 0 } { updateStatusBar [expr $line_cnt/double($maxLine)] $num }
	foreach {stunum capaid name email action set prob date time blank} [split $aline "|"] {}
	if {$specificSet && ($specificSet == $set)} {set aline [gets $fileId];continue}
	if { $action == "ViewProblem" } {
	    if { [catch {incr count($set,$prob)}]} {
		set count($set,$prob) 1
		if { $set > $last } { set last $set }
		if { [catch {set max($set)}]} { set max($set) 0 }
		if { $prob > $max($set)} { set max($set) $prob }
		if { [catch {set posts($set,$prob) [llength [glob $dir/discussion/$set/[format "%06d" $prob]-*-*-*.msg]]}]} { set posts($set,$prob) 0 }
	    }
	    set ever($name) 1
	    set names($set,$name) 1
	    set nameprob($set,$prob,$name) 1
	}
	set aline [gets $fileId]
    }

    updateStatusMessage "Summarizing Data" $num
    updateStatusBar 0 $num
    for {set i 1} { $i <= $last } { incr i } {
	updateStatusBar [expr $i/$last] $num 
	set total($i) 0
	for {set j 1} { $j <= $max($i) } { incr j } {
	    set message ""
	    if {[catch { set result($num.$i.$j.posts) $posts($i,$j) }]} {
		set result($num.$i.$j.posts) 0
	    }
	    if {[catch {set result($num.$i.$j.views) $count($i,$j)}]} {
		set result($num.$i.$j.views) 0
	    } 
	    catch {incr total($i) $count($i,$j)}
	    if { [catch { set result($num.$i.$j.ratio) \
			      [expr $result($num.$i.$j.views)/double($result($num.$i.$j.posts))]} error]} {
		set result($num.$i.$j.ratio) 0.0
	    }
	    set result($num.$i.$j.viewers) [llength [array names nameprob $i,$j,*]]
	}
	set result($num.$i.views) $total($i)
	set result($num.$i.max) $max($i)
    }
    
    for {set i 1} { $i<=$last } { incr i } {
	set result($num.$i.viewers) [llength [array names names $i,*]]
    }
    close $fileId
    set result($num.viewers) [llength [array names ever]]
    set result($num.last) $last
    #IDEAS:
    #     : how many views are repeats
    #     : Student Course Profile, add #ViewProblems #Posts
    #     : add some portion of these stats to analyze log files?
}

###########################################################
# CTputsDiscussResults
###########################################################
###########################################################
proc CTputsDiscussResults { num resultsVar } {
    upvar $resultsVar result
    for {set i 1} { $i <= $result($num.last) } { incr i } {
	CTputs $num "For Set $i #Visitors:$result($num.$i.viewers) did #views:$result($num.$i.views)\n"
        CTputs $num "Prob# #Posts #Views Ratio #UniqueStu\n"
	CTputs $num "------------------------------------\n"  
	for {set j 1} { $j <= $result($num.$i.max)} { incr j } {
	    CTputs $num [format "%5d %6d %6d %5s %6d\n" $j \
			     $result($num.$i.$j.posts) $result($num.$i.$j.views) \
			     [if {$result($num.$i.$j.ratio) == 0.0} {set temp " "} \
				  {format %.1f $result($num.$i.$j.ratio)}] \
			     $result($num.$i.$j.viewers)]
	}
    }
    CTputs $num "Overall Unique #viewers: $result($num.viewers)\n"
}

###########################################################
# CTcreateReportDialog
###########################################################
###########################################################
###########################################################
proc CTcreateReportDialog { num cmdnum } {
    global gCT gFile

    
    set gCT(summary.section.$cmdnum) 1
    set gCT(summary.set.$cmdnum) 1

    set summary [toplevel $gCT($num).summary]
    set whoFrame [frame $summary.whoFrame -borderwidth 4 -relief groove]
    set whichFrame [frame $summary.whichFrame -borderwidth 4 -relief groove]
    set sortFrame [frame $summary.sortFrame]
    set file2Frame [frame $summary.file2Frame]
    set buttonFrame [frame $summary.buttonFrame]
    pack $whoFrame $whichFrame $sortFrame $file2Frame $buttonFrame -side top
    pack configure $whoFrame $whichFrame -padx 10 -pady 10

    set sectionFrame [frame $whoFrame.section]
    set allFrame [frame $whoFrame.all]
    pack $sectionFrame $allFrame -side top

    set gCT(summary.who.$cmdnum) section

    radiobutton $sectionFrame.section -text \
	    "For students in default section:" -variable gCT(summary.who.$cmdnum) \
	    -value section 
    entry $sectionFrame.entry -textvariable gCT(summary.section.$cmdnum) -width 3 
    pack $sectionFrame.section $sectionFrame.entry -side left

    radiobutton $allFrame.all -text "For all students in the class" \
	    -variable gCT(summary.who.$cmdnum) -value all 
    pack $allFrame.all

    set sectionFrame [frame $whichFrame.section]
    set allFrame [frame $whichFrame.all]
    pack $sectionFrame $allFrame -side top

    set gCT(summary.which.$cmdnum) specific

    radiobutton $sectionFrame.section -text "For set:" \
	    -variable gCT(summary.which.$cmdnum) -value specific 
    entry $sectionFrame.entry -textvariable gCT(summary.set.$cmdnum) -width 3 
    pack $sectionFrame.section $sectionFrame.entry -side left

    radiobutton $allFrame.all -text "For all sets up to:" -variable \
	    gCT(summary.which.$cmdnum) -value upto 
    entry $allFrame.entry -textvariable gCT(summary.set.$cmdnum) -width 3 
    pack $allFrame.all $allFrame.entry -side left

    set firstFrame [frame $sortFrame.firstFrame -borderwidth 4 -relief groove]
    set secondFrame [frame $sortFrame.secondFrame -borderwidth 4 \
	    -relief groove]
    pack $firstFrame $secondFrame -side left

    set gCT(summary.first.$cmdnum) name

    label $firstFrame.label -text "Sorting Order - Primary"
    radiobutton $firstFrame.name -text "Student Name" -variable \
	    gCT(summary.first.$cmdnum) -value name
    radiobutton $firstFrame.number -text "Student Number" -variable \
	    gCT(summary.first.$cmdnum) -value number
    radiobutton $firstFrame.section -text "Section" -variable \
	    gCT(summary.first.$cmdnum) -value section
    radiobutton $firstFrame.grade -text "Grade" -variable gCT(summary.first.$cmdnum) \
	    -value grade
    pack $firstFrame.label $firstFrame.name $firstFrame.number \
	    $firstFrame.section $firstFrame.grade -side top -anchor w

    set gCT(summary.second.$cmdnum) number

    label $secondFrame.label -text "Sorting Order - Secondary"
    radiobutton $secondFrame.name -text "Student Name" -variable \
	    gCT(summary.second.$cmdnum) -value name
    radiobutton $secondFrame.number -text "Student Number" -variable \
	    gCT(summary.second.$cmdnum) -value number
    radiobutton $secondFrame.section -text "Section" -variable \
	    gCT(summary.second.$cmdnum) -value section
    radiobutton $secondFrame.grade -text "Grade" -variable gCT(summary.second.$cmdnum) \
	    -value grade
    pack $secondFrame.label $secondFrame.name $secondFrame.number \
	    $secondFrame.section $secondFrame.grade -side top -anchor w

    set defaultFrame [frame $file2Frame.defaultFrame]
    set fileFrame [frame $file2Frame.fileFrame]
    pack $defaultFrame $fileFrame -side top

    set gCT(summary.filename.$cmdnum) default 

    radiobutton $defaultFrame.default -text "Grader Chooses File Name" \
	-variable gCT(summary.filename.$cmdnum) -value default
    pack $defaultFrame.default

    radiobutton $fileFrame.label -text "Specified Output File:" \
	-variable gCT(summary.filename.$cmdnum) -value specified
    set entryFrame [frame $fileFrame.entryFrame]
    button $fileFrame.select -text "Select File" \
	    -command "CTselectOutputFile $cmdnum"
    pack $fileFrame.label $entryFrame $fileFrame.select -side left
    entry $entryFrame.entry -textvariable gCT(summary.file.$cmdnum) \
	-xscrollcommand "$entryFrame.scroll set"
    scrollbar $entryFrame.scroll -orient h -command \
	    "$entryFrame.entry xview"
    pack $entryFrame.entry $entryFrame.scroll
    pack configure $entryFrame.scroll -fill x

    button $buttonFrame.create -text "Create" -command \
	    "removeWindowEntry Summary
             destroy $summary
             CTcreateSummaryReport $num $cmdnum"
    button $buttonFrame.cancel -text "Cancel" -command \
	    "removeWindowEntry Summary
             destroy $summary"
    pack $buttonFrame.create $buttonFrame.cancel -side left

    Centre_Dialog $summary default
}

###########################################################
# CTselectOutputFile
###########################################################
###########################################################
###########################################################
proc CTselectOutputFile { num } {
    global gCT
    set gCT(summary.filename.$num) specified
    if { "" != [ set temp [tk_getSaveFile] ] } {set gCT(summary.file.$num) $temp}
}    

###########################################################
# CTcreateSummaryReport
###########################################################
###########################################################
###########################################################
proc CTcreateSummaryReport { num cmdnum } {
    global gCT gFile

    displayStatus "Opening File" both $cmdnum

    switch $gCT(summary.who.$cmdnum) {
	all {
	    set file ClassSet$gCT(summary.set.$cmdnum).rpt
	}
	section	{
	    set file Sec$gCT(summary.section.$cmdnum)Set$gCT(summary.set.$cmdnum).rpt 
	}
	default	{
	    displayError "An error has occurred while creating a summary \
		    report $gCT(summary.section.$cmdnum)"
	    return
	}
    }

    if { $gCT(summary.filename.$cmdnum) == "specified" } { 
	set file $gCT(summary.file.$cmdnum)
    }
    if { $file == "" } { 
	removeStatus
	displayError "Must specify a valid filename"
	return
    }
    updateStatusMessage "Creating Summary" $cmdnum

    set cwd [pwd]
    cd $gFile($num)
    set error [ catch {CTcreateSummary $file $cmdnum} ]
    cd $cwd

    removeStatus $cmdnum

    if {!$error && "Yes" == [makeSure \
	       "Created summary file $file, would you like to see it?"]} {
	set fileId [open [file join $gFile($num) $file] r]
	CTputs $cmdnum [read $fileId]
	CToutput $num $cmdnum 
    }
}

###########################################################
# CTsetList
###########################################################
###########################################################
###########################################################
proc CTsetList { file } {
    set list ""
    for { set i 0 } { $i < 100 } { incr i } {
	if { [file readable [file join $file records set$i.db]] } {
	    lappend list $i
	}
    }
    return $list
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.