Annotation of loncom/homework/radiobuttonresponse.pm, revision 1.153.6.9

1.22      albertel    1: # The LearningOnline Network with CAPA
                      2: # mutliple choice style responses
1.31      albertel    3: #
1.153.6.9! foxr        4: # $Id: radiobuttonresponse.pm,v 1.153.6.8 2012/01/30 11:36:55 foxr Exp $
1.31      albertel    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
1.130     foxr       21: # along with LON-CAPA; if not, write to the Free Software# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1.31      albertel   22: #
                     23: # /home/httpd/html/adm/gpl.txt
                     24: #
                     25: # http://www.lon-capa.org/
                     26: #
1.1       albertel   27: 
                     28: package Apache::radiobuttonresponse;
                     29: use strict;
1.42      albertel   30: use HTML::Entities();
1.85      albertel   31: use Apache::lonlocal;
1.100     albertel   32: use Apache::lonnet;
1.115     foxr       33: use Apache::response;
1.153.6.5  foxr       34: use Apache::caparesponse;
1.1       albertel   35: 
1.120     foxr       36: my $default_bubbles_per_line = 10;
1.153.6.3  foxr       37: my @alphabet      = ( 'A' .. 'Z' ); # Foil labels.
                     38: 
                     39: 
1.121     foxr       40: 
1.36      harris41   41: BEGIN {
1.153     foxr       42:     &Apache::lonxml::register( 'Apache::radiobuttonresponse',
                     43:         ('radiobuttonresponse') );
1.1       albertel   44: }
                     45: 
1.121     foxr       46: sub bubble_line_count {
1.153     foxr       47:     my ( $numfoils, $bubbles_per_line ) = @_;
1.121     foxr       48:     my $bubble_lines;
1.153     foxr       49:     $bubble_lines = int( $numfoils / $bubbles_per_line );
                     50:     if ( ( $numfoils % $bubbles_per_line ) != 0 ) {
                     51:         $bubble_lines++;
1.121     foxr       52:     }
                     53:     return $bubble_lines;
1.153     foxr       54: 
1.121     foxr       55: }
                     56: 
1.1       albertel   57: sub start_radiobuttonresponse {
1.153     foxr       58:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                     59:       @_;
1.83      albertel   60:     my $result;
1.115     foxr       61: 
1.83      albertel   62:     #when in a radiobutton response use these
1.153     foxr       63:     &Apache::lonxml::register( 'Apache::radiobuttonresponse',
                     64:         ( 'foilgroup', 'foil', 'conceptgroup' ) );
                     65:     push( @Apache::lonxml::namespace, 'radiobuttonresponse' );
                     66:     my $id = &Apache::response::start_response( $parstack, $safeeval );
1.120     foxr       67: 
1.153     foxr       68:     %Apache::hint::radiobutton = ();
1.85      albertel   69:     undef(%Apache::response::foilnames);
1.153     foxr       70:     if ( $target eq 'meta' ) {
                     71:         $result = &Apache::response::meta_package_write('radiobuttonresponse');
                     72:     }
                     73:     elsif ( $target eq 'edit' ) {
                     74:         $result .=
                     75:             &Apache::edit::start_table($token)
                     76:           . '<tr><td>'
                     77:           . &Apache::lonxml::description($token)
                     78:           . &Apache::loncommon::help_open_topic('Radio_Response_Problems')
                     79:           . '</td>'
                     80:           . '<td><span class="LC_nobreak">'
                     81:           . &mt('Delete?') . ' '
                     82:           . &Apache::edit::deletelist( $target, $token )
                     83:           . '</span></td>'
                     84:           . '<td>&nbsp;'
                     85:           . &Apache::edit::end_row()
                     86:           . &Apache::edit::start_spanning_row();
                     87:         $result .= &Apache::edit::text_arg( 'Max Number Of Shown Foils:',
                     88:             'max', $token, '4' )
                     89:           . '&nbsp;' x 3
                     90:           . &Apache::edit::select_arg( 'Randomize Foil Order:',
                     91:             'randomize', [ 'yes', 'no' ], $token )
                     92:           . '&nbsp;' x 3
                     93:           . &Apache::edit::select_arg(
                     94:             'Display Direction:', 'direction',
                     95:             [ 'vertical', 'horizontal' ], $token
                     96:           )
                     97:           . &Apache::edit::end_row()
                     98:           . &Apache::edit::start_spanning_row() . "\n";
                     99:     }
                    100:     elsif ( $target eq 'modified' ) {
                    101:         my $constructtag =
                    102:           &Apache::edit::get_new_args( $token, $parstack, $safeeval, 'max',
                    103:             'randomize', 'direction' );
                    104:         if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
                    105:     }
                    106:     elsif ( $target eq 'tex' ) {
                    107:         my $type =
                    108:           &Apache::lonxml::get_param( 'TeXtype', $parstack, $safeeval, undef,
                    109:             0 );
                    110:         if ( $type eq '1' ) {
                    111:             $result .= ' \renewcommand{\labelenumi}{\arabic{enumi}.}';
                    112:         }
                    113:         elsif ( $type eq 'A' ) {
                    114:             $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}';
                    115:         }
                    116:         elsif ( $type eq 'a' ) {
                    117:             $result .= ' \renewcommand{\labelenumi}{\alph{enumi}.}';
                    118:         }
                    119:         elsif ( $type eq 'i' ) {
                    120:             $result .= ' \renewcommand{\labelenumi}{\roman{enumi}.}';
                    121:         }
                    122:         else {
                    123:             $result .= ' \renewcommand{\labelenumi}{\Alph{enumi}.}';
                    124:         }
1.153.6.4  foxr      125: 
1.153     foxr      126:     }
                    127:     elsif ( $target eq 'analyze' ) {
                    128:         my $part_id = "$Apache::inputtags::part.$id";
1.131     raeburn   129:         $Apache::lonhomework::analyze{"$part_id.type"} = 'radiobuttonresponse';
1.153     foxr      130:         push( @{ $Apache::lonhomework::analyze{"parts"} }, $part_id );
1.83      albertel  131:     }
                    132:     return $result;
1.1       albertel  133: }
                    134: 
                    135: sub end_radiobuttonresponse {
1.153     foxr      136:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                    137:       @_;
1.83      albertel  138:     my $result;
1.153     foxr      139:     if ( $target eq 'edit' ) { $result = &Apache::edit::end_table(); }
1.153.6.4  foxr      140: 
1.83      albertel  141:     &Apache::response::end_response;
                    142:     pop @Apache::lonxml::namespace;
1.153     foxr      143:     &Apache::lonxml::deregister( 'Apache::radiobuttonresponse',
                    144:         ( 'foilgroup', 'foil', 'conceptgroup' ) );
1.85      albertel  145:     undef(%Apache::response::foilnames);
1.83      albertel  146:     return $result;
1.1       albertel  147: }
                    148: 
1.153     foxr      149: %Apache::response::foilgroup = ();
                    150: 
1.1       albertel  151: sub start_foilgroup {
1.153     foxr      152:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                    153:       @_;
                    154:     %Apache::response::foilgroup               = ();
                    155:     $Apache::radiobuttonresponse::conceptgroup = 0;
                    156:     &Apache::response::pushrandomnumber( undef, $target );
1.151     raeburn   157:     return;
1.5       albertel  158: }
                    159: 
1.15      albertel  160: sub storesurvey {
1.144     raeburn   161:     my ($style) = @_;
1.99      albertel  162:     if ( !&Apache::response::submitted() ) { return ''; }
1.153     foxr      163:     my $response = $env{ 'form.HWVAL_' . $Apache::inputtags::response['-1'] };
1.83      albertel  164:     &Apache::lonxml::debug("Here I am!:$response:");
1.153     foxr      165:     if ( $response !~ /[0-9]+/ ) { return ''; }
                    166:     my $part       = $Apache::inputtags::part;
                    167:     my $id         = $Apache::inputtags::response['-1'];
                    168:     my @whichfoils = @{ $Apache::response::foilgroup{'names'} };
1.83      albertel  169:     my %responsehash;
1.153     foxr      170:     $responsehash{ $whichfoils[$response] } = $response;
                    171:     my $responsestr = &Apache::lonnet::hash2str(%responsehash);
                    172:     $Apache::lonhomework::results{"resource.$part.$id.submission"} =
                    173:       $responsestr;
                    174:     my %previous =
                    175:       &Apache::response::check_for_previous( $responsestr, $part, $id );
1.144     raeburn   176:     my $ad;
1.153     foxr      177: 
                    178:     if ( $style eq 'anonsurvey' ) {
                    179:         $ad = $Apache::lonhomework::results{"resource.$part.$id.awarddetail"} =
                    180:           'ANONYMOUS';
                    181:     }
                    182:     elsif ( $style eq 'anonsurveycred' ) {
                    183:         $ad = $Apache::lonhomework::results{"resource.$part.$id.awarddetail"} =
                    184:           'ANONYMOUS_CREDIT';
                    185:     }
                    186:     elsif ( $style eq 'surveycred' ) {
                    187:         $ad = $Apache::lonhomework::results{"resource.$part.$id.awarddetail"} =
                    188:           'SUBMITTED_CREDIT';
                    189:     }
                    190:     else {
                    191:         $ad = $Apache::lonhomework::results{"resource.$part.$id.awarddetail"} =
                    192:           'SUBMITTED';
1.144     raeburn   193:     }
1.153     foxr      194:     &Apache::response::handle_previous( \%previous, $ad );
1.83      albertel  195:     &Apache::lonxml::debug("submitted a $response<br />\n");
                    196:     return '';
1.15      albertel  197: }
                    198: 
1.32      albertel  199: sub grade_response {
1.153     foxr      200:     my ( $answer, $whichfoils, $bubbles_per_line ) = @_;
1.123     albertel  201: 
1.99      albertel  202:     if ( !&Apache::response::submitted() ) { return; }
1.83      albertel  203:     my $response;
1.116     foxr      204: 
1.153     foxr      205:     if ( $env{'form.submitted'} eq 'scantron' ) {
                    206:         $response =
                    207:           &Apache::response::getresponse( 1, undef,
                    208:             &bubble_line_count( scalar( @{$whichfoils} ), $bubbles_per_line ),
                    209:             $bubbles_per_line );
                    210: 
                    211:     }
                    212:     else {
                    213:         $response = $env{ 'form.HWVAL_' . $Apache::inputtags::response['-1'] };
1.83      albertel  214:     }
1.120     foxr      215: 
1.153     foxr      216:     if ( $response !~ /[0-9]+/ ) { return; }
                    217:     my $part = $Apache::inputtags::part;
                    218:     my $id   = $Apache::inputtags::response['-1'];
1.83      albertel  219:     my %responsehash;
1.153     foxr      220:     $responsehash{ $whichfoils->[$response] } = $response;
                    221:     my $responsestr = &Apache::lonnet::hash2str(%responsehash);
                    222:     my %previous =
                    223:       &Apache::response::check_for_previous( $responsestr, $part, $id );
                    224:     $Apache::lonhomework::results{"resource.$part.$id.submission"} =
                    225:       $responsestr;
1.83      albertel  226:     &Apache::lonxml::debug("submitted a $response<br />\n");
                    227:     my $ad;
1.153     foxr      228: 
                    229:     if ( $response == $answer ) {
                    230:         $ad = 'EXACT_ANS';
                    231:     }
                    232:     else {
                    233:         $ad = 'INCORRECT';
1.83      albertel  234:     }
1.153     foxr      235:     $Apache::lonhomework::results{"resource.$part.$id.awarddetail"} = $ad;
                    236:     &Apache::response::handle_previous( \%previous, $ad );
1.32      albertel  237: }
                    238: 
1.1       albertel  239: sub end_foilgroup {
1.153     foxr      240:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                    241:       @_;
1.29      albertel  242: 
1.83      albertel  243:     my $result;
1.121     foxr      244:     my $bubble_lines;
                    245:     my $answer_count;
1.153     foxr      246:     my $id               = $Apache::inputtags::response['-1'];
                    247:     my $part             = $Apache::inputtags::part;
                    248:     my $bubbles_per_line = &getbubblesnum( $part, $id );
                    249: 
1.153.6.9! foxr      250: 
1.153     foxr      251:     if (   $target eq 'grade'
                    252:         || $target eq 'web'
                    253:         || $target eq 'answer'
                    254:         || $target eq 'tex'
                    255:         || $target eq 'analyze' )
                    256:     {
                    257:         my $style = $Apache::lonhomework::type;
                    258:         my $direction =
                    259:           &Apache::lonxml::get_param( 'direction', $parstack, $safeeval, '-2' );
                    260:         if (
                    261:             (
                    262:                    ( $style eq 'survey' )
                    263:                 || ( $style eq 'surveycred' )
                    264:                 || ( $style eq 'anonsurvey' )
                    265:                 || ( $style eq 'anonsurveycred' )
                    266:             )
                    267:             && ( $target ne 'analyze' )
                    268:           )
                    269:         {
                    270:             if ( $target eq 'web' || $target eq 'tex' ) {
                    271:                 $result = &displayallfoils( $direction, $target );
                    272:             }
                    273:             elsif ( $target eq 'answer' ) {
                    274:                 $result = &displayallanswers();
                    275:             }
                    276:             elsif ( $target eq 'grade' ) {
                    277:                 $result = &storesurvey($style);
                    278:             }
                    279:             $answer_count =
                    280:               scalar( @{ $Apache::response::foilgroup{'names'} } );
                    281: 
                    282:         }
                    283:         else {
                    284: 
                    285:             my $name;
                    286:             my $max =
                    287:               &Apache::lonxml::get_param( 'max', $parstack, $safeeval, '-2' );
                    288:             my $randomize =
                    289:               &Apache::lonxml::get_param( 'randomize', $parstack, $safeeval,
                    290:                 '-2' );
                    291:             my ( $answer, @shown ) = &whichfoils( $max, $randomize );
                    292:             $answer_count = scalar(@shown);
                    293: 
                    294:             if ( $target eq 'web' || $target eq 'tex' ) {
                    295:                 $result =
                    296:                   &displayfoils( $target, $answer, \@shown, $direction,
                    297:                     $bubbles_per_line );
                    298:             }
                    299:             elsif ( $target eq 'answer' ) {
                    300:                 $result =
                    301:                   &displayanswers( $answer, \@shown, $bubbles_per_line );
                    302:             }
                    303:             elsif ( $target eq 'grade' ) {
                    304:                 &grade_response( $answer, \@shown, $bubbles_per_line );
                    305:             }
                    306:             elsif ( $target eq 'analyze' ) {
                    307:                 my $bubble_lines =
                    308:                   &bubble_line_count( $answer_count, $bubbles_per_line );
                    309:                 &Apache::response::analyze_store_foilgroup( \@shown,
                    310:                     [ 'text', 'value', 'location' ] );
                    311:                 my $part_id = "$part.$id";
                    312:                 push(
                    313:                     @{ $Apache::lonhomework::analyze{"$part_id.options"} },
                    314:                     ( 'true', 'false' )
                    315:                 );
1.121     foxr      316: 
1.153     foxr      317:             }
                    318:         }
                    319:         $Apache::lonxml::post_evaluate = 0;
                    320:     }
                    321:     if ( $target eq 'web' ) {
                    322:         &Apache::response::setup_prior_tries_hash( \&format_prior_answer,
                    323:             [ \%Apache::response::foilgroup ] );
1.114     albertel  324:     }
1.128     foxr      325:     &Apache::response::poprandomnumber();
1.153     foxr      326:     $bubble_lines = &bubble_line_count( $answer_count, $bubbles_per_line );
                    327:     &Apache::lonxml::increment_counter( $bubble_lines, "$part.$id" );
                    328:     if ( $target eq 'analyze' ) {
                    329:         &Apache::lonhomework::set_bubble_lines();
1.128     foxr      330:     }
1.83      albertel  331:     return $result;
1.6       albertel  332: }
                    333: 
1.151     raeburn   334: sub getbubblesnum {
1.153     foxr      335:     my ( $part, $id ) = @_;
1.151     raeburn   336:     my $bubbles_per_line;
                    337:     my $default_numbubbles = $default_bubbles_per_line;
1.153     foxr      338:     if (   ( $env{'form.bubbles_per_row'} =~ /^\d+$/ )
                    339:         && ( $env{'form.bubbles_per_row'} > 0 ) )
                    340:     {
1.151     raeburn   341:         $default_numbubbles = $env{'form.bubbles_per_row'};
                    342:     }
1.153     foxr      343:     $bubbles_per_line = &Apache::response::get_response_param( $part . "_$id",
                    344:         'numbubbles', $default_numbubbles );
1.151     raeburn   345:     return $bubbles_per_line;
                    346: }
                    347: 
1.6       albertel  348: sub getfoilcounts {
1.83      albertel  349:     my @names;
1.153     foxr      350:     my $truecnt  = 0;
                    351:     my $falsecnt = 0;
1.83      albertel  352:     my $name;
                    353:     if ( $Apache::response::foilgroup{'names'} ) {
1.153     foxr      354:         @names = @{ $Apache::response::foilgroup{'names'} };
1.6       albertel  355:     }
1.83      albertel  356:     foreach $name (@names) {
1.153     foxr      357:         if ( $Apache::response::foilgroup{ $name . '.value' } eq 'true' ) {
                    358:             $truecnt++;
                    359:         }
                    360:         elsif ( $Apache::response::foilgroup{ $name . '.value' } eq 'false' ) {
                    361:             $falsecnt++;
                    362:         }
1.83      albertel  363:     }
1.153     foxr      364:     return ( $truecnt, $falsecnt );
1.5       albertel  365: }
                    366: 
1.114     albertel  367: sub format_prior_answer {
1.153     foxr      368:     my ( $mode, $answer, $other_data ) = @_;
1.114     albertel  369:     my $foil_data = $other_data->[0];
1.153     foxr      370:     my %response  = &Apache::lonnet::str2hash($answer);
                    371:     my ($name)    = keys(%response);
                    372:     return
                    373:         '<span class="LC_prior_radiobutton">'
                    374:       . $foil_data->{ $name . '.text' }
                    375:       . '</span>';
1.114     albertel  376: 
1.112     albertel  377: }
                    378: 
1.153.6.8  foxr      379: ## 
                    380: # Return the last survey response.  The logic is slightly different than that of 
                    381: # get_last_responses.  TODO: See if there are chunks of code betweenthis and
                    382: # get_last_reponses that are common and can be factored.
                    383: #
                    384: # @param $part - Problem part under consideration.
                    385: # @param $showanswer - True if answers should be shown.
                    386: # @param $id         - Problem id.
                    387: #
                    388: # @return hash reference.
                    389: # @retval reference to the has indexed by answer selection that 
                    390: #         indicates the most recent answer.
                    391: #
                    392: sub get_last_survey_response {
                    393:     my ($part, $showanswer, $id) = @_;
1.153.6.5  foxr      394: 
1.153.6.8  foxr      395:     my $newvariation;
                    396:     my $lastresponse;		# stringified last response.
1.153.6.5  foxr      397: 
1.153     foxr      398:     if (
                    399:         (
                    400:             (
                    401:                 $Apache::lonhomework::history{"resource.$part.type"} eq
                    402:                 'randomizetry'
                    403:             )
                    404:             || ( $Apache::lonhomework::type eq 'randomizetry' )
                    405:         )
                    406:         && ( $Apache::inputtags::status[-1] eq 'CAN_ANSWER' )
                    407:       )
                    408:     {
                    409:         if ( $env{ 'form.' . $part . '.rndseed' } ne
                    410:             $Apache::lonhomework::history{"resource.$part.rndseed"} )
                    411:         {
1.147     raeburn   412:             $newvariation = 1;
                    413:         }
                    414:     }
1.153     foxr      415:     unless (
                    416:         (
                    417:             (
                    418:                 $Apache::lonhomework::history{"resource.$part.type"} eq
                    419:                 'anonsurvey'
                    420:             )
                    421:             || ( $Apache::lonhomework::history{"resource.$part.type"} eq
                    422:                 'anonsurveycred' )
                    423:         )
                    424:         && ( defined( $env{'form.grade_symb'} ) )
                    425:         || ( $newvariation && !$showanswer )
                    426:       )
                    427:     {
                    428:         $lastresponse =
                    429:           $Apache::lonhomework::history{"resource.$part.$id.submission"};
1.144     raeburn   430:     }
1.153     foxr      431:     my %lastresponse = &Apache::lonnet::str2hash($lastresponse);
1.153.6.8  foxr      432:    
                    433: 
                    434:     return \%lastresponse;
                    435: 
                    436: }
                    437: ##
                    438: # Removes the names from a foil group that are marked as unused.
                    439: #
                    440: # @param $names - reference to the array of names to filter.
                    441: #
                    442: # @return arrayref
                    443: # @retval reference to the filtered array.
                    444: #
                    445: sub remove_unused {
                    446:     my ($names) = @_;
                    447:     my @result;
                    448: 
                    449:     foreach my $name (@{$names}) {
                    450: 	if ($Apache::response::foilgroup{$name . '.value'} ne 'unused') {
                    451: 	    push(@result, $name);
                    452: 	}
                    453:     }
                    454:     return \@result;
                    455: }
                    456: ## 
                    457: # Displays all foils in a survey type problem for HTML rendition.
                    458: # TODO: See if there is any logic in this sub that can be shared
                    459: #      with display_foils_html
                    460: #
                    461: # @param $names        - ref to array of names of the foils to display.
                    462: # @param $part         - Problem part number.
                    463: # @param $showanswer   - If true, show the answers.
                    464: # @param $lastresponse - Ref to the last response hash.
                    465: # @param $direction    - Display direction of the radiobuttons.
                    466: #
                    467: # @return string
                    468: # @retval HTML required to display the resource in a browser.
                    469: #
                    470: sub display_survey_html {
                    471:     my ($names, $part, $showanswer, $lastresponse, $direction) = @_;
                    472:     my $result;
                    473: 
                    474:     # Figure out a few fragments of html that depend onthe 
                    475:     # orientation of the radiobuttons:
                    476:     # closing_html - HTML to emit at the end of the resource.
                    477:     # pre_foil     - HTML to emit prior to each foil.
                    478:     # post_foil    - HTML to emit following each foil.
                    479:     #
                    480:     #  The opening HTML is just added to the $result now
                    481:     #
                    482:     #  Figuring these outin advance compresses the loop over foils into something
                    483:     #  pretty simple:
                    484:     #
                    485:     # NOTE: There's probably a really cool way to do this with style sheets
                    486:     #       and picking the selector based on the orientation, if someone wants to puzzle
                    487:     #       that out.  In that case, probably the whole thing lives in a <div> and each
                    488:     #       foil lives in a <p>
                    489:     #
                    490: 
                    491:     my $closing_html;
                    492:     my $pre_foil;
                    493:     my $post_foil;
                    494: 	
                    495:     if ($direction eq 'horizontal') {
                    496: 	$result       .= '<table><tr>';
                    497: 	$closing_html = '</tr></table>';
                    498: 	$pre_foil     = '<td>';
                    499: 	$post_foil    = '</td>';
                    500:     } else {
                    501: 	$pre_foil     = '<br />';
                    502:     }
                    503:     # Different rendering depending on whether answers are shown:
                    504: 
                    505: 
1.147     raeburn   506:     if ($showanswer) {
1.153.6.8  foxr      507: 	foreach my $name (@{$names}) {
                    508: 
                    509: 	    $result .= $pre_foil;
                    510: 	    my $foiltext =  $Apache::response::foilgroup{$name . '.text'};
                    511: 
                    512: 	    # Bold the prior  response:
                    513: 
                    514: 	    if (defined($lastresponse->{$name})) {
                    515: 		$result .= '<b>' . $foiltext . '</b>';
                    516: 	    } else {
                    517: 		$result .= $foiltext;
                    518: 	    }
                    519: 
                    520: 	    $result .= $post_foil;
                    521: 	}
                    522:     } else {
                    523: 	my $temp = 0;
                    524: 	foreach my $name (@{$names}) {
                    525: 	    $result .=  $pre_foil;
                    526: 
                    527: 	    $result .= &html_radiobutton(
                    528: 		$part, $Apache::inputtags::response['-1'], $name, $lastresponse, $temp
                    529: 	     );
                    530: 
                    531: 	    $result .= $post_foil;
                    532: 	    $temp++;
                    533: 				       
                    534: 	}
1.153     foxr      535:     }
1.153.6.8  foxr      536: 
                    537:     $result .= $closing_html;
                    538:     return $result;
                    539: 
                    540: }
                    541: 
1.153.6.9! foxr      542: ##
        !           543: #  Generate LaTeX for surveys.
        !           544: #  
        !           545: #   @param $names - names of the foils to display.
        !           546: #   @param $showanswer - flag that is true to display answers.
        !           547: #   @param $lastresponse - Reference to a hash the indicates the last response.
        !           548: #   @param $direction    - Orientation of foils ('horiztonal' or otherwise).
        !           549: #   @param $venv         - LaTeX name for vertical env.
        !           550: #
        !           551: #   @return string
        !           552: #   @retval LaTeX rendering of the survey question.
        !           553: 
        !           554: sub latex_survey {
        !           555:     my ($names, $showanswer, $lastresponse, $direction, $venv) = @_;
        !           556: 
        !           557:     my $result;
        !           558: 
        !           559: 	
        !           560:  
        !           561: 
        !           562:     if ($showanswer) {
        !           563: 	
        !           564: 	$result .= "\\begin{$venv}";
        !           565: 	foreach my $name (@{$names}) {
        !           566: 	    
        !           567: 	    
        !           568: 	    $result .= '\item \vskip -2mm ';
        !           569: 	    
        !           570: 	    if ( defined( $lastresponse->{$name} ) ) {
        !           571: 		$result .= '}';
        !           572: 	    }
        !           573: 	    $result .= $Apache::response::foilgroup{ $name . '.text' } . ' ';
        !           574: 	}
        !           575: 	$result .= "\\end{$venv}";
        !           576: 
        !           577:     } elsif ( $env{'form.pdfFormFields'} eq 'yes'
        !           578: 	      && $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
        !           579: 	$result .= &display_pdf_form($names, $direction, $venv);
        !           580:     } else {
        !           581: 	if ($direction eq 'horizontal') {
        !           582: 	    my @foil_texts = &get_foil_texts($names);
        !           583: 	    $result .=  &Apache::caparesponse::make_horizontal_latex_bubbles(
        !           584: 	    $names, \@foil_texts, '$\bigcirc$');
        !           585: 	} else {
        !           586: 	    $result .= "\\begin{$venv}";
        !           587: 
        !           588: 	    my $temp = 0;
        !           589: 	    my $i    = 0;
        !           590: 	    foreach my $name (@{$names}) {
        !           591: 
        !           592: 		$result .= '\item \vskip -2mm ';
        !           593: 		
        !           594: 		if ($env{'form.pdfFormFields'} ne 'yes'
        !           595: 		    or $Apache::inputtags::status[-1] ne 'CAN_ANSWER' )
        !           596: 		{
        !           597: 		    $result .=
        !           598: 			'$\bigcirc$'
        !           599: 			. $Apache::response::foilgroup{ $name . '.text' }
        !           600: 		    . '\\\\';    #' stupid emacs
        !           601: 		}
        !           602: 		
        !           603: 		$i++;	    
        !           604: 		$temp++;
        !           605: 		
        !           606: 		$result .= '\vskip 0 mm ';
        !           607: 	    }
        !           608: 	    $result .= "\\end{$venv}";
        !           609: 	}
        !           610: 	
        !           611: 	
        !           612:     }
        !           613:     
        !           614:     return $result;
        !           615: 
        !           616:     
        !           617: }
        !           618: ##
        !           619: #  Figure out the LaTeX environment in which to wrap the LaTeX vertical output.
        !           620: #
        !           621: # @return string
        !           622: # @retval the environment name.  The LaTeX should be wrapped a 
        !           623: #    \begin{retval} \end{retval} pair.
        !           624: #
        !           625: sub latex_vertical_environment {
        !           626:     if ($env{'form.pdfFormFields'} eq 'yes'
        !           627: 	&& $Apache::inputtags::status[-1] eq 'CAN_ANSWER') {
        !           628: 	return 'itemize';
        !           629:     } else {
        !           630: 	return 'enumerate';
        !           631:     }
        !           632: }
        !           633: 
        !           634: 
1.153.6.8  foxr      635: 
                    636: ##
                    637: #
                    638: #  Displays all the foils of a problem in a format suitable for
                    639: #   surveys, surveys for credit, anonymous surveys and anonymous surveys for credit.
                    640: #
                    641: #  @param $direction - Display direction of the choices ('horiztonal' or not).
                    642: #  @param $target    - Rendering target.
                    643: #
                    644: #  @return string
                    645: #  @retval Text that renders for the selected target.
                    646: # 
                    647: sub displayallfoils{
                    648:     my ( $direction, $target ) = @_;
                    649:     my $result;
                    650:     &Apache::lonxml::debug("survey style display");
1.153.6.9! foxr      651: 
1.153.6.8  foxr      652:     my @names;
1.153.6.9! foxr      653: 
1.153.6.8  foxr      654:     if ( $Apache::response::foilgroup{'names'} ) {
                    655:         @names = @{ $Apache::response::foilgroup{'names'} };
                    656:     }
                    657: 
                    658: 
                    659:     my $id   = $Apache::inputtags::response['-1'];
                    660:     my $part = $Apache::inputtags::part;
1.153.6.9! foxr      661:     
        !           662:     my $showanswer = &Apache::response::show_answer();
1.153.6.8  foxr      663:     my $lastresponse = &get_last_survey_response($part, $showanswer, $id);
                    664:     my $used_names = &remove_unused(\@names);
                    665: 
                    666: 
                    667:     if ($target ne 'tex') {
1.153.6.9! foxr      668: 	$result .= &display_survey_html(
        !           669: 	    $used_names, $part, $showanswer, $lastresponse, $direction
        !           670: 	);
        !           671:     } else {	
        !           672: 
        !           673: 	my $vertical_env = &latex_vertical_environment();
        !           674: 	$result .= &latex_survey(
        !           675: 	    $used_names, $showanswer, $lastresponse, $direction, $vertical_env
        !           676: 	);
1.153.6.8  foxr      677: 
1.45      albertel  678:     }
1.153.6.5  foxr      679: 
1.153.6.8  foxr      680: 
1.153.6.5  foxr      681: 
1.83      albertel  682:     return $result;
1.15      albertel  683: }
                    684: 
1.153.6.6  foxr      685: 
                    686: 
1.28      albertel  687: sub whichfoils {
1.153     foxr      688:     my ( $max, $randomize ) = @_;
1.28      albertel  689: 
1.83      albertel  690:     my @truelist;
                    691:     my @falselist;
1.153     foxr      692:     my @whichfalse = ();
                    693:     my ( $truecnt, $falsecnt ) = &getfoilcounts();
                    694:     my $count = 0;
                    695: 
1.83      albertel  696:     # we will add in 1 of the true statements
1.153     foxr      697:     if ( $max > 0 && ( $falsecnt + 1 ) > $max ) { $count = $max }
                    698:     else { $count = $falsecnt + 1; $max = $count; }
                    699:     my $answer = int( &Math::Random::random_uniform() * ($count) );
1.83      albertel  700:     &Apache::lonxml::debug("Count is $count, $answer is $answer");
                    701:     my @names;
                    702:     if ( $Apache::response::foilgroup{'names'} ) {
1.153     foxr      703:         @names = @{ $Apache::response::foilgroup{'names'} };
                    704:     }
                    705:     if ( &Apache::response::showallfoils() ) {
                    706:         @whichfalse = @names;
                    707:     }
                    708:     elsif ( $randomize eq 'no' ) {
                    709:         &Apache::lonxml::debug("No randomization");
                    710:         my $havetrue = 0;
                    711:         foreach my $name (@names) {
                    712:             if ( $Apache::response::foilgroup{ $name . '.value' } eq 'true' ) {
                    713:                 if ( !$havetrue ) {
                    714:                     push( @whichfalse, $name );
                    715:                     $havetrue++;
                    716:                     $answer = $#whichfalse;
                    717:                 }
                    718:             }
                    719:             elsif (
                    720:                 $Apache::response::foilgroup{ $name . '.value' } eq 'false' )
                    721:             {
                    722:                 push( @whichfalse, $name );
                    723:             }
                    724:             elsif (
                    725:                 $Apache::response::foilgroup{ $name . '.value' } eq 'unused' )
                    726:             {
                    727:             }
                    728:             else {
                    729:                 &Apache::lonxml::error(
                    730:                     &HTML::Entities::encode(
                    731: "No valid value assigned ($Apache::response::foilgroup{$name.'.value'}) for foil $name in <foilgroup>",
                    732:                         '<>&"'
                    733:                     )
                    734:                 );
                    735:             }
                    736:         }
                    737:         if (   ( !$havetrue )
                    738:             && ( $Apache::lonhomework::type ne 'survey' )
                    739:             && ( $Apache::lonhomework::type ne 'surveycred' )
                    740:             && ( $Apache::lonhomework::type ne 'anonsurvey' )
                    741:             && ( $Apache::lonhomework::type ne 'anonsurveycred' ) )
                    742:         {
                    743:             &Apache::lonxml::error(
                    744:                 &mt('There are no true statements available.') . '<br />' );
                    745:         }
1.83      albertel  746:     }
1.153     foxr      747:     else {
                    748:         my $current = 0;
                    749:         &Apache::lonhomework::showhash(%Apache::response::foilgroup);
                    750:         my ( %top, %bottom );
                    751: 
                    752:         #first find out where everyone wants to be
                    753:         foreach my $name (@names) {
                    754:             $current++;
                    755:             if ( $Apache::response::foilgroup{ $name . '.value' } eq 'true' ) {
                    756:                 push( @truelist, $name );
                    757:                 if ( $Apache::response::foilgroup{ $name . '.location' } eq
                    758:                     'top' )
                    759:                 {
                    760:                     $top{$name} = $current;
                    761:                 }
                    762:                 elsif ( $Apache::response::foilgroup{ $name . '.location' } eq
                    763:                     'bottom' )
                    764:                 {
                    765:                     $bottom{$name} = $current;
                    766:                 }
                    767:             }
                    768:             elsif (
                    769:                 $Apache::response::foilgroup{ $name . '.value' } eq 'false' )
                    770:             {
                    771:                 push( @falselist, $name );
                    772:                 if ( $Apache::response::foilgroup{ $name . '.location' } eq
                    773:                     'top' )
                    774:                 {
                    775:                     $top{$name} = $current;
                    776:                 }
                    777:                 elsif ( $Apache::response::foilgroup{ $name . '.location' } eq
                    778:                     'bottom' )
                    779:                 {
                    780:                     $bottom{$name} = $current;
                    781:                 }
                    782:             }
                    783:             elsif (
                    784:                 $Apache::response::foilgroup{ $name . '.value' } eq 'unused' )
                    785:             {
                    786:             }
                    787:             else {
                    788:                 &Apache::lonxml::error(
                    789:                     &HTML::Entities::encode(
                    790: "No valid value assigned ($Apache::response::foilgroup{$name.'.value'}) for foil $name in <foilgroup>",
                    791:                         '<>&"'
                    792:                     )
                    793:                 );
                    794:             }
                    795:         }
                    796: 
                    797:         #pick a true statement
                    798:         my $notrue = 0;
                    799:         if ( scalar(@truelist) == 0 ) { $notrue = 1; }
                    800:         my $whichtrue =
                    801:           int( &Math::Random::random_uniform() * ( $#truelist + 1 ) );
                    802:         &Apache::lonxml::debug(
                    803:             "Max is $max, From $#truelist elms, picking $whichtrue");
                    804:         my ( @toplist, @bottomlist );
                    805:         my $topcount    = 0;
                    806:         my $bottomcount = 0;
                    807: 
                    808:         # assign everyone to either toplist/bottomlist or whichfalse
                    809:         # which false is randomized, toplist bottomlist are in order
                    810:         while (( ( $#whichfalse + $topcount + $bottomcount ) < $max - 2 )
                    811:             && ( $#falselist > -1 ) )
                    812:         {
                    813:             &Apache::lonxml::debug("Have $#whichfalse max is $max");
                    814:             my $afalse =
                    815:               int( &Math::Random::random_uniform() * ( $#falselist + 1 ) );
                    816:             &Apache::lonxml::debug("From $#falselist elms, picking $afalse");
                    817:             $afalse = splice( @falselist, $afalse, 1 );
                    818:             &Apache::lonxml::debug("Picked $afalse");
                    819:             &Apache::lonhomework::showhash( ( 'names' => \@names ) );
                    820:             &Apache::lonhomework::showhash(%top);
                    821:             if ( $top{$afalse} ) {
                    822:                 $toplist[ $top{$afalse} ] = $afalse;
                    823:                 $topcount++;
                    824:             }
                    825:             elsif ( $bottom{$afalse} ) {
                    826:                 $bottomlist[ $bottom{$afalse} ] = $afalse;
                    827:                 $bottomcount++;
                    828:             }
                    829:             else {
                    830:                 push( @whichfalse, $afalse );
                    831:             }
                    832:         }
                    833:         &Apache::lonxml::debug("Answer wants $answer");
                    834:         my $truename = $truelist[$whichtrue];
                    835:         my $dosplice = 1;
                    836:         if (   ($notrue)
                    837:             && ( $Apache::lonhomework::type ne 'survey' )
                    838:             && ( $Apache::lonhomework::type ne 'surveycred' )
                    839:             && ( $Apache::lonhomework::type ne 'anonsurvey' )
                    840:             && ( $Apache::lonhomework::type ne 'anonsurveycred' ) )
                    841:         {
                    842:             $dosplice = 0;
                    843:             &Apache::lonxml::error(
                    844:                 &mt('There are no true statements available.') . '<br />' );
                    845:         }
                    846: 
                    847:         #insert the true statement, keeping track of where it wants to be
                    848:         if (   $Apache::response::foilgroup{ $truename . '.location' } eq 'top'
                    849:             && $dosplice )
                    850:         {
                    851:             $toplist[ $top{$truename} ] = $truename;
                    852:             $answer = -1;
                    853:             foreach my $top ( reverse(@toplist) ) {
                    854:                 if ($top) { $answer++; }
                    855:                 if ( $top eq $truename ) { last; }
                    856:             }
                    857:             $dosplice = 0;
                    858:         }
                    859:         elsif (
                    860:             $Apache::response::foilgroup{ $truename . '.location' } eq 'bottom'
                    861:             && $dosplice )
                    862:         {
                    863:             $bottomlist[ $bottom{$truename} ] = $truename;
                    864:             $answer = -1;
                    865:             foreach my $bot (@bottomlist) {
                    866:                 if ($bot) { $answer++; }
                    867:                 if ( $bot eq $truename ) { last; }
                    868:             }
                    869:             $answer += $topcount + $#whichfalse + 1;
                    870:             $dosplice = 0;
                    871:         }
                    872:         else {
                    873:             if ( $topcount > 0 || $bottomcount > 0 ) {
1.150     raeburn   874:                 my $inc = 1;
1.153     foxr      875:                 if (   ( $bottomcount > 0 )
                    876:                     && ( $Apache::lonhomework::type ne 'exam' ) )
                    877:                 {
1.150     raeburn   878:                     $inc = 2;
                    879:                 }
1.153     foxr      880:                 $answer = int(
                    881:                     &Math::Random::random_uniform() * ( $#whichfalse + $inc ) )
                    882:                   + $topcount;
                    883:             }
                    884:         }
                    885:         &Apache::lonxml::debug("Answer now wants $answer");
                    886: 
                    887:         #add the top items to the top, bottom items to the bottom
                    888:         for ( my $i = 0 ; $i <= $#toplist ; $i++ ) {
                    889:             if ( $toplist[$i] ) { unshift( @whichfalse, $toplist[$i] ) }
                    890:         }
                    891:         for ( my $i = 0 ; $i <= $#bottomlist ; $i++ ) {
                    892:             if ( $bottomlist[$i] ) { push( @whichfalse, $bottomlist[$i] ) }
                    893:         }
                    894: 
                    895:         #if the true statement is randomized insert it into the list
                    896:         if ($dosplice) {
                    897:             splice( @whichfalse, $answer, 0, $truelist[$whichtrue] );
                    898:         }
1.49      albertel  899:     }
1.83      albertel  900:     &Apache::lonxml::debug("Answer is $answer");
1.153     foxr      901:     return ( $answer, @whichfalse );
1.28      albertel  902: }
1.153.6.6  foxr      903: 
                    904: ## 
                    905: #  Return a list  of foil texts given foil names.
                    906: #  
                    907: # @param $whichfoils - Reference to a list of foil names.
                    908: #
                    909: # @return array
                    910: # @retval foil texts
                    911: #
                    912: sub get_foil_texts {
                    913:     my ($whichfoils) = @_;
                    914:     my @foil_texts;
                    915: 
                    916:     foreach my $name (@{$whichfoils}) {
                    917: 	push(@foil_texts, $Apache::response::foilgroup{$name . '.text'});
                    918:     }
                    919:     return @foil_texts;
                    920: }
                    921: 
1.153.6.1  foxr      922: ##
1.153.6.2  foxr      923: # Generate the HTML for a single html foil.
                    924: # @param $part           - The part for which the response is being generated.
                    925: # @param $fieldname      - The basename of the radiobutton field
                    926: # @param $name           - The foilname.
                    927: # @param $last_responses - Reference to a hash that holds the most recent
                    928: #                          responses.
                    929: # @param $value          - radiobutton value.
                    930: # 
                    931: # @return text
                    932: # @retval The generated html.
                    933: #
                    934: sub html_radiobutton {
                    935:     my ($part, $fieldname, $name, $last_responses, $value) = @_;
                    936: 
                    937:     my $result='<label>';
                    938:     
                    939:     $result .= '<input type="radio"
                    940:                 onchange="javascript:setSubmittedPart(' . "'$part');\""
                    941: 		. 'name="HWVAL_' . $fieldname . '"'
                    942: 		. "value='$value'";
                    943: 
                    944:     if (defined($last_responses->{$name})) {
                    945: 	$result .= '  checked="checked" ';
                    946:     }
                    947:     $result .= ' />';
                    948:     $result .= $Apache::response::foilgroup{$name . '.text'};
                    949:     $result .= '</label>';
                    950: 
                    951:     return $result;
                    952: 
                    953: }
1.153.6.3  foxr      954: ##
                    955: # Return a reference to the last response hash. This hash has exactly
                    956: # one or zero entries.  The one entry is keyed by the foil 'name' of
                    957: # the prior response
                    958: #
                    959: # @param $part - Number of the problem part.
                    960: # 
                    961: # @return reference to a hash.
                    962: # @retval see above.
                    963: #
                    964: sub get_last_response {
                    965:     my ($part) = @_;
                    966: 
                    967:     my $id = $Apache::inputtags::response['-1'];
                    968:     my ( $lastresponse, $newvariation );
                    969:     
                    970:     if ((( $Apache::lonhomework::history{"resource.$part.type"} eq  'randomizetry')
                    971: 	 || ( $Apache::lonhomework::type eq 'randomizetry' )
                    972: 	)
                    973: 	&& ( $Apache::inputtags::status[-1] eq 'CAN_ANSWER' )
                    974: 	)
                    975:     {
                    976: 	
                    977: 	if ( $env{ 'form.' . $part . '.rndseed' } ne
                    978: 	     $Apache::lonhomework::history{"resource.$part.rndseed"} )
                    979: 	{
                    980: 	    $newvariation = 1;
                    981: 	}
                    982:     }
                    983:     unless ($newvariation) {
                    984: 	$lastresponse =
                    985: 	    $Apache::lonhomework::history{"resource.$part.$id.submission"};
                    986:     }
                    987:     my %lastresponse = &Apache::lonnet::str2hash($lastresponse);
                    988: 
                    989:     return \%lastresponse;
                    990: }
1.153.6.2  foxr      991: 
                    992: ##
1.153.6.3  foxr      993: # Display foils in html rendition.:
1.153.6.1  foxr      994: #
                    995: # @param $whichfoils - Set of foils to display.
                    996: # @param $target     - Rendition target...there are several html targets.
                    997: # @param $direction  - 'horizontal' if layout is horizontal.
                    998: # @param $part       - Part of the problem that's being displayed.
                    999: # @param $show_answer- True if answers should be shown.
                   1000: #
                   1001: # @return string
                   1002: # @retval generated html.
                   1003: #
                   1004: sub display_foils_html {
1.153.6.8  foxr     1005:     my ($whichfoils, $target, $direction, $part, $show_answer) = @_;
1.153.6.1  foxr     1006:     my $result;
                   1007: 
                   1008:     # if the answers get shown, we need to label each item as correct or
                   1009:     # incorrect.
                   1010: 
                   1011:     if ($show_answer) {
                   1012: 	my $item_pretext     = '<br />'; # html prior to each item
                   1013: 	my $item_posttext    = '';	 # html after each item.
                   1014: 	my $finalclose       = '';	 # html to close off the whole shebang
                   1015: 
                   1016: 
                   1017: 	# Horizontal layout is a table with each foil in a cell
                   1018: 
                   1019: 	if ($direction eq 'horizontal') {
                   1020: 	    $result        = '<table><tr>';
                   1021: 	    $item_pretext  = '<td>' . $item_pretext;
                   1022: 	    $item_posttext = '</td>';
                   1023: 	    $finalclose    = '</tr></table>';
                   1024: 	} 
                   1025: 
                   1026: 	foreach my $name (@{$whichfoils}) {
                   1027: 
                   1028: 	    # If the item gets further surrounded by tags, this 
                   1029: 	    # holds the closures for those tages.
                   1030: 
                   1031: 	    my $item_closetag = '';
                   1032: 
                   1033: 	    $result .= $item_pretext;
                   1034: 
                   1035: 	    # Label each foil as correct or incorrect:
                   1036: 
                   1037: 	    if ($Apache::response::foilgroup{$name . '.value'} eq 'true') {
                   1038: 		$result .= &mt('Correct:') . '<b>';
                   1039: 		$item_closetag .= '</b>';
                   1040: 		
                   1041: 	    } else {
                   1042: 		$result .= &mt('Incorrect');
                   1043: 	    }
                   1044: 
                   1045: 	    # Web rendition encloses the 
                   1046: 	    # item text in a label tag as well:
                   1047: 
                   1048: 	    if ($target eq 'web') {
                   1049: 		$result .= '<label>';
                   1050: 		$item_closetag = '</label>' . $item_closetag;
                   1051: 	    }
                   1052: 	    $result .= $Apache::response::foilgroup{$name . '.text'};
                   1053: 	    $result .= $item_closetag;
                   1054: 	    $result .= $item_posttext;
                   1055: 	    $result .= "\n";	# make the html a bit more readable.
                   1056: 	}
                   1057: 
                   1058: 	$result .= $finalclose;
                   1059: 
                   1060:     } else {
1.153.6.3  foxr     1061: 	$result .= '<br />';	# end line prior to foilgroup:
                   1062: 
1.153.6.1  foxr     1063: 	#  Not showing the answers, we need to generate the HTML appropriate
                   1064: 	#  to allowing the student to respond.
                   1065: 	
1.153.6.3  foxr     1066: 	my $item_pretext;
                   1067: 	my $item_posttext;
                   1068: 	my $lastresponse = &get_last_response($part);
1.153.6.1  foxr     1069: 
1.153.6.3  foxr     1070: 	if ( $direction eq 'horizontal' ) {
                   1071: 	    $item_pretext  = '<td>';
                   1072: 	    $item_posttext = '</td>';
                   1073: 	}
                   1074: 	else {
                   1075: 	    $item_pretext = '<br/>';
                   1076: 	}
                   1077: 	my $item_no = 0;
                   1078: 	foreach my $name (@{$whichfoils}) {
                   1079: 	    $result .= $item_pretext;
                   1080: 	    $result .= &html_radiobutton(
                   1081: 		$part, $Apache::inputtags::response[-1],
                   1082: 		$name, $lastresponse, $item_no
                   1083: 		);
                   1084: 	    $result .= $item_posttext;
                   1085: 	    $item_no++;
                   1086: 	}
                   1087: 
                   1088: 	if ($direction eq 'horizontal' ) {
                   1089:             $result .= "</tr></table>";
                   1090:         } else {
                   1091: 	     $result .= "<br />"; 
                   1092: 	}	
1.153.6.1  foxr     1093:     }
                   1094: 
                   1095:     return $result;
                   1096: }
1.153.6.4  foxr     1097: ##
                   1098: #  Display foils in exam mode for latex
                   1099: #
1.153.6.5  foxr     1100: # @param $whichfoils       - Reference to an array that contains the foil names to display
1.153.6.4  foxr     1101: # @param $bubbles_per_line - Number of bubbles on a line.
1.153.6.5  foxr     1102: # @param $direction        - Rendering direction 'horizontal' is what we're looking for.
1.153.6.9! foxr     1103: # @param $venv             - Name of LaTeX environment to use for vertical rendering.
1.153.6.4  foxr     1104: #
                   1105: # @return string
                   1106: # @return the latex rendering of the exam problem.
                   1107: #
                   1108: #
                   1109: sub display_latex_exam {
1.153.6.9! foxr     1110:     my ($whichfoils, $bubbles_per_line, $direction, $venv) = @_;
1.153.6.4  foxr     1111:     my $result;
                   1112:     my $numlines;
                   1113:     my $bubble_number = 0;
                   1114:     my $line          = 0;
                   1115:     my $i             = 0;
                   1116: 
1.153.6.5  foxr     1117: 
                   1118:     if ($direction eq  'horizontal') {
                   1119: 
                   1120: 	# Marshall the display text for each foil and turn things over to
                   1121: 	# Apache::response::make_horizontal_bubbles:
                   1122: 
1.153.6.6  foxr     1123: 	my @foil_texts = &get_foil_texts($whichfoils);
1.153.6.5  foxr     1124: 	$result .= &Apache::caparesponse::make_horizontal_latex_bubbles(
                   1125: 	    $whichfoils, \@foil_texts, '$\bigcirc$');
1.153.6.4  foxr     1126: 
                   1127: 
1.153.6.5  foxr     1128:     } else {
1.153.6.9! foxr     1129: 	$result .= "\\begin{$venv}";
1.153.6.5  foxr     1130: 	
                   1131: 	# This section puts out the prefix that tells the user
                   1132: 	# (if necessary) to only choose one bubble in the next n lines
                   1133: 	# for problems with more than one line worth of bubbles in the grid sheet:
                   1134: 	
                   1135: 	my $numitems = scalar( @{$whichfoils} );
                   1136: 	$numlines = int( $numitems / $bubbles_per_line );
                   1137: 	if ( ( $numitems % $bubbles_per_line ) != 0 ) {
                   1138: 	    $numlines++;
                   1139: 	}
                   1140: 	if ( $numlines < 1 ) {
                   1141: 	    $numlines = 1;
1.153.6.4  foxr     1142: 	}
                   1143: 	if ( $numlines > 1 ) {
1.153.6.5  foxr     1144: 	    my $linetext;
                   1145: 	    for ( my $i = 0 ; $i < $numlines ; $i++ ) {
                   1146: 		$linetext .= $Apache::lonxml::counter + $i . ', ';
                   1147: 	    }
                   1148: 	    $linetext =~ s/,\s$//;
                   1149: 	    $result .=
                   1150: 		'\item[\small {\textbf{'
                   1151: 		. $linetext . '}}]'
                   1152: 		. ' {\footnotesize '
                   1153: 		. &mt( '(Bubble once in [_1] lines)', $numlines )
                   1154: 		. '} \hspace*{\fill} \\\\';
1.153.6.4  foxr     1155: 	}
1.153.6.5  foxr     1156: 	else {
                   1157: 	    $result .= '\item[\textbf{' . $Apache::lonxml::counter . '}.]';
                   1158: 	}
                   1159: 	
                   1160: 	# Now output the bubbles themselves:
                   1161: 	
                   1162: 	foreach my $name (@{$whichfoils}) {
                   1163: 	    if ( $bubble_number >= $bubbles_per_line ) {
                   1164: 		$line++;
                   1165: 		$i             = 0;
                   1166: 		$bubble_number = 0;
                   1167: 	    }
                   1168: 	    my $identifier;
                   1169: 	    if ( $numlines > 1 ) {
                   1170: 		$identifier = $Apache::lonxml::counter + $line;
                   1171: 	    }
                   1172: 	    $result .=
                   1173: 		'{\small \textbf{'
                   1174: 		. $identifier
                   1175: 		. $alphabet[$i]
                   1176: 		. '}}$\bigcirc$'
                   1177: 		. $Apache::response::foilgroup{ $name . '.text' }
                   1178: 	    . '\\\\';    #' stupid emacs -- it thinks it needs that apostrophe to close the quote
                   1179: 	    
                   1180: 	    $i++;
                   1181: 	    $bubble_number++;
                   1182: 	}
1.153.6.9! foxr     1183: 	$result .= "\\end{$venv}";
1.153.6.4  foxr     1184: 
1.153.6.5  foxr     1185:     }	
1.153.6.4  foxr     1186: 
1.153.6.5  foxr     1187:     return $result;
                   1188:     
1.153.6.4  foxr     1189: }
                   1190: 
                   1191: ##
                   1192: #  Display latex when exam mode is not on.
                   1193: #
                   1194: #  @param $whichfoils - The foils to display
                   1195: #  @param $direction  - Display direction ('horizontal' is what matters to us).
1.153.6.9! foxr     1196: #  @param $venv       - Vertical env. to use for vertical rendering.
1.153.6.4  foxr     1197: #  @param  $vend      - End the vertical environment being used.
                   1198: #
                   1199: #  @return string
                   1200: #  @retval - The LaTeX rendering of the resource.'
                   1201: #
                   1202: sub display_latex {
1.153.6.9! foxr     1203:     my ($whichfoils, $direction, $venv) = @_;
1.153.6.4  foxr     1204:     my $result;
                   1205: 
1.153.6.6  foxr     1206:     # how we render depends on the direction.
                   1207:     # Vertical is some kind of list environment determined by vbegin/vend.
                   1208:     # Horizontal is a table that is generated by 
                   1209:     # Apache::caparesponse::make_horizontal_latex_bubbles with an empty string
                   1210:     # for the actual bubble text.
1.153.6.4  foxr     1211: 
1.153.6.6  foxr     1212:     if ($direction eq 'horizontal') {
                   1213: 	my @foil_texts = &get_foil_texts($whichfoils);
                   1214: 	$result .= &Apache::caparesponse::make_horizontal_latex_bubbles(
                   1215: 	    $whichfoils, \@foil_texts, '');
                   1216:     } else {
1.153.6.9! foxr     1217: 	$result .= "\\begin{$venv}";
1.153.6.6  foxr     1218: 	foreach my $name (@{$whichfoils}) {
                   1219: 	    $result .=  '\vspace*{-2 mm}\item '
                   1220: 		. $Apache::response::foilgroup{ $name . '.text' };
                   1221: 	}
1.153.6.4  foxr     1222: 	
1.153.6.9! foxr     1223: 	$result .= "\\end{$venv}";
1.153.6.6  foxr     1224:     }
1.153.6.4  foxr     1225:     return $result;
                   1226: }
1.153.6.1  foxr     1227: 
                   1228: 
                   1229: ##
1.153.6.5  foxr     1230: #  Render foils for a PDF form. This is a variant of tex rednering that provides
                   1231: #  sufficient markup that the final PDF is a form that can be filled in online,
                   1232: #  or offline.
                   1233: #
                   1234: # @param $whichfoils - References an array of foils to display in the order in which
                   1235: #                     they should be displayed.
                   1236: # @param $direction  - Rendering direction.  'horiztonal' means inputs are laid out
                   1237: #                      horizontally otherwise they are stacked vertically.
1.153.6.9! foxr     1238: # @param $venv       - Vertical environment in which to wrap the foils.
1.153.6.5  foxr     1239: #
                   1240: # @return string
                   1241: # @retval String containing the rendering of the resource.
                   1242: #
1.153.6.9! foxr     1243: # TODO: Take into account direction!!!
        !          1244: #
1.153.6.5  foxr     1245: sub display_pdf_form {
1.153.6.9! foxr     1246:     my ($whichfoils, $direction, $venv) = @_;
1.153.6.5  foxr     1247:     my $temp = 0;
                   1248:     my $result;
                   1249: 
1.153.6.9! foxr     1250:     $result .= "\\begin{$venv}";
1.153.6.5  foxr     1251:     foreach my $name ( @{$whichfoils} ) {
                   1252: 	
                   1253: 	my $fieldname =
                   1254: 	    $env{'request.symb'} 
                   1255: 	. '&part_'
                   1256: 	    . $Apache::inputtags::part
                   1257: 	    . '&radiobuttonresponse'
                   1258: 	    . '&HWVAL_'
                   1259: 	    . $Apache::inputtags::response['-1'];
                   1260: 	$result .= '\item[{'
                   1261: 	    . &Apache::lonxml::print_pdf_radiobutton( $fieldname,
                   1262: 						      $temp )
                   1263: 	    . '}]'
                   1264: 	    . $Apache::response::foilgroup{ $name . '.text' }
                   1265: 	. "\n";
                   1266: 	
                   1267: 	$temp++;
                   1268:     }
1.153.6.9! foxr     1269:     $result .= "\\end{$venv}";
1.153.6.5  foxr     1270: 
                   1271:     return $result;
                   1272: }
                   1273: 
                   1274: 
                   1275: ##
                   1276: # Display selected foils:  This is really just a dispatchter to appropriate renderers
                   1277: #  
                   1278: # @param $target   - Target (e.g. 'tex'...).
                   1279: # @param $answer   - True if answers should be shown.
                   1280: # @param $whichfoils - Array of foil selectors that indicate which foils shouild be
                   1281: #                      rendered, in rendering order.
                   1282: # @param $direction- Rendering direction ('horizontal' is the one we look for,
                   1283: #                    otherwise foils are rendered one per line vertically.
                   1284: # @param $bubbles_per_line - number of exam bubbles per line.
                   1285: #
                   1286: # @return string
                   1287: # @retval The rendered problem.
1.28      albertel 1288: 
                   1289: sub displayfoils {
1.153     foxr     1290:     my ( $target, $answer, $whichfoils, $direction, $bubbles_per_line ) = @_;
1.83      albertel 1291:     my $result;
1.28      albertel 1292: 
1.153     foxr     1293:     my $part   = $Apache::inputtags::part;
                   1294:     my $solved = $Apache::lonhomework::history{"resource.$part.solved"};
1.153.6.4  foxr     1295: 
                   1296:     # Show answers html.
                   1297: 
1.153     foxr     1298:     if ( ( $target ne 'tex' )
                   1299:         && &Apache::response::show_answer() )
                   1300:     {
1.153.6.1  foxr     1301: 
                   1302: 	$result = &display_foils_html(
1.153.6.8  foxr     1303: 	    $whichfoils, $target, $direction, $part,  1);
1.153.6.4  foxr     1304: 	
                   1305: 	# other html
                   1306:     }  elsif ($target ne 'tex') {
                   1307: 	    $result = &display_foils_html($whichfoils, $target, $direction, $part,
                   1308: 					  0, 0);
                   1309: 
                   1310:        # LaTeX rendering:
                   1311:     } else {
1.153.6.1  foxr     1312: 
1.153.6.9! foxr     1313: 
1.153     foxr     1314:         my $id            = $Apache::inputtags::response['-1'];
                   1315:         my $part          = $Apache::inputtags::part;
1.153.6.4  foxr     1316: 	my $numlines;
                   1317: 	
                   1318: 	# Decide how to bracket the list of foils:
1.153.6.3  foxr     1319: 
1.153.6.9! foxr     1320: 	my $vertical_env = &latex_vertical_environment();
1.153.6.3  foxr     1321: 
1.153.6.4  foxr     1322: 	# Rendering for latex exams.
                   1323: 	
                   1324: 	if ( ( $Apache::lonhomework::type eq 'exam' ) )
                   1325: 	{
1.153.6.5  foxr     1326: 	    $result .= &display_latex_exam(
1.153.6.9! foxr     1327: 		$whichfoils, $bubbles_per_line, $direction, $vertical_env);
1.153.6.5  foxr     1328: 
1.153.6.4  foxr     1329: 	    $result .= '\vskip 0mm ';
1.153.6.3  foxr     1330: 	    
1.153.6.4  foxr     1331: 	} else {	    
                   1332: 
                   1333: 	    # Different rendering for PDF form than for a
                   1334: 	    # 'regular' answer direction is honored in both of those
                   1335: 	    #
                   1336: 
                   1337: 	    if ( ($env{'form.pdfFormFields'} eq 'yes')
                   1338: 		    && ($Apache::inputtags::status[-1] eq 'CAN_ANSWER'))
1.153.6.3  foxr     1339: 	    {
1.153.6.9! foxr     1340: 		$result .= &display_pdf_form($whichfoils, $direction, $vertical_env);
1.153.6.4  foxr     1341: 	    } else {
1.153.6.9! foxr     1342: 		$result .= &display_latex($whichfoils,  $direction, $vertical_env );
1.153.6.2  foxr     1343: 	    }
1.153.6.4  foxr     1344: 	    $result .= '\vskip 0 mm '; 
                   1345:        
1.153.6.2  foxr     1346: 	}
1.153.6.4  foxr     1347: 
                   1348: 
1.83      albertel 1349:     }
                   1350:     return $result;
1.81      albertel 1351: }
                   1352: 
                   1353: sub displayallanswers {
1.106     albertel 1354:     my @names;
                   1355:     if ( $Apache::response::foilgroup{'names'} ) {
1.153     foxr     1356:         @names = @{ $Apache::response::foilgroup{'names'} };
1.106     albertel 1357:     }
1.153     foxr     1358:     my $result = &Apache::response::answer_header('radiobuttonresponse');
1.81      albertel 1359:     foreach my $name (@names) {
1.153     foxr     1360:         $result .=
                   1361:           &Apache::response::answer_part( 'radiobuttonresponse',
                   1362:             $Apache::response::foilgroup{ $name . '.value' } );
1.81      albertel 1363:     }
1.153     foxr     1364:     $result .= &Apache::response::answer_footer('radiobuttonresponse');
1.81      albertel 1365:     return $result;
1.14      albertel 1366: }
                   1367: 
1.28      albertel 1368: sub displayanswers {
1.153     foxr     1369:     my ( $answer, $whichopt, $bubbles_per_line ) = @_;
1.124     albertel 1370:     my $result;
                   1371: 
1.153     foxr     1372:     if ( $Apache::lonhomework::type eq 'exam' ) {
                   1373:         my $line    = int( $answer / $bubbles_per_line );
                   1374:         my $correct = ( 'A' .. 'Z' )[ $answer % $bubbles_per_line ];
                   1375:         $result .=
                   1376:           &Apache::response::answer_header( 'radiobuttonresponse', $line );
                   1377:         $result .=
                   1378:           &Apache::response::answer_part( 'radiobuttonresponse', $correct );
                   1379:     }
                   1380:     else {
                   1381:         $result .= &Apache::response::answer_header('radiobuttonresponse');
                   1382:     }
                   1383:     foreach my $name ( @{$whichopt} ) {
                   1384:         $result .=
                   1385:           &Apache::response::answer_part( 'radiobuttonresponse',
                   1386:             $Apache::response::foilgroup{ $name . '.value' } );
1.105     albertel 1387:     }
1.153     foxr     1388:     $result .= &Apache::response::answer_footer('radiobuttonresponse');
1.83      albertel 1389:     return $result;
1.28      albertel 1390: }
                   1391: 
1.14      albertel 1392: sub start_conceptgroup {
1.153     foxr     1393:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                   1394:       @_;
                   1395:     $Apache::radiobuttonresponse::conceptgroup = 1;
                   1396:     %Apache::response::conceptgroup            = ();
1.83      albertel 1397:     my $result;
1.153     foxr     1398:     if ( $target eq 'edit' ) {
                   1399:         $result .= &Apache::edit::tag_start( $target, $token );
                   1400:         $result .=
                   1401:             &Apache::edit::text_arg( 'Concept:', 'concept', $token, '50' )
                   1402:           . &Apache::edit::end_row()
                   1403:           . &Apache::edit::start_spanning_row();
                   1404:     }
                   1405:     elsif ( $target eq 'modified' ) {
                   1406:         my $constructtag =
                   1407:           &Apache::edit::get_new_args( $token, $parstack, $safeeval,
                   1408:             'concept' );
                   1409:         if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
1.83      albertel 1410:     }
                   1411:     return $result;
1.14      albertel 1412: }
                   1413: 
                   1414: sub end_conceptgroup {
1.153     foxr     1415:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                   1416:       @_;
                   1417:     $Apache::radiobuttonresponse::conceptgroup = 0;
1.83      albertel 1418:     my $result;
1.153     foxr     1419:     if (   $target eq 'web'
                   1420:         || $target eq 'grade'
                   1421:         || $target eq 'answer'
                   1422:         || $target eq 'tex'
                   1423:         || $target eq 'analyze' )
                   1424:     {
                   1425:         &Apache::response::pick_foil_for_concept( $target,
                   1426:             [ 'value', 'text', 'location' ],
                   1427:             \%Apache::hint::radiobutton, $parstack, $safeeval );
                   1428:     }
                   1429:     elsif ( $target eq 'edit' ) {
                   1430:         $result = &Apache::edit::end_table();
1.83      albertel 1431:     }
                   1432:     return $result;
1.26      albertel 1433: }
                   1434: 
                   1435: sub insert_conceptgroup {
1.153     foxr     1436:     my $result =
                   1437:         "\n\t\t<conceptgroup concept=\"\">"
                   1438:       . &insert_foil()
                   1439:       . "\n\t\t</conceptgroup>\n";
1.83      albertel 1440:     return $result;
1.1       albertel 1441: }
                   1442: 
                   1443: sub start_foil {
1.153     foxr     1444:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                   1445:       @_;
                   1446:     my $result = '';
                   1447:     if ( $target eq 'web' || $target eq 'tex' || $target eq 'analyze' ) {
                   1448:         &Apache::lonxml::startredirection;
                   1449:         if ( $target eq 'analyze' ) {
                   1450:             &Apache::response::check_if_computed( $token, $parstack, $safeeval,
                   1451:                 'value' );
                   1452:         }
                   1453:     }
                   1454:     elsif ( $target eq 'edit' ) {
                   1455:         $result = &Apache::edit::tag_start( $target, $token );
                   1456:         $result .= &Apache::edit::text_arg( 'Name:', 'name', $token );
                   1457:         $result .= &Apache::edit::select_or_text_arg(
                   1458:             'Correct Option:', 'value',
                   1459:             [ 'unused', 'true', 'false' ], $token
                   1460:         );
                   1461:         my $randomize =
                   1462:           &Apache::lonxml::get_param( 'randomize', $parstack, $safeeval, '-3' );
                   1463:         if ( $randomize ne 'no' ) {
                   1464:             $result .=
                   1465:               &Apache::edit::select_arg( 'Location:', 'location',
                   1466:                 [ 'random', 'top', 'bottom' ], $token );
                   1467:         }
                   1468:         $result .=
                   1469:           &Apache::edit::end_row() . &Apache::edit::start_spanning_row();
                   1470:     }
                   1471:     elsif ( $target eq 'modified' ) {
                   1472:         my $constructtag =
                   1473:           &Apache::edit::get_new_args( $token, $parstack, $safeeval, 'value',
                   1474:             'name', 'location' );
                   1475:         if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); }
                   1476:     }
1.83      albertel 1477:     return $result;
1.1       albertel 1478: }
                   1479: 
                   1480: sub end_foil {
1.153     foxr     1481:     my ( $target, $token, $tagstack, $parstack, $parser, $safeeval, $style ) =
                   1482:       @_;
                   1483:     my $text = '';
                   1484:     if ( $target eq 'web' || $target eq 'tex' || $target eq 'analyze' ) {
                   1485:         $text = &Apache::lonxml::endredirection;
                   1486:     }
                   1487:     if (   $target eq 'web'
                   1488:         || $target eq 'grade'
                   1489:         || $target eq 'answer'
                   1490:         || $target eq 'tex'
                   1491:         || $target eq 'analyze' )
                   1492:     {
                   1493:         my $value = &Apache::lonxml::get_param( 'value', $parstack, $safeeval );
                   1494:         if ( $value ne 'unused' ) {
                   1495:             my $name =
                   1496:               &Apache::lonxml::get_param( 'name', $parstack, $safeeval );
                   1497:             if ( $name eq "" ) {
                   1498:                 &Apache::lonxml::warning(
                   1499:                     &mt(
                   1500: 'Foils without names exist. This can cause problems to malfunction.'
                   1501:                     )
                   1502:                 );
                   1503:                 $name = $Apache::lonxml::curdepth;
                   1504:             }
                   1505:             if ( defined( $Apache::response::foilnames{$name} ) ) {
                   1506:                 &Apache::lonxml::error(
                   1507:                     &mt(
                   1508: 'Foil name [_1] appears more than once. Foil names need to be unique.',
                   1509:                         '<b><tt>' . $name . '</tt></b>'
                   1510:                     )
                   1511:                 );
                   1512:             }
                   1513:             $Apache::response::foilnames{$name}++;
                   1514:             my $location =
                   1515:               &Apache::lonxml::get_param( 'location', $parstack, $safeeval );
                   1516:             if ( $Apache::radiobuttonresponse::conceptgroup
                   1517:                 && !&Apache::response::showallfoils() )
                   1518:             {
                   1519:                 push @{ $Apache::response::conceptgroup{'names'} }, $name;
                   1520:                 $Apache::response::conceptgroup{"$name.value"}    = $value;
                   1521:                 $Apache::response::conceptgroup{"$name.text"}     = $text;
                   1522:                 $Apache::response::conceptgroup{"$name.location"} = $location;
                   1523:             }
                   1524:             else {
                   1525:                 push @{ $Apache::response::foilgroup{'names'} }, $name;
                   1526:                 $Apache::response::foilgroup{"$name.value"}    = $value;
                   1527:                 $Apache::response::foilgroup{"$name.text"}     = $text;
                   1528:                 $Apache::response::foilgroup{"$name.location"} = $location;
                   1529:             }
                   1530:         }
1.18      albertel 1531:     }
1.83      albertel 1532:     return '';
1.1       albertel 1533: }
                   1534: 
1.27      albertel 1535: sub insert_foil {
1.83      albertel 1536:     return '
1.27      albertel 1537: <foil name="" value="unused">
                   1538: <startouttext />
                   1539: <endouttext />
                   1540: </foil>';
                   1541: }
1.151     raeburn  1542: 
1.1       albertel 1543: 1;
                   1544: __END__
1.139     jms      1545: 
                   1546: 
                   1547: 
                   1548: =head1 NAME
                   1549: 
                   1550: Apache::radiobuttonresponse
                   1551: 
                   1552: =head1 SYNOPSIS
                   1553: 
                   1554: Handles multiple-choice style responses.
                   1555: 
                   1556: This is part of the LearningOnline Network with CAPA project
                   1557: described at http://www.lon-capa.org.
                   1558: 
                   1559: =head1 SUBROUTINES
                   1560: 
                   1561: =over
                   1562: 
                   1563: =item start_radiobuttonresponse()
                   1564: 
                   1565: =item bubble_line_count()
                   1566: 
                   1567: =item end_radiobuttonresponse()
                   1568: 
                   1569: =item start_foilgroup()
                   1570: 
                   1571: =item storesurvey()
                   1572: 
                   1573: =item grade_response()
                   1574: 
                   1575: =item end_foilgroup()
                   1576: 
                   1577: =item getfoilcounts()
                   1578: 
                   1579: =item format_prior_answer()
                   1580: 
                   1581: =item displayallfoils()
                   1582: 
                   1583: =item &whichfoils($max,$randomize)
                   1584: 
                   1585: Randomizes the list of foils.
                   1586: Respects
                   1587:   - each foils desire to be randomized
                   1588:   - the existance of Concept groups of foils (select 1 foil from each)
                   1589:   - and selects a single correct statement from all possilble true statments
                   1590:   - and limits it to a toal of $max foils
                   1591: 
                   1592: WARNING: this routine uses the random number generator, it should only
                   1593: be called once per target, otherwise it can cause randomness changes in
                   1594: homework problems.
                   1595: 
                   1596: Arguments
                   1597:   $max - maximum number of foils to select (including the true one)
                   1598:          (so a max of 5 is: 1 true, 4 false)
                   1599: 
                   1600:   $randomize - whether to randomize the listing of foils, by default
                   1601:                will randomize, only if randomize is 'no' will it not
                   1602: 
                   1603: Returns
                   1604:   $answer - location in the array of the correct answer
                   1605:   @foils  - array of foil names in to display order
                   1606: 
                   1607: =item displayfoils()
                   1608: 
                   1609: =item displayallanswers()
                   1610: 
                   1611: =item displayanswers()
                   1612: 
                   1613: =item start_conceptgroup()
                   1614: 
                   1615: =item end_conceptgroup()
                   1616: 
                   1617: =item insert_conceptgroup()
                   1618: 
                   1619: =item start_foil()
                   1620: 
                   1621: =item end_foil()
                   1622: 
                   1623: =item insert_foil()
                   1624: 
                   1625: =back
                   1626: 
                   1627: =cut
1.1       albertel 1628:  

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