Annotation of loncom/publisher/testbankimport.pm, revision 1.13

1.3       albertel    1: # Handler for parsing text upload problem descriptions into .problems
1.13    ! raeburn     2: # $Id: testbankimport.pm,v 1.12 2007/05/02 01:34:23 albertel Exp $
1.3       albertel    3: #
                      4: # Copyright Michigan State University Board of Trustees
                      5: #
                      6: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      7: #
                      8: # LON-CAPA is free software; you can redistribute it and/or modify
                      9: # it under the terms of the GNU General Public License as published by
                     10: # the Free Software Foundation; either version 2 of the License, or
                     11: # (at your option) any later version.
                     12: #
                     13: # LON-CAPA is distributed in the hope that it will be useful,
                     14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     16: # GNU General Public License for more details.
                     17: #
                     18: # You should have received a copy of the GNU General Public License
                     19: # along with LON-CAPA; if not, write to the Free Software
                     20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     21: #
                     22: # /home/httpd/html/adm/gpl.txt
                     23: #
                     24: # http://www.lon-capa.org/
                     25: #
                     26: 
1.1       raeburn    27: package Apache::testbankimport;
                     28: 
1.3       albertel   29: use strict;
                     30: use Apache::Constants qw(:common :http :methods);
                     31: use Apache::loncacc;
                     32: use Apache::loncommon();
                     33: use Apache::lonnet;
                     34: use HTML::Entities();
                     35: use Apache::lonlocal;
                     36: use Apache::lonupload;
                     37: use File::Basename();
1.11      albertel   38: use LONCAPA();
1.1       raeburn    39: 
                     40: # ---------------------------------------------------------------- Display Control
                     41: sub display_control {
                     42: # figure out what page we're on and where we're heading.
1.6       albertel   43:     my $page = $env{'form.page'};
                     44:     my $command = $env{'form.go'};
1.1       raeburn    45:     my $current_page = &calculate_page($page,$command);
                     46:     return $current_page;
                     47: }
                     48: 
                     49: # CALCULATE THE CURRENT PAGE
                     50: sub calculate_page($$) {
                     51:     my ($prev,$dir) = @_;
                     52:     return 0 if $prev eq '';    # start with first page
                     53:     return $prev + 1 if $dir eq 'NextPage';
                     54:     return $prev - 1 if $dir eq 'PreviousPage';
                     55:     return $prev     if $dir eq 'ExitPage';
                     56:     return 0 if $dir eq 'BackToStart';
                     57: }
                     58: 
                     59: # ---------------------------------------------------------------- Jscript One
                     60: 
                     61: sub jscript_one {
                     62:     my $jsref = shift;
                     63:     $$jsref = <<"END_SCRIPT";
                     64: function verify() {
                     65:     if ((document.forms.display.blocks.value == "") || (!document.forms.display.blocks.value) || (document.forms.display.blocks.value == "0")) {
                     66:         alert("You must enter the number of blocks of questions of a given question type.  This number must be 1 or more.")
                     67:         return false
                     68:     }
                     69:     if (document.forms.display.qnumformat.options[document.forms.display.qnumformat.selectedIndex].value == "-1") {
                     70:         alert("You must select the format used for the question number, e.g., (1), 1., (1, or 1).")
                     71:         return false
                     72:     }
                     73:     return true
                     74: }
                     75: function nextPage() {
                     76:     if (verify()) {
                     77:         document.forms.display.go.value="NextPage"
                     78:         document.forms.display.submit()
                     79:     }
                     80: }
                     81: function backPage() {
                     82:     document.forms.display.go.value="PreviousPage"
                     83:     document.forms.display.submit()
                     84: }
                     85: function setElements() {
                     86:     var iter = 0
                     87:     var selParam = 0
                     88: END_SCRIPT
1.6       albertel   89:     if (exists($env{'form.blocks'}) ) {
1.1       raeburn    90:         $$jsref .= qq|
1.6       albertel   91:     document.forms.display.blocks.value = $env{'form.blocks'}\n|;
                     92:     } elsif (exists($env{'form.qnumformat'}) ) {
1.1       raeburn    93:         $$jsref .= <<"TO_HERE";
                     94:     for (iter=0; iter<document.forms.display.qnumformat.length; iter++) {
1.6       albertel   95:         if(document.forms.display.qnumformat.options[iter].value == "$env{'form.qnumformat'}") {
1.1       raeburn    96:             selParam = iter
                     97:         }
                     98:     }
                     99:     document.forms.display.qnumformat.selectedIndex = selParam
                    100: TO_HERE
                    101:     }
                    102:     $$jsref .= qq|
                    103: }
                    104:     |;
                    105: }
                    106: 
                    107: # ---------------------------------------------------------------- Jscript Two
                    108: sub jscript_two {
                    109:     my ($jsref,$qcount) = @_;
                    110:     my $blocks = 0;
1.6       albertel  111:     if ( exists( $env{'form.blocks'}) ) {
                    112:         $blocks = $env{'form.blocks'};
1.1       raeburn   113:     }
                    114:     $$jsref = <<"END_SCRIPT";
                    115: function verify() {
                    116:     var poolForm = document.forms.display
                    117:     var curmax = 0
                    118:     var curmin = 0
                    119:     for (var i=0; i<$blocks; i++) {
                    120:         var iter = i+1
                    121:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "MC") {
                    122:             if (poolForm.elements[5*i+4].selectedIndex == 0) {
                    123:                 alert ("You must choose the foil labelling format in Multiple Choice questions")
                    124:                 return false
                    125:             }
                    126:         }
                    127:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "MA") {
                    128:             if (poolForm.elements[5*i+4].selectedIndex == 0) {
                    129:                 alert ("You must choose the foil labelling format in Multiple Answer questions")
                    130:                 return false
                    131:             }
                    132:             if (poolForm.elements[5*i+5].selectedIndex == 0) {
                    133:                 alert ("You must choose the answer format in Multiple Answer questions") 
                    134:                 return false
                    135:             }
                    136:         }
                    137:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "FIB") {
                    138:             if (poolForm.elements[5*i+5].selectedIndex == 0) {
                    139:                 alert ("You must choose the answer format in Fill-in-the-blank questions") 
                    140:                 return false
                    141:             }
                    142:         }
                    143:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "TF") {
                    144:             if (poolForm.elements[5*i+5].selectedIndex == 0) {
                    145:                 alert ("You must choose the answer format in True/False questions") 
                    146:                 return false
                    147:             }
                    148:         }
                    149:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "Ord") {
                    150:             if (poolForm.elements[5*i+4].selectedIndex == 0) {
                    151:                 alert ("You must choose the foil labelling format in Ranking/ordering questions")
                    152:                 return false
                    153:             }
                    154:             if (poolForm.elements[5*i+5].selectedIndex == 0) {
                    155:                 alert ("You must choose the answer format in Ranking/ordering questions")
                    156:                 return false
                    157:             }
                    158:         }
                    159:         if (poolForm.elements[5*i+3].options[poolForm.elements[5*i+3].selectedIndex].value == "-1") {
                    160:             alert ("You must choose the question type for block "+iter)
                    161:             return false
                    162:         }
                    163:         if ((poolForm.elements[5*i+1].value == "") || !(poolForm.elements[5*i+1].value)) {
                    164:             alert ("You must choose the start number for block "+iter)
                    165:             return false
                    166:         }
                    167:         if ((poolForm.elements[5*i+2].value == "") || !(poolForm.elements[5*i+2].value)) {
                    168:             alert ("You must choose the end number for block "+iter)
                    169:             return false
                    170:         }
                    171:         if (poolForm.elements[5*i+2].value - poolForm.elements[5*i+1].value < 0) {
                    172:             alert ("In block: "+iter+" the end number must be the same or greater than the start number")
                    173:             return false
                    174:         }
                    175:         if (i == 0) {
                    176:             curmin = parseInt(poolForm.elements[5*i+1].value)
                    177:             curmax = parseInt(poolForm.elements[5*i+2].value)
                    178:         }
                    179:         else {
                    180:             if (parseInt(poolForm.elements[5*i+1].value) < curmin) {
                    181:                 if (parseInt(poolForm.elements[5*i+2].value) >= curmin ) {
                    182:                     alert("The question number range for block "+iter+" overlaps with the question number range for one of the previous blocks - this is not permitted.")
                    183:                     return false
                    184:                 }
                    185:             }
                    186:             else {
                    187:                 if (parseInt(poolForm.elements[5*i+1].value) <= curmax) {
                    188:                     for (var j=parseInt(poolForm.elements[5*i+1].value); j<=parseInt(poolForm.elements[5*i+2].value); j++) {
                    189:                         for (var k=0; k<i; k++) {
                    190:                             if ((j >= parseInt(poolForm.elements[5*k+1].value)) && (j <= parseInt(poolForm.elements[5*k+2].value))) {
                    191:                                 var overlap = k+1
                    192:                                 alert("The question number range for block "+iter+" overlaps with the question number range for block "+overlap+" - this is not permitted.")
                    193:                                 return false
                    194:                             }
                    195:                         }
                    196:                     }
                    197:                 }
                    198:             }
                    199:             if (parseInt(poolForm.elements[5*i+1].value) < curmin) {
                    200:                 curmin = parseInt(poolForm.elements[5*i+1].value)
                    201:             }
                    202:             if (parseInt(poolForm.elements[5*i+2].value) > curmax) {
                    203:                 curmax = parseInt(poolForm.elements[5*i+2].value)
                    204:             }
                    205:         }
                    206:     }
                    207:     if (curmax >$qcount+curmin) {
                    208:         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.")
                    209:         return false
                    210:     }
                    211:     var endpt = $qcount + curmin
                    212:     for (var n=curmin; n<endpt; n++) {
                    213:         var warnFlag = true
                    214:         for (var m=0; m<$blocks; m++) {
                    215:             if ((n >= parseInt(poolForm.elements[5*m+1].value)) && (n <= parseInt(poolForm.elements[5*m+2].value))) {
                    216:                 warnFlag = false
                    217:             }
                    218:         }
                    219:         if (warnFlag) {
                    220:             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)")
                    221:             return false
                    222:         }
                    223:     } 
                    224:     return true 
                    225: }
                    226:  
                    227: function nextPage() {
                    228:     if (verify()) {
                    229:         document.forms.display.go.value="NextPage"
                    230:         document.forms.display.submit()
                    231:     }
                    232: }
                    233: function backPage() {
                    234:     document.forms.display.go.value="PreviousPage"
                    235:     document.forms.display.submit()
                    236: }
                    237: function colSet(caller) {
                    238:     var poolForm = document.forms.display
                    239:     var curVal = poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value  
                    240:     poolForm.elements[caller*5+4].length = 0
                    241:     if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "-1") {
                    242:         poolForm.elements[caller*5+4].options[0] = new Option("<--- Set type ","-1",true,true)
                    243:     }
                    244:     else {
                    245:         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")) {
                    246:             poolForm.elements[caller*5+4].options[0] = new Option("Please Select","-1",true,true)
                    247:             poolForm.elements[caller*5+4].options[1] = new Option("a.","lcperiod",false,false)
                    248:             poolForm.elements[caller*5+4].options[2] = new Option("A.","ucperiod",false,false)
                    249:             poolForm.elements[caller*5+4].options[3] = new Option("(a)","lcparen",false,false)
                    250:             poolForm.elements[caller*5+4].options[4] = new Option("(A)","ucparen",false,false)
1.5       raeburn   251:             poolForm.elements[caller*5+4].options[5] = new Option("a)","lconeparen",false,false)
                    252:             poolForm.elements[caller*5+4].options[6] = new Option("A)","uconeparen",false,false)
                    253:             poolForm.elements[caller*5+4].options[7] = new Option("a.)","lcdotparen",false,false)
                    254:             poolForm.elements[caller*5+4].options[8] = new Option("A.)","ucdotparen",false,false)
                    255:             poolForm.elements[caller*5+4].options[9] = new Option("(i)","romparen",false,false)
                    256:             poolForm.elements[caller*5+4].options[10] = new Option("i)","romoneparen",false,false)
                    257:             poolForm.elements[caller*5+4].options[11] = new Option("i.)","romdotparen",false,false)
                    258:             poolForm.elements[caller*5+4].options[12] = new Option("i.","romperiod",false,false)
1.1       raeburn   259:             poolForm.elements[caller*5+4].selectedIndex = 0
                    260:         }
                    261:         else {
                    262:             poolForm.elements[caller*5+4].options[0] = new Option("Not required","0",true,true)
                    263:         }
                    264:     }
                    265:     poolForm.elements[caller*5+5].length = 0
                    266:     if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "-1") {
                    267:         poolForm.elements[caller*5+5].options[0] = new Option("<--- Set type ","-1",true,true)
                    268:     }
                    269:     else {
                    270:         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"))  {
                    271:             poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
                    272:             poolForm.elements[caller*5+5].options[1] = new Option("single answer","single",false,false)
                    273:             poolForm.elements[caller*5+5].options[2] = new Option("comma","comma",false,false)
                    274:             poolForm.elements[caller*5+5].options[3] = new Option("space","space",false,false)
                    275:             poolForm.elements[caller*5+5].options[4] = new Option("new line","line",false,false)
                    276:             poolForm.elements[caller*5+5].options[5] = new Option("tab","tab",false,false)
                    277:         }
                    278:         else {
                    279:             if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "Ord") {
                    280:                 poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
                    281:                 poolForm.elements[caller*5+5].options[1] = new Option("comma","comma",false,false)
                    282:                 poolForm.elements[caller*5+5].options[2] = new Option("space","space",false,false)
                    283:                 poolForm.elements[caller*5+5].options[3] = new Option("new line","line",false,false)
                    284:                 poolForm.elements[caller*5+5].options[4] = new Option("tab","tab",false,false)
                    285:             }
                    286:             else { 
                    287:                 if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "TF") {
                    288:                     poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
                    289:                     poolForm.elements[caller*5+5].options[1] = new Option("True or False","word",false,false)
1.5       raeburn   290:                     poolForm.elements[caller*5+5].options[2] = new Option("true or false","word",false,false)
                    291:                     poolForm.elements[caller*5+5].options[3] = new Option("TRUE or FALSE","word",false,false)
                    292:                     poolForm.elements[caller*5+5].options[4] = new Option("T or F","lett",false,false)
                    293:                     poolForm.elements[caller*5+5].options[5] = new Option("t or f","lett",false,false)
1.1       raeburn   294:                 }
                    295:                 else {
                    296:                     poolForm.elements[caller*5+5].options[0] = new Option("Not required","0",true,true)
                    297:                 }
                    298:             }
                    299:         }
                    300:     }
                    301: }
                    302: 
                    303: function setElements() {
                    304:     var iter = 0
                    305:     var selParam = 0
                    306: END_SCRIPT
                    307:     my @names = ("start_","end_","qtype_","foilformat_","ansr_");
                    308:     for (my $x=0; $x<$blocks; $x++) {
                    309:         foreach my $name (@names) {
                    310:             my $parname = $name.$x;
1.6       albertel  311:             my $value = $env{"form.$parname"};
1.1       raeburn   312:             if ($value ne "") {
                    313:                 if (($name eq "start_")  || ($name eq "end_")) {
                    314:                     $$jsref .= qq|
                    315:     document.forms.display.$parname.value = $value\n|;
                    316:                 } elsif ($name eq "qtype_") {
                    317:                     $$jsref .= qq|
                    318:     for (iter=0; iter<document.forms.display.$parname.length; iter++) {
                    319:         if (document.forms.display.$parname.options[iter].value == "$value") {
                    320:             selParam = iter
                    321:         }
                    322:     }
                    323:     document.forms.display.$parname.selectedIndex = selParam
                    324:     colSet($x)
                    325:                     |;
                    326:                 } elsif (($name eq "foilformat_") || ($name eq "ansr_")) {
                    327:                     $$jsref .= <<"TO_HERE";
                    328:     for (iter=0; iter<document.forms.display.$parname.length; iter++) {
                    329:         if (document.forms.display.$parname.options[iter].value == "$value") {
                    330:             selParam = iter
                    331:         }
                    332:     }
                    333:     document.forms.display.$parname.selectedIndex = selParam
                    334: TO_HERE
                    335:                 } 
                    336:             }
                    337:         }
                    338:     }
                    339:     $$jsref .= qq|
                    340: }
                    341:     |;
                    342: } 
                    343: # ---------------------------------------------------------------- Jscript Three
                    344: 
                    345: sub jscript_three {
                    346:     my ($fullpath,$jsref) = @_;
                    347:     my $source = '';
1.6       albertel  348:     if (exists($env{'form.go'}) ) {
                    349:         $source = $env{'form.go'};
1.1       raeburn   350:     }
1.8       albertel  351: 
1.10      albertel  352:     my %body_layout = ('rightmargin'  => "0",
                    353: 		       'leftmargin'   => "0",
                    354: 		       'marginwidth'  => "0",
                    355: 		       'topmargin'    => "0",
                    356: 		       'marginheight' => "0");
                    357: 
1.8       albertel  358:     my $start_page = 
1.9       albertel  359: 	&Apache::loncommon::start_page('Create Testbank directory',undef,
1.8       albertel  360: 				       {'only_body'   => 1,
1.10      albertel  361: 					'add_entries' => \%body_layout,
1.8       albertel  362: 					'js_ready'    => 1,});
                    363:     my $end_page = 
                    364: 	&Apache::loncommon::end_page({'js_ready' => 1,});
1.1       raeburn   365:     $$jsref = <<"END_OF_ONE";
                    366: function verify() {
                    367:     if ((document.forms.dataForm.newdir.value == '')  || (!document.forms.dataForm.newdir.value)) {
                    368:         alert("Step 4: You must choose a destination directory for the import") 
                    369:         return false
                    370:     }
                    371:     return true
                    372: } 
                    373: 
                    374: function nextPage() {
                    375:     if (verify()) {
                    376:         document.forms.dataForm.go.value="NextPage"
                    377:         document.forms.dataForm.submit()
                    378:     }
                    379: }
                    380: function backPage() {
                    381:     document.forms.dataForm.go.value="PreviousPage"
                    382:     document.forms.dataForm.submit()
                    383: }
                    384: 
                    385: function createWin() {
                    386:     document.dataForm.newdir.value = "";
                    387:     newWindow = window.open("","CreateDir","HEIGHT=400,WIDTH=750,scrollbars=yes")
                    388:     newWindow.document.open()
1.8       albertel  389:     newWindow.document.write('$start_page')
1.1       raeburn   390:     newWindow.document.write("<img border='0' src='/adm/lonInterFace/author.jpg' alt='[Author Header]'>\\n")
                    391:     newWindow.document.write("<table border='0' cellspacing='0' cellpadding='0' width='430' bgcolor='#CCFFDD'>\\n")
                    392:     newWindow.document.write("<tr><td width='2'>&nbsp;</td><td width='3'>&nbsp;</td>\\n")
                    393:     newWindow.document.write("<td><h3>Location: <tt>$fullpath</tt></h3><h3>New Directory</h3></td></tr>\\n")
                    394:     newWindow.document.write("<tr><td width='2'>&nbsp;</td><td width='3'>&nbsp;</td>\\n")
                    395:     newWindow.document.write("<td><form name='fileaction' action='/adm/cfile' method='post'>\\n")
1.12      albertel  396:     newWindow.document.write("<font face='arial,helvetica,sans-serif'>Enter the name of the new directory where you will save the converted testbank questions<br /><br />")
1.1       raeburn   397:     newWindow.document.write("<input type='hidden' name='filename' value='$fullpath'>")   
                    398:     newWindow.document.write("<input type='hidden' name='action' value='newdir'>")
                    399:     newWindow.document.write("<input type='hidden' name='callingmode' value='testbank'>")
                    400:     newWindow.document.write("$fullpath<input type='text' name='newfilename' value=''/>")
                    401:     newWindow.document.write("<input type='button' value='Go' onClick='document.fileaction.submit();' />")
                    402:     newWindow.document.write("</td></tr>\\n")
1.8       albertel  403:     newWindow.document.write("</table>")
                    404:     newWindow.document.write('$end_page')
1.1       raeburn   405:     newWindow.document.close()
                    406:     newWindow.focus()
                    407: }
                    408: END_OF_ONE
                    409:     if ($source eq "PreviousPage") { 
                    410:         $$jsref .= qq|  
                    411: function setElements() {
                    412:     var iter = 0
                    413:     var selParam = 0
                    414:         |;
1.6       albertel  415:         foreach my $item (keys %env) {
1.1       raeburn   416:             if ($item =~ m/^form\.(\w+)$/) {
                    417:                 my $name = $1; 
1.6       albertel  418:                 my $value = $env{"form.$name"};
1.1       raeburn   419:                 unless ($value eq "") {
                    420:                     if ($name eq "newdir") {
                    421:              	        $$jsref .= qq(    document.forms.dataForm.$name.value = "$value"\n);
                    422:                     }
                    423:                 }
                    424:             }
                    425:         }
                    426:         $$jsref .= "}";
                    427:     }
                    428: }
                    429: 
                    430: 
                    431: # ---------------------------------------------------------------- Jscript Four
                    432: sub jscript_four {
                    433:     my ($jsref,$fullpath) = @_;
                    434:     $$jsref = qq|   
                    435: function backtoStart() {
                    436:     document.location.href="$fullpath"
                    437: }
                    438: function backpage() {
                    439:     document.forms.verify.go.value="PreviousPage"
                    440:     document.forms.verify.submit()
                    441: }
                    442:     |;
                    443: }
                    444: 
                    445: # ---------------------------------------------------------------- Display Zero
                    446: sub display_zero {
                    447:     my ($r,$uname,$fn,$page,$fullpath) = @_;
                    448:     $r->print(qq|
                    449: <table border='0' cellspacing='0' cellpadding='0' width='100%'>
                    450:        <tr>
                    451:         <td>&nbsp;</td>
                    452:         <td colspan='2'><font face='arial,helvetica,sans-serif'> 
                    453: The <b>Testbank Upload</b> utility can be used by LON-CAPA authors to convert <i>multiple choice</i>, <i>multiple answer correct</i>, <i>fill-in-the-blank</i>, <i>ordering/ranking</i>, <i>true/false</i> and <i>essay</i> questions from a plain text testbank file to LON-CAPA problem files.  Five requirements must be met to ensure that you will succeed in converting your plain text file of testbank questions to functioning LON-CAPA problems.
                    454:         <ol>
                    455:          <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>
                    456:          <li>All questions (including question text and all foils) 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>
                    457:          <li><i>Multiple choice</i> and <i>multiple answer correct</i> questions should consist of: (i) the question number followed by (ii) the question text 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>
                    458:          <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 <b>all</b> the questions.        
                    459:          <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. For a <i>ranking/ordering</i> question, the "answer" should contain the foil identifiers correctly ordered in a similarly delimited list.</li> 
                    460:         </ol>      
                    461: Five steps are involved in the import process.
                    462:         <ol>
                    463:          <li>Upload your text file to the server.|);
                    464: 
                    465:     if ($fn eq '') {
                    466:         $r->print("<b>Incomplete</b>. Please return to the <a href='$fullpath'>construction space menu<a> to upload a file");
                    467:     } else {
                    468:         $r->print(" <b>Completed</b> - successful upload of <i>$fn</i>");
                    469:     } 
                    470:     $r->print(qq|</li>
                    471:          <li>Provide information about the question format - i.e.,  question numbering style, and the number of blocks of questions of each question type.</li>
                    472:          <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>
1.12      albertel  473:          <li>Create a new directory where you will save the converted testbank questions.</li> 
1.1       raeburn   474:          <li>Complete the import of questions to the selected pool.</li>
                    475:         </ol>
                    476:         </font>
                    477:         </td>
                    478:        </tr>
                    479:        </table>
                    480:        <br />
                    481:        <br />
                    482:        <form name="info" method="post">
                    483:        <input type="hidden" name="uploaduname" value="$uname">
                    484:        <input type="hidden" name="filename" value="$fn">
                    485:        <input type="hidden" name="page" value="$page">
                    486:        <input type="hidden" name="phase" value="three">
                    487:        <input type="hidden" name="go" value="NextPage">
                    488:        <table border="0" width="100%">
                    489:         <tr>
                    490:          <td align='left'>
                    491:           <input type="button" name="goback" value="Exit Now" onClick="javascript:location.href='$fullpath'">
                    492:          </td>
                    493:          <td align='right'>
                    494:           <input type="button" name="nextpage" value="Continue to step 2" onClick="javascript:submit()">
                    495:          </td>
                    496:         </tr>
                    497:        </table>
                    498:        </form> 
                    499:     |);  
                    500: }
                    501: 
                    502: 
                    503: # ---------------------------------------------------------------- Display One
                    504: 
                    505: sub display_one {
                    506:     my ($r,$uname,$fn,$page,$textref) = @_;
                    507:     $r->print(qq|
                    508:    <form method='post' name='display'>
                    509:    <table border='0' cellspacing='0' cellpadding='3' width='100%'>
                    510:     <tr bgcolor='#ccddaa'>
                    511:      <td>&nbsp;</td> 
                    512:      <td align='left'>
                    513:        <h3><font face='arial,helvetica,sans-serif'>Step 2: Identification of blocks of questions</b>&nbsp;</font></h3>
                    514:      </td>
                    515:     </tr>
                    516:     <tr>
                    517:      <td colspan='2'>&nbsp;</td>
                    518:     </tr>
                    519:     <tr>
                    520:      <td colspan='2'>
                    521:       <table border="0" cellspacing="0" cellpadding="2">
                    522:        <tr>
                    523:         <td>&nbsp;</td>
                    524:         <td colspan='2'>
                    525:          <font face='arial,helvetica,sans-serif'><b>Testbank data uploaded to the server:</b></font>
                    526:        </td>
                    527:       </tr>
                    528:       <tr>
                    529:        <td colspan='3'>&nbsp;</td>
                    530:       </tr>
                    531:       <tr>
                    532:        <td>&nbsp;</td>
                    533:        <td colspan='2'>
                    534:          <textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
                    535:     |);
                    536:     foreach my $line (@{$textref}) {
                    537:         $line =~ s/\n//g;
                    538:         $r->print("$line\n");
                    539:     }
                    540:     $r->print(qq|
                    541:        </textarea>
                    542:       </td>
                    543:      </tr>
                    544:      <tr>
                    545:       <td colspan='3'>&nbsp;</td>
                    546:      </tr>
                    547:      <tr>
                    548:      <tr>
                    549:       <td colspan='3'>&nbsp;</td>
                    550:      </tr>
                    551:      <tr bgcolor='#ccddaa'>
                    552:       <td>&nbsp;</td>
                    553:       <td align='left' valign='middle'><img src="/res/adm/pages/bl_step1.gif">&nbsp;&nbsp;
                    554:       </td>
                    555:       <td>
                    556:        <font face='arial,helvetica,sans-serif'><b>
                    557: Select the format of the question number</b> [e.g., 1,  1., 1), (1 or (1)].&nbsp;
                    558:                  <select name="qnumformat">
                    559:                   <option value = "-1" selected>Please Select
                    560:                   <option value="number">1
                    561:                   <option value="period">1.
                    562:                   <option value="paren">(1)
                    563:                   <option value="leadparen">(1
                    564:                   <option value="trailparen">1)
                    565:                  </select>
                    566:        </font>
                    567:       </td>
                    568:      </tr>
                    569:      <tr>
                    570:       <td colspan='3'>&nbsp;</td>
                    571:      </tr>
                    572:      <tr>
                    573:       <td>&nbsp;</td>
                    574:       <td colspan='2'><font face='arial,helvetica,sans-serif'>
                    575: A number in the specified format should appear at the start of each question. For multiple choice questions, the question number must begin the line that contains the question text; foils (starting (a), (i) etc.) should occur on subsequent lines. Correct answers should be numbered in the same way as the questions and should appear after <b>all</b> the questions (including question text and possible foils for all questions). Each numbered question must have a corresponding numbered answer, although the answer itself may be blank for essay questions.</td>
                    576:      </tr>
                    577:      <tr>
                    578:       <td colspan="3">&nbsp;</td>
                    579:      </tr>
                    580:      <tr>
                    581:       <td>&nbsp;</td>
                    582:       <td colspan='2'>
                    583:        <font face='arial,helvetica,sans-serif'>
                    584:         For example, you would select <b>1.</b> if your text file contained the following questions:<br><br>
                    585:  1. The capital of the USA is ..<br />
                    586:  &nbsp;&nbsp;(a) Washington D.C.<br />
                    587:  &nbsp;&nbsp;(b) New York<br />
                    588:  &nbsp;&nbsp;(c) Los Angeles<br />
                    589:  <br />
                    590:  2. The capital of Canada is ..<br />
                    591:  &nbsp;&nbsp;(a) Toronto<br />
                    592:  &nbsp;&nbsp;(b) Vancouver<br />
                    593:  &nbsp;&nbsp;(c) Ottawa<br />
                    594: <br />
                    595:  3. Describe an experiment you could conduct to measure c, the speed of light in a vacuum. <br /><br />
                    596:  1. (a)<br />
                    597:  2. (c)<br />
                    598:  3. <br />
                    599:       </td>
                    600:      <tr>
                    601:       <td colspan="3">&nbsp;</td>
                    602:      </tr>
                    603:      <tr bgcolor='#ccddaa'>
                    604:       <td>&nbsp;</td>
                    605:       <td><img src='/res/adm/pages/bl_step2.gif' align='left' valign='middle'>&nbsp;&nbsp;
                    606:       </td>
                    607:       <td>
                    608:        <font face='arial,helvetica,sans-serif'><b>
                    609: Please indicate the number of blocks of different question types in the text file.</b>&nbsp;&nbsp;
                    610:          <input type="text" name="blocks" value="" size="5">
                    611:       </td>
                    612:      </tr>
                    613:      <tr>
                    614:       <td colspan="3">&nbsp;</td>
                    615:      </tr>
                    616:      <tr>
                    617:       <td>&nbsp;</td>
                    618:       <td colspan='2'>
                    619:        <font face='arial,helvetica,sans-serif'>
                    620:         For example, you would enter <b>6</b> if your text file contained the following sequence of questions:<br><br>
                    621:  10 multiple choice questions<br>
                    622:   5 essay questions<br>
                    623:   5 fill-in-the-blank questions<br>
                    624:   5 multiple answer questions<br>
                    625:   4 multiple choice questions<br>
                    626:   3 essay questions<br>
                    627:       </font>
                    628:       </td>
                    629:      </tr>
                    630:      <tr>
                    631:       <td colspan='3'>&nbsp;</td>
                    632:      </tr>
                    633:      <tr>
                    634:        <td>&nbsp;</td>
                    635:        <td colspan='2'><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>
                    636:      </tr>
                    637:      <tr>
                    638:       <td colspan='3'>&nbsp;</td>
                    639:      </tr>
                    640:      <tr>
                    641:       <td colspan='3'>
                    642:        <table border='0' width="100%" cellspacing='0' cellpadding='2'>
                    643:         <tr>
                    644:          <td align='left'>
                    645:           <input type="button" name="backpage" value="Go back to step 1" onClick="javascript:backPage()">
                    646:          </td>
                    647:          <td align='right'>
                    648:           <input type="button" name="nextpage" value="Continue to step 3" onClick="javascript:nextPage()">
                    649:          </td>
                    650:         </tr>
                    651:        </table>
                    652:        <input type="hidden" name="page" value ="$page">
                    653:        <input type="hidden" name="go" value="">
                    654:        <input type="hidden" name="uploaduname" value="$uname">
                    655:        <input type="hidden" name="filename" value="$fn">
                    656:        <input type="hidden" name="phase" value="three">
                    657:       </td>
                    658:      </tr>
                    659:     </table>
                    660:    </td>
                    661:   </tr>
                    662:  </table>
                    663:  </form>
                    664:     |);
                    665: }
                    666: 
                    667: # ---------------------------------------------------------------- Display Two
                    668: 
                    669: sub display_two {
                    670:     my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
1.6       albertel  671:     my $blocks = $env{'form.blocks'};
                    672:     my $qnumformat = $env{'form.qnumformat'};
1.1       raeburn   673:     my @types = ("MC","MA","TF","Ess","FIB","Ord");
                    674:     my %typenames = (
                    675:              MC => "Multiple Choice",
                    676:              TF => "True/False",
                    677:              MA => "Multiple Answer",
                    678:              Ess => "Essay",
                    679:              FIB => "Fill-in-the-blank",
                    680:              Ord => "Ranking/ordering",
                    681:              );
                    682:     my %qnumtypes = (
                    683:              number => "1",
                    684:              period => "1.",
                    685:              paren => "(1)",
                    686:              leadparen => "(1",
                    687:              trailparen => "1)",
                    688:              );
                    689:     my @bgcolors = ('#ffffff','#eeeeee');
                    690:     my $bl1st = '';
                    691:     my $bl1end = '';
                    692:     if ($blocks == 1) {
                    693:         $bl1st = '1';
                    694:         $bl1end = $qcount;
                    695:     }
                    696:     $r->print(<<"END_OF_FUNC");
                    697:  <h3><font face='arial,helvetica,sans-serif'>Step 3: Classification of blocks</b>&nbsp;</font></h3>
                    698: <form method='post' name='display'>
                    699:    <table border='0' cellspacing='0' cellpadding ='0'>
                    700:     <tr>
                    701:      <td colspan='2'>&nbsp;</td>
                    702:     </tr>
                    703:     <tr>
                    704:      <td colspan='2'>
                    705:       <table border="0" cellspacing="0" cellpadding="0">
                    706:        <tr>
                    707:         <td>&nbsp;</td>
                    708:         <td><font face='arial,helvetica,sans-serif'>
                    709:           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 questions, and click "Return to step 2" on this page and the "Return to Step 1" on the preceding page, so you can upload your text file again.<br><br>
                    710:           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>
                    711:         </td>
                    712:        </tr>
                    713:        <tr>
                    714:         <td colpsan='2'>&nbsp;</td>
                    715:        </tr>
                    716:        <tr>
                    717:         <td>&nbsp;</td>
                    718:         <td><font face='arial,helvetica,sans-serif'>
                    719:           Please provide additional information below ,about the types of questions you have uploaded, and, if applicable, the format of answers and &quot;foils&quot; for specific types of questions.
                    720:         </td>
                    721:        </tr>
                    722:        <tr>
                    723:         <td colpsan='2'>&nbsp;</td>
                    724:        </tr>
                    725:        <tr>
                    726:         <td>&nbsp;</td>
                    727:         <td>
                    728: <font face='arial,helvetica,sans-serif'>The following data were uploaded to the server</font><br>
                    729: <textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
                    730: END_OF_FUNC
                    731:     foreach my $line (@{$textref}) {
                    732:         $line =~ s/\n//g;
                    733:         $r->print("$line\n");
                    734:     }
                    735:     $r->print(qq| 
                    736: </textarea>
                    737:       </td>
                    738:      </tr>
                    739:      <tr>
                    740:       <td colspan='2'>&nbsp;</td>
                    741:      </tr>
                    742:      <tr bgcolor='#ccddaa'>
                    743:       <td><img src='/res/adm/pages/bl_step3.gif' align='left' valign='middle'>
                    744:       </td>
                    745:       <td width='100%' align='left'>&nbsp;&nbsp;
                    746:        <font size='+1' face='arial,helvetica,sans-serif'><b>Information about question types and formats in each block.</b></font>
                    747:       </td>
                    748:      </tr>
                    749:      <tr>
                    750:       <td colspan='2'>&nbsp;</td>
                    751:      </tr>
                    752:      <tr>
                    753:       <td>&nbsp;</td>
                    754:       <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>
                    755:       </td>
                    756:      </tr>
                    757:      <tr>
                    758:       <td colspan='2'>&nbsp;</td>
                    759:      </tr>
                    760:      <tr>
                    761:       <td>&nbsp;</td>
                    762:       <td>
                    763:        <table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" align="left">
                    764:         <tr>
                    765:          <td>
                    766:           <table border="1" valign="top" align="center" width='100%'>
                    767:            <tr bgcolor="#eef6f6" align="left">
                    768:             <td>
                    769:              <table border='0' cellspacing='1' cellpadding='1' align='left' width='100%'>
                    770:               <tr bgcolor='#CCDDAA' align='center' valign='middle'>
                    771:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>
                    772:                 &nbsp;<b>Block</b>&nbsp;</font>
                    773:                </td>
                    774:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
                    775:                 &nbsp;<b>First&nbsp;number</b>&nbsp;</font>
                    776:                </td>
                    777:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
                    778:                 &nbsp;<b>Last&nbsp;number</b>&nbsp;</font>
                    779:                </td>
                    780:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
                    781:                 &nbsp;<b>Question&nbsp;type</b>&nbsp;</font>
                    782:                </td>
                    783:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
                    784:                 &nbsp;<b>Foil&nbsp;format</b>&nbsp;</font>
                    785:                </td>
                    786:                <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
                    787:                 &nbsp;<b>Answer&nbsp;format</b>&nbsp;</font>
                    788:                </td>
                    789:               </tr>
                    790:     |);
                    791:     for (my $i=0; $i<$blocks; $i++) {
                    792:         my $iter = $i+1;
                    793:         my $rowcol = $i%2;
                    794:         $r->print(qq|
                    795:  <tr bgcolor="$bgcolors[$rowcol]">
                    796:   <td align="left">
                    797:    <font face='arial,helvetica,sans-serif'>&nbsp;$iter.</font>
                    798:   </td>
                    799:   <td align="left">&nbsp;
                    800:    <input type="text" name="start_$i" value="$bl1st" size="5">&nbsp;
                    801:   </td>
                    802:   <td align="left">&nbsp;
                    803:    <input type="text" name="end_$i" value="$bl1end" size="5">&nbsp;
                    804:   </td>
                    805:   <td align="left">
                    806:    <font face='arial,helvetica,sans-serif'>
                    807:    <select name="qtype_$i" onChange="colSet($i)">
                    808:     <option value= "-1" selected>Please Select
                    809:         |);
                    810:         foreach my $qtype (@types) {
                    811:             $r->print(qq|<option value="$qtype">$typenames{$qtype}|);
                    812:         }
                    813:         $r->print(qq|
                    814:    </select>
                    815:    </font>
                    816:   </td>
                    817:   <td align="left">&nbsp;
                    818:     <select name="foilformat_$i">
                    819:      <option value="-1">&lt;--- Set type&nbsp; 
                    820:     </select>&nbsp;
                    821:   </td>
                    822:   <td align="left">&nbsp;
                    823:     <select name="ansr_$i">
                    824:      <option value="-1">&lt;--- Set type&nbsp;
                    825:     </select>
                    826:   </td>
                    827:  </tr>
                    828:         |);
                    829:     }
                    830:     $r->print(qq|
                    831:        </table>
                    832:       </td>
                    833:      </tr>
                    834:     </table>
                    835:    </td>
                    836:   </tr>
                    837:  </table>
                    838: </td>
                    839: </tr>
                    840: <tr>
                    841:  <td colspan="2">&nbsp;</td>
                    842: </tr>
                    843: <tr>
                    844:  <td>&nbsp;</td>
                    845:  <td>
                    846: <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 &quot;comma&quot;, or if they were listed as:</font><br><table border='0'><tr><td><font face='arial,helvetica,sans-serif'>28.&nbsp</font></td><td><font face='arial,helvetica,sans-serif'>(a)</font></td></tr><tr><td>&nbsp;</td><td><font face='arial,helvetica,sans-serif'>(d)</font></td></tr><tr><td>&nbsp;</td><td><font face='arial,helvetica,sans-serif'>(e)</font></td></tr></table>
                    847: <font face='arial,helvetica,sans-serif'>you would choose &quot;new line&quot;. 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 (ranked) answers.</font><br><br>
                    848:       </td>
                    849:      </tr>
                    850:      <tr>
                    851:       <td colspan='2'>&nbsp;</td>
                    852:      </tr>
                    853:      <tr>
                    854:       <td colspan='2'>
                    855: <input type="hidden" name="blocks" value="$blocks">
                    856: <input type="hidden" name="qnumformat" value="$qnumformat">
                    857:    <table border='0' width="100%" cellspacing='0' cellpadding='2'>
                    858:     <tr>
                    859:      <td align='left'>
                    860:       <input type="button" name="backpage" value="Go back to step 2" onClick="javascript:backPage()">
                    861:      </td>
                    862:      <td align='right'>
                    863:       <input type="button" name="nextpage" value="Continue to step 4" onClick="javascript:nextPage()">
                    864:      </td>
                    865:     </tr>
                    866:    </table>
                    867:    <input type="hidden" name="page" value ="$page">
                    868:    <input type="hidden" name="go" value="">
                    869:    <input type="hidden" name="uploaduname" value="$uname">
                    870:    <input type="hidden" name="filename" value="$fn">
                    871:    <input type="hidden" name="phase" value="three">
                    872:    </form>
                    873:   </td>
                    874:  </tr>
                    875: </table>
                    876: </td>
                    877: </tr>
                    878: </table>
                    879:     |);
                    880: } 
                    881: # ---------------------------------------------------------------- Display Three
                    882: sub display_three { 
                    883:     my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
1.6       albertel  884:     my $qnumformat = $env{'form.qnumformat'};
                    885:     my $filename = $env{'form.filename'};
                    886:     my $source = $env{'form.go'};
                    887:     my $blocks = $env{'form.blocks'};
1.1       raeburn   888:     my @items = ();
                    889:     my @bgcolors = ('#ffffff','#eeeeee');
                    890:     my @types = ("MC","MA","TF","Ess","FIB","Ord");
                    891:     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");
                    892:     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");
                    893:     my @start = ();
                    894:     my @end = ();
                    895:     my @nums = ();
                    896:     my @qtype = ();
                    897:     my @foilformats = ();
                    898:     my @ansrtypes = ();
                    899:     my %multparts = ();
                    900:     my $numitems = 0;
                    901:     for (my $i=0; $i<$blocks; $i++) {
1.6       albertel  902:         if (($env{"form.start_$i"} ne '') && ($env{"form.end_$i"} ne '')) {
                    903:             $start[$i] = $env{"form.start_$i"};
                    904:             $end[$i] = $env{"form.end_$i"};
1.1       raeburn   905:             $nums[$i] = $end[$i]-$start[$i] +1;
1.6       albertel  906:             $qtype[$i] = $env{"form.qtype_$i"};
1.1       raeburn   907:             if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
1.6       albertel  908:                 $foilformats[$i] = $env{"form.foilformat_$i"};
1.1       raeburn   909:             } else {
                    910:                 $foilformats[$i] = '';
                    911:             } 
                    912:             if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
1.6       albertel  913:                 $ansrtypes[$i] = $env{"form.ansr_$i"};
1.1       raeburn   914:             } else {
                    915:                 $ansrtypes[$i] = '';
                    916:             }  
                    917:         } else { 
                    918:             $nums[$i] = 0;
                    919:         }
                    920:         $numitems += $nums[$i];
                    921:     }
                    922: 
                    923:     my $import = join//,@{$textref};
                    924:     @items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
                    925:     $r->print(<<"END_OF_ONE");
                    926:  <h3><font face='arial,helvetica,sans-serif'>Step 4: Review and selection of destination directory</b>&nbsp;</font></h3>
                    927: <form name="dataForm" method="post">
                    928: <table border='0' bgcolor='#CCFFDD' cellspacing='0' cellpadding ='0'>
                    929:       <tr>
                    930:        <td colspan='2'>
                    931:         <table border='0' cellspacing='0' cellpadding='0'>
                    932:        <tr>
                    933:         <td colspan='2'>&nbsp;</td>
                    934:        </tr>
                    935:        <tr>
                    936:         <td>&nbsp;</td>
                    937:         <td><font face='arial,helvetica,sans-serif'><b>
                    938: Based on your previous responses your data have been split into a total of $numitems questions.</b> 
                    939:         </td>
                    940:       </tr>
                    941:       <tr>
                    942:         <td colspan='2'>&nbsp;</td>
                    943:       </tr>
                    944:       <tr>
                    945:        <td>&nbsp;</td>
                    946:      <td width="80%" bgcolor="#000000" align="left">
                    947:      <table width="100%" border="0" cellpadding="1" cellspacing="0">
                    948:       <tr>
                    949:        <td width="100%" bgcolor="#000000">
                    950:         <table border="0" cellspacing="0" cellpadding="1" width="100%">
                    951:          <tr>
                    952:           <td width="100%" bgcolor="#000000">
                    953:            <table border="0" cellpadding="0" cellspacing="1" bgcolor="#ffffff" width="100%">
                    954:             <tr>
                    955:              <td bgcolor="#CCFFDD" width="100%">
                    956:               <table border='0' cellspacing='1' cellpadding='2' align='left' width= '100%'>
                    957:                <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>
                    958: END_OF_ONE
                    959:     for (my $j=0; $j<$numitems; $j++) {
                    960:         my $qnum = $j+1;
                    961:         my $rowcol = $j%2;
                    962:         $rowcol = @bgcolors[$rowcol];
                    963:         for (my $i=0; $i<$blocks; $i++) {
                    964:             if ($nums[$i] > 0) {
                    965:                 if (($j+1 >= $start[$i]) && ($j+1 <= $end[$i])) { 
                    966:                     if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA")) { 
                    967:                         for (my $k=0; $k<@{$multparts{$j}}; $k++) {
                    968:                             if ($k == 0) {
                    969:                                 $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|);
                    970:                             } else { 
                    971:                                 my $foiltag = '';
                    972:                                 if ($foilformats[$i] eq "lcperiod") {
                    973:                                     $foiltag = $alphabet[$k-1].'.'; 
                    974:                                 } elsif ($foilformats[$i] eq "lcparen") {
                    975:                                     $foiltag = '('.$alphabet[$k-1].')';
1.5       raeburn   976:                                 } elsif ($foilformats[$i] eq "lconeparen") {
                    977:                                     $foiltag = $alphabet[$k-1].')';
                    978:                                 } elsif ($foilformats[$i] eq "lcdotparen") {
                    979:                                     $foiltag = $alphabet[$k-1].'.)';
1.1       raeburn   980:                                 } elsif ($foilformats[$i] eq "ucperiod") {
                    981:                                     $foiltag = $alphabet[$k-1].'.';
                    982:                                     $foiltag =~ tr/a-z/A-Z/;
                    983:                                 } elsif ($foilformats[$i] eq "ucparen") {
                    984:                                     $foiltag = '('.$alphabet[$k-1].')';
                    985:                                     $foiltag =~ tr/a-z/A-Z/;
1.5       raeburn   986:                                 } elsif ($foilformats[$i] eq "uconeparen") {
                    987:                                     $foiltag = $alphabet[$k-1].')';
                    988:                                     $foiltag =~ tr/a-z/A-Z/;
                    989:                                 } elsif ($foilformats[$i] eq "ucdotparen") {
                    990:                                     $foiltag = $alphabet[$k-1].'.)';
                    991:                                     $foiltag =~ tr/a-z/A-Z/;
1.1       raeburn   992:                                 } elsif ($foilformats[$i] eq "romperiod") {
                    993:                                     $foiltag = $romans[$k-1].'.';
                    994:                                 } elsif ($foilformats[$i] eq "romparen") {
                    995:                                     $foiltag = '('.$romans[$k-1].')';
1.5       raeburn   996:                                 } elsif ($foilformats[$i] eq "romoneparen") {
                    997:                                     $foiltag = $romans[$k-1].')';
                    998:                                 } elsif ($foilformats[$i] eq "romdotparen") {
                    999:                                     $foiltag = $romans[$k-1].'.)';
                   1000:                                 } 
1.1       raeburn  1001:                                 $r->print(qq|$foiltag $multparts{$j}[$k]<br>\n|);
                   1002:                             }
                   1003:                         }
                   1004:                         $r->print(qq|<br></font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$items[$j+$numitems]</font></td></tr>|);
                   1005:                     } else {
                   1006:                         $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>|);
                   1007:                     }
                   1008:                     last;
                   1009:                 }
                   1010:             }
                   1011:         }
                   1012:     }
                   1013:     $r->print(qq|
                   1014:               </table>
                   1015:               </td>
                   1016:               </tr>
                   1017:               </table>
                   1018:              </td>
                   1019:             </tr>
                   1020:            </table>
                   1021:           </td>
                   1022:          </tr>
                   1023:         </table>
                   1024:        </td>
                   1025:       </tr>
                   1026:       <tr>
                   1027:        <td colspan='2'>&nbsp;</td>
                   1028:       </tr>
                   1029:       <tr bgcolor='#ccddaa'>
                   1030:        <td width='30' align='top'><img src='/res/adm/pages/bl_step4.gif'>
                   1031:        </td>
                   1032:        <td width='100%' align='left'>&nbsp;&nbsp;
1.12      albertel 1033:         <font size='+1' face='arial,helvetica,sans-serif'><b>Create a directory to save your testbank questions.</b></font>
1.1       raeburn  1034:        </td>
                   1035:       </tr>
                   1036:       <tr>
                   1037:        <td colspan='2'>&nbsp;</td>
                   1038:       </tr>
                   1039:       <tr>
                   1040:        <td>&nbsp;</td>
                   1041:        <td>
                   1042:         <font face='Arial,Helvetica,sans-serif'>
1.12      albertel 1043: Please choose a destination LON-CAPA directory in which to save your uploaded questions.&nbsp;&nbsp;
1.1       raeburn  1044:        <input type="button" name="createdir" value="Create Directory" onClick="javascript:createWin()"><input type="hidden" name="newdir" value=""></font></td>
                   1045:       </tr>
                   1046:       <tr>
                   1047:        <td colspan='2'>&nbsp;</td>
                   1048:       </tr>
                   1049:       <tr>
                   1050:        <td>&nbsp;</td>
                   1051:        <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 click the "Continue to step 5" button to convert the questions in your testbank to LON-CAPA problem files.</font></td>
                   1052:       </tr>
                   1053:       <tr>
                   1054:        <td colspan='2'>
                   1055:           <input type='hidden' name="go" value="">
                   1056:           <input type='hidden' name="qnumformat" value="$qnumformat">
                   1057:           <input type='hidden' name="blocks" value="$blocks">
                   1058:           <input type="hidden" name="uploaduname" value="$uname">
                   1059:           <input type="hidden" name="filename" value="$fn">
                   1060:           <input type='hidden' name="page" value="$page">
                   1061:           <input type="hidden" name="phase" value="three">
                   1062:     |);
                   1063:     for (my $i=0; $i<$blocks; $i++) {
                   1064:         $r->print(qq|
                   1065:           <input type='hidden' name="start_$i" value="$start[$i]">
                   1066:           <input type='hidden' name="end_$i" value="$end[$i]">
                   1067:           <input type='hidden' name="qtype_$i" value="$qtype[$i]">
                   1068:         |);
                   1069:         if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
                   1070:             $r->print(qq|
                   1071:           <input type='hidden' name="foilformat_$i" value="$foilformats[$i]">
                   1072:             |);
                   1073:         }
                   1074:         if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
                   1075:             $r->print(qq|
                   1076:           <input type='hidden' name="ansr_$i" value="$ansrtypes[$i]">
                   1077:             |);
                   1078:         }
                   1079:     }
                   1080:     $r->print(qq|
                   1081:        </td>
                   1082:       </tr>
                   1083:       <tr>
                   1084:        <td colspan='2'>&nbsp;<br /><br /></td>
                   1085:       </tr>
                   1086:       <tr>
                   1087:        <td colspan='2'>
                   1088:         <table border='0' cellspacing='0' cellpadding='0' width="100%">
                   1089:          <tr>
                   1090:           <td align='left'>
                   1091:            <input type="button" name="backpage" value="Go back to step 3" onClick="javascript:backPage()">
                   1092:           </td>
                   1093:           <td align='right'>
                   1094:            <input type="button" name="nextpage" value="Continue to step 5" onClick="javascript:nextPage()">
                   1095:           </td>
                   1096:          </tr>
                   1097:         </table>
                   1098:        </td>
                   1099:       </tr>
                   1100:      </table>
                   1101:     </td>
                   1102:    </tr>
                   1103:   </table>
                   1104: </form>
                   1105:     |);
                   1106: }
                   1107: 
                   1108: # ---------------------------------------------------------------- Final Display
                   1109: sub final_display {
                   1110:     my ($r,$uname,$fn,$page,$textref) = @_;
1.6       albertel 1111:     my $qnumformat = $env{'form.qnumformat'};
                   1112:     my $blocks = $env{'form.blocks'};
                   1113:     my $newdir = $env{'form.newdir'};
1.1       raeburn  1114:     my $linkdir = $newdir;
                   1115:     if ($linkdir =~ m#^/home/$uname/public_html/(.+)$#) {
                   1116:         $linkdir = '/priv/'.$uname.'/'.$1;
                   1117:     }
                   1118:     my $question_id = '';
                   1119:     my @question_title = ();
                   1120:     my @question_status  = ();
                   1121:     my @qtype = ();
                   1122:     my @start = ();
                   1123:     my @nums = ();
                   1124:     my @end = ();
                   1125:     my @foilformats = ();
                   1126:     my @ansrtypes = ();
                   1127:     my %multparts = ();
                   1128:     my $numitems = 0;
                   1129:     for (my $i=0; $i<$blocks; $i++) {
1.6       albertel 1130:         $start[$i] = $env{"form.start_$i"};
                   1131:         $end[$i] = $env{"form.end_$i"};
1.1       raeburn  1132:         if (($end[$i] - $start[$i]) >= 0) {
                   1133:             $nums[$i] = $end[$i] - $start[$i]+1;
                   1134:         } else {
                   1135:             $nums[$i] = 0;
                   1136:         }
1.6       albertel 1137:         $qtype[$i] = $env{"form.qtype_$i"};
1.1       raeburn  1138:         if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
1.6       albertel 1139:             $foilformats[$i] = $env{"form.foilformat_$i"};
1.1       raeburn  1140:         } else {
                   1141:             $foilformats[$i] = '';
                   1142:         }
                   1143:         if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
1.6       albertel 1144:             $ansrtypes[$i] = $env{"form.ansr_$i"};
1.1       raeburn  1145:         }
                   1146:         $numitems += $nums[$i];
                   1147:     }
                   1148: 
                   1149:     my @bgcolors = ('#ffffff','#eeeeee');
                   1150: 
                   1151:     my $import = join/'\s'/,@{$textref};
                   1152:     my %answers = ();
                   1153:     my @items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
                   1154: 
                   1155: # Converting MC and MA answer to number, and splitting answers for FIB, and ordering for Ord.
                   1156:   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");
                   1157:     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");
                   1158:     my %patterns = (
                   1159:          comma => ',',
                   1160:          space => '\s+',
                   1161:          line => '[\r\n\f]+',
                   1162:          tab => '\t+',
                   1163:        );
                   1164:     for (my $i=0; $i<$blocks; $i++) {
                   1165:         if ($nums[$i] > 0) {
                   1166:             if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
                   1167:                 for (my $k=$numitems+$start[$i]-1; $k<$numitems+$end[$i]; $k++) {
                   1168:                     @{$answers{$k}} = ();
                   1169:                     if ($qtype[$i] eq "MC") {
1.4       raeburn  1170:                         $items[$k] =~ tr/A-Z/a-z/;
1.1       raeburn  1171:                         $items[$k] =~ s/\W//g;
1.5       raeburn  1172:                         if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "lconeparen" || $foilformats[$i] eq "lcdotparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod" || $foilformats[$i] eq "uconeparen" || $foilformats[$i] eq "ucdotparen") {
1.1       raeburn  1173:                             for (my $j=0; $j<@alphabet; $j++) {
                   1174:                                 if ($alphabet[$j] eq $items[$k]) {
                   1175:                                     push @{$answers{$k}}, $j;
                   1176:                                     last;
                   1177:                                 }
                   1178:                             }
1.5       raeburn  1179:                         } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod") || ($foilformats[$i] eq "romoneparen") || ($foilformats[$i] eq "romdotparen")) {
1.1       raeburn  1180:                             for (my $j=0; $j<@romans; $j++) {
                   1181:                                 if ($romans[$j] eq $items[$k]) {
                   1182:                                     push @{$answers{$k}}, $j;
                   1183:                                     last;
                   1184:                                 }
                   1185:                             }
                   1186:                         }
                   1187:                     } elsif (($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
1.4       raeburn  1188:                         $items[$k] =~ tr/A-Z/a-z/;
1.1       raeburn  1189:                         my @corrects = split/$patterns{$ansrtypes[$i]}/,$items[$k];
                   1190:                         foreach my $correct (@corrects) {
                   1191:                             $correct =~s/\W//g;
                   1192:                             if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") {
                   1193:                                 for (my $j=0; $j<@alphabet; $j++) {
                   1194:                                     if ($alphabet[$j] eq $correct) {
                   1195:                                         push @{$answers{$k}}, $j;
                   1196:                                         last;
                   1197:                                     }
                   1198:                                 }
1.5       raeburn  1199:                             } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod") || ($foilformats[$i] eq "romoneparen") || ($foilformats[$i] eq "romdotparen")) {
1.1       raeburn  1200:                                 for (my $j=0; $j<@romans; $j++) {
                   1201:                                     if ($romans[$j] eq $correct) {
                   1202:                                         push @{$answers{$k}}, $j;
                   1203:                                         last;
                   1204:                                     }
                   1205:                                 }
                   1206:                             }
                   1207:                         }
                   1208:                     } elsif ($qtype[$i] eq "FIB") {
                   1209:                         @{$answers{$k}} = split/$patterns{$ansrtypes[$i]}/,$items[$k];
                   1210:                         for (my $j=0; $j<@{$answers{$k}}; $j++) {
                   1211:                             $answers{$k}[$j] =~ s/^\s+//;
                   1212:                             $answers{$k}[$j] =~ s/\s+$//;
                   1213:                         }
                   1214:                     }
                   1215:                 }
                   1216:             }
                   1217:         }
                   1218:     }
                   1219:     my $pooltarget = '';
                   1220:     my $pooldesc = '';
                   1221:     my @newquestions = ();
                   1222:     my $numquestions = 0;
                   1223:     my %qtype = ();
                   1224:     my %qtext = ();
                   1225:     my %qflag = ();
                   1226: 
                   1227:     $r->print(<<"END_OF_BLOCK");
                   1228:         <form name="verify" method="post">
                   1229:         <table border='0' cellspacing='0' cellpadding='0' width="100%">
                   1230:          <tr>
                   1231:           <td colspan='2'  align='left'>&nbsp;
                   1232:           </td>
                   1233:          </tr>
                   1234:          <tr bgcolor='#ccddaa'>
                   1235:           <td align='top'>&nbsp;
                   1236:           </td>
                   1237:           <td valign='middle'><img src='/res/adm/pages/bl_step5.gif'>&nbsp;&nbsp;
                   1238:            <font size='+1' face='arial,helvetica,sans-serif'>&nbsp;<b>Result of conversion of tesbank questions to LON-CAPA problems.</b></font>
                   1239:           </td>
                   1240:          </tr>
                   1241:          <tr>
                   1242:           <td colspan='2'>&nbsp;</td>
                   1243:          </tr>
                   1244: END_OF_BLOCK
                   1245:     if ($newdir ne "") {
                   1246:         my @qn_file = ();
                   1247:         my $qcount = 0;
                   1248:         for (my $i=0; $i<$blocks; $i++) {
                   1249:             if ($nums[$i] > 0) {
                   1250:                 if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
                   1251:                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
                   1252:                         my $answer = $j + $numitems;
                   1253:                         my $numans = scalar(@{$answers{$answer}});
                   1254:                         my $foilcount = 0;
                   1255:                         if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) { 
                   1256:                             $foilcount = @{$multparts{$j}};
                   1257:                             $foilcount --;
                   1258:                         }
                   1259:                         $qn_file[$qcount] = &create_mcq($newdir,\@{$multparts{$j}},\@{$answers{$answer}},$qtype[$i],$j);
                   1260:                         $qcount ++;
                   1261:                         push @newquestions, $question_id;
                   1262:                     }
                   1263:                 } elsif ($qtype[$i] eq "TF") {
                   1264:                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
                   1265:                         my $answer = $j + $numitems;
                   1266:                         $items[$answer] =~ s/^\s+//;
                   1267:                         $items[$answer] =~ s/\s+$//;
                   1268:                         $items[$answer] =~ s/\W//g;
                   1269:                         $items[$answer] =~ tr/A-Z/a-z/;
                   1270:                         my $answer_id = '';
                   1271:                         if ($ansrtypes[$i] eq 'word' ) {
                   1272:                             if ($items[$answer] =~ m/true/) {
                   1273:                                 $answer_id = 0;
                   1274:                             } else {
                   1275:                                 $answer_id = 1;
                   1276:                             }
                   1277:                         } elsif ($ansrtypes[$i] eq 'lett') {
                   1278:                             if ($items[$answer] =~ m/^t/) {
                   1279:                                 $answer_id = 0;
                   1280:                             } else {
                   1281:                                 $answer_id = 1;
                   1282:                             }
                   1283:                         }
                   1284:                         $qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$j);
                   1285:                         push @newquestions, $question_id;
                   1286:                         $qcount ++;
                   1287:                     }
                   1288:                 } elsif ($qtype[$i] eq "Ess") {
                   1289:                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
                   1290:                         my $answer = $j + $numitems;
                   1291:                         my $answer_id = '';
                   1292:                         $qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$j);
                   1293:                         push @newquestions, $question_id;
                   1294:                         $qcount ++;
                   1295:                     }
                   1296:                 }
                   1297:             }
                   1298:         }
                   1299:         $r->print(qq|<tr><tr><td>&nbsp;</td><td><font face='arial,helvetica,sans-serif'>Individual problem files have been created from the problems included in the textbank file:
                   1300:        <ul>|);
                   1301:         for (my $i=0; $i<@qn_file; $i++) {
                   1302:             my $display = $i+1;
                   1303:             $r->print(qq|
                   1304:        <li><b><a href="$linkdir/$qn_file[$i]">Problem $display file</a></b></li>
                   1305:             |);
                   1306:         }
                   1307:         $r->print(qq|
                   1308:        </ul></font></td></tr>
                   1309:        <tr><td>&nbsp;</td>
                   1310:            <td><font face='arial,helvetica,sans-serif'>The problems must be published before they can be used in a course.</font></td>
                   1311:         |);
                   1312:     } else {
                   1313:         $r->print(qq|
                   1314:          <tr>
                   1315:           <td>&nbsp;</td>
                   1316:           <td><font face='arial,helvetica,sans-serif'>No destination file was selected or created, so import of your questions could not proceed.  
                   1317:           Please return to the previous page and select a valid file into which to import the questions. </font>
                   1318:            <input type="hidden" name="go" value="">
                   1319:            <input type="hidden" name="page" value="$page">
                   1320:            <input type="hidden" name="uploaduname" value="$uname">
                   1321:            <input type="hidden" name="filename" value="$fn">
                   1322:            <input type='hidden' name="page" value="$page">
                   1323:            <input type="hidden" name="phase" value="three">
                   1324:            <input type="hidden" name="qnumformat" value="$qnumformat">
                   1325:            <input type="hidden" name="newdir" value="$newdir">
                   1326:         |);
                   1327:         for (my $i=0; $i<$blocks; $i++) {
                   1328:            $r->print(qq|
                   1329:            <input type="hidden" name="start_$i" value="$start[$i]">
                   1330:            <input type="hidden" name="end_$i" value="$end[$i]">
                   1331:            <input type="hidden" name="qtype_$i" value="$qtype[$i]">
                   1332:            <input type="hidden" name="foilformat_$i" value="$foilformats[$i]">
                   1333:            <input type="hidden" name="ansr_$i" value="$ansrtypes[$i]">
                   1334:             |);
                   1335:         }
                   1336:         $r->print(<<"END_OF_FAIL");
                   1337:           </td>
                   1338:          </tr>
                   1339:          <tr>
                   1340:           <td colspan='2'>
                   1341:            <table border='0' width='100%'>
                   1342:             <tr>
                   1343:              <td align='right'>
                   1344:               <input type="button" name="backpage" value="Return to step 3" onClick="javascript:backPage()">
                   1345:              </td>
                   1346:             </tr>
                   1347:            </table>
                   1348:           </td>
                   1349:          </tr>
                   1350:         </table>
                   1351:        </td>
                   1352:       </tr>
                   1353:      </table>
                   1354:     </td>
                   1355:    </tr>
                   1356:   </table>
                   1357:  </form>
                   1358: END_OF_FAIL
                   1359:     return;
                   1360:   }
                   1361:   $r->print(<<"END_OF_BODY");
                   1362:              </table>
                   1363:             </td>
                   1364:            </tr>
                   1365:           </table>
                   1366:         </td>
                   1367:        </tr>
                   1368:        <tr>
                   1369:         <td colspan='2'>&nbsp;
                   1370:          <input type="hidden" name="go" value="">
                   1371:          <input type="hidden" name="page" value="$page">
                   1372:          <input type="hidden" name="uploaduname" value="$uname">
                   1373:          <input type="hidden" name="filename" value="$fn">
                   1374:          <input type='hidden' name="page" value="$page">
                   1375:          <input type="hidden" name="phase" value="one">
                   1376:          <input type="hidden" name="qnumformat" value="$qnumformat"> 
                   1377:          <input type="hidden" name="newdir" value="$newdir">
                   1378:         </td>
                   1379:        </tr>
                   1380:        <tr>
                   1381:         <td colspan='2'>
                   1382:          <table border='0' width='100%'>
                   1383:           <tr>
                   1384:            <td align='left'>
                   1385:              <input type='button' name='backtostart' value='Back to start page' onClick='javascript:backtoStart()'>
                   1386:            </td>
                   1387:           </tr>
                   1388:          </table>
                   1389:         </td>
                   1390:        </tr>
                   1391:       </table>
                   1392:      </td>
                   1393:     </tr>
                   1394:    </table>
                   1395:   </td>
                   1396:  </tr>
                   1397: </table>
                   1398: </form>
                   1399: END_OF_BODY
                   1400: }
                   1401: 
                   1402: sub question_count {
                   1403:     my ($qnumformat,$textref) = @_;
                   1404:     my $text_in = join "\n", @{$textref};
                   1405:     $text_in = "\n ".$text_in;
                   1406:     my $qpattern ='';
                   1407:     if ($qnumformat eq "period") {
                   1408:         $qpattern = '\d{1,}\.';
                   1409:     } elsif ($qnumformat eq "paren") {
                   1410:         $qpattern = '\(\d{1,}\)';
                   1411:     } elsif ($qnumformat eq "number") {
                   1412:         $qpattern = '\d{1,}';
                   1413:     } elsif ($qnumformat eq "leadparen") {
                   1414:         $qpattern = '\(\d{1,}';
                   1415:     } elsif ($qnumformat eq "trailparen") {
                   1416:         $qpattern = '\d{1,}\)';
                   1417:     }
                   1418:     my @questions = split/[\r\n\f]+\s?$qpattern\s?/,$text_in;
                   1419:     my $qcount = scalar(@questions);
                   1420:     $qcount = $qcount/2;
                   1421:     $qcount = int($qcount);
                   1422:     return $qcount;
                   1423: }
                   1424: 
                   1425: sub file_split {
                   1426:     my ($startsref,$endsref,$numsref,$qnumformat,$foilsref,$textref,$multpartsref,$numitems,$qtyperef,$blocks) = @_;
                   1427:     my $text_in = join "\n", @{$textref};
                   1428:     $text_in = "\n ".$text_in;
                   1429:     my $dignum = length($numitems);
                   1430:     my $numpat;
                   1431:     if ($dignum > 1) {
                   1432:         $numpat = ','.$dignum.'}';
                   1433:     } else {
                   1434:         $numpat = '}';
                   1435:     }
                   1436:     my $qpattern ='';
                   1437:     if ($qnumformat eq "period") {
                   1438:         $qpattern = '\d{1'.$numpat.'\.'; 
                   1439:     } elsif ($qnumformat eq "paren") {
                   1440:         $qpattern = '\(\d{1'.$numpat.'\)';
                   1441:     } elsif ($qnumformat eq "number") {
                   1442:         $qpattern = '\d{1'.$numpat;
                   1443:     } elsif ($qnumformat eq "leadparen") {
                   1444:         $qpattern = '\(\d{1'.$numpat;
                   1445:     } elsif ($qnumformat eq "trailparen") {
                   1446:         $qpattern = '\d{1'.$numpat.'\)';
                   1447:     }
1.5       raeburn  1448:     my @questions = split/[\r\n\f]+\s*$qpattern\s*/,$text_in;
1.1       raeburn  1449: # my @questions = split/\n\s\d{1,3}\.\s/,$text_in;
                   1450:     shift @questions;
                   1451:     my %multparts = ();
                   1452:     for (my $i=0; $i<$blocks; $i++) {
                   1453:         if (${$numsref}[$i] > 0) {
                   1454:             if ((${$qtyperef}[$i] eq "MC") || (${$qtyperef}[$i] eq "MA")) {
                   1455:                 my $splitstr = '';
                   1456:                 if (${$foilsref}[$i] eq "lcperiod") {
                   1457:                     $splitstr = '[a-z]\.';
                   1458:                 } elsif (${$foilsref}[$i] eq "lcparen") {
                   1459:                     $splitstr = '\([a-z]\)';
1.5       raeburn  1460:                 } elsif (${$foilsref}[$i] eq "lconeparen") {
                   1461:                     $splitstr = '[a-z]\)';
                   1462:                 } elsif (${$foilsref}[$i] eq "lcdotparen") {
                   1463:                     $splitstr = '[a-z]\.\)';
1.1       raeburn  1464:                 } elsif (${$foilsref}[$i] eq "ucperiod") {
                   1465:                     $splitstr = '[A-Z]\.';
                   1466:                 } elsif (${$foilsref}[$i] eq "ucparen") {
                   1467:                     $splitstr = '\([A-Z]\)';
1.5       raeburn  1468:                 } elsif (${$foilsref}[$i] eq "uconeparen") {
                   1469:                     $splitstr = '[A-Z]\)';
                   1470:                 } elsif (${$foilsref}[$i] eq "ucdotparen") {
                   1471:                     $splitstr = '[A-Z]\.\)';
1.1       raeburn  1472:                 } elsif (${$foilsref}[$i] eq "romperiod") {
                   1473:                     $splitstr = '[ivx]+\.';
                   1474:                 } elsif (${$foilsref}[$i] eq "romparen") {
                   1475:                     $splitstr = '\([ivx]+\)';
1.5       raeburn  1476:                 } elsif (${$foilsref}[$i] eq "romoneparen") {
                   1477:                     $splitstr = '[ivx]+\)';
                   1478:                 } elsif (${$foilsref}[$i] eq "romdotparen") {
                   1479:                     $splitstr = '[ivx]+\.\)';
1.1       raeburn  1480:                 }
                   1481:                 for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) {
1.5       raeburn  1482:                     @{$multparts{$j}} = split/[\r\n\f]+\s*$splitstr\s*/,$questions[$j];
1.1       raeburn  1483:                     chomp(@{$multparts{$j}});
                   1484:                 }
                   1485:             } elsif (${$qtyperef}[$i] eq "FIB") { 
                   1486:                 for (my $j=${$startsref}[$i]-1; $j<${$endsref}[$i]; $j++) {
                   1487:                     @{$multparts{$j}} = ("$questions[$j]");
                   1488:                 }
                   1489:             }
                   1490:         }
                   1491:     }    
                   1492:     %{$multpartsref} = %multparts;
                   1493:     return @questions;
                   1494: }
                   1495:  
                   1496: # create_mcq builds an MC, MA, Ord or FIB question
                   1497: 
                   1498: sub create_mcq {
                   1499:     my ($newdir,$qstnref,$answerref,$qtype,$qnum) = @_;
                   1500:     $qnum ++;
                   1501:     if (length($qnum) == 1) {
                   1502:         $qnum = "00".$qnum;
                   1503:     } elsif (length($qnum) == 2) {
                   1504:         $qnum = "0".$qnum;
                   1505:     }
                   1506:     my $qstn = ${$qstnref}[0];
                   1507:     my $numfoils = scalar(@{$qstnref}) - 1; 
                   1508:     my $datestamp = localtime;
                   1509:     my $timestamp = time;
                   1510:     my $libfile = 'question_'.$qnum;
                   1511:     $libfile .= '.problem';
                   1512:     my $numansrs = scalar(@{$answerref});
                   1513:     my $output = qq|<problem>
                   1514:  <startouttext />$qstn<endouttext />
                   1515:     |;
                   1516:   
                   1517:     if ($qtype eq "MA") {
                   1518:         $output .= qq|
                   1519:    <optionresponse max="$numfoils" randomize="yes">
                   1520:     <foilgroup options="('True','False')">
                   1521:         |;
                   1522:         for (my $k=0; $k<@{$qstnref}-1; $k++) {
                   1523:             $output .= "   <foil name=\"foil".$k."\" value=\"";
                   1524:             if (grep/^$k$/,@{$answerref}) {
                   1525:                 $output .= "True\" location=\"random\"";
                   1526:             } else {
                   1527:                 $output .= "False\" location=\"random\"";
                   1528:             }
                   1529:             $output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
                   1530:         }
                   1531:         chomp($output);
                   1532:         $output .= qq|
                   1533:     </foilgroup>
                   1534:    </optionresponse>
                   1535:   </problem>
                   1536:         |;
                   1537:     }
                   1538:     if ($qtype eq "MC") {
                   1539:         $output .= qq|
                   1540:    <radiobuttonresponse max="$numfoils" randomize="yes">
                   1541:     <foilgroup>
                   1542:         |;
                   1543:         for (my $k=0; $k<@{$qstnref}-1; $k++) {
                   1544:             $output .= "   <foil name=\"foil".$k."\" value=\"";
                   1545:             if (grep/^$k$/,@{$answerref}) {
                   1546:                 $output .= "true\" location=\"";
                   1547:             } else {
                   1548:                 $output .= "false\" location=\"";
                   1549:             }
                   1550:             if (lc (${$qstnref}[$k+1]) =~ m/^\s?([Aa]ll)|([Nn]one)\sof\sthe\sabove\.?/) { 
                   1551:                 $output .= "bottom\"";
                   1552:             } else {
                   1553:                 $output .= "random\"";
                   1554:             }
                   1555:             $output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
                   1556:         }
                   1557:         chomp($output);
                   1558:         $output .= qq|
                   1559:     </foilgroup>
                   1560:    </radiobuttonresponse>
                   1561:   </problem>
                   1562:         |;
                   1563:     }
                   1564: 
                   1565:     if ($qtype eq "Ord") {
                   1566:         $output .= qq|
                   1567:    <rankresponse max="$numfoils" randomize="yes">
                   1568:     <foilgroup>
                   1569:         |;
                   1570:         for (my $k=0; $k<@{$qstnref}-1; $k++) {
                   1571:             $output .= "   <foil location=\"random\" name=\"foil".$k."\" value=\"".$$answerref[$k]."\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
                   1572:         }
                   1573:         chomp($output);
                   1574:         $output .= qq|
                   1575:     </foilgroup>
                   1576:    </rankresponse>
                   1577:   </problem>
                   1578:         |;
                   1579:     }
                   1580:    
                   1581:     if ($qtype eq "FIB") {
                   1582:         my $numerical = 1;
                   1583:         for (my $i=0; $i<@{$answerref}; $i++) {
                   1584:             if (${$answerref}[$i] =~ m/([^\d\.]|\.\.)/) {
                   1585:                 $numerical = 0;
                   1586:             }
                   1587:         }
                   1588:         if ($numerical) {
                   1589:             my $numans;
                   1590:             my $tol;
                   1591:             if (@{$answerref} == 1) {
                   1592:                 $tol = 5;
                   1593:                 $numans = $$answerref[0];
                   1594:             } else {
1.2       raeburn  1595:                 my $min = $$answerref[0];
                   1596:                 my $max = $$answerref[0];    
                   1597:                 for (my $i=1; $i<@{$answerref}; $i++) {
                   1598:                     if ($$answerref[$i]<=$min) {
1.1       raeburn  1599:                         $min = $$answerref[$i];
1.2       raeburn  1600:                     } elsif ($$answerref[$i] >= $max) {
1.1       raeburn  1601:                         $max = $$answerref[$i];
                   1602:                     }
                   1603:                 }
                   1604:                 $numans = ($max + $min)/2;
                   1605:                 $tol = 100*($max - $min)/($numans*2); 
                   1606:             }
                   1607:             $output .= qq|
                   1608: <numericalresponse answer="$numans">
                   1609: 	<responseparam type="tolerance" default="$tol%" name="tol" description="Numerical Tolerance" />
                   1610: 	<responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures" />
                   1611: 	<textline />
                   1612: </numericalresponse>
                   1613: </problem>
                   1614: |;
                   1615:         } else {
                   1616:             if (@{$answerref} == 1) {
                   1617:                 $output .= qq|
                   1618: <stringresponse answer="$$answerref[0]" type="ci">
                   1619: <textline>
                   1620: </textline>
                   1621: </stringresponse>
                   1622: </problem>
                   1623: |;
                   1624:             } else {
                   1625:                 for (my $i=0; $i<@{$answerref}; $i++) {
                   1626:                     ${$answerref}[$i] =~ s/\|/\|/g;
                   1627:                 }
                   1628:                 my $regexpans = join('|',@{$answerref});
                   1629:                 $regexpans = '/('.$regexpans.')/'; 
                   1630:                 $output .= qq|
                   1631: <stringresponse answer="$regexpans" type="re">
                   1632: <textline>
                   1633: </textline>
                   1634: </stringresponse>
                   1635: </problem>
                   1636: |;
                   1637:             }
                   1638:         }
                   1639:     }
                   1640:     open(PROB,">$newdir/$libfile");
                   1641:     print PROB $output;
                   1642:     close PROB;
                   1643:     return $libfile;
                   1644: }
                   1645: 
                   1646: # create_ess builds an essay or True/False question
                   1647: 
                   1648: sub create_ess {
                   1649:     my ($newdir,$answer_id,$qstn,$answertxt,$qtype,$qnum) = @_;
                   1650:     $qnum ++;
                   1651:     if (length($qnum) == 1) {
                   1652:         $qnum = "00".$qnum;
                   1653:     } elsif (length($qnum) == 2) {
                   1654:         $qnum = "0".$qnum;
                   1655:     }
                   1656:     my $libfile = 'question_'.$qnum;
                   1657:     $libfile .= '.problem';
                   1658:     my $output = qq|<problem>
                   1659:  <startouttext />$qstn<endouttext />|;
                   1660: 
                   1661:     my $answer = '';
                   1662:     my $answerlog = '';
                   1663:     if ($qtype eq "Ess") {
                   1664:         $output .= qq|
                   1665:    <essayresponse>
                   1666:    <textfield></textfield>
                   1667:    </essayresponse>
                   1668:    <postanswerdate>
1.13    ! raeburn  1669:     <startouttext />
1.1       raeburn  1670:    $answertxt
1.13    ! raeburn  1671:     <endouttext />
1.1       raeburn  1672:    </postanswerdate>
                   1673:   </problem>|;
                   1674:     } elsif ($qtype eq "TF") {
                   1675:          $answer = $answer_id;
                   1676:          $output .= qq|
                   1677:    <radiobuttonresponse max="2" randomize="yes">
                   1678:     <foilgroup>
                   1679:          |;
                   1680:          $output .= "   <foil name=\"foil0\" value=\"true\" location=\"random\"><startouttext />";
                   1681:          if ($answer_id) {
                   1682:               $output .= "False";
                   1683:          } else {
                   1684:               $output .= "True";
                   1685:          }
                   1686:          $output .= "<endouttext /></foil>\n";
                   1687:          $output .= "   <foil name=\"foil1\" value=\"false\" location=\"random\"><startouttext />";
                   1688:          if ($answer_id) {
                   1689:               $output .= "True";
                   1690:          } else {
                   1691:               $output .= "False";
                   1692:          }
                   1693:          $output .= qq|<endouttext /></foil>
                   1694:     </foilgroup>
                   1695:    </radiobuttonresponse>
                   1696:   </problem>|;
                   1697:      }
                   1698:      open(PROB,">$newdir/$libfile");
                   1699:      print PROB $output;
                   1700:      close PROB;
                   1701:      return $libfile;
                   1702: }
                   1703: 
                   1704: sub file_error {
                   1705:     my ($r,$uname,$fn,$current_page);
                   1706:     $r->print("No data here");
                   1707: } 
                   1708: 
                   1709: # ---------------------------------------------------------------- Main Handler
                   1710: sub handler {
                   1711:     my $r=shift;
                   1712:     my $uname;
                   1713:     my $udom;
                   1714:     my $javascript = '';
                   1715:     my $page_name = '';
                   1716:     my $current_page = '';
                   1717:     my $qcount = '';
                   1718: #
                   1719: # phase two: re-attach user
                   1720: #
1.6       albertel 1721:     if ($env{'form.uploaduname'}) {
                   1722:         $env{'form.filename'}='/priv/'.$env{'form.uploaduname'}.'/'.
                   1723:             $env{'form.filename'};
1.1       raeburn  1724:     }
                   1725:     ($uname,$udom)=
1.6       albertel 1726:         &Apache::loncacc::constructaccess($env{'form.filename'},
1.1       raeburn  1727:                                           $r->dir_config('lonDefDomain'));
                   1728:     unless (($uname) && ($udom)) {
                   1729:         $r->log_reason($uname.' at '.$udom.
1.6       albertel 1730:                        ' trying to publish file '.$env{'form.filename'}.
1.1       raeburn  1731:                        ' - not authorized',
                   1732:                        $r->filename);
                   1733:         return HTTP_NOT_ACCEPTABLE;
                   1734:     }
                   1735:                                                                              
                   1736:     my $fn;
                   1737:     my $badfile = 0;
1.6       albertel 1738:     if ($env{'form.filename'}) {
                   1739:         $fn=$env{'form.filename'};
1.1       raeburn  1740:         $fn=~s/^http\:\/\/[^\/]+\///;
                   1741:         $fn=~s/^\///;
1.11      albertel 1742:         $fn=~s{(~|priv/)($LONCAPA::username_re)}{};
1.1       raeburn  1743:         $fn=~s/\/+/\//g;
                   1744:     } else {
1.6       albertel 1745:         $r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
1.1       raeburn  1746:                        ' unspecified filename for upload', $r->filename);
                   1747:         return HTTP_NOT_FOUND;
                   1748:     }
                   1749:     my $pathname = &File::Basename::dirname($fn);
                   1750:     my $fullpath = '/priv/'.$uname.$pathname;
                   1751:     unless ($pathname eq '/') {
                   1752:         $fullpath .= '/';
                   1753:     }
                   1754: 
                   1755:     my $dirpath = '/home/'.$uname.'/public_html';
                   1756: 
                   1757:     my @text = ();
1.6       albertel 1758:     if ($env{'form.phase'} eq 'three') {    
1.1       raeburn  1759:         if (-e "$dirpath$fn") {
                   1760:             open(TESTBANK,"<$dirpath$fn");
                   1761:             @text = <TESTBANK>;
                   1762:             close(TESTBANK);
                   1763:         } else {
                   1764:             $badfile = 1;  
                   1765:         }
                   1766:     }
                   1767:         
                   1768: # ----------------------------------------------------------- Start page output
                   1769:     &Apache::loncommon::content_type($r,'text/html');
                   1770:     $r->send_http_header;
                   1771: 
1.10      albertel 1772:     my %loadentries;
1.6       albertel 1773:     if ($env{'form.phase'} eq 'three') {
1.1       raeburn  1774:         $current_page = &display_control();
                   1775:         my @PAGES = ('Welcome','Blocks','Format','Target','Confirmation');
                   1776:         $page_name = $PAGES[$current_page];
                   1777: 
                   1778:         if ($page_name eq 'Blocks') {
1.10      albertel 1779: 	    $loadentries{'onload'} = "setElements()";
1.1       raeburn  1780:             &jscript_one(\$javascript);
                   1781:         } elsif ($page_name eq 'Format') { 
1.6       albertel 1782:             $qcount = question_count($env{'form.qnumformat'},\@text);
1.1       raeburn  1783:  	    &jscript_two(\$javascript,$qcount);
                   1784:          } elsif ($page_name eq 'Target') {
1.6       albertel 1785:              if ($env{'form.go'} eq "PreviousPage") {
1.10      albertel 1786:                  $loadentries{'onload'} = "setElements()";
1.1       raeburn  1787:  	     }
                   1788: 	     &jscript_three($fullpath,\$javascript);
                   1789:         } elsif ($page_name eq 'Confirmation') {
                   1790: 	    &jscript_four(\$javascript,$fullpath);
                   1791:         }
1.8       albertel 1792:     }
                   1793: 
                   1794:     $javascript = "<script type=\"text/javascript\">\n//<!--\n".
                   1795: 	$javascript."\n// --></script>\n";
                   1796: 
                   1797:     $r->print(&Apache::loncommon::start_page('Upload testbank questions to Construction Space',
                   1798: 					     $javascript,
1.10      albertel 1799: 					     {'add_entries' => \%loadentries}));
1.1       raeburn  1800: 
1.6       albertel 1801:     if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
1.1       raeburn  1802:         $r->print('<h3><font color=red>'.&mt('Co-Author').': '.$uname.
                   1803:                   &mt(' at ').$udom.'</font></h3>');
                   1804:     }
                   1805: 
1.6       albertel 1806:     if ($env{'form.phase'} eq 'three') {
1.1       raeburn  1807:         if ($badfile) {
                   1808:             &file_error($r,$uname,$fn,$current_page);
                   1809:         } else {        
                   1810:             &display_zero ($r,$uname,$fn,$current_page,$fullpath) if $page_name eq 'Welcome';
                   1811:             &display_one ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Blocks';
                   1812:             &display_two ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Format';
                   1813:             &display_three ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Target';
                   1814:             &final_display ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Confirmation';
                   1815:         }
1.6       albertel 1816:     } elsif ($env{'form.phase'} eq 'two') {
1.1       raeburn  1817:         my $flag = &Apache::lonupload::phasetwo($r,$fn,$uname,$udom,'testbank');
                   1818:         if ($flag eq 'ok') {
                   1819:             my $current_page = 0;
                   1820:             &display_zero($r,$uname,$fn,$current_page,$fullpath);
                   1821:         }
                   1822:     } else {
                   1823:         &Apache::lonupload::phaseone($r,$fn,$uname,$udom,'testbank');
                   1824:     }
1.8       albertel 1825:     $r->print(&Apache::loncommon::end_page());
1.1       raeburn  1826:     return OK;
                   1827: }
                   1828: 1;
                   1829: __END__
                   1830: 

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