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

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

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