[LON-CAPA-cvs] cvs: loncom /publisher testbankimport.pm

raeburn lon-capa-cvs-allow@mail.lon-capa.org
Tue, 17 Jun 2008 13:00:20 -0000


This is a MIME encoded message

--raeburn1213707620
Content-Type: text/plain

raeburn		Tue Jun 17 09:00:20 2008 EDT

  Modified files:              
    /loncom/publisher	testbankimport.pm 
  Log:
  Bug 5727. Testbank import now accepts RTF and HTML formatted files, so text formatting (e.g., superscript, subscript etc. are preserved).  Images embedded in the page will also be preserved:
  (i) for RTF documents, the images are extracted from the RTF using RTF::HTMLConverter
  (ii) for HTML documents, user will be prompted to upload images referenced in file during the initial file upload.
  - font tags eliminated  
  - datatable functions form loncommon replace table tags
  - "Create directory" moved from penultimate page to first page, and now optional.
  - File names to be used for individual problems can be set by user
  - User can choose which of the problems identified in the testbank are to be converted
  
  Some perl modules from CPAN are used: File::Magic, XML::DOM and RTF::HTMLConverter. A new LONCAPA-prerequisites.rpm will be built, rpms will be created for these modules, and added to the repositories in msu/testing/
  
  
--raeburn1213707620
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20080617090020.txt"

Index: loncom/publisher/testbankimport.pm
diff -u loncom/publisher/testbankimport.pm:1.14 loncom/publisher/testbankimport.pm:1.15
--- loncom/publisher/testbankimport.pm:1.14	Wed Jun  4 21:24:59 2008
+++ loncom/publisher/testbankimport.pm	Tue Jun 17 09:00:19 2008
@@ -1,5 +1,5 @@
 # Handler for parsing text upload problem descriptions into .problems
-# $Id: testbankimport.pm,v 1.14 2008/06/05 01:24:59 raeburn Exp $
+# $Id: testbankimport.pm,v 1.15 2008/06/17 13:00:19 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -34,8 +34,13 @@
 use HTML::Entities();
 use Apache::lonlocal;
 use Apache::lonupload;
+use Apache::londocs;
 use File::Basename();
 use LONCAPA();
+use File::MMagic;
+use XML::DOM;
+use RTF::HTMLConverter;
+use HTML::TokeParser;
 
 # ---------------------------------------------------------------- Display Control
 sub display_control {
@@ -56,6 +61,45 @@
     return 0 if $dir eq 'BackToStart';
 }
 
+sub jscript_zero {
+    my ($webpath,$jsref) = @_;
+    my $start_page =
+        &Apache::loncommon::start_page('Create Testbank directory',undef,
+                                       {'only_body'   => 1,
+                                        'js_ready'    => 1,});
+    my $end_page =
+        &Apache::loncommon::end_page({'js_ready' => 1,});
+    my %lt = &Apache::lonlocal::texthash(
+                                         loca => 'Location',
+                                         newd => 'New Directory',
+                                         ente => 'Enter the name of the new directory where you will save the converted testbank questions',
+                                         go  => 'Go',
+                                        );
+    $$jsref = <<"END_SCRIPT";
+function createWin() {
+    document.info.newdir.value = "";
+    newWindow = window.open("","CreateDir","HEIGHT=400,WIDTH=750,scrollbars=yes")
+    newWindow.document.open()
+    newWindow.document.write('$start_page')
+    newWindow.document.write("<img border='0' src='/adm/lonInterFace/author.jpg' alt='[Author Header]'>\\n")
+    newWindow.document.write("<h3>$lt{'loca'}: <tt>$webpath</tt></h3><h3>$lt{'newd'}</h3>\\n")
+    newWindow.document.write("<form name='fileaction' action='/adm/cfile' method='post'>\\n")
+    newWindow.document.write("$lt{'ente'}.<br /><br />")
+    newWindow.document.write("<input type='hidden' name='filename' value='$webpath'>")
+    newWindow.document.write("<input type='hidden' name='action' value='newdir'>")
+    newWindow.document.write("<input type='hidden' name='callingmode' value='testbank'>")
+    newWindow.document.write("$webpath<input type='text' name='newfilename' value=''/>")
+    newWindow.document.write("<input type='button' value='$lt{'go'}' onClick='document.fileaction.submit();' /></form>")
+    newWindow.document.write('$end_page')
+    newWindow.document.close()
+    newWindow.focus()
+}
+
+END_SCRIPT
+    return;
+}
+
+
 # ---------------------------------------------------------------- Jscript One
 
 sub jscript_one {
@@ -89,7 +133,8 @@
     if (exists($env{'form.blocks'}) ) {
         $$jsref .= qq|
     document.forms.display.blocks.value = $env{'form.blocks'}\n|;
-    } elsif (exists($env{'form.qnumformat'}) ) {
+    }
+    if (exists($env{'form.qnumformat'}) ) {
         $$jsref .= <<"TO_HERE";
     for (iter=0; iter<document.forms.display.qnumformat.length; iter++) {
         if(document.forms.display.qnumformat.options[iter].value == "$env{'form.qnumformat'}") {
@@ -243,7 +288,7 @@
     }
     else {
         if ((poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MC") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MA") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "Ord")) {
-            poolForm.elements[caller*5+4].options[0] = new Option("Please Select","-1",true,true)
+            poolForm.elements[caller*5+4].options[0] = new Option("Select","-1",true,true)
             poolForm.elements[caller*5+4].options[1] = new Option("a.","lcperiod",false,false)
             poolForm.elements[caller*5+4].options[2] = new Option("A.","ucperiod",false,false)
             poolForm.elements[caller*5+4].options[3] = new Option("(a)","lcparen",false,false)
@@ -268,7 +313,7 @@
     }
     else {
         if ((poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "MA") || (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "FIB"))  {
-            poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
+            poolForm.elements[caller*5+5].options[0] = new Option("Select","-1",true,true)
             poolForm.elements[caller*5+5].options[1] = new Option("single answer","single",false,false)
             poolForm.elements[caller*5+5].options[2] = new Option("comma","comma",false,false)
             poolForm.elements[caller*5+5].options[3] = new Option("space","space",false,false)
@@ -277,7 +322,7 @@
         }
         else {
             if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "Ord") {
-                poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
+                poolForm.elements[caller*5+5].options[0] = new Option("Select","-1",true,true)
                 poolForm.elements[caller*5+5].options[1] = new Option("comma","comma",false,false)
                 poolForm.elements[caller*5+5].options[2] = new Option("space","space",false,false)
                 poolForm.elements[caller*5+5].options[3] = new Option("new line","line",false,false)
@@ -285,7 +330,7 @@
             }
             else { 
                 if (poolForm.elements[caller*5+3].options[poolForm.elements[caller*5+3].selectedIndex].value == "TF") {
-                    poolForm.elements[caller*5+5].options[0] = new Option("Please Select","-1",true,true)
+                    poolForm.elements[caller*5+5].options[0] = new Option("Select","-1",true,true)
                     poolForm.elements[caller*5+5].options[1] = new Option("True or False","word",false,false)
                     poolForm.elements[caller*5+5].options[2] = new Option("true or false","word",false,false)
                     poolForm.elements[caller*5+5].options[3] = new Option("TRUE or FALSE","word",false,false)
@@ -343,68 +388,25 @@
 # ---------------------------------------------------------------- Jscript Three
 
 sub jscript_three {
-    my ($fullpath,$jsref) = @_;
+    my ($webpath,$jsref) = @_;
     my $source = '';
     if (exists($env{'form.go'}) ) {
         $source = $env{'form.go'};
     }
 
-    my %body_layout = ('rightmargin'  => "0",
-		       'leftmargin'   => "0",
-		       'marginwidth'  => "0",
-		       'topmargin'    => "0",
-		       'marginheight' => "0");
-
-    my $start_page = 
-	&Apache::loncommon::start_page('Create Testbank directory',undef,
-				       {'only_body'   => 1,
-					'add_entries' => \%body_layout,
-					'js_ready'    => 1,});
-    my $end_page = 
-	&Apache::loncommon::end_page({'js_ready' => 1,});
     $$jsref = <<"END_OF_ONE";
-function verify() {
-    if ((document.forms.dataForm.newdir.value == '')  || (!document.forms.dataForm.newdir.value)) {
-        alert("Step 4: You must choose a destination directory for the import") 
-        return false
-    }
-    return true
-} 
-
 function nextPage() {
     if (verify()) {
         document.forms.dataForm.go.value="NextPage"
-        document.forms.dataForm.submit()
+        document.forms.dataForm.submit();
     }
 }
+
 function backPage() {
     document.forms.dataForm.go.value="PreviousPage"
     document.forms.dataForm.submit()
 }
 
-function createWin() {
-    document.dataForm.newdir.value = "";
-    newWindow = window.open("","CreateDir","HEIGHT=400,WIDTH=750,scrollbars=yes")
-    newWindow.document.open()
-    newWindow.document.write('$start_page')
-    newWindow.document.write("<img border='0' src='/adm/lonInterFace/author.jpg' alt='[Author Header]'>\\n")
-    newWindow.document.write("<table border='0' cellspacing='0' cellpadding='0' width='430' bgcolor='#CCFFDD'>\\n")
-    newWindow.document.write("<tr><td width='2'>&nbsp;</td><td width='3'>&nbsp;</td>\\n")
-    newWindow.document.write("<td><h3>Location: <tt>$fullpath</tt></h3><h3>New Directory</h3></td></tr>\\n")
-    newWindow.document.write("<tr><td width='2'>&nbsp;</td><td width='3'>&nbsp;</td>\\n")
-    newWindow.document.write("<td><form name='fileaction' action='/adm/cfile' method='post'>\\n")
-    newWindow.document.write("<font face='arial,helvetica,sans-serif'>Enter the name of the new directory where you will save the converted testbank questions<br /><br />")
-    newWindow.document.write("<input type='hidden' name='filename' value='$fullpath'>")   
-    newWindow.document.write("<input type='hidden' name='action' value='newdir'>")
-    newWindow.document.write("<input type='hidden' name='callingmode' value='testbank'>")
-    newWindow.document.write("$fullpath<input type='text' name='newfilename' value=''/>")
-    newWindow.document.write("<input type='button' value='Go' onClick='document.fileaction.submit();' />")
-    newWindow.document.write("</td></tr>\\n")
-    newWindow.document.write("</table>")
-    newWindow.document.write('$end_page')
-    newWindow.document.close()
-    newWindow.focus()
-}
 END_OF_ONE
     if ($source eq "PreviousPage") { 
         $$jsref .= qq|  
@@ -412,262 +414,166 @@
     var iter = 0
     var selParam = 0
         |;
-        foreach my $item (keys %env) {
-            if ($item =~ m/^form\.(\w+)$/) {
+        foreach my $item (keys(%env)) {
+            if ($item =~ m/^form\.(probfile_\d+)$/) {
                 my $name = $1; 
                 my $value = $env{"form.$name"};
-                unless ($value eq "") {
-                    if ($name eq "newdir") {
-             	        $$jsref .= qq(    document.forms.dataForm.$name.value = "$value"\n);
-                    }
+                if ($value ne '') {
+             	    $$jsref .= qq(    document.dataForm.$name.value = "$value"\n);
                 }
             }
         }
         $$jsref .= "}";
     }
-}
+    $$jsref .= '
 
+function verify() {
+';
+    my $blocks = 0;
+    if ( exists( $env{'form.blocks'}) ) {
+        $blocks = $env{'form.blocks'};
+    }
+    my $numitems = 0;
+    for (my $i=0; $i<$blocks; $i++) {
+        my $count = 0;
+        if (($env{"form.start_$i"} ne '') && ($env{"form.end_$i"} ne '')) {
+            $count = $env{"form.end_$i"} - $env{"form.start_$i"} +1;
+        }
+        $numitems += $count;
+    }
+    if ($numitems > 0) {
+        my $maxnum = $numitems - 1;
+        my %lt = &Apache::lonlocal::texthash(
+                                              fnmb => 'File names must be unique',
+                                              isum => 'is used more than once',
+                                            );
+        $$jsref .= qq|
+    for (var j=$maxnum; j>0;  j--) {
+        var currname = document.dataForm.elements['probfile_'+j].value;
+        for (var k=j-1; k>=0; k--) {
+            var comparename = document.dataForm.elements['probfile_'+k].value;
+            if (currname == comparename) {
+                alert("$lt{fnmb} - "+currname+" $lt{isum}");
+                return false;
+            }
+        }
+    }
+|;
+    }
+    $$jsref .= '
+    return true;
+}
+';
+    $$jsref .= &Apache::loncommon::check_uncheck_jscript();
+    return;
+}
 
 # ---------------------------------------------------------------- Jscript Four
 sub jscript_four {
-    my ($jsref,$fullpath) = @_;
+    my ($jsref,$webpath) = @_;
     $$jsref = qq|   
 function backtoStart() {
-    document.location.href="$fullpath"
+    document.location.href="$webpath"
 }
-function backpage() {
+function backPage() {
     document.forms.verify.go.value="PreviousPage"
-    document.forms.verify.submit()
+    document.forms.verify.submit();
 }
     |;
 }
 
 # ---------------------------------------------------------------- Display Zero
 sub display_zero {
-    my ($r,$uname,$fn,$page,$fullpath) = @_;
-    $r->print(qq|
-<table border='0' cellspacing='0' cellpadding='0' width='100%'>
-       <tr>
-        <td>&nbsp;</td>
-        <td colspan='2'><font face='arial,helvetica,sans-serif'> 
-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.
-        <ol>
-         <li>The questions and answers you upload must be in plain text format.  Any header lines should occur before the text containing the questions and answers.</li>
-         <li>All questions (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>
-         <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>
-         <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.        
-         <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. If two or more foils have the same ranking, they should occur together, with an equals sign separating equally ranked foils [e.g., (b),(e)=(a),(d),(c)].</li> 
-        </ol>
-Five steps are involved in the import process.
-        <ol>
-         <li>Upload your text file to the server.|);
-
+    my ($r,$uname,$fn,$page,$webpath) = @_;
+    my $go_default = 'NextPage'; 
     if ($fn eq '') {
-        $r->print("<b>Incomplete</b>. Please return to the <a href='$fullpath'>construction space menu<a> to upload a file");
-    } else {
-        $r->print(" <b>Completed</b> - successful upload of <i>$fn</i>");
-    } 
-    $r->print(qq|</li>
-         <li>Provide information about the question format - i.e.,  question numbering style, and the number of blocks of questions of each question type.</li>
-         <li>Provide information about the questions in each block, including question type, start and end question numbers for each block, and foil labelling style and answer format where required.</li>
-         <li>Create a new directory where you will save the converted testbank questions.</li> 
-         <li>Complete the import of questions to the selected pool.</li>
-        </ol>
-        </font>
-        </td>
-       </tr>
-       </table>
-       <br />
-       <br />
-       <form name="info" method="post">
-       <input type="hidden" name="uploaduname" value="$uname">
-       <input type="hidden" name="filename" value="$fn">
-       <input type="hidden" name="page" value="$page">
-       <input type="hidden" name="phase" value="three">
-       <input type="hidden" name="go" value="NextPage">
-       <table border="0" width="100%">
-        <tr>
-         <td align='left'>
-          <input type="button" name="goback" value="Exit Now" onClick="javascript:location.href='$fullpath'">
-         </td>
-         <td align='right'>
-          <input type="button" name="nextpage" value="Continue to step 2" onClick="javascript:submit()">
-         </td>
-        </tr>
-       </table>
-       </form> 
-    |);  
+        $r->print('<b>'.&mt('Incomplete file upload').'</b> '.&mt('Return to the [_1]construction space menu[_2] to upload a file','<a href="'.$webpath.'">','</a>'));
+    }
+    $r->print(&mt('The <b>Testbank Upload</b> utility can be used by LON-CAPA authors to generate LON-CAPA problem files from a testbank file of questions/answers.').'<br />'.
+              &mt('The following question types can be converted:').'
+              <ul>
+                <li>'.&mt('multiple choice').'</li>
+                <li>'.&mt('multiple answer correct').'</li>
+                <li>'.&mt('fill-in-the-blank').'</li>
+                <li>'.&mt('ordering/ranking').'</li>
+                <li>'.&mt('true/false').'</li>
+                <li>'.&mt('essay').'</li>
+              </ul>
+              '.&mt('The file of questions (in plain text, RTF or HTML format) must meet certain requirements for the conversion process to generate functioning LON-CAPA problems.').&Apache::loncommon::help_open_topic('Testbank_Formatting').'<br />'.
+              &mt('Five steps are involved in the conversion process.').'
+        <ol>
+         <li>'.&mt('Optionally create a new sub-directory where the converted testbank questions will be saved.').'</li>
+         <li>'.&mt('Provide information about the question format - i.e.,  question numbering style, and the number of blocks of questions of each question type.').'</li>
+         <li>'.&mt('Provide information about the questions in each block, including question type, start and end question numbers for each block, and foil labelling style and answer format where required.').'</li>
+         <li>'.&mt('Review the identified questions, choose which to convert, and (optionally) override the default filename to be used for each problem file.').'</li> 
+         <li>'.&mt('Complete the import of questions.').'</li>
+        </ol><form name="info" method="post" action="/adm/testbank">'.
+        &topic_bar(1,&mt('Optional: create a sub-directory in which the testbank questions will be saved')).
+        &mt('By default, LON-CAPA problems generated from the testbank file will be stored in the current directory.').' '.&mt('To store them in a new sub-directory:'). 
+       ' <input type="button" name="createdir" value="'.&mt('Create sub-directory').'" onClick="javascript:createWin()">'.
+       &page_footer($env{'form.newdir'},$uname,$fn,$page,$webpath).'
+       </form>');
 }
 
-
 # ---------------------------------------------------------------- Display One
 
 sub display_one {
-    my ($r,$uname,$fn,$page,$textref) = @_;
-    $r->print(qq|
-   <form method='post' name='display'>
-   <table border='0' cellspacing='0' cellpadding='3' width='100%'>
-    <tr bgcolor='#ccddaa'>
-     <td>&nbsp;</td> 
-     <td align='left'>
-       <h3><font face='arial,helvetica,sans-serif'>Step 2: Identification of blocks of questions</b>&nbsp;</font></h3>
-     </td>
-    </tr>
-    <tr>
-     <td colspan='2'>&nbsp;</td>
-    </tr>
-    <tr>
-     <td colspan='2'>
-      <table border="0" cellspacing="0" cellpadding="2">
-       <tr>
-        <td>&nbsp;</td>
-        <td colspan='2'>
-         <font face='arial,helvetica,sans-serif'><b>Testbank data uploaded to the server:</b></font>
-       </td>
-      </tr>
-      <tr>
-       <td colspan='3'>&nbsp;</td>
-      </tr>
-      <tr>
-       <td>&nbsp;</td>
-       <td colspan='2'>
-         <textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
-    |);
-    foreach my $line (@{$textref}) {
-        $line =~ s/\n//g;
-        $r->print("$line\n");
-    }
-    $r->print(qq|
-       </textarea>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='3'>&nbsp;</td>
-     </tr>
-     <tr>
-     <tr>
-      <td colspan='3'>&nbsp;</td>
-     </tr>
-     <tr bgcolor='#ccddaa'>
-      <td>&nbsp;</td>
-      <td align='left' valign='middle'><img src="/res/adm/pages/bl_step1.gif">&nbsp;&nbsp;
-      </td>
-      <td>
-       <font face='arial,helvetica,sans-serif'><b>
-Select the format of the question number</b> [e.g., 1,  1., 1), (1 or (1)].&nbsp;
-                 <select name="qnumformat">
-                  <option value = "-1" selected>Please Select
-                  <option value="number">1
-                  <option value="period">1.
-                  <option value="paren">(1)
-                  <option value="leadparen">(1
-                  <option value="trailparen">1)
-                 </select>
-       </font>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='3'>&nbsp;</td>
-     </tr>
-     <tr>
-      <td>&nbsp;</td>
-      <td colspan='2'><font face='arial,helvetica,sans-serif'>
-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>
-     </tr>
-     <tr>
-      <td colspan="3">&nbsp;</td>
-     </tr>
-     <tr>
-      <td>&nbsp;</td>
-      <td colspan='2'>
-       <font face='arial,helvetica,sans-serif'>
-        For example, you would select <b>1.</b> if your text file contained the following questions:<br><br>
- 1. The capital of the USA is ..<br />
- &nbsp;&nbsp;(a) Washington D.C.<br />
- &nbsp;&nbsp;(b) New York<br />
- &nbsp;&nbsp;(c) Los Angeles<br />
- <br />
- 2. The capital of Canada is ..<br />
- &nbsp;&nbsp;(a) Toronto<br />
- &nbsp;&nbsp;(b) Vancouver<br />
- &nbsp;&nbsp;(c) Ottawa<br />
-<br />
- 3. Describe an experiment you could conduct to measure c, the speed of light in a vacuum. <br /><br />
- 1. (a)<br />
- 2. (c)<br />
- 3. <br />
-      </td>
-     <tr>
-      <td colspan="3">&nbsp;</td>
-     </tr>
-     <tr bgcolor='#ccddaa'>
-      <td>&nbsp;</td>
-      <td><img src='/res/adm/pages/bl_step2.gif' align='left' valign='middle'>&nbsp;&nbsp;
-      </td>
-      <td>
-       <font face='arial,helvetica,sans-serif'><b>
-Please indicate the number of blocks of different question types in the text file.</b>&nbsp;&nbsp;
-         <input type="text" name="blocks" value="" size="5">
-      </td>
-     </tr>
-     <tr>
-      <td colspan="3">&nbsp;</td>
-     </tr>
-     <tr>
-      <td>&nbsp;</td>
-      <td colspan='2'>
-       <font face='arial,helvetica,sans-serif'>
-        For example, you would enter <b>6</b> if your text file contained the following sequence of questions:<br><br>
- 10 multiple choice questions<br>
-  5 essay questions<br>
-  5 fill-in-the-blank questions<br>
-  5 multiple answer questions<br>
-  4 multiple choice questions<br>
-  3 essay questions<br>
-      </font>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='3'>&nbsp;</td>
-     </tr>
-     <tr>
-       <td>&nbsp;</td>
-       <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>
-     </tr>
-     <tr>
-      <td colspan='3'>&nbsp;</td>
-     </tr>
-     <tr>
-      <td colspan='3'>
-       <table border='0' width="100%" cellspacing='0' cellpadding='2'>
-        <tr>
-         <td align='left'>
-          <input type="button" name="backpage" value="Go back to step 1" onClick="javascript:backPage()">
-         </td>
-         <td align='right'>
-          <input type="button" name="nextpage" value="Continue to step 3" onClick="javascript:nextPage()">
-         </td>
-        </tr>
-       </table>
-       <input type="hidden" name="page" value ="$page">
-       <input type="hidden" name="go" value="">
-       <input type="hidden" name="uploaduname" value="$uname">
-       <input type="hidden" name="filename" value="$fn">
-       <input type="hidden" name="phase" value="three">
-      </td>
-     </tr>
-    </table>
-   </td>
-  </tr>
- </table>
- </form>
-    |);
+    my ($r,$uname,$fn,$page,$textref,$header) = @_;
+    my %topics;
+    $topics{2} = &mt('Select the format of the question number - e.g., 1,  1., 1), (1 or (1) - ').'&nbsp;
+               <select name="qnumformat">
+                  <option value = "-1" selected>'.&mt('Select').'</option>
+                  <option value="number">1</option>
+                  <option value="period">1.</option>
+                  <option value="paren">(1)</option>
+                  <option value="leadparen">(1</option>
+                  <option value="trailparen">1)</option>
+                 </select>'."\n";
+    $topics{3} = &mt('Indicate the number of blocks of different question types in the testbank file.').'&nbsp;&nbsp;<input type="text" name="blocks" value="" size="5" />';
+    $r->print('<h3>'.&mt('Identification of blocks of questions').'</h3>'."\n".
+              '<form method="post" name="display" action="/adm/testbank">'."\n".
+              &show_uploaded_data($textref,$header)."\n".
+              &topic_bar(2,$topics{2}).'<p>'.
+              &mt('A number in the specified format should appear at the start of each question.').'<br />'.
+              &mt('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.').'<br />'."\n".
+              &mt('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).').'<br />'."\n".
+              &mt('Each numbered question must have a corresponding numbered answer, although the answer itself may be blank for essay questions.').'<br /><br />'."\n".
+              &mt('For example, you would select <b>1.</b> if your testbank file contained the following questions:').'<br /><blockquote>'.
+'<pre>
+ 1. '.&mt('The capital of the USA is ...').'
+ (a) Washington D.C.
+ (b) New York
+ (c) Los Angeles
+
+ 2. '.&mt('The capital of Canada is ...').'
+ (a) Toronto
+ (b) Vancouver
+ (c) Ottawa
+
+ 3. '.&mt('Describe an experiment you could conduct to measure c, the speed of light in a vacuum.').'
+ 1. (a)
+ 2. (c)
+ 3.
+</pre>'.
+             '</blockquote></p>'.
+             &topic_bar(3,$topics{3}).'<p>'.
+             &mt('For example, you would enter <b>6</b> if your testbank file contained the following sequence of questions:').'</p><blockquote>'.
+             &mt('10 multiple choice questions').'<br />'.
+             &mt('5 essay questions').'<br />'.
+             &mt('5 fill-in-the-blank questions').'<br />'.
+             &mt('5 multiple answer questions').'<br />'.
+             &mt('4 multiple choice questions').'<br />'.
+             &mt('3 essay questions').'</blockquote></p><p>'.
+             &mt('You will indicate the question type and the question number range for each of the blocks on the next page.').'</p><br />'.
+             &page_footer($env{'form.newdir'},$uname,$fn,$page).'
+ </form>');
+    return;
 }
 
 # ---------------------------------------------------------------- Display Two
 
 sub display_two {
-    my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
+    my ($r,$uname,$fn,$page,$textref,$header,$qcount) = @_;
     my $blocks = $env{'form.blocks'};
     my $qnumformat = $env{'form.qnumformat'};
     my @types = ("MC","MA","TF","Ess","FIB","Ord");
@@ -686,210 +592,84 @@
              leadparen => "(1",
              trailparen => "1)",
              );
-    my @bgcolors = ('#ffffff','#eeeeee');
     my $bl1st = '';
     my $bl1end = '';
     if ($blocks == 1) {
         $bl1st = '1';
         $bl1end = $qcount;
     }
-    $r->print(<<"END_OF_FUNC");
- <h3><font face='arial,helvetica,sans-serif'>Step 3: Classification of blocks</b>&nbsp;</font></h3>
-<form method='post' name='display'>
-   <table border='0' cellspacing='0' cellpadding ='0'>
-    <tr>
-     <td colspan='2'>&nbsp;</td>
-    </tr>
-    <tr>
-     <td colspan='2'>
-      <table border="0" cellspacing="0" cellpadding="0">
-       <tr>
-        <td>&nbsp;</td>
-        <td><font face='arial,helvetica,sans-serif'>
-          You indicated that <b>all</b> questions (and the corresponding answer(s) for each question) begin with a number in the following format:  <b>$qnumtypes{$qnumformat}</b>.<br><br>A total of <b>$qcount</b> questions and <b>$qcount</b> corresponding answers were found in the file you uploaded. If this questions total does not match the number you expect, please examine your original text file to verify that each question <i>and</i> each answer begins with a number in the specified format. If necessary use a text editor to edit your text file of 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>
-          You also indicated that the <b>$qcount</b> questions can be divided into <b>$blocks</b> blocks of questions of a particular question type.</font>
-        </td>
-       </tr>
-       <tr>
-        <td colpsan='2'>&nbsp;</td>
-       </tr>
-       <tr>
-        <td>&nbsp;</td>
-        <td><font face='arial,helvetica,sans-serif'>
-          Please provide additional information below ,about the types of questions you have uploaded, and, if applicable, the format of answers and &quot;foils&quot; for specific types of questions.
-        </td>
-       </tr>
-       <tr>
-        <td colpsan='2'>&nbsp;</td>
-       </tr>
-       <tr>
-        <td>&nbsp;</td>
-        <td>
-<font face='arial,helvetica,sans-serif'>The following data were uploaded to the server</font><br>
-<textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">
-END_OF_FUNC
-    foreach my $line (@{$textref}) {
-        $line =~ s/\n//g;
-        $r->print("$line\n");
-    }
-    $r->print(qq| 
-</textarea>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='2'>&nbsp;</td>
-     </tr>
-     <tr bgcolor='#ccddaa'>
-      <td><img src='/res/adm/pages/bl_step3.gif' align='left' valign='middle'>
-      </td>
-      <td width='100%' align='left'>&nbsp;&nbsp;
-       <font size='+1' face='arial,helvetica,sans-serif'><b>Information about question types and formats in each block.</b></font>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='2'>&nbsp;</td>
-     </tr>
-     <tr>
-      <td>&nbsp;</td>
-      <td><font face='arial,helvetica,sans-serif'>For <i>each</i> of the <b>$blocks</b> question blocks, please specify the question numbers of the first and last questions in the block (e.g., 1 and 10), and the question type of the questions in the block. Please provide additional information about foil formats and answer formats if required for the question type you selected.</font>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='2'>&nbsp;</td>
-     </tr>
-     <tr>
-      <td>&nbsp;</td>
-      <td>
-       <table border="0" cellspacing="0" cellpadding="0" bgcolor="#000000" align="left">
-        <tr>
-         <td>
-          <table border="1" valign="top" align="center" width='100%'>
-           <tr bgcolor="#eef6f6" align="left">
-            <td>
-             <table border='0' cellspacing='1' cellpadding='1' align='left' width='100%'>
-              <tr bgcolor='#CCDDAA' align='center' valign='middle'>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>
-                &nbsp;<b>Block</b>&nbsp;</font>
-               </td>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
-                &nbsp;<b>First&nbsp;number</b>&nbsp;</font>
-               </td>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
-                &nbsp;<b>Last&nbsp;number</b>&nbsp;</font>
-               </td>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
-                &nbsp;<b>Question&nbsp;type</b>&nbsp;</font>
-               </td>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
-                &nbsp;<b>Foil&nbsp;format</b>&nbsp;</font>
-               </td>
-               <td align="center" valign="middle" height='10'><font face='arial,helvetica,sans-serif'>&nbsp;
-                &nbsp;<b>Answer&nbsp;format</b>&nbsp;</font>
-               </td>
-              </tr>
-    |);
+    my $steptitle = &mt('Information about question types and formats in each block.');
+    $r->print('<h3>'.&mt('Classification of blocks').'</h3>'.
+              '<form method="post" name="display" action="/adm/testbank"><p>'.
+              &mt('You indicated that <b>all</b> questions (and the corresponding answer(s) for each question) begin with a number in the following format: [_1].','<b>'.$qnumtypes{$qnumformat}.'</b>').'</p><p>'.
+              &mt('A total of <b>[quant,_1,question]</b> and <b>[quant,_2,answer]</b> were found in the file you uploaded.',$qcount,$qcount).' '.
+              &mt('If this total does not match the number you expect, examine your original testbank file to verify that each question <i>and</i> each answer begins with a number in the specified format.').' '.
+              &mt('If necessary use an editor to edit your testbank file of questions, and click "Previous Page" on this page and the "Exit Now" on the preceding page, so you can upload your file again.').'</p><p>'.
+              &mt('You also indicated that the <b>[quant,_1,question]</b> can be divided into <b>[quant,_2,block]</b> of questions of a particular question type.',$qcount,$blocks).'</p><p>'.
+              &mt('Provide additional information below, about the types of questions you have uploaded, and, if applicable, the format of answers and "foils" for specific types of questions.').'</p>'.
+              &show_uploaded_data($textref,$header).
+              &topic_bar(4,$steptitle).'<p>'.
+              &mt('For <i>each</i> of the [_1] question blocks, 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.','<b>'.$blocks.'</b>').' '.
+              &mt('If required, provide additional information about foil formats and answer formats for the question types you select.').'</p><p>'.
+              &Apache::loncommon::start_data_table().
+              &Apache::loncommon::start_data_table_header_row().
+              '<th>'.&mt('Block').'</th>'."\n".
+              '<th>'.&mt('First number').'</th>'."\n".
+              '<th>'.&mt('Last number').'</th>'."\n".
+              '<th>'.&mt('Question type').'</th>'."\n".
+              '<th>'.&mt('Foil format').'</th>'."\n".
+              '<th>'.&mt('Answer format').'</th>'."\n".
+              &Apache::loncommon::end_data_table_header_row());
     for (my $i=0; $i<$blocks; $i++) {
         my $iter = $i+1;
-        my $rowcol = $i%2;
-        $r->print(qq|
- <tr bgcolor="$bgcolors[$rowcol]">
-  <td align="left">
-   <font face='arial,helvetica,sans-serif'>&nbsp;$iter.</font>
-  </td>
-  <td align="left">&nbsp;
-   <input type="text" name="start_$i" value="$bl1st" size="5">&nbsp;
-  </td>
-  <td align="left">&nbsp;
-   <input type="text" name="end_$i" value="$bl1end" size="5">&nbsp;
-  </td>
-  <td align="left">
-   <font face='arial,helvetica,sans-serif'>
-   <select name="qtype_$i" onChange="colSet($i)">
-    <option value= "-1" selected>Please Select
-        |);
+        $r->print(&Apache::loncommon::start_data_table_row().
+                 '<td valign="top">&nbsp;'.$iter.'&nbsp;</td>'."\n".
+                 '<td valign="top">&nbsp;<input type="text" name="start_'.$i.'" value="'.$bl1st.'" size="5" />&nbsp;</td>'."\n".
+                 '<td valign="top">&nbsp;<input type="text" name="end_'.$i.'" value="'.$bl1end.'" size="5">&nbsp;</td>'."\n".
+                 '<td valign="top">
+   <select name="qtype_'.$i.'" onChange="colSet('.$i.')">
+    <option value= "-1" selected>'.&mt('Select').'</option>'."\n");
         foreach my $qtype (@types) {
-            $r->print(qq|<option value="$qtype">$typenames{$qtype}|);
+            $r->print('<option value="'.$qtype.'">'.$typenames{$qtype}.'</option>'."\n");
         }
-        $r->print(qq|
-   </select>
-   </font>
+        $r->print('   </select>
   </td>
-  <td align="left">&nbsp;
-    <select name="foilformat_$i">
+  <td align="left" valign="top">&nbsp;
+    <select name="foilformat_'.$i.'">
      <option value="-1">&lt;--- Set type&nbsp; 
     </select>&nbsp;
   </td>
-  <td align="left">&nbsp;
-    <select name="ansr_$i">
+  <td align="left" valign="top">&nbsp;
+    <select name="ansr_'.$i.'">
      <option value="-1">&lt;--- Set type&nbsp;
     </select>
-  </td>
- </tr>
-        |);
+  </td>'.
+                     &Apache::loncommon::end_data_table_row()); 
     }
-    $r->print(qq|
-       </table>
-      </td>
-     </tr>
-    </table>
-   </td>
-  </tr>
- </table>
-</td>
-</tr>
-<tr>
- <td colspan="2">&nbsp;</td>
-</tr>
-<tr>
- <td>&nbsp;</td>
- <td>
-<font face='arial,helvetica,sans-serif'>For <i>multiple choice</i>, <i>multiple correct answer</i> and <i>ranking</i> type questions, you must use the <b>Foil format</b> column to choose the format of the identifier used for each of the possible answers (e.g., (a), a, a., i, (i) etc.) provided for a given question stem. For <i>multiple correct answer</i> and <i>fill-in-the-blank</i> questions with more than one correct answer you must use the <b>Answer format</b> column to choose the separator used between the answers, e.g., if the correct answers for question 28. were listed as: 28. (a),(d),(e) you would choose &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>
-<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>
-      </td>
-     </tr>
-     <tr>
-      <td colspan='2'>&nbsp;</td>
-     </tr>
-     <tr>
-      <td colspan='2'>
-<input type="hidden" name="blocks" value="$blocks">
-<input type="hidden" name="qnumformat" value="$qnumformat">
-   <table border='0' width="100%" cellspacing='0' cellpadding='2'>
-    <tr>
-     <td align='left'>
-      <input type="button" name="backpage" value="Go back to step 2" onClick="javascript:backPage()">
-     </td>
-     <td align='right'>
-      <input type="button" name="nextpage" value="Continue to step 4" onClick="javascript:nextPage()">
-     </td>
-    </tr>
-   </table>
-   <input type="hidden" name="page" value ="$page">
-   <input type="hidden" name="go" value="">
-   <input type="hidden" name="uploaduname" value="$uname">
-   <input type="hidden" name="filename" value="$fn">
-   <input type="hidden" name="phase" value="three">
-   </form>
-  </td>
- </tr>
-</table>
-</td>
-</tr>
-</table>
-    |);
-} 
+    $r->print(&Apache::loncommon::end_data_table().'</p><ul><li>'.
+              &mt('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.').'</li><li>'.
+             &mt('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:[_1] you would choose "comma", or if they were listed as:[_2] you would choose "new line".','<blockquote><pre>28. (a),(d),(e)</pre></blockquote>','<blockquote><pre>
+28. (a)
+    (d)
+    (e)
+</pre></blockquote>').'</li><li>'.
+             &mt('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.).').'</li><li>'.
+            &mt('For <i>ranking</i> questions you must use the <b>Answer format</b> column to choose the separator used between the (ranked) answers.').'</li></ul>
+<input type="hidden" name="blocks" value="'.$blocks.'" />
+<input type="hidden" name="qnumformat" value="'.$qnumformat.'" />'.
+           &page_footer($env{'form.newdir'},$uname,$fn,$page).'
+</form>');
+    return;
+}
+
 # ---------------------------------------------------------------- Display Three
-sub display_three { 
-    my ($r,$uname,$fn,$page,$textref,$qcount) = @_;
+sub display_three {
+    my ($r,$uname,$fn,$page,$textref,$res,$header,$urlpath,$qcount) = @_;
     my $qnumformat = $env{'form.qnumformat'};
     my $filename = $env{'form.filename'};
     my $source = $env{'form.go'};
     my $blocks = $env{'form.blocks'};
-    my @items = ();
-    my @bgcolors = ('#ffffff','#eeeeee');
-    my @types = ("MC","MA","TF","Ess","FIB","Ord");
-    my @alphabet = ("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
-    my @romans = ("i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","xiii","xiv","xv","xvi","xvii","xviii","xix","xx","xxi","xxii","xxiii","xxiv","xxv","xxvi");
+    my ($alphabet,$romans) = &get_constants();
     my @start = ();
     my @end = ();
     my @nums = ();
@@ -898,6 +678,15 @@
     my @ansrtypes = ();
     my %multparts = ();
     my $numitems = 0;
+    my %lt = &Apache::lonlocal::texthash (
+                                          crt  => 'Create?',
+                                          typ  => 'Type',
+                                          fnam => 'File Name',
+                                          ques => 'Question',
+                                          answ => 'Answer',
+                                          chka => 'check all',
+                                          unch => 'uncheck all',
+                                         );
     for (my $i=0; $i<$blocks; $i++) {
         if (($env{"form.start_$i"} ne '') && ($env{"form.end_$i"} ne '')) {
             $start[$i] = $env{"form.start_$i"};
@@ -919,202 +708,165 @@
         }
         $numitems += $nums[$i];
     }
-
-    my $import = join//,@{$textref};
-    @items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
-    $r->print(<<"END_OF_ONE");
- <h3><font face='arial,helvetica,sans-serif'>Step 4: Review and selection of destination directory</b>&nbsp;</font></h3>
-<form name="dataForm" method="post">
-<table border='0' bgcolor='#CCFFDD' cellspacing='0' cellpadding ='0'>
-      <tr>
-       <td colspan='2'>
-        <table border='0' cellspacing='0' cellpadding='0'>
-       <tr>
-        <td colspan='2'>&nbsp;</td>
-       </tr>
-       <tr>
-        <td>&nbsp;</td>
-        <td><font face='arial,helvetica,sans-serif'><b>
-Based on your previous responses your data have been split into a total of $numitems questions.</b> 
-        </td>
-      </tr>
-      <tr>
-        <td colspan='2'>&nbsp;</td>
-      </tr>
-      <tr>
-       <td>&nbsp;</td>
-     <td width="80%" bgcolor="#000000" align="left">
-     <table width="100%" border="0" cellpadding="1" cellspacing="0">
-      <tr>
-       <td width="100%" bgcolor="#000000">
-        <table border="0" cellspacing="0" cellpadding="1" width="100%">
-         <tr>
-          <td width="100%" bgcolor="#000000">
-           <table border="0" cellpadding="0" cellspacing="1" bgcolor="#ffffff" width="100%">
-            <tr>
-             <td bgcolor="#CCFFDD" width="100%">
-              <table border='0' cellspacing='1' cellpadding='2' align='left' width= '100%'>
-               <tr><td bgcolor="#CCDDAA" align="center" width='3%'><font face='arial,helvetica,sans-serif'><b>#</b></font></td><td bgcolor="#CCDDAA" align="center" width='5%'><font face='arial,helvetica,sans-serif'><b>Type</b></font></td><td bgcolor="#CCDDAA" align="center" width='60%'><font face='arial,helvetica,sans-serif'><b>Question</b></font></td><td bgcolor="#CCDDAA" align="center" width='32%'><font face='arial,helvetica,sans-serif'><b>Answer</b></font></td></tr>
-END_OF_ONE
+    my ($items,$ids,$footer) = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
+    my ($showheader,$showcss);
+    if ($res eq 'application/rtf' || $res eq 'text/html') {
+        if ($header ne '') {
+            $showheader = &HTML::Entities::decode($header);
+            if ($res eq 'text/html') {
+                $showheader = &build_image_url($urlpath,$showheader);
+            }
+        }
+    }
+    $r->print('<h3>'.&mt('Review and selection of problems to convert').'</h3>'."\n".
+              '<form name="dataForm" method="post" action="/adm/testbank">'."\n".
+              &mt('Based on your previous responses your data have been split into a total of [quant,_1,question].',$numitems).
+              &topic_bar(5,&mt('Choose which problems to convert and names to use for individual problem files')));
+              if ($showheader) {
+                  $r->print($showheader.'<br />');
+              }
+              $r->print('<input type="button" value="'.$lt{'chka'}.'" onclick="javascript:checkAll(document.dataForm.createprob)" /> &nbsp;
+<input type="button" value="'.$lt{'unch'}.'" onclick="javascript:uncheckAll(document.dataForm.createprob)" /><br /><br />'.
+              &Apache::loncommon::start_data_table().
+              &Apache::loncommon::start_data_table_header_row(). 
+              '<th>'.#'.</th>'.
+              '<th>'.$lt{'crt'}.'</th>'.
+              '<th>'.$lt{'typ'}.'</th>'.
+              '<th>'.$lt{'fnam'}.'</th>'.
+              '<th>'.$lt{'ques'}.'</th>'.
+              '<th>'.$lt{'answ'}.'</th>'.
+              &Apache::loncommon::end_data_table_header_row());
+    my $idx;
+    if ($numitems =~ /^\d+$/ && $numitems > 0) {
+        $idx = int(log($numitems)/log(10));
+        $idx ++;
+    }
+    if ($idx<3) {
+        $idx = 3;
+    }
     for (my $j=0; $j<$numitems; $j++) {
-        my $qnum = $j+1;
-        my $rowcol = $j%2;
-        $rowcol = @bgcolors[$rowcol];
+        my $qnum = $ids->[$j]; 
+        my $libfile = 'question_';
+        my $leading = 0;
+        while (($idx - length($qnum) - $leading) > 0) {   
+            $libfile .= '0';
+            $leading ++;
+        }
+        $libfile .= $qnum.'.problem';
         for (my $i=0; $i<$blocks; $i++) {
             if ($nums[$i] > 0) {
                 if (($j+1 >= $start[$i]) && ($j+1 <= $end[$i])) { 
                     if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA")) { 
                         for (my $k=0; $k<@{$multparts{$j}}; $k++) {
                             if ($k == 0) {
-                                $r->print(qq|<tr><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$qnum.</font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'><b>$qtype[$i]</b></font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$multparts{$j}[$k]<br><br>\n|);
-                            } else { 
+                                my $showqn = $multparts{$j}[$k];
+                                if (($res eq 'application/rtf') || ($res eq 'text/html')) {
+                                    $showqn = &HTML::Entities::decode($showqn);
+                                    if ($res eq 'text/html') {
+                                        $showqn = &build_image_url($urlpath,$showqn);
+                                    }
+                                }
+                                $r->print(&Apache::loncommon::start_data_table_row().
+                                          '<td valign="top">'.$qnum.'.</td>'."\n".
+                                          '<td valign="top"><input name="createprob" type="checkbox" "checked="checked" value="'.$j.'" /></td>'."\n".
+                                          '<td valign="top"><b>'.$qtype[$i].'</b></td>'."\n".
+                                          '<td valign="top"><input type="textbox" name="probfile_'.$j.'" value="'.$libfile.'" size="20" /></td>'.
+                                          '<td valign="top">'.$showqn.'<br /><br />'."\n");
+                            } else {
                                 my $foiltag = '';
                                 if ($foilformats[$i] eq "lcperiod") {
-                                    $foiltag = $alphabet[$k-1].'.'; 
+                                    $foiltag = $alphabet->[$k-1].'.'; 
                                 } elsif ($foilformats[$i] eq "lcparen") {
-                                    $foiltag = '('.$alphabet[$k-1].')';
+                                    $foiltag = '('.$alphabet->[$k-1].')';
                                 } elsif ($foilformats[$i] eq "lconeparen") {
-                                    $foiltag = $alphabet[$k-1].')';
+                                    $foiltag = $alphabet->[$k-1].')';
                                 } elsif ($foilformats[$i] eq "lcdotparen") {
-                                    $foiltag = $alphabet[$k-1].'.)';
+                                    $foiltag = $alphabet->[$k-1].'.)';
                                 } elsif ($foilformats[$i] eq "ucperiod") {
-                                    $foiltag = $alphabet[$k-1].'.';
+                                    $foiltag = $alphabet->[$k-1].'.';
                                     $foiltag =~ tr/a-z/A-Z/;
                                 } elsif ($foilformats[$i] eq "ucparen") {
-                                    $foiltag = '('.$alphabet[$k-1].')';
+                                    $foiltag = '('.$alphabet->[$k-1].')';
                                     $foiltag =~ tr/a-z/A-Z/;
                                 } elsif ($foilformats[$i] eq "uconeparen") {
-                                    $foiltag = $alphabet[$k-1].')';
+                                    $foiltag = $alphabet->[$k-1].')';
                                     $foiltag =~ tr/a-z/A-Z/;
                                 } elsif ($foilformats[$i] eq "ucdotparen") {
-                                    $foiltag = $alphabet[$k-1].'.)';
+                                    $foiltag = $alphabet->[$k-1].'.)';
                                     $foiltag =~ tr/a-z/A-Z/;
                                 } elsif ($foilformats[$i] eq "romperiod") {
-                                    $foiltag = $romans[$k-1].'.';
+                                    $foiltag = $romans->[$k-1].'.';
                                 } elsif ($foilformats[$i] eq "romparen") {
-                                    $foiltag = '('.$romans[$k-1].')';
+                                    $foiltag = '('.$romans->[$k-1].')';
                                 } elsif ($foilformats[$i] eq "romoneparen") {
-                                    $foiltag = $romans[$k-1].')';
+                                    $foiltag = $romans->[$k-1].')';
                                 } elsif ($foilformats[$i] eq "romdotparen") {
-                                    $foiltag = $romans[$k-1].'.)';
+                                    $foiltag = $romans->[$k-1].'.)';
+                                }
+                                my $showfoil = $multparts{$j}[$k];
+                                if ($res eq 'application/rtf' || $res eq 'text/html') {
+                                    $showfoil = &HTML::Entities::decode($showfoil);
+                                    if ($res eq 'text/html') {
+                                        $showfoil = &build_image_url($urlpath,$showfoil);
+                                    }
                                 } 
-                                $r->print(qq|$foiltag $multparts{$j}[$k]<br>\n|);
+                                $r->print("$foiltag $showfoil<br />\n");
                             }
                         }
-                        $r->print(qq|<br></font></td><td bgcolor="$rowcol" valign='top'><font face='arial,helvetica,sans-serif'>$items[$j+$numitems]</font></td></tr>|);
+                        my $showfoil = $items->[$j+$numitems];
+                        if ($res eq 'application/rtf' || $res eq 'text/html') {
+                            $showfoil = &HTML::Entities::decode($showfoil);
+                            $showfoil =~ s/<\/?[^>]+>//g;
+                        }
+
+                        $r->print('<br /></td><td valign="top">'.$showfoil.'</td>'.
+                                  &Apache::loncommon::end_data_table_row());
                     } else {
-                        $r->print(qq|<tr><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$qnum.</font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'><b>$qtype[$i]</b></font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$items[$j]</font></td><td bgcolor="$rowcol" valign="top"><font face='arial,helvetica,sans-serif'>$items[$j+$numitems]</font></td></tr>|);
+                        my $showfoil = $items->[$j+$numitems];
+                        if ($res eq 'application/rtf' || $res eq 'text/html') {
+                            $showfoil = &HTML::Entities::decode($showfoil);
+                            $showfoil =~ s/<\/?[^>]+>//g;
+                        }
+                        $r->print(&Apache::loncommon::start_data_table_row().
+                                  '<td valign="top">'.$qnum.'</td>'."\n".
+                                  '<td valign="top"><input name="createprob" type="checkbox" "checked="checked" value="'.$j.'" /></td>'."\n".
+                                  '<td valign="top"><b>'.$qtype[$i].'</b></td>'."\n".
+                                  '<td valign="top"><input type="textbox" name="probfile_'.$j.'" value="'.$libfile.'" size="20" /></td>'."\n".
+                                  '<td valign="top">'.$items->[$j].'</td>'."\n".
+                                  '<td valign="top">'.$showfoil.'</td>'."\n".
+                                  &Apache::loncommon::end_data_table_row());
                     }
                     last;
                 }
             }
         }
     }
-    $r->print(qq|
-              </table>
-              </td>
-              </tr>
-              </table>
-             </td>
-            </tr>
-           </table>
-          </td>
-         </tr>
-        </table>
-       </td>
-      </tr>
-      <tr>
-       <td colspan='2'>&nbsp;</td>
-      </tr>
-      <tr bgcolor='#ccddaa'>
-       <td width='30' align='top'><img src='/res/adm/pages/bl_step4.gif'>
-       </td>
-       <td width='100%' align='left'>&nbsp;&nbsp;
-        <font size='+1' face='arial,helvetica,sans-serif'><b>Create a directory to save your testbank questions.</b></font>
-       </td>
-      </tr>
-      <tr>
-       <td colspan='2'>&nbsp;</td>
-      </tr>
-      <tr>
-       <td>&nbsp;</td>
-       <td>
-        <font face='Arial,Helvetica,sans-serif'>
-Please choose a destination LON-CAPA directory in which to save your uploaded questions.&nbsp;&nbsp;
-       <input type="button" name="createdir" value="Create Directory" onClick="javascript:createWin()"><input type="hidden" name="newdir" value=""></font></td>
-      </tr>
-      <tr>
-       <td colspan='2'>&nbsp;</td>
-      </tr>
-      <tr>
-       <td>&nbsp;</td>
-       <td><font face='arial,helvetica,sans-serif'>If you are satisfied with the questions and answers extracted from your uploaded text file, as shown above, and you have created a destination directory click the "Continue to step 5" button to convert the questions in your testbank to LON-CAPA problem files.</font></td>
-      </tr>
-      <tr>
-       <td colspan='2'>
-          <input type='hidden' name="go" value="">
-          <input type='hidden' name="qnumformat" value="$qnumformat">
-          <input type='hidden' name="blocks" value="$blocks">
-          <input type="hidden" name="uploaduname" value="$uname">
-          <input type="hidden" name="filename" value="$fn">
-          <input type='hidden' name="page" value="$page">
-          <input type="hidden" name="phase" value="three">
-    |);
+    $r->print(&Apache::loncommon::end_data_table().'</p><p>'."\n".
+              '<input type="hidden" name="qnumformat" value="'.$qnumformat.'" />'."\n".
+              '<input type="hidden" name="blocks" value="'.$blocks.'" />');
     for (my $i=0; $i<$blocks; $i++) {
-        $r->print(qq|
-          <input type='hidden' name="start_$i" value="$start[$i]">
-          <input type='hidden' name="end_$i" value="$end[$i]">
-          <input type='hidden' name="qtype_$i" value="$qtype[$i]">
-        |);
+        $r->print('
+          <input type="hidden" name="start_'.$i.'" value="'.$start[$i].'" />
+          <input type="hidden" name="end_'.$i.'" value="'.$end[$i].'" />
+          <input type="hidden" name="qtype_'.$i.'" value="'.$qtype[$i].'" />');
         if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
-            $r->print(qq|
-          <input type='hidden' name="foilformat_$i" value="$foilformats[$i]">
-            |);
+            $r->print('
+          <input type="hidden" name="foilformat_'.$i.'" value="'.$foilformats[$i].'" />');
         }
         if (($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "TF") || ($qtype[$i] eq "Ord")) {
-            $r->print(qq|
-          <input type='hidden' name="ansr_$i" value="$ansrtypes[$i]">
-            |);
-        }
-    }
-    $r->print(qq|
-       </td>
-      </tr>
-      <tr>
-       <td colspan='2'>&nbsp;<br /><br /></td>
-      </tr>
-      <tr>
-       <td colspan='2'>
-        <table border='0' cellspacing='0' cellpadding='0' width="100%">
-         <tr>
-          <td align='left'>
-           <input type="button" name="backpage" value="Go back to step 3" onClick="javascript:backPage()">
-          </td>
-          <td align='right'>
-           <input type="button" name="nextpage" value="Continue to step 5" onClick="javascript:nextPage()">
-          </td>
-         </tr>
-        </table>
-       </td>
-      </tr>
-     </table>
-    </td>
-   </tr>
-  </table>
-</form>
-    |);
+            $r->print('
+          <input type="hidden" name="ansr_'.$i.'" value="'.$ansrtypes[$i].'" />');
+        }
+    }
+    $r->print('</p>'.&page_footer($env{'form.newdir'},$uname,$fn,$page).'
+              </form>');
 }
 
 # ---------------------------------------------------------------- Final Display
 sub final_display {
-    my ($r,$uname,$fn,$page,$textref) = @_;
+    my ($r,$uname,$fn,$page,$textref,$res,$header,$css,$js,$webpath,$dirpath,$subdir) = @_;
     my $qnumformat = $env{'form.qnumformat'};
     my $blocks = $env{'form.blocks'};
-    my $newdir = $env{'form.newdir'};
-    my $linkdir = $newdir;
-    if ($linkdir =~ m#^/home/$uname/public_html/(.+)$#) {
-        $linkdir = '/priv/'.$uname.'/'.$1;
-    }
     my $question_id = '';
     my @question_title = ();
     my @question_status  = ();
@@ -1126,6 +878,7 @@
     my @ansrtypes = ();
     my %multparts = ();
     my $numitems = 0;
+    my @createprobs = &Apache::loncommon::get_env_multiple('form.createprob');
     for (my $i=0; $i<$blocks; $i++) {
         $start[$i] = $env{"form.start_$i"};
         $end[$i] = $env{"form.end_$i"};
@@ -1146,15 +899,11 @@
         $numitems += $nums[$i];
     }
 
-    my @bgcolors = ('#ffffff','#eeeeee');
-
-    my $import = join/'\s'/,@{$textref};
-    my %answers = ();
-    my @items = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
+    my %answers;
+    my ($items,$ids,$footer) = &file_split(\@start,\@end,\@nums,$qnumformat,\@foilformats,$textref,\%multparts,$numitems,\@qtype,$blocks);
 
 # Converting MC and MA answer to number, and splitting answers for FIB, and ordering for Ord.
-  my @alphabet = ("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
-    my @romans = ("i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","xiii","xiv","xv","xvi","xvii","xviii","xix","xx","xxi","xxii","xxiii","xxiv","xxv","xxvi");
+    my ($alphabet,$romans) = &get_constants();
     my %patterns = (
          comma => ',',
          space => '\s+',
@@ -1165,28 +914,35 @@
         if ($nums[$i] > 0) {
             if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
                 for (my $k=$numitems+$start[$i]-1; $k<$numitems+$end[$i]; $k++) {
-                    @{$answers{$k}} = ();
+                    my $qnum = $k - $numitems;
+                    next if (!grep(/^$qnum$/,@createprobs));
+                    if (($res eq 'application/rtf') || ($res eq 'text/html')) {
+                        $items->[$k] = &HTML::Entities::decode($items->[$k]);
+                    }
+                    @{$answers{$qnum}} = ();
                     if ($qtype[$i] eq "MC") {
-                        $items[$k] =~ tr/A-Z/a-z/;
-                        $items[$k] =~ s/\W//g;
+                        $items->[$k] =~ tr/A-Z/a-z/;
+                        $items->[$k] =~ s/<\/?[^>]+>//g;
+                        $items->[$k] =~ s/\W//g;
                         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") {
-                            for (my $j=0; $j<@alphabet; $j++) {
-                                if ($alphabet[$j] eq $items[$k]) {
-                                    push @{$answers{$k}}, $j;
+                            for (my $j=0; $j<@{$alphabet}; $j++) {
+                                if ($alphabet->[$j] eq $items->[$k]) {
+                                    push @{$answers{$qnum}}, $j;
                                     last;
                                 }
                             }
                         } elsif (($foilformats[$i] eq "romparen") || ($foilformats[$i] eq "romperiod") || ($foilformats[$i] eq "romoneparen") || ($foilformats[$i] eq "romdotparen")) {
-                            for (my $j=0; $j<@romans; $j++) {
-                                if ($romans[$j] eq $items[$k]) {
-                                    push @{$answers{$k}}, $j;
+                            for (my $j=0; $j<@{$romans}; $j++) {
+                                if ($romans->[$j] eq $items->[$k]) {
+                                    push @{$answers{$qnum}}, $j;
                                     last;
                                 }
                             }
                         }
                     } elsif (($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) {
-                        $items[$k] =~ tr/A-Z/a-z/;
-                        my @corrects = split/$patterns{$ansrtypes[$i]}/,$items[$k];
+                        $items->[$k] =~ tr/A-Z/a-z/;
+                        $items->[$k] =~ s/<\/?[^>]+>//g;
+                        my @corrects = split/$patterns{$ansrtypes[$i]}/,$items->[$k];
                         foreach my $correct (@corrects) {
                             my @tied;
                             if ($qtype[$i] eq "Ord") {
@@ -1202,22 +958,22 @@
                                 $correct =~s/\W//g;
                             }
                             if ($foilformats[$i] eq "lcperiod" || $foilformats[$i] eq "lcparen" || $foilformats[$i] eq "ucparen" || $foilformats[$i] eq "ucperiod") {
-                                if (($qtype[$i] eq "Ord") && (@tied > 0)) { 
+                                if (($qtype[$i] eq "Ord") && (@tied > 0)) {
                                     my @ties;
                                     foreach my $tie (@tied) {
-                                        for (my $j=0; $j<@alphabet; $j++) {
-                                            if ($alphabet[$j] eq $tie) {
+                                        for (my $j=0; $j<@{$alphabet}; $j++) {
+                                            if ($alphabet->[$j] eq $tie) {
                                                 push(@ties,$j);
                                                 last;
                                             }
                                         }
                                     }
                                     my $ans = join('=',@ties);
-                                    push(@{$answers{$k}},$ans);
+                                    push(@{$answers{$qnum}},$ans);
                                 } else {
-                                    for (my $j=0; $j<@alphabet; $j++) {
-                                        if ($alphabet[$j] eq $correct) {
-                                            push @{$answers{$k}}, $j;
+                                    for (my $j=0; $j<@{$alphabet}; $j++) {
+                                        if ($alphabet->[$j] eq $correct) {
+                                            push @{$answers{$qnum}}, $j;
                                             last;
                                         }
                                     }
@@ -1226,18 +982,18 @@
                                 if (($qtype[$i] eq "Ord") && (@tied > 0)) {
                                     my @ties;
                                     foreach my $tie (@tied) {
-                                        for (my $j=0; $j<@romans; $j++) {
-                                            if ($romans[$j] eq $tie) {
+                                        for (my $j=0; $j<@{$romans}; $j++) {
+                                            if ($romans->[$j] eq $tie) {
                                                 push(@ties,$j);
                                                 last;
                                             }
                                         }
                                     }
-                                    push(@{$answers{$k}},join('=',@ties));
+                                    push(@{$answers{$qnum}},join('=',@ties));
                                 } else {
-                                    for (my $j=0; $j<@romans; $j++) {
-                                        if ($romans[$j] eq $correct) {
-                                            push @{$answers{$k}}, $j;
+                                    for (my $j=0; $j<@{$romans}; $j++) {
+                                        if ($romans->[$j] eq $correct) {
+                                            push @{$answers{$qnum}}, $j;
                                             last;
                                         }
                                     }
@@ -1245,197 +1001,212 @@
                             }
                         }
                     } elsif ($qtype[$i] eq "FIB") {
-                        @{$answers{$k}} = split/$patterns{$ansrtypes[$i]}/,$items[$k];
-                        for (my $j=0; $j<@{$answers{$k}}; $j++) {
-                            $answers{$k}[$j] =~ s/^\s+//;
-                            $answers{$k}[$j] =~ s/\s+$//;
+                        $items->[$k] =~ s/<\/?[^>]+>//g;
+                        @{$answers{$qnum}} = split/$patterns{$ansrtypes[$i]}/,$items->[$k];
+                        for (my $j=0; $j<@{$answers{$qnum}}; $j++) {
+                            $answers{$qnum}[$j] =~ s/^\s+//;
+                            $answers{$qnum}[$j] =~ s/\s+$//;
+                            if ($j==0) {
+                                $answers{$qnum}[$j] =~ s/^<[^>]+>//;
+                            } elsif ($j == @{$answers{$qnum}}-1) {
+                                $answers{$qnum}[$j] =~ s/<\/[^>]+>$//;
+                            }
                         }
                     }
                 }
             }
         }
     }
-    my $pooltarget = '';
-    my $pooldesc = '';
-    my @newquestions = ();
-    my $numquestions = 0;
-    my %qtype = ();
-    my %qtext = ();
-    my %qflag = ();
-
-    $r->print(<<"END_OF_BLOCK");
-        <form name="verify" method="post">
-        <table border='0' cellspacing='0' cellpadding='0' width="100%">
-         <tr>
-          <td colspan='2'  align='left'>&nbsp;
-          </td>
-         </tr>
-         <tr bgcolor='#ccddaa'>
-          <td align='top'>&nbsp;
-          </td>
-          <td valign='middle'><img src='/res/adm/pages/bl_step5.gif'>&nbsp;&nbsp;
-           <font size='+1' face='arial,helvetica,sans-serif'>&nbsp;<b>Result of conversion of tesbank questions to LON-CAPA problems.</b></font>
-          </td>
-         </tr>
-         <tr>
-          <td colspan='2'>&nbsp;</td>
-         </tr>
-END_OF_BLOCK
-    if ($newdir ne "") {
-        my @qn_file = ();
+    my $state;
+
+    $r->print('<form name="verify" method="post" action="/adm/testbank">'."\n".
+              '<input type="hidden" name="blocks" value="'.$blocks.'" />'."\n".
+              '<input type="hidden" name="qnumformat" value="'.$qnumformat.'" />'."\n");
+    for (my $i=0; $i<$blocks; $i++) {
+       $r->print('<input type="hidden" name="start_'.$i.'" value="'.$start[$i].'" />
+           <input type="hidden" name="end_'.$i.'" value="'.$end[$i].'" />
+           <input type="hidden" name="qtype_'.$i.'" value="'.$qtype[$i].'" />
+           <input type="hidden" name="foilformat_'.$i.'" value="'.$foilformats[$i].'" />
+           <input type="hidden" name="ansr_'.$i.'" value="'.$ansrtypes[$i].'" />'."\n");
+    }
+    for (my $i=0; $i<$numitems; $i++) {
+        $r->print('<input type="hidden" name="probfile_'.$i.'" value="'.$env{'form.probfile_'.$i}.'" />'."\n");
+    }
+    $r->print(&topic_bar(6,&mt('Result of conversion of testbank questions to LON-CAPA problems')));
+    my $destdir = $dirpath;
+    if ($destdir ne '' && $subdir ne '') {
+        $subdir .= '/';
+        $destdir .= $subdir; 
+    }
+    if (@createprobs == 0) {
+        $state = 'unchecked';
+        $r->print('<p>'.&mt('No questions were selected for conversion.').'</p>'.
+                  &page_footer($env{'form.newdir'},$uname,$fn,$page,$webpath,$subdir,$state).'</form>');
+    } elsif (($destdir ne '') && (-e $destdir)) {
+        my (@qn_file,@result,@numid);
         my $qcount = 0;
+        my $itemcount = 0;
         for (my $i=0; $i<$blocks; $i++) {
             if ($nums[$i] > 0) {
                 if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "FIB") || ($qtype[$i] eq "Ord")) {
                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
+                        $numid[$qcount] = $ids->[$itemcount];
+                        $itemcount ++;
+                        next if (!grep(/^$qcount$/,@createprobs));
+                        my $libfile = &probfile_name($j);
                         my $answer = $j + $numitems;
-                        my $numans = scalar(@{$answers{$answer}});
+                        my $numans = scalar(@{$answers{$qcount}});
                         my $foilcount = 0;
                         if (($qtype[$i] eq "MC") || ($qtype[$i] eq "MA") || ($qtype[$i] eq "Ord")) { 
                             $foilcount = @{$multparts{$j}};
                             $foilcount --;
                         }
-                        $qn_file[$qcount] = &create_mcq($newdir,\@{$multparts{$j}},\@{$answers{$answer}},$qtype[$i],$j);
+                        ($result[$qcount],$qn_file[$qcount]) = &create_mcq($destdir,$subdir,\@{$multparts{$j}},\@{$answers{$qcount}},$qtype[$i],$libfile,$res,$header,$footer,$js,$css);
                         $qcount ++;
-                        push @newquestions, $question_id;
                     }
                 } elsif ($qtype[$i] eq "TF") {
                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
+                        $numid[$qcount] = $ids->[$itemcount];
+                        $itemcount ++;
+                        next if (!grep(/^$qcount$/,@createprobs));
+                        my $libfile = &probfile_name($j);
                         my $answer = $j + $numitems;
-                        $items[$answer] =~ s/^\s+//;
-                        $items[$answer] =~ s/\s+$//;
-                        $items[$answer] =~ s/\W//g;
-                        $items[$answer] =~ tr/A-Z/a-z/;
+                        $items->[$answer] =~ s/^\s+//;
+                        $items->[$answer] =~ s/\s+$//;
+                        $items->[$answer] =~ s/\W//g;
+                        $items->[$answer] =~ tr/A-Z/a-z/;
                         my $answer_id = '';
                         if ($ansrtypes[$i] eq 'word' ) {
-                            if ($items[$answer] =~ m/true/) {
+                            if ($items->[$answer] =~ m/true/) {
                                 $answer_id = 0;
                             } else {
                                 $answer_id = 1;
                             }
                         } elsif ($ansrtypes[$i] eq 'lett') {
-                            if ($items[$answer] =~ m/^t/) {
+                            if ($items->[$answer] =~ m/^t/) {
                                 $answer_id = 0;
                             } else {
                                 $answer_id = 1;
                             }
                         }
-                        $qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$j);
-                        push @newquestions, $question_id;
+                        ($result[$qcount],$qn_file[$qcount]) = &create_ess($destdir,$subdir,$answer_id,$items->[$j],$items->[$answer],$qtype[$i],$libfile,$res,$header,$footer,$js,$css);
                         $qcount ++;
                     }
                 } elsif ($qtype[$i] eq "Ess") {
                     for (my $j=$start[$i]-1; $j<$end[$i]; $j++) {
+                        $numid[$qcount] = $ids->[$itemcount];
+                        $itemcount ++;
+                        next if (!grep(/^$qcount$/,@createprobs));
+                        my $libfile = &probfile_name($j);
                         my $answer = $j + $numitems;
                         my $answer_id = '';
-                        $qn_file[$qcount] = create_ess($newdir,$answer_id,$items[$j],$items[$answer],$qtype[$i],$j);
-                        push @newquestions, $question_id;
+                        ($result[$qcount],$qn_file[$qcount]) = &create_ess($destdir,$subdir,$answer_id,$items->[$j],$items->[$answer],$qtype[$i],$libfile,$res,$header,$footer,$js,$css);
                         $qcount ++;
                     }
                 }
             }
         }
-        $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:
-       <ul>|);
+        my ($successes,$failures,$existing);
         for (my $i=0; $i<@qn_file; $i++) {
-            my $display = $i+1;
-            $r->print(qq|
-       <li><b><a href="$linkdir/$qn_file[$i]">Problem $display file</a></b></li>
-            |);
-        }
-        $r->print(qq|
-       </ul></font></td></tr>
-       <tr><td>&nbsp;</td>
-           <td><font face='arial,helvetica,sans-serif'>The problems must be published before they can be used in a course.</font></td>
-        |);
+            if ($result[$i] eq 'ok') {
+                $successes .= '<b>'.$numid[$i].':&nbsp;<a href="'.$webpath.$qn_file[$i].'">'.
+                          $qn_file[$i].'</a></b><br />'."\n";
+            } elsif ($result[$i] eq 'failed') {
+                $failures .= $numid[$i].':&nbsp;'.$qn_file[$i].'<br />'."\n";
+            } elsif ($result[$i] eq 'exists') {
+                $existing .= '<b>'.$numid[$i].':&nbsp;<a href="'.$webpath.$qn_file[$i].'">'.
+                          $qn_file[$i].'</a></b><br />'."\n";
+            }
+        }
+        if ($successes) {
+            $r->print('<p>'.&mt('Individual problem files have been created from the following problems included in the testbank file:').'<br />'.$successes.'</p><p>'.
+                     &mt('The problems must be published before they can be used in a course').'</p>');
+        }
+        if ($failures) {
+            $r->print('<p>'.&mt('An error occurred when opening files for the following problems, so they have not been created:').'<br />'.$failures.'</p>');
+        }
+        if ($existing) {
+            $r->print('<p>'.&mt('The following files already existed, and were not overwritten so these problems generated from the testbank have not been saved:').'<br />'.$existing.'</p>');
+            $state = 'existing';
+        }
+        $r->print(&page_footer($env{'form.newdir'},$uname,$fn,$page,$webpath,$subdir,$state).'</form>');
     } else {
-        $r->print(qq|
-         <tr>
-          <td>&nbsp;</td>
-          <td><font face='arial,helvetica,sans-serif'>No destination file was selected or created, so import of your questions could not proceed.  
-          Please return to the previous page and select a valid file into which to import the questions. </font>
-           <input type="hidden" name="go" value="">
-           <input type="hidden" name="page" value="$page">
-           <input type="hidden" name="uploaduname" value="$uname">
-           <input type="hidden" name="filename" value="$fn">
-           <input type='hidden' name="page" value="$page">
-           <input type="hidden" name="phase" value="three">
-           <input type="hidden" name="qnumformat" value="$qnumformat">
-           <input type="hidden" name="newdir" value="$newdir">
-        |);
-        for (my $i=0; $i<$blocks; $i++) {
-           $r->print(qq|
-           <input type="hidden" name="start_$i" value="$start[$i]">
-           <input type="hidden" name="end_$i" value="$end[$i]">
-           <input type="hidden" name="qtype_$i" value="$qtype[$i]">
-           <input type="hidden" name="foilformat_$i" value="$foilformats[$i]">
-           <input type="hidden" name="ansr_$i" value="$ansrtypes[$i]">
-            |);
-        }
-        $r->print(<<"END_OF_FAIL");
-          </td>
-         </tr>
-         <tr>
-          <td colspan='2'>
-           <table border='0' width='100%'>
-            <tr>
-             <td align='right'>
-              <input type="button" name="backpage" value="Return to step 3" onClick="javascript:backPage()">
-             </td>
-            </tr>
-           </table>
-          </td>
-         </tr>
-        </table>
-       </td>
-      </tr>
-     </table>
-    </td>
-   </tr>
-  </table>
- </form>
-END_OF_FAIL
+        $state = 'nodir';
+        $r->print('<p>'.&mt('No destination directory was available so import of questions could not proceed.').'</p>'.
+                  &page_footer($env{'form.newdir'},$uname,$fn,$page,$webpath,$subdir,$state).'</form>');
+    }
     return;
-  }
-  $r->print(<<"END_OF_BODY");
-             </table>
-            </td>
-           </tr>
-          </table>
-        </td>
-       </tr>
-       <tr>
-        <td colspan='2'>&nbsp;
-         <input type="hidden" name="go" value="">
-         <input type="hidden" name="page" value="$page">
-         <input type="hidden" name="uploaduname" value="$uname">
-         <input type="hidden" name="filename" value="$fn">
-         <input type='hidden' name="page" value="$page">
-         <input type="hidden" name="phase" value="one">
-         <input type="hidden" name="qnumformat" value="$qnumformat"> 
-         <input type="hidden" name="newdir" value="$newdir">
-        </td>
-       </tr>
-       <tr>
-        <td colspan='2'>
-         <table border='0' width='100%'>
-          <tr>
-           <td align='left'>
-             <input type='button' name='backtostart' value='Back to start page' onClick='javascript:backtoStart()'>
-           </td>
-          </tr>
-         </table>
-        </td>
-       </tr>
-      </table>
-     </td>
-    </tr>
-   </table>
-  </td>
- </tr>
-</table>
-</form>
-END_OF_BODY
+}
+
+sub show_uploaded_data {
+    my ($textref,$header) = @_;
+    my $output = '<p><b>'.&mt('Testbank data uploaded to the server').'</b></p><p>'."\n".
+                 '<textarea name="rawdata" cols="70" rows="6" wrap="virtual" align="center">'."\n";
+    if ($header ne '') {
+        $output .= $header."\n";
+    }
+    if (ref($textref) eq 'ARRAY') {
+        foreach my $line (@{$textref}) {
+           $line =~ s/\n//g;
+           if ($line ne '') {
+               $output .= $line."\n";
+           }
+        }
+    }
+    $output .= '</textarea></p>';
+    return $output;
+}
+
+sub page_footer {
+    my ($newdir,$uname,$fn,$page,$webpath,$subdir,$state) = @_;
+    my $prevval = &mt('Previous Page');
+    my $nextval = &mt('Next Page');
+    my $prevclick = 'javascript:backPage();';
+    my $nextclick = 'javascript:nextPage();';
+    my $go = ''; 
+    if ($page == 0) {
+        $go = 'NextPage';
+        $prevval = &mt('Exit Now');
+        $prevclick = 'javascript:location.href='."'$webpath';";
+        $nextclick = 'javascript:submit();'
+    } elsif ($page == 3) {
+        $nextval = &mt('Complete Testbank Conversion');
+    } elsif ($page == 4) {
+        if (($state ne 'existing') && ($state ne 'unchecked')) {
+            my $destdir = $webpath;
+            if ($subdir ne '') {
+                $destdir = $webpath.$subdir;
+            }
+            $prevval = &mt('Back to Directory');
+            $prevclick = 'javascript:location.href='."'$destdir';";
+       }
+    }
+    my $output = '
+       <input type="hidden" name="newdir" value="'.&HTML::Entities::encode($newdir,'<>&"').'" />
+       <input type="hidden" name="uploaduname" value="'.$uname.'" />
+       <input type="hidden" name="filename" value="'.$fn.'" />
+       <input type="hidden" name="page" value="'.$page.'" />
+       <input type="hidden" name="phase" value="three" />
+       <input type="hidden" name="go" value="'.$go.'" />';
+    if ($page ne '') {
+        $output .= '
+       <table border="0">
+        <tr>
+         <td>
+          <input type="button" name="backpage" value="'.$prevval.'" onclick="'.$prevclick.'" />
+         </td>';
+        if ($page < 4)  {
+            $output .= '
+         <td>&nbsp;</td>
+         <td>
+          <input type="button" name="nextpage" value="'.$nextval.'" onclick="'.$nextclick.'">
+         </td>';
+        }
+        $output .= '    </tr>
+       </table>
+';
+    }
+    return $output;
 }
 
 sub question_count {
@@ -1461,32 +1232,44 @@
     return $qcount;
 }
 
+sub get_constants {
+    my @alphabet = ("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
+    my @romans = ("i","ii","iii","iv","v","vi","vii","viii","ix","x","xi","xii","xiii","xiv","xv","xvi","xvii","xviii","xix","xx","xxi","xxii","xxiii","xxiv","xxv","xxvi");
+    return (\@alphabet,\@romans);
+}
+
 sub file_split {
     my ($startsref,$endsref,$numsref,$qnumformat,$foilsref,$textref,$multpartsref,$numitems,$qtyperef,$blocks) = @_;
     my $text_in = join "\n", @{$textref};
     $text_in = "\n ".$text_in;
     my $dignum = length($numitems);
-    my $numpat;
+    my ($qpatst,$qpatend,$numpat,@questions,@qids);
+    my $numpat = '\d{1';
     if ($dignum > 1) {
-        $numpat = ','.$dignum.'}';
+        $numpat .= ','.$dignum.'}';
     } else {
-        $numpat = '}';
+        $numpat .= '}';
     }
-    my $qpattern ='';
     if ($qnumformat eq "period") {
-        $qpattern = '\d{1'.$numpat.'\.'; 
+        $qpatend = '\.'; 
     } elsif ($qnumformat eq "paren") {
-        $qpattern = '\(\d{1'.$numpat.'\)';
-    } elsif ($qnumformat eq "number") {
-        $qpattern = '\d{1'.$numpat;
+        $qpatst = '\(';
+        $qpatend = '\)';
     } elsif ($qnumformat eq "leadparen") {
-        $qpattern = '\(\d{1'.$numpat;
+        $qpatst = '\(';
     } elsif ($qnumformat eq "trailparen") {
-        $qpattern = '\d{1'.$numpat.'\)';
+        $qpatend = '\)';
     }
-    my @questions = split/[\r\n\f]+\s*$qpattern\s*/,$text_in;
+    my @lines = split/[\r\n\f]+\s*$qpatst($numpat)$qpatend\s*/,$text_in;
 # my @questions = split/\n\s\d{1,3}\.\s/,$text_in;
-    shift @questions;
+    shift(@lines);
+    for (my $i=0; $i<@lines; $i++) {
+        if ($i%2) {
+            push(@questions,$lines[$i]);
+        } else {
+            push(@qids,$lines[$i]);
+        }
+    }
     my %multparts = ();
     for (my $i=0; $i<$blocks; $i++) {
         if (${$numsref}[$i] > 0) {
@@ -1527,32 +1310,40 @@
                 }
             }
         }
-    }    
+    }
+    my ($lastanswer,$footer) = ($questions[-1] =~ /^([,\r\n\f\t\s().A-Za-z]+)(.+)$/);
+    if ($footer ne '') {
+        $questions[-1] = $lastanswer;
+    }
     %{$multpartsref} = %multparts;
-    return @questions;
+    return (\@questions,\@qids,$footer);
 }
  
 # create_mcq builds an MC, MA, Ord or FIB question
 
 sub create_mcq {
-    my ($newdir,$qstnref,$answerref,$qtype,$qnum) = @_;
-    $qnum ++;
-    if (length($qnum) == 1) {
-        $qnum = "00".$qnum;
-    } elsif (length($qnum) == 2) {
-        $qnum = "0".$qnum;
-    }
+    my ($destdir,$subdir,$qstnref,$answerref,$qtype,$libfile,$res,$header,$footer,$js,$css) = @_;
+
     my $qstn = ${$qstnref}[0];
     my $numfoils = scalar(@{$qstnref}) - 1; 
     my $datestamp = localtime;
     my $timestamp = time;
-    my $libfile = 'question_'.$qnum;
-    $libfile .= '.problem';
     my $numansrs = scalar(@{$answerref});
-    my $output = qq|<problem>
- <startouttext />$qstn<endouttext />
-    |;
-  
+    my $output = '<problem>
+ <startouttext />';
+    if ($res eq 'application/rtf' || $res eq 'text/html') {
+        if ($header ne '') {
+            $output .= &HTML::Entities::decode($header);
+        }
+        if ($js ne '') {
+            $output .= &HTML::Entities::decode($js);
+        }
+        if ($css ne '') {
+            $output .= &HTML::Entities::decode($css);
+        }
+        $qstn = &HTML::Entities::decode($qstn);
+    }
+    $output .= $qstn.'<endouttext />'."\n";
     if ($qtype eq "MA") {
         $output .= qq|
    <optionresponse max="$numfoils" randomize="yes">
@@ -1565,14 +1356,16 @@
             } else {
                 $output .= "False\" location=\"random\"";
             }
-            $output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
+            my $showfoil = ${$qstnref}[$k+1];
+            if ($res eq 'application/rtf' || $res eq 'text/html') {
+                $showfoil = &HTML::Entities::decode($showfoil);
+            }
+            $output .= "\><startouttext />$showfoil<endouttext /></foil>\n";
         }
         chomp($output);
         $output .= qq|
     </foilgroup>
-   </optionresponse>
-  </problem>
-        |;
+   </optionresponse>|;
     }
     if ($qtype eq "MC") {
         $output .= qq|
@@ -1591,16 +1384,17 @@
             } else {
                 $output .= "random\"";
             }
-            $output .= "\><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
+            my $showfoil = ${$qstnref}[$k+1];
+            if ($res eq 'application/rtf' || $res eq 'text/html') {
+                $showfoil = &HTML::Entities::decode($showfoil);
+            }
+            $output .= "\><startouttext />$showfoil<endouttext /></foil>\n";
         }
         chomp($output);
         $output .= qq|
     </foilgroup>
-   </radiobuttonresponse>
-  </problem>
-        |;
+   </radiobuttonresponse>|;
     }
-
     if ($qtype eq "Ord") {
         $output .= qq|
    <rankresponse max="$numfoils" randomize="yes">
@@ -1626,16 +1420,17 @@
                     $num ++;
                 }
             }
-            $output .= "   <foil location=\"random\" name=\"foil".$k."\" value=\"".$ansval."\"><startouttext />".${$qstnref}[$k+1]."<endouttext /></foil>\n";
+            my $showfoil = ${$qstnref}[$k+1];
+            if ($res eq 'application/rtf' || $res eq 'text/html') {
+                $showfoil = &HTML::Entities::decode($showfoil);
+            }
+            $output .= "   <foil location=\"random\" name=\"foil".$k."\" value=\"".$ansval."\"><startouttext />$showfoil<endouttext /></foil>\n";
         }
         chomp($output);
         $output .= qq|
     </foilgroup>
-   </rankresponse>
-  </problem>
-        |;
+   </rankresponse>|;
     }
-   
     if ($qtype eq "FIB") {
         my $numerical = 1;
         for (my $i=0; $i<@{$answerref}; $i++) {
@@ -1667,18 +1462,14 @@
 	<responseparam type="tolerance" default="$tol%" name="tol" description="Numerical Tolerance" />
 	<responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures" />
 	<textline />
-</numericalresponse>
-</problem>
-|;
+</numericalresponse>|;
         } else {
             if (@{$answerref} == 1) {
                 $output .= qq|
 <stringresponse answer="$$answerref[0]" type="ci">
 <textline>
 </textline>
-</stringresponse>
-</problem>
-|;
+</stringresponse>|;
             } else {
                 for (my $i=0; $i<@{$answerref}; $i++) {
                     ${$answerref}[$i] =~ s/\|/\|/g;
@@ -1689,46 +1480,64 @@
 <stringresponse answer="$regexpans" type="re">
 <textline>
 </textline>
-</stringresponse>
-</problem>
-|;
+</stringresponse>|;
             }
         }
     }
-    open(PROB,">$newdir/$libfile");
-    print PROB $output;
-    close PROB;
-    return $libfile;
+    if ($footer ne '') {
+        $output .= '<startouttext />'.&HTML::Entities::decode($footer).'<endouttext />';
+    }
+    $output .= qq|
+  </problem>
+|;
+    my $result;
+    if (-e $destdir.$libfile) {
+        $result = 'exists';
+    } else {
+        if (open(PROB,">$destdir$libfile")) {
+            print PROB $output;
+            close(PROB);
+            $result = 'ok';
+        } else {
+            $result = 'failed';
+        } 
+    }
+    return ($result,$subdir.$libfile);
 }
 
 # create_ess builds an essay or True/False question
 
 sub create_ess {
-    my ($newdir,$answer_id,$qstn,$answertxt,$qtype,$qnum) = @_;
-    $qnum ++;
-    if (length($qnum) == 1) {
-        $qnum = "00".$qnum;
-    } elsif (length($qnum) == 2) {
-        $qnum = "0".$qnum;
-    }
-    my $libfile = 'question_'.$qnum;
-    $libfile .= '.problem';
-    my $output = qq|<problem>
- <startouttext />$qstn<endouttext />|;
-
+    my ($destdir,$subdir,$answer_id,$qstn,$answertxt,$qtype,$libfile,$res,$header,
+        $footer,$js,$css) = @_;
+    my $output = '<problem>
+ <startouttext />';
+    if ($res eq 'application/rtf' || $res eq 'text/html') {
+        if ($header ne '') {
+            $output .= &HTML::Entities::decode($header);
+        }
+        if ($js ne '') {
+            $output .= &HTML::Entities::decode($js);
+        }
+        if ($css ne '') {
+            $output .= &HTML::Entities::decode($css);
+        }
+        $qstn = &HTML::Entities::decode($qstn);
+        $answertxt = &HTML::Entities::decode($answertxt);
+    }
+    $output .= $qstn.'<endouttext />';
     my $answer = '';
     my $answerlog = '';
     if ($qtype eq "Ess") {
-        $output .= qq|
+        $output .= '
    <essayresponse>
    <textfield></textfield>
    </essayresponse>
    <postanswerdate>
     <startouttext />
-   $answertxt
-    <endouttext />
-   </postanswerdate>
-  </problem>|;
+   '.$answertxt
+   .'<endouttext />
+   </postanswerdate>';
     } elsif ($qtype eq "TF") {
          $answer = $answer_id;
          $output .= qq|
@@ -1748,21 +1557,227 @@
          } else {
               $output .= "False";
          }
-         $output .= qq|<endouttext /></foil>
+         $output .= '<endouttext /></foil>
     </foilgroup>
-   </radiobuttonresponse>
-  </problem>|;
+   </radiobuttonresponse>';
      }
-     open(PROB,">$newdir/$libfile");
-     print PROB $output;
-     close PROB;
-     return $libfile;
+     if ($footer ne '') {
+        $output .= '
+<startouttext />'.&HTML::Entities::decode($footer).'<endouttext />';
+     }
+     $output .= '
+  </problem>
+';
+     my $result;
+     if (-e $destdir.$libfile) {
+         $result = 'exists';
+     } else {
+         if (open(PROB,">$destdir$libfile")) {
+             print PROB $output;
+             close(PROB);
+         } else {
+             $result = 'failed';
+         }
+     }
+     return ($result,$subdir.$libfile);
+}
+
+sub probfile_name {
+    my ($j) = @_;
+    my $libfile = &HTML::Entities::decode($env{'form.probfile_'.$j});
+    my $qnum = $j + 1;
+    if ($libfile eq '') {
+        if (length($qnum) == 1) {
+            $qnum = "00".$qnum;
+        } elsif (length($qnum) == 2) {
+            $qnum = "0".$qnum;
+        }
+        $libfile = 'testbank_question_'.$qnum;
+        $libfile .= '.problem';
+    }
+    return $libfile;
 }
 
 sub file_error {
     my ($r,$uname,$fn,$current_page);
     $r->print("No data here");
-} 
+}
+
+sub parse_datafile {
+    my ($r,$uname,$filename,$pathname,$dirpath,$urlpath,$page_name,$subdir) = @_;
+    my ($badfile,$res,%allfiles,%codebase);
+    my $mm = new File::MMagic;
+    my ($text,$header,$css,$js);
+    if (-e "$dirpath") {
+        $res = $mm->checktype_filename($dirpath.$filename);
+        if ($env{'form.phase'} eq 'three') {          
+            if ($res eq 'text/plain') {
+                open(TESTBANK,"<$dirpath$filename");
+                @{$text} = <TESTBANK>;
+                close(TESTBANK);
+            } elsif ($res eq 'application/rtf') {
+                my $html = '';
+#                my $image_uri = '..'.$pathname;
+                my $image_uri = $pathname;
+                if ($page_name eq 'Target') {
+                    $image_uri = $urlpath;
+                }
+                $image_uri =~ s/\/$//;
+                my $image_dir;
+                if ($page_name eq 'Blocks') {
+                    $image_dir = $dirpath;
+                    $image_dir =~ s/\/$//;
+                } else {
+                    $image_dir = $r->dir_config('lonDaemons').'/tmp/'.
+                                 $env{'user.name'}.'_'.$env{'user.domain'}.
+                                 '_rtfupload_'.$filename.'_'.time.'_'.$$;
+                   if (!-e $image_dir) {
+                       mkdir($image_dir,0755);
+                   }
+                }
+                my $parser = RTF::HTMLConverter->new (
+                                  in                => $dirpath.$filename,
+                                  out               => \$html,
+                                  DOMImplementation => 'XML::DOM',
+                                  image_uri         => $image_uri,
+                                  image_dir         => $image_dir,
+                             );
+                $parser->parse();
+                utf8::decode($html);
+                ($text,$header,$css,$js) = 
+                    &parse_htmlcontent($res,$subdir,$html);
+            } elsif ($res eq 'text/html') {
+                ($text,$header,$css,$js) = 
+                    &parse_htmlcontent($res,$subdir,undef,$dirpath.$filename);
+            } else {
+                $badfile = 1;
+            }
+        }
+    }
+    return ($res,$badfile,$text,$header,$css,$js,\%allfiles,\%codebase);
+}
+
+sub parse_htmlcontent {
+    my ($res,$subdir,$html,$fullpath) = @_;
+    my ($p,$fh);
+    if ($res eq 'application/rtf') {
+        $p = HTML::TokeParser->new( \$html );
+    } elsif ($res eq 'text/html') {
+        open($fh, "<:utf8", $fullpath);
+        $p = HTML::TokeParser->new( $fh );
+    }
+    my ($current_tag,$line,@text,$header,$css,$js,$have_header,$delayed);
+    while (my $token = $p->get_token) {
+        if (ref($token) eq 'ARRAY') {
+            if ($token->[0] eq 'S') {
+                if ($delayed ne '') {
+                    $line.= $delayed;
+                    $delayed = '';
+                }
+                $current_tag = $token->[1];
+                next if ($token->[1] eq 'html' || $token->[1] eq 'head' || $token->[1] eq 'body' || $token->[1] eq 'meta' || $token->[1] eq 'title');
+                if ($token->[1] eq 'p') {
+                    $line =~ s/^[\s\240]*(.*?)[\s\240]*$/$1/;
+                    if (!$have_header) {
+                        $header = $line;
+                        if ($header ne '') {
+                            $header =~ s/\s*[\n\r\f]+/\n/gs;
+                        }
+                        $have_header = 1;
+                    } else {
+                        push(@text,$line);
+                    }
+                    $line = '';
+                } elsif ($current_tag eq 'style') {
+                    $css .= $token->[4];
+                } elsif ($current_tag eq 'script') {
+                    $js .= $token->[4];
+                } else {
+                    my $contents = $token->[4];
+                    if ($subdir ne '') {
+                        if (($token->[1] eq 'img') && ($token->[2]->{'src'} ne '')) {
+                            $contents =~ s/(src=\s*["']?)/$1..\//i;
+                        }
+                    }
+                    if (($line eq '') && ($current_tag eq 'font')) {
+                        $delayed = &HTML::Entities::encode($contents,'<>&"');
+                    } else {
+                        $line .= &HTML::Entities::encode($contents,'<>&"');
+                    }
+                }
+            } elsif ($token->[0] eq 'T') {
+                if ($current_tag ne 'html' && $current_tag ne 'head' && $current_tag ne 'body' && $current_tag ne 'meta' && $current_tag ne 'title') {
+                    if ($current_tag eq 'style') { 
+                       $css .=  $token->[1];
+                    } elsif ($current_tag eq 'script') {
+                       $js .=  $token->[1];
+                    } else {
+                        if ($delayed ne '') {
+                            my ($id,$rest) = ($token->[1] =~ /^(\s*\(*[A-Za-z0-9]+\)*\.*\s+)(.+)$/s);
+                            if ($id ne '') {
+                                $line .= $id.$delayed.$rest;
+                            } else {
+                                $line .= $token->[1].$delayed;
+                            }
+                            $delayed = '';
+                        } else {
+                            $line .= $token->[1];
+                        }
+                    }
+                }
+            } elsif ($token->[0] eq 'E') {
+                next if ($token->[1] eq 'html' || $token->[1] eq 'head' || $token->[1] eq 'body' || $token->[1] eq 'meta' || $token->[1] eq 'title' || $token->[1] eq 'p');
+                if ($token->[1] eq 'style') {
+                    $css .= $token->[2];
+                } elsif ($token->[1] eq 'script') {
+                    $js .= $token->[2];
+                } else {
+                    $line .= &HTML::Entities::encode($token->[2],'<>&"');
+                }
+                $current_tag = '';
+            }
+        }
+    }
+    if ($line ne '') {
+        if ($line ne '') {
+            $line =~ s/\s*[\n\r\f]+/\n/gs;
+        }
+        $line =~ s/^[\s\240]*(.*?)[\s\240]*$/$1/;
+        push(@text,$line);
+    }
+    if ($res eq 'text/html') {
+        close($fh);
+    }
+    return (\@text,$header,$css,$js);
+}
+
+sub build_image_url {
+    my ($urlpath,$item) = @_;
+    $item =~ s/(<img[^>]+src=["']?\s*)(\.?\.?\/?)/$1$urlpath/gsi;
+    return $item; 
+}
+
+sub print_header {
+    my ($uname,$udom,$javascript,$loadentries,$title) = @_;
+    my $output = &Apache::loncommon::start_page($title,$javascript,
+                                             {'add_entries' => $loadentries});
+    if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
+        $output .= '<h3><span class="LC_error">'.&mt('Co-Author').': '.$uname.
+                   &mt(' at ').$udom.'</span></h3>';
+    }
+    return $output;
+}
+
+sub topic_bar {
+    my ($imgnum,$title) = @_;
+    my $output = '
+<div class="LC_topic_bar">
+    <img alt="'.&mt('Step [_1]',$imgnum).
+              ' "src="/res/adm/pages/bl_step'.$imgnum.'.gif" />&nbsp;'.$title.'
+</div>
+';
+    return $output;
+}
 
 # ---------------------------------------------------------------- Main Handler
 sub handler {
@@ -1773,9 +1788,8 @@
     my $page_name = '';
     my $current_page = '';
     my $qcount = '';
-#
-# phase two: re-attach user
-#
+    my $title = 'Upload testbank questions to Construction Space';
+
     if ($env{'form.uploaduname'}) {
         $env{'form.filename'}='/priv/'.$env{'form.uploaduname'}.'/'.
             $env{'form.filename'};
@@ -1784,15 +1798,12 @@
         &Apache::loncacc::constructaccess($env{'form.filename'},
                                           $r->dir_config('lonDefDomain'));
     unless (($uname) && ($udom)) {
-        $r->log_reason($uname.' at '.$udom.
-                       ' trying to publish file '.$env{'form.filename'}.
-                       ' - not authorized',
-                       $r->filename);
+        $r->log_reason($uname.':'.$udom.' trying to convert testbank file '.
+                       $env{'form.filename'}.' - not authorized',$r->filename);
         return HTTP_NOT_ACCEPTABLE;
     }
-                                                                             
-    my $fn;
-    my $badfile = 0;
+
+    my ($fn,$filename);
     if ($env{'form.filename'}) {
         $fn=$env{'form.filename'};
         $fn=~s/^http\:\/\/[^\/]+\///;
@@ -1804,78 +1815,87 @@
                        ' unspecified filename for upload', $r->filename);
         return HTTP_NOT_FOUND;
     }
-    my $pathname = &File::Basename::dirname($fn);
-    my $fullpath = '/priv/'.$uname.$pathname;
-    unless ($pathname eq '/') {
-        $fullpath .= '/';
-    }
 
-    my $dirpath = '/home/'.$uname.'/public_html';
-
-    my @text = ();
-    if ($env{'form.phase'} eq 'three') {    
-        if (-e "$dirpath$fn") {
-            open(TESTBANK,"<$dirpath$fn");
-            @text = <TESTBANK>;
-            close(TESTBANK);
-        } else {
-            $badfile = 1;  
-        }
-    }
-        
 # ----------------------------------------------------------- Start page output
     &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;
 
-    my %loadentries;
+    my ($filename,$pathname) = &File::Basename::fileparse($fn);
+    my $webpath = '/priv/'.$uname.$pathname;
+    my $urlpath = '/~'.$uname.$pathname;
+    my $dirpath = '/home/'.$uname.'/public_html'.$pathname;
+    my ($res,$subdir,$badfile,$textref,$header,$css,$js,%loadentries);
+
     if ($env{'form.phase'} eq 'three') {
         $current_page = &display_control();
-        my @PAGES = ('Welcome','Blocks','Format','Target','Confirmation');
-        $page_name = $PAGES[$current_page];
-
-        if ($page_name eq 'Blocks') {
-	    $loadentries{'onload'} = "setElements()";
+        my @pages = ('Welcome','Blocks','Format','Target','Confirmation');
+        $page_name = $pages[$current_page];
+        if ($env{'form.newdir'} ne '') {
+            if ($env{'form.newdir'} =~ /^\Q$dirpath\E(.+)$/) {
+                $subdir = $1;
+            }
+        }
+        ($res,$badfile,$textref,$header,$css,$js) = 
+            &parse_datafile($r,$uname,$filename,$pathname,$dirpath,$urlpath,
+                            $page_name,$subdir);
+        if ($page_name eq 'Welcome') {
+             &jscript_zero($webpath,\$javascript);
+        } elsif ($page_name eq 'Blocks') {
+            if ($env{'form.go'} eq "PreviousPage") {
+	        $loadentries{'onload'} = "setElements()";
+            }
             &jscript_one(\$javascript);
-        } elsif ($page_name eq 'Format') { 
-            $qcount = question_count($env{'form.qnumformat'},\@text);
+        } elsif ($page_name eq 'Format') {
+            if ($env{'form.go'} eq "PreviousPage") {
+                $loadentries{'onload'} = "setElements()";
+            }
+            $qcount = question_count($env{'form.qnumformat'},$textref);
  	    &jscript_two(\$javascript,$qcount);
-         } elsif ($page_name eq 'Target') {
+        } elsif ($page_name eq 'Target') {
              if ($env{'form.go'} eq "PreviousPage") {
                  $loadentries{'onload'} = "setElements()";
  	     }
-	     &jscript_three($fullpath,\$javascript);
+	     &jscript_three($webpath,\$javascript);
         } elsif ($page_name eq 'Confirmation') {
-	    &jscript_four(\$javascript,$fullpath);
+	     &jscript_four(\$javascript,$webpath);
+        }
+        $javascript = "<script type=\"text/javascript\">\n//<!--\n".
+	              $javascript."\n// --></script>\n";
+        if ($res eq 'application/rtf' || $res eq 'text/html') {
+            if ($page_name eq 'Target') {
+                $javascript .= $js.$css;
+            }
         }
     }
 
-    $javascript = "<script type=\"text/javascript\">\n//<!--\n".
-	$javascript."\n// --></script>\n";
-
-    $r->print(&Apache::loncommon::start_page('Upload testbank questions to Construction Space',
-					     $javascript,
-					     {'add_entries' => \%loadentries}));
-
-    if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
-        $r->print('<h3><font color=red>'.&mt('Co-Author').': '.$uname.
-                  &mt(' at ').$udom.'</font></h3>');
-    }
+    $r->print(&print_header($uname,$udom,$javascript,\%loadentries,$title));
 
     if ($env{'form.phase'} eq 'three') {
+        if ($env{'form.action'} eq 'upload_embedded') {
+            $r->print(&Apache::lonupload::phasethree($r,$fn,$uname,$udom,'testbank'));
+        }
         if ($badfile) {
             &file_error($r,$uname,$fn,$current_page);
         } else {        
-            &display_zero ($r,$uname,$fn,$current_page,$fullpath) if $page_name eq 'Welcome';
-            &display_one ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Blocks';
-            &display_two ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Format';
-            &display_three ($r,$uname,$fn,$current_page,\@text,$qcount) if $page_name eq 'Target';
-            &final_display ($r,$uname,$fn,$current_page,\@text) if $page_name eq 'Confirmation';
+            &display_zero ($r,$uname,$fn,$current_page,$webpath) if $page_name eq 'Welcome';
+            &display_one ($r,$uname,$fn,$current_page,$textref,$header) if $page_name eq 'Blocks';
+            &display_two ($r,$uname,$fn,$current_page,$textref,$header,$qcount) if $page_name eq 'Format';
+            &display_three ($r,$uname,$fn,$current_page,$textref,$res,$header,$urlpath,$qcount) if $page_name eq 'Target';
+            &final_display ($r,$uname,$fn,$current_page,$textref,$res,$header,$css,$js,$webpath,$dirpath,$subdir) if $page_name eq 'Confirmation';
         }
     } elsif ($env{'form.phase'} eq 'two') {
-        my $flag = &Apache::lonupload::phasetwo($r,$fn,$uname,$udom,'testbank');
+        my ($result,$flag) = &Apache::lonupload::phasetwo($r,$fn,$uname,$udom,'testbank');
+        $r->print($result);
         if ($flag eq 'ok') {
             my $current_page = 0;
-            &display_zero($r,$uname,$fn,$current_page,$fullpath);
+            my $js;
+            &jscript_zero($webpath,\$js);
+            $js = '<script type="text/javascript">'."\n$js\n".'</script>';
+            $r->print($js);
+            &display_zero($r,$uname,$fn,$current_page,$webpath);
+        } elsif ($flag eq 'embedded') {
+            $r->print($js.'<form name="testbankForm" method="post" action="/adm/testbank">'.
+                      &page_footer('',$uname,$fn).'</form>');
         }
     } else {
         &Apache::lonupload::phaseone($r,$fn,$uname,$udom,'testbank');
@@ -1883,6 +1903,7 @@
     $r->print(&Apache::loncommon::end_page());
     return OK;
 }
+
 1;
 __END__
 

--raeburn1213707620--