[LON-CAPA-cvs] cvs: modules /raeburn testbankimport.pm
raeburn
lon-capa-cvs@mail.lon-capa.org
Tue, 10 Feb 2004 23:39:02 -0000
This is a MIME encoded message
--raeburn1076456342
Content-Type: text/plain
raeburn Tue Feb 10 18:39:02 2004 EDT
Added files:
/modules/raeburn testbankimport.pm
Log:
Temporary storage for testbank importer. When ready for testing by LON-CAPA
developer community, this will be placed in the main loncom tree. Requires changes to lonupload.pm and loncfile.pm to operate.
--raeburn1076456342
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20040210183902.txt"
Index: modules/raeburn/testbankimport.pm
+++ modules/raeburn/testbankimport.pm
package Apache::lontestbankimport;
use strict;
use Apache::Constants qw(:common :http :methods);
use Apache::loncacc;
use Apache::loncommon();
use Apache::Log();
use Apache::lonnet;
use HTML::Entities();
use Apache::lonlocal;
use Apache::lonupload;
use File::Basename();
# ---------------------------------------------------------------- Display Control
sub display_control {
# figure out what page we're on and where we're heading.
my $page = $ENV{'form.page'};
my $command = $ENV{'form.go'};
my $current_page = &calculate_page($page,$command);
return $current_page;
}
# CALCULATE THE CURRENT PAGE
sub calculate_page($$) {
my ($prev,$dir) = @_;
return 0 if $prev eq ''; # start with first page
return $prev + 1 if $dir eq 'NextPage';
return $prev - 1 if $dir eq 'PreviousPage';
return $prev if $dir eq 'ExitPage';
return 0 if $dir eq 'BackToStart';
}
# ---------------------------------------------------------------- Jscript One
sub jscript_one {
my $jsref = shift;
$$jsref = <<"END_SCRIPT";
function verify() {
if ((document.forms.display.blocks.value == "") || (!document.forms.display.blocks.value) || (document.forms.display.blocks.value == "0")) {
alert("You must enter the number of blocks of questions of a given question type. This number must be 1 or more.")
return false
}
if (document.forms.display.qnumformat.options[document.forms.display.qnumformat.selectedIndex].value == "-1") {
alert("You must select the format used for the question number, e.g., (1), 1., (1, or 1).")
return false
}
return true
}
function nextPage() {
if (verify()) {
document.forms.display.go.value="NextPage"
document.forms.display.submit()
}
}
function backPage() {
document.forms.display.go.value="PreviousPage"
document.forms.display.submit()
}
function setElements() {
var iter = 0
var selParam = 0
END_SCRIPT
if (exists($ENV{'form.blocks'}) ) {
$$jsref .= qq|
document.forms.display.blocks.value = $ENV{'form.blocks'}\n|;
} elsif (exists($ENV{'form.qnumformat'}) ) {
$$jsref .= <<"TO_HERE";
for (iter=0; iter<document.forms.display.qnumformat.length; iter++) {
if(document.forms.display.qnumformat.options[iter].value == "$ENV{'form.qnumformat'}") {
selParam = iter
}
}
document.forms.display.qnumformat.selectedIndex = selParam
TO_HERE
}
$$jsref .= qq|
}
|;
}
# ---------------------------------------------------------------- Jscript Two
sub jscript_two {
my ($jsref,$qcount) = @_;
my $blocks = 0;
if ( exists( $ENV{'form.blocks'}) ) {
$blocks = $ENV{'form.blocks'};
}
$$jsref = <<"END_SCRIPT";
function verify() {
var poolForm = document.forms.display
var curmax = 0
var curmin = 0
for (var i=0; i<$blocks; i++) {
var iter = i+1
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "MC") {
if (poolForm.elements[5*i+4].selectedIndex == 0) {
alert ("You must choose the foil labelling format in Multiple Choice questions")
return false
}
}
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "MA") {
if (poolForm.elements[5*i+4].selectedIndex == 0) {
alert ("You must choose the foil labelling format in Multiple Answer questions")
return false
}
if (poolForm.elements[5*i+5].selectedIndex == 0) {
alert ("You must choose the answer format in Multiple Answer questions")
return false
}
}
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "FIB") {
if (poolForm.elements[5*i+5].selectedIndex == 0) {
alert ("You must choose the answer format in Fill-in-the-blank questions")
return false
}
}
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "TF") {
if (poolForm.elements[5*i+5].selectedIndex == 0) {
alert ("You must choose the answer format in True/False questions")
return false
}
}
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "Ord") {
if (poolForm.elements[5*i+4].selectedIndex == 0) {
alert ("You must choose the foil labelling format in Ranking/ordering questions")
return false
}
if (poolForm.elements[5*i+5].selectedIndex == 0) {
alert ("You must choose the answer format in Ranking/ordering questions")
return false
}
}
if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "-1") {
alert ("You must choose the question type for block "+iter)
return false
}
if ((poolForm.elements[5*i+1].value == "") || !(poolForm.elements[5*i+1].value)) {
alert ("You must choose the start number for block "+iter)
return false
}
if ((poolForm.elements[5*i+2].value == "") || !(poolForm.elements[5*i+2].value)) {
alert ("You must choose the end number for block "+iter)
return false
}
if (poolForm.elements[5*i+2].value - poolForm.elements[5*i+1].value < 0) {
alert ("In block: "+iter+" the end number must be the same or greater than the start number")
return false
}
if (i == 0) {
curmin = parseInt(poolForm.elements[5*i+1].value)
curmax = parseInt(poolForm.elements[5*i+2].value)
}
else {
if (parseInt(poolForm.elements[5*i+1].value) < curmin) {
if (parseInt(poolForm.elements[5*i+2].value) >= curmin ) {
alert("The question number range for block "+iter+" overlaps with the question number range for one of the previous blocks - this is not permitted.")
return false
}
}
else {
if (parseInt(poolForm.elements[5*i+1].value) <= curmax) {
for (var j=parseInt(poolForm.elements[5*i+1].value); j<=parseInt(poolForm.elements[5*i+2].value); j++) {
for (var k=0; k<i; k++) {
if ((j >= parseInt(poolForm.elements[5*k+1].value)) && (j <= parseInt(poolForm.elements[5*k+2].value))) {
var overlap = k+1
alert("The question number range for block "+iter+" overlaps with the question number range for block "+overlap+" - this is not permitted.")
return false
}
}
}
}
}
if (parseInt(poolForm.elements[5*i+1].value) < curmin) {
curmin = parseInt(poolForm.elements[5*i+1].value)
}
if (parseInt(poolForm.elements[5*i+2].value) > curmax) {
curmax = parseInt(poolForm.elements[5*i+2].value)
}
}
}
if (curmax >$qcount+curmin) {
alert("The last # for one or more of the blocks is too large - the last number of the last block can not be greater than $qcount: the total number of questions in the uploaded file.")
return false
}
var endpt = $qcount + curmin
for (var n=curmin; n<endpt; n++) {
var warnFlag = true
for (var m=0; m<$blocks; m++) {
if ((n >= parseInt(poolForm.elements[5*m+1].value)) && (n <= parseInt(poolForm.elements[5*m+2].value))) {
warnFlag = false
}
}
if (warnFlag) {
alert("The question type for question "+n+" could not be identified because it does not fall within the number ranges you have provided for any of the $blocks block(s)")
return false
}
}
return true
}
function nextPage() {
if (verify()) {
document.forms.display.go.value="NextPage"
document.forms.display.submit()
}
}
function backPage() {
document.forms.display.go.value="PreviousPage"
document.forms.display.submit()
}
function colSet(caller) {
var poolForm = document.forms.display
var curVal = poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value
poolForm.elements[caller*5+4].length = 0
if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "-1") {
poolForm.elements[caller*5+4].options[0] = new Option("<--- Set type ","-1",true,true)
}
else {
if ((poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MC") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MA") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "Ord")) {
poolForm.elements[caller*5+4].options[0] = new Option("Please Select","-1",true,true)
poolForm.elements[caller*5+4].options[1] = new Option("a.","lcperiod",false,false)
poolForm.elements[caller*5+4].options[2] = new Option("A.","ucperiod",false,false)
poolForm.elements[caller*5+4].options[3] = new Option("(a)","lcparen",false,false)
poolForm.elements[caller*5+4].options[4] = new Option("(A)","ucparen",false,false)
poolForm.elements[caller*5+4].options[5] = new Option("(i)","romparen",false,false)
poolForm.elements[caller*5+4].options[6] = new Option("i.","romperiod",false,false)
poolForm.elements[caller*5+4].selectedIndex = 0
}
else {
poolForm.elements[caller*5+4].options[0] = new Option("Not required","0",true,true)
}
}
poolForm.elements[caller*5+5].length = 0
if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "-1") {
poolForm.elements[caller*5+5].options[0] = new Option("<--- Set type ","-1",true,true)
}
else {
if ((poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MA") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "FIB")) {
poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
poolForm.elements[caller*5+5].options[1] = new Option("single answer","single",false,false)
poolForm.elements[caller*5+5].options[2] = new Option("comma","comma",false,false)
poolForm.elements[caller*5+5].options[3] = new Option("space","space",false,false)
poolForm.elements[caller*5+5].options[4] = new Option("new line","line",false,false)
poolForm.elements[caller*5+5].options[5] = new Option("tab","tab",false,false)
}
else {
if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "Ord")
{
poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
poolForm.elements[caller*5+5].options[2] = new Option("comma","comma",false,false)
poolForm.elements[caller*5+5].options[3] = new Option("space","space",false,false)
poolForm.elements[caller*5+5].options[4] = new Option("new line","line",false,false)
poolForm.elements[caller*5+5].options[5] = new Option("tab","tab",false,false)
}
else {
if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "TF") {
poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
poolForm.elements[caller*5+5].options[1] = new Option("True or False","word",false,false)
poolForm.elements[caller*5+5].options[2] = new Option("T or F","lett",false,false)
}
else {
poolForm.elements[caller*5+5].options[0] = new Option("Not required","0",true,true)
}
}
}
}
}
function setElements() {
var iter = 0
var selParam = 0
END_SCRIPT
my @names = ("start_","end_","qtype_","foilformat_","ansr_");
for (my $x=0; $x<$blocks; $x++) {
foreach my $name (@names) {
my $parname = $name.$x;
my $value = $ENV{"form.$parname"};
if ($value ne "") {
if (($name eq "start_") || ($name eq "end_")) {
$$jsref .= qq|
document.forms.display.$parname.value = $value\n|;
} elsif ($name eq "qtype_") {
$$jsref .= qq|
for (iter=0; iter<document.forms.display.$parname.length; iter++) {
if(document.forms.display.$parname.options[iter].value == "$value") {
selParam = iter
}
}
document.forms.display.$parname.selectedIndex = selParam
colSet($x)
|;
} elsif (($name eq "foilformat_") || ($name eq "ansr_")) {
$$jsref .= <<"TO_HERE";
for (iter=0; iter<document.forms.display.$parname.length; iter++) {
if(document.forms.display.$parname.options[iter].value == "$value") {
selParam = iter
}
}
document.forms.display.$parname.selectedIndex = selParam
TO_HERE
}
}
}
}
$$jsref .= qq|
}
|;
}
# ---------------------------------------------------------------- Jscript Three
sub jscript_three {
my ($fullpath,$jsref) = @_;
my $source = '';
if (exists($ENV{'form.go'}) ) {
$source = $ENV{'form.go'};
}
$$jsref = <<"END_OF_ONE";
function verify() {
if ((document.forms.dataForm.newdir.value == '') || (!document.forms.dataForm.newdir.value)) {
alert("Step 5: You must choose a destination directory for the import")
return false
}
return true
}
function nextPage() {
if (verify()) {
document.forms.dataForm.go.value="NextPage"
document.forms.dataForm.submit()
}
}
function backPage() {
document.forms.dataForm.go.value="PreviousPage"
document.forms.dataForm.submit()
}
function createWin() {
document.dataForm.newdir.value = "";
newWindow = window.open("","CreateDir","HEIGHT=400,WIDTH=750,scrollbars=yes")
newWindow.document.open()
newWindow.document.write("<html><head><title>Create Testbank directory</title><meta http-equiv='pragma' content='no-cache'>\\n")
newWindow.document.write("</head><body bgcolor='#CCFFDD' topmargin='0' leftmargin='0' marginheight='0'marginwidth='0' rightmargin='0'>\\n")
newWindow.document.write("<img border='0' src='/adm/lonInterFace/author.jpg' alt='[Author Header]'>\\n")
newWindow.document.write("<table border='0' cellspacing='0' cellpadding='0' width='430' bgcolor='#CCFFDD'>\\n")
newWindow.document.write("<tr><td width='2'> </td><td width='3'> </td>\\n")
newWindow.document.write("<td><h3>Location: <tt>$fullpath</tt></h3><h3>New Directory</h3></td></tr>\\n")
newWindow.document.write("<tr><td width='2'> </td><td width='3'> </td>\\n")
newWindow.document.write("<td><form name='fileaction' action='/adm/cfile' method='post'>\\n")
newWindow.document.write("<font face='arial,helvetica,sans-serif'>Enter the name of the new directory where you will store the converted testbank questions<br /><br />")
newWindow.document.write("<input type='hidden' name='filename' value='$fullpath'>")
newWindow.document.write("<input type='hidden' name='action' value='newdir'>")
newWindow.document.write("<input type='hidden' name='callingmode' value='testbank'>")
newWindow.document.write("$fullpath<input type='text' name='newfilename' value=''/>")
newWindow.document.write("<input type='button' value='Go' onClick='document.fileaction.submit();' />")
newWindow.document.write("</td></tr>\\n")
newWindow.document.write("</table></body></html>")
newWindow.document.close()
newWindow.focus()
}
END_OF_ONE
if ($source eq "PreviousPage") {
$$jsref .= qq|
function setElements() {
var iter = 0
var selParam = 0
|;
foreach my $item (keys %ENV) {
if ($item =~ m/^form\.(\w+)$/) {
my $name = $1;
my $value = $ENV{"form.$name"};
unless ($value eq "") {
if ($name eq "newdir") {
$$jsref .= qq( document.forms.dataForm.$name.value = "$value"\n);
}
}
}
}
$$jsref .= "}";
}
}
# ---------------------------------------------------------------- Jscript Four
sub jscript_four {
my ($jsref,$uname) = @_;
$$jsref = qq|
function backtoStart() {
document.location.href="/priv/$uname/"
}
function backpage() {
document.forms.verify.go.value="PreviousPage"
document.forms.verify.submit()
}
|;
}
# ---------------------------------------------------------------- Display Zero
sub display_zero {
my ($r,$uname,$fn,$page) = @_;
$r->print(qq|
<table border='0' cellspacing='0' cellpadding='0' width='100%'>
<tr>
<td> </td>
<td colspan='2'><font face='arial,helvetica,sans-serif'>
The <b>Testbank Upload</b> utility can be used by LON-CAPA Authors to import <i>multiple choice</i>, <i>multiple answer correct</i>, <i>fill-in-the-blank</i>, <i>true/false</i> and <i>essay</i> questions from a plain text file into library files. Four requirements must be met to ensure that you will succeed in building a LON-CAPA library files using your plain text file of testbank questions.
<ol>
<li>The questions and answers you upload must be in plain text format. Any header lines should occur before the text containing the questions and answers.</li>
<li>All questions must occur before any of the answers. Each question should begin on a new line, and should start with the question number. Questions should be numbered sequentially using a number followed immediately by a space, a period, or enclosed in parentheses, i.e., 1 , 1., (1), 1), or (1 .</li>
<li>One or more correct answers should be provided for all questions (although blank answers may be provided for <i>essay</i> questions). Answers should be numbered sequentially, using the same scheme as used for the questions, and must occur after all the questions.
<li><i>Multiple choice</i> and <i>multiple answer correct</i> questions should consist of (i) the question number followed by (ii) a question stem beginning on the same line and (iii) two or more foils, with each foil beginning on a new line and prefixed by a unique letter, or Roman numeral, listed in alphabetic or numeric order, beginning at a (alphabetic) or i (Roman numeral), followed by a period, or enclosed in parentheses, i.e., a., (a), i., or (i) .</li>
<li>If <i>fill-in-the-blank</i> or <i>multiple answer</i> questions have more than one correct answer, each answer should appear in a comma-, tab-, space-, or new line-delimited list. </li>
</ol>
Four steps are involved in the import process.
<ol>
<li>Upload your text file to the server.|);
if ($fn eq '') {
$r->print("<b>Incomplete</b>. Please return to the <a href='/priv/$uname'>construction space menu<a> to upload a file");
} else {
$r->print(" <b>Completed</b> - upload of $fn");
}
$r->print(qq|</li>
<li>Provide information about the question format - i.e., question numbering style, and the number of blocks of questions of the same question type.</li>
<li>Provide information about the questions in each block, including question type, start and end question numbers for each block, and foil labelling style and answer format where required.</li>
<li>Complete the import of questions to the selected pool.</li>
</ol>
</font>
</td>
</tr>
</table>
<br />
<br />
<form name="info" method="post">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type="hidden" name="page" value="$page">
<input type="hidden" name="phase" value="three">
<input type="hidden" name="go" value="NextPage">
<table border="0" width="100%">
<tr>
<td align='left'>
<input type="button" name="goback" value="Return to main menu" onClick="javascript:location.href='/priv/$uname/'">
</td>
<td align='right'>
<input type="button" name="nextpage" value="Continue to step 2" onClick="javascript:submit()">
</td>
</tr>
</table>
</form>
|);
}
# ---------------------------------------------------------------- Display One
sub display_one {
my ($r,$uname,$fn,$page,$textref) = @_;
$r->print(qq|
<form method='post' name='display'>
<table border='0' cellspacing='0' cellpadding='3' width='100%'>
<tr>
<td> </td>
<td>
<h2><font face='arial,helvetica,sans-serif'>Step 2: Identication of Blocks</b> </font></h2>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td colspan='2'>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>
You need to provide some information about the format of the questions you uploaded, so that the data in your plain text file can be stored in LON-CAPA library files.</font>
</td>
</tr>
<tr>
<td colpsan='2'> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>The following data were uploaded to the server</font><br>
<textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
|);
foreach my $line (@{$textref}) {
$line =~ s/\n//g;
$r->print("$line\n");
}
$r->print(qq|
</textarea>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr bgcolor='#ccddaa'>
<td width='21'>
</td>
<td width='100%' align='left'>
<font size='+1' face='arial,helvetica,sans-serif'><b>Format information for questions and answers</b>
</font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>
Please specify the format of the question number [e.g., 1, 1., 1), (1 or (1)].
</font><br><br>
</td>
</tr>
<tr>
<td> </td>
<td>
<table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" align="left">
<tr>
<td>
<table border="1" valign="top" align="center">
<tr bgcolor="#eef6f6" align="left">
<td>
<table border='0' cellspacing='1' cellpadding='1' align='left'>
<tr bgcolor="#CCDDAA" align='center'>
<td align="left">
<font face='arial,helvetica,sans-serif'>
<b>Number format used at start of each question (and answer)</b>
</font>
<font face='arial,helvetica,sans-serif'>
<select name="qnumformat">
<option value = "-1" selected>Please Select
<option value="number">1
<option value="period">1.
<option value="paren">(1)
<option value="leadparen">(1
<option value="trailparen">1)
</select>
</font>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>
A number in the specified format should appear at the start of each question (and each answer). Within the uploaded text file, each question (and answer) should begin on a new line. The answers should be numbered in the same way as the questions and should appear after <b>all</b> the questions. Each numbered question must have a corresponding numbered answer, although the answer itself may be blank for essay questions.</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>
Please indicate the number of blocks of different question types in the text file.</font>
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td> </td>
<td>
<table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" align="left">
<tr>
<td>
<table border="1" valign="top" align="center">
<tr bgcolor="#eef6f6" align="left">
<td>
<table border='0' cellspacing='0' cellpadding='1' align='left'>
<tr bgcolor="#CCDDAA" align='center'>
<td align="left">
<font face='arial,helvetica,sans-serif'>
<b>Number of blocks of different question types:</b></font> <input type="text" name="blocks" value="" size="5">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>
For example, you would enter <b>6</b> if your text file contained the following sequence of questions:<br><br>
10 multiple choice questions<br>
5 essay questions<br>
5 fill-in-the-blank questions<br>
5 multiple answer questions<br>
4 multiple choice questions<br>
3 essay questions<br>
</font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>You will indicate the question type and the question number range for each of the blocks on the next page.</font></td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td colspan='2'>
<table border='0' width="100%" cellspacing='0' cellpadding='2'>
<tr>
<td align='left'>
<input type="button" name="backpage" value="Go back to step 1" onClick="javascript:backPage()">
</td>
<td align='right'>
<input type="button" name="nextpage" value="Continue to step 3" onClick="javascript:nextPage()">
</td>
</tr>
</table>
<input type="hidden" name="page" value ="$page">
<input type="hidden" name="go" value="">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type="hidden" name="phase" value="three">
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
|);
}
# ---------------------------------------------------------------- Display Two
sub display_two {
my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
my $blocks = $ENV{'form.blocks'};
my $qnumformat = $ENV{'form.qnumformat'};
my @types = ("MC","MA","TF","Ess","FIB","Ord");
my %typenames = (
MC => "Multiple Choice",
TF => "True/False",
MA => "Multiple Answer",
Ess => "Essay",
FIB => "Fill-in-the-blank",
Ord => "Ranking/ordering",
);
my %qnumtypes = (
number => "1",
period => "1.",
paren => "(1)",
leadparen => "(1",
trailparen => "1)",
);
my @bgcolors = ('#ffffff','#eeeeee');
$r->print(<<"END_OF_FUNC");
<h2><font face='arial,helvetica,sans-serif'>Step 3: Classification of Blocks</b> </font></h2>
<form method='post' name='display'>
<table border='0' cellspacing='0' cellpadding ='0'>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td colspan='2'>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>
You indicated that <b>all</b> questions (and the corresponding answer(s) for each question) begin with a number in the following format: <b>$qnumtypes{$qnumformat}</b>.<br><br>A total of <b>$qcount</b> questions and <b>$qcount</b> corresponding answers were found in the file you uploaded. If this questions total does not match the number you expect, please examine your original text file to verify that each question <i>and</i> each answer begins with a number in the specified format. If necessary use a text editor to edit your text file of pool questions, and click "Previous Page" on this page and the preceding one to return to Step 1, so you can upload your text file again.<br><br>
You also indicated that the <b>$qcount</b> questions can be divided into <b>$blocks</b> blocks of questions of a particular question type.</font>
</td>
</tr>
<tr>
<td colpsan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>
Please provide additional information below ,about the types of questions you have uploaded, and, if applicable, the format of answers and "foils" for specific types of questions.
</td>
</tr>
<tr>
<td colpsan='2'> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>The following data were uploaded to the server</font><br>
<textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
END_OF_FUNC
foreach my $line (@{$textref}) {
$line =~ s/\n//g;
$r->print("$line\n");
}
$r->print(qq|
</textarea>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr bgcolor='#ccddaa'>
<td width='21'>
</td>
<td width='100%' align='left'>
<font size='+1' face='arial,helvetica,sans-serif'><b>Information about question types and formats in each block.</b></font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>For <i>each</i> of the <b>$blocks</b> question blocks, please specify the question numbers of the first and last questions in the block (e.g., 1 and 10), and the question type of the questions in the block. Please provide additional information about foil formats and answer formats if required for the question type you selected.</font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td>
<table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" align="left">
<tr>
<td>
<table border="1" valign="top" align="center">
<tr bgcolor="#eef6f6" align="left">
<td>
<table border='0' cellspacing='2' cellpadding='2' align='left' width='100%'>
<tr bgcolor="#CCDDAA" align='center'>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>Block</b></font>
</td>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>First #</b> </font>
</td>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>Last #</b> </font>
</td>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>Question type</b> </font>
</td>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>"Foil" format</b> </font>
</td>
<td align="center"><font face='arial,helvetica,sans-serif'>
<b>Answer format</b> </font>
</td>
</tr>
|);
for (my $i=0; $i<$blocks; $i++) {
my $iter = $i+1;
my $rowcol = $i%2;
$r->print(qq|
<tr bgcolor="$bgcolors[$rowcol]">
<td align="left">
<font face='arial,helvetica,sans-serif'> $iter.</font>
</td>
<td align="left">
<input type="text" name="start_$i" value="" size="5">
</td>
<td align="left">
<input type="text" name="end_$i" value="" size="5">
</td>
<td align="left">
<font face='arial,helvetica,sans-serif'>
<select name="qtype_$i" onChange="colSet($i)">
<option value= "-1" selected>Please Select
|);
foreach my $qtype (@types) {
$r->print(qq|<option value= "$qtype">$typenames{$qtype}|);
}
$r->print(qq|
</select>
</font>
</td>
<td align="left">
<select name="foilformat_$i">
<option value="-1"><--- Set type
</select>
</td>
<td align="left">
<select name="ansr_$i">
<option value="-1"><--- Set type
</select>
</td>
</tr>
|);
}
$r->print(qq|
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='arial,helvetica,sans-serif'>For <i>multiple choice</i>, <i>multiple correct answer</i> and <i>ranking</i> type questions, you must use the <b>"Foil" format</b> column to choose the format of the identifier used for each of the possible answers (e.g., (a), a, a., i, (i) etc.) provided for a given question stem. For <i>multiple correct answer</i> and <i>fill-in-the-blank</i> questions with more than one correct answer you must use the <b>Answer format</b> column to choose the separator used between the answers, e.g., if the correct answers for question 28. were listed as: 28. (a),(d),(e) you would choose "comma", or if they were listed as:</font><br><table border='0'><tr><td><font face='arial,helvetica,sans-serif'>28. </font></td><td><font face='arial,helvetica,sans-serif'>(a)</font></td></tr><tr><td> </td><td><font face='arial,helvetica,sans-serif'>(d)</font></td></tr><tr><td> </td><td><font face='arial,helvetica,sans-serif'>(e)</font></td></tr></table>
<font face='arial,helvetica,sans-serif'>you would choose "new line". For <i>true/false</i> questions you must use the <b>Answer format</b> column to choose how the correct answer - True or False, is displayed in the text file (e.g., T or F, true or false etc.). For <i>ranking</i> questions you must use the <b>Answer format</b> column to choose the separator used between the answers, and also indicate the ordering direction of the answers.</font><br><br>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td colspan='2'>
<input type="hidden" name="blocks" value="$blocks">
<input type="hidden" name="qnumformat" value="$qnumformat">
<table border='0' width="100%" cellspacing='0' cellpadding='2'>
<tr>
<td align='left'>
<input type="button" name="backpage" value="Go back to step 2" onClick="javascript:backPage()">
</td>
<td align='right'>
<input type="button" name="nextpage" value="Continue to step 4" onClick="javascript:nextPage()">
</td>
</tr>
</table>
<input type="hidden" name="page" value ="$page">
<input type="hidden" name="go" value="">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type="hidden" name="phase" value="three">
</form>
</td>
</tr>
</table>
</td>
</tr>
</table>
|);
}
# ---------------------------------------------------------------- Display Three
sub display_three {
my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
my $qnumformat = $ENV{'form.qnumformat'};
my $filename = $ENV{'form.filename'};
my $source = $ENV{'form.go'};
my $blocks = $ENV{'form.blocks'};
my @items = ();
my @bgcolors = ('#ffffff','#eeeeee');
my @types = ("MC","MA","TF","Ess","FIB","Ord");
my @alphabet = ("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");
my @romans = ("i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","xiii","xiv","xv","xvi","xvii","xviii","xix","xx","xxi","xxii","xxiii","xxiv","xxv","xxvi");
my @start = ();
my @end = ();
my @nums = ();
my @qtype = ();
my @foilformats = ();
my @ansrtypes = ();
my %multparts = ();
my $numitems = 0;
for (my $i=0; $i<$blocks; $i++) {
if (($ENV{"form.start_$i"} ne '') && ($ENV{"form.end_$i"} ne '')) {
$start[$i] = $ENV{"form.start_$i"};
$end[$i] = $ENV{"form.end_$i"};
$nums[$i] = $end[$i]-$start[$i] +1;
$qtype[$i] = $ENV{"form.qtype_$i"};
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
$foilformats[$i] = $ENV{"form.foilformat_$i"};
} else {
$foilformats[$i] = '';
}
if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
$ansrtypes[$i] = $ENV{"form.ansr_$i"};
} else {
$ansrtypes[$i] = '';
}
} else {
$nums[$i] = 0;
}
$numitems += $nums[$i];
}
my $import = join//,@{$textref};
@items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
# Get existing pool IDs.
$r->print(<<"END_OF_ONE");
<h2><font face='arial,helvetica,sans-serif'>Step 3: Review and selection of destination directory</b> </font></h2>
<form name="dataForm" method="post">
<table border='0' bgcolor='#CCFFDD' cellspacing='0' cellpadding ='0'>
<tr>
<td colspan='2'>
<table border='0' cellspacing='0' cellpadding='0'>
<tr>
<td colspan='2' align='left'>
</td>
</tr>
<tr bgcolor='#CCDDAA'>
<td width='30' valign='top'>
</td>
<td width='100%' align='left'>
<font size='+1' face='arial,helvetica,sans-serif'><b>Display of questions and answers extracted from uploaded data file.</b></font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>
Based on your previous responses your data have been split into a total of $numitems questions.
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td width="80%" bgcolor="#000000" align="left">
<table width="100%" border="0" cellpadding="1" cellspacing="0">
<tr>
<td width="100%" bgcolor="#000000">
<table border="0" cellspacing="0" cellpadding="1" width="100%">
<tr>
<td width="100%" bgcolor="#000000">
<table border="0" cellpadding="0" cellspacing="1" bgcolor="#ffffff" width="100%">
<tr>
<td bgcolor="#CCFFDD" width="100%">
<table border='0' cellspacing='1' cellpadding='2' align='left' width= '100%'>
<tr><td bgcolor="#CCDDAA" align="center" width='3%'><font face='arial,helvetica,sans-serif'><b>#</b></font></td><td bgcolor="#CCDDAA" align="center" width='5%'><font face='arial,helvetica,sans-serif'><b>Type</b></font></td><td bgcolor="#CCDDAA" align="center" width='60%'><font face='arial,helvetica,sans-serif'><b>Question</b></font></td><td bgcolor="#CCDDAA" align="center" width='32%'><font face='arial,helvetica,sans-serif'><b>Answer</b></font></td></tr>
END_OF_ONE
for (my $j=0; $j<$numitems; $j++) {
my $qnum = $j+1;
my $rowcol = $j%2;
$rowcol = @bgcolors[$rowcol];
for (my $i=0; $i<$blocks; $i++) {
if ($nums[$i] > 0) {
if (($j+1 >= $start[$i]) && ($j+1 <= $end[$i])) {
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA")) {
for (my $k=0; $k<@{$multparts{$j}}; $k++) {
if ($k == 0) {
$r->print(qq|<tr><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$qnum.</font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'><b>$qtype[$i]</b></font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$multparts{$j}[$k]<br><br>\n|);
} else {
my $foiltag = '';
if ($foilformats[$i] eq "lcperiod") {
$foiltag = $alphabet[$k-1].'.';
} elsif ($foilformats[$i] eq "lcparen") {
$foiltag = '('.$alphabet[$k-1].')';
} elsif ($foilformats[$i] eq "ucperiod") {
$foiltag = $alphabet[$k-1].'.';
$foiltag =~ tr/a-z/A-Z/;
} elsif ($foilformats[$i] eq "ucparen") {
$foiltag = '('.$alphabet[$k-1].')';
$foiltag =~ tr/a-z/A-Z/;
} elsif ($foilformats[$i] eq "romperiod") {
$foiltag = $romans[$k-1].'.';
} elsif ($foilformats[$i] eq "romparen") {
$foiltag = '('.$romans[$k-1].')';
}
$r->print(qq|$foiltag $multparts{$j}[$k]<br>\n|);
}
}
$r->print(qq|<br></font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$items[$j+$numitems]</font></td></tr>|);
} else {
$r->print(qq|<tr><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$qnum.</font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'><b>$qtype[$i]</b></font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$items[$j]</font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$items[$j+$numitems]</font></td></tr>|);
}
last;
}
}
}
}
$r->print(qq|
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr bgcolor='#ccddaa'>
<td width='30' align='top'>
</td>
<td width='100%' align='left'>
<font size='+1' face='arial,helvetica,sans-serif'><b>Create a directory to store testbank questions</b></font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td>
<font face='Arial,Helvetica,sans-serif'>
Please choose a destination LON-CAPA directory in which to store your uploaded questions.</font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><input type="button" name="createdir" value="Create Directory" onClick="javascript:createWin()"><input type="hidden" name="newdir" value=""></td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>If you are satisfied with the questions and answers extracted from your uploaded text file, as shown above, and you have created a destination directory you should use the "Next Page" button to complete the process of uploading the questions (and answers) to your LON-CAPA problem files.</font></td>
</tr>
<tr>
<td colspan='2'>
<input type='hidden' name="go" value="">
<input type='hidden' name="qnumformat" value="$qnumformat">
<input type='hidden' name="blocks" value="$blocks">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type='hidden' name="page" value="$page">
<input type="hidden" name="phase" value="three">
|);
for (my $i=0; $i<$blocks; $i++) {
$r->print(qq|
<input type='hidden' name="start_$i" value="$start[$i]">
<input type='hidden' name="end_$i" value="$end[$i]">
<input type='hidden' name="qtype_$i" value="$qtype[$i]">
|);
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
$r->print(qq|
<input type='hidden' name="foilformat_$i" value="$foilformats[$i]">
|);
}
if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
$r->print(qq|
<input type='hidden' name="ansr_$i" value="$ansrtypes[$i]">
|);
}
}
$r->print(qq|
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
<tr>
<td colspan='2'>
<table border='0' cellspacing='0' cellpadding='0' width="100%">
<tr>
<td align='left'>
<input type="button" name="backpage" value="Go back to step 2" onClick="javascript:backPage()">
</td>
<td align='right'>
<input type="button" name="nextpage" value="Continue to step 4" onClick="javascript:nextPage()">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
|);
}
# ---------------------------------------------------------------- Final Display
sub final_display {
my ($r,$uname,$fn,$page,$textref) = @_;
my $qnumformat = $ENV{'form.qnumformat'};
my $blocks = $ENV{'form.blocks'};
my $newdir = $ENV{'form.newdir'};
my $linkdir = $newdir;
if ($linkdir =~ m#^/home/$uname/public_html/(.+)$#) {
$linkdir = '/priv/'.$uname.'/'.$1;
}
my $question_id = '';
my @question_title = ();
my @question_status = ();
my @qtype = ();
my @start = ();
my @nums = ();
my @end = ();
my @foilformats = ();
my @ansrtypes = ();
my %multparts = ();
my $numitems = 0;
for (my $i=0; $i<$blocks; $i++) {
$start[$i] = $ENV{"form.start_$i"};
$end[$i] = $ENV{"form.end_$i"};
if (($end[$i] - $start[$i]) >= 0) {
$nums[$i] = $end[$i] - $start[$i]+1;
} else {
$nums[$i] = 0;
}
$qtype[$i] = $ENV{"form.qtype_$i"};
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
$foilformats[$i] = $ENV{"form.foilformat_$i"};
} else {
$foilformats[$i] = '';
}
if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
$ansrtypes[$i] = $ENV{"form.ansr_$i"};
}
$numitems += $nums[$i];
}
my @bgcolors = ('#ffffff','#eeeeee');
my $import = join/'\s'/,@{$textref};
my %answers = ();
my @items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
# foreach my $key (sort keys %multparts) {
# print STDERR "Key is $key\n";
# for (my $k=0; $k<@{$multparts{$key}}; $k++) {
# print STDERR "Value is $key, foil for $k is $multparts{$key}[$k]\n";
# }
# }
# Converting MC and MA answer to number, and splitting answers for FIB, and ordering for Ord.
my @alphabet = ("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");
my @romans = ("i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","xiii","xiv","xv","xvi","xvii","xviii","xix","xx","xxi","xxii","xxiii","xxiv","xxv","xxvi");
my %patterns = (
comma => ',',
space => '\s+',
line => '[\r\n\f]+',
tab => '\t+',
);
for (my $i=0; $i<$blocks; $i++) {
if ($nums[$i] > 0) {
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
for (my $k=$numitems+$start[$i]-1; $k<$numitems+$end[$i]; $k++) {
@{$answers{$k}} = ();
if ($qtype[$i] eq "MC") {
lc $items[$k];
$items[$k] =~ s/\W//g;
# print STDERR "count is $k, item is ||$items[$k]||, foilformat is $foilformats[$i]\n";
if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") {
for (my $j=0; $j<@alphabet; $j++) {
if ($alphabet[$j] eq $items[$k]) {
push @{$answers{$k}}, $j;
last;
}
}
} elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod")) {
for (my $j=0; $j<@romans; $j++) {
if ($romans[$j] eq $items[$k]) {
push @{$answers{$k}}, $j;
last;
}
}
}
} elsif (($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
lc $items[$k];
# print STDERR "Answer string is $items[$k]. Pattern is $patterns{$ansrtypes[$i]}\n";
my @corrects = split/$patterns{$ansrtypes[$i]}/,$items[$k];
foreach my $correct (@corrects) {
$correct =~s/\W//g;
# print STDERR "Correct is $correct for $qtype[$i] and number $k, foilformat is $foilformats[$i]\n";
if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") {
for (my $j=0; $j<@alphabet; $j++) {
if ($alphabet[$j] eq $correct) {
push @{$answers{$k}}, $j;
# print STDERR "Added $j to answer array for $k\n";
last;
}
}
} elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod")) {
for (my $j=0; $j<@romans; $j++) {
if ($romans[$j] eq $correct) {
push @{$answers{$k}}, $j;
# print STDERR "Added $j to answer array for $k\n";
last;
}
}
}
}
} elsif ($qtype[$i] eq "FIB") {
@{$answers{$k}} = split/$patterns{$ansrtypes[$i]}/,$items[$k];
for (my $j=0; $j<@{$answers{$k}}; $j++) {
$answers{$k}[$j] =~ s/^\s+//;
$answers{$k}[$j] =~ s/\s+$//;
# print STDERR "Answer for FIB is $answers{$k}[$j]\n";
}
}
}
}
}
}
my $pooltarget = '';
my $pooldesc = '';
my @newquestions = ();
my $numquestions = 0;
my %qtype = ();
my %qtext = ();
my %qflag = ();
my %qfoilnum = ();
$r->print(<<"END_OF_BLOCK");
<form name="verify" method="post">
<table border='0' cellspacing='0' cellpadding='0' width="100%">
<tr>
<td colspan='2' align='left'>
</td>
</tr>
<tr bgcolor='#ccddaa'>
<td align='top'>
</td>
<td>
<font size='+1' face='arial,helvetica,sans-serif'> <b>Result of import of questions to pool</b></font>
</td>
</tr>
<tr>
<td colspan='2'> </td>
</tr>
END_OF_BLOCK
if ($newdir ne "") {
my @qn_file = ();
my $qcount = 0;
for (my $i=0; $i<$blocks; $i++) {
if ($nums[$i] > 0) {
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
my $answer = $j + $numitems;
my $numans = scalar(@{$answers{$answer}});
# print STDERR "Num answers is $numans for $qtype[$i] for $j\n";
my $foilcount = 0;
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
$foilcount = @{$multparts{$j}};
$foilcount --;
}
# print STDERR "Passed parameters are $newdir,\@{$multparts{$j}},\@{$answers{$answer}},$qtype[$i],$j\n";
$qn_file[$qcount] = &create_mcq($newdir,\@{$multparts{$j}},\@{$answers{$answer}},$qtype[$i],$j);
$question_status[$j] = 1;
if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
$qfoilnum{$question_id} = " - $foilcount foils";
} else {
$question_status[$j] = 0;
}
if ($question_status[$j]) {
$qcount ++;
push @newquestions, $question_id;
}
}
} elsif ($qtype[$i] eq "TF") {
for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
my $answer = $j + $numitems;
$items[$answer] =~ s/^\s+//;
$items[$answer] =~ s/\s+$//;
$items[$answer] =~ s/\W//g;
$items[$answer] =~ tr/A-Z/a-z/;
# print STDERR "TF answer is $items[$answer]";
my $answer_id = '';
if ($ansrtypes[$i] eq 'word' ) {
if ($items[$answer] =~ m/true/) {
$answer_id = 0;
} else {
$answer_id = 1;
}
} elsif ($ansrtypes[$i] eq 'lett') {
if ($items[$answer] =~ m/^t/) {
$answer_id = 0;
} else {
$answer_id = 1;
}
}
$qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$i);
push @newquestions, $question_id;
$qcount ++;
}
} elsif ($qtype[$i] eq "Ess") {
for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
my $answer = $j + $numitems;
my $answer_id = '';
# print STDERR "Passed parameters are $newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$i";
$qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$i);
push @newquestions, $question_id;
$qcount ++;
}
}
}
}
$r->print(qq|<tr><tr><td> </td><td><font face='arial,helvetica,sans-serif'>Individual problem files have been created from the problems included in the textbank file.
These files are accessible via the following links:<ul>|);
for (my $i=0; $i<@qn_file; $i++) {
my $display = $i+1;
$r->print(qq|
<li><b><a href="$linkdir/$qn_file[$i]">Problem $display file</a></b></li>
|);
}
$r->print(qq|
</ul></font></td></tr>
|);
} else {
$r->print(qq|
<tr>
<td> </td>
<td><font face='arial,helvetica,sans-serif'>No destination file was selected or created, so import of your questions could not proceed.
Please return to the previous page and select a valid file into which to import the questions. </font>
<input type="hidden" name="go" value="">
<input type="hidden" name="page" value="$page">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type='hidden' name="page" value="$page">
<input type="hidden" name="phase" value="three">
<input type="hidden" name="qnumformat" value="$qnumformat">
<input type="hidden" name="newdir" value="$newdir">
|);
for (my $i=0; $i<$blocks; $i++) {
$r->print(qq|
<input type="hidden" name="start_$i" value="$start[$i]">
<input type="hidden" name="end_$i" value="$end[$i]">
<input type="hidden" name="qtype_$i" value="$qtype[$i]">
<input type="hidden" name="foilformat_$i" value="$foilformats[$i]">
<input type="hidden" name="ansr_$i" value="$ansrtypes[$i]">
|);
}
$r->print(<<"END_OF_FAIL");
</td>
</tr>
<tr>
<td colspan='2'>
<table border='0' width='100%'>
<tr>
<td align='right'>
<input type="button" name="backpage" value="Return to step 3" onClick="javascript:backPage()">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
</body>
</html>
END_OF_FAIL
return;
}
$r->print(<<"END_OF_BODY");
</table>
</td>
</tr>
</table>
<p>
<br>
</td>
</tr>
<tr>
<td colspan='2'>
<input type="hidden" name="go" value="">
<input type="hidden" name="page" value="$page">
<input type="hidden" name="uploaduname" value="$uname">
<input type="hidden" name="filename" value="$fn">
<input type='hidden' name="page" value="$page">
<input type="hidden" name="phase" value="one">
<input type="hidden" name="qnumformat" value="$qnumformat">
<input type="hidden" name="newdir" value="$newdir">
</td>
</tr>
<tr>
<td colspan='2'>
<table border='0' width='100%'>
<tr>
<td align='right'>
<a href='javascript:backtoStart()'><font face="arial,helvetica,sans-serif" size="+1"><b>Back to Start Page</b></font></a> <br><br>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</form>
END_OF_BODY
}
sub question_count {
my ($qnumformat,$textref) = @_;
my $text_in = join "\n", @{$textref};
$text_in = "\n ".$text_in;
my $qpattern ='';
if ($qnumformat eq "period") {
$qpattern = '\d{1,}\.';
} elsif ($qnumformat eq "paren") {
$qpattern = '\(\d{1,}\)';
} elsif ($qnumformat eq "number") {
$qpattern = '\d{1,}';
} elsif ($qnumformat eq "leadparen") {
$qpattern = '\(\d{1,}';
} elsif ($qnumformat eq "trailparen") {
$qpattern = '\d{1,}\)';
}
my @questions = split/[\r\n\f]+\s?$qpattern\s?/,$text_in;
my $qcount = scalar(@questions);
$qcount = $qcount/2;
$qcount = int($qcount);
return $qcount;
}
sub file_split {
my ($startsref,$endsref,$numsref,$qnumformat,$foilsref,$textref,$multpartsref,$numitems,$qtyperef,$blocks) = @_;
my $text_in = join "\n", @{$textref};
$text_in = "\n ".$text_in;
my $dignum = length($numitems);
my $numpat;
if ($dignum > 1) {
$numpat = ','.$dignum.'}';
} else {
$numpat = '}';
}
my $qpattern ='';
if ($qnumformat eq "period") {
$qpattern = '\d{1'.$numpat.'\.';
} elsif ($qnumformat eq "paren") {
$qpattern = '\(\d{1'.$numpat.'\)';
} elsif ($qnumformat eq "number") {
$qpattern = '\d{1'.$numpat;
} elsif ($qnumformat eq "leadparen") {
$qpattern = '\(\d{1'.$numpat;
} elsif ($qnumformat eq "trailparen") {
$qpattern = '\d{1'.$numpat.'\)';
}
my @questions = split/[\r\n\f]+\s?$qpattern\s?/,$text_in;
# my @questions = split/\n\s\d{1,3}\.\s/,$text_in;
shift @questions;
my %multparts = ();
for (my $i=0; $i<$blocks; $i++) {
# print STDERR "Total blocks = $blocks; Block is $i, questions = ${$numsref}[$i]\n";
if (${$numsref}[$i] > 0) {
if ((${$qtyperef}[$i] eq "MC") || (${$qtyperef}[$i] eq "MA")) {
my $splitstr = '';
if (${$foilsref}[$i] eq "lcperiod") {
$splitstr = '[a-z]\.';
} elsif (${$foilsref}[$i] eq "lcparen") {
$splitstr = '\([a-z]\)';
} elsif (${$foilsref}[$i] eq "ucperiod") {
$splitstr = '[A-Z]\.';
} elsif (${$foilsref}[$i] eq "ucparen") {
$splitstr = '\([A-Z]\)';
} elsif (${$foilsref}[$i] eq "romperiod") {
$splitstr = '[ivx]+\.';
} elsif (${$foilsref}[$i] eq "romparen") {
$splitstr = '\([ivx]+\)';
}
for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) {
# print STDERR "Q is $j, question is $questions[$j]\n";
@{$multparts{$j}} = split/[\r\n\f]+\s?$splitstr\s?/,$questions[$j];
chomp(@{$multparts{$j}});
foreach my $foil (@{$multparts{$j}}) {
# print STDERR "Foil is $foil\n";
}
}
} elsif (${$qtyperef}[$i] eq "FIB") {
for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) {
@{$multparts{$j}} = ("$questions[$j]");
}
}
}
}
%{$multpartsref} = %multparts;
return @questions;
}
# create_mcq builds an MC, MA, Ord or FIB question
sub create_mcq {
my ($newdir,$qstnref,$answerref,$qtype,$qnum) = @_;
$qnum ++;
if (length($qnum) == 1) {
$qnum = "00".$qnum;
} elsif (length($qnum) == 2) {
$qnum = "0".$qnum;
}
my $qstn = ${$qstnref}[0];
my $numfoils = scalar(@{$qstnref}) - 1;
my $datestamp = localtime;
my $timestamp = time;
my $libfile = 'question_'.$qnum;
$libfile .= '.problem';
my $numansrs = scalar(@{$answerref});
# print STDERR "Number of answers is $numansrs\n";
foreach my $one (@{$answerref}) {
# print STDERR "Answer is $one\n";
}
foreach my $one (@{$qstnref} ) {
# print STDERR "Answer text is: $one\n";
}
my $output = qq|<problem>
<startouttext />$qstn<endouttext />
|;
if ($qtype eq "MA") {
# print STDERR "$qtype is MA\n";
$output .= qq|
<radiobuttonresponse max="$numfoils" randomize="yes">
<foilgroup>
|;
for (my $k=0; $k<@{$qstnref}-1; $k++) {
$output .= " <foil name=\"foil".$k."\" value=\"";
if (grep/^$k$/,@{$answerref}) {
$output .= "true\" location=\"random\"";
} else {
$output .= "false\" location=\"random\"";
}
$output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
}
chomp($output);
$output .= qq|
</foilgroup>
</radiobuttonresponse>
</problem>
|;
}
if ($qtype eq "MC") {
# print STDERR "qtype is $qtype\n";
$output .= qq|
<radiobuttonresponse max="$numfoils" randomize="yes">
<foilgroup>
|;
for (my $k=0; $k<@{$qstnref}-1; $k++) {
$output .= " <foil name=\"foil".$k."\" value=\"";
if (grep/^$k$/,@{$answerref}) {
$output .= "true\" location=\"";
} else {
$output .= "false\" location=\"";
}
if (lc (${$qstnref}[$k+1]) =~ m/^\s?([Aa]ll)|([Nn]one)\sof\sthe\sabove\.?/) {
$output .= "bottom\"";
} else {
$output .= "random\"";
}
$output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
}
chomp($output);
$output .= qq|
</foilgroup>
</radiobuttonresponse>
</problem>
|;
}
if ($qtype eq "Ord") {
# print STDERR "$qtype is Ord\n";
$output .= qq|
<rankresponse max="$numfoils" randomize="yes">
<foilgroup>
|;
for (my $k=0; $k<@{$qstnref}-1; $k++) {
$output .= " <foil location=\"random\" name=\"foil".$k."\" value=\"".$$answerref[$k]."\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
}
chomp($output);
$output .= qq|
</foilgroup>
</rankresponse>
</problem>
|;
}
if ($qtype eq "FIB") {
my $numerical = 1;
for (my $i=0; $i<@{$answerref}; $i++) {
unless (${$answerref}[$i] =~ m/^\d+$/) {
$numerical = 0;
}
}
if ($numerical) {
my $numans;
my $tol;
if (@{$answerref} == 1) {
$tol = 5;
$numans = $$answerref[0];
} else {
my $min = 0;
my $max = 0;
for (my $i=0; $i<@{$answerref}; $i++) {
if ($$answerref[$i]<$min) {
$min = $$answerref[$i];
} elsif ($$answerref[$i] > $max) {
$max = $$answerref[$i];
}
}
$numans = ($max + $min)/2;
$tol = 100*($max - $min)/($numans*2);
}
$output .= qq|
<numericalresponse answer="$numans">
<responseparam type="tolerance" default="$tol%" name="tol" description="Numerical Tolerance" />
<responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures" />
<textline />
</numericalresponse>
</problem>
|;
} else {
if (@{$answerref} == 1) {
$output .= qq|
<stringresponse answer="$$answerref[0]" type="ci">
<textline>
</textline>
</stringresponse>
</problem>
|;
} else {
for (my $i=0; $i<@{$answerref}; $i++) {
${$answerref}[$i] =~ s/\|/\|/g;
}
my $regexpans = join('|',@{$answerref});
$regexpans = '/('.$regexpans.')/';
$output .= qq|
<stringresponse answer="$regexpans" type="re">
<textline>
</textline>
</stringresponse>
</problem>
|;
}
}
}
open(PROB,">$newdir/$libfile");
print PROB $output;
close PROB;
return $libfile;
}
# create_ess builds an essay or True/False question
sub create_ess {
my ($newdir,$answer_id,$qstn,$answertxt,$qtype,$qnum) = @_;
$qnum ++;
if (length($qnum) == 1) {
$qnum = "00".$qnum;
} elsif (length($qnum) == 2) {
$qnum = "0".$qnum;
}
my $libfile = 'question_'.$qnum;
$libfile .= '.problem';
my $output = qq|<problem>
<startouttext />$qstn<endouttext />|;
my $answer = '';
my $answerlog = '';
if ($qtype eq "Ess") {
$output .= qq|
<essayresponse>
<textfield></textfield>
</essayresponse>
<postanswerdate>
$answertxt
</postanswerdate>
</problem>|;
# print STDERR "Adding: essay answer: $answertxt\n";
} elsif ($qtype eq "TF") {
$answer = $answer_id;
$output .= qq|
<radiobuttonresponse max="2" randomize="yes">
<foilgroup>
|;
for (my $k=0; $k<2; $k++) {
$output .= " <foil name=\"foil".$k."\" value=\"";
if ($answer_id) {
$output .= "false\"";
$answerlog = "False\n";
} else {
$output .= "true\"";
$answerlog = "True\n";
}
$output .= "location=\"random\"><startouttext />".$answerlog."<endouttext /></foil>\n";
}
chomp($output);
$output .= qq|
</foilgroup>
</radiobuttonresponse>
</problem>|;
# print STDERR "Adding: TF answer: $answerlog\n";
}
open(PROB,">$newdir/$libfile");
print PROB $output;
close PROB;
return $libfile;
}
# ---------------------------------------------------------------- Main Handler
sub handler {
my $r=shift;
my $uname;
my $udom;
my $javascript = '';
my $page_name = '';
my $current_page = '';
my $loadentries = '';
my $qcount = '';
#
# phase two: re-attach user
#
if ($ENV{'form.uploaduname'}) {
$ENV{'form.filename'}='/priv/'.$ENV{'form.uploaduname'}.'/'.
$ENV{'form.filename'};
}
($uname,$udom)=
&Apache::loncacc::constructaccess($ENV{'form.filename'},
$r->dir_config('lonDefDomain'));
unless (($uname) && ($udom)) {
$r->log_reason($uname.' at '.$udom.
' trying to publish file '.$ENV{'form.filename'}.
' - not authorized',
$r->filename);
return HTTP_NOT_ACCEPTABLE;
}
my $fn;
if ($ENV{'form.filename'}) {
$fn=$ENV{'form.filename'};
$fn=~s/^http\:\/\/[^\/]+\///;
$fn=~s/^\///;
$fn=~s/(\~|priv\/)(\w+)//;
$fn=~s/\/+/\//g;
} else {
$r->log_reason($ENV{'user.name'}.' at '.$ENV{'user.domain'}.
' unspecified filename for upload', $r->filename);
return HTTP_NOT_FOUND;
}
my $pathname = &File::Basename::dirname($fn);
my $fullpath = '/priv/'.$uname.$pathname;
unless ($pathname eq '/') {
$fullpath .= '/';
}
my @text = ();
my $loadentries = '';
if ($ENV{'form.phase'} eq 'three') {
if (-e "$fullpath$fn") {
open(TESTBANK,"<$fullpath$fn");
@text = <TESTBANK>;
close(TESTBANK);
}
}
# ----------------------------------------------------------- Start page output
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
if ($ENV{'form.phase'} eq 'three') {
$current_page = &display_control();
my @PAGES = ('Welcome','Blocks','Format','Target','Confirmation');
$page_name = $PAGES[$current_page];
if ($page_name eq 'Blocks') {
$loadentries = 'onLoad= "setElements()"';
&jscript_one(\$javascript);
} elsif ($page_name eq 'Format') {
$qcount = question_count($ENV{'form.qnumformat'},\@text);
&jscript_two(\$javascript,$qcount);
} elsif ($page_name eq 'Target') {
if ($ENV{'form.go'} eq "PreviousPage") {
$loadentries = 'onLoad = "setElements()"';
}
&jscript_three($fullpath,\$javascript);
} elsif ($page_name eq 'Confirmation') {
&jscript_four(\$javascript,$uname);
}
}
$r->print("<html><head><title>LON-CAPA Construction Space</title><script type=\"text/javascript\">\n//<!--\n$javascript\n// --></script>\n</head>");
$r->print(&Apache::loncommon::bodytag('Upload testbank questions to Construction Space',undef,$loadentries));
if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})) {
$r->print('<h3><font color=red>'.&mt('Co-Author').': '.$uname.
&mt(' at ').$udom.'</font></h3>');
}
if ($ENV{'form.phase'} eq 'three') {
&display_zero ($r,$uname,$fn,$current_page) if $page_name eq 'Welcome';
&display_one ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Blocks';
&display_two ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Format';
&display_three ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Target';
&final_display ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Confirmation';
} elsif ($ENV{'form.phase'} eq 'two') {
my $flag = &Apache::lonupload::phasetwo($r,$fn,$uname,$udom,'testbank');
if ($flag eq 'ok') {
my $current_page = 0;
&display_zero($r,$uname,$fn,$current_page);
}
} else {
&Apache::lonupload::phaseone($r,$fn,$uname,$udom,'testbank');
}
$r->print('</body></html>');
return OK;
}
1;
__END__
--raeburn1076456342--