File:  [LON-CAPA] / loncom / imspackages / imsprocessor.pm
Revision 1.58: download - view: text, annotated - select for diffs
Wed May 2 19:34:58 2018 UTC (6 years ago) by raeburn
Branches: MAIN
CVS tags: version_2_12_X, HEAD
- Use three-argument open() to separate file mode from the filename.

    1: # The LearningOnline Network with CAPA
    2: # Processor for IMS Packages
    3: #
    4: # $Id: imsprocessor.pm,v 1.58 2018/05/02 19:34:58 raeburn Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: 
   29: package Apache::imsprocessor;
   30: 
   31: use Apache::lonnet;
   32: use Apache::loncommon;
   33: use Apache::loncleanup;
   34: use Apache::lonlocal;
   35: use HTTP::Request::Common;
   36: use LONCAPA::Configuration;
   37: use LONCAPA::LWPReq;
   38: use strict;
   39: 
   40: sub ims_config {
   41:     my ($areas,$cmsmap,$areaname) = @_;
   42:     @{$areas} = ("doc","extlink","announce","staff","board","quiz","survey","pool","users","question");
   43:     %{$$cmsmap{bb5}} = (
   44:                 announce => 'resource/x-bb-announcement',
   45:                 board => 'resource/x-bb-discussionboard',
   46:                 doc => 'resource/x-bb-document',
   47:                 extlink => 'resource/x-bb-externallink',
   48:                 pool => 'assessment/x-bb-pool',
   49:                 quiz => 'assessment/x-bb-quiz',
   50:                 staff => 'resource/x-bb-staffinfo',
   51:                 survey => 'assessment/x-bb-survey',
   52:                 users => 'course/x-bb-user',
   53:                 );
   54:     %{$$cmsmap{bb6}} = (
   55:                 announce => 'resource/x-bb-announcement',
   56:                 board => 'resource/x-bb-discussionboard',
   57:                 doc => 'resource/x-bb-document',
   58:                 extlink => 'resource/x-bb-externallink',
   59:                 pool => 'assessment/x-bb-qti-pool',
   60:                 quiz => 'assessment/x-bb-qti-test',
   61:                 staff => 'resource/x-bb-staffinfo',
   62:                 survey => 'assessment/x-bb-survey',
   63:                 users => 'course/x-bb-user',
   64:                 );
   65:     $$cmsmap{bb6}{conference} = 'resource/x-bb-conference';
   66:     %{$$cmsmap{angel5}} =  (
   67:                 board => 'BOARD',
   68:                 extlink => 'LINK',
   69:                 msg => 'MESSAGE',
   70:                 quiz => 'QUIZ',
   71:                 survey => 'FORM',
   72:                 );
   73:     @{$$cmsmap{angel5}{doc}} = ('FILE','PAGE');
   74:     %{$$cmsmap{webctce4}} = (
   75:                 quiz => 'webctquiz',
   76:                 survey => 'webctsurvey',
   77:                 doc => 'webcontent'
   78:                 );
   79:     %{$$cmsmap{webctvista4}} = (
   80:                 question => 'webct.question',
   81:                 quiz => 'webct.assessment',
   82:                 survey => 'webctsurvey',
   83:                 doc => 'webcontent'
   84:                 );
   85:     %{$areaname} = &Apache::lonlocal::texthash (
   86:                 announce => 'Announcements',
   87:                 board => 'Discussion Boards',
   88:                 doc => 'Documents, pages, and folders',
   89:                 extlink => 'Links to external sites',
   90:                 pool => 'Question pools',
   91:                 quiz => 'Quizzes',
   92:                 question => 'Assessment Questions',
   93:                 staff => 'Staff information',
   94:                 survey => 'Surveys',
   95:                 users => 'Enrollment',
   96:                 );
   97: }
   98:  
   99: sub create_tempdir {
  100:     my ($context,$pathinfo,$timenow) = @_;   
  101:     my $configvars = &LONCAPA::Configuration::read_conf('loncapa.conf');
  102:     my $tempdir;
  103:     $pathinfo = &Apache::loncommon::clean_path($pathinfo);
  104: # Collapse dots
  105:     $pathinfo =~ s/\.+/./g;
  106:     if ($context eq 'DOCS') {
  107:         $tempdir =  $$configvars{'lonDaemons'}.'/tmp/'.$pathinfo;
  108:         if (!-e "$tempdir") {
  109:             mkdir("$tempdir",0770);
  110:         } 
  111:         $tempdir .= '/'.$timenow;
  112:         if (!-e "$tempdir") {
  113:             mkdir("$tempdir",0770);
  114:         } 
  115:     } elsif ($context eq "CSTR") {
  116:         if (!-e "$pathinfo/temp") {
  117:             mkdir("$pathinfo/temp",0770);
  118:         }
  119:         $tempdir =  $pathinfo.'/temp';
  120:     }
  121:     return $tempdir;
  122: }
  123: 
  124: sub uploadzip {
  125:     my ($context,$tempdir,$source) = @_;
  126:     my $fname;
  127:     if ($context eq 'DOCS') {
  128:         $fname=$env{'form.uploadname.filename'};
  129: # Replace Windows backslashes by forward slashes
  130:         $fname=~s/\\/\//g;
  131: # Get rid of everything but the actual filename
  132:         $fname=~s/^.*\/([^\/]+)$/$1/;
  133: # Replace spaces by underscores
  134:         $fname=~s/\s+/\_/g;
  135: # Replace all other weird characters by nothing
  136:         $fname=~s/[^\w\.\-]//g;
  137: # Collapse dots
  138:         $fname=~s/\.+/./g;
  139: # See if there is anything left
  140:         unless ($fname) { return 'error: no uploaded file'; }
  141: # Save the file
  142:         chomp($env{'form.uploadname'});
  143:         open(my $fh,'>',"$tempdir/$fname");
  144:         print $fh $env{'form.uploadname'};
  145:         close($fh);
  146:     } elsif ($context eq 'CSTR') {
  147:         if ($source =~ m/\/([^\/]+)$/) {
  148:             $fname = $1;
  149:             my $destination = $tempdir.'/'.$fname;
  150:             rename($source,$destination);
  151:         }
  152:     }
  153:     return $fname;   
  154: }
  155: 
  156: sub expand_zip {
  157:     my ($tempdir,$filename) = @_;
  158:     my $zipfile = "$tempdir/$filename";
  159:     if (!-e "$zipfile") {
  160:         return 'no zip';
  161:     }
  162:     if ($filename =~ m|\.zip$|i) {
  163:         open(OUTPUT, "unzip -o $zipfile -d $tempdir  2> /dev/null |");
  164:         close(OUTPUT);
  165:     } else {
  166:         return 'nozip';
  167:     }
  168:     if ($filename =~ m|\.zip$|i) {
  169:         unlink($zipfile);
  170:     }
  171:     return 'ok';
  172: }
  173: 
  174: sub process_manifest {
  175:     my ($cms,$tempdir,$resources,$items,$hrefs,$resinfo,$phase,$includedres,$includeditems) = @_;
  176:     my %toc = (
  177:               bb6 => 'organization',
  178:               bb5 => 'tableofcontents',
  179:               angel5 => 'organization',
  180:               webctce4 => 'organization',
  181:               webctvista4 => 'organization'
  182:               );
  183:     my @seq = "Top";
  184:     %{$$items{'Top'}} = (
  185:                       contentscount => 0,
  186:                       resnum => 'toplevel',
  187:                       );
  188:     %{$$resources{'toplevel'}} = (
  189:                                   revitm => 'Top'
  190:                                  );
  191:  
  192:     if ($cms eq 'angel5') {
  193:         $$resources{'toplevel'}{type} = "FOLDER";
  194:     } elsif ($cms eq 'bb5' || $cms eq 'bb6') {
  195:         $$resources{'toplevel'}{type} = 'resource/x-bb-document';
  196:     } else {
  197:         $$resources{'toplevel'}{type} = 'webcontent';
  198:     }
  199: 
  200:     unless (-e "$tempdir/imsmanifest.xml") {
  201:         return 'nomanifest';
  202:     }
  203: 
  204:     my $xmlfile = $tempdir.'/imsmanifest.xml';
  205:     &parse_manifest($cms,$phase,$tempdir,$xmlfile,\%toc,$includedres,
  206:                     $includeditems,$items,$resources,$resinfo,$hrefs,\@seq);
  207:     return 'ok' ;
  208: }
  209: 
  210: sub parse_manifest {
  211:     my ($cms,$phase,$tempdir,$xmlfile,$toc,$includedres,$includeditems,$items,
  212:         $resources,$resinfo,$hrefs,$seq,$requirer) = @_;
  213:     my @state = ();
  214:     my $itm = '';
  215:     my %contents = ();
  216:     my $identifier = '';
  217:     my @allidentifiers = ();
  218:     my $lastitem;
  219:     my $neededby;
  220:     my $p = HTML::Parser->new
  221:     (
  222:        xml_mode => 1,
  223:        start_h =>
  224:            [sub {
  225:                 my ($tagname, $attr) = @_;
  226:                 push @state, $tagname;
  227:                 my $start = @state - 3;
  228:                 if ( ($state[0] eq "manifest") && ($state[1] eq "organizations") && ($state[2] eq $$toc{$cms}) ) {
  229:                     if ($state[-1] eq 'item') {
  230:                         $itm = $attr->{identifier};
  231:                         if ($$includeditems{$itm} || $phase ne 'build') {
  232:                             %{$$items{$itm}} = ();
  233:                             $$items{$itm}{contentscount} = 0;
  234:                             @{$$items{$itm}{contents}} = ();
  235:                             if ($cms eq 'bb5' || $cms eq 'bb6' || $cms eq 'webctce4' || $cms eq 'webctvista4') {
  236:                                 $$items{$itm}{resnum} = $attr->{identifierref};
  237:                                 if ($cms eq 'bb5') {
  238:                                     $$items{$itm}{title} = $attr->{title};
  239:                                 }
  240:                             } elsif ($cms eq 'angel5') {
  241:                                 if ($attr->{identifierref} =~ m/^res(.+)$/) {
  242:                                     $$items{$itm}{resnum} = $1;
  243:                                 }
  244:                             }
  245:                             unless (%{$$resources{$$items{$itm}{resnum}}}) {
  246:                                 %{$$resources{$$items{$itm}{resnum}}} = ();
  247:                             }
  248:                             $$resources{$$items{$itm}{resnum}}{revitm} = $itm;
  249:                             if ($start > @{$seq}) {
  250:                                 unless ($lastitem eq '') {
  251:                                     push @{$seq}, $lastitem;
  252:                                     unless ( defined($contents{$$seq[-1]}) ) {
  253:                                         @{$contents{$$seq[-1]}} = ();
  254:                                     }
  255:                                     push @{$contents{$$seq[-1]}},$itm;
  256:                                     $$items{$itm}{parentseq} = $$seq[-1];
  257:                                 }
  258:                             } elsif ($start < @{$seq}) {
  259:                                 my $diff = @{$seq} - $start;
  260:                                 while ($diff > 0) {
  261:                                     pop @{$seq};
  262:                                     $diff --;
  263:                                 }
  264:                                 if (@{$seq}) {
  265:                                     push @{$contents{$$seq[-1]}}, $itm;
  266:                                 }
  267:                             } else {
  268:                                 push @{$contents{$$seq[-1]}}, $itm;
  269:                             }
  270:                             my $path;
  271:                             if (@{$seq} > 1) {
  272:                                 $path = join(',',@{$seq});
  273:                             } elsif (@{$seq} > 0) {
  274:                                 $path = $$seq[0];
  275:                             }
  276:                             $$items{$itm}{filepath} = $path;
  277:                             if ($cms eq 'bb5' || $cms eq 'bb6') {
  278:                                 if ($$items{$itm}{filepath} eq 'Top') {
  279:                                     $$items{$itm}{resnum} = $itm;
  280:                                     $$resources{$$items{$itm}{resnum}}{type} = 'resource/x-bb-document';
  281:                                     $$resources{$$items{$itm}{resnum}}{revitm} = $itm;
  282:                                     $$resinfo{$$items{$itm}{resnum}}{'isfolder'} = 'true';
  283:                                 }
  284:                             }
  285:                             $$items{$$seq[-1]}{contentscount} ++;
  286:                             $$resources{$$items{$itm}{resnum}}{seqref} = $seq;
  287:                             $lastitem = $itm;
  288:                         }
  289:                     }
  290:                     if ($cms eq 'webctce4') {
  291:                         if (($state[-1] eq "webct:properties") && (@state > 4)) {
  292:                             $$items{$itm}{properties} = $attr->{identifierref};
  293:                         }
  294:                     }
  295:                 } elsif ("@state" eq "manifest resources resource" ) {
  296:                     $identifier = $attr->{identifier};
  297:                     push(@allidentifiers,$identifier);
  298:                     if ($$includedres{$identifier} || $phase ne 'build') { 
  299:                         if ($cms eq 'bb5' || $cms eq 'bb6') {
  300:                             $$resources{$identifier}{file} = $attr->{file};
  301:                             $$resources{$identifier}{type} = $attr->{type};
  302:                         } elsif ($cms eq 'webctce4') {
  303:                             $$resources{$identifier}{type} = $attr->{type};
  304:                             $$resources{$identifier}{file} = $attr->{href};
  305:                         } elsif ($cms eq 'webctvista4') {
  306:                             $$resources{$identifier}{type} = $attr->{type};
  307:                             $$resources{$identifier}{'webct:coType'} = $attr->{'webct:coType'};
  308:                         } elsif ($cms eq 'angel5') {
  309:                             $identifier = substr($identifier,3);
  310:                             if ($attr->{href} =~ m-^_assoc/$identifier/(.+)$-) {
  311:                                 $$resources{$identifier}{file} = $1;
  312:                             }
  313:                         }
  314:                         @{$$hrefs{$identifier}} = ();
  315:                     }
  316:                 } elsif ("@state" eq "manifest resources resource file") {
  317:                     if ($$includedres{$identifier} || $phase ne 'build') {
  318:                         if ($cms eq 'bb5' || $cms eq 'bb6' || 
  319:                             $cms eq 'webctce4' || $cms eq 'webctvista4') {
  320:                             if ($$resources{$identifier}{type} eq 
  321:                                 'webct.manifest') {
  322:                                 my $manifestfile = $tempdir.'/'.$attr->{href};
  323:                                 my $currseqref = [];
  324:                                 if ($itm) {
  325:                                     $currseqref =   
  326:                                     $$resources{$$items{$itm}{resnum}}{seqref};
  327:                                 }
  328:                                 &parse_manifest($cms,$phase,$tempdir,$manifestfile,
  329:                                                 $toc,$includedres,$includeditems,
  330:                                                 $items,$resources,$resinfo,
  331:                                                 $hrefs,$currseqref,$neededby);
  332:                             } else {
  333:                                 if ($cms eq 'webctvista4') {
  334:                                     if ($$resources{$identifier}{type} eq 'ims_qtiasiv1p2') {
  335:                                         $neededby = $identifier;
  336:                                     } elsif ($$resources{$identifier}{type} eq 'webcontent') {
  337:                                         $$resources{$identifier}{usedby} = $requirer;
  338:                                         push(@{$$hrefs{$identifier}},$attr->{href});
  339:                                     }
  340:                                     $$resources{$identifier}{file} = $attr->{href};
  341:                                 } else {
  342:                                     push(@{$$hrefs{$identifier}},$attr->{href});
  343:                                 }
  344:                             }
  345:                         } elsif ($cms eq 'angel5') {
  346:                             if ($attr->{href} =~ m/^_assoc\\$identifier\\(.+)$/) {
  347:                                 push @{$$hrefs{$identifier}},$1;
  348:                             } elsif ($attr->{href} =~ m/^Icons\\icon(\w+)\.gif/) {
  349:                                 $$resources{$identifier}{type} = $1;
  350:                             }
  351:                         }
  352:                     }
  353:                 } elsif ("@state" eq "manifest webct:ContentObject") {
  354:                     foreach my $ident (@allidentifiers) {
  355:                         if ($$resources{$ident}{type} eq 'ims_qtiasiv1p2') {
  356:                             $$resources{$ident}{type} = $attr->{'webct:coType'};
  357:                         }
  358:                     }
  359:                 }
  360:            }, "tagname, attr"],
  361:         text_h =>
  362:             [sub {
  363:                 my ($text) = @_;
  364:                 if ("@state" eq "manifest metadata lom general title langstring") {
  365:                     $$items{'Top'}{title} = $text;
  366:                 }
  367:                 if ($state[0] eq "manifest" && $state[1] eq "organizations" && $state[2] eq $$toc{$cms} && $state[-1] eq "title") {
  368:                     if ($$includeditems{$itm} || $phase ne 'build') {
  369:                         if ($cms eq 'angel5' || $cms eq 'bb6' || $cms eq 'webctvista4') {
  370:                             $$items{$itm}{title} = $text;
  371:                         }
  372:                         if ($cms eq 'webctce4') {
  373:                             $$items{$itm}{title} = $text;
  374:                             $$items{$itm}{title} =~ s/(<[^>]*>)//g;
  375:                         }
  376:                     }
  377:                 }
  378:                 if ("@state" eq "manifest webct:ContentObject webct:Name") {
  379:                     if ($cms eq 'webctvista4') {
  380:                         if ($text =~ /,/) {
  381:                             $$resources{$identifier}{title} = (split(/,/,$text))[-1];
  382:                         } else {
  383:                             $$resources{$identifier}{title} = $text;
  384:                         }
  385:                     }
  386:                 }
  387:               }, "dtext"],
  388:         end_h =>
  389:               [sub {
  390:                   my ($tagname) = @_;
  391:                   pop @state;
  392:                }, "tagname"],
  393:     );
  394:     $p->parse_file($xmlfile);
  395:     $p->eof;
  396:     foreach my $itm (keys(%contents)) {
  397:         @{$$items{$itm}{contents}} = @{$contents{$itm}};
  398:     }
  399: }
  400: 
  401: sub get_imports {
  402:     my ($includeditems,$items,$resources,$importareas,$itm) = @_;
  403:     if (exists($$items{$itm}{resnum})) {
  404:         if ($$importareas{$$resources{$$items{$itm}{resnum}}{type}}) {
  405:             unless (exists($$includeditems{$itm})) {
  406:                 $$includeditems{$itm} = 1;
  407:             }
  408:         }
  409:     }
  410:     if ($$items{$itm}{contentscount} > 0) {
  411:         foreach my $child (@{$$items{$itm}{contents}}) {
  412:             &get_imports($includeditems,$items,$resources,$importareas,$child);
  413:         }
  414:     }
  415: }
  416: 
  417: sub get_parents {
  418:     my ($includeditems,$items,$itm) = @_;
  419:     my @pathitems = ();
  420:     if ($$items{$itm}{filepath} =~ m/,/) {
  421:        @pathitems = split/,/,$$items{$itm}{filepath};
  422:     } else {
  423:        $pathitems[0] = $$items{$itm}{filepath};
  424:     }
  425:     foreach (@pathitems) {
  426:         $$includeditems{$_} = 1;
  427:     }
  428: }
  429: 
  430: sub target_resources {
  431:     my ($resources,$oktypes,$targets) = @_;
  432:     foreach my $key (sort(keys(%{$resources}))) {
  433:         if ( defined($$oktypes{$$resources{$key}{type}}) ) {
  434:             push(@{$targets},$key);
  435:         } elsif (defined($$resources{$key}{usedby})) {
  436:             if (defined($$oktypes{$$resources{$$resources{$key}{usedby}}{type}})) {
  437:                 push(@{$targets},$key);
  438:             }
  439:         }
  440:     }
  441:     return;
  442: }
  443: 
  444: sub copy_resources {
  445:     my ($context,$cms,$hrefs,$resources,$tempdir,$targets,$url,$crs,$cdom,$destdir,$timenow,$assessmentfiles,$total) = @_;
  446:     if ($context eq 'DOCS') {
  447:         foreach my $key (sort(keys(%{$hrefs}))) {
  448:             if (grep/^$key$/,@{$targets}) {
  449:                 %{$$url{$key}} = ();
  450:                 foreach my $file (@{$$hrefs{$key}}) {
  451:                     my $source = $tempdir.'/'.$key.'/'.$file;
  452:                     if ($cms eq 'webctce4' || $cms eq 'webctvista4') {
  453:                         $source = $tempdir.'/'.$file;
  454:                     }
  455:                     my $filename = '';
  456:                     my $fpath = $timenow.'/resfiles/'.$key.'/';
  457:                     if ($cms eq 'angel5') {
  458:                         if ($file eq 'pg'.$key.'.htm') {
  459:                             next;
  460:                         }
  461:                     }
  462:                     $file =~ s-\\-/-g;
  463:                     my $copyfile = $file;
  464:                     if ($cms eq 'webctce4' || $cms eq 'webctvista4') {
  465:                         if ($file =~ m-/my_files/(.+)$-) {
  466:                             $copyfile = $1;
  467:                         }
  468:                     }
  469:                     if ($cms eq 'webctvista4') {
  470:                         if ($file =~ m{/\QX-WEBCT-VISTA-V0\E/.+([^.]+)$}) {
  471:                             $copyfile = $1;
  472:                         }
  473:                         if ($$resources{$key}{usedby}) {
  474:                             if ($$resources{$$resources{$key}{usedby}}{image} =~ /^\Q$copyfile\E/) {
  475:                                 $copyfile = $$resources{$$resources{$key}{usedby}}{image};
  476:                             }
  477:                         }
  478:                     }
  479:                     unless ((($cms eq 'webctce4') && ($copyfile =~ m/questionDB\.xml$/ || $copyfile =~ m/quiz_QIZ_\d+\.xml$/ || $copyfile =~ m/properties_QIZ_\d+\.xml$/)) || (($cms eq 'webctvista4') && (grep/^$key$/,@{$assessmentfiles}) && $file =~ /\.xml$/))    {
  480:                         $copyfile = $fpath.$copyfile;
  481:                         my $fileresult;
  482:                         if (-e $source) {
  483:                             $fileresult = &Apache::lonnet::process_coursefile('copy',$crs,$cdom,$copyfile,$source);
  484:                         }
  485:                     }
  486:                 }
  487:             }
  488:         }
  489:     } elsif ($context eq 'CSTR') {
  490:         if (!-e "$destdir/resfiles") {
  491:             mkdir("$destdir/resfiles",0770);
  492:         }
  493:         foreach my $key (sort(keys(%{$hrefs}))) {
  494:             if (grep/^$key$/,@{$targets}) {
  495:                 foreach my $file (@{$$hrefs{$key}}) {
  496:                     $file =~ s-\\-/-g;
  497:                     if ( ($cms eq 'angel5' && $file ne 'pg'.$key.'.htm') || ($cms eq 'bb5') || ($cms eq 'bb6')) {
  498:                         if (!-e "$destdir/resfiles/$key") {
  499:                             mkdir("$destdir/resfiles/$key",0770);
  500:                         }
  501:                         my $filepath = $file;
  502:                         my $front = '';
  503:                         while ($filepath =~ m-(\w+)/(.+)-) {
  504:                             $front .= $1.'/';
  505:                             $filepath = $2;
  506:                             my $fulldir = "$destdir/resfiles/$key/$front";
  507:                             chop($fulldir);
  508:                             if (!-e "$fulldir") {
  509:                                 mkdir("$fulldir",0770);
  510:                             }
  511:                         }
  512:                         my $renameres;
  513:                         if ($cms eq 'angel5') {
  514:                             $renameres = rename("$tempdir/_assoc/$key/$file","$destdir/resfiles/$key/$file");
  515:                         } elsif ($cms eq 'bb5' || $cms eq 'bb6') {
  516:                             $renameres = rename("$tempdir/$key/$file","$destdir/resfiles/$key/$file");
  517:                         }
  518:                         if ($renameres) {
  519:                             if (ref($total) eq 'HASH') {
  520:                                 $$total{'file'} ++;
  521:                             }
  522:                         } else {
  523:                             &Apache::lonnet::logthis("IMS import error: $cms - renaming failed for file $file");
  524:                         }
  525:                     } elsif ($cms eq 'webctce4') {
  526:                         if ($file =~ m-/my_files/(.+)$-) {
  527:                             my $copyfile = $1;
  528:                             if ($copyfile =~ m-^[^/]+/[^/]+-) {
  529:                                 my @dirs = split/\//,$copyfile;
  530:                                 my $path = "$destdir/resfiles";
  531:                                 while (@dirs > 1) {
  532:                                     $path .= '/'.$dirs[0];
  533:                                     if (!-e "$path") {
  534:                                         mkdir("$path",0755);
  535:                                     }
  536:                                     shift @dirs;
  537:                                 }
  538:                             }
  539:                             if (-e "$tempdir/$file") {
  540:                                 my $renameres = rename("$tempdir/$file","$destdir/resfiles/$copyfile");
  541:                                 if ($renameres) {
  542:                                     if (ref($total) eq 'HASH') {
  543:                                         $$total{'file'} ++;
  544:                                     }
  545:                                 } else {
  546:                                     &Apache::lonnet::logthis("IMS import error: WebCT4 - renaming failed for file $file");
  547:                                 }
  548:                             }
  549:                         } elsif ($file !~ m-/data/(.+)$-) {
  550:                             &Apache::lonnet::logthis("IMS import error: WebCT4 - file $file is in unexpected location");
  551:                         }
  552:                     } elsif ($cms eq 'webctvista4') {
  553:                         if ($file =~ m{^\QX-WEBCT-VISTA-V0\E/(.+)$}) {
  554:                             my $copyfile = $1;
  555:                             if ($copyfile =~ m{^[^/]+/[^/]+}) {
  556:                                 my @dirs = split/\//,$copyfile;
  557:                                 my $path = "$destdir/resfiles";
  558:                                 while (@dirs > 1) {
  559:                                     $path .= '/'.$dirs[0];
  560:                                     if (!-e "$path") {
  561:                                         mkdir("$path",0755);
  562:                                     }
  563:                                     shift @dirs;
  564:                                 }
  565:                             } else {
  566:                                 $copyfile =~ s/^[^.]+\.(\d+)_R/$1/;
  567:                                 my ($filestem,$extension) = ($copyfile =~ /^(.+)\.(\w+)$/); 
  568:                                 if ($$resources{$key}{usedby}) {
  569:                                     if (ref($$resources{$$resources{$key}{usedby}}{image}) eq 'ARRAY') {
  570:                                         for (my $i=0; $i<@{$$resources{$$resources{$key}{usedby}}{image}}; $i++) {
  571:                                             my ($img,$imgtitle);
  572:                                             $img = $$resources{$$resources{$key}{usedby}}{image}[$i];
  573:                                             if (ref($$resources{$$resources{$key}{usedby}}{imagetitle}) eq 'ARRAY') {
  574:                                                 $imgtitle = $$resources{$$resources{$key}{usedby}}{imagetitle}[$i]; 
  575:                                             }
  576:                                             if ($imgtitle =~ /\Q$extension\E/i) {
  577:                                                 $copyfile = $imgtitle;
  578:                                                 last;
  579:                                             } elsif ($img =~ /^\Q$filestem\E/i) {
  580:                                                 $copyfile = $img.'.'.$extension;
  581:                                                 last;
  582:                                             }
  583:                                         }
  584:                                     }
  585:                                 }
  586:                             }
  587:                             if (-e "$tempdir/$file") {
  588:                                 my $renameres = rename("$tempdir/$file","$destdir/resfiles/$copyfile");
  589:                                 if ($renameres) {
  590:                                     if (ref($total) eq 'HASH') {
  591:                                         $$total{'file'} ++;
  592:                                     }
  593:                                 } else {
  594:                                     &Apache::lonnet::logthis("IMS import error: WebCTVista - renaming failed for file $file");
  595:                                 }
  596:                             }
  597:                         }
  598:                     }
  599:                 }
  600:             }
  601:         }
  602:     }
  603: }
  604: 
  605: sub process_resinfo {
  606:     my ($cms,$context,$docroot,$destdir,$items,$resources,$targets,$boards,$announcements,$quizzes,$surveys,$pools,$groups,$messages,$timestamp,$boardnum,$resinfo,$udom,$uname,$cdom,$crs,$db_handling,$user_handling,$total,$dirname,$seqstem,$resrcfiles,$packages,$hrefs,$pagesfiles,$sequencesfiles,$randompicks) = @_;
  607:     my $board_id = time;
  608:     my $board_count = 0;
  609:     my $dbparse = 0;
  610:     my $announce_handling = 'include';
  611:     my $longcrs = '';
  612:     my %allassessments = ();
  613:     my %allquestions = ();
  614:     my %qzdbsettings = ();
  615:     my %catinfo = ();
  616:     if ($crs =~ m/^(\d)(\d)(\d)/) {
  617:         $longcrs = $1.'/'.$2.'/'.$3.'/'.$crs;
  618:     }
  619:     if ($context eq 'CSTR') {
  620:         if (!-e "$destdir/resfiles") {
  621:             mkdir("$destdir/resfiles",0770);
  622:         }
  623:     }
  624:     if ($cms eq 'angel5') {
  625:         my $currboard = '';
  626:         foreach my $key (sort(keys(%{$resources}))) {
  627:           if (grep/^$key$/,@{$targets}) {
  628:             if ($$resources{$key}{type} eq "BOARD") {
  629:                 push @{$boards}, $key;
  630:                 $$boardnum{$$resources{$key}{revitm}} = $board_count;
  631:                 $currboard = $key;
  632:                 @{$$messages{$key}} = ();
  633:                 $$timestamp[$board_count] = $board_id;
  634:                 $board_id ++;
  635:                 $board_count ++;
  636:             } elsif ($$resources{$key}{type} eq "MESSAGE") {
  637:                 push @{$$messages{$currboard}}, $key;
  638:             } elsif ($$resources{$key}{type} eq "PAGE" || $$resources{$key}{type} eq "LINK") {
  639:                 %{$$resinfo{$key}} = ();
  640:                 &angel_content($key,$docroot,$destdir,\%{$$resinfo{$key}},$udom,$uname,$$resources{$key}{type},$$items{$$resources{$key}{revitm}}{title},$resrcfiles);
  641:             } elsif ($$resources{$key}{type} eq "QUIZ") {
  642:                 %{$$resinfo{$key}} = ();
  643:                 push @{$quizzes}, $key;
  644: #               &angel_assessment($key,$docroot,$dirname,$destdir,\%{$$resinfo{$key}},$resrcfiles);
  645:             } elsif ($$resources{$key}{type} eq "FORM") {
  646:                 %{$$resinfo{$key}} = ();
  647:                 push @{$surveys}, $key;
  648: #                &angel_assessment($key,$docroot,$dirname,$destdir,\%{$$resinfo{$key}},$resrcfiles);
  649:             } elsif ($$resources{$key}{type} eq "DROPBOX") {
  650:                 %{$$resinfo{$key}} = ();
  651:             }
  652:           }
  653:         }
  654:     } elsif ($cms eq 'bb5' || $cms eq 'bb6') {
  655:         foreach my $key (sort(keys(%{$resources}))) {
  656:           if (grep/^$key$/,@{$targets}) {
  657:             if ($$resources{$key}{type} eq "resource/x-bb-document") {
  658:                 unless ($$items{$$resources{$key}{revitm}}{filepath} eq 'Top') {
  659:                     %{$$resinfo{$key}} = ();
  660:                     &process_content($cms,$key,$context,$docroot,$destdir,\%{$$resinfo{$key}},$udom,$uname,$resrcfiles,$packages,$hrefs);
  661:                 }
  662:             } elsif ($$resources{$key}{type} eq "resource/x-bb-staffinfo") {
  663:                 %{$$resinfo{$key}} = ();
  664:                 &process_staff($key,$docroot,$destdir,\%{$$resinfo{$key}},$resrcfiles);
  665:             } elsif ($$resources{$key}{type} eq "resource/x-bb-externallink") {
  666:                 %{$$resinfo{$key}} = ();
  667:                 &process_link($key,$docroot,$destdir,\%{$$resinfo{$key}},$resrcfiles);
  668:             } elsif ($$resources{$key}{type} eq "resource/x-bb-discussionboard") {
  669:                 %{$$resinfo{$key}} = ();
  670:                 unless ($db_handling eq 'ignore') {
  671:                     push @{$boards}, $key;
  672:                     $$timestamp[$board_count] = $board_id;
  673:                     &process_db($key,$docroot,$destdir,$board_id,$crs,$cdom,$db_handling,$uname,\%{$$resinfo{$key}},$longcrs);
  674:                     $board_id ++;
  675:                     $board_count ++;
  676:                 }
  677:             } elsif ($$resources{$key}{type} =~/assessment\/x\-bb\-(qti\-)?pool/) {
  678:                 %{$$resinfo{$key}} = ();
  679:                 &process_assessment($cms,$context,$key,$docroot,'pool',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  680:                 push @{$pools}, $key;
  681:             } elsif ($$resources{$key}{type} =~ /assessment\/x\-bb\-(qti\-)?quiz/) {
  682:                 %{$$resinfo{$key}} = ();
  683:                 &process_assessment($cms,$context,$key,$docroot,'quiz',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  684:                 push @{$quizzes}, $key;
  685:             } elsif ($$resources{$key}{type} =~ /assessment\/x\-bb\-(qti\-)?survey/) {
  686:                 %{$$resinfo{$key}} = ();
  687:                 &process_assessment($cms,$context,$key,$docroot,'survey',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  688:                 push @{$surveys}, $key;
  689:             } elsif ($$resources{$key}{type} eq "assessment/x-bb-group") {
  690:                 %{$$resinfo{$key}} = ();
  691:                 push @{$groups}, $key;
  692:                 &process_group($key,$docroot,$destdir,\%{$$resinfo{$key}});
  693:             } elsif ($$resources{$key}{type} eq "resource/x-bb-user") {   
  694:                 %{$$resinfo{$key}} = ();
  695:                 unless ($user_handling eq 'ignore') {
  696:                     &process_user($key,$docroot,$destdir,\%{$$resinfo{$key}},$crs,$cdom,$user_handling);
  697:                 }
  698:             } elsif ($$resources{$key}{type} eq "resource/x-bb-announcement") {
  699:                 unless ($announce_handling eq 'ignore') {
  700:                     push @{$announcements}, $key;
  701:                     %{$$resinfo{$key}} = ();
  702:                     &process_announce($key,$docroot,$destdir,\%{$$resinfo{$key}},$resinfo,$seqstem,$resrcfiles);
  703:                 }
  704:             }
  705:           }
  706:         }
  707:         if (@{$announcements}) {
  708:             $$items{'Top'}{'contentscount'} ++;
  709:         }
  710:         if (@{$boards}) {
  711:             $$items{'Top'}{'contentscount'} ++;
  712:         }
  713:         if (@{$quizzes}) {
  714:             $$items{'Top'}{'contentscount'} ++;
  715:         }
  716:         if (@{$surveys}) {
  717:             $$items{'Top'}{'contentscount'} ++;
  718:         }
  719:         if (@{$pools}) {
  720:             $$items{'Top'}{'contentscount'} ++;
  721:         }
  722:     } elsif ($cms eq 'webctce4') {
  723:         foreach my $key (sort(keys(%{$resources}))) {
  724:             if (grep/^$key$/,@{$targets}) {
  725:                 if ($$resources{$key}{type} eq "webcontent") {
  726:                     %{$$resinfo{$key}} = ();
  727:                     if ($$resources{$key}{file} eq 'questiondb.xml') {
  728:                         &process_assessment($cms,$context,$key,$docroot,'quiz',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  729:                     } else {
  730:                         &webct4_content($key,$docroot,$destdir,\%{$$resinfo{$key}},$udom,$uname,$$resources{$key}{type},$$items{$$resources{$key}{revitm}}{title},$resrcfiles);
  731:                     }
  732:                 } elsif ($$resources{$key}{type} eq "webctquiz") {
  733:                     &process_assessment($cms,$context,$key,$docroot,'quiz',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  734:                 }
  735:             }
  736:         }
  737:     } elsif ($cms eq 'webctvista4') {
  738:         foreach my $key (sort(keys(%{$resources}))) {
  739:             if (grep/^$key$/,@{$targets}) {
  740:                 %{$$resinfo{$key}} = ();
  741:                 if ($$resources{$key}{type} eq 'webct.question') {
  742:                     $allquestions{$key} = 1;
  743:                 } elsif ($$resources{$key}{type} eq 'webct.assessment') {
  744:                     $allassessments{$key} = 1;
  745:                 }
  746:             }
  747:         }
  748:         if (keys(%allassessments) > 0) {
  749:             foreach my $key (sort(keys(%allassessments))) {
  750:                 &process_assessment($cms,$context,$key,$docroot,'quiz',$dirname,$destdir,\%{$$resinfo{$key}},$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,\$dbparse,$resources,$items,\%catinfo,\%qzdbsettings,$hrefs,\%allquestions);
  751:             }
  752:         } elsif (keys(%allquestions) > 0) {
  753:             my %catinfo = ();
  754:             my @allids = ();
  755:             my @allquestids = ();
  756:             my %allanswers = ();
  757:             my %allchoices = ();
  758:             my $containerdir;
  759:             my $newdir;
  760:             my $cid;
  761:             my $randompickflag = 0;
  762:             if ($context eq 'DOCS') {
  763:                 $cid = $env{'request.course.id'};
  764:             }
  765:             my $destresdir = $destdir;
  766:             my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
  767:             if ($context eq 'CSTR') {
  768:                 $destresdir =~ s{^\Q$londocroot/priv/\E}{/res/};
  769:             } elsif ($context eq 'DOCS') {
  770:                 $destresdir =~ s{^\Q$londocroot/userfiles\E}{/uploaded};
  771:             }
  772:             foreach my $res (sort(keys(%allquestions))) {
  773:                 my $parent = $allquestions{$res};
  774:                 &parse_webctvista4_question($res,$docroot,$resources,$hrefs,\%qzdbsettings,\@allquestids,\%allanswers,\%allchoices,$parent,\%catinfo);
  775:             }
  776:             &build_category_sequences($destdir,\%catinfo,$sequencesfiles,$pagesfiles,$destresdir,$newdir,$cms,$total,$randompickflag,$context,$udom,$uname,$dirname,$cid,$cdom,$crs,\%qzdbsettings);
  777:             &write_webct4_questions($cms,\@allquestids,$context,\%qzdbsettings,$dirname,\%allanswers,\%allchoices,$total,$cid,$cdom,$crs,$destdir,\%catinfo);
  778:         }
  779:     }
  780: 
  781:     $$total{'board'} = $board_count;
  782:     $$total{'quiz'} = @{$quizzes};
  783:     $$total{'surv'} = @{$surveys};
  784:     $$total{'pool'} = @{$pools};
  785: }
  786: 
  787: sub build_structure {
  788:     my ($cms,$context,$destdir,$items,$resinfo,$resources,$targets,$hrefs,$udom,$uname,$newdir,$timenow,$cdom,$crs,$timestamp,$total,$boards,$announcements,$quizzes,$surveys,$pools,$boardnum,$pagesfiles,$seqfiles,$topurls,$topnames,$packages,$includeditems,$randompicks) = @_;
  789:     my %flag = ();
  790:     my %count = ();
  791:     my %pagecontents = ();
  792:     my %seqtext = ();
  793:     my $topnum = 0;
  794:     my $topspecials = @$announcements + @$boards + @$quizzes + @$surveys + @$pools;
  795: 
  796:     if (!-e "$destdir") {
  797:         mkdir("$destdir",0755);
  798:     }
  799:     if (!-e "$destdir/sequences") {
  800:         mkdir("$destdir/sequences",0770);
  801:     }
  802:     if (!-e "$destdir/resfiles") {
  803:         mkdir("$destdir/resfiles",0770);
  804:     }
  805:     if (!-e "$destdir/pages") {
  806:         mkdir("$destdir/pages",0770);
  807:     }
  808:     if (!-e "$destdir/problems") {
  809:         mkdir("$destdir/problems",0770);
  810:     }
  811: 
  812:     $seqtext{'Top'} = qq|<map>\n|;       
  813:     %{$$resinfo{$$items{'Top'}{resnum}}} = (
  814:                                          isfolder => 'true',
  815:                                         );
  816: 
  817:     my $srcstem = "";
  818:  
  819:     if ($context eq 'DOCS') {
  820:         $srcstem = "/uploaded/$cdom/$crs/$timenow";
  821:     } elsif ($context eq 'CSTR') {
  822:         $srcstem = "/res/$udom/$uname/$newdir";
  823:     }
  824: 
  825:     foreach my $key (sort(keys(%{$items}))) {
  826:       if ($$includeditems{$key}) {
  827:         %{$flag{$key}} = (
  828:                           page => 0,
  829:                           seq => 0,
  830:                           board => 0,
  831:                           file => 0,
  832:                          );
  833: 
  834:         %{$count{$key}} = (
  835:                            page => -1,
  836:                            seq => 0,
  837:                            board => 0,
  838:                            file => 0,
  839:                           );
  840: 
  841:         my $src = "";
  842: 
  843:         my $next_id = 2;
  844:         my $curr_id = 1;
  845:         my $resnum = $$items{$key}{resnum};
  846:         my $type = $$resources{$resnum}{type};
  847:         my $contentscount = $$items{$key}{'contentscount'};
  848:         my $seqtitle = $$items{$key}{'title'};
  849:         $seqtitle =~ s|/+|_|g;
  850:         $seqtitle =~ s/\s+/_/g;
  851:         $seqtitle .= '_'.$key;
  852:         if (($cms eq 'angel5' && $type eq "FOLDER") || (($cms eq 'bb5' || $cms eq 'bb6') && $$resinfo{$resnum}{'isfolder'} eq "true") && (($type eq "resource/x-bb-document") || ($type eq "resource/x-bb-staffinfo") || ($type eq "resource/x-bb-externallink")) || ($cms eq 'webctce4' &&  $contentscount > 0)) {
  853:             unless (($cms eq 'bb5') && $key eq 'Top') {
  854:                 $seqtext{$key} = "<map>\n";
  855:             }
  856:             if ($contentscount == 0) {
  857: 	        if ($key eq 'Top') {
  858:                     unless ($topspecials) {
  859:                         $seqtext{$key} .= qq|<resource id="$curr_id" src="" type="start"></resource>
  860: <link from="$curr_id" to="$next_id" index="$curr_id"></link>
  861: <resource id="$next_id" src="" type="finish"></resource>\n|;
  862:                     }
  863:                 } else {
  864:                     $seqtext{$key} .= qq|<resource id="$curr_id" src="" type="start"></resource>
  865: <link from="$curr_id" to="$next_id" index="$curr_id"></link>
  866: <resource id="$next_id" src="" type="finish"></resource>\n|;
  867:                 }
  868:             } else {
  869:                 my $contcount = 0;
  870:                 if (defined($$items{$key}{contents})) { 
  871:                     $contcount = @{$$items{$key}{contents}};
  872:                 } else {
  873:                     &Apache::lonnet::logthis("IMS Import error for item: $key- contents count = $contentscount, but identity of contents not defined.");
  874:                 }
  875:                 my $contitem = $$items{$key}{contents}[0];
  876:                 my $contitemcount = $$items{$contitem}{contentscount}; 
  877:                 my ($res,$itm,$type,$file);
  878:                 if (exists($$items{$contitem}{resnum})) {
  879:                     $res = $$items{$contitem}{resnum};
  880:                     $itm = $$resources{$res}{revitm};
  881:                     $type = $$resources{$res}{type};
  882:                     $file = $$resources{$res}{file};
  883:                 }
  884:                 my $title = $$items{$contitem}{title};
  885:                 my $packageflag = 0;
  886:                 if (grep/^$res$/,@{$packages}) {
  887:                     $packageflag = 1;
  888:                 }
  889:                 $src = &make_structure($cms,$key,$srcstem,\%flag,\%count,$timestamp,$boardnum,$hrefs,\%pagecontents,$res,$type,$file,$resinfo,$contitem,$uname,$cdom,$contcount,$packageflag,$contitemcount,$$randompicks{$contitem},$title);
  890:                 unless ($flag{$key}{page} == 1) {
  891:                     if ($$randompicks{$contitem}) {
  892:                         $seqtext{$key} .= qq|
  893: <param to="$curr_id" type="int_pos" name="parameter_randompick" value="$$randompicks{$contitem}"></param>\n|;
  894:                     }
  895:                     $seqtext{$key} .= qq|<resource id="$curr_id" src="$src" title="$title" type="start"|;
  896:                     unless ($flag{$key}{seq} || $flag{$key}{board} || $flag{$key}{file}) {
  897:                         $flag{$key}{page} = 1;
  898:                     }
  899:                     if ($key eq 'Top') {
  900:                         push @{$topurls}, $src;
  901:                         push @{$topnames}, $title;
  902:                     }
  903:                 }
  904:                 if ($contcount == 1) {
  905:                     $seqtext{$key} .= qq|></resource>
  906: <link from="$curr_id" to="$next_id" index="$curr_id"></link>|;
  907:                     if ($key eq 'Top') {
  908:                         unless ($topspecials) {
  909:                             $seqtext{$key} .= qq|
  910: <resource id="$next_id" src="" type="finish"></resource>\n|;
  911:                         }
  912:                     } else {
  913:                         $seqtext{$key} .= qq|
  914: <resource id="$next_id" src="" type="finish"></resource>\n|;
  915:                     }
  916:                 } else {
  917:                     if ($contcount > 2 ) {
  918:                         for (my $i=1; $i<$contcount-1; $i++) {
  919:                             my $contitem = $$items{$key}{contents}[$i];
  920:                             my $contitemcount = $$items{$contitem}{contentscount};
  921:                             my $res = $$items{$contitem}{resnum};
  922:                             my $type = $$resources{$res}{type};
  923:                             my $file = $$resources{$res}{file};
  924:                             my $title = $$items{$contitem}{title};
  925:                             my $packageflag = 0;
  926:                             if (grep/^$res$/,@{$packages}) {
  927:                                 $packageflag = 1;
  928:                             }
  929:                             $src = &make_structure($cms,$key,$srcstem,\%flag,\%count,$timestamp,$boardnum,$hrefs,\%pagecontents,$res,$type,$file,$resinfo,$contitem,$uname,$cdom,$contcount,$packageflag,$contitemcount,$$randompicks{$contitem},$title);
  930:                             unless ($flag{$key}{page} == 1) {
  931:                                 $seqtext{$key} .= qq|></resource>
  932: <link from="$curr_id" to="$next_id" index="$curr_id"></link>\n|;
  933:                                 if ($$randompicks{$contitem}) {
  934:                                     $seqtext{$key} .= qq|
  935: <param to="$next_id" type="int_pos" name="parameter_randompick" value="$$randompicks{$contitem}"></param>|;
  936:                                 }
  937:                                 $seqtext{$key} .= qq|
  938: <resource id="$next_id" src="$src" title="$title"|;
  939:                                 $curr_id ++;
  940:                                 $next_id ++;
  941:                                 unless ($flag{$key}{seq} || $flag{$key}{board} || $flag{$key}{file}) {
  942:                                     $flag{$key}{page} = 1;
  943:                                 }
  944:                                 if ($key eq 'Top') {
  945:                                     push @{$topurls}, $src;
  946:                                     push @{$topnames}, $title;
  947:                                 }
  948:                             }
  949:                         }
  950:                     }
  951:                     my $contitem = $$items{$key}{contents}[-1];
  952:                     my $contitemcount = $$items{$contitem}{contentscount};
  953:                     my $res = $$items{$contitem}{resnum};
  954:                     my $type = $$resources{$res}{type};
  955:                     my $file = $$resources{$res}{file};
  956:                     my $title = $$items{$contitem}{title};
  957:                     my $packageflag = 0;
  958:                     if (grep/^$res$/,@{$packages}) {
  959:                         $packageflag = 1;
  960:                     }
  961:                     $src = &make_structure($cms,$key,$srcstem,\%flag,\%count,$timestamp,$boardnum,$hrefs,\%pagecontents,$res,$type,$file,$resinfo,$contitem,$uname,$cdom,$contcount,$packageflag,$contitemcount,$$randompicks{$contitem},$title);
  962: 
  963:                     if ($flag{$key}{page}) {
  964:                         if ($count{$key}{seq} + $count{$key}{page} + $count{$key}{board} + $count{$key}{file} +1 == 1) {
  965:                             $seqtext{$key} .= qq|></resource>
  966: <link from="$curr_id" index="$curr_id" to="$next_id">
  967: <resource id ="$next_id" src="" |;
  968:                         }
  969:                     } else {
  970:                         $seqtext{$key} .= qq|></resource>
  971: <link from="$curr_id" to="$next_id" index="$curr_id"></link>\n|;
  972:                         if ($$randompicks{$contitem}) {
  973:                             $seqtext{$key} .= qq|
  974: <param to="$next_id" type="int_pos" name="parameter_randompick" value="$$randompicks{$contitem}"></param>\n|;
  975:                         }
  976:                         $seqtext{$key} .= qq|
  977: <resource id="$next_id" src="$src" title="$title" |;
  978:                         if ($key eq 'Top') {
  979:                             push @{$topurls}, $src;
  980:                             push @{$topnames}, $title;
  981:                         }
  982:                     }
  983:                     if ($contcount == $$items{$key}{contentscount}) {
  984:                         $seqtext{$key} .= qq|type="finish"></resource>\n|;
  985:                     } else {
  986:                         $curr_id ++;
  987:                         $next_id ++;
  988:                         $seqtext{$key} .= qq|></resource>
  989: <link from="$curr_id" to="$next_id" index="$curr_id"></link>\n|;
  990:                     } 
  991:                 }
  992:             }
  993:             unless (($cms eq 'bb5') && $key eq 'Top') {
  994:                 $seqtext{$key} .= "</map>\n";
  995:                 if ($cms eq 'webctce4' && $key ne 'Top') {
  996:                     push @{$seqfiles}, "$seqtitle.sequence";
  997:                     open(LOCFILE,'>',"$destdir/sequences/$seqtitle.sequence");
  998:                 } else {
  999:                     push @{$seqfiles}, "$key.sequence";
 1000:                     open(LOCFILE,'>',"$destdir/sequences/$key.sequence");
 1001:                 }
 1002:                 print LOCFILE $seqtext{$key};
 1003:                 close(LOCFILE);
 1004:             }
 1005:             $count{$key}{page} ++;
 1006:             $$total{page} += $count{$key}{page};
 1007:         }
 1008:         $$total{seq} += $count{$key}{seq};
 1009:       }
 1010:     }
 1011:     $topnum += ($count{'Top'}{page} + $count{'Top'}{seq});
 1012: 
 1013:     if ($cms eq 'bb5' || $cms eq 'bb6') {
 1014:         if (@{$announcements} > 0) {
 1015:             &process_specials($context,'announcements',$announcements,\$topnum,$$items{'Top'}{contentscount},$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,\$seqtext{'Top'},$pagesfiles,$seqfiles,$topurls,$topnames);
 1016:         }
 1017:         if (@{$boards} > 0) {
 1018:             &process_specials($context,'boards',$boards,\$topnum,$$items{'Top'}{contentscount},$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,\$seqtext{'Top'},$pagesfiles,$seqfiles,$topurls,$topnames);
 1019:         }
 1020:         if (@{$quizzes} > 0) {
 1021:             &process_specials($context,'quizzes',$quizzes,\$topnum,$$items{'Top'}{contentscount},$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,\$seqtext{'Top'},$pagesfiles,$seqfiles,$topurls,$topnames);
 1022:         }
 1023:         if (@{$surveys} > 0)  {
 1024:             &process_specials($context,'surveys',$surveys,\$topnum,$$items{'Top'}{contentscount},$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,\$seqtext{'Top'},$pagesfiles,$seqfiles,$topurls,$topnames);
 1025:         }
 1026:         if (@{$pools} > 0)  {
 1027:             &process_specials($context,'pools',$pools,\$topnum,$$items{'Top'}{contentscount},$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,\$seqtext{'Top'},$pagesfiles,$seqfiles,$topurls,$topnames);
 1028:         }
 1029:         $seqtext{'Top'} .= "</map>\n";
 1030:         open(TOPFILE,'>',"$destdir/sequences/Top.sequence");
 1031:         print TOPFILE $seqtext{'Top'};
 1032:         close(TOPFILE);
 1033:         push @{$seqfiles}, 'Top.sequence';
 1034:     }
 1035: 
 1036:     my $filestem;
 1037:     if ($context eq 'DOCS') {
 1038:         $filestem = "/uploaded/$cdom/$crs/$timenow";
 1039:     } elsif ($context eq 'CSTR') {
 1040:         $filestem = "/res/$udom/$uname/$newdir";
 1041:     }
 1042: 
 1043:     foreach my $key (sort(keys(%pagecontents))) {
 1044:         for (my $i=0; $i<@{$pagecontents{$key}}; $i++) {
 1045:             my $filename = $destdir.'/pages/'.$key.'_'.$i.'.page';
 1046:             my $resource = "$filestem/resfiles/$$items{$pagecontents{$key}[$i][0]}{resnum}.html";
 1047:             my $res = $$items{$pagecontents{$key}[$i][0]}{resnum};
 1048:             my $resource = $filestem.'/resfiles/'.$res.'.html';
 1049:             if (grep/^$res$/,@{$packages}) {
 1050:                 $resource =  $filestem.'/resfiles/'.$res.'./index.html'; # should be entry_point
 1051:             }
 1052:             open(PAGEFILE,'>',$filename);
 1053:             print PAGEFILE qq|<map>
 1054: <resource src="$resource" id="1" type="start" title="$$items{$pagecontents{$key}[$i][0]}{title}"></resource>
 1055: <link to="2" index="1" from="1">\n|;
 1056:             if (@{$pagecontents{$key}[$i]} == 1) {
 1057:                 print PAGEFILE qq|<resource src="" id="2" type="finish"></resource>\n|;
 1058:             } elsif (@{$pagecontents{$key}[$i]} == 2)  {
 1059:                 my $res = $$items{$pagecontents{$key}[$i][1]}{resnum};
 1060:                 my $resource = $filestem.'/resfiles/'.$res.'.html';
 1061:                 if (grep/^$res$/,@{$packages}) {
 1062:                     $resource =  $filestem.'/resfiles/'.$res.'./index.html'; # should be entry_point
 1063:                 }
 1064:                 print PAGEFILE qq|<resource src="$resource" id="2" type="finish" title="$$items{$pagecontents{$key}[$i][1]}{title}"></resource>\n|;
 1065:             } else {
 1066:                 for (my $j=1; $j<@{$pagecontents{$key}[$i]}-1; $j++) {
 1067:                     my $curr_id = $j+1;
 1068:                     my $next_id = $j+2;
 1069:                     my $res = $$items{$pagecontents{$key}[$i][$j]}{resnum};
 1070:                     my $resource = $filestem.'/resfiles/'.$res.'.html';
 1071:                     if (grep/^$res$/,@{$packages}) {
 1072:                         $resource =  $filestem.'/resfiles/'.$res.'./index.html'; # entry_point
 1073:                     }
 1074:                     print PAGEFILE qq|<resource src="$resource" id="$curr_id" title="$$items{$pagecontents{$key}[$i][$j]}{title}"></resource>
 1075: <link to="$next_id" index="$curr_id" from="$curr_id">\n|;
 1076:                 }
 1077:                 my $final_id = @{$pagecontents{$key}[$i]};
 1078:                 my $res = $$items{$pagecontents{$key}[$i][-1]}{resnum};
 1079:                 my $resource = $filestem.'/resfiles/'.$res.'.html';
 1080:                 if (grep/^$res$/,@{$packages}) {
 1081:                     $resource =  $filestem.'/resfiles/'.$res.'./index.html'; # entry_point
 1082:                 }
 1083:                 print PAGEFILE qq|<resource src="$resource" id="$final_id" type="finish" title="$$items{$pagecontents{$key}[$i][-1]}{title}"></resource>\n|;
 1084:             }
 1085:             print PAGEFILE "</map>";
 1086:             close(PAGEFILE);
 1087:             push @{$pagesfiles}, $key.'_'.$i.'.page'; 
 1088:         }
 1089:     }
 1090: }
 1091: 
 1092: sub make_structure {
 1093:     my ($cms,$key,$srcstem,$flag,$count,$timestamp,$boardnum,$hrefs,$pagecontents,$res,$type,$file,$resinfo,$contitem,$uname,$cdom,$contcount,$packageflag,$contitemcount,$randompick,$title) = @_;
 1094:     my $src ='';
 1095:     if (($cms eq 'angel5' && $type eq 'FOLDER') || (($cms eq 'bb5' || $cms eq 'bb6') && (($$resinfo{$res}{'isfolder'} eq 'true') || $key eq 'Top')) || ($cms eq 'webctce4' && $contitemcount > 0)) {
 1096:         $src = $srcstem.'/sequences/'.$contitem.'.sequence';
 1097:         if ($cms eq 'webctce4') {
 1098:             $title =~ s|/+|_|g;
 1099:             $title =~ s/\s+/_/g;
 1100:             $title .= '_'.$contitem;
 1101:             $src = $srcstem.'/sequences/'.$title.'.sequence';
 1102:         }
 1103:         $$flag{$key}{page} = 0;
 1104:         $$flag{$key}{seq} = 1;
 1105:         $$count{$key}{seq} ++;
 1106:     } elsif ($cms eq 'webctce4' && $randompick) {
 1107:         $src = $srcstem.'/sequences/'.$res.'.sequence';
 1108:         $$flag{$key}{page} = 0;
 1109:         $$flag{$key}{seq} = 1;
 1110:         $$count{$key}{seq} ++;
 1111:     } elsif ($cms eq 'angel5' && $type eq 'BOARD') {
 1112:         $src = '/adm/'.$cdom.'/'.$uname.'/'.$$timestamp[$$boardnum{$res}].'/bulletinboard'; 
 1113:         $$flag{$key}{page} = 0;
 1114:         $$flag{$key}{board} = 1;
 1115:         $$count{$key}{board} ++;
 1116:     } elsif ($cms eq 'angel5' && $type eq "FILE") {
 1117:         foreach my $file (@{$$hrefs{$res}}) {
 1118:             unless ($file eq 'pg'.$res.'.htm') {
 1119:                 $src = $srcstem.'/resfiles/'.$res.'/'.$file;
 1120:             }
 1121:         }
 1122:         $$flag{$key}{page} = 0;
 1123:         $$flag{$key}{file} = 1;
 1124:     } elsif ($cms eq 'angel5' && (($type eq "PAGE") || ($type eq "LINK")) )  {
 1125:         if ($$flag{$key}{page}) {
 1126:             if ($$count{$key}{page} == -1) {
 1127:                 &Apache::lonnet::logthis("IMS Angel import error in array index for page: value = -1, resource is $key, type is $type.");
 1128:             } else { 
 1129:                 push @{$$pagecontents{$key}[$$count{$key}{page}]},$contitem;
 1130:             }
 1131:         } else {
 1132:             $$count{$key}{page} ++;
 1133:             $src = $srcstem.'/pages/'.$key.'_'.$$count{$key}{page}.'.page';
 1134:             @{$$pagecontents{$key}[$$count{$key}{page}]} = ("$contitem");
 1135:             $$flag{$key}{seq} = 0;
 1136:         }
 1137:     } elsif ($cms eq 'bb5' || $cms eq 'bb6') {
 1138:         if ($$flag{$key}{page}) {
 1139:             push @{$$pagecontents{$key}[$$count{$key}{page}]},$contitem;
 1140:         } else {
 1141:             if ($contcount == 1) {
 1142:                 if ($packageflag) {
 1143:                     $src = $srcstem.'/resfiles/'.$res.'/index.html'; # Needs to be entry point
 1144:                 } else {
 1145:                     $src = $srcstem.'/resfiles/'.$res.'.html';
 1146:                 }
 1147:             } else {
 1148:                 $$count{$key}{page} ++;
 1149:                 $src = $srcstem.'/pages/'.$key.'_'.$$count{$key}{page}.'.page';
 1150:                 @{$$pagecontents{$key}[$$count{$key}{page}]} = ("$contitem");
 1151:             }
 1152:             $$flag{$key}{seq} = 0;
 1153:         }
 1154:     } elsif ($cms eq 'webctce4') {
 1155:         if ($type eq 'webctquiz') {
 1156:             $src =  $srcstem.'/pages/'.$res.'.page';
 1157:             $$count{$key}{page} ++;
 1158:             $$flag{$key}{seq} = 0;
 1159:         } else {
 1160:             if (grep/^$file$/,@{$$hrefs{$res}}) {
 1161:                 my $filename;
 1162:                 if ($file =~ m-/([^/]+)$-) {
 1163:                     $filename = $1;
 1164:                 }
 1165:                 $src =  $srcstem.'/resfiles/'.$filename;
 1166:             } else {
 1167:                 foreach my $file (@{$$hrefs{$res}}) {
 1168:                     my $filename;
 1169:                     if ($file =~ m-/my_files/(.+)$-) {
 1170:                         $filename = $1;
 1171:                     } elsif ($file =~ m-/([^/]+)$-) { 
 1172:                         $filename = $1;
 1173:                     }
 1174:                     $src = $srcstem.'/resfiles/'.$filename;
 1175:                 }
 1176:             }
 1177:             $$flag{$key}{page} = 0;
 1178:             $$flag{$key}{file} = 1;
 1179:         }
 1180:     }
 1181:     return $src;
 1182: }
 1183: 
 1184: 
 1185: # ---------------------------------------------------------------- Process Blackboard specials - announcements, bulletin boards, quizzes and surveys
 1186: sub process_specials {
 1187:     my ($context,$type,$specials,$topnum,$contentscount,$destdir,$udom,$uname,$cdom,$crs,$timenow,$newdir,$timestamp,$resinfo,$seqtext,$pagesfiles,$seqfiles,$topurls,$topnames) = @_;
 1188:     my $src = '';
 1189:     my $specialsrc = '';
 1190:     my $nextnum = 0;
 1191:     my $seqstem = '';
 1192:     if ($context eq 'CSTR') {
 1193:         $seqstem = "/res/$udom/$uname/$newdir";
 1194:     } elsif ($context eq 'DOCS') {
 1195:         $seqstem = '/uploaded/'.$cdom.'/'.$crs.'/'.$timenow;
 1196:     }
 1197:     my %seqnames = (
 1198:                   boards => 'bulletinboards',
 1199:                   quizzes => 'quizzes',
 1200:                   surveys => 'surveys',
 1201:                   announcements => 'announcements',
 1202:                   pools => 'pools'
 1203:                   );
 1204:     my %seqtitles = (
 1205:                   boards => 'Course Discussion Boards',
 1206:                   quizzes => 'Course Quizzes',
 1207:                   surveys => 'Course Surveys',
 1208:                   announcements => 'Course Announcements',
 1209:                   pools => 'Course Question Pools'
 1210:                    );
 1211:     $$topnum ++;
 1212: 
 1213:     if ($type eq 'announcements') {
 1214:         $src = "$seqstem/pages/$seqnames{$type}.page";
 1215:     } else {
 1216:         $src = "$seqstem/sequences/$seqnames{$type}.sequence";
 1217:     }
 1218: 
 1219:     push @{$topurls}, $src;
 1220:     push @{$topnames}, $seqtitles{$type};
 1221: 
 1222:     $$seqtext .= qq|<resource id="$$topnum" src="$src" title="$seqtitles{$type}"|;
 1223:     $nextnum = $$topnum +1;
 1224:     if ($$topnum == 1) {
 1225:         $$seqtext .= qq| type="start"></resource>
 1226: <link from="$$topnum" to="$nextnum" index="$$topnum"></link>\n|;
 1227:         if ($$topnum == $contentscount) {
 1228:             $$seqtext .= qq|<resource id="$nextnum" src="" type="finish"></resource>\n|;
 1229:         }
 1230:     } else {
 1231:         if ($$topnum == $contentscount) {
 1232:             $$seqtext .= qq| type="finish"></resource>\n|;
 1233:         } else {
 1234:             $$seqtext .= qq|></resource>
 1235: <link from="$$topnum" to="$nextnum" index="$$topnum"></link>\n|;
 1236:         }
 1237:     }
 1238: 
 1239:     if ($type eq "announcements") {
 1240:         push @{$pagesfiles}, "$seqnames{$type}.page";
 1241:         open(ITEM,'>',"$destdir/pages/$seqnames{$type}.page");
 1242:     } else {
 1243:         push @{$seqfiles}, "$seqnames{$type}.sequence";
 1244:         open(ITEM,'>',"$destdir/sequences/$seqnames{$type}.sequence");
 1245:     }
 1246: 
 1247:     if ($type eq 'boards') {
 1248:         $specialsrc = "/adm/$udom/$uname/$$timestamp[0]/bulletinboard";
 1249:     } elsif ($type eq 'announcements') {
 1250:         $specialsrc = "$seqstem/resfiles/$$specials[0].html";
 1251:     } elsif ($type eq 'pools') {
 1252:         $specialsrc = "$seqstem/sequences/$$specials[0].sequence";
 1253:     } else {
 1254:         $specialsrc = "$seqstem/pages/$$specials[0].page";
 1255:     }
 1256:     print ITEM qq|<map>
 1257: <resource id="1" src="$specialsrc" title="$$resinfo{$$specials[0]}{title}" type="start"></resource>
 1258: <link from="1" to="2" index="1"></link>|;
 1259:     if (@{$specials} == 1) {
 1260:         print ITEM qq|
 1261: <resource id="2" src="" type="finish"></resource>\n|;
 1262:     } else {
 1263:         for (my $i=1; $i<@{$specials}; $i++) {
 1264:             my $curr = $i+1;
 1265:             my $next = $i+2;
 1266:             if ($type eq 'boards') {
 1267:                 $specialsrc = "/adm/$udom/$uname/$$timestamp[$i]/bulletinboard";
 1268:             } elsif ($type eq 'announcements') {
 1269:                 $specialsrc = "$seqstem/resfiles/$$specials[$i].html";
 1270:             } else {
 1271:                 $specialsrc = "$seqstem/pages/$$specials[$i].page";
 1272:             }
 1273:             print ITEM qq|<resource id="$curr" src="$specialsrc" title="$$resinfo{$$specials[$i]}{title}"|;
 1274:             if (@{$specials} == $i+1) {
 1275:                 print ITEM qq| type="finish"></resource>\n|;
 1276:             } else {
 1277:                 print ITEM qq|></resource>
 1278: <link from="$curr" to="$next" index="$next">\n|;
 1279:             }
 1280:         }
 1281:     }
 1282:     print ITEM qq|</map>|;
 1283:     close(ITEM);
 1284: }
 1285: 
 1286: # ---------------------------------------------------------------- Process Blackboard users
 1287: sub process_user {
 1288:   my ($res,$docroot,$destdir,$settings,$user_crs,$user_cdom,$user_handling) = @_;
 1289:   my $xmlfile = $docroot.'/'.$res.".dat";
 1290:   my $filecount = 0;
 1291:   my @state;
 1292:   my $userid = '';
 1293:   my $linknum = 0;
 1294: 
 1295:   my $p = HTML::Parser->new
 1296:     (
 1297:      xml_mode => 1,
 1298:      start_h =>
 1299:      [sub {
 1300:         my ($tagname, $attr) = @_;
 1301:         push @state, $tagname;
 1302:         if ("@state" eq "USERS USER") {
 1303:             $userid = $attr->{value};
 1304:             %{$$settings{$userid}} = ();
 1305:             @{$$settings{$userid}{links}} = ();
 1306:         } elsif ("@state" eq "USERS USER LOGINID") {  
 1307:             $$settings{$userid}{loginid} = $attr->{value};
 1308:         } elsif ("@state" eq "USERS USER PASSPHRASE") {  
 1309:             $$settings{$userid}{passphrase} = $attr->{value};
 1310:         } elsif ("@state" eq "USERS USER STUDENTID" ) {
 1311:             $$settings{$userid}{studentid} = $attr->{value};
 1312:         } elsif ("@state" eq "USERS USER NAMES FAMILY" ) {
 1313:             $$settings{$userid}{family} = $attr->{value};
 1314:         } elsif ("@state" eq "USERS USER NAMES GIVEN" ) {
 1315:             $$settings{$userid}{given} = $attr->{value};
 1316:         } elsif ("@state" eq "USERS USER ADDRESSES BUSINESS DATA EMAIL") {
 1317:             $$settings{$userid}{email} = $attr->{value};
 1318:         } elsif ("@state" eq "USERS USER USER_ROLE") {
 1319:             $$settings{$userid}{user_role} = $attr->{value};
 1320:         } elsif ("@state" eq "USERS USER FLAGS ISAVAILABLE") {
 1321:             $$settings{$userid}{isavailable} = $attr->{value};
 1322:         } elsif ("@state" eq "USERS USER PERSONALPAGE FILELIST IMAGE") {
 1323:             $$settings{$userid}{image} = $attr->{value};
 1324:         } elsif ( ($state[-2] eq "LINKLIST") && ($state[-1] eq "LINK") ) {
 1325:             %{$$settings{$userid}{links}[$linknum]} = ();
 1326:             $$settings{$userid}{links}[$linknum]{url} = $attr->{value};
 1327:             $linknum ++;
 1328:         }
 1329:      }, "tagname, attr"],
 1330:      text_h =>
 1331:      [sub {
 1332:         my ($text) = @_;
 1333:         if ("@state" eq "USERS USER PERSONALPAGE TITLE") {
 1334:             $$settings{$userid}{title} = $text;
 1335:         } elsif ("@state" eq "USERS USER PERSONALPAGE DESCRIPTION") {
 1336:             $$settings{$userid}{description} = $text;
 1337:         } elsif (($state[-2] eq "LINK") && ($state[-1] eq "TITLE")) {
 1338:             $$settings{$userid}{links}[$linknum]{title} = $text;
 1339:         } elsif (($state[-3] eq "LINK") && ($state[-2] eq  "DESCRIPTION") && ($state[-1] eq "TEXT")) {
 1340:             $$settings{$userid}{links}[$linknum]{text} = $text;
 1341:         }
 1342:       }, "dtext"],
 1343:      end_h =>
 1344:      [sub {
 1345:         my ($tagname) = @_;
 1346:         if ("@state" eq "USERS USER") {
 1347:             $linknum = 0;
 1348:         }
 1349:         pop @state;
 1350:      }, "tagname"],
 1351:     );
 1352:   $p->unbroken_text(1);
 1353:   $p->parse_file($xmlfile);
 1354:   $p->eof;
 1355:   
 1356:   my $configvars = &LONCAPA::Configuration::read_conf('loncapa.conf');
 1357:   my $xmlstem =  $$configvars{'lonDaemons'}."/tmp/".$user_cdom."_".$user_crs."_";
 1358: 
 1359:   foreach my $user_id (keys(%{$settings})) {
 1360:       if ($$settings{$user_id}{user_role} eq "s") {
 1361:            
 1362:       } elsif ($user_handling eq 'enrollall') {
 1363: 
 1364:       }
 1365:   }
 1366: }
 1367: 
 1368: # ---------------------------------------------------------------- Process Blackboard groups
 1369: sub process_group {  
 1370:   my ($res,$docroot,$destdir,$settings) = @_;
 1371:   my $xmlfile = $docroot.'/'.$res.".dat";
 1372:   my $filecount = 0;
 1373:   my @state;
 1374:   my $grp;
 1375: 
 1376:   my $p = HTML::Parser->new
 1377:     (
 1378:      xml_mode => 1,
 1379:      start_h =>
 1380:      [sub {
 1381:         my ($tagname, $attr) = @_;
 1382:         push @state, $tagname;
 1383:         if ("@state" eq "GROUPS GROUP") {
 1384:             $grp = $attr->{id};
 1385:         }        
 1386:         if ("@state" eq "GROUPS GROUP TITLE") {
 1387:             $$settings{$grp}{title} = $attr->{value};
 1388:         } elsif ("@state" eq "GROUPS GROUP FLAGS ISAVAILABLE") {  
 1389:             $$settings{$grp}{isavailable} = $attr->{value};
 1390:         } elsif ("@state" eq "GROUPS GROUP FLAGS HASCHATROOM") {  
 1391:             $$settings{$grp}{chat} = $attr->{value};
 1392:         } elsif ("@state" eq "GROUPS GROUP FLAGS HASDISCUSSIONBOARD") {
 1393:             $$settings{$grp}{discussion} = $attr->{value};
 1394:         } elsif ("@state" eq "GROUPS GROUP FLAGS HASTRANSFERAREA") {
 1395:             $$settings{$grp}{transfer} = $attr->{value};
 1396:         } elsif ("@state" eq "GROUPS GROUP FLAGS ISPUBLIC") {
 1397:             $$settings{$grp}{public} = $attr->{value};
 1398:         }
 1399:      }, "tagname, attr"],
 1400:      text_h =>
 1401:      [sub {
 1402:         my ($text) = @_;
 1403:         if ("@state" eq "GROUPS DESCRIPTION") {
 1404:           $$settings{$grp}{description} = $text;
 1405: #          print "Staff text is $text\n";
 1406:         }
 1407:       }, "dtext"],
 1408:      end_h =>
 1409:      [sub {
 1410:         my ($tagname) = @_;
 1411:         pop @state;
 1412:      }, "tagname"],
 1413:     );
 1414:   $p->unbroken_text(1);
 1415:   $p->parse_file($xmlfile);
 1416:   $p->eof;
 1417: }
 1418: 
 1419: # ---------------------------------------------------------------- Process Blackboard Staff
 1420: sub process_staff {
 1421:   my ($res,$docroot,$destdir,$settings,$resrcfiles) = @_;
 1422:   my $xmlfile = $docroot.'/'.$res.".dat";
 1423:   my $filecount = 0;
 1424:   my @state;
 1425:   %{$$settings{name}} = ();
 1426:   %{$$settings{office}} = ();
 1427: 
 1428:   my $p = HTML::Parser->new
 1429:     (
 1430:      xml_mode => 1,
 1431:      start_h =>
 1432:      [sub {
 1433:         my ($tagname, $attr) = @_;
 1434:         push @state, $tagname;
 1435:         if ("@state" eq "STAFFINFO TITLE") {
 1436:             $$settings{title} = $attr->{value};
 1437:         } elsif ("@state" eq "STAFFINFO BIOGRAPHY TEXTCOLOR") {
 1438:             $$settings{textcolor} = $attr->{value};
 1439:         } elsif ("@state" eq "STAFFINFO BIOGRAPHY FLAGS ISHTML") {
 1440:             $$settings{ishtml} = $attr->{value};
 1441:         } elsif ("@state" eq "STAFFINFO FLAGS ISAVAILABLE" ) {
 1442:             $$settings{isavailable} = $attr->{value};
 1443:         } elsif ("@state" eq "STAFFINFO FLAGS ISFOLDER" ) {
 1444:             $$settings{isfolder} = $attr->{value};
 1445:         } elsif ("@state" eq "STAFFINFO POSITION" ) {
 1446:             $$settings{position} = $attr->{value};
 1447:         } elsif ("@state" eq "STAFFINFO HOMEPAGE" ) {
 1448:             $$settings{homepage} = $attr->{value};
 1449:         } elsif ("@state" eq "STAFFINFO IMAGE") {
 1450:             $$settings{image} = $attr->{value};
 1451:         }
 1452:      }, "tagname, attr"],
 1453:      text_h =>
 1454:      [sub {
 1455:         my ($text) = @_;
 1456:         if ("@state" eq "STAFFINFO BIOGRAPHY TEXT") {
 1457:           $$settings{text} = $text;
 1458: #          print "Staff text is $text\n";
 1459:         } elsif ("@state" eq "STAFFINFO CONTACT PHONE") {
 1460:           $$settings{phone} = $text;
 1461:         } elsif ("@state" eq "STAFFINFO CONTACT EMAIL") {
 1462:           $$settings{email} = $text;
 1463:         } elsif ("@state" eq "STAFFINFO CONTACT NAME FORMALTITLE") {
 1464:           $$settings{name}{formaltitle} = $text;
 1465:         } elsif ("@state" eq "STAFFINFO CONTACT NAME FAMILY") {
 1466:           $$settings{name}{family} = $text;
 1467:         } elsif ("@state" eq "STAFFINFO CONTACT NAME GIVEN") {
 1468:           $$settings{name}{given} = $text;
 1469:         } elsif ("@state" eq "STAFFINFO CONTACT OFFICE HOURS") {
 1470:           $$settings{office}{hours} = $text;
 1471:         }  elsif ("@state" eq "STAFFINFO CONTACT OFFICE ADDRESS") {
 1472:           $$settings{office}{address} = $text;
 1473:         }        
 1474:       }, "dtext"],
 1475:      end_h =>
 1476:      [sub {
 1477:         my ($tagname) = @_;
 1478:         pop @state;
 1479:      }, "tagname"],
 1480:     );
 1481:   $p->unbroken_text(1);
 1482:   $p->parse_file($xmlfile);
 1483:   $p->eof;
 1484: 
 1485:     my $fontcol = '';
 1486:     if (defined($$settings{textcolor})) {
 1487:         $fontcol =  qq|color="$$settings{textcolor}"|;
 1488:     }
 1489:     if (defined($$settings{text})) {
 1490:         if ($$settings{ishtml} eq "true") {
 1491:             $$settings{text} = &HTML::Entities::decode($$settings{text});
 1492:         }
 1493:     }
 1494:     my $staffentry = qq|
 1495: <table border="0" cellpadding="0" cellspacing="0" width="100%">
 1496:   <tr>
 1497:     <td colspan="2"><hr /><font face="arial,helv" size="3"><b>$$settings{name}{formaltitle} $$settings{name}{given} $$settings{name}{family}</b></font>
 1498:     </td>
 1499:   </tr>
 1500:   <tr>
 1501:     <td valign="top">
 1502:       <table width="100% border="0" cols="2" cellpadding="0" cellspacing="0">|;
 1503:     if ( defined($$settings{email}) && $$settings{email} ne '') {
 1504:         $staffentry .= qq|
 1505:         <tr>
 1506:           <td width="100" valign="top">
 1507:            <font face="arial" size="2"><b>Email:</b></font>
 1508:           </td>
 1509:           <td>
 1510:            <font face="arial" size="2"><a href="mailto:$$settings{email}">$$settings{email}</a></font>
 1511:           </td>
 1512:         </tr>
 1513:         |;
 1514:     }
 1515:     if (defined($$settings{phone}) && $$settings{phone} ne '') {
 1516:         $staffentry .= qq|
 1517:         <tr>
 1518:           <td width="100" valign="top">
 1519:             <font face="arial" size="2"><b>Phone:</b></font>
 1520:           </td>
 1521:           <td>
 1522:             <font face="arial" size="2">$$settings{phone}</font>
 1523:           </td>
 1524:         </tr>
 1525:         |;
 1526:     }
 1527:     if (defined($$settings{office}{address}) && $$settings{office}{address} ne '') {
 1528:         $staffentry .= qq|
 1529:         <tr>
 1530:          <td width="100" valign="top">
 1531:            <font face="arial" size="2"><b>Address:</b></font>
 1532:          </td>
 1533:          <td>
 1534:            <font face="arial" size="2">$$settings{office}{address}</font>
 1535:          </td>
 1536:         </tr>
 1537:         |;
 1538:     }
 1539:     if (defined($$settings{office}{hours}) && $$settings{office}{hours} ne '') {
 1540:         $staffentry .= qq|
 1541:         <tr>
 1542:           <td width="100" valign="top">
 1543:             <font face="arial" size="2"><b>Office Hours:</b></font>
 1544:           </td>
 1545:           <td>
 1546:             <font face="arial" size="2">$$settings{office}{hours}</font>
 1547:           </td>
 1548:         </tr>
 1549:         |;
 1550:     }
 1551:     if ( defined($$settings{homepage}) && $$settings{homepage} ne '') {
 1552:         $staffentry .= qq|
 1553:         <tr>
 1554:           <td width="100" valign="top">
 1555:             <font face="arial" size="2"><b>Personal Link:</b></font>
 1556:           </td>
 1557:           <td>
 1558:             <font face="arial" size="2"><a href="$$settings{homepage}">$$settings{homepage}</a></font>
 1559:           </td>
 1560:         </tr>
 1561:         |;
 1562:     }
 1563:     if (defined($$settings{text}) && $$settings{text} ne '') {
 1564:         $staffentry .= qq|
 1565:         <tr>
 1566:           <td colspan="2">
 1567:             <font face="arial" size="2" $fontcol><b>Other Information:</b><br/>$$settings{text}</font>
 1568:           </td>
 1569:         </tr>
 1570:         |;
 1571:      }
 1572:      $staffentry .= qq|
 1573:       </table>
 1574:     </td>
 1575:     <td align="right" valign="top">
 1576:      |;
 1577:      if ( defined($$settings{image}) ) {
 1578:          $staffentry .= qq|
 1579:       <img src="$res/$$settings{image}">
 1580:          |;
 1581:      }
 1582:      $staffentry .= qq|
 1583:     </td>
 1584:   </tr>
 1585: </table>
 1586:     |;
 1587:     open(FILE,'>',"$destdir/resfiles/$res.html");
 1588:     push @{$resrcfiles}, "$res.html";
 1589:     print FILE qq|<html>
 1590: <head>
 1591: <title>$$settings{title}</title>
 1592: </head>
 1593: <body bgcolor='#ffffff'>
 1594: $staffentry
 1595: </body>
 1596: </html>|;
 1597:     close(FILE);
 1598: }
 1599: 
 1600: # ---------------------------------------------------------------- Process Blackboard Links
 1601: sub process_link {
 1602:     my ($res,$docroot,$destdir,$settings,$resrcfiles) = @_;
 1603:     my $xmlfile = $docroot.'/'.$res.".dat";
 1604:     my @state = ();
 1605:     my $p = HTML::Parser->new
 1606:     (
 1607:         xml_mode => 1,
 1608:         start_h =>
 1609:         [sub {
 1610:             my ($tagname, $attr) = @_;
 1611:             push @state, $tagname;
 1612:             if ("@state" eq "EXTERNALLINK TITLE") {
 1613:                 $$settings{title} = $attr->{value};
 1614:             } elsif ("@state" eq "EXTERNALLINK TEXTCOLOR") {  
 1615:                 $$settings{textcolor} = $attr->{value};
 1616:             } elsif ("@state" eq "EXTERNALLINK DESCRIPTION FLAGS ISHTML") {  
 1617:                 $$settings{ishtml} = $attr->{value};
 1618:             } elsif ("@state" eq "EXTERNALLINK FLAGS ISAVAILABLE" ) {
 1619:                 $$settings{isavailable} = $attr->{value};
 1620:             } elsif ("@state" eq "EXTERNALLINK FLAGS LAUNCHINNEWWINDOW" ) {
 1621:                 $$settings{newwindow} = $attr->{value};
 1622:             } elsif ("@state" eq "EXTERNALLINK FLAGS ISFOLDER" ) {
 1623:                 $$settings{isfolder} = $attr->{value};
 1624:             } elsif ("@state" eq "EXTERNALLINK POSITION" ) {
 1625:                 $$settings{position} = $attr->{value};
 1626:             } elsif ("@state" eq "EXTERNALLINK URL" ) {
 1627:                 $$settings{url} = $attr->{value};
 1628:             }
 1629:         }, "tagname, attr"],
 1630:         text_h =>
 1631:         [sub {
 1632:             my ($text) = @_;
 1633:             if ("@state" eq "EXTERNALLINK DESCRIPTION TEXT") {
 1634:                $$settings{text} = $text;
 1635:             }
 1636:         }, "dtext"],
 1637:         end_h =>
 1638:         [sub {
 1639:             my ($tagname) = @_;
 1640:             pop @state;
 1641:         }, "tagname"],
 1642:     );
 1643:     $p->unbroken_text(1);
 1644:     $p->parse_file($xmlfile);
 1645:     $p->eof;
 1646: 
 1647:     my $linktag = '';
 1648:     my $fontcol = '';
 1649:     if (defined($$settings{textcolor})) {
 1650:         $fontcol =  qq|<font color="$$settings{textcolor}">|;
 1651:     }
 1652:     if (defined($$settings{text})) {
 1653:         if ($$settings{ishtml} eq "true") {
 1654:             $$settings{text} = &HTML::Entities::decode($$settings{text});
 1655:         }
 1656:     }
 1657: 
 1658:     if (defined($$settings{url}) ) {
 1659:         $linktag = qq|<a href="$$settings{url}"|;
 1660:         if ($$settings{newwindow} eq "true") {
 1661:             $linktag .= qq| target="launch"|;
 1662:         }
 1663:         $linktag .= qq|>$$settings{title}</a>|;
 1664:     }
 1665: 
 1666:     open(FILE,'>',"$destdir/resfiles/$res.html");
 1667:     push @{$resrcfiles}, "$res.html";
 1668:     print FILE qq|<html>
 1669: <head>
 1670: <title>$$settings{title}</title>
 1671: </head>
 1672: <body bgcolor='#ffffff'>
 1673: $fontcol
 1674: $linktag
 1675: $$settings{text}
 1676: |;
 1677:     if (defined($$settings{textcolor})) {
 1678:         print FILE qq|</font>|;
 1679:     }
 1680:     print FILE qq|
 1681:   </body>
 1682:  </html>|;
 1683:     close(FILE);
 1684: }
 1685: 
 1686: # ---------------------------------------------------------------- Process Blackboard Discussion Boards
 1687: sub process_db {
 1688:     my ($res,$docroot,$destdir,$timestamp,$crs,$cdom,$handling,$uname,$settings,$longcrs) = @_;
 1689:     my $xmlfile = $docroot.'/'.$res.".dat";
 1690:     my @state = ();
 1691:     my @allmsgs = ();
 1692:     my %msgidx = ();
 1693:     my %threads; # all threads, keyed by message ID
 1694:     my $msg_id; # the current message ID
 1695:     my %message; # the current message being accumulated for $msg_id
 1696: 
 1697:     my $p = HTML::Parser->new
 1698:     (
 1699:        xml_mode => 1,
 1700:        start_h =>
 1701:        [sub {
 1702:            my ($tagname, $attr) = @_;
 1703:            push @state, $tagname;
 1704:            my $depth = 0;
 1705:            my @seq = ();
 1706:            if ("@state" eq "FORUM TITLE") {
 1707:                $$settings{title} = $attr->{value};
 1708:            } elsif ("@state" eq "FORUM DESCRIPTION TEXTCOLOR") {  
 1709:                $$settings{textcolor} = $attr->{value};
 1710:            } elsif ("@state" eq "FORUM DESCRIPTION FLAGS ISHTML") {  
 1711:                $$settings{ishtml} = $attr->{value};
 1712:            } elsif ("@state" eq "FORUM DESCRIPTION FLAGS ISNEWLINELITERAL") {  
 1713:                $$settings{newline} = $attr->{value};
 1714:            } elsif ("@state" eq "FORUM POSITION" ) {
 1715:                $$settings{position} = $attr->{value};
 1716:            } elsif ("@state" eq "FORUM FLAGS ISREADONLY") {
 1717:                $$settings{isreadonly} = $attr->{value};
 1718:            } elsif ("@state" eq "FORUM FLAGS ISAVAILABLE" ) {
 1719:                $$settings{isavailable} = $attr->{value};
 1720:            } elsif ("@state" eq "FORUM FLAGS ALLOWANONYMOUSPOSTINGS" ) {
 1721:                $$settings{allowanon} = $attr->{value};
 1722:            } elsif ( ($state[0] eq "FORUM") && ($state[1] eq "MESSAGETHREADS") && ($state[2] eq "MSG") ) {
 1723:                if ($state[-1] eq "MSG") {
 1724:                    unless ($msg_id eq '') {
 1725:                        push @{$threads{$msg_id}}, { %message };
 1726:                        $depth = @state - 3;
 1727:                        if ($depth > @seq) {
 1728:                            push @seq, $msg_id; 
 1729:                        }
 1730:                    }
 1731:                    if ($depth < @seq) {
 1732:                        pop @seq;
 1733:                    }                
 1734:                    $msg_id = $attr->{id};
 1735:                    push @allmsgs, $msg_id;
 1736:                    $msgidx{$msg_id} = @allmsgs;
 1737:                    %message = ();
 1738:                    $message{depth} = $depth;
 1739:                    if ($depth > 0) {
 1740:                        $message{parent} = $seq[-1];
 1741:                    } else {
 1742:                        $message{parent} = "None";
 1743:                    }
 1744:                } elsif ($state[-1] eq "TITLE") {
 1745:                    $message{title} = $attr->{value};
 1746:                } elsif ( ( $state[-3] eq "MESSAGETEXT" ) && ( $state[-2] eq "FLAGS" ) && ( $state[-1] eq "ISHTML" ) ) {
 1747:                    $message{ishtml} = $attr->{value};
 1748:                } elsif ( ( $state[-3] eq "MESSAGETEXT" ) && ( $state[-2] eq "FLAGS" ) && ( $state[-1] eq "ISNEWLINELITERAL" ) ) {
 1749:                    $message{newline} = $attr->{value};
 1750:                } elsif ( ( $state[-2] eq "DATES" ) && ( $state[-1] eq "CREATED" ) ) {
 1751:                    $message{created} = $attr->{value};
 1752:                } elsif ( $state[@state-2] eq "FLAGS") {
 1753:                    if ($state[@state-1] eq "ISANONYMOUS") {
 1754:                        $message{isanonymous} =  $attr->{value};
 1755:                    }
 1756:                } elsif ( $state[-2] eq "USER" ) {
 1757:                    if ($state[-1] eq "USERID") {
 1758:                        $message{userid} =  $attr->{value};
 1759:                    } elsif ($state[@state-1] eq "USERNAME") {
 1760:                        $message{username} =  $attr->{value};
 1761:                    } elsif ($state[@state-1] eq "EMAIL") {
 1762:                        $message{email} =  $attr->{value};
 1763:                    }          
 1764:                } elsif ( ($state[-2] eq "FILELIST") && ($state[-1] eq "IMAGE") ) {
 1765:                    $message{attachment} = $attr->{value};
 1766:                }
 1767:            }
 1768:        }, "tagname, attr"],
 1769:        text_h =>
 1770:        [sub {
 1771:            my ($text) = @_;
 1772:            if ("@state" eq "FORUM DESCRIPTION TEXT") {
 1773:                $$settings{text} = $text;
 1774:            } elsif ( ($state[0] eq "FORUM") && ($state[1] eq "MESSAGETHREADS") && ($state[2] eq "MSG") ) {
 1775:                if ( ($state[-2] eq "MESSAGETEXT") && ($state[-1] eq "TEXT") ){
 1776:                    $message{text} = $text;
 1777:                }
 1778:            }
 1779:        }, "dtext"],
 1780:        end_h =>
 1781:        [sub {
 1782:            my ($tagname) = @_;
 1783:            if ( $state[-1] eq "MESSAGETHREADS" ) {
 1784:                push @{$threads{$msg_id}}, { %message };
 1785:            }
 1786:            pop @state;
 1787:        }, "tagname"],
 1788:     );
 1789:     $p->unbroken_text(1);
 1790:     $p->parse_file($xmlfile);
 1791:     $p->eof;
 1792: 
 1793:     if (defined($$settings{text})) {
 1794:         if ($$settings{ishtml} eq "false") {
 1795:             if ($$settings{isnewline} eq "true") {
 1796:                 $$settings{text} =~ s#\n#<br/>#g;
 1797:             }
 1798:         } else {
 1799:             $$settings{text} = &HTML::Entities::decode($$settings{text});
 1800:         }
 1801:         if (defined($$settings{fontcolor}) ) {
 1802:             $$settings{text} = "<font color=\"".$$settings{textcolor}."\">".$$settings{text}."</font>";
 1803:         }
 1804:     }
 1805:     my $boardname = 'bulletinpage_'.$timestamp;
 1806:     my %boardinfo = (
 1807:                   'aaa_title' => $$settings{title},
 1808:                   'bbb_content' => $$settings{text},
 1809:                   'ccc_webreferences' => '',
 1810:                   'uploaded.lastmodified' => time,
 1811:                   );
 1812:   
 1813:     my $putresult = &Apache::lonnet::put($boardname,\%boardinfo,$cdom,$crs);
 1814:     if ($handling eq 'importall') {
 1815:         foreach my $msg_id (@allmsgs) {
 1816:             foreach my $message ( @{$threads{$msg_id}} ) {
 1817:                 my %contrib = (
 1818:                             'sendername' => $$message{userid},
 1819:                             'senderdomain' => $cdom,
 1820:                             'screenname' => '',
 1821:                             'plainname' => $$message{username},
 1822:                             );
 1823:                 unless ($$message{parent} eq 'None') {
 1824:                     $contrib{replyto} = $msgidx{$$message{parent}};
 1825:                 }
 1826:                 if (defined($$message{isanonymous}) ) {
 1827:                     if ($$message{isanonymous} eq 'true') {
 1828:                         $contrib{'anonymous'} = 'true';
 1829:                     }
 1830:                 }
 1831:                 if ( defined($$message{attachment}) )  {
 1832:                     my $url = $$message{attachment};
 1833:                     my $oldurl = $url;
 1834:                     my $newurl = $url;
 1835:                     unless ($url eq '') {
 1836:                         $newurl =~ s/\//_/g;
 1837:                         unless ($longcrs eq '') {
 1838:                             if (!-e "/home/httpd/lonUsers/$cdom/$longcrs/userfiles") {
 1839:                                 mkdir("/home/httpd/lonUsers/$cdom/$longcrs/userfiles",0755);
 1840:                             }
 1841:                             if (!-e "/home/httpd/lonUsers/$cdom/$longcrs/userfiles/$newurl") {
 1842:                                 system("cp $destdir/resfiles/$res/$$message{attachment} /home/httpd/lonUsers/$cdom/$longcrs/userfiles/$newurl");
 1843:                             }
 1844:                             $contrib{attachmenturl} = '/uploaded/'.$cdom.'/'.$crs.'/'.$newurl;
 1845:                         }
 1846:                     }
 1847:                 }
 1848:                 if (defined($$message{title}) ) {
 1849:                     $contrib{'message'} = $$message{title};
 1850:                 }
 1851:                 if (defined($$message{text})) {
 1852:                     if ($$message{ishtml} eq "false") {
 1853:                         if ($$message{isnewline} eq "true") {
 1854:                             $$message{text} =~ s#\n#<br/>#g;
 1855:                         }
 1856:                     } else {
 1857:                         $$message{text} = &HTML::Entities::decode($$message{text});
 1858:                     }
 1859:                     $contrib{'message'} .= '<br /><br />'.$$message{text};
 1860:                     my $symb = 'bulletin___'.$timestamp.'___adm/wrapper/adm/'.$cdom.'/'.$uname.'/'.$timestamp.'/bulletinboard';
 1861:                     my $postresult = &addposting($symb,\%contrib,$cdom,$crs);
 1862:                 }
 1863:             }
 1864:         }
 1865:     }
 1866: }
 1867: 
 1868: # ---------------------------------------------------------------- Add Posting to Discussion Board
 1869: sub addposting {
 1870:     my ($symb,$contrib,$cdom,$crs)=@_;
 1871:     my $status='';
 1872:     if (($symb) && ($$contrib{message})) {
 1873:          my $crsdom = $cdom.'_'.$crs;
 1874:          &Apache::lonnet::store($contrib,$symb,$crsdom,$cdom,$crs);
 1875:          my %storenewentry=($symb => time);
 1876:          &Apache::lonnet::put('discussiontimes',\%storenewentry,$cdom,$crs);
 1877:     }
 1878:     my %record=&Apache::lonnet::restore('_discussion');
 1879:     my ($temp)=keys(%record);
 1880:     unless ($temp=~/^error\:/) {
 1881:         my %newrecord=();
 1882:         $newrecord{'resource'}=$symb;
 1883:         $newrecord{'subnumber'}=$record{'subnumber'}+1;
 1884:         &Apache::lonnet::cstore(\%newrecord,'_discussion');
 1885:         $status = 'ok';
 1886:     } else {
 1887:         $status.='Failed.';
 1888:     }
 1889:     return $status;
 1890: }
 1891: 
 1892: sub parse_bb5_assessment {
 1893:     my ($res,$docroot,$container,$settings,$allanswers,$allchoices,$allids) = @_;
 1894:     my $xmlfile = $docroot.'/'.$res.".dat";
 1895:     my @state = ();
 1896:     my $id; # the current question ID
 1897:     my $answer_id; # the current answer ID
 1898:     my %toptag = ( pool => 'POOL',
 1899:                  quiz => 'ASSESSMENT',
 1900:                  survey => 'ASSESSMENT'
 1901:                );
 1902: 
 1903:     my $p = HTML::Parser->new
 1904:     (
 1905:      xml_mode => 1,
 1906:      start_h =>
 1907:      [sub {
 1908:         my ($tagname, $attr) = @_;
 1909:         push @state, $tagname;
 1910:         my $depth = 0;
 1911:         my @seq = ();
 1912:         my $class;
 1913:         my $state_str = join(" ",@state);
 1914:         if ($container eq "pool") {
 1915:             if ("@state" eq "POOL TITLE") {
 1916:                 $$settings{title} = $attr->{value};
 1917:             }
 1918:         } else {
 1919:             if ("@state" eq "ASSESSMENT TITLE") {  
 1920:                 $$settings{title} = $attr->{value};          
 1921:             } elsif ("@state" eq "ASSESSMENT FLAG" ) {
 1922:                 $$settings{isnewline} = $attr->{value};
 1923:             } elsif ("@state" eq "ASSESSMENT FLAGS ISAVAILABLE") {
 1924:                 $$settings{isavailable} = $attr->{value};
 1925:             } elsif ("@state" eq "ASSESSMENT FLAGS ISANONYMOUS" ) {
 1926:                 $$settings{isanonymous} = $attr->{id};
 1927:             } elsif ("@state" eq "ASSESSMENT FLAGS GIVE FEEDBACK" ) {
 1928:                 $$settings{feedback} = $attr->{id};        
 1929:             } elsif ("@state" eq "ASSESSMENT FLAGS SHOWCORRECT" ) {
 1930:                 $$settings{showcorrect} = $attr->{id};        
 1931:             } elsif ("@state" eq "ASSESSMENT FLAGS SHOWRESULTS" ) {
 1932:                 $$settings{showresults} = $attr->{id};        
 1933:             } elsif ("@state" eq "ASSESSMENT FLAGS ALLOWMULTIPLE" ) {
 1934:                 $$settings{allowmultiple} = $attr->{id};        
 1935:             } elsif ("@state" eq "ASSESSMENT ASSESSMENTTYPE" ) {
 1936:                 $$settings{type} = $attr->{id};        
 1937:             }
 1938:         }    
 1939:         if ("@state" eq "$toptag{$container} QUESTIONLIST QUESTION") {  
 1940:             $id = $attr->{id};
 1941:             push @{$allids}, $id;
 1942:             %{$$settings{$id}} = ();
 1943:             @{$$allanswers{$id}} = ();
 1944:             $$settings{$id}{class} = $attr->{class};
 1945:             unless ($container eq "pool") {
 1946:                 $$settings{$id}{points} = $attr->{points};
 1947:             }
 1948:             @{$$settings{$id}{correctanswer}} = ();                              
 1949:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[-1] =~ m/^QUESTION_(\w+)$/) ) {
 1950:             $id = $attr->{id};
 1951:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "BODY") && ($state[3] eq "FLAGS") ) {
 1952:             if ($state[4] eq "ISHTML") {
 1953:                 $$settings{$id}{ishtml} = $attr->{value};
 1954:             } elsif ($state[4] eq "ISNEWLINELITERAL") {
 1955:                 $$settings{$id}{newline} = $attr->{value};
 1956:             }
 1957:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "IMAGE") ) {
 1958:             $$settings{$id}{image} = $attr->{value};
 1959:             $$settings{$id}{style} = $attr->{style};
 1960:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "URL") ) {
 1961:             $$settings{$id}{url} = $attr->{value};
 1962:             $$settings{$id}{name} = $attr->{name};
 1963:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[-1] eq "ANSWER") ) {
 1964:             $answer_id = $attr->{id};
 1965:             push @{$$allanswers{$id}},$answer_id;
 1966:             %{$$settings{$id}{$answer_id}} = ();
 1967:             $$settings{$id}{$answer_id}{position} = $attr->{position};
 1968:             if ($$settings{$id}{class} eq 'QUESTION_MATCH') {
 1969:                 $$settings{$id}{$answer_id}{placement} = $attr->{placement};
 1970:                 $$settings{$id}{$answer_id}{type} = 'answer';
 1971:             }
 1972:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[-1] eq "CHOICE") ) {
 1973:             $answer_id = $attr->{id};
 1974:             push @{$$allchoices{$id}},$answer_id; 
 1975:             %{$$settings{$id}{$answer_id}} = ();
 1976:             $$settings{$id}{$answer_id}{position} = $attr->{position};
 1977:             $$settings{$id}{$answer_id}{placement} = $attr->{placement};
 1978:             $$settings{$id}{$answer_id}{type} = 'choice';
 1979:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "ANSWER") ) {
 1980:             if ($state[3] eq "IMAGE") {
 1981:                 $$settings{$id}{$answer_id}{image} = $attr->{value};
 1982:                 $$settings{$id}{$answer_id}{style} = $attr->{style};
 1983:             } elsif ($state[3] eq "URL") {
 1984:                 $$settings{$id}{$answer_id}{url} = $attr->{value};
 1985:             }
 1986:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "CHOICE") ) {
 1987:             if ($state[3] eq "IMAGE") {
 1988:                 $$settings{$id}{$answer_id}{image} = $attr->{value};
 1989:                 $$settings{$id}{$answer_id}{style} = $attr->{style};
 1990:             } elsif ($state[3] eq "URL") {
 1991:                 $$settings{$id}{$answer_id}{url} = $attr->{value};
 1992:             }
 1993:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "GRADABLE") && ($state[3] eq "CORRECTANSWER") ) {
 1994:             my $corr_answer = $attr->{answer_id};
 1995:             push @{$$settings{$id}{correctanswer}}, $corr_answer;
 1996:             my $type = $1;
 1997:             if ($type eq 'TRUEFALSE') {
 1998:                 $$settings{$id}{$corr_answer}{answer_position} = $attr->{position};
 1999:             } elsif ($type eq 'ORDER') {
 2000:                 $$settings{$id}{$corr_answer}{order} = $attr->{order};
 2001:             } elsif ($type eq 'MATCH') {
 2002:                 $$settings{$id}{$corr_answer}{choice_id} = $attr->{choice_id};
 2003:             }
 2004:         }
 2005:      }, "tagname, attr"],
 2006:      text_h =>
 2007:      [sub {
 2008:         my ($text) = @_;
 2009:         $text =~ s/^\s+//g;
 2010:         $text =~ s/\s+$//g;
 2011:         unless ($container eq "pool") {        
 2012:             if ("@state" eq "ASSESSMENT DESCRIPTION TEXT") {
 2013:                 $$settings{description} = $text;
 2014:             } elsif ("@state" eq "ASSESSMENT INSTRUCTIONS ") {
 2015:                 $$settings{instructions}{text} = $text;
 2016:             }
 2017:         }
 2018:         if ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "BODY") && ($state[-1] eq "TEXT") ) {
 2019:             unless ($text eq '') { 
 2020:                 $$settings{$id}{text} = $text;
 2021:             }
 2022:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "ANSWER") && ($state[-1] eq "TEXT") ) {
 2023:             unless ($text eq '') {
 2024:                 $$settings{$id}{$answer_id}{text} = $text;
 2025:             }
 2026:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "CHOICE") && ($state[-1] eq "TEXT") ) {
 2027:             unless ($text eq '') {
 2028:                 $$settings{$id}{$answer_id}{text} = $text;
 2029:             }
 2030:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "GRADABLE") && ($state[-1] eq "FEEDBACK_WHEN_CORRECT") ) {
 2031:             unless ($text eq '') {
 2032:                 $$settings{$id}{feedback_corr} = $text;
 2033:             }
 2034:         } elsif ( ($state[0] eq $toptag{$container}) && ($state[1] =~ m/^QUESTION_(\w+)$/) && ($state[2] eq "GRADABLE") && ($state[-1] eq "FEEDBACK_WHEN_INCORRECT") ) {
 2035:             unless ($text eq '') {
 2036:                 $$settings{$id}{feedback_incorr} = $text;
 2037:             }
 2038:         }
 2039:       }, "dtext"],
 2040:      end_h =>
 2041:      [sub {
 2042:         my ($tagname) = @_;
 2043:         pop @state;
 2044:      }, "tagname"],
 2045:     );
 2046:     $p->unbroken_text(1);
 2047:     $p->marked_sections(1);
 2048:     $p->parse_file($xmlfile);
 2049:     $p->eof;
 2050: }
 2051: 
 2052: sub parse_bb6_assessment {
 2053:     my ($res,$docroot,$container,$settings,$allids) = @_;
 2054:     my $xmlfile = $docroot.'/'.$res.".dat";
 2055:     my @state = ();
 2056:     my $id; # the current question ID
 2057:     my $response; # the current response ID
 2058:     my $foil; # the current foil ID
 2059:     my $numchoice; # the current right match choice;
 2060:     my $labelcount; # the current count of choices for a matching item.
 2061:     my $curr_shuffle;
 2062:     my $curr_class; # the current question type
 2063:     my $curr_matchitem;
 2064:     my $curr_block_type; # the current block type
 2065:     my $curr_flow; # the current flow class attribute
 2066:     my $curr_flow_mat; # the current flow_mat class attribute
 2067:     my $curr_feedback_type; # the current feedback type
 2068:     my $numorder; # counter for ordering type questions
 2069: 
 2070:     my $itemfrag = "questestinterop assessment section item";
 2071:     my $presfrag = "$itemfrag presentation flow flow";
 2072:     my $blockflow = 'flow';
 2073:     my $responselid;
 2074:     my $instructionfrag = "questestinterop assessment presentation_material flow_mat material";
 2075:     my $feedbackfrag = "$itemfrag itemfeedback";
 2076:     my $feedback_tag = '';
 2077:     my $responselid;
 2078:     my $p = HTML::Parser->new
 2079:     (
 2080:      xml_mode => 1,
 2081:      start_h =>
 2082:      [sub {
 2083:         my ($tagname, $attr) = @_;
 2084:         push @state, $tagname;
 2085:         if ("@state" eq "questestinterop assessment") {
 2086:             $$settings{title} = $attr->{title};
 2087:         }
 2088:         if ("@state" eq "questestinterop assessment rubric flow_mat material mat_extension mat_formattedtext") {
 2089:             $$settings{description}{texttype} = $attr->{type};
 2090:         }
 2091:         if ("@state" eq $presfrag) {
 2092:             if ($attr->{class} eq 'QUESTION_BLOCK') {
 2093:                 $curr_block_type = 'question';
 2094:             } elsif ($attr->{class} eq 'RESPONSE_BLOCK') {
 2095:                 $curr_block_type = 'response';
 2096:                 if ($curr_class eq 'Matching') {
 2097:                     $responselid = 'flow response_lid';
 2098:                 } else {
 2099:                     $responselid = 'response_lid';
 2100:                 }
 2101:             } elsif (($attr->{class} eq 'RIGHT_MATCH_BLOCK')) {
 2102:                 $numchoice = 0;
 2103:                 $curr_block_type = 'rightmatch';
 2104:             }
 2105:         }
 2106:         if ("@state" eq "$presfrag flow") {
 2107:             if (($curr_block_type =~ /^rightmatch/)  && ($attr->{class} eq 'Block')) {
 2108:                 $curr_block_type = 'rightmatch'.$numchoice;
 2109:                 $numchoice ++;
 2110:             }
 2111:         }
 2112:         if ($state[-1] eq 'flow') {
 2113:             $curr_flow = $attr->{class};
 2114:         }
 2115:         if ($state[-1] eq 'flow_mat') {
 2116:             $curr_flow_mat = $attr->{class};
 2117:         }
 2118:         if ("@state" eq "$presfrag $blockflow material mat_extension mat_formattedtext") {
 2119:             $$settings{$id}{$curr_block_type}{texttype} = $attr->{texttype};
 2120:         }
 2121:         if ("@state" eq "$presfrag $blockflow material matapplication") {
 2122:             $$settings{$id}{$curr_block_type}{image} = $attr->{uri};
 2123:             $$settings{$id}{$curr_block_type}{style} = $attr->{embedded};
 2124:             $$settings{$id}{$curr_block_type}{label} = $attr->{label};
 2125:         }
 2126:         if ("@state" eq "$presfrag $blockflow material mattext") {
 2127:             $$settings{$id}{$curr_block_type}{link} = $attr->{uri};
 2128:         }
 2129:         if ("@state" eq "$presfrag $responselid") {
 2130:             $response = $attr->{ident};
 2131:             $labelcount = 0; 
 2132:             if ($curr_class eq 'Matching') {
 2133:                 push(@{$$settings{$id}{answers}},$response);
 2134:                 %{$$settings{$id}{$response}} = ();
 2135:                 foreach my $key (keys(%{$$settings{$id}{$curr_block_type}})) {
 2136:                     $$settings{$id}{$response}{$key} = $$settings{$id}{$curr_block_type}{$key};
 2137:                 }
 2138:                 %{$$settings{$id}{$curr_block_type}} = ();
 2139:             }
 2140:         }
 2141:         if ("@state" eq "$presfrag $responselid render_choice") {
 2142:             $curr_shuffle = $attr->{shuffle};
 2143:         }
 2144:         if ("@state" eq "$presfrag $responselid render_choice flow_label response_label") {
 2145:             $foil = $attr->{ident};
 2146:             %{$$settings{$id}{$foil}} = ();
 2147:             $$settings{$id}{$foil}{randomize} = $curr_shuffle;
 2148:             unless ($curr_class eq 'Essay'){
 2149:                 if ($curr_class eq 'Matching') {
 2150:                     push(@{$$settings{$id}{$response}{items}},$foil);
 2151:                     $$settings{$id}{$foil}{order} = $labelcount;
 2152:                     $labelcount ++;
 2153:                 } else {
 2154:                     push(@{$$settings{$id}{answers}},$foil);
 2155:                     @{$$settings{$id}{correctanswer}} = ();
 2156:                 }
 2157:             }
 2158:         }
 2159:         if ("@state" eq "$presfrag $responselid render_choice flow_label response_label flow_mat material matapplication") {
 2160:             $$settings{$id}{$foil}{filetype} = $attr->{embedded};
 2161:             $$settings{$id}{$foil}{label} = $attr->{label};
 2162:             $$settings{$id}{$foil}{uri} = $attr->{uri};
 2163:         }
 2164:         if ("@state" eq "$presfrag $responselid render_choice flow_label response_label flow_mat material mattext") {
 2165:             $$settings{$id}{$foil}{link} = $attr->{uri};
 2166:         }
 2167:         if ("@state" eq "questestinterop assessment section item resprocessing") {
 2168:             if ($curr_class eq 'Matching') {
 2169:                 $$settings{$id}{allchoices} = $numchoice;
 2170:             }
 2171:         }
 2172:         if ("@state" eq "questestinterop assessment section item resprocessing respcondition conditionvar varequal") {
 2173:             if ($curr_class eq 'Matching') { 
 2174:                 $curr_matchitem = $attr->{respident};
 2175:             }
 2176:         }
 2177:         if ("@state" eq $feedbackfrag) {
 2178:             $curr_feedback_type = $attr->{ident};
 2179:             $feedback_tag = "";
 2180:         }
 2181:         if ("@state" eq "$feedbackfrag solution") {
 2182:             $curr_feedback_type = 'solution';
 2183:             $feedback_tag = "solution solutionmaterial";
 2184:         }
 2185:         if ("@state" eq "$feedbackfrag $feedback_tag flow_mat flow_mat material matapplication") {
 2186:             $$settings{$id}{$curr_feedback_type.'feedback'}{filetype} = $attr->{'embedded'};
 2187:             $$settings{$id}{$curr_feedback_type.'feedback'}{label} = $attr->{label};
 2188:             $$settings{$id}{$curr_feedback_type.'feedback'}{uri} = $attr->{uri};
 2189:         }
 2190:         if ("@state" eq "$feedbackfrag $feedback_tag flow_mat flow_mat material mattext") {
 2191:             $$settings{$id}{$curr_feedback_type.'feedback'}{link} = $attr->{uri};
 2192:         }
 2193:      }, "tagname, attr"],
 2194:      text_h =>
 2195:      [sub {
 2196:         my ($text) = @_;
 2197:         $text =~ s/^\s+//g;
 2198:         $text =~ s/\s+$//g;
 2199:         if ("@state" eq "questestinterop assessment rubric flow_mat material mat_extension mat_formattedtext") {
 2200:             $$settings{description}{text} = $text;
 2201:         }
 2202:         if ("@state" eq "questestinterop assessment rubric flow_mat material mattext") {
 2203:             $$settings{description}{text} = $text;
 2204:         }
 2205:         if ("@state" eq "$instructionfrag mat_extension mat_formattedtext") {
 2206:             $$settings{instructions}{text} = $text;
 2207:         }
 2208:         if ("@state" eq "$instructionfrag mattext") {
 2209:             $$settings{instructions}{text} = $text;
 2210:         }
 2211:         if ("@state" eq "questestinterop assessment section item itemmetadata bbmd_asi_object_id") {
 2212:             $id = $text;
 2213:             push @{$allids}, $id;
 2214:             %{$$settings{$id}} = ();
 2215:             @{$$settings{$id}{answers}} = ();
 2216:             %{$$settings{$id}{question}} = ();
 2217:             %{$$settings{$id}{correctfeedback}} = ();
 2218:             %{$$settings{$id}{incorrectfeedback}} = ();
 2219:             %{$$settings{$id}{solutionfeedback}} = ();
 2220:         }
 2221:         if ("@state" eq "questestinterop assessment section item itemmetadata bbmd_questiontype") {
 2222:             $$settings{$id}{class} = $text;
 2223:             $curr_class = $text;
 2224:             if ($curr_class eq 'Matching') {
 2225:                 $blockflow = 'flow flow';
 2226:             } else {
 2227:                 $blockflow = 'flow';
 2228:             } 
 2229:         }
 2230:         if ("@state" eq "$presfrag $blockflow material mat_extension mat_formattedtext") {
 2231:             $$settings{$id}{$curr_block_type}{text} = $text;
 2232:         }
 2233:         if ("@state" eq "$presfrag $blockflow material mattext") {
 2234:             if ($curr_flow eq 'LINK_BLOCK') { 
 2235:                 $$settings{$id}{$curr_block_type}{linkname} = $text;
 2236:             } elsif ($curr_flow eq 'FORMATTED_TEXT_BLOCK') {
 2237:                 $$settings{$id}{$curr_block_type}{text} = $text;
 2238:             }
 2239:         }
 2240:         if ("@state" eq "$presfrag $responselid render_choice flow_label response_label flow_mat material mat_extension mat_formattedtext") {
 2241:             $$settings{$id}{$foil}{text} = $text;
 2242:         }
 2243:         if ("@state" eq "$presfrag $responselid render_choice flow_label response_label flow_mat material mattext") {
 2244:             if ($curr_flow_mat eq 'LINK_BLOCK') {
 2245:                 $$settings{$id}{$foil}{linkname} = $text;
 2246:             } else {
 2247:                 $$settings{$id}{$foil}{text} = $text;
 2248:             } 
 2249:         }
 2250:         if ("@state" eq "questestinterop assessment section item resprocessing respcondition conditionvar varequal") {
 2251:             if ($curr_class eq 'Matching') {
 2252:                 $$settings{$id}{$curr_matchitem}{correctanswer} = $text;
 2253:             } else {
 2254:                 push(@{$$settings{$id}{correctanswer}},$text);
 2255:             }
 2256:         }
 2257:         if ("@state" eq "questestinterop assessment section item resprocessing respcondition conditionvar") {
 2258:             $numorder = 0;
 2259:         }
 2260:         if ("@state" eq "questestinterop assessment section item resprocessing respcondition conditionvar and varequal") {
 2261:             push(@{$$settings{$id}{correctanswer}},$text);
 2262:             if ($curr_class eq 'Ordering') {
 2263:                 $numorder ++;
 2264:                 $$settings{$id}{$text}{order} = $numorder;
 2265:             }
 2266:         }
 2267:         if ("@state" eq "$feedbackfrag $feedback_tag flow_mat flow_mat material mat_extension mat_formattedtext") {
 2268:             $$settings{$id}{$curr_feedback_type.'feedback'}{text} = $text;
 2269:         }
 2270:         if ("@state" eq "$feedbackfrag $feedback_tag flow_mat flow_mat material mattext") {
 2271:             $$settings{$id}{$curr_feedback_type.'feedback'}{linkname} = $text;
 2272:         }
 2273:      }, "dtext"],
 2274:      end_h =>
 2275:      [sub {
 2276:         my ($tagname) = @_;
 2277:         pop @state;
 2278:      }, "tagname"],
 2279:     );
 2280:     $p->unbroken_text(1);
 2281:     $p->marked_sections(1);
 2282:     $p->parse_file($xmlfile);
 2283:     $p->eof;
 2284:     return;
 2285: }
 2286: 
 2287: sub parse_webctvista4_assessment {
 2288:     my ($res,$docroot,$href,$allids,$qzparams) = @_;
 2289:     my $xmlfile = $docroot.'/'.$href; #assessment file
 2290:     my @state = ();
 2291:     my $id; # the current question ID
 2292:     my $fieldlabel; # the current qti metadata field label
 2293:     my $outcome_id; # the current question ID for outcomes conditions
 2294:     my $pname; # the current outcomes parameter name
 2295:     my $numids = 0;
 2296:     %{$$qzparams{$res}} = ();
 2297:     %{$$qzparams{$res}{weight}} = ();
 2298: 
 2299:     my $p = HTML::Parser->new
 2300:     (
 2301:      xml_mode => 1,
 2302:      start_h =>
 2303:      [sub {
 2304:         my ($tagname, $attr) = @_;
 2305:         push @state, $tagname;
 2306:         my @seq = ();
 2307:         if ("@state" eq "questestinterop assessment") {
 2308:             $$qzparams{$res}{id} = $attr->{'ident'};
 2309:             $$qzparams{$res}{title} = $attr->{'title'};
 2310:         }
 2311:         if ("@state" eq "questestinterop assessment section itemref") {
 2312:             $id = $attr->{linkrefid};
 2313:             push(@{$allids},$id);
 2314:             $numids ++;
 2315:         }
 2316:         if ("@state" eq "questestinterop assessment section selection_ordering order") {
 2317:            $$qzparams{$res}{order_type} = $attr->{order_type};
 2318:         }
 2319:      }, "tagname, attr"],
 2320:      text_h =>
 2321:      [sub {
 2322:         my ($text) = @_;
 2323:         if ("@state" eq "questestinterop assessment qtimetadata qtimetadatafield fieldlabel") {
 2324:             $fieldlabel = $text;
 2325:         }
 2326:         if ("@state" eq "questestinterop assessment qtimetadata qtimetadatafield fieldentry") {
 2327:             $$qzparams{$res}{$fieldlabel} = $text;
 2328:         }
 2329:         if ("@state" eq "questestinterop assessment section outcomes_processing objects_condition outcomes_metadata") {
 2330:             $outcome_id = $text;
 2331:         }
 2332:         if ("@state" eq "questestinterop assessment section outcomes_processing objects_condition objects_parameter") {
 2333:             if ($pname eq 'qmd_weighting') {
 2334:                 $$qzparams{$res}{weight}{$outcome_id} = $text;
 2335:             }
 2336:         }
 2337:         if ("@state" eq "questestinterop assessment section selection_ordering selection selection_number") {
 2338:             $$qzparams{$res}{numpick} = $text;
 2339:         }
 2340:       }, "dtext"],
 2341:      end_h =>
 2342:      [sub {
 2343:         my ($tagname) = @_;
 2344:         pop @state;
 2345:      }, "tagname"],
 2346:     );
 2347:     $p->unbroken_text(1);
 2348:     $p->parse_file($xmlfile);
 2349:     $p->eof;
 2350:     unless(defined($$qzparams{$res}{numpick})) {
 2351:         $$qzparams{$res}{numpick} = $numids;
 2352:     }
 2353: }
 2354: 
 2355: sub parse_webctvista4_question {
 2356:     my ($res,$docroot,$resources,$hrefs,$settings,$allquestids,$allanswers,$allchoices,$parent,$catinfo) = @_;
 2357:     my $xmlfile = $docroot.'/'.$$resources{$res}{file};
 2358:     my %classtypes = (
 2359:                       WCT_Calculated => 'numerical',
 2360:                       WCT_TrueFalse => 'multiplechoice',
 2361:                       WCT_ShortAnswer => 'shortanswer',
 2362:                       WCT_Paragraph => 'paragraph',
 2363:                       WCT_MultipleChoice => 'multiplechoice',
 2364:                       WCT_Matching => 'match',
 2365:                       WCT_JumbledSentence => 'jumbled',
 2366:                       WCT_FillInTheBlank => 'string',
 2367:                       WCT_Combination => 'combination'
 2368:     );
 2369:     my @state = ();
 2370:     my $fieldlabel;
 2371:     my %questiondata;
 2372:     my $id; # the current question ID
 2373:     my $list; # the current list ID for multiple choice questions 
 2374:     my $numid; # the current answer ID for numerical questions
 2375:     my $grp; # the current group ID for matching questions
 2376:     my $label; # the current reponse label for string questions
 2377:     my $str_id; # the current string ID for string questions
 2378:     my $unitid; # the current unit ID for numerical questions
 2379:     my $answer_id;  # the current answer ID 
 2380:     my $fdbk; # the current feedback ID
 2381:     my $currvar; # the current variable for numerical problems
 2382:     my $fibtype; # the current fill-in-blank type for numerical or string
 2383:     my $prompt;
 2384:     my $rows;
 2385:     my $columns;
 2386:     my $maxchars;
 2387:     my %setvar = (
 2388:                    varname => '',
 2389:                    action => '',
 2390:                  );
 2391:     my $currtexttype;
 2392:     my $jumble_item;
 2393:     my $numbox = 0;
 2394:     my %str_answers = ();
 2395:     my $textlabel;
 2396:     my $currindex;
 2397:     my %varinfo = ();
 2398:     my $formula;
 2399:     my $jumbnum = 0;
 2400:     my $p = HTML::Parser->new
 2401:     (
 2402:      xml_mode => 1,
 2403:      start_h =>
 2404:      [sub {
 2405:         my ($tagname, $attr) = @_;
 2406:         push @state, $tagname;
 2407:         if ("@state" eq "questestinterop item") {
 2408:             $id = $attr->{ident};
 2409:             push(@{$allquestids},$id);
 2410:             %{$$settings{$id}} = ();
 2411:             %{$varinfo{$id}} = ();
 2412:             @{$$allchoices{$id}} = ();
 2413:             @{$$settings{$id}{grps}} = ();
 2414:             @{$$settings{$id}{lists}} = ();
 2415:             @{$$settings{$id}{feedback}} = ();
 2416:             @{$$settings{$id}{str}} = ();
 2417:             %{$$settings{$id}{strings}} = ();
 2418:             @{$$settings{$id}{numids}} = ();
 2419:             %{$$allanswers{$id}} = ();
 2420:             $$settings{$id}{title} = $attr->{title};
 2421:             $$settings{$id}{title} =~ s/\%/pct_/g;
 2422:         }
 2423:         if ("@state" eq "questestinterop item presentation flow material mat_extension webct:calculated webct:var") {
 2424:             $currvar = $attr->{'webct:name'};
 2425:             %{$varinfo{$id}{$currvar}} = ();
 2426:             $varinfo{$id}{$currvar}{min} = $attr->{'webct:min'};
 2427:             $varinfo{$id}{$currvar}{max} = $attr->{'webct:max'};
 2428:             $varinfo{$id}{$currvar}{precision} = $attr->{'webct:precision'};
 2429:         }
 2430:         if ("@state" eq "questestinterop item presentation flow response_num") {
 2431:             $numid = $attr->{ident};
 2432:             push(@{$$settings{$id}{numids}},$numid);
 2433:             %{$$settings{$id}{$numid}} = ();
 2434:             %{$$settings{$id}{$numid}{vars}} = ();
 2435:             @{$$settings{$id}{$numid}{units}} = ();
 2436:             $$settings{$id}{$numid}{rcardinality} = $attr->{rcardinality};
 2437:             $$settings{$id}{$numid}{formula} = $formula;
 2438:             foreach my $var (keys(%{$varinfo{$id}})) {
 2439:                 %{$$settings{$id}{$numid}{vars}{$var}} = %{$varinfo{$id}{$var}};
 2440:             }
 2441:         }
 2442:         if ("@state" eq "questestinterop item presentation flow material mat_extension webct:variable") {
 2443:             $$settings{$id}{text} .= '['.$attr->{'webct:name'}.']';
 2444:         }
 2445:         if ("@state" eq "questestinterop item presentation flow material matimage") {
 2446:             if ($attr->{uri} =~ /\QRelativeResourceManager?contentID=\E(\d+)$/) {
 2447:                 $$settings{$id}{image} = $1;
 2448:                 push(@{$$resources{$res}{image}},$$settings{$id}{image});
 2449:             } else {
 2450:                 $$settings{$id}{image} = $attr->{uri};
 2451:             }
 2452:         }
 2453: 
 2454:         if ("@state" eq "questestinterop item presentation flow material mattext")  {
 2455:             $currtexttype = lc($attr->{texttype});
 2456:             $$settings{$id}{texttype} = $currtexttype;
 2457:             if ($$settings{$id}{class} eq 'combination') {
 2458:                 if (exists($attr->{label})) {
 2459:                     $textlabel = $attr->{label};
 2460:                 } else {
 2461:                     $textlabel = '';
 2462:                 }
 2463:             }
 2464:         }
 2465:         if ("@state" eq "questestinterop item presentation flow response_lid") {
 2466:             $list = $attr->{ident};
 2467:             push(@{$$settings{$id}{lists}},$list);
 2468:             %{$$settings{$id}{$list}} = ();
 2469:             @{$$allanswers{$id}{$list}} = ();
 2470:             @{$$settings{$id}{$list}{correctanswer}} = ();
 2471:             @{$$settings{$id}{$list}{jumbledtext}} = ();
 2472:             @{$$settings{$id}{$list}{jumbledtype}} = ();
 2473:             @{$$settings{$id}{$list}{jumbled}} = ();
 2474:             $$settings{$id}{$list}{rcardinality} = $attr->{rcardinality};
 2475:         }
 2476: # Jumbled sentence
 2477:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object")  {
 2478:             $$settings{$id}{$list}{orientation} = $attr->{orientation};
 2479:         }
 2480:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object material mattext")  {
 2481:             $currtexttype = lc($attr->{texttype});
 2482:             $$settings{$id}{$list}{texttype} = $currtexttype;
 2483:         }
 2484:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object response_label")  {
 2485:             $jumble_item = $attr->{ident};
 2486:         }
 2487:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object response_label material mattext")  {
 2488:             $currtexttype = lc($attr->{texttype});
 2489:             $$settings{$id}{$list}{$jumble_item}{texttype} = $currtexttype;
 2490:         }
 2491:         if ("@state" eq "questestinterop item resprocessing respcondition") { # Jumbled
 2492:             if ($$settings{$id}{class} eq 'jumbled') {
 2493:                 $jumbnum ++;
 2494:                 @{$$settings{$id}{$list}{jumbled}[$jumbnum]} = (); 
 2495:             }
 2496:         }
 2497: 
 2498:         if ("@state" eq "questestinterop item resprocessing respcondition conditionvar and varequal") { # Jumbled
 2499:             $currindex = $attr->{index};
 2500:         }
 2501:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice") {
 2502:             $$settings{$id}{$list}{randomize} = $attr->{shuffle};
 2503:         }
 2504: # Multiple Choice, True/False and Combination
 2505:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice flow_label response_label") {
 2506:             $answer_id = $attr->{ident};
 2507:             push(@{$$allanswers{$id}{$list}},$answer_id);
 2508:             %{$$settings{$id}{$list}{$answer_id}} = ();
 2509:         }
 2510: # True/False
 2511:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice flow_label response_label material mat_extension webct:localizable_mattext") {
 2512:             $currtexttype = lc($attr->{texttype});
 2513:             $$settings{$id}{$list}{$answer_id}{texttype} = $currtexttype;
 2514:         }
 2515: 
 2516: # Multiple Choice and Combination
 2517:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice flow_label response_label material mattext") {
 2518:             $currtexttype = lc($attr->{texttype});
 2519:             $$settings{$id}{$list}{$answer_id}{texttype} = $currtexttype;
 2520:         }
 2521: 
 2522: # String, Shortanswer or Paragraph
 2523:         if (($$settings{$id}{class} eq 'string') || 
 2524:             ($$settings{$id}{class} eq 'shortanswer') ||
 2525:             ($$settings{$id}{class} eq 'paragraph')) { 
 2526:             if ("@state" eq "questestinterop item presentation flow response_str") {
 2527:                 $str_id = $attr->{ident};
 2528:                 %{$$settings{$id}{$str_id}} = ();
 2529:                 push(@{$$settings{$id}{str}},$str_id);
 2530:                 $$settings{$id}{$str_id}{rcardinality} = $attr->{rcardinality};
 2531:                 @{$$settings{$id}{$str_id}{labels}} = ();
 2532:                 %{$$settings{$id}{$str_id}{comparison}} = ();
 2533:             }
 2534:         }
 2535:         if ("@state" eq "questestinterop item presentation flow response_str material mattext") { # string
 2536:             $currtexttype = lc($attr->{texttype});
 2537:             $$settings{$id}{$str_id}{texttype} = $currtexttype;
 2538:         }
 2539:         if ("@state" eq "questestinterop item presentation flow response_str render_fib") {
 2540:             $fibtype = $attr->{fibtype};
 2541:             $prompt = $attr->{prompt};
 2542:             $rows = $attr->{rows};
 2543:             $columns = $attr->{columns};
 2544:             $maxchars = $attr->{maxchars};
 2545:         }
 2546:         if ("@state" eq "questestinterop item presentation flow response_str render_fib response_label") {
 2547:             push(@{$$settings{$id}{$str_id}{labels}},$label);
 2548:             @{$$settings{$id}{strings}{$str_id}} = ();
 2549:             %{$$settings{$id}{$str_id}{$label}} = ();
 2550:             $$settings{$id}{$str_id}{$label}{fibtype} = $fibtype;
 2551:             if ($$settings{$id}{class} eq 'string') {
 2552:                 $$settings{$id}{text} .= '________';
 2553:             }
 2554:         }
 2555:         if ("@state" eq "questestinterop item presentation flow response_str render_fib response_label material mattext") { # Paragraph
 2556:             $textlabel = $attr->{label}; 
 2557:         }
 2558: # Matching
 2559:         if ("@state" eq "questestinterop item presentation flow flow response_grp") {
 2560:             $grp = $attr->{ident};
 2561:             push(@{$$settings{$id}{grps}},$grp);
 2562:             %{$$settings{$id}{$grp}} = ();
 2563:             @{$$allanswers{$id}{$grp}} = ();
 2564:             @{$$settings{$id}{$grp}{correctanswer}} = ();
 2565:             $$settings{$id}{$grp}{rcardinality} = $attr->{rcardinality};
 2566:         }
 2567:         if ("@state" eq "questestinterop item presentation flow flow response_grp material mattext") {
 2568:             $currtexttype = lc($attr->{texttype});
 2569:             $$settings{$id}{$grp}{texttype} = $currtexttype;
 2570:         }
 2571:         if ("@state" eq "questestinterop item presentation flow flow response_grp render_choice flow_label response_label") {
 2572:             $answer_id = $attr->{ident};
 2573:             push(@{$$allanswers{$id}{$grp}},$answer_id);
 2574:             %{$$settings{$id}{$grp}{$answer_id}} = ();
 2575:             $currtexttype = lc($attr->{texttype});
 2576:             $$settings{$id}{$grp}{$answer_id}{texttype} =  $currtexttype;
 2577:         }
 2578: # Multiple choice or combination or string or match 
 2579:         if ("@state" eq "questestinterop item resprocessing respcondition conditionvar varequal") {
 2580:             if (($$settings{$id}{class} eq 'multiplechoice') || 
 2581:                 ($$settings{$id}{class} eq 'combination')) {
 2582:                 $list = $attr->{respident};
 2583:             } elsif (($$settings{$id}{class} eq 'string') ||
 2584:                      ($$settings{$id}{class} eq 'shortanswer')) {
 2585:                 $label = $attr->{respident};
 2586:                 $$settings{$id}{$label}{case} = $attr->{'case'};
 2587:             } elsif ($$settings{$id}{class} eq 'match') {
 2588:                 $grp = $attr->{respident};
 2589:             }
 2590:         }
 2591:         if ("@state" eq "questestinterop item resprocessing") {
 2592:             if (($$settings{$id}{class} eq 'string') ||
 2593:                 ($$settings{$id}{class} eq 'shortanswer')) {
 2594:                 foreach my $str_id (@{$$settings{$id}{str}}) {
 2595:                     @{$str_answers{$str_id}} = ();
 2596:                 }
 2597:             }
 2598:         }
 2599:         if ("@state" eq "questestinterop item resprocessing respcondition") {
 2600:             if (($$settings{$id}{class} eq 'string') ||
 2601:                 ($$settings{$id}{class} eq 'shortanswer')) { 
 2602:                 $numbox ++;
 2603:             }
 2604:         }
 2605:         if ("@state" eq "questestinterop item resprocessing respcondition setvar") {
 2606:             foreach my $key (keys(%{$attr})) {
 2607:                 $setvar{$key} = $attr->{$key};
 2608:             }
 2609:         }
 2610:         if (($$settings{$id}{class} eq 'string') ||
 2611:             ($$settings{$id}{class} eq 'shortanswer')) {
 2612:             if (("@state" eq "questestinterop item resprocessing respcondition conditionvar or varsubset") || ("@state" eq "questestinterop item resprocessing respcondition conditionvar varsubset")) {
 2613:                 $str_id = $attr->{respident};
 2614:                 $$settings{$id}{$str_id}{case} = $attr->{case};
 2615:             }
 2616:         }
 2617:         if ("@state" eq "questestinterop item resprocessing respcondition conditionvar and varsubset") {
 2618:             $list = $attr->{respident};
 2619:         }
 2620: # Numerical
 2621:         if ("@state" eq "questestinterop item resprocessing itemproc_extension webct:calculated_answer") {
 2622:             $numid = $attr->{respident};
 2623:             $$settings{$id}{$numid}{toltype} = $attr->{'webct:toleranceType'};
 2624:             $$settings{$id}{$numid}{tolerance} = $attr->{'webct:tolerance'};
 2625:         }
 2626:         if ("@state" eq "questestinterop item resprocessing itemproc_extension unit_eval conditionvar varequal") {
 2627:             $unitid = $attr->{respident};
 2628:             %{$$settings{$id}{$numid}{$unitid}} = ();
 2629:             push(@{$$settings{$id}{$numid}{units}},$unitid);
 2630:             $$settings{$id}{$numid}{$unitid}{case} = $attr->{case};
 2631:         }
 2632: # Feedback
 2633:         if ("@state" eq "questestinterop item respcondition displayfeedback") {
 2634:             $fdbk = $attr->{linkrefid};
 2635:             push(@{$$settings{$id}{feedback}},$fdbk);
 2636:             $$settings{$id}{$fdbk} = ();
 2637:             $$settings{$id}{$fdbk}{feedbacktype} = $attr->{feedbacktype};
 2638:         }
 2639:         if ("@state" eq "questestinterop item itemfeedback") {
 2640:             $fdbk = $attr->{ident};
 2641:             push(@{$$settings{$id}{feedback}},$fdbk);
 2642:             $$settings{$id}{$fdbk}{view} = $attr->{view};
 2643:         }
 2644:         if ("@state" eq "questestinterop item itemfeedback material mattext") {
 2645:             $currtexttype = lc($attr->{texttype});
 2646:             $$settings{$id}{$fdbk}{texttype} = $currtexttype;
 2647:         }
 2648:         if ("@state" eq "questestinterop item itemfeedback solution solutionmaterial material mattext") {
 2649:             $currtexttype = lc($attr->{texttype});
 2650:             $$settings{$id}{$fdbk}{texttype} = $currtexttype;
 2651:         }
 2652:      }, "tagname, attr"],
 2653:      text_h =>
 2654:      [sub {
 2655:         my ($text) = @_;
 2656:         $text =~ s/\s*\&\s*/_and_/g;
 2657:         if ($currtexttype eq '/text/html') {
 2658:             $text =~ s#(&lt;img\ssrc=")([^"]+)"&gt;#$1../resfiles/$2#g;
 2659:         }
 2660:         if ("@state" eq "questestinterop item presentation flow material matimage") {
 2661:             my $imagetitle;
 2662:             if ($text =~ /,/) {
 2663:                 $imagetitle = (split(/,/,$text))[-1];
 2664:             } else {
 2665:                 $imagetitle = $text;
 2666:             }
 2667:             $$settings{$id}{imagetitle} = $imagetitle;
 2668:             push(@{$$resources{$res}{imagetitle}},$imagetitle);
 2669:         }
 2670:         if ("@state" eq "questestinterop item itemmetadata qtimetadata qtimetadatafield fieldlabel") {
 2671:             $fieldlabel = $text;
 2672:         }
 2673:         if ("@state" eq "questestinterop item itemmetadata qtimetadata qtimetadatafield fieldentry") {
 2674:             $questiondata{$fieldlabel} = $text;
 2675:             if ($fieldlabel eq 'wct_questiontype') {
 2676:                 $$settings{$id}{class} = $classtypes{$text};
 2677:             } elsif ($fieldlabel eq 'wct_questioncategory') {
 2678:                 $$settings{$id}{category} = $text;
 2679:                 unless(exists($$catinfo{$text})) {
 2680:                     %{$$catinfo{$text}} = ();
 2681:                     $$catinfo{$text}{title} = $text;
 2682:                 }
 2683:                 push(@{$$catinfo{$text}{contents}},$id);
 2684:             }
 2685:         }
 2686:         if ("@state" eq "questestinterop item presentation flow material mat_extension webct:calculated webct:formula") {
 2687:             $formula = $text;
 2688:         }
 2689:         if ("@state" eq "questestinterop item presentation flow response_str material mattext") {
 2690:             $$settings{$id}{$str_id}{text} = $text;
 2691:         }
 2692:         if ("@state" eq "questestinterop item presentation flow response_str render_fib response_label material mattext") { # Paragraph
 2693:             if ($textlabel eq 'PRE_FILL_ANSWER') {
 2694:                 $$settings{$id}{$str_id}{$label}{$textlabel} = $text;
 2695:             }
 2696:         }
 2697: # Matching
 2698:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice flow_label response_label material mattext") {
 2699:             $$settings{$id}{$list}{$answer_id}{text} .= $text;
 2700:         }
 2701: # Multiple choice, True/False, Combination
 2702:         if ("@state" eq "questestinterop item presentation flow response_lid render_choice flow_label response_label material mat_extension webct:localizable_mattext") {
 2703:             $$settings{$id}{$list}{$answer_id}{text} = $text;
 2704:         }
 2705:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object material mattext")  {
 2706:             push(@{$$settings{$id}{$list}{jumbledtext}},$text);
 2707:             push(@{$$settings{$id}{$list}{jumbledtype}},'No');
 2708:         }
 2709:         if ("@state" eq "questestinterop item presentation flow response_lid render_extension ims_render_object response_label material mattext")  {
 2710:             $$settings{$id}{$list}{$jumble_item}{text} = $text;
 2711:             push(@{$$settings{$id}{$list}{jumbledtext}},$text);
 2712:             push(@{$$settings{$id}{$list}{jumbledtype}},'Yes');
 2713:         }
 2714:         if ("@state" eq "questestinterop item presentation flow material mattext")  {
 2715:             $$settings{$id}{text} .= $text;
 2716:             if ($$settings{$id}{class} eq 'combination') {
 2717:                 if ($textlabel =~ /^wct_question_label_\d+$/) {
 2718:                     $$settings{$id}{text} .= '<br />';
 2719:                 }
 2720:                 if ($textlabel =~ /^wct_cmc_single_answer\d+$/) {
 2721:                     $$settings{$id}{text} .= '<br />';
 2722:                 }
 2723:             }
 2724:         }
 2725: # Matching
 2726:         if ("@state" eq "questestinterop item presentation flow flow response_grp material mattext")  {
 2727:             $$settings{$id}{$grp}{text} = $text;
 2728:             unless ($text eq '') {
 2729:                 push(@{$$allchoices{$id}},$grp);
 2730:             }
 2731:         }
 2732:         if ("@state" eq "questestinterop item presentation flow flow response_grp render_choice flow_label response_label material mattext") {
 2733:             $$settings{$id}{$grp}{$answer_id}{text} = $text;
 2734:         }
 2735: # Numerical
 2736:         if ("@state" eq "questestinterop item resprocessing itemproc_extension unit_eval conditionvar varequal") {
 2737:             $$settings{$id}{$numid}{$unitid}{text} = $text;
 2738:         }
 2739:         if ("@state" eq "questestinterop item resprocessing respcondition conditionvar varequal") {
 2740:             if (($$settings{$id}{class} eq 'string') ||
 2741:                 ($$settings{$id}{class} eq 'shortanswer')) {
 2742:                 unless (grep/^$text$/,@{$str_answers{$str_id}}) {
 2743:                     push(@{$str_answers{$str_id}},$text);
 2744:                     $$settings{$id}{$str_id}{comparison}{$text} = $questiondata{'wct_comparison_type'.$numbox};
 2745:                 }
 2746:             } else {
 2747:                 $answer_id = $text;
 2748:             }
 2749:         }
 2750:         if (("@state" eq "questestinterop item resprocessing respcondition conditionvar or varsubset") || ("@state" eq "questestinterop item resprocessing respcondition conditionvar varsubset")) { # string
 2751:             if (($$settings{$id}{class} eq 'string') ||
 2752:                 ($$settings{$id}{class} eq 'shortanswer')) {
 2753:                 unless (grep/^$text$/,@{$str_answers{$str_id}}) {
 2754:                     push(@{$str_answers{$str_id}},$text);
 2755:                     $$settings{$id}{$str_id}{comparison}{$text} = $questiondata{'wct_comparison_type'.$numbox};
 2756:                 }
 2757:             }
 2758:         }
 2759: 
 2760:         if ("@state" eq "questestinterop item resprocessing respcondition conditionvar and varequal") { # Jumbled
 2761:             $$settings{$id}{$list}{jumbled}[$jumbnum][$currindex] = $text;
 2762:         }
 2763:         if ("@state" eq "questestinterop item resprocessing respcondition setvar") {
 2764:             if ($setvar{varname} eq "SCORE") { # Multiple Choice, String or Match
 2765:                 if ($text =~ m/^[\d\.]+$/) {
 2766:                     if ($text > 0) {
 2767:                         if (($$settings{$id}{class} eq 'multiplechoice') ||
 2768:                             ($$settings{$id}{class} eq 'combination')) {
 2769:                             push(@{$$settings{$id}{$list}{correctanswer}},$answer_id);
 2770:                         } elsif (($$settings{$id}{class} eq 'string') ||
 2771:                                  ($$settings{$id}{class} eq 'shortanswer')) {
 2772:                             foreach my $answer (@{$str_answers{$str_id}}) {
 2773:                                 unless (grep/^$answer$/,@{$$settings{$id}{strings}{$str_id}}) {
 2774:                                     push(@{$$settings{$id}{strings}{$str_id}},$answer);
 2775:                                 }
 2776:                             }
 2777:                         } elsif ($$settings{$id}{class} eq 'match') {
 2778:                             push(@{$$settings{$id}{$grp}{correctanswer}},$answer_id);
 2779:                         }
 2780:                     }
 2781:                 }
 2782:             }
 2783:         }
 2784:         if ("@state" eq "questestinterop item itemfeedback material mattext") {
 2785:             $$settings{$id}{$fdbk}{text} = $text;
 2786:         }
 2787:         if ("@state" eq "questestinterop item itemfeedback solution solutionmaterial material mattext") {
 2788:             $$settings{$id}{$fdbk}{text} = $text;
 2789:         }
 2790:       }, "dtext"],
 2791:      end_h =>
 2792:      [sub {
 2793:         my ($tagname) = @_;
 2794:         pop @state;
 2795:      }, "tagname"],
 2796:     );
 2797:     $p->unbroken_text(1);
 2798:     $p->parse_file($xmlfile);
 2799:     $p->eof;
 2800: }
 2801: 
 2802: sub parse_webct4_assessment {
 2803:     my ($res,$docroot,$href,$container,$allids) = @_;
 2804:     my $xmlfile = $docroot.'/'.$href; #quiz file
 2805:     my @state = ();
 2806:     my $id; # the current question ID
 2807:     my $p = HTML::Parser->new
 2808:     (
 2809:      xml_mode => 1,
 2810:      start_h =>
 2811:      [sub {
 2812:         my ($tagname, $attr) = @_;
 2813:         push @state, $tagname;
 2814:         my $depth = 0;
 2815:         my @seq = ();
 2816:         if ("@state" eq "questestinterop assessment section itemref") {
 2817:             $id = $attr->{linkrefid}; 
 2818:             push(@{$allids},$id);
 2819:         }
 2820:      }, "tagname, attr"],
 2821:      text_h =>
 2822:      [sub {
 2823:         my ($text) = @_;
 2824:       }, "dtext"],
 2825:      end_h =>
 2826:      [sub {
 2827:         my ($tagname) = @_;
 2828:         pop @state;
 2829:      }, "tagname"],
 2830:     );
 2831:     $p->unbroken_text(1);
 2832:     $p->parse_file($xmlfile);
 2833:     $p->eof;
 2834: }
 2835: 
 2836: sub parse_webct4_quizprops {
 2837:     my ($res,$docroot,$href,$container,$qzparams) = @_;
 2838:     my $xmlfile = $docroot.'/'.$href; #properties file
 2839:     my @state = ();
 2840:     %{$$qzparams{$res}} = ();
 2841:     my $p = HTML::Parser->new
 2842:     (
 2843:      xml_mode => 1,
 2844:      start_h =>
 2845:      [sub {
 2846:         my ($tagname, $attr) = @_;
 2847:         push @state, $tagname;
 2848:      }, "tagname, attr"],
 2849:      text_h =>
 2850:      [sub {
 2851:         my ($text) = @_;
 2852:         if ($state[0] eq 'properties' && $state[1] eq 'delivery')  {
 2853:             if ($state[2] eq 'time_available') {
 2854:                 $$qzparams{$res}{opendate} = $text;
 2855:             } elsif ($state[2] eq 'time_due') {
 2856:                 $$qzparams{$res}{duedate} = $text;
 2857:             } elsif ($state[3] eq 'max_attempt') {
 2858:                 $$qzparams{$res}{tries} = $text;
 2859:             } elsif ($state[3] eq 'post_submission') {
 2860:                 $$qzparams{$res}{posts} = $text;
 2861:             } elsif ($state[3] eq 'method') {
 2862:                 $$qzparams{$res}{method} = $text;
 2863:             }
 2864:         } elsif ($state[0] eq 'properties' && $state[1] eq 'processing')  {
 2865:             if ($state[2] eq 'scores' && $state[3] eq 'score') {
 2866:                 $$qzparams{$res}{weight} = $text;
 2867:             } elsif ($state[2] eq 'selection' && $state[3] eq 'select') {
 2868:                 $$qzparams{$res}{numpick} = $text;
 2869:             }
 2870:         } elsif ($state[0] eq 'properties' && $state[1] eq 'result') {
 2871:             if ($state[2] eq 'display_answer') {
 2872:                 $$qzparams{$res}{showanswer} = $text;
 2873:             }
 2874:         } 
 2875:       }, "dtext"],
 2876:      end_h =>
 2877:      [sub {
 2878:         my ($tagname) = @_;
 2879:         pop @state;
 2880:      }, "tagname"],
 2881:     );
 2882:     $p->unbroken_text(1);
 2883:     $p->parse_file($xmlfile);
 2884:     $p->eof;
 2885: }
 2886: 
 2887: sub parse_webct4_questionDB {
 2888:     my ($docroot,$href,$catinfo,$settings,$allanswers,$allchoices,$allids) = @_;
 2889:     my $xmlfile;
 2890:     if ($href eq 'questiondb.xml') {
 2891:         $xmlfile = $docroot.'/'.$href;
 2892:     } else {
 2893:         $href =~ s#[^/]+$##;
 2894:         $xmlfile = $docroot.'/'.$href.'questionDB.xml'; #quizDB file
 2895:     }
 2896:     my @state = ();
 2897:     my $category; # the current category ID
 2898:     my $id; # the current question ID
 2899:     my $list; # the current list ID for multiple choice questions
 2900:     my $numid; # the current answer ID for numerical questions
 2901:     my $grp; # the current group ID for matching questions
 2902:     my $label; # the current reponse label for string questions 
 2903:     my $str_id; # the current string ID for string questions
 2904:     my $unitid; # the current unit ID for numerical questions
 2905:     my $answer_id; # the current answer ID
 2906:     my $fdbk; # the current feedback ID
 2907:     my $currvar; # the current variable for numerical problems
 2908:     my $fibtype; # the current fill-in-blank type for numerical or string
 2909:     my $prompt;
 2910:     my $boxnum; 
 2911:     my %setvar = (
 2912:                    varname => '',
 2913:                    action => '',
 2914:                  );
 2915:     my $currtexttype;
 2916:     my $currimagtype;
 2917:     my $is_objectbank;
 2918:     my $p = HTML::Parser->new
 2919:     (
 2920:      xml_mode => 1,
 2921:      start_h =>
 2922:      [sub {
 2923:         my ($tagname, $attr) = @_;
 2924:         if (("@state" eq "questestinterop") && ($tagname eq 'objectbank')) {
 2925:             $is_objectbank = 1;
 2926:         } else {
 2927:             push @state, $tagname;
 2928:         }
 2929:         if ("@state" eq "questestinterop section") {
 2930:             $category = $attr->{ident};
 2931:             %{$$catinfo{$category}} = ();
 2932:             $$catinfo{$category}{title} = $attr->{title};   
 2933:         }
 2934:         if ("@state" eq "questestinterop section item") {
 2935:             $id = $attr->{ident};
 2936:             push @{$allids}, $id;
 2937:             push(@{$$catinfo{$category}{contents}},$id);
 2938:             %{$$settings{$id}} = ();
 2939:             @{$$allchoices{$id}} = ();
 2940:             @{$$settings{$id}{grps}} = ();
 2941:             @{$$settings{$id}{lists}} = ();
 2942:             @{$$settings{$id}{feedback}} = ();
 2943:             @{$$settings{$id}{str}} = ();
 2944:             %{$$settings{$id}{strings}} = ();
 2945:             @{$$settings{$id}{numids}} = ();
 2946:             @{$$settings{$id}{boxes}} = ();
 2947:             %{$$allanswers{$id}} = ();
 2948:             $$settings{$id}{title} = $attr->{title};
 2949:             $$settings{$id}{category} = $category;
 2950:             $boxnum = 0;
 2951:         }
 2952: 
 2953:         if ("@state" eq "questestinterop section item presentation material mattext") {
 2954:             $$settings{$id}{texttype} = $attr->{texttype};
 2955:             $currtexttype = $attr->{texttype};
 2956:         }
 2957:         if ("@state" eq "questestinterop section item presentation material matimage") {
 2958:             $$settings{$id}{imagtype} = $attr->{imagtype};
 2959:             $currimagtype = $attr->{imagtype};
 2960:             $$settings{$id}{uri} = $attr->{uri};
 2961:         }
 2962: 
 2963: # Matching
 2964:         if ("@state" eq "questestinterop section item presentation response_grp") {
 2965:             $$settings{$id}{class} = 'match';
 2966:             $grp = $attr->{ident};
 2967:             push(@{$$settings{$id}{grps}},$grp);
 2968:             %{$$settings{$id}{$grp}} = ();
 2969:             @{$$settings{$id}{$grp}{correctanswer}} = ();
 2970:             $$settings{$id}{$grp}{rcardinality} = $attr->{rcardinality};
 2971:         }
 2972:         if ("@state" eq "questestinterop section item presentation response_grp material mattext") { 
 2973:             $$settings{$id}{$grp}{texttype} = $attr->{texttype};
 2974:             $currtexttype = $attr->{texttype};
 2975:         }
 2976:         if ("@state" eq "questestinterop section item presentation response_grp render_choice response_label") {
 2977:             $answer_id = $attr->{ident};
 2978:             push(@{$$allanswers{$id}{$grp}},$answer_id);
 2979:             %{$$settings{$id}{$grp}{$answer_id}} = ();
 2980:             $$settings{$id}{$grp}{$answer_id}{texttype} =  $attr->{texttype};
 2981:             $currtexttype = $attr->{texttype};
 2982:         }
 2983: 
 2984: # Multiple choice
 2985: 
 2986:         if ("@state" eq "questestinterop section item presentation flow material mattext") {
 2987:             $$settings{$id}{texttype} = $attr->{texttype};
 2988:             $currtexttype = $attr->{texttype};
 2989:         }
 2990:         if ("@state" eq "questestinterop section item presentation flow material matimage") {
 2991:             $$settings{$id}{imagtype} = $attr->{imagtype};
 2992:             $currimagtype = $attr->{imagtype};
 2993:             $$settings{$id}{uri} = $attr->{uri};
 2994: 
 2995:         }
 2996:         if ("@state" eq "questestinterop section item presentation flow response_lid") {
 2997:             $$settings{$id}{class} = 'multiplechoice';
 2998:             $list = $attr->{ident};
 2999:             push(@{$$settings{$id}{lists}},$list);
 3000:             %{$$settings{$id}{$list}} = ();
 3001:             @{$$allanswers{$id}{$list}} = ();
 3002:             @{$$settings{$id}{$list}{correctanswer}} = ();
 3003:             $$settings{$id}{$list}{rcardinality} = $attr->{rcardinality};
 3004:         }
 3005:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice") {
 3006:             $$settings{$id}{$list}{randomize} = $attr->{shuffle};
 3007:         }
 3008:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice flow_label response_label") {
 3009:             $answer_id = $attr->{ident};
 3010:             push(@{$$allanswers{$id}{$list}},$answer_id);
 3011:             %{$$settings{$id}{$list}{$answer_id}} = ();
 3012:         }
 3013:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice flow_label response_label material mattext") {
 3014:             $$settings{$id}{$list}{$answer_id}{texttype} = $attr->{texttype};
 3015:             $currtexttype = $attr->{texttype};
 3016:         }
 3017:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice flow_label response_label flow_mat material mattext") {
 3018:             $$settings{$id}{$list}{$answer_id}{texttype} = $attr->{texttype};
 3019:             $currtexttype = $attr->{texttype};
 3020:         }
 3021: 
 3022: # Numerical
 3023:         if ("@state" eq "questestinterop section item presentation material mat_extension webct:x_webct_v01_dynamicmattext") {
 3024:             $$settings{$id}{texttype} = $attr->{texttype};
 3025:             $currtexttype = $attr->{texttype};
 3026:         }
 3027:         if ("@state" eq "questestinterop section item presentation response_num") {
 3028:             $$settings{$id}{class} = 'numerical';
 3029:             $numid = $attr->{ident};
 3030:             push(@{$$settings{$id}{numids}},$numid);
 3031:             %{$$settings{$id}{$numid}} = ();
 3032:             %{$$settings{$id}{$numid}{vars}} = ();
 3033:             @{$$settings{$id}{$numid}{units}} = ();
 3034:             $$settings{$id}{$numid}{rcardinality} = $attr->{rcardinality};
 3035:         }
 3036:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_minvalue webct:x_webct_v01_variable") {            
 3037:             $currvar = $attr->{name};
 3038:             %{$$settings{$id}{$numid}{vars}{$currvar}} = ();
 3039:         }
 3040:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_maxvalue webct:x_webct_v01_variable") {
 3041:             $currvar = $attr->{name};
 3042:         }
 3043:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_decimalnum webct:x_webct_v01_variable") {
 3044:             $currvar = $attr->{name};
 3045:         }
 3046:         if ("@state" eq "questestinterop section item presentation response_num render_fib") {
 3047:             $fibtype = $attr->{fibtype};
 3048:             $prompt = $attr->{prompt};
 3049:         }
 3050:         if ("@state" eq "questestinterop section item presentation response_num render_fib response_label") {
 3051:             $$settings{$id}{$numid}{label} = $attr->{ident};
 3052:         }
 3053: 
 3054: # String or Numerical
 3055:         if ("@state" eq "questestinterop section item presentation response_str") {
 3056:             $str_id = $attr->{ident};
 3057:             push(@{$$settings{$id}{str}},$str_id);
 3058:             @{$$settings{$id}{boxes}[$boxnum]} = ();
 3059:             $boxnum ++;
 3060:             %{$$settings{$id}{$str_id}} = ();
 3061:             @{$$settings{$id}{$str_id}{labels}} = ();
 3062:             $$settings{$id}{$str_id}{rcardinality} = $attr->{rcardinality};
 3063:         }
 3064: 
 3065:         if ("@state" eq "questestinterop section item presentation response_str render_fib") {
 3066:             $fibtype = $attr->{fibtype};
 3067:             $prompt = $attr->{prompt};
 3068:         }    
 3069:         if ("@state" eq "questestinterop section item presentation response_str render_fib response_label") {
 3070:             $label = $attr->{ident};
 3071:             push(@{$$settings{$id}{$str_id}{labels}},$label);
 3072:             @{$$settings{$id}{strings}{$label}} = ();
 3073:             %{$$settings{$id}{$str_id}{$label}} = ();
 3074:             $$settings{$id}{$str_id}{$label}{fibtype} = $fibtype;
 3075:         }
 3076: 
 3077: # Numerical
 3078:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_anspresentation") {
 3079:             $$settings{$id}{$numid}{digits} = $attr->{digits};
 3080:             $$settings{$id}{$numid}{format} = $attr->{format};
 3081:         }
 3082:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_anstolerance") {
 3083:             $$settings{$id}{$numid}{toltype} = $attr->{type};
 3084:         }
 3085:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_unit") {
 3086:             $unitid = $attr->{ident};
 3087:             %{$$settings{$id}{$numid}{$unitid}} = ();
 3088:             push(@{$$settings{$id}{$numid}{units}},$unitid);
 3089:             $$settings{$id}{$numid}{$unitid}{value} = $attr->{value}; 
 3090:             $$settings{$id}{$numid}{$unitid}{space} = $attr->{space};
 3091:             $$settings{$id}{$numid}{$unitid}{case} = $attr->{case};
 3092:         }
 3093: 
 3094: # Matching 
 3095:         if ("@state" eq "questestinterop section item resprocessing respcondition conditionvar varequal") {
 3096:             if ($$settings{$id}{class} eq 'match') {
 3097:                 unless ($attr->{respident} eq 'WebCT_Incorrect') {
 3098:                     $grp = $attr->{respident};
 3099:                 }
 3100: # String
 3101:             } else {
 3102:                 $label = $attr->{respident};
 3103:                 $$settings{$id}{$label}{case} = $attr->{case};   
 3104:             } 
 3105:         }
 3106:         if ("@state" eq "questestinterop section item resprocessing respcondition setvar") {
 3107:             foreach my $key (keys(%{$attr})) {
 3108:                 $setvar{$key} = $attr->{$key};
 3109:             }
 3110:             if ($setvar{varname} eq 'WebCT_Correct') {
 3111:                 push(@{$$settings{$id}{$grp}{correctanswer}},$answer_id);
 3112:             }
 3113:         }
 3114: 
 3115: # String
 3116:         if ("@state" eq "questestinterop section item resprocessing") {
 3117:             $boxnum = -1;
 3118:         }
 3119:         if ("@state" eq "questestinterop section item resprocessing respcondition") {            $boxnum ++;
 3120:         }
 3121:         if ("@state" eq "questestinterop section item resprocessing respcondition conditionvar varsubset") {
 3122:             $$settings{$id}{class} = 'string';
 3123:             $label = $attr->{respident};
 3124:         }
 3125:         if ("@state" eq "questestinterop section item resprocessing respcondition conditionvar not") {
 3126:             $$settings{$id}{class} = 'paragraph';
 3127:         }
 3128:  
 3129: 
 3130: # Feedback
 3131:  
 3132:         if ("@state" eq "questestinterop section item respcondition displayfeedback") {
 3133:             $fdbk = $attr->{linkrefid};
 3134:             push(@{$$settings{$id}{feedback}},$fdbk);
 3135:             $$settings{$id}{$fdbk} = ();
 3136:             $$settings{$id}{$fdbk}{feedbacktype} = $attr->{feedbacktype};
 3137:         }
 3138:         if ("@state" eq "questestinterop section item itemfeedback") {
 3139:             $fdbk = $attr->{ident};
 3140:             push(@{$$settings{$id}{feedback}},$fdbk);
 3141:             $$settings{$id}{$fdbk}{view} = $attr->{view};
 3142:         }
 3143:         if ("@state" eq "questestinterop section item itemfeedback material mattext") {
 3144:             $$settings{$id}{$fdbk}{texttype} = $attr->{texttype};
 3145:             $currtexttype = $attr->{texttype};
 3146:         }
 3147:      }, "tagname, attr"],
 3148:      text_h =>
 3149:      [sub {
 3150:         my ($text) = @_;
 3151:         if ($currtexttype eq '/text/html') {
 3152:             $text =~ s#(&lt;img\ssrc=")([^"]+)"&gt;#$1../resfiles/$2#g;
 3153:         }
 3154:         if ("@state" eq "questestinterop section item itemmetadata qmd_itemtype") {
 3155:             $$settings{$id}{itemtype} = $text;
 3156:             if ($text eq 'String') {
 3157:                 $$settings{$id}{class} = 'string';
 3158:             }
 3159:         }
 3160: 
 3161:         if ("@state" eq "questestinterop section item presentation material mattext") {
 3162:             $$settings{$id}{text} = $text;
 3163:         }
 3164: # Matching
 3165:         if ("@state" eq "questestinterop section item presentation response_grp material mattext") {
 3166:             $$settings{$id}{$grp}{text} = $text;
 3167:             unless ($text eq '') {
 3168:                 push(@{$$allchoices{$id}},$grp);
 3169:             }
 3170:         }
 3171:         if ("@state" eq "questestinterop section item presentation response_grp render_choice response_label material mattext") {
 3172:             $$settings{$id}{$grp}{$answer_id}{text} = $text;
 3173:         }
 3174: 
 3175: # Multiple choice
 3176: 
 3177:         if ("@state" eq "questestinterop section item presentation flow material mattext") {
 3178:             $$settings{$id}{text} = $text;
 3179:         }
 3180: 
 3181:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice flow_label response_label material mattext") {
 3182:             $$settings{$id}{$list}{$answer_id}{text} = $text;
 3183:         }
 3184:         if ("@state" eq "questestinterop section item presentation flow response_lid render_choice flow_label response_label flow_mat material mattext") {
 3185:             $$settings{$id}{$list}{$answer_id}{text} = $text;
 3186:         }
 3187: 
 3188: # Numerical
 3189:         if ("@state" eq "questestinterop section item presentation material mat_extension webct:x_webct_v01_dynamicmattext") {
 3190:             $$settings{$id}{text} = $text;
 3191:         }
 3192:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_minvalue webct:x_webct_v01_variable") {
 3193:              $$settings{$id}{$numid}{vars}{$currvar}{min} = $text;
 3194:         }
 3195:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_maxvalue webct:x_webct_v01_variable") {
 3196:              $$settings{$id}{$numid}{vars}{$currvar}{max} = $text;
 3197:         }
 3198:         if ("@state" eq "questestinterop section item presentation response_num material mat_extension webct:x_webct_v01_dynamicdata webct:x_webct_v01_datarange webct:x_webct_v01_decimalnum webct:x_webct_v01_variable") {
 3199:              $$settings{$id}{$numid}{vars}{$currvar}{dec} = $text;
 3200:         }
 3201:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_formula") {
 3202:             $$settings{$id}{$numid}{formula} = $text;
 3203:         }
 3204:         if ("@state" eq "questestinterop section item resprocessing respcondition conditionvar varequal") {
 3205:             if ($$settings{$id}{class} eq 'string') {
 3206:                 unless (grep/^$text$/,@{$$settings{$id}{strings}{$label}}) {
 3207:                     push(@{$$settings{$id}{strings}{$label}},$text);
 3208:                 }
 3209:                 unless (grep/^$text$/,@{$$settings{$id}{boxes}[$boxnum]}) {
 3210:                     push(@{$$settings{$id}{boxes}[$boxnum]},$text);
 3211:                 }
 3212:             } else {
 3213:                 $answer_id = $text;
 3214:             }
 3215:         }
 3216:         if ("@state" eq "questestinterop section item resprocessing respcondition conditionvar varsubset") { # String
 3217:             unless (grep/^$text$/,@{$$settings{$id}{strings}{$label}}) {
 3218:                 push(@{$$settings{$id}{strings}{$label}},$text);
 3219:             }
 3220:             unless (grep/^$text$/,@{$$settings{$id}{boxes}[$boxnum]}) {
 3221:                 push(@{$$settings{$id}{boxes}[$boxnum]},$text);
 3222:             }
 3223:         }
 3224:         if ("@state" eq "questestinterop section item resprocessing respcondition setvar") {
 3225:             if ($setvar{varname} eq "answerValue") { # Multiple Choice WebCT4.0
 3226:                 if ($text =~ m/^\d+$/) {
 3227:                     if ($text > 0) {
 3228:                         push(@{$$settings{$id}{$list}{correctanswer}},$answer_id);   
 3229:                     }
 3230:                 }
 3231:             } elsif ($setvar{varname} eq "que_score") { # Multiple Choice WebCT4.1
 3232:                 if ($text =~ m/^\d+$/) {
 3233:                     if ($text > 0) {
 3234:                         push(@{$$settings{$id}{$list}{correctanswer}},$answer_id);
 3235:                     }
 3236:                 }
 3237:             } elsif ($is_objectbank) { #Multiple Choice WebCT 4.1 D2L objectbank
 3238:                 if ($setvar{action} eq "Set") {
 3239:                     if ($text =~ /^\d+\.?\d*$/) {
 3240:                         if ($text > 0.000000001) {
 3241:                             push(@{$$settings{$id}{$list}{correctanswer}},$answer_id);
 3242:                         }
 3243:                     }
 3244:                 }
 3245:             }
 3246:         }
 3247:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_anstolerance") {
 3248:             $$settings{$id}{$numid}{tolerance} = $text;
 3249:         }
 3250:         if ("@state" eq "questestinterop section item resprocessing itemproc_extension webct:x_webct_v01_autocalculate webct:x_webct_v01_unit") {
 3251:             $$settings{$id}{$numid}{$unitid}{text} = $text;
 3252:         }
 3253: 
 3254:         if ("@state" eq "questestinterop section item itemfeedback material mattext") {
 3255:             $$settings{$id}{$fdbk}{text} = $text;
 3256:         }
 3257:       }, "dtext"],
 3258:      end_h =>
 3259:      [sub {
 3260:         my ($tagname) = @_;
 3261:         if (("@state" eq "questestinterop") && ($tagname eq 'objectbank')) {
 3262:             $is_objectbank = '';
 3263:         } else {
 3264:             pop @state;
 3265:         }
 3266:      }, "tagname"],
 3267:     );
 3268:     $p->unbroken_text(1);
 3269:     $p->parse_file($xmlfile);
 3270:     $p->eof;
 3271:     my $boxcount;
 3272:     foreach my $id (keys(%{$settings})) {
 3273:         if ($$settings{$id}{class} eq 'string') {
 3274:             $boxcount = 0;
 3275:             if (@{$$settings{$id}{boxes}} > 1) {
 3276:                 foreach my $str_id (@{$$settings{$id}{str}}) {
 3277:                     foreach my $label (@{$$settings{$id}{$str_id}{labels}}) {
 3278:                         @{$$settings{$id}{strings}{$label}} = @{$$settings{$id}{boxes}[$boxcount]};
 3279:                         $boxcount ++;
 3280:                     }
 3281:                 }
 3282:             }
 3283:         } elsif ($$settings{$id}{class} eq 'multiplechoice') {
 3284:             if (ref($$settings{$id}) eq 'HASH') {
 3285:                 foreach my $list (keys(%{$$settings{$id}})) {
 3286:                     if (ref($$settings{$id}{$list}) eq 'HASH') {
 3287:                         if (defined($$settings{$id}{$list}{rcardinality})) {
 3288:                             if ($$settings{$id}{$list}{rcardinality} eq 'Multiple') {
 3289:                                 if (ref($$settings{$id}{$list}{correctanswer}) eq 'ARRAY') {
 3290:                                     if (@{$$settings{$id}{$list}{correctanswer}} == 1) {
 3291:                                         $$settings{$id}{$list}{rcardinality} = 'Single';
 3292:                                     }
 3293:                                 }
 3294:                             }
 3295:                         }
 3296:                     }
 3297:                 }
 3298:             }
 3299:         }
 3300:     }
 3301: }
 3302: 
 3303: sub process_assessment {
 3304:     my ($cms,$context,$res,$docroot,$container,$dirname,$destdir,$settings,$total,$udom,$uname,$pagesfiles,$sequencesfiles,$randompicks,$dbparse,$resources,$items,$catinfo,$qzdbsettings,$hrefs,$allquestions) = @_;
 3305:     my @allids = ();
 3306:     my @allquestids = ();
 3307:     my %allanswers = ();
 3308:     my %allchoices = ();
 3309:     my %qzparams = ();
 3310:     my %alldbanswers = ();
 3311:     my %alldbchoices = ();
 3312:     my @alldbquestids = ();
 3313:     my $containerdir;
 3314:     my $newdir;
 3315:     my $randompickflag = 0;
 3316:     my ($cid,$cdom,$cnum);
 3317:     if ($context eq 'DOCS') {
 3318:         $cid = $env{'request.course.id'};
 3319:         ($cdom,$cnum) = split/_/,$cid;
 3320:     }
 3321:     my $destresdir = $destdir;
 3322:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
 3323:     if ($context eq 'CSTR') {
 3324:         $destresdir =~ s{^\Q$londocroot/priv/\E}{/res/};
 3325:     } elsif ($context eq 'DOCS') {
 3326:         $destresdir =~ s{^\Q$londocroot/userfiles\E}{/uploaded};
 3327:     }
 3328:     if ($cms eq 'bb5') {
 3329:         &parse_bb5_assessment($res,$docroot,$container,$settings,\%allanswers,\%allchoices,\@allids);
 3330:     } elsif ($cms eq 'bb6') {
 3331:         &parse_bb6_assessment($res,$docroot,$container,$settings,\@allids);
 3332:     } elsif ($cms eq 'webctce4') {
 3333:         unless($$dbparse) {
 3334:             &parse_webct4_questionDB($docroot,$$resources{$res}{file},$catinfo,$qzdbsettings,\%alldbanswers,\%alldbchoices,\@alldbquestids);
 3335:             &build_category_sequences($destdir,$catinfo,$sequencesfiles,$pagesfiles,$destresdir,$newdir,$cms,$total,$randompickflag,$context,$udom,$uname,$dirname,$cid,$cdom,$cnum,$qzdbsettings);
 3336:             &write_webct4_questions($cms,\@alldbquestids,$context,$qzdbsettings,$dirname,\%alldbanswers,\%alldbchoices,$total,$cid,$cdom,$cnum,$destdir,$catinfo);
 3337:             $$dbparse = 1;
 3338:         }
 3339:         &parse_webct4_assessment($res,$docroot,$$resources{$res}{file},$container,\@allids);
 3340:         &parse_webct4_quizprops($res,$docroot,$$hrefs{$$items{$$resources{$res}{revitm}}{properties}}[0],$container,\%qzparams);
 3341:         if (exists($qzparams{$res}{numpick})) { 
 3342:             if ($qzparams{$res}{numpick} < @allids) {
 3343:                 $$randompicks{$$resources{$res}{revitm}} = $qzparams{$res}{numpick};
 3344:                 $randompickflag = 1;
 3345:             }
 3346:         }
 3347:     } elsif ($cms eq 'webctvista4') {
 3348:         unless($$dbparse) {
 3349:             foreach my $res (sort(keys(%{$allquestions}))) {
 3350:                 my $parent = $$allquestions{$res};
 3351:                 &parse_webctvista4_question($res,$docroot,$resources,$hrefs,$qzdbsettings,\@allquestids,\%allanswers,\%allchoices,$parent,$catinfo);
 3352:             }
 3353:             &build_category_sequences($destdir,$catinfo,$sequencesfiles,$pagesfiles,$destresdir,$newdir,$cms,$total,$randompickflag,$context,$udom,$uname,$dirname,$cid,$cdom,$cnum,$qzdbsettings);
 3354:             $$dbparse = 1;
 3355:         }
 3356:         &parse_webctvista4_assessment($res,$docroot,$$resources{$res}{file},\@allids,\%qzparams);
 3357:         if ($qzparams{$res}{numpick} < @allids) {
 3358:             $$randompicks{$$resources{$res}{revitm}} = $qzparams{$res}{numpick};
 3359:             $randompickflag = 1;
 3360:         }
 3361:     }
 3362:     my $dirtitle;
 3363:     unless ($cms eq 'webctce4' || $cms eq 'webctvista4') {
 3364:         $dirtitle = $$settings{'title'};
 3365:         $dirtitle =~ s/\s+/_/g;
 3366:         $dirtitle =~ s/:/_/g;
 3367:         $dirtitle .= '_'.$res;
 3368:         if (!-e "$destdir/problems") {
 3369:             mkdir("$destdir/problems",0755);
 3370:         }
 3371:         if (!-e "$destdir/problems/$dirtitle") {
 3372:             mkdir("$destdir/problems/$dirtitle",0755);
 3373:         }
 3374:         $newdir = "$destdir/problems/$dirtitle";
 3375:     }
 3376: 
 3377:     if ($cms eq 'webctce4') {
 3378:         if (@allids > 0 && $allids[0] ne '') {
 3379:             &build_problem_container($cms,$dirtitle,$destdir,$container,$res,$total,$sequencesfiles,$pagesfiles,$randompickflag,$context,\@allids,$udom,$uname,$dirname,\$containerdir,$cid,$cdom,$cnum,$catinfo,$qzdbsettings);
 3380:         }
 3381:     } else {
 3382:         &build_problem_container($cms,$dirtitle,$destdir,$container,$res,$total,$sequencesfiles,$pagesfiles,$randompickflag,$context,\@allids,$udom,$uname,$dirname,\$containerdir,$cid,$cdom,$cnum,$catinfo,$qzdbsettings,\%qzparams);
 3383:     }
 3384:     if ($cms eq 'bb5') {
 3385:         &write_bb5_questions(\@allids,$containerdir,$context,$settings,$dirname,$destdir,$res,\%allanswers,\%allchoices,$total,$newdir,$cid,$cdom,$cnum,$docroot);
 3386:     } elsif ($cms eq 'bb6') {
 3387:         &write_bb6_questions(\@allids,$containerdir,$context,$settings,$dirname,$destdir,$res,$total,$newdir,$cid,$cdom,$cnum,$docroot);
 3388:     } elsif ($cms eq 'webctvista4') {
 3389:         &write_webct4_questions($cms,\@allquestids,$context,$qzdbsettings,$dirname,\%allanswers,\%allchoices,$total,$cid,$cdom,$cnum,$destdir,$catinfo,$dirtitle);
 3390:     }
 3391: }
 3392: 
 3393: sub build_category_sequences {
 3394:     my ($destdir,$catinfo,$sequencesfiles,$pagesfiles,$destresdir,$newdir,$cms,$total,$randompickflag,$context,$udom,$uname,$dirname,$cid,$cdom,$cnum,$qzdbsettings) = @_;
 3395:     if (!-e "$destdir/sequences") {
 3396:         mkdir("$destdir/sequences",0755);
 3397:     }
 3398:     my $numcats = scalar(keys(%{$catinfo}));
 3399:     my $curr_id = 0;
 3400:     my $next_id = 1;
 3401:     my $fh;
 3402:     open($fh,'>',"$destdir/sequences/question_database.sequence");
 3403:     push @{$sequencesfiles},'question_database.sequence';
 3404:     foreach my $category (sort(keys(%{$catinfo}))) {
 3405:         my $seqname;
 3406:         if ($cms eq 'webctce4') { 
 3407:             $seqname = $$catinfo{$category}{title}.'_'.$category;
 3408:         } else {
 3409:             $seqname = $$catinfo{$category}{title};
 3410:         }
 3411:         $seqname =~ s/\s+/_/g;
 3412:         $seqname =~ s/:/_/g;
 3413:         push(@{$sequencesfiles},$seqname.'.sequence');
 3414:         my $catsrc = "$destresdir/sequences/$seqname.sequence";
 3415:         if ($curr_id == 0) {
 3416:             print $fh qq|<resource id="1" src="$catsrc" type="start" title="$$catinfo{$category}{title}"></resource>|;
 3417:         }
 3418:         if ($numcats == 1) {
 3419:             print $fh qq|
 3420: <link from="1" to="2" index="1"></link>
 3421: <resource id="2" src="" type="finish">\n|;
 3422:         } else {
 3423:             $curr_id = $next_id;
 3424:             $next_id = $curr_id + 1;
 3425:             $catsrc = "$destresdir/sequences/$seqname.sequence";
 3426:             print $fh qq|
 3427: <link from="$curr_id" to="$next_id" index="$curr_id"></link>
 3428: <resource id="$next_id" src="$catsrc" title="$$catinfo{$category}{title}"|;
 3429:             if ($next_id == $numcats) {
 3430:                 print $fh qq| type="finish"></resource>\n|;
 3431:             } else {
 3432:                 print $fh qq|></resource>\n|;
 3433:             }
 3434:         }
 3435:         print $fh qq|</map>|;
 3436:         if (!-e "$destdir/problems") {
 3437:             mkdir("$destdir/problems",0755);
 3438:         }
 3439:         if (!-e "$destdir/problems/$seqname") {
 3440:             mkdir("$destdir/problems/$seqname",0755);
 3441:         }
 3442:         $$newdir = "$destdir/problems/$seqname";
 3443:         my $dbcontainerdir;
 3444:         &build_problem_container($cms,$seqname,$destdir,'database',$seqname,$total,$sequencesfiles,$pagesfiles,$randompickflag,$context,\@{$$catinfo{$category}{contents}},$udom,$uname,$dirname,\$dbcontainerdir,$cid,$cdom,$cnum,$catinfo,$qzdbsettings);
 3445:     }
 3446:     close($fh);
 3447: }
 3448: 
 3449: sub build_problem_container {
 3450:     my ($cms,$dirtitle,$destdir,$container,$res,$total,$sequencesfiles,$pagesfiles,$randompickflag,$context,$allids,$udom,$uname,$dirname,$containerdir,$cid,$cdom,$cnum,$catinfo,$settings,$qzparams) = @_;
 3451:     my $seqdir = "$destdir/sequences";
 3452:     my $pagedir = "$destdir/pages";
 3453:     my $curr_id = 0;
 3454:     my $next_id = 1;
 3455:     my $fh;
 3456:     my $mapname = $res;
 3457:     if ($cms eq 'webctvista4' && ref($$qzparams{$res}) eq 'HASH') {
 3458:         if ($$qzparams{$res}{title}) {
 3459:             $mapname = $$qzparams{$res}{title};
 3460:             $mapname =~ s/\s+/_/g;
 3461:         }
 3462:     }
 3463:     if ($container eq 'pool' || $randompickflag || $container eq 'database') {
 3464:         $$containerdir = $seqdir.'/'.$mapname.'.sequence';
 3465:         if (!-e "$seqdir") {
 3466:             mkdir("$seqdir",0770);
 3467:         }
 3468:         open($fh,'>',$$containerdir);
 3469:         $$total{seq} ++;
 3470:         push @{$sequencesfiles},$mapname.'.sequence';
 3471:     } else {
 3472:         $$containerdir = $pagedir.'/'.$mapname.'.page';
 3473:         if (!-e "$pagedir") {
 3474:             mkdir("$pagedir",0770);
 3475:         }
 3476:         open($fh,'>',$$containerdir);
 3477:         $$total{page} ++;
 3478:         push @{$pagesfiles},$mapname.'.page';
 3479:     }
 3480:     print $fh qq|<map>
 3481: |;
 3482:     my %probtitle = ();
 3483:     my $probsrc = "/res/lib/templates/simpleproblem.problem";
 3484:     if ($context eq 'CSTR') {
 3485:         foreach my $id (@{$allids}) {
 3486:             if (($cms eq 'webctce4') || ($cms eq 'webctvista4')) {
 3487:                 $probtitle{$id} = $$settings{$id}{title};
 3488:             } else {
 3489:                 $probtitle{$id} = $$settings{title};
 3490:             }
 3491:             $probtitle{$id} =~ s/\s+/_/g;
 3492:             $probtitle{$id} =~ s/:/_/g;
 3493:             $probtitle{$id} =~ s/\//_/g;
 3494:             if ($cms eq 'webctce4') {
 3495:                 $probtitle{$id} .= '_'.$id;
 3496:             }
 3497:         }
 3498:         if (($cms eq 'webctce4' && $container ne 'database') ||
 3499:             ($cms eq 'webctvista4'))   {
 3500:             my $probdir;
 3501:             my $catid = $$settings{$$allids[0]}{category};
 3502:             if ($catid) {
 3503:                 if ($cms eq 'webctce4') { 
 3504:                     $probdir = $$catinfo{$catid}{title}.'_'.$catid;
 3505:                 } else {
 3506:                     $probdir = $$catinfo{$catid}{title};
 3507:                 }
 3508:                 $probdir =~ s/\s+/_/g;
 3509:                 $probdir =~ s/:/_/g;
 3510:                 $probsrc = "$dirname/problems/$probdir/$probtitle{$$allids[0]}.problem";
 3511:             } else {
 3512:                 $probsrc="$dirname/problems/$dirtitle/$probtitle{$$allids[0]}.problem";
 3513:             }
 3514:         } else {
 3515:             $probsrc="$dirname/problems/$dirtitle/$probtitle{$$allids[0]}.problem";
 3516:         }
 3517:     }
 3518:     print $fh qq|<resource id="1" src="$probsrc" type="start" title="question_0001"></resource>|;
 3519:     if (@{$allids} == 1) {
 3520:         print $fh qq|
 3521: <link from="1" to="2" index="1"></link>
 3522: <resource id="2" src="" type="finish">\n|;
 3523:     } else {
 3524:         for (my $j=1; $j<@{$allids}; $j++) {
 3525:             my $qntitle = $j+1;
 3526:             while (length($qntitle) <4) {
 3527:                 $qntitle = '0'.$qntitle;
 3528:             }
 3529:             $curr_id = $j;
 3530:             $next_id = $curr_id + 1;
 3531:             if ($context eq 'CSTR') {
 3532:                 if (($cms eq 'webctce4' && $container ne 'database') ||
 3533:                     ($cms eq 'webctvista4')) {
 3534:                     my $probdir;
 3535:                     my $catid = $$settings{$$allids[$j]}{category};
 3536:                     if ($catid) {
 3537:                         if ($cms eq 'webctce4') {
 3538:                             $probdir = $$catinfo{$catid}{title}.'_'.$catid;
 3539:                         } else {
 3540:                             $probdir = $$catinfo{$catid}{title};
 3541:                         }
 3542:                         $probdir =~ s/\s/_/g;
 3543:                         $probdir =~ s/:/_/g;
 3544:                         $probsrc = "$dirname/problems/$probdir/$probtitle{$$allids[$j]}.problem";
 3545:                     } else {
 3546:                         $probsrc = "$dirname/problems/$dirtitle/$probtitle{$$allids[$j]}.problem";
 3547:                     }
 3548:                 } else {
 3549:                     $probsrc = "$dirname/problems/$dirtitle/$probtitle{$$allids[$j]}.problem";
 3550:                 }
 3551:             }
 3552:             print $fh qq|
 3553: <link from="$curr_id" to="$next_id" index="$curr_id"></link>
 3554: <resource id="$next_id" src="$probsrc" title="question_$qntitle"|;
 3555:             if ($next_id == @{$allids}) {
 3556:                 print $fh qq| type="finish"></resource>\n|;
 3557:             } else {
 3558:                 print $fh qq|></resource>|;
 3559:             }
 3560:         }
 3561:     }
 3562:     print $fh qq|</map>|;
 3563:     close($fh);
 3564: }
 3565: 
 3566: sub write_bb5_questions {
 3567:     my ($allids,$containerdir,$context,$settings,$dirname,$destdir,$res,$allanswers,$allchoices,$total,$newdir,$cid,$cdom,$cnum,$docroot) = @_;
 3568:     my $qnum = 0;
 3569:     my $pathstart;
 3570:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
 3571:     if ($context eq 'CSTR') {
 3572:         $pathstart = '../..';
 3573:     } else {
 3574:         $pathstart = $dirname;
 3575:     }
 3576:     foreach my $id (@{$allids}) {
 3577:         if ($$settings{$id}{ishtml} eq 'true') {
 3578:             $$settings{$id}{text} = &HTML::Entities::decode($$settings{$id}{text});
 3579:         }
 3580:         if ($$settings{$id}{text} =~ m#<img src=['"]?(https?://[^\s]+/)([^/\s\'"]+)['"]?[^>]*>#) {
 3581:             if (&retrieve_image($context,$res,$dirname,$cdom,$cnum,$docroot,$destdir,$1,$2) eq 'ok') {
 3582:                 $$settings{$id}{text} =~ s#(<img src=['"]?)(https?://[^\s]+/)([^/\s'"]+)(['"]?[^>]*>)#$1$pathstart/resfiles/$res/webimages/$3$4#g;
 3583:             }
 3584:         }
 3585:         $$settings{$id}{text} =~ s#(<img src=[^>]+)/*>#$1 />#gi;
 3586:         $$settings{$id}{text} =~ s#<br>#<br />#g;
 3587:         $qnum ++;
 3588:         my $output;
 3589:         my $permcontainer = $containerdir;
 3590:         $permcontainer =~ s{^\Q$londocroot/userfiles\E}{uploaded};
 3591:         my $symb = $cid.'.'.$permcontainer.'___'.$qnum.'___lib/templates/simpleproblem.problem.0.';
 3592:         my %resourcedata = ();
 3593:         for (my $i=0; $i<10; $i++) {
 3594:             my $iter = $i+1;
 3595:             $resourcedata{$symb.'text'.$iter} = "";
 3596:             $resourcedata{$symb.'value'.$iter} = "unused";
 3597:             $resourcedata{$symb.'position'.$iter} = "random";
 3598:         }
 3599:         $resourcedata{$symb.'randomize'} = 'yes';
 3600:         $resourcedata{$symb.'maxfoils'} = 10;
 3601:         if ($context eq 'CSTR') {
 3602:             $output = qq|<problem>
 3603: |;
 3604:         }
 3605:         $$total{prob} ++;
 3606:         if ($$settings{$id}{class} eq "QUESTION_ESSAY") {
 3607:             if ($context eq 'CSTR') {
 3608:                 $output .= qq|<startouttext />$$settings{$id}{text}<endouttext />
 3609:  <essayresponse>
 3610:  <textfield></textfield>
 3611:  </essayresponse>
 3612:  <postanswerdate>
 3613:   $$settings{$id}{feedbackcorr} 
 3614:  </postanswerdate>
 3615: |;
 3616:              } else {
 3617: 		 $resourcedata{$symb.'questiontext'} = $$settings{$id}{text};
 3618:                  $resourcedata{$symb.'hiddenparts'} = '!essay';
 3619:                  $resourcedata{$symb.'questiontype'} = 'essay';
 3620:              }
 3621:         } else {
 3622:             if ($context eq 'CSTR') {
 3623:                 $output .= qq|<startouttext />$$settings{$id}{text}\n|;
 3624:             } else {
 3625:                 $resourcedata{$symb.'questiontext'} = $$settings{$id}{text};
 3626:             }
 3627:             my ($image,$imglink,$url);
 3628:             if ( defined($$settings{$id}{image}) ) {
 3629:                 if ( $$settings{$id}{style} eq 'embed' ) {
 3630:                     $image = qq|<br /><img src="$pathstart/resfiles/$res/$$settings{$id}{image}" /><br />|;
 3631:                 } else {
 3632:                     $imglink = qq|<br /><a href="$pathstart/resfiles/$res/$$settings{$id}{image}">Link to file</a><br />|;
 3633:                 }
 3634:             }
 3635:             if ( defined($$settings{$id}{url}) ) {
 3636:                 $url = qq|<br /><a href="$$settings{$id}{url}">$$settings{$id}{name}</a><br />|;
 3637:             }
 3638:             if ($context eq 'CSTR') {
 3639:                 $output .= $image.$imglink.$url.'
 3640: <endouttext />';
 3641:             } else {
 3642:                 $resourcedata{$symb.'questiontext'} .= $image.$imglink.$url;
 3643:             }
 3644:             if ($$settings{$id}{class} eq 'QUESTION_MULTIPLECHOICE') {
 3645:                 my $numfoils = @{$$allanswers{$id}};
 3646:                 if ($context eq 'CSTR') {
 3647:                     $output .= qq|
 3648:  <radiobuttonresponse max="$numfoils" randomize="yes">
 3649:   <foilgroup>
 3650: |;
 3651:                 } else {
 3652:                     $resourcedata{$symb.'hiddenparts'} = '!radio';
 3653:                     $resourcedata{$symb.'questiontype'} = 'radio';
 3654:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 3655:                 }
 3656:                 for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3657:                     my $iter = $k+1;
 3658:                     $output .= "   <foil name=\"foil".$k."\" value=\"";
 3659:                     if (grep/^$$allanswers{$id}[$k]$/,@{$$settings{$id}{correctanswer}}) {
 3660:                         $output .= "true\" location=\"";
 3661:                         $resourcedata{$symb.'value'.$iter} = "true";
 3662:                     } else {
 3663:                         $output .= "false\" location=\"";
 3664:                         $resourcedata{$symb.'value'.$iter} = "false";
 3665:                     }
 3666:                     if (lc ($$allanswers{$id}[$k]) =~ m/^\s?([Aa]ll)|([Nn]one)\s(of\s)?the\sabove\.?/) {
 3667:                         $output .= "bottom\"";
 3668:                         $resourcedata{$symb.'position'.$iter} = "bottom";
 3669:                     } else {
 3670:                         $output .= "random\"";
 3671:                     }
 3672:                     $output .= "\><startouttext />".$$settings{$id}{$$allanswers{$id}[$k]}{text};
 3673:                     $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3674:                     my ($ans_image,$ans_link);
 3675:                     if ( defined($$settings{$id}{$$allanswers{$id}[$k]}{image}) ) {
 3676:                         if ( $$settings{$id}{$$allanswers{$id}[$k]}{style} eq 'embed' ) {
 3677:                             $ans_image .= qq|<br /><img src="$pathstart/resfiles/$res/$$settings{$id}{$$allanswers{$id}[$k]}{image}" /><br />|;
 3678:                         } else {
 3679:                             $ans_link .= qq|<br /><a href="$pathstart/resfiles/$res/$$settings{$id}{$$allanswers{$id}[$k]}{image}" />Link to file</a><br/>|;
 3680:                         }
 3681:                     }
 3682:                     $output .= $ans_image.$ans_link.'<endouttext /></foil>'."\n";
 3683:                     $resourcedata{$symb.'text'.$iter} .= $ans_image.$ans_link;
 3684:                 }
 3685:                 if ($context eq 'CSTR') {
 3686:                     chomp($output);
 3687:                     $output .= qq|
 3688:   </foilgroup>
 3689:  </radiobuttonresponse>
 3690: |;
 3691:                 }
 3692:             } elsif ($$settings{$id}{class} eq 'QUESTION_TRUEFALSE') {
 3693:                 my $numfoils = @{$$allanswers{$id}};
 3694:                 if ($context eq 'CSTR') {
 3695:                     $output .= qq|
 3696:    <radiobuttonresponse max="$numfoils" randomize="yes">
 3697:     <foilgroup>
 3698: |;
 3699:                 } else {
 3700:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 3701:                     $resourcedata{$symb.'hiddenparts'} = '!radio';
 3702:                     $resourcedata{$symb.'questiontype'} = 'radio';
 3703:                 }
 3704:                 for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3705:                     my $iter = $k+1;
 3706:                     $output .= "   <foil name=\"foil".$k."\" value=\"";
 3707:                     if (grep/^$$allanswers{$id}[$k]$/,@{$$settings{$id}{correctanswer}}) {
 3708:                         $output .= "true\" location=\"random\"";
 3709:                         $resourcedata{$symb.'value'.$iter} = "true";
 3710:                     } else {
 3711:                         $output .= "false\" location=\"random\"";
 3712:                         $resourcedata{$symb.'value'.$iter} = "false";
 3713:                     }
 3714:                     $output .= "\><startouttext />".$$settings{$id}{$$allanswers{$id}[$k]}{text}."<endouttext /></foil>\n";
 3715:                     $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3716:                 }
 3717:                 if ($context eq 'CSTR') {
 3718:                     chomp($output);
 3719:                     $output .= qq|
 3720:     </foilgroup>
 3721:    </radiobuttonresponse>
 3722: |;
 3723:                 }
 3724:             } elsif ($$settings{$id}{class} eq 'QUESTION_MULTIPLEANSWER') {
 3725:                 my $numfoils = @{$$allanswers{$id}};
 3726:                 if ($context eq 'CSTR') {
 3727:                     $output .= qq|
 3728:    <optionresponse max="$numfoils" randomize="yes">
 3729:     <foilgroup options="('True','False')">
 3730: |;
 3731:                 } else {
 3732:                     $resourcedata{$symb.'newopt'} = '';
 3733:                     $resourcedata{$symb.'delopt'} = '';
 3734:                     $resourcedata{$symb.'options'} = "('True','False')";
 3735:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 3736:                     $resourcedata{$symb.'questiontype'} = 'option';
 3737:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 3738:                 }
 3739:                 for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3740:                     my $iter = $k+1;
 3741:                     $output .= "   <foil name=\"foil".$k."\" value=\"";
 3742:                     if (grep/^$$allanswers{$id}[$k]$/,@{$$settings{$id}{correctanswer}}) {
 3743:                         $output .= "True\"";
 3744:                         $resourcedata{$symb.'value'.$iter} = "True";
 3745:                     } else {
 3746:                         $output .= "False\"";
 3747:                         $resourcedata{$symb.'value'.$iter} = "False";
 3748:                     }
 3749:                     $output .= "\><startouttext />".$$settings{$id}{$$allanswers{$id}[$k]}{text}."<endouttext /></foil>\n";
 3750:                     $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3751:                 }
 3752:                 if ($context eq 'CSTR') {  
 3753:                     chomp($output);
 3754:                     $output .= qq|
 3755:     </foilgroup>
 3756:    </optionresponse>
 3757: |;
 3758:                 }
 3759:             } elsif ($$settings{$id}{class} eq 'QUESTION_ORDER') {
 3760:                 my $numfoils = @{$$allanswers{$id}};
 3761:                 my @allorder = ();
 3762:                 if ($context eq 'CSTR') {
 3763:                     $output .= qq|
 3764:    <rankresponse max="$numfoils" randomize="yes">
 3765:     <foilgroup>
 3766: |;
 3767:                 } else {
 3768:                     $resourcedata{$symb.'newopt'} = '';
 3769:                     $resourcedata{$symb.'delopt'} = '';
 3770:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 3771:                     $resourcedata{$symb.'questiontype'} = 'option';
 3772:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 3773:                 }
 3774:                 for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3775:                     if ($context eq 'CSTR') {
 3776:                         $output .= "   <foil location=\"random\" name=\"foil".$k."\" value=\"".$$settings{$id}{$$allanswers{$id}[$k]}{order}."\"><startouttext />".$$settings{$id}{$$allanswers{$id}[$k]}{text}."<endouttext /></foil>\n";
 3777:                     } else {
 3778:                         my $iter = $k+1;
 3779:                         $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3780:                         if (!grep/^$$settings{$id}{$$allanswers{$id}[$k]}{order}$/,@allorder) {
 3781:                             push @allorder, $$settings{$id}{$$allanswers{$id}[$k]}{order};
 3782:                         }
 3783:                     }
 3784:                 }
 3785:                 if ($context eq 'CSTR') {
 3786:                     chomp($output);
 3787:                     $output .= qq|
 3788:     </foilgroup>
 3789:    </rankresponse>
 3790: |;
 3791:                 } else {
 3792:                     @allorder = sort {$a <=> $b} @allorder;
 3793:                     $resourcedata{$symb.'options'} = "('".join("','",@allorder)."')";
 3794:                 }
 3795:             } elsif ($$settings{$id}{class} eq 'QUESTION_FILLINBLANK') {
 3796:                 my $numerical = 1;
 3797:                 if ($context eq 'DOCS') {
 3798:                     $numerical = 0;
 3799:                 } else {
 3800:                     for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3801:                         if ($$settings{$id}{$$allanswers{$id}[$k]}{text} =~ m/([^\d\.]|\.\.)/) {
 3802:                             $numerical = 0;
 3803:                         }
 3804:                     }
 3805:                 }
 3806:                 if ($numerical) {
 3807:                     my $numans;
 3808:                     my $tol;
 3809:                     if (@{$$allanswers{$id}} == 1) {
 3810:                         $tol = 5;
 3811:                         $numans = $$settings{$id}{$$allanswers{$id}[0]}{text};
 3812:                     } else {
 3813:                         my $min = $$settings{$id}{$$allanswers{$id}[0]}{text};
 3814:                         my $max = $$settings{$id}{$$allanswers{$id}[0]}{text};
 3815:                         for (my $k=1; $k<@{$$allanswers{$id}}; $k++) {
 3816:                             if ($$settings{$id}{$$allanswers{$id}[$k]}{text} <= $min) {
 3817:                                 $min = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3818:                             }
 3819:                             if ($$settings{$id}{$$allanswers{$id}[$k]}{text} >= $max) {
 3820:                                 $max = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3821:                             }
 3822:                         }
 3823:                         $numans = ($max + $min)/2;
 3824:                         $tol = 100*($max - $min)/($numans*2);
 3825:                     }
 3826:                     if ($context eq 'CSTR') {
 3827:                         $output .= qq|
 3828: <numericalresponse answer="$numans">
 3829:         <responseparam type="tolerance" default="$tol%" name="tol" description="Numerical Tolerance" />
 3830:         <responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures"
 3831: />
 3832:         <textline />
 3833: </numericalresponse>
 3834: |;
 3835:                     }
 3836:                 } else {
 3837:                     if ($context eq 'DOCS') {
 3838:                         $resourcedata{$symb.'hiddenparts'} = '!string';
 3839:                         $resourcedata{$symb.'questiontype'} = 'string';
 3840:                         $resourcedata{$symb.'maxfoils'} = @{$$allanswers{$id}};
 3841:                         $resourcedata{$symb.'hiddenparts'} = '!string';
 3842:                         $resourcedata{$symb.'stringtype'} = 'ci';
 3843:                         $resourcedata{$symb.'stringanswer'} = $$settings{$id}{$$allanswers{$id}[0]}{text};
 3844:                     } else {
 3845:                         if (@{$$allanswers{$id}} == 1) {
 3846:                             $output .= qq|
 3847: <stringresponse answer="$$settings{$id}{$$allanswers{$id}[0]}{text}" type="ci">
 3848: <textline>
 3849: </textline>
 3850: </stringresponse>
 3851: |;
 3852:                         } else {
 3853:                             my @answertext = ();
 3854:                             for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3855:                                 $$settings{$id}{$$allanswers{$id}[$k]}{text} =~ s/\|/\|/g;
 3856:                                 push @answertext, $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3857:                             }
 3858:                             my $regexpans = join('|',@answertext);
 3859:                             $regexpans = '/^('.$regexpans.')\b/';
 3860:                             $output .= qq|
 3861: <stringresponse answer="$regexpans" type="re">
 3862: <textline>
 3863: </textline>
 3864: </stringresponse>
 3865: |;
 3866:                         }
 3867:                     } 
 3868:                 }
 3869:             } elsif ($$settings{$id}{class} eq "QUESTION_MATCH") {
 3870:                 my @allmatchers = ();
 3871:                 my %matchtext = ();
 3872:                 if ($context eq 'CSTR') {
 3873:                     $output .= qq|
 3874: <matchresponse max="10" randomize="yes">
 3875:     <foilgroup>
 3876:         <itemgroup>
 3877: |;
 3878:                 } else {
 3879:                     $resourcedata{$symb.'newopt'} = '';
 3880:                     $resourcedata{$symb.'delopt'} = '';
 3881:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 3882:                     $resourcedata{$symb.'questiontype'} = 'option';
 3883:                     $resourcedata{$symb.'maxfoils'} =  @{$$allanswers{$id}};
 3884:                 }
 3885:                 for (my $k=0; $k<@{$$allchoices{$id}}; $k++) {
 3886:                     if ($context eq 'CSTR') {
 3887:                         $output .= qq|
 3888: <item name="$$allchoices{$id}[$k]">
 3889: <startouttext />$$settings{$id}{$$allchoices{$id}[$k]}{text}<endouttext />
 3890: </item>
 3891:                     |;
 3892:                     } else {
 3893:                         if (!grep/^$$settings{$id}{$$allchoices{$id}[$k]}{text}$/,@allmatchers) {
 3894:                             push @allmatchers, $$settings{$id}{$$allchoices{$id}[$k]}{text};
 3895:                             $matchtext{$$allchoices{$id}[$k]} = $$settings{$id}{$$allchoices{$id}[$k]}{text};
 3896:                         }
 3897:                     }
 3898:                 }
 3899:                 if ($context eq 'CSTR') {
 3900:                     $output .= qq|
 3901:         </itemgroup>
 3902: |;
 3903:                 }
 3904:                 for (my $k=0; $k<@{$$allanswers{$id}}; $k++) {
 3905:                     if ($context eq 'CSTR') {
 3906:                         $output .= qq|
 3907:         <foil location="random" value="$$settings{$id}{$$allanswers{$id}[$k]}{choice_id}" name="$$allanswers{$id}[$k]">
 3908:          <startouttext />$$settings{$id}{$$allanswers{$id}[$k]}{text}<endouttext />
 3909:         </foil>
 3910: |;
 3911:                     } else {
 3912:                         my $iter = $k+1;
 3913:                         $resourcedata{$symb.'value'.$iter} = $matchtext{$$settings{$id}{$$allanswers{$id}[$k]}{choice_id}};
 3914:                         $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allanswers{$id}[$k]}{text};
 3915:                     }
 3916:                 }
 3917:                 if ($context eq 'CSTR') {
 3918:                     $output .= qq|
 3919:     </foilgroup>
 3920: </matchresponse>
 3921: |;
 3922:                 } else {
 3923:                     $resourcedata{$symb.'options'} = "('".join("','",@allmatchers)."')";
 3924:                 }
 3925:             }
 3926:         }
 3927:         if ($context eq 'CSTR') {
 3928:             $output .= qq|</problem>
 3929: |;
 3930:             my $title = $$settings{title};
 3931:             $title =~ s/\s/_/g;
 3932:             $title =~ s/\W//g;
 3933:             $title .= '_'.$id;
 3934:             open(PROB,'>',"$newdir/$title.problem");
 3935:             print PROB $output;
 3936:             close PROB;
 3937:         } else {
 3938: # put %resourcedata;
 3939:             my $reply=&Apache::lonnet::cput
 3940:                 ('resourcedata',\%resourcedata,$cdom,$cnum);
 3941:         }
 3942:     }
 3943: }
 3944: 
 3945: sub write_webct4_questions {
 3946:     my ($cms,$alldbquestids,$context,$settings,$dirname,$allanswers,$allchoices,$total,$cid,$cdom,$cnum,$destdir,$catinfo,$dirtitle) = @_;
 3947:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
 3948:     my $qnum = 0;
 3949:     foreach my $id (@{$alldbquestids}) {
 3950:         $qnum ++;
 3951:         my $output;
 3952:         my $permcontainer = $destdir.'/sequences/'.$id.'.sequence';
 3953:         my $allfeedback;
 3954:         my $questionimage;
 3955:         foreach my $fdbk (@{$$settings{$id}{feedback}}) {
 3956:             my $feedback =  $$settings{$id}{$fdbk}{text};
 3957:             if ($feedback ne '') {
 3958:                 if ($$settings{$id}{$fdbk}{texttype} eq 'text/html') {
 3959:                     $feedback = &HTML::Entities::decode($feedback);
 3960:                 }
 3961:                 $allfeedback .= $feedback;
 3962:             }
 3963:         }
 3964:         if ($$settings{$id}{texttype} eq 'text/html') {
 3965:             if ($$settings{$id}{text}) {
 3966:                 $$settings{$id}{text} = &text_cleanup($$settings{$id}{text});
 3967:             }
 3968:         } 
 3969:         if ($$settings{$id}{class} eq 'numerical') {
 3970:             foreach my $numid (@{$$settings{$id}{numids}}) {
 3971:                 foreach my $var (keys(%{$$settings{$id}{$numid}{vars}})) {
 3972:                     if ($cms eq 'webctce4') {
 3973:                         $$settings{$id}{text} =~ s/{($var)}/\$$1 /g;
 3974:                     } elsif ($cms eq 'webctvista4') {
 3975:                         $$settings{$id}{text} =~ s/\[($var)\]/\$$1 /g;
 3976:                     }
 3977:                 }
 3978:             }
 3979:         }
 3980:         $permcontainer =~ s{\Q$londocroot/userfiles\E}{uploaded};
 3981:         my $symb = $cid.'.'.$permcontainer.'___'.$qnum.'___lib/templates/simpleproblem.problem.0.';
 3982:         my %resourcedata = ();
 3983:         for (my $i=0; $i<10; $i++) {
 3984:             my $iter = $i+1;
 3985:             $resourcedata{$symb.'text'.$iter} = "";
 3986:             $resourcedata{$symb.'value'.$iter} = "unused";
 3987:             $resourcedata{$symb.'position'.$iter} = "random";
 3988:         }
 3989:         $resourcedata{$symb.'randomize'} = 'yes';
 3990:         $resourcedata{$symb.'maxfoils'} = 10;
 3991:         if ($context eq 'CSTR') {
 3992:             unless ($$settings{$id}{class} eq 'numerical') {
 3993:                 $output = qq|<problem>
 3994: |;
 3995:             }
 3996:         }
 3997:         $$total{prob} ++;
 3998: 
 3999:         if (exists($$settings{$id}{uri})) {
 4000:             if ($cms eq 'webctce4') {
 4001:                 if ($$settings{$id}{imagtype} =~ /^image\//) {
 4002:                     $questionimage = '<p><img src="../../resfiles/'.$$settings{$id}{uri}.'" /></p>'."\n";
 4003:                 } else {
 4004:                     $questionimage = '<p><img src="../../resfiles/'.$$settings{$id}{uri}.'" /></p>'."\n";
 4005:                 }
 4006:             } elsif ($cms eq 'webctvista4') {
 4007:                 if ($$settings{$id}{uri} =~ /(gif|jpg|png)$/i) {
 4008:                     $questionimage = '<p><img src="../../resfiles/'.$$settings{$id}{uri}.'" /></p>'."\n";
 4009:                     $questionimage =~ s#(//+)#/#g;
 4010:                 } else {
 4011:                     $questionimage = '<a href="'.$$settings{$id}{uri}.'" target="exturi" >'.$$settings{$id}{uri}.'</a>';
 4012:                 }
 4013:             }
 4014:         }
 4015:         if (($cms eq 'webctvista4') && (defined($$settings{$id}{image}))) {
 4016:             my $imgsrc = '../../resfiles/'.$$settings{$id}{image};
 4017:             if (defined($$settings{$id}{imagetitle})) {
 4018:                 $imgsrc = '../../resfiles/'.$$settings{$id}{imagetitle};
 4019:             }
 4020:             $questionimage = qq|<p><img src="$imgsrc" /></p>|;
 4021:         }
 4022:         if ($$settings{$id}{class} eq "paragraph") {
 4023:             my $pre_fill_answer = $$settings{$id}{PARA}{PARA}{PRE_FILL_ANSWER};
 4024:             if ($context eq 'CSTR') {
 4025:                 $output .= qq|<startouttext /><p>$$settings{$id}{text}</p>$questionimage<endouttext />
 4026:  <essayresponse>
 4027:  <textfield>$pre_fill_answer</textfield>
 4028:  </essayresponse>
 4029: |;
 4030:             } else {
 4031:                 $resourcedata{$symb.'questiontext'} = '<p>'.$$settings{$id}{text}.'</p>'.$questionimage;
 4032:                 $resourcedata{$symb.'hiddenparts'} = '!essay';
 4033:                 $resourcedata{$symb.'questiontype'} = 'essay';
 4034:             }
 4035:         } elsif ($$settings{$id}{class} eq 'jumbled') {
 4036:             if ($context eq 'CSTR') {
 4037:                 my %foiloptions = ();
 4038:                 foreach my $list (@{$$settings{$id}{lists}}) {
 4039:                     @{$foiloptions{$list}} = ();
 4040:                     my $numalternates = @{$$settings{$id}{$list}{jumbled}} - 1;
 4041:                     my $loopstop = 2; #Hard coded for now, so only one permutation of answers is correct; <or> functionality is needed to support the case where multiple permutations are correct.  
 4042:                     for (my $i=1; $i<$loopstop; $i++) {  
 4043:                         $foiloptions{$list}[$i]  = '(';
 4044:                         for (my $j=@{$$settings{$id}{$list}{jumbled}[$i]}-1; $j>0; $j--) {
 4045:                             my $jumble_item = $$settings{$id}{$list}{jumbled}[$i][$j];
 4046:                             $foiloptions{$list}[$i] .= "'".$$settings{$id}{$list}{$jumble_item}{text}."',";
 4047:                         }
 4048:                         $foiloptions{$list}[$i] =~ s/,$//;
 4049:                         $foiloptions{$list}[$i] .= ')';
 4050:                         my $jnum = 0; 
 4051:                         for (my $k=0; $k<@{$$settings{$id}{$list}{jumbledtype}}; $k++) {
 4052:                             if ($$settings{$id}{$list}{jumbledtype}[$k] eq 'No') {
 4053:                                 $output .= qq|
 4054: <startouttext />
 4055: $$settings{$id}{$list}{jumbledtext}[$k]
 4056: <endouttext />|;
 4057:                             } elsif ($$settings{$id}{$list}{jumbledtype}[$k] eq 'Yes') {
 4058:                                 $jnum ++;
 4059:                                 my $jumble_item = $$settings{$id}{$list}{jumbled}[$i][$jnum];
 4060:                                 $output .= qq|
 4061: <optionresponse max="1" randomize="yes" TeXlayout="horizontal">
 4062:     <foilgroup options="$foiloptions{$list}[$i]">
 4063:         <foil location="random" value="$$settings{$id}{$list}{$jumble_item}{text}" name="$jumble_item"></foil>
 4064:     </foilgroup>
 4065: </optionresponse>
 4066: |;
 4067:                             }
 4068:                         }
 4069:                     }
 4070:                     if ($numalternates > 0) { # for now alternates are stored in an instructorcomment.  In the future these alternates could be moved into the main response area once <or> functionality is available.
 4071:                         $output .= '<instructorcomment>(Not shown to students) '."\n".'The following alternates were imported from the corresponding WebCT Vista 4 jumbled sentence question, but are not included in the LON-CAPA version, because this style of question does not currently support multiple correct solutions.'."\n";
 4072:                         for (my $i=2; $i<@{$$settings{$id}{$list}{jumbled}}; $i++) {
 4073:                             my $altid = $i-1;
 4074:                             my $jnum = 0;
 4075:                             $output .= $altid.'. '; 
 4076:                             for (my $k=0; $k<@{$$settings{$id}{$list}{jumbledtype}}; $k++) {
 4077:                                 if ($$settings{$id}{$list}{jumbledtype}[$k] eq 'No') {
 4078:                                     $output .= "$$settings{$id}{$list}{jumbledtext}[$k]" ;
 4079:                                 } elsif ($$settings{$id}{$list}{jumbledtype}[$k] eq 'Yes') {
 4080:                                     $jnum ++;
 4081:                                     my $jumble_item = $$settings{$id}{$list}{jumbled}[$i][$jnum];
 4082:                                     $output .= '['.$$settings{$id}{$list}{$jumble_item}{text}.']';
 4083:                                 }
 4084:                             }
 4085:                             $output .= " \n";
 4086:                         }
 4087:                         $output .= '</instructorcomment>';
 4088:                     }  
 4089:                 }
 4090:             }
 4091:         } else {
 4092:             if ($context eq 'CSTR') {
 4093:                 $output .= qq|<startouttext /><p>$$settings{$id}{text}</p>$questionimage<endouttext />\n|;
 4094:             } else {
 4095:                 $resourcedata{$symb.'questiontext'} = '<p>'.$$settings{$id}{text}.'</p>'.$questionimage;
 4096:             }
 4097:             if (($$settings{$id}{class} eq 'multiplechoice') || 
 4098:                 ($$settings{$id}{class} eq 'combination')) {
 4099:                 foreach my $list (@{$$settings{$id}{lists}}) {
 4100:                     my $numfoils = @{$$allanswers{$id}{$list}};
 4101:                     if ($$settings{$id}{$list}{rcardinality} eq 'Single') {
 4102:                         if ($context eq 'CSTR') {
 4103:                             $output .= qq|
 4104:  <radiobuttonresponse max="$numfoils" randomize="$$settings{$id}{$list}{randomize}">
 4105:   <foilgroup>
 4106: |;
 4107:                         } else {
 4108:                             $resourcedata{$symb.'hiddenparts'} = '!radio';
 4109:                             $resourcedata{$symb.'questiontype'} = 'radio';
 4110:                             $resourcedata{$symb.'maxfoils'} = $numfoils;
 4111:                         }
 4112:                         for (my $k=0; $k<@{$$allanswers{$id}{$list}}; $k++) {
 4113:                             my $iter = $k+1;
 4114:                             $output .= "   <foil name=\"foil".$k."\" value=\"";
 4115:                             if (grep/^$$allanswers{$id}{$list}[$k]$/,@{$$settings{$id}{$list}{correctanswer}}) {
 4116:                                 $output .= "true\" location=\"";
 4117:                                 $resourcedata{$symb.'value'.$iter} = "true";
 4118:                             } else {
 4119:                                 $output .= "false\" location=\"";
 4120:                                 $resourcedata{$symb.'value'.$iter} = "false";
 4121:                             }
 4122:                             if (lc ($$allanswers{$id}{$list}[$k]) =~ m/^\s?([Aa]ll)|([Nn]one)\s(of\s)?the\sabove\.?/) {
 4123:                                 $output .= "bottom\"";
 4124:                                 $resourcedata{$symb.'position'.$iter} = "bottom";
 4125:                             } else {
 4126:                                 $output .= "random\"";
 4127:                             }
 4128:                             if ($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{texttype} eq 'text/html') {
 4129:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} = &HTML::Entities::decode($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text});
 4130:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} = &Apache::loncleanup::htmlclean($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text});
 4131:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} =~  s#(<img src=")([^>]+)>#$1../../resfiles/$2 />#gi;
 4132:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} =~  s#</?p>##g;
 4133: 
 4134:                             }
 4135:                             $output .= "\><startouttext />".$$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text};
 4136:                             $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text};
 4137:                             $output .= '<endouttext /></foil>'."\n";
 4138:                         }
 4139:                         if ($context eq 'CSTR') {
 4140:                             chomp($output);
 4141:                             $output .= qq|
 4142:   </foilgroup>
 4143:  </radiobuttonresponse>
 4144: |;
 4145:                         }
 4146:                     } else {
 4147:                         if ($context eq 'CSTR') {
 4148:                             $output .= qq|
 4149:    <optionresponse max="$numfoils" randomize="yes">
 4150:     <foilgroup options="('True','False')">
 4151: |;
 4152:                         } else {
 4153:                             $resourcedata{$symb.'newopt'} = '';
 4154:                             $resourcedata{$symb.'delopt'} = '';
 4155:                             $resourcedata{$symb.'options'} = "('True','False')";
 4156:                             $resourcedata{$symb.'hiddenparts'} = '!option';
 4157:                             $resourcedata{$symb.'questiontype'} = 'option';
 4158:                             $resourcedata{$symb.'maxfoils'} = $numfoils;
 4159:                         }
 4160:                         for (my $k=0; $k<@{$$allanswers{$id}{$list}}; $k++) {
 4161:                             my $iter = $k+1;
 4162:                             $output .= "   <foil name=\"foil".$k."\" value=\"";
 4163:                             if (grep/^$$allanswers{$id}{$list}[$k]$/,@{$$settings{$id}{$list}{correctanswer}}) {
 4164:                                 $output .= "True\"";
 4165:                                 $resourcedata{$symb.'value'.$iter} = "True";
 4166:                             } else {
 4167:                                 $output .= "False\"";
 4168:                                 $resourcedata{$symb.'value'.$iter} = "False";
 4169:                             }
 4170:                             if ($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{texttype} eq 'text/html') {
 4171:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} = &HTML::Entities::decode($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text});
 4172:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} = &Apache::loncleanup::htmlclean($$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text});
 4173:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} =~  s#(<img src=")([^>]+)>#$1../../resfiles/$2 />#gi;
 4174:                                 $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text} =~  s#</?p>##g;
 4175:                             }
 4176:                             $output .= "\><startouttext />".$$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text}."<br /><endouttext /></foil>\n";
 4177:                             $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$list}{$$allanswers{$id}{$list}[$k]}{text};
 4178:                         }
 4179:                         if ($context eq 'CSTR') {
 4180:                             chomp($output);
 4181:                             $output .= qq|
 4182:     </foilgroup>
 4183:    </optionresponse>
 4184: |;
 4185:                         }
 4186:                     }
 4187:                 }
 4188:             } elsif ($$settings{$id}{class} eq 'match') {
 4189:                 my %allmatchers = ();
 4190:                 my @allmatch = ();
 4191:                 my %matchtext = ();
 4192:                 my $anscount = 0;
 4193:                 my %ansnum = ();
 4194:                 my $maxfoils = 0;
 4195:                 my $test_for_html = 0; 
 4196:                 foreach my $grp (@{$$allchoices{$id}}) {
 4197:                     $maxfoils += @{$$settings{$id}{$grp}{correctanswer}};
 4198:                     foreach my $answer_id (@{$$allanswers{$id}{$grp}}) {
 4199:                         if ($$settings{$id}{$grp}{$answer_id}{texttype} eq '/text/html') {
 4200:                              
 4201:                             $$settings{$id}{$grp}{$answer_id}{text} = &HTML::Entities::decode($$settings{$id}{$grp}{$answer_id}{text});
 4202:                             $test_for_html = &test_for_html($$settings{$id}{$grp}{$answer_id}{text});
 4203:                             $$settings{$id}{$grp}{$answer_id}{text} = &Apache::loncleanup::htmlclean($$settings{$id}{$grp}{$answer_id}{text});
 4204:                             $$settings{$id}{$grp}{$answer_id}{text} =~  s#(<img src=")([^>]+)>#$1../../resfiles/$2 />#gi;
 4205:                             $$settings{$id}{$grp}{$answer_id}{text} =~  s#</?p>##g;
 4206:                         }
 4207:                         unless (exists($allmatchers{$$settings{$id}{$grp}{$answer_id}{text}})) {
 4208:                             $allmatchers{$$settings{$id}{$grp}{$answer_id}{text}} = $anscount;
 4209:                             $allmatch[$anscount] = $$settings{$id}{$grp}{$answer_id}{text};
 4210:                             $anscount ++;
 4211:                             
 4212:                         }
 4213:                         if (grep/^$answer_id$/,@{$$settings{$id}{$grp}{correctanswer}}) {
 4214:                             push(@{$ansnum{$grp}},$allmatchers{$$settings{$id}{$grp}{$answer_id}{text}});
 4215:                         }
 4216:                     }
 4217:                     if ($context eq 'DOCS') {
 4218:                         $matchtext{$ansnum{$grp}[0]} = $allmatch[$ansnum{$grp}[0]-1];
 4219:                     }
 4220:                 }
 4221:                 my $allmatchlist = "('".join("','",@allmatch)."')";
 4222:                 if ($context eq 'CSTR') {
 4223:                     if ($test_for_html) {
 4224:                         $output .= qq|
 4225: <matchresponse max="$maxfoils" randomize="yes">
 4226:     <foilgroup>
 4227:         <itemgroup>
 4228: |;
 4229:                     } else {
 4230:                         $output .= qq|
 4231: <optionresponse max="10" randomize="yes">
 4232:     <foilgroup options="$allmatchlist">
 4233: |;
 4234:                     }
 4235:                 } else {
 4236:                     $resourcedata{$symb.'newopt'} = '';
 4237:                     $resourcedata{$symb.'delopt'} = '';
 4238:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 4239:                     $resourcedata{$symb.'questiontype'} = 'option';
 4240:                     $resourcedata{$symb.'maxfoils'} =  $maxfoils;
 4241:                 }
 4242:                 my $iter = 0;
 4243:                 foreach my $match (@allmatch) {  
 4244:                     $iter ++;
 4245:                     if ($context eq 'CSTR') {
 4246:                         if ($test_for_html) {
 4247:                             $output .= qq|
 4248: <item name="ans_$iter">
 4249: <startouttext />$match<endouttext />
 4250: </item>
 4251: |;
 4252:                         }
 4253:                     }
 4254:                 }
 4255:                 if ($context eq 'CSTR') {
 4256:                     if ($test_for_html) {
 4257:                         $output .= qq|
 4258:         </itemgroup>
 4259: |;
 4260:                     }
 4261:                 }
 4262:                 $iter = 0;
 4263:                 for (my $k=0; $k<@{$$allchoices{$id}}; $k++) {
 4264:                     if ($$settings{$id}{$$allchoices{$id}[$k]}{texttype} eq 'text/html') {
 4265:                         $$settings{$id}{$$allchoices{$id}[$k]}{text} = &HTML::Entities::decode($$settings{$id}{$$allchoices{$id}[$k]}{text});
 4266:                         $$settings{$id}{$$allchoices{$id}[$k]}{text} = &Apache::loncleanup::htmlclean($$settings{$id}{$$allchoices{$id}[$k]}{text});
 4267:                         $$settings{$id}{$$allchoices{$id}[$k]}{text} =~  s#(<img src=")([^>]+)>#$1../../resfiles/$2 />#gi;
 4268:                         $$settings{$id}{$$allchoices{$id}[$k]}{text} =~  s#</?p>##g;
 4269:                     }
 4270:                     foreach my $ans (@{$ansnum{$$allchoices{$id}[$k]}}) {
 4271:                         $iter ++;
 4272:                         my $ans_id = $ans + 1;
 4273:                         if ($context eq 'CSTR') {
 4274:                             my $value;
 4275:                             if ($test_for_html) {
 4276:                                 $value = 'ans_'.$ans_id;
 4277:                             } else {
 4278:                                 $value = $allmatch[$ans];
 4279:                             }
 4280:                             $output .= qq|
 4281:         <foil location="random" value="$value" name="foil_$iter">
 4282:          <startouttext />$$settings{$id}{$$allchoices{$id}[$k]}{text}<endouttext />
 4283:         </foil>
 4284:                            
 4285: |;
 4286:                         }
 4287:                     }
 4288:                     if ($context eq 'DOCS') {
 4289:                         $resourcedata{$symb.'value'.$iter} = $matchtext{$ansnum{$$allchoices{$id}[$k]}[0]};
 4290:                         $resourcedata{$symb.'text'.$iter} = $$settings{$id}{$$allchoices{$id}[0]}{text};
 4291:                     }
 4292:                 }
 4293:                 if ($context eq 'CSTR') {
 4294:                     $output .= qq|
 4295:     </foilgroup>
 4296: |;
 4297:                     if ($test_for_html) {
 4298:                         $output .= qq|
 4299: </matchresponse>
 4300: |;
 4301:                     } else {
 4302:                         $output .= qq|
 4303: </optionresponse>
 4304: |;
 4305:                     }
 4306:                 } else {
 4307:                     $resourcedata{$symb.'options'} = "('".join("','",@allmatch)."')";
 4308:                 }
 4309:             } elsif (($$settings{$id}{class} eq 'string') || 
 4310:                      ($$settings{$id}{class} eq 'shortanswer')) {
 4311:                 my $labelnum = 0;
 4312:                 my @str_labels = ();
 4313:                 if ($cms eq 'webctce4') {
 4314:                     foreach my $str_id (@{$$settings{$id}{str}}) {
 4315:                         foreach my $label (@{$$settings{$id}{$str_id}{labels}}) {
 4316:                             push(@str_labels,$label);
 4317:                         }
 4318:                     }
 4319:                 } elsif ($cms eq 'webctvista4') {
 4320:                     @str_labels = @{$$settings{$id}{str}};
 4321:                 }
 4322:                 foreach my $label (@str_labels) {
 4323:                     $labelnum ++;
 4324:                     my $numerical = 1;
 4325:                     if ($context eq 'DOCS') {
 4326:                         $numerical = 0;
 4327:                     } else {
 4328:                         for (my $i=0; $i<@{$$settings{$id}{strings}{$label}}; $i++) {
 4329:                             $$settings{$id}{strings}{$label}[$i] =~ s/^\s+//;
 4330:                             $$settings{$id}{strings}{$label}[$i] =~ s/\s+$//; 
 4331:                             if ($$settings{$id}{strings}{$label}[$i] =~ m/([^\-\d\.]|\.\.)/) {
 4332:                                 $numerical = 0;
 4333:                             }
 4334:                         }
 4335:                     }
 4336:                     if ($numerical) {
 4337:                         my $numans;
 4338:                         my $tol;
 4339:                         if (@{$$settings{$id}{strings}{$label}} == 1) {
 4340:                             $tol = '5%';
 4341:                             $numans = $$settings{$id}{strings}{$label}[0];
 4342:                         } else {
 4343:                             my $min = $$settings{$id}{strings}{$label}[0];
 4344:                             my $max = $$settings{$id}{strings}{$label}[0];
 4345:                             for (my $k=1; $k<@{$$settings{$id}{strings}{$label}}; $k++) {
 4346:                                 if ($$settings{$id}{strings}{$label}[$k] <= $min) {
 4347:                                     $min = $$settings{$id}{strings}{$label}[$k];
 4348:                                 }
 4349:                                 if ($$settings{$id}{strings}{$label}[$k] >= $max) {
 4350:                                     $max = $$settings{$id}{strings}{$label}[$k];
 4351:                                 }
 4352:                             }
 4353:                             $numans = ($max + $min)/2;
 4354:                             if ($numans == 0) {
 4355:                                 my $dev = abs($max - $numans);
 4356:                                 if (abs($numans - $min) > $dev) {
 4357:                                     $dev = abs($numans - $min);
 4358:                                 }
 4359:                                 $tol = $dev;
 4360:                             } else {
 4361:                                 $tol = 100*($max - $min)/($numans*2);
 4362:                                 $tol .= '%';
 4363:                             }
 4364:                         }
 4365:                         if ($context eq 'CSTR') {
 4366:                             if (@{$$settings{$id}{str}} > 1) {
 4367:                                 $output .= qq|
 4368: <startouttext />$labelnum.<endouttext />
 4369: |;
 4370:                             }
 4371:                             $output .= qq|
 4372: <numericalresponse answer="$numans">
 4373:         <responseparam type="tolerance" default="$tol" name="tol" description="Numerical Tolerance" />
 4374:         <responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures"
 4375: />
 4376:         <textline />
 4377: </numericalresponse>
 4378: <startouttext /><br /><endouttext />
 4379: |;
 4380:                         }
 4381:                     } else {
 4382:                         if ($context eq 'DOCS') {
 4383:                             $resourcedata{$symb.'hiddenparts'} = '!string';
 4384:                             $resourcedata{$symb.'questiontype'} = 'string';
 4385:                             $resourcedata{$symb.'maxfoils'} = @{$$allanswers{$id}{strings}{$label}};
 4386:                             $resourcedata{$symb.'hiddenparts'} = '!string';
 4387:                             if ($$settings{$id}{$label}{case} eq "No") {
 4388:                                 $resourcedata{$symb.'stringtype'} = 'ci';
 4389:                             } elsif ($$settings{$id}{$label}{case} eq "Yes") {
 4390:                                 $resourcedata{$symb.'stringtype'} = 'cs';
 4391:                             }
 4392:                             $resourcedata{$symb.'stringanswer'} = $$settings{$id}{strings}{$label}[0];
 4393:                         } else {
 4394:                             if (@{$$settings{$id}{str}} > 1) {
 4395:                                 $output .= qq|
 4396: <startouttext />$labelnum.<endouttext />
 4397: |;
 4398:                             }
 4399:                             if (@{$$settings{$id}{strings}{$label}} == 1) {
 4400:                                 my $casetype;
 4401:                                 if ($$settings{$id}{$label}{case} eq "No") {
 4402:                                     $casetype = 'ci';
 4403:                                 } elsif ($$settings{$id}{$label}{case} eq "Yes") {
 4404:                                     $casetype = 'cs';
 4405:                                 }
 4406:                                 $output .= qq|
 4407: <stringresponse answer="$$settings{$id}{strings}{$label}[0]" type="$casetype">
 4408: <textline>
 4409: </textline>
 4410: </stringresponse>
 4411: <startouttext /><br /><endouttext />
 4412: |;
 4413:                             } else {
 4414:                                 my @answertext = ();
 4415:                                 for (my $k=0; $k<@{$$settings{$id}{strings}{$label}}; $k++) {
 4416:                                     $$settings{$id}{strings}{$label}[$k] =~ s/\|/\|/g;
 4417:                                     push @answertext, $$settings{$id}{strings}{$label}[$k];
 4418:                                 }
 4419:                                 my $regexpans = join('|',@answertext);
 4420:                                 $regexpans = '/^('.$regexpans.')\b/';
 4421:                                 $output .= qq|
 4422: <stringresponse answer="$regexpans" type="re">
 4423: <textline>
 4424: </textline>
 4425: </stringresponse>
 4426: <startouttext /><br /><endouttext />
 4427: |;
 4428:                             }
 4429:                         }
 4430:                     }
 4431:                 }
 4432:             } elsif ($$settings{$id}{class} eq 'numerical') {
 4433:                 my %mathfns = (
 4434:                     'abs' => 'abs',
 4435:                     'acos' => 'acos',
 4436:                     'asin' => 'asin',
 4437:                     'atan' => 'atan',
 4438:                     'ceil' => 'ceil',
 4439:                     'cos' => 'cos',
 4440:                     'exp' => 'exp',
 4441:                     'fact' => 'factorial',
 4442:                     'floor' => 'floor',
 4443:                     'int' => 'int',
 4444:                     'ln' => 'log',
 4445:                     'log' => 'log',
 4446:                     'max' => 'max',
 4447:                     'min' => 'min',
 4448:                     'round' => 'roundto',
 4449:                     'sin' => 'sin',
 4450:                     'sqrt' => 'sqrt',
 4451:                     'tan' => 'tan',
 4452:                 );
 4453:                 my $scriptblock = qq|
 4454: <script type="loncapa/perl">
 4455: |;
 4456:                 foreach my $numid (@{$$settings{$id}{numids}}) {
 4457:                     my $formula = $$settings{$id}{$numid}{formula};
 4458:                     my $pattern = join('|',(sort(keys(%mathfns))));
 4459:                     $formula =~ s/($pattern)/\&$mathfns{$1}/g;
 4460:                     foreach my $var (keys(%{$$settings{$id}{$numid}{vars}})) {
 4461:                         my $decnum = $$settings{$id}{$numid}{vars}{$var}{dec};
 4462:                         my $increment = '0.';
 4463:                         if ($decnum == 0) {
 4464:                             $increment = 1; 
 4465:                         } else {
 4466:                             my $deccount = $decnum;
 4467:                             while ($deccount > 1) {
 4468:                                 $increment.= '0';
 4469:                                 $deccount --;
 4470:                             }
 4471:                             $increment .= '1';
 4472:                         }
 4473:                         if ($cms eq 'webctce4') { 
 4474:                             $formula =~ s/{($var)}/(\$$1)/g;
 4475:                         } elsif ($cms eq 'webctvista4') {
 4476:                             $formula =~ s/\[($var)\]/(\$$1)/g;
 4477:                         }
 4478:                         $scriptblock .= qq|
 4479: \$$var=&random($$settings{$id}{$numid}{vars}{$var}{min},$$settings{$id}{$numid}{vars}{$var}{max},$increment);
 4480: |;
 4481:                     }
 4482:                     $scriptblock .= qq|
 4483: \$answervar = $formula;
 4484: </script>
 4485: |;
 4486:                     if ($context eq 'CSTR') {
 4487:                         $output = "<problem>\n".$scriptblock.$output;
 4488:                         my $ansformat = '';
 4489:                         my $sigfig = '0,15';
 4490:                         if ($$settings{$id}{$numid}{format} eq 'sig') {
 4491:                             $sigfig = $$settings{$id}{$numid}{digits}.','.$$settings{$id}{$numid}{digits};
 4492:                         } elsif ($$settings{$id}{$numid}{format} eq 'dec') {
 4493:                             $ansformat = $$settings{$id}{$numid}{digits}.'f';
 4494:                         }
 4495:                         if ($ansformat) {
 4496:                             $ansformat = 'format="'.$ansformat.'"';
 4497:                         }
 4498:                         my $tolerance = $$settings{$id}{$numid}{tolerance};
 4499:                         if (lc($$settings{$id}{$numid}{toltype}) eq 'percent') {
 4500:                             $tolerance .= '%';
 4501:                         }
 4502:                         my $unit = '';
 4503:                         foreach my $unitid (@{$$settings{$id}{$numid}{units}}) {
 4504:                             $unit .=  $$settings{$id}{$numid}{$unitid}{text};
 4505:                         }
 4506:                         my $unitentry = '';
 4507:                         if ($unit ne '') {
 4508:                             $unitentry =  'unit="'.$unit.'"';
 4509:                         }
 4510:                         $output .= qq|
 4511: <numericalresponse $unitentry $ansformat  answer="\$answervar">
 4512:         <responseparam type="tolerance" default="$tolerance" name="tol" description="Numerical Tolerance" />
 4513:         <responseparam name="sig" type="int_range" default="$sigfig" description="Significant Figures"
 4514: />
 4515:         <textline />
 4516: </numericalresponse>
 4517: |;
 4518:                     }
 4519:                 }
 4520:             }
 4521:         }
 4522:         if ($context eq 'CSTR') {
 4523:             my $probdir;
 4524:             my $catid = $$settings{$id}{category};
 4525:             if ($catid) {
 4526:                 if ($cms eq 'webctce4') {
 4527:                     $probdir = $$catinfo{$catid}{title}.'_'.$catid;
 4528:                 } else {
 4529:                     $probdir = $$catinfo{$catid}{title};
 4530:                 }
 4531:                 $probdir =~ s/\s/_/g;
 4532:                 $probdir =~ s/://g;
 4533:             } elsif (defined($dirtitle)) {
 4534:                 $probdir = $dirtitle;
 4535:             }
 4536:             if (!-e "$destdir/problems/$probdir") {
 4537:                 mkdir("$destdir/problems/$probdir",0755);
 4538:             }
 4539:             if ($allfeedback ne '') {
 4540:                 $output .= qq|
 4541:  <postanswerdate>
 4542:   $allfeedback
 4543:  </postanswerdate>
 4544: |;
 4545:             }
 4546:             $output .= qq|</problem>
 4547: |;
 4548:             my $title = $$settings{$id}{title};
 4549:             $title =~ s/\s/_/g;
 4550:             $title =~ s/:/_/g;
 4551:             $title =~ s/\//_/g;
 4552:             open(PROB,'>',"$destdir/problems/$probdir/$title.problem");
 4553:             print PROB $output;
 4554:             close PROB;
 4555:         } else {
 4556: # put %resourcedata;
 4557:             my $reply=&Apache::lonnet::cput
 4558:                 ('resourcedata',\%resourcedata,$cdom,$cnum);
 4559:         }
 4560:     }
 4561: }
 4562: 
 4563: sub text_cleanup {
 4564:     my ($text) = @_;
 4565:     $text =~ s/(\&)(nbsp|gt|lt)(?!;)/$1$2;$3/gi;
 4566:     $text = &Apache::loncleanup::htmlclean($text);
 4567:     $text =~ s#(<img src=["']?)([^>]+?)(/?>)#$1../../resfiles/$2 />#gi;
 4568:     $text =~ s#<([bh])r>#<$1r />#g;
 4569:     $text =~ s#<p>#<br /><br />#g;
 4570:     $text =~ s#</p>##g;
 4571:     return $text;
 4572: }
 4573: 
 4574: sub test_for_html {
 4575:     my ($source) = @_; 
 4576:     my @tags = ();
 4577:     my $p = HTML::Parser->new
 4578:     (
 4579:      xml_mode => 1,
 4580:      start_h =>
 4581:      [sub {
 4582:         my ($tagname) = @_;
 4583:         push @tags, $tagname;
 4584:      }, "tagname"],
 4585:     );
 4586:     $p->parse($source);
 4587:     $p->eof;
 4588:     return length(@tags); 
 4589: } 
 4590: 
 4591: sub write_bb6_questions {
 4592:     my ($allids,$containerdir,$context,$settings,$dirname,$destdir,$res,$total,$newdir,$cid,$cdom,$cnum,$docroot) = @_;
 4593:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
 4594:     my $qnum = 0;
 4595:     foreach my $id (@{$allids}) {
 4596:         my $questiontext = $$settings{$id}{question}{text};
 4597:         my $question_texttype = $$settings{$id}{question}{texttype};
 4598:         &process_html(\$questiontext,'bb6',$question_texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4599:         $qnum ++;
 4600:         my $output;
 4601:         my $permcontainer = $containerdir;
 4602:         $permcontainer =~ s{\Q$londocroot/userfiles\E}{uploaded};
 4603:         my $symb = $cid.'.'.$permcontainer.'___'.$qnum.'___lib/templates/simpleproblem.problem.0.';
 4604:         my %resourcedata = ();
 4605:         for (my $i=0; $i<10; $i++) {
 4606:             my $iter = $i+1;
 4607:             $resourcedata{$symb.'text'.$iter} = "";
 4608:             $resourcedata{$symb.'value'.$iter} = "unused";
 4609:             $resourcedata{$symb.'position'.$iter} = "random";
 4610:         }
 4611:         $resourcedata{$symb.'randomize'} = 'yes';
 4612:         $resourcedata{$symb.'maxfoils'} = 10;
 4613:         if ($context eq 'CSTR') {
 4614:             $output = qq|<problem>
 4615: |;
 4616:         }
 4617:         $$total{prob} ++;
 4618:         $questiontext .= &add_images_links('question',$context,$settings,$id,$dirname,$res);
 4619:         if ($$settings{$id}{class} eq "Essay") {
 4620:             if ($context eq 'CSTR') {
 4621:                 $output .= qq|<startouttext />$questiontext<endouttext />
 4622:  <essayresponse>
 4623:  <textfield></textfield>
 4624:  </essayresponse>
 4625: |;
 4626:              } else {
 4627:                  $resourcedata{$symb.'questiontext'} = $questiontext;
 4628:                  $resourcedata{$symb.'hiddenparts'} = '!essay';
 4629:                  $resourcedata{$symb.'questiontype'} = 'essay';
 4630:              }
 4631:         } else {
 4632:             if ($context eq 'CSTR') {
 4633:                 $output .= qq|<startouttext />$questiontext\n<endouttext />|;
 4634:             } else {
 4635:                 $resourcedata{$symb.'questiontext'} = $questiontext;
 4636:             }
 4637:             my $numfoils = @{$$settings{$id}{answers}};
 4638:             if (($$settings{$id}{class} eq 'Multiple Choice') || 
 4639:                 ($$settings{$id}{class} eq 'True/False')) {
 4640:                 if ($context eq 'CSTR') {
 4641:                     $output .= qq|
 4642:  <radiobuttonresponse max="$numfoils" randomize="yes">
 4643:   <foilgroup>
 4644: |;
 4645:                 } else {
 4646:                     $resourcedata{$symb.'hiddenparts'} = '!radio';
 4647:                     $resourcedata{$symb.'questiontype'} = 'radio';
 4648:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 4649:                 }
 4650:                 for (my $k=0; $k<$numfoils; $k++) {
 4651:                     my $iter = $k+1;
 4652:                     my $answer_id = $$settings{$id}{answers}[$k];
 4653:                     my $answer_text = $$settings{$id}{$answer_id}{text};
 4654:                     my $texttype = $$settings{$id}{$answer_id}{texttype};
 4655:                     &process_html(\$answer_text,'bb6',$texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4656:                     $answer_text .= &add_images_links('response',$context,$settings,$id,$dirname,$res); 
 4657:                     $output .= "   <foil name=\"foil".$k."\" value=\"";
 4658:                     if (grep/^$answer_id$/,@{$$settings{$id}{correctanswer}}) {
 4659:                         $output .= "true\" location=\"";
 4660:                         $resourcedata{$symb.'value'.$iter} = "true";
 4661:                     } else {
 4662:                         $output .= "false\" location=\"";
 4663:                         $resourcedata{$symb.'value'.$iter} = "false";
 4664:                     }
 4665:                     if (lc ($$settings{$id}{$answer_id}{text}) =~ m/^\s?([Aa]ll)|([Nn]one)\s(of\s)?the\sabove\.?/) {
 4666:                         $output .= "bottom\"";
 4667:                         $resourcedata{$symb.'position'.$iter} = "bottom";
 4668:                     } else {
 4669:                         $output .= "random\"";
 4670:                     }
 4671:                     $output .= '\><startouttext />'.$answer_text.
 4672:                                '<endouttext /></foil>'."\n";
 4673:                     $resourcedata{$symb.'text'.$iter} = $answer_text;
 4674:                 }
 4675:                 if ($context eq 'CSTR') {
 4676:                     chomp($output);
 4677:                     $output .= qq|
 4678:     </foilgroup>
 4679:     <hintgroup showoncorrect="no">
 4680:      <radiobuttonhint>
 4681:      </radiobuttonhint>
 4682:      <hintpart on="default">
 4683:       <startouttext/><endouttext />
 4684:      </hintpart>
 4685:     </hintgroup>
 4686:    </radiobuttonresponse>
 4687: |;
 4688:                 }
 4689:             } elsif ($$settings{$id}{class} eq 'Multiple Answer') {
 4690:                 if ($context eq 'CSTR') {
 4691:                     $output .= qq|
 4692:    <optionresponse max="$numfoils" randomize="yes">
 4693:     <foilgroup options="('True','False')">
 4694: |;
 4695:                 } else {
 4696:                     $resourcedata{$symb.'newopt'} = '';
 4697:                     $resourcedata{$symb.'delopt'} = '';
 4698:                     $resourcedata{$symb.'options'} = "('True','False')";
 4699:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 4700:                     $resourcedata{$symb.'questiontype'} = 'option';
 4701:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 4702:                 }
 4703:                 for (my $k=0; $k<$numfoils; $k++) {
 4704:                     my $iter = $k+1;
 4705:                     my $answer_id = $$settings{$id}{answers}[$k];
 4706:                     my $answer_text = $$settings{$id}{$answer_id}{text};
 4707:                     my $texttype = $$settings{$id}{$answer_id}{texttype};
 4708:                     &process_html(\$answer_text,'bb6',$texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4709:                     $answer_text .= &add_images_links('response',$context,$settings,$id,$dirname,$res);
 4710: 
 4711:                     $output .= "   <foil name=\"foil".$k."\" value=\"";
 4712:                     if (grep/^$answer_id$/,@{$$settings{$id}{correctanswer}}) {
 4713:                         $output .= "True\"";
 4714:                         $resourcedata{$symb.'value'.$iter} = "True";
 4715:                     } else {
 4716:                         $output .= "False\"";
 4717:                         $resourcedata{$symb.'value'.$iter} = "False";
 4718:                     }
 4719:                     $output .= "\><startouttext />".$answer_text."<endouttext /></foil>\n";
 4720:                     $resourcedata{$symb.'text'.$iter} = $answer_text;
 4721:                 }
 4722:                 if ($context eq 'CSTR') {
 4723:                     chomp($output);
 4724:                     $output .= qq|
 4725:     </foilgroup>
 4726:     <hintgroup showoncorrect="no">
 4727:      <optionhint>
 4728:      </optionhint>
 4729:      <hintpart on="default">
 4730:       <startouttext/><endouttext />
 4731:      </hintpart>
 4732:     </hintgroup>
 4733:    </optionresponse>
 4734: |;
 4735:                 }
 4736:             } elsif ($$settings{$id}{class} eq 'Ordering') {
 4737:                 my @allorder = ();
 4738:                 if ($context eq 'CSTR') {
 4739:                     $output .= qq|
 4740:    <rankresponse max="$numfoils" randomize="yes">
 4741:     <foilgroup>
 4742: |;
 4743:                 } else {
 4744:                     $resourcedata{$symb.'newopt'} = '';
 4745:                     $resourcedata{$symb.'delopt'} = '';
 4746:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 4747:                     $resourcedata{$symb.'questiontype'} = 'option';
 4748:                     $resourcedata{$symb.'maxfoils'} = $numfoils;
 4749:                 }
 4750:                 for (my $k=0; $k<$numfoils; $k++) {
 4751:                     my $answer_id = $$settings{$id}{answers}[$k];
 4752:                     my $answer_text = $$settings{$id}{$answer_id}{text};
 4753:                     my $texttype = $$settings{$id}{$answer_id}{texttype};
 4754:                     &process_html(\$answer_text,'bb6',$texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4755:                     $answer_text .= &add_images_links('response',$context,$settings,$id,$dirname,$res);
 4756:                     my $iter = $k+1;
 4757:                     if ($context eq 'CSTR') {
 4758:                         $output .= "   <foil location=\"random\" name=\"foil".$k."\" value=\"".$$settings{$id}{$answer_id}{order}."\"><startouttext />".$answer_text."<endouttext /></foil>\n";
 4759:                     } else {
 4760:                         $resourcedata{$symb.'text'.$iter} = $answer_text;
 4761:                         $resourcedata{$symb.'value'.$iter} = $$settings{$id}{$answer_id}{order};
 4762:                         if (!grep/^$$settings{$id}{$answer_id}{order}$/,@allorder) {
 4763:                             push(@allorder,$$settings{$id}{$answer_id}{order}); 
 4764:                         }
 4765:                     }
 4766:                 }
 4767:                 if ($context eq 'CSTR') {
 4768:                     chomp($output);
 4769:                     $output .= qq|
 4770:     </foilgroup>
 4771:    </rankresponse>
 4772: |;
 4773:                 } else {
 4774:                     @allorder = sort {$a <=> $b} @allorder;
 4775:                     $resourcedata{$symb.'options'} = "('".join("','",@allorder)."')";
 4776:                 }
 4777:             } elsif ($$settings{$id}{class} eq 'Fill in the Blank') {
 4778:                 my $numerical = 1;
 4779:                 if ($context eq 'DOCS') {
 4780:                     $numerical = 0;
 4781:                 } else {
 4782:                     for (my $k=0; $k<@{$$settings{$id}{correctanswer}}; $k++) {
 4783:                         if ($$settings{$id}{correctanswer}[$k] =~ m/([^\d\.]|\.\.)/) {
 4784:                             $numerical = 0;
 4785:                         }
 4786:                     }
 4787:                 }
 4788:                 if ($numerical) {
 4789:                     my $numans;
 4790:                     my $tol;
 4791:                     if (@{$$settings{$id}{correctanswer}} == 1) {
 4792:                         $tol = 5;
 4793:                         $numans = $$settings{$id}{correctanswer}[0];
 4794:                     } else {
 4795:                         my $min = $$settings{$id}{correctanswer}[0];;
 4796:                         my $max = $min;
 4797:                         for (my $k=1; $k<@{$$settings{$id}{correctanswer}}; $k++) {
 4798:                             if ($$settings{$id}{correctanswer}[$k] <= $min) {
 4799:                                 $min = $$settings{$id}{correctanswer}[$k];
 4800:                             }
 4801:                             if ($$settings{$id}{correctanswer}[$k] >= $max) {
 4802:                                 $max = $$settings{$id}{correctanswer}[$k];
 4803:                             }
 4804:                         }
 4805:                         $numans = ($max + $min)/2;
 4806:                         $tol = 100*($max - $min)/($numans*2);
 4807:                         $tol = 5;
 4808:                     }
 4809:                     if ($context eq 'CSTR') {
 4810:                         $output .= qq|
 4811: <numericalresponse answer="$numans">
 4812:         <responseparam type="tolerance" default="$tol%" name="tol" description="Numerical Tolerance" />
 4813:         <responseparam name="sig" type="int_range,0-16" default="0,15" description="Significant Figures"
 4814: />
 4815:         <textline />
 4816: </numericalresponse>
 4817: <hintgroup showoncorrect="no">
 4818:  <numericalhint>
 4819:  </numericalhint>
 4820:  <hintpart on="default">
 4821:     <startouttext/><endouttext />
 4822:  </hintpart>
 4823: </hintgroup>
 4824: |;
 4825:                     }
 4826:                 } else {
 4827:                     if ($context eq 'DOCS') {
 4828:                         $resourcedata{$symb.'hiddenparts'} = '!string';
 4829:                         $resourcedata{$symb.'questiontype'} = 'string';
 4830:                         $resourcedata{$symb.'maxfoils'} = 1;
 4831:                         $resourcedata{$symb.'hiddenparts'} = '!string';
 4832:                         $resourcedata{$symb.'stringtype'} = 'ci';
 4833:                         $resourcedata{$symb.'stringanswer'} = $$settings{$id}{correctanswer}[0];
 4834:                     } else {
 4835:                         if (@{$$settings{$id}{correctanswer}} == 1) {
 4836:                             $output .= qq|
 4837: <stringresponse answer="$$settings{$id}{correctanswer}[0];" type="ci">
 4838: <textline>
 4839: </textline>
 4840: </stringresponse>
 4841: <hintgroup showoncorrect="no">
 4842: <stringhint type="cs">
 4843: </stringhint>
 4844: <hintpart on="default">
 4845:   <startouttext/><endouttext />
 4846: </hintpart>
 4847: </hintgroup>
 4848: |;
 4849:                         } else {
 4850:                             my @answertext = ();
 4851:                             for (my $k=0; $k<@{$$settings{$id}{correctanswer}}; $k++) {
 4852:                                 my $answer_text = $$settings{$id}{correctanswer}[$k];
 4853:                                 $answer_text =~ s/\|/\|/g;
 4854:                                 push @answertext, $answer_text;
 4855:                             }
 4856:                             my $regexpans = join('|',@answertext);
 4857:                             $regexpans = '/^('.$regexpans.')\b/';
 4858:                             $output .= qq|
 4859: <stringresponse answer="$regexpans" type="re">
 4860: <textline>
 4861: </textline>
 4862: </stringresponse>
 4863: <hintgroup showoncorrect="no">
 4864:  <stringhint type="cs">
 4865:  </stringhint>
 4866:  <hintpart on="default">
 4867:     <startouttext/><endouttext />
 4868:  </hintpart>
 4869: </hintgroup>
 4870: |;
 4871:                         }
 4872:                     }
 4873:                 }
 4874:             } elsif ($$settings{$id}{class} eq "Matching") {
 4875:                 my @allmatchers = ();
 4876:                 my %matchtext = ();
 4877:                 if ($context eq 'CSTR') {
 4878:                     $output .= qq|
 4879: <matchresponse max="10" randomize="yes">
 4880:     <foilgroup>
 4881:         <itemgroup>
 4882: |;
 4883:                 } else {
 4884:                     $resourcedata{$symb.'newopt'} = '';
 4885:                     $resourcedata{$symb.'delopt'} = '';
 4886:                     $resourcedata{$symb.'hiddenparts'} = '!option';
 4887:                     $resourcedata{$symb.'questiontype'} = 'option';
 4888:                     $resourcedata{$symb.'maxfoils'} =  $numfoils;
 4889:                 }
 4890:                 for (my $k=0; $k<$$settings{$id}{allchoices}; $k++) {
 4891:                     my $choice_id = 'rightmatch'.$k;
 4892:                     my $choice_text = $$settings{$id}{$choice_id}{text};
 4893:                     my $texttype = $$settings{$id}{$choice_id}{texttype};
 4894:                     my $choice_plaintext = &remove_html($choice_text);
 4895:                     &process_html(\$choice_text,'bb6',$texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4896:                     $choice_text .= &add_images_links($choice_id,$context,$settings,$id,$dirname,$res);
 4897:                     push(@allmatchers,$choice_plaintext);
 4898:                     if ($context eq 'CSTR') {
 4899:                         $output .= qq|
 4900: <item name="$choice_id">
 4901: <startouttext />$choice_text<endouttext />
 4902: </item>
 4903:                     |;
 4904:                     }
 4905:                 }
 4906:                 if ($context eq 'CSTR') {
 4907:                     $output .= qq|
 4908:         </itemgroup>
 4909: |;
 4910:                 }
 4911:                 for (my $k=0; $k<$numfoils; $k++) {
 4912:                     my $answer_id = $$settings{$id}{answers}[$k];
 4913:                     my $answer_text = $$settings{$id}{$answer_id}{text};
 4914:                     my $texttype = $$settings{$id}{$answer_id}{texttype};
 4915:                     &process_html(\$answer_text,'bb6',$texttype,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir);
 4916:                     $answer_text .= &add_images_links($answer_id,$context,$settings,$id,$dirname,$res);
 4917:                     if ($context eq 'CSTR') {
 4918:                         $output .= '
 4919:         <foil location="random" value="rightmatch'.$$settings{$id}{$$settings{$id}{$answer_id}{correctanswer}}{order}.'" name="'.$answer_id.'">
 4920:          <startouttext />'.$answer_text.'<endouttext />
 4921:         </foil>
 4922: ';
 4923:                     } else {
 4924:                         my $iter = $k+1;
 4925:                         $resourcedata{$symb.'value'.$iter} = "$allmatchers[$$settings{$id}{$$settings{$id}{$answer_id}{correctanswer}}{order}]";
 4926:                         $resourcedata{$symb.'text'.$iter} = $answer_text;
 4927:                     }
 4928:                 }
 4929:                 if ($context eq 'CSTR') {
 4930:                     $output .= qq|
 4931:     </foilgroup>
 4932: </matchresponse>
 4933: |;
 4934:                 } else {
 4935:                     $resourcedata{$symb.'options'} = "('".join("','",@allmatchers)."')";
 4936:                 }
 4937:             }
 4938:         }
 4939:         if ($context eq 'CSTR') {
 4940:             
 4941:             $output .= qq|
 4942:  <postanswerdate>
 4943:   $$settings{$id}{solutionfeedback}{text}
 4944:  </postanswerdate>
 4945: </problem>
 4946: |;
 4947:             my $title = $$settings{title};
 4948:             $title =~ s/\s/_/g;
 4949:             $title =~ s/\W//g;
 4950:             $title .= '_'.$id;
 4951:             open(PROB,'>',"$newdir/$title.problem");
 4952:             print PROB $output;
 4953:             close PROB;
 4954:         } else {
 4955: # put %resourcedata;
 4956:             my $reply=&Apache::lonnet::cput
 4957:                 ('resourcedata',\%resourcedata,$cdom,$cnum);
 4958:         }
 4959:     }
 4960: }
 4961: 
 4962: sub retrieve_image {
 4963:     my ($context,$res,$dirname,$cdom,$cname,$docroot,$destdir,$urlpath,$filename) = @_;
 4964:     my $contents;
 4965:     my $url = $urlpath.$filename;
 4966:     my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
 4967:     my $request=new HTTP::Request('GET',$url);
 4968:     my $response=&LONCAPA::LWPReq::makerequest($lonhost,$request);
 4969:     if ($response->is_success) { 
 4970:         $contents = $response->content;
 4971:         if (!-e "$docroot/$res") {
 4972:             mkdir("$docroot/$res",0755);
 4973:         }
 4974:         if (!-e "$docroot/$res/webimages") {
 4975:             mkdir("$docroot/$res/webimages",0755);
 4976:         }
 4977:         open(my $fh,'>',"$docroot/$res/webimages/$filename");
 4978:         print $fh $contents;
 4979:         close($fh);
 4980:         if ($context eq 'DOCS') {
 4981:             my $copyfile = $dirname.'/'.$filename;
 4982:             my $source = "$docroot/$res/webimages/$filename";
 4983:             my $fileresult;
 4984:             if (-e $source) {
 4985:                 $fileresult = &Apache::lonnet::process_coursefile('copy',$cname,$cdom,$copyfile,$source);
 4986:             }
 4987:             return $fileresult;
 4988:         } elsif ($context eq 'CSTR') {
 4989:             if (!-e "$destdir/resfiles/$res") {
 4990:                 mkdir("$destdir/resfiles/$res",0755);
 4991:             }
 4992:             if (!-e "$destdir/resfiles/$res/webimages") {
 4993:                 mkdir("$destdir/resfiles/$res/webimages",0755);
 4994:             }
 4995:             rename("$docroot/$res/webimages/$filename","$destdir/resfiles/$res/webimages/$filename");
 4996:             return 'ok';
 4997:         }
 4998:     } else {
 4999:         return -1;
 5000:     }
 5001: }
 5002: 
 5003: # ---------------------------------------------------------------- Process Blackboard Announcements
 5004: sub process_announce {
 5005:     my ($res,$docroot,$destdir,$settings,$globalresref,$seqstem,$resrcfiles) = @_;
 5006:     my $xmlfile = $docroot.'/'.$res.".dat";
 5007:     my @state = ();
 5008:     my @assess = ();
 5009:     my $id;
 5010:     my $p = HTML::Parser->new
 5011:     (
 5012:      xml_mode => 1,
 5013:      start_h =>
 5014:      [sub {
 5015:         my ($tagname, $attr) = @_;
 5016:         push @state, $tagname;
 5017:         if ("@state" eq "ANNOUNCEMENT TITLE") {
 5018:             $$settings{title} = $attr->{value};
 5019:             $$settings{startassessment} = ();
 5020:         } elsif ("@state" eq "ANNOUNCEMENT DESCRIPTION FLAGS ISHTML") {  
 5021:             $$settings{ishtml} = $attr->{value};          
 5022:         } elsif ("@state" eq "ANNOUNCEMENT DESCRIPTION FLAGS ISNEWLINELITERAL" ) {
 5023:             $$settings{isnewline} = $attr->{value};
 5024:         } elsif ("@state" eq "ANNOUNCEMENT ISPERMANENT" ) {
 5025:             $$settings{ispermanent} = $attr->{value};
 5026:         } elsif ("@state" eq "ANNOUNCEMENT DATES UPDATED") {
 5027:             $$settings{dates} = $attr->{value}; 
 5028:         } elsif ("@state" eq "ANNOUNCEMENT FILES STARTASSESSMENT" ) {
 5029:             $id = $attr->{id};
 5030:             %{$$settings{startassessment}{$id}} = ();
 5031:             push @assess,$id;
 5032:         } elsif ("@state" eq "ANNOUNCEMENT FILES STARTASSESSMENT ATTRIB" ) {
 5033:             my $key = $attr->{key};
 5034:             $$settings{startassessment}{$id}{$key} = $attr->{value};
 5035:         }
 5036:      }, "tagname, attr"],
 5037:      text_h =>
 5038:      [sub {
 5039:         my ($text) = @_;
 5040:         if ("@state" eq "ANNOUNCEMENT DESCRIPTION TEXT") {
 5041:             $$settings{text} = $text;
 5042:         }
 5043:       }, "dtext"],
 5044:      end_h =>
 5045:      [sub {
 5046:         my ($tagname) = @_;
 5047:         pop @state;
 5048:      }, "tagname"],
 5049:     );
 5050:     $p->unbroken_text(1);
 5051:     $p->parse_file($xmlfile);
 5052:     $p->eof;
 5053: 
 5054:     if (defined($$settings{text})) {
 5055:         if ($$settings{ishtml} eq "false") {
 5056:             if ($$settings{isnewline} eq "true") {
 5057:                 $$settings{text} =~ s#\n#<br/>#g;
 5058:             }
 5059:         } else {
 5060:             $$settings{text} = &HTML::Entities::decode($$settings{text});
 5061:         }
 5062:     }
 5063:   
 5064:     if (@assess > 0) {
 5065:         foreach my $id (@assess) {
 5066:             $$settings{text} = "A $$settings{startassessment}{$id}{assessment_type}, entitled $$globalresref{$$settings{startassessment}{$id}{assessment_id}}{title} is available. Click <a href='$seqstem/pages/$$settings{startassessment}{$id}{assessment_id}.page' target='quizpage'>here</a> to enter the page that contains the problems in this assessment.";
 5067:         }
 5068:     }
 5069: 
 5070:     open(FILE,'>',"$destdir/resfiles/$res.html");
 5071:     push @{$resrcfiles}, "$res.html";
 5072:     print FILE qq|<html>
 5073: <head>
 5074: <title>$$settings{title}</title>
 5075: </head>
 5076: <body bgcolor='#ffffff'>
 5077: <table>
 5078:  <tr>
 5079:   <td bgcolor='#CCCCFF'>$$settings{title} - announcement date: $$settings{dates}</td>
 5080:  </tr>
 5081: </table>
 5082: <br/>
 5083: $$settings{text}
 5084: |;
 5085:     print FILE qq|
 5086:   </body>
 5087:  </html>|;
 5088:     close(FILE);
 5089: }
 5090: 
 5091: # ---------------------------------------------------------------- Process Blackboard Content
 5092: sub process_content {
 5093:     my ($cms,$res,$context,$docroot,$destdir,$settings,$dom,$user,$resrcfiles,$packages,$hrefs) = @_;
 5094:     my $xmlfile = $docroot.'/'.$res.".dat";
 5095:     my $destresdir = $destdir;
 5096:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
 5097:     if ($context eq 'CSTR') {
 5098:         $destresdir =~ s{^\Q$londocroot/priv/\E}{/res/};
 5099:     } elsif ($context eq 'DOCS') {
 5100:         $destresdir =~ s{^\Q$londocroot/userfiles\E}{/uploaded};
 5101:     }
 5102:     my $filetag = '';
 5103:     if ($cms eq 'bb5') {
 5104:         $filetag = 'FILEREF';
 5105:     } elsif ($cms eq 'bb6') {
 5106:         $filetag = 'FILE';
 5107:     }
 5108:     my $filecount = 0;
 5109:     my @allrelfiles = ();
 5110:     my @state;
 5111:     @{$$settings{files}} = (); 
 5112:     my $p = HTML::Parser->new
 5113:     (
 5114:       xml_mode => 1,
 5115:       start_h =>
 5116:       [sub {
 5117:         my ($tagname, $attr) = @_;
 5118:         push @state, $tagname;
 5119:         if ("@state" eq "CONTENT ") {
 5120:             %{$$settings{maindata}} = ();
 5121:         } elsif ("@state" eq "CONTENT TITLECOLOR") {
 5122:             $$settings{titlecolor} =  $attr->{value};
 5123:         } elsif ("@state" eq "CONTENT MAINDATA TEXTCOLOR") {
 5124:             $$settings{maindata}{color} = $attr->{value};
 5125:         } elsif ("@state" eq "CONTENT MAINDATA FLAGS ISHTML") {  
 5126:             $$settings{maindata}{ishtml} = $attr->{value}; 
 5127:         } elsif ("@state" eq "CONTENT MAINDATA FLAGS ISNEWLINELITERAL") {  
 5128:             $$settings{maindata}{isnewline} = $attr->{value};
 5129:         } elsif ("@state" eq "CONTENT BODY TYPE") {
 5130:             $$settings{maindata}{bodytype} =  $attr->{value};
 5131:         } elsif ("@state" eq "CONTENT FLAGS ISAVAILABLE" ) {
 5132:             $$settings{isavailable} = $attr->{value};
 5133:         } elsif ("@state" eq "CONTENT FLAGS ISFOLDER" ) {
 5134:             $$settings{isfolder} = $attr->{value};
 5135:         } elsif ("@state" eq "CONTENT FLAGS LAUNCHINNEWWINDOW" ) {
 5136:             $$settings{newwindow} = $attr->{value};
 5137:         } elsif ("@state" eq "CONTENT FILES $filetag") {
 5138:             %{$$settings{files}[$filecount]} = ();
 5139:             %{$$settings{files}[$filecount]{registry}} = (); 
 5140:         } elsif ("@state" eq "CONTENT FILES FILEREF RELFILE" ) {
 5141:             $$settings{files}[$filecount]{'relfile'} = $attr->{value};
 5142:             push @allrelfiles, $attr->{value};
 5143:         } elsif ("@state" eq "CONTENT FILES $filetag MIMETYPE") {
 5144:             $$settings{files}[$filecount]{mimetype} = $attr->{value};
 5145:         } elsif ("@state" eq "CONTENT FILES $filetag CONTENTTYPE") {
 5146:             $$settings{files}[$filecount]{contenttype} = $attr->{value};
 5147:         } elsif ("@state" eq "CONTENT FILES $filetag FILEACTION") {
 5148:             $$settings{files}[$filecount]{fileaction} = $attr->{value};
 5149:         } elsif ("@state" eq "CONTENT FILES $filetag PACKAGEPARENT") {
 5150:             $$settings{files}[$filecount]{packageparent} = $attr->{value};
 5151:         } elsif ("@state" eq "CONTENT FILES $filetag LINKNAME") {
 5152:             $$settings{files}[$filecount]{linkname} = $attr->{value};
 5153:         } elsif ("@state" eq "CONTENT FILES $filetag REGISTRY REGISTRYENTRY") {
 5154:             my $key = $attr->{key};
 5155:             $$settings{files}[$filecount]{registry}{$key} = $attr->{value};
 5156:         }
 5157:       }, "tagname, attr"],
 5158:       text_h =>
 5159:       [sub {
 5160:         my ($text) = @_;
 5161:         if ("@state" eq "CONTENT TITLE") {
 5162:             $$settings{title} = $text;
 5163:         } elsif ( ("@state" eq "CONTENT MAINDATA TEXT") || ("@state" eq "CONTENT BODY TEXT") ) {
 5164:             $$settings{maindata}{text} = $text;
 5165:         }  elsif ("@state" eq "CONTENT FILES $filetag REFTEXT") {
 5166:             $$settings{files}[$filecount]{reftext} = $text;
 5167:         } elsif ("@state" eq "CONTENT FILES FILE NAME" ) {
 5168:             $$settings{files}[$filecount]{'relfile'} = $text;
 5169:             push @allrelfiles, $text;
 5170:         }
 5171:        }, "dtext"],
 5172:       end_h =>
 5173:       [sub {
 5174:         my ($tagname) = @_;
 5175:         if ("@state" eq "CONTENT FILES $filetag") {
 5176:             $filecount ++;
 5177:         }
 5178:         pop @state;
 5179:       }, "tagname"],
 5180:      );
 5181:     $p->unbroken_text(1);
 5182:     $p->parse_file($xmlfile);
 5183:     $p->eof;
 5184:     my $linktag = '';
 5185:     my $fontcol = '';
 5186:     if (@{$$settings{files}} > 0) {
 5187:         for (my $filecount=0;  $filecount<@{$$settings{files}}; $filecount++) {
 5188:             if ($$settings{files}[$filecount]{'fileaction'} eq 'embed') {
 5189:                 if ( $$settings{files}[$filecount]{reftext} =~ m#<\!\-\-\s_(\d+)\\_\s\-\-\>#) { 
 5190:                     my $newtag = qq|<img src="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}"/>|;
 5191:                     $$settings{maindata}{text} =~ s#<\!\-\-\s_/($1)\\_\s\-\-\>#$newtag#;
 5192:                 } elsif ( $$settings{files}[$filecount]{reftext} =~m#^_/(\d+)\\_$# ) {
 5193:                     my $reftag = $1;
 5194:                     my $newtag;
 5195:                     if ($$settings{files}[$filecount]{mimetype} =~ m/^image/) {
 5196:                         $newtag = qq|<img src="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}"|;
 5197:                         if ( defined($$settings{files}[$filecount]{registry}{alttext}) ) {
 5198:                             $newtag .= qq| alt="$$settings{files}[$filecount]{registry}{alttext}"|;
 5199:                         }
 5200:                         if ( defined($$settings{files}[$filecount]{registry}{alignment}) )
 5201: {
 5202:                             $newtag .= qq| align="$$settings{files}[$filecount]{registry}{alignment}"|; 
 5203:                         }
 5204:                         if ( defined($$settings{files}[$filecount]{registry}{border}) ) {
 5205:                             $newtag .= qq| border="$$settings{files}[$filecount]{registry}{border}"|;
 5206:                         }
 5207:                         $newtag .= " />";
 5208:                         my $reftext =  $$settings{files}[$filecount]{reftext};
 5209:                         my $fname = $$settings{files}[$filecount]{'relfile'};
 5210:                         $$settings{maindata}{text} =~ s/<!\-\-\sCOMMENT\sBLOCK\sFOR\sEMBEDDED\sFILE:\s$fname[\s\n]+DO\sNOT\sEDIT\sTHIS\sCOMMENT\sBLOCK[\s\n]+//;
 5211: #                      $$settings{maindata}{text} =~ s/DO\sNOT\sEDIT\sTHIS\sCOMMENT\sBLOCK[\s\n]+//;
 5212:                         $$settings{maindata}{text} =~ s/Move\swhole\scomment\sto\schange\sfile\splacement\swithin\spage\.[\s\n]+//;
 5213:                         $$settings{maindata}{text} =~ s/_\/$reftag\\_/$newtag/;
 5214:                         $$settings{maindata}{text} =~ s/END\sOF\sBLOCK\sON\sNEXT\sLINE[\s\n]+//;
 5215:                         $$settings{maindata}{text} =~ s/\-\->//;
 5216: #                      $$settings{maindata}{text} =~ s/<!\-\-\sCOMMENT\sBLOCK\sFOR\sEMBEDDED\sFILE:\s$fname[\s\n]+DO\sNOT\sEDIT\sTHIS\sCOMMENT\sBLOCK[\s\n\]+_\/$reftag\\_[\s\n]+END\sOF\sBLOCK\sON\sNEXT\sLINE[\s\n\]+\-\->/$newtag/;
 5217: #                      print STDERR $$settings{maindata}{text};
 5218:                     }
 5219:                 } else {
 5220:                     my $filename=$$settings{files}[$filecount]{'relfile'};
 5221:                     my $newfilename="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}";
 5222:                     $$settings{maindata}{text} =~ s#(src|SRC|value)=("|&quot;)$filename("|&quot;)#$1="$newfilename"#g;
 5223:                 }
 5224:             } elsif ($$settings{files}[$filecount]{fileaction} eq 'link') {
 5225:                 unless (($$settings{files}[$filecount]{packageparent} ne '') && (grep/^$$settings{files}[$filecount]{packageparent}$/,@{$$settings{files}}) ) {
 5226:                     $linktag .= qq|<a href="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}"|;
 5227:                     if ($$settings{newwindow} eq "true") {
 5228:                         $linktag .= qq| target="$res$filecount"|;
 5229:                     }
 5230:                     foreach my $entry (keys(%{$$settings{files}[$filecount]{registry}})) {
 5231:                         $linktag .= qq| $entry="$$settings{files}[$filecount]{registry}{$entry}"|;
 5232:                     }
 5233:                       $linktag .= qq|>$$settings{files}[$filecount]{linkname}</a><br/>\n|;
 5234:                 }
 5235:             } elsif ( ($$settings{files}[$filecount]{fileaction} eq 'PACKAGE') || ($$settings{files}[$filecount]{fileaction} eq 'package') ) {
 5236:                my $open_package = '';
 5237:                if ($$settings{files}[$filecount]{'relfile'} =~ m|\.zip$|i) {
 5238:                    $open_package = &expand_zip("$docroot/$res",$$settings{files}[$filecount]{'relfile'});
 5239:                }
 5240:                if ($open_package eq 'ok') {
 5241:                    opendir(DIR,"$docroot/$res");
 5242:                    my @dircontents = grep(!/^\./,readdir(DIR));
 5243:                    closedir(DIR);
 5244:                    push @{$resrcfiles}, @dircontents;
 5245:                    @{$$hrefs{$res}} = @dircontents;
 5246:                    push @{$packages}, $res;
 5247:                }
 5248:             } elsif ( ($$settings{files}[$filecount]{fileaction} eq 'BROKEN_IMAGE') && ($cms eq 'bb6') ) {
 5249:                 my $filename=$$settings{files}[$filecount]{'relfile'};
 5250:                 my $newfilename="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}";
 5251:                 $$settings{maindata}{text} =~ s#(src|SRC|value)=("|&quot;)$filename("|&quot;)#$1="$newfilename"#g;
 5252:             } elsif ( ($$settings{files}[$filecount]{fileaction} eq 'LINK') && ($cms eq 'bb6') ) {
 5253:                 my $filename=$$settings{files}[$filecount]{'relfile'};
 5254:                 my $newfilename="$destresdir/resfiles/$res/$$settings{files}[$filecount]{relfile}";
 5255:                 my $filetitle = $$settings{files}[$filecount]{'linkname'};
 5256:                 $$settings{maindata}{text} = '<a href="'.$newfilename.'">'.$filetitle.'</a><br /><br />'. $$settings{maindata}{text};
 5257:             }
 5258:         }
 5259:     }
 5260:     if (defined($$settings{maindata}{textcolor})) {
 5261:         $fontcol =  qq|<font color="$$settings{maindata}{textcolor}">|;
 5262:     }
 5263:     if (defined($$settings{maindata}{text})) {
 5264:         if ($$settings{maindata}{bodytype} eq "S") {
 5265:             $$settings{maindata}{text} =~ s#\n#<br/>#g;
 5266:         }
 5267:         if ($$settings{maindata}{ishtml} eq "false") {
 5268:             if ($$settings{maindata}{isnewline} eq "true") {
 5269:                 $$settings{maindata}{text} =~ s#\n#<br/>#g;
 5270:             }
 5271:         } else {
 5272: #            $$settings{maindata}{text} = &HTML::Entities::decode($$settings{maindata}{text});
 5273:         }
 5274:     }
 5275: 
 5276:     if (!open(FILE,'>',"$destdir/resfiles/$res.html")) {
 5277:         &Apache::lonnet::logthis("IMS import error: Cannot open file - $destdir/resfiles/$res.html - $!");
 5278:     } else {
 5279:         push @{$resrcfiles}, "$res.html";
 5280:         my $htmldoc = 0;
 5281: #        if ($$settings{maindata}{text} =~ m-&lt;(html|HTML)>.+&lt;\\(html|HTML)-) {
 5282:         if ($$settings{maindata}{text} =~ m-<(html|HTML)>-) {
 5283:             $htmldoc = 1;
 5284:         }
 5285:         unless ($htmldoc) {
 5286:             print FILE qq|<html>
 5287: <head>
 5288: <title>$$settings{title}</title>
 5289: </head>
 5290: <body bgcolor='#ffffff'>
 5291: $fontcol
 5292: |;
 5293:         }
 5294:         unless ($$settings{title} eq '') { 
 5295:             print FILE qq|$$settings{title}<br/><br/>\n|;
 5296:         }
 5297:         print FILE qq|
 5298: $$settings{maindata}{text}
 5299: $linktag|;
 5300:         unless ($htmldoc) {
 5301:             if (defined($$settings{maindata}{textcolor})) {
 5302:                 print FILE qq|</font>|;
 5303:             }
 5304:             print FILE qq|
 5305:   </body>
 5306:  </html>|;
 5307:         }
 5308:         close(FILE);
 5309:     }
 5310: }
 5311: 
 5312: 
 5313: sub process_angelboards {
 5314:     my ($context,$destdir,$boards,$timestamp,$crs,$cdom,$uname,$db_handling,$messages,$items,$resources,$hrefs,$tempdir,$longcrs) = @_;
 5315:     for (my $i=0; $i<@{$boards}; $i++) {
 5316:         my %msgidx = ();
 5317:         my $forumtext = '';
 5318:         my $boardname = 'bulletinpage_'.$$timestamp[$i];
 5319:         my $forumfile = $tempdir.'/_assoc/'.$$boards[$i].'/pg'.$$boards[$i].'.htm';
 5320:         my @state = ();
 5321:         my $p = HTML::Parser->new
 5322:         (
 5323:            xml_mode => 1,
 5324:            start_h =>
 5325:            [sub {
 5326:                 my ($tagname, $attr) = @_;
 5327:                 push @state, $tagname;
 5328:                 },  "tagname, attr"],
 5329:            text_h =>
 5330:            [sub {
 5331:                 my ($text) = @_;
 5332:                 if ("@state" eq "html body div div") {
 5333:                     $forumtext = $text;
 5334:                 }
 5335:               }, "dtext"],
 5336:             end_h =>
 5337:             [sub {
 5338:                   my ($tagname) = @_;
 5339:                   pop @state;
 5340:                }, "tagname"],
 5341:         );
 5342:         $p->parse_file($forumfile);
 5343:         $p->eof;
 5344: 
 5345:         my %boardinfo = (
 5346:                   'aaa_title' => $$items{$$resources{$$boards[$i]}{revitm}}{title},
 5347:                   'bbb_content' => $forumtext,
 5348:                   'ccc_webreferences' => '',
 5349:                   'uploaded.lastmodified' => time,
 5350:                   );
 5351:         my $msgcount = 0; 
 5352:                                                                                                      
 5353:         my $putresult = &Apache::lonnet::put($boardname,\%boardinfo,$cdom,$crs);
 5354:         if ($db_handling eq 'importall') {
 5355:             foreach my $msg_id (@{$$messages{$$boards[$i]}}) {
 5356:                 $msgcount ++;
 5357:                 $msgidx{$msg_id} = $msgcount;
 5358:                 my %contrib = (
 5359:                             'sendername' => 'NoName',
 5360:                             'senderdomain' => $cdom,
 5361:                             'screenname' => '',
 5362:                             'message' => $$items{$$resources{$msg_id}{revitm}}{title}
 5363:                             );
 5364:                 unless ( $$items{$$resources{$msg_id}{revitm}}{parentseq} eq $$resources{$$boards[$i]}{revitm} ) {
 5365:                     unless ( $msgidx{$$items{$$items{$$resources{$msg_id}{revitm}}{parentseq}}{resnum}} eq ''){
 5366:                         $contrib{replyto} = $msgidx{$$items{$$items{$$resources{$msg_id}{revitm}}{parentseq}}{resnum}};
 5367:                     }
 5368:                 }
 5369:                 if ( @{$$hrefs{$msg_id}} > 1 )  {
 5370:                     my $newurl = '';
 5371:                     foreach my $file (@{$$hrefs{$msg_id}}) {
 5372:                         unless ($file eq 'pg'.$msg_id.'.htm') {
 5373:                             $newurl = $msg_id.$file;
 5374:                              unless ($longcrs eq '') {
 5375:                                 if ($context eq 'CSTR') {
 5376:                                     if (!-e "/home/httpd/lonUsers/$cdom/$longcrs/userfiles") {
 5377:                                         mkdir("/home/httpd/lonUsers/$cdom/$longcrs/userfiles",0755);
 5378:                                     }
 5379:                                     if (!-e "/home/httpd/lonUsers/$cdom/$longcrs/userfiles/$newurl") {
 5380:                                         rename("$destdir/resfiles/$msg_id/$file","/home/httpd/lonUsers/$cdom/$longcrs/userfiles/$newurl");
 5381:                                     }
 5382:                                 }
 5383:                                 $contrib{attachmenturl} = '/uploaded/'.$cdom.'/'.$crs.'/'.$file;
 5384:                             }
 5385:                         }
 5386:                     }
 5387:                 }
 5388:                 my $xmlfile = $tempdir.'/_assoc/'.$msg_id.'/'.$$resources{$msg_id}{file};
 5389:                 &angel_message($msg_id,\%contrib,$xmlfile);
 5390:                 unless ($$resources{$msg_id}{file} eq '') {
 5391:                     unlink($xmlfile);
 5392:                 }
 5393:                 my $symb = 'bulletin___'.$$timestamp[$i].'___adm/wrapper/adm/'.$cdom.'/'.$uname.'/'.$$timestamp[$i].'/bulletinboard';
 5394:                 my $postresult = &addposting($symb,\%contrib,$cdom,$crs);
 5395:             }
 5396:         }
 5397:     }
 5398: }
 5399: 
 5400: # ---------------------------------------------------------------- Process ANGEL message board messages
 5401: sub angel_message {
 5402:     my ($msg_id,$contrib,$xmlfile) = @_;
 5403:     my @state = ();
 5404:     my $p = HTML::Parser->new
 5405:     (
 5406:        xml_mode => 1,
 5407:        start_h =>
 5408:        [sub {
 5409:              my ($tagname, $attr) = @_;
 5410:              push @state, $tagname;
 5411:              },  "tagname, attr"],
 5412:         text_h =>
 5413:         [sub {
 5414:              my ($text) = @_;
 5415:              if ("@state" eq "html body table tr td div small span") {
 5416:                   $$contrib{'plainname'} = $text;
 5417:              } elsif ("@state" eq "html body div div") {
 5418:                   $$contrib{'message'} .= '<br /><br />'.$text;
 5419:              }
 5420:            }, "dtext"],
 5421:          end_h =>
 5422:          [sub {
 5423:                my ($tagname) = @_;
 5424:                pop @state;
 5425:             }, "tagname"],
 5426:     );
 5427:     $p->parse_file($xmlfile);
 5428:     $p->eof;
 5429: }
 5430: 
 5431: # ---------------------------------------------------------------- ANGEL content
 5432: sub angel_content {
 5433:     my ($res,$docroot,$destdir,$settings,$dom,$user,$type,$title,$resrcfiles) = @_;
 5434:     my $xmlfile = $docroot.'/_assoc/'.$res.'/pg'.$res.'.htm';
 5435:     my $filecount = 0;
 5436:     my $firstline;
 5437:     my $lastline;
 5438:     my @buffer = ();
 5439:     my @state;
 5440:     @{$$settings{links}} = ();
 5441:     my $p = HTML::Parser->new
 5442:     (
 5443:        xml_mode => 1,
 5444:        start_h =>
 5445:        [sub {
 5446:              my ($tagname, $attr) = @_;
 5447:              push @state, $tagname;
 5448:             },  "tagname, attr"],
 5449:        text_h =>
 5450:        [sub {
 5451:              my ($text) = @_;
 5452:              if ("@state" eq "html body table tr td div small span") {
 5453:                  $$settings{'subtitle'} = $text;
 5454:              } elsif ("@state" eq "html body div div") {
 5455:                  $$settings{'text'} = $text;
 5456:              } elsif ("@state" eq "html body div div a") {
 5457:                 push @{$$settings{'links'}}, $text;
 5458:              }
 5459:             }, "dtext"],
 5460:        end_h =>
 5461:        [sub {
 5462:              my ($tagname) = @_;
 5463:              pop @state;
 5464:             }, "tagname"],
 5465:     );
 5466:     $p->parse_file($xmlfile);
 5467:     $p->eof;
 5468:     if ($type eq "PAGE") {
 5469:         open(FILE,'<',$xmlfile);
 5470:         @buffer = <FILE>;
 5471:         close(FILE);
 5472:         chomp(@buffer);
 5473:         $firstline = -1;
 5474:         $lastline = 0;
 5475:         for (my $i=0; $i<@buffer; $i++) {
 5476:             if (($firstline == -1) && ($buffer[$i] =~ m/<div\sclass="normalDiv"><div\sclass="normalSpan">/)) {
 5477:                 $firstline = $i;
 5478:                 $buffer[$i] = substr($buffer[$i],index($buffer[$i],'"normalSpan"')+13);
 5479:             }
 5480:             if (($firstline > -1) && ($buffer[$i] =~ m-<p></p></div></div>-)) {
 5481:                 $buffer[$i] = substr($buffer[$i],0,index($buffer[$i],'<p></p></div></div>'));
 5482:                 $lastline = $i;
 5483:             }
 5484:         }
 5485:     }
 5486:     open(FILE,'>',"$destdir/resfiles/$res.html");
 5487:     push @{$resrcfiles}, "$res.html";
 5488:     print FILE qq|<html>
 5489: <head>
 5490: <title>$title</title>
 5491: </head>
 5492: <body bgcolor='#ffffff'>
 5493:     |;
 5494:     unless ($title eq '') {
 5495:         print FILE qq|<b>$title</b><br/>\n|;
 5496:     }
 5497:     unless ($$settings{subtitle} eq '') {
 5498:         print FILE qq|$$settings{subtitle}<br/>\n|;
 5499:     }
 5500:     print FILE "<br/>\n";
 5501:     if ($type eq "LINK") {
 5502:         foreach my $link (@{$$settings{links}}) {
 5503:             print FILE qq|<a href="$link">$link</a><br/>\n|; 
 5504:         }
 5505:     } elsif ($type eq "PAGE") {
 5506:         if ($firstline > -1) {
 5507:             for (my $i=$firstline; $i<=$lastline; $i++) {
 5508:                 print FILE "$buffer[$i]\n";
 5509:             }
 5510:         }
 5511:     }
 5512:     print FILE qq|
 5513:   </body>
 5514:  </html>|;
 5515:     close(FILE);
 5516: }
 5517: 
 5518: # ---------------------------------------------------------------- WebCT content
 5519: sub webct4_content {
 5520:     my ($res,$docroot,$destdir,$settings,$dom,$user,$type,$title,$resrcfiles) = @_;
 5521:     if (defined($$settings{url})) {
 5522:         if (!open(FILE,'>',"$destdir/resfiles/$res.html")) {
 5523:             &Apache::lonnet::logthis("IMS import error: Cannot open file - $destdir/resfiles/$res.html - $!");
 5524:         } else {
 5525:             push(@{$resrcfiles}, "$res.html");
 5526:             my $linktag = qq|<a href="$$settings{url}"|;
 5527:             if ($title ne '') {
 5528:                 $linktag .= qq|>$title</a>|;
 5529:             } else {
 5530:                 $linktag .= qq|>$$settings{url}|;
 5531:             }
 5532:             print FILE qq|<html>
 5533: <head>
 5534: <title>$title</title>
 5535: </head>
 5536: <body bgcolor='#ffffff'>
 5537: $linktag
 5538: </body>
 5539: </html>|;
 5540:             close(FILE);
 5541:         }
 5542:     }
 5543: }
 5544: 
 5545: sub process_html {
 5546:     my ($text,$caller,$html_cond,$context,$res,$dirname,$cdom,$cnum,$docroot,$destdir) = @_;
 5547:     my $pathstart;
 5548:     if ($context eq 'CSTR') {
 5549:         $pathstart = '../..';
 5550:     } else {
 5551:         $pathstart = $dirname;
 5552:     }
 5553:     if ($caller eq 'bb5') {
 5554:         if ($html_cond eq 'true') {
 5555:             $$text = &HTML::Entities::decode($$text);
 5556:         }
 5557:     } elsif ($caller eq 'bb6') {
 5558:         if ($html_cond eq 'HTML') {
 5559:             $$text = &HTML::Entities::decode($$text);
 5560:         }
 5561:     }
 5562:     if ($$text =~ m#<img src=['"]?(https?://[^\s]+/)([^/\s\'"]+)['"]?[^>]*>#) {
 5563:         if (&retrieve_image($context,$res,$dirname,$cdom,$cnum,$docroot,$destdir,$1,$2) eq 'ok') {
 5564:             $$text =~ s#(<img src=['"]?)(https?://[^\s]+/)([^/\s'"]+)(['"]?[^>]*>)#$1$pathstart/resfiles/$res/webimages/$3$4#g;
 5565:         }
 5566:     }
 5567:     $$text =~ s#(<img src=[^>]+)/*>#$1 />#gi;
 5568:     $$text =~ s#<br>#<br />#g;
 5569:     return;
 5570: }
 5571: 
 5572: sub add_images_links {
 5573:     my ($type,$context,$settings,$id,$dirname,$res) = @_;
 5574:     my ($image,$imglink,$url,$pathstart);
 5575:     if ($context eq 'CSTR') {
 5576:         $pathstart = '../..';
 5577:     } else {
 5578:         $pathstart = $dirname;
 5579:     }
 5580:     if ((defined($$settings{$id}{$type}{image})) && ($$settings{$id}{$type}{image} ne '')) {
 5581:         if ( $$settings{$id}{$type}{style} eq 'Inline' ) {
 5582:             $image = qq|<br /><img src="$pathstart/resfiles/$res/$$settings{$id}{$type}{image}" alt="$$settings{$id}{$type}{label}"/><br />|;
 5583:         } else {
 5584:             $imglink = qq|<br /><a href="$pathstart/resfiles/$res/$$settings{$id}{$type}{image}">$$settings{$id}{$type}{label}</a><br />|;
 5585:         }
 5586:     }
 5587:     if ((defined($$settings{$id}{$type}{link})) && ($$settings{$id}{$type}{link} ne '' )) {
 5588:         $url = qq|<br /><a href="$$settings{$id}{$type}{link}">$$settings{$id}{$type}{linkname}</a><br />|;
 5589:     }
 5590:     return $image.$imglink.$url; 
 5591: }
 5592: 
 5593: sub remove_html {
 5594:     my ($choice_text) = @_;
 5595:     return $choice_text;
 5596: }
 5597: 
 5598: 
 5599: 1;
 5600: __END__

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