--- loncom/interface/lonprintout.pm 2002/08/09 18:06:46 1.48 +++ loncom/interface/lonprintout.pm 2010/05/11 11:10:19 1.575.2.2 @@ -1,7 +1,8 @@ +# # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.48 2002/08/09 18:06:46 sakharuk Exp $ +# $Id: lonprintout.pm,v 1.575.2.2 2010/05/11 11:10:19 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -22,813 +23,5177 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt -# # http://www.lon-capa.org/ # -# (Internal Server Error Handler -# -# (Login Screen -# 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14, -# 1/14/00,5/29,5/30,6/1,6/29,7/1,11/9 Gerd Kortemeyer) -# -# 3/1/1 Gerd Kortemeyer) -# -# 3/1 Gerd Kortemeyer -# -# 9/17 Alex Sakharuk # package Apache::lonprintout; - use strict; use Apache::Constants qw(:common :http); use Apache::lonxml; use Apache::lonnet; +use Apache::loncommon; use Apache::inputtags; +use Apache::grades; use Apache::edit; use Apache::File(); +use Apache::lonnavmaps; +use Apache::admannotations; +use Apache::lonenc; +use Apache::entities; +use Apache::londefdef; + +use File::Basename; + +use HTTP::Response; + +use LONCAPA::map(); use POSIX qw(strftime); +use Apache::lonlocal; +use Carp; +use LONCAPA; + +my %perm; +my %parmhash; +my $resources_printed; +# Global variables that describe errors in ssi calls detected by ssi_with_retries. +# -sub headerform { - my $r = shift; - $r->print(< - -LON-CAPA output for printing - - -
-$ENV{'form.postdata'}

-

What do you want to print? Make a choice.


-ENDHEADER +my $ssi_error; # True if there was an ssi error. +my $ssi_last_error_resource; # The resource URI that could not be fetched. +my $ssi_last_error + ; # The error text from the server. (e.g. 500 Server timed out). + +# +# Our ssi max retry count. +# + +my $ssi_retry_count = 5; # Some arbitrary value. + +# Font size: + +my $font_size = 'normalsize'; # Default is normalsize... + +# +# Useful filters that will be filled in by printHelper. +# These are put here to support modularizing helpers into +# less of a helper soup than it was originally: +# These can't be filled in here as there's some conditionalization +# involved. +# + +my $isProblem; +my $isProblemOrMap; +my $isNotMap; +my $isMap; +my $symbFilter; + +#---------------------------- Helper helpers. ------------------------- + + +# Returns the text needd for a student chooser. +# that text must still be parsed by the helper xml parser. +# Parameters: +# this_state - State name of the chooser. +# sort_choice - variable to hold the sorting choice. +# variable - Name of variable to hold students. +# next_state - State after chooser. + +sub generate_student_chooser { + my ( $this_state, $sort_choice, $variable, $next_state ) = @_; + my $result = < + Select sorting order of printout + + + Sort by section then student + Sort by students across sections. + + +


+ + + +CHOOSE_STUDENTS + + return $result; } +# Generate the text needed for a resource chooser given the top level of +# the sequence/page +# +# Parameters: +# this_state - State name of the chooser. +# prompt_text - Text to use to prompt user. +# resource_options - Resource tag options e.g. +# "multichoice='1', toponly='1', addstatus='1'" +# that control the selection and appearance of the +# resource selector. +# variable - Name of the variable to hold the choice +# next_state - Name of the next state the helper should transition +# to +# top_url - Top level URL within which to make the selector. +# If empty the top level sequence is shown. +# filter - How to filter the resources. +# value_func - function. +# choice_func - If not empty generates a with this function. +# start_new_option +# - Fragment appended after valuefunc. +# +# +sub generate_resource_chooser { + my ( + $this_state, $prompt_text, $resource_options, + $variable, $next_state, $top_url, + $filter, $choice_func, $value_func, + $start_new_option + ) = @_; + + my $result = < + + $next_state + return $filter; +CHOOSE_RESOURCES + if ( $choice_func ne '' ) { + $result .= "return $choice_func;"; + } + if ( $top_url ne '' ) { + $result .= "$top_url"; + } + $result .= <return $value_func; + $start_new_option + + +CHOOSE_RESOURCES -sub menu_for_output { - my $r = shift; - $r->print(< - - Current document -(you will print what you see on the screen)
-ENDMENUOUT1 - if ((not $ENV{'request.role'}=~m/^au\./) and (not $ENV{'request.role'}=~m/^ca\./)) { - $r->print(< All problems from the primary sequence
- The whole primary sequence (problems plus all html and xml files)
- All problems from the top level sequence
-
-ENDMENUOUT2 + return $result; +} + +# +# Generate the helper XML for a code choice helper dialog: +# +# Paramters: +# $helper - Reference to the helper. +# $state - Name of the state for the chooser. +# $next_state - Name fo the state to follow the chooser. +# $bubble_types - Populates the bubble sheet type dropt down. +# $code_selections - Provides set of code choices that have been used +# $saved_codes - Provides the list of saved codes. +# +# Returns; +# The Xml of the code chooser. +# +sub generate_code_selector { + my ( $helper, $state, $next_state, $bubble_types, $code_selections, + $saved_codes ) + = @_; # Unpack the parameters. + + my $result = < + $next_state +

Fill out one of the forms below

+


+

Generate new CODEd Assignments

+
Number of CODEd assignments to print: + + + if (((\$helper->{'VARS'}{'NUMBER_TO_PRINT_TOTAL'}+0) < 1) && + !\$helper->{'VARS'}{'REUSE_OLD_CODES'} && + !\$helper->{'VARS'}{'SINGLE_CODE'} && + !\$helper->{'VARS'}{'CODE_SELECTED_FROM_LIST'}) { + return "You need to specify the number of assignments to print"; + } + return undef; + + +
+ Names to save the CODEs under for later: + + +
+ Bubble sheet type: + + + $bubble_types + +
+
+

Print a Specific CODE


+
Enter a CODE to print: + + + if(!\$helper->{'VARS'}{'NUMBER_TO_PRINT_TOTAL'} && + !\$helper->{'VARS'}{'REUSE_OLD_CODES'} && + !\$helper->{'VARS'}{'CODE_SELECTED_FROM_LIST'}) { + return &Apache::lonprintout::is_code_valid(\$helper->{'VARS'}{'SINGLE_CODE'}, + \$helper->{'VARS'}{'CODE_OPTION'}); + } else { + return undef; # Other forces control us. + } + + +
+ $code_selections +
+

Reprint a Set of Saved CODEs

+ Select saved CODEs: + + + $saved_codes + +
+ +CHOOSE_ANON1 + + return $result; +} + +# Returns the XML for the states associated with choosing incomplete problems +# for selected students: +# Paramterss: +# helper - reference to the helper. +# map - Map within which to generate the selector. +# base_state - The first/base state of the helper subsegment. +# +# +# +# States we will use: +# $base_state - Selects resources. +# $base_state.WHO - Selects the people to display. +# $base_state.FORMAT - Selects the final print format etc. +# + +sub generate_incomplete_states { + my ($helper, $map, $base_state) = @_; + my $result = ''; + + $result .= &generate_resource_chooser( + $base_state, + 'Select Problem(s) to print.', + "multichoice='1' addstatus='1'", + 'RESOURCES', + $base_state.'WHO', + '', + '$res->is_incomplete()' + ); + $result .= &generate_student_chooser( + $base_state.'WHO', + 'student_sort', + 'STUDENTS', + $base_state.'FORMAT'); + return $result; +} + +#----------------------------------------------------------------------- + +# Fetch the contents of a resource, uninterpreted. +# This is used here to fetch a latex file to be included +# verbatim into the printout< +# NOTE: Ask Guy if there is a lonnet function similar to this? +# +# Parameters: +# URL of the file +# +sub fetch_raw_resource { + my ($url) = @_; + + my $filename = &Apache::lonnet::filelocation( "", $url ); + my $contents = &Apache::lonnet::getfile($filename); + + if ( $contents == -1 ) { + return "File open failed for $filename"; # This will bomb the print. } - my $subdirtoprint = &Apache::lonnet::filelocation("",$ENV{'form.url'}); - $subdirtoprint =~ s/\/[^\/]+$//; - if (&Apache::lonnet::allowed('bre',$subdirtoprint) eq 'F') { - $r->print(< All problems from current subdirectory (where this particular problem is)
-ENDMENUOUT4 - } - $r->print(<

-

And what page format do you prefer?

- - - - - - -
- Landscape
- Portrait
-
  - Number of columns: -
-
- - - - -ENDMENUOUT5 + return $contents; + } +# Fetch the annotations associated with a URL and +# put a centered 'annotations:' title. +# This is all suppressed if the annotations are empty. +# +sub annotate { + my ($symb) = @_; + my $annotation_text = &Apache::loncommon::get_annotation( $symb, 1 ); + my $result = ""; -sub output_data { - my $r = shift; - $r->print(< - -LON-CAPA output for printing - - -
-ENDPART + if ( length($annotation_text) > 0 ) { + $result .= + '\\hspace*{\\fill} \\\\[\\baselineskip] \textbf{Annotations:} \\\\ '; + $result .= "\n"; + $result .= + &Apache::lonxml::latex_special_symbols( $annotation_text, "" ) + ; # Escape latex. + $result .= "\n\n"; + } + return $result; +} - my $choice = $ENV{'form.choice'}; - my $layout = $ENV{'form.layout'}; - my $numberofcolumns = $ENV{'form.numberofcolumns'}; - my $laystyle = 'book'; - my $result = ''; - my $number_of_columns = 1; -# my $number_of_columns = $ENV{'form.numberofcolumns'}; - - if ($choice eq 'Standard LaTeX output for current document') { - #-- single document - problem, page, html, xml - my %moreenv; - $moreenv{'form.grade_target'}='tex'; - if ($ENV{'request.role'}=~m/^au\./ or $ENV{'request.role'}=~m/^ca\./) { - $ENV{'form.url'}=~s/http:\/\/[^\/]+//; - } - $moreenv{'request.filename'}=$ENV{'form.url'}; - &Apache::lonnet::appenv(%moreenv); - my $texversion=&Apache::lonnet::ssi($ENV{'form.url'}); - &Apache::lonnet::delenv('form.grade_target'); - $result .= $texversion; - $result = &additional_cleanup($result); - if ($ENV{'form.url'}=~m/\.page\s*$/) { - ($result,$number_of_columns) = &page_cleanup($result); - } - } elsif ($choice eq 'Standard LaTeX output for the primary sequence' or - $choice eq 'Standard LaTeX output for whole primary sequence') { - #-- minimal sequence to which the current document belongs - #-- where is the primary sequence containing file? - my $symbolic = &Apache::lonnet::symbread($ENV{'form.url'}); - $_ = $symbolic; - m/([^_]+)_/; - my $primary_sequence = '/res/'.$1; - #-- open and analyses the primary sequence - my $sequence_file=&Apache::lonnet::filelocation("",$primary_sequence); - my $sequencefilecontents=&Apache::lonnet::getfile($sequence_file); - my @master_seq = &content_map($sequencefilecontents); - #-- produce an output string - for (my $i=0;$i<=$#master_seq;$i++) { - $_ = $master_seq[$i]; - m/\"(.*)\"/; - $_ = $1; - my $urlp = $1; - if ($choice eq 'Standard LaTeX output for the primary sequence') { - if ($urlp =~ m/\.(problem|exam|quiz|assess|survey|form|library)/) { - my %moreenv; - $moreenv{'form.grade_target'}='tex'; - &Apache::lonnet::appenv(%moreenv); - my $texversion=&Apache::lonnet::ssi($urlp); - &Apache::lonnet::delenv('form.grade_target'); - $result .= $texversion; - } - } else { - my %moreenv; - $moreenv{'form.grade_target'}='tex'; - &Apache::lonnet::appenv(%moreenv); - my $texversion=&Apache::lonnet::ssi($urlp); - &Apache::lonnet::delenv('form.grade_target'); - $result .= $texversion; - } - } - $result = &additional_cleanup($result); - } elsif ($choice eq 'Standard LaTeX output for the top level sequence') { - my @master_seq = (); - my @add_file_seq = (); - # where is the main sequence of the course? - my $main_seq = '/res/'.$ENV{'request.course.uri'}; - my $file=&Apache::lonnet::filelocation("",$main_seq); - my $filecontents=&Apache::lonnet::getfile($file); - my @file_seq = &content_map($filecontents); - for (my $iu=0;$iu<=$#file_seq;$iu++) { - $file_seq[$iu]=~s/^"//; - $file_seq[$iu]=~s/"$//; - $file_seq[$iu]=&Apache::lonnet::filelocation("",$file_seq[$iu]); -#remove $result .= ' SSS '.$file_seq[$iu].' FFF '; - } - my $i=0; - while ($i<=$#file_seq) { - unless ($file_seq[$i]=~m/\.(problem|page)/) { - if ($file_seq[$i]=~m/\.sequence/) { - my $filecontents=&Apache::lonnet::getfile($file_seq[$i]); - my @newfile_seq = &content_map($filecontents); - $result .=' START '.$i.' LOOK '.$filecontents.' FINISH '; -# splice @file_seq,$1,1,@newfile_seq; -# $i=-1; - } else { - splice @file_seq,$1,1; - } - } +# +# Set a global document font size: +# This is done by replacing \begin{document} +# with \begin{document}{\some-font-directive +# and \end{document} with +# }\end{document +# +sub set_font_size { + my ($text) = @_; + # There appear to be cases where the font directive is empty.. in which + # case the first substituion would insert a spurious \ oh happy day. + # as this has been the cause of much mystery and hair pulling _sigh_ + if ( $font_size ne '' ) { - $i++; - } - for (my $iu=0;$iu<=$#file_seq;$iu++) { - $result .= ' SSS '.$file_seq[$iu].' FFF '; - } + $text =~ s/\\begin{document}/\\begin{document}{\\$font_size/; + } + $text =~ s/\\end{document}/}\\end{document}/; + return $text; +} - # do we have any other sequence inside? -# $result.=$#file_seq.' '; -## my $i=1; -## while ($i<=$#file_seq) { -# $result.=' '.$file_seq[$i].' '; -## $file_seq[$i]=~s/^"//; -## $file_seq[$i]=~s/"$//; -## if ($file_seq[$i]=~m/\.sequence\s*$/) { -## $file = &Apache::lonnet::filelocation("",$file_seq[$i]); -# $result.=' location '.$file.' '; -# $result .= 'FFFFFFFFF'.$file.' '; -## $filecontents=&Apache::lonnet::getfile($file); -## @add_file_seq = &content_map($filecontents); - -# -# for (my $iu=0;$iu<=$#add_file_seq;$iu++) { -# $result .= ' SDSD '.$add_file_seq[$iu].' FDFD '; -# } +# include_pdf - PDF files are included into the +# output as follows: +# - The PDF, if necessary, is replicated. +# - The PDF is added to the list of files to convert to postscript (along with the images). +# - The LaTeX is added to include the final converted postscript in the file as an included +# job. The assumption is that the includedpsheader.ps header will be included. +# +# Parameters: +# pdf_uri - URI of the PDF file to include. +# +# Returns: +# The LaTeX to include. # +# Assumptions: +# The uri is actually a PDF file +# The postscript will have the includepsheader.ps included. +# +# +sub include_pdf { + my ($pdf_uri) = @_; + # Where is the file? If not local we'll need to repcopy it:' -## splice(@file_seq,$i,1,@add_file_seq); -## @add_file_seq = (); -## $i = -1; -## } -## $i++; -## last; #do not forget to remove -## } -## @master_seq = @file_seq; - -# -# for (my $iu=0;$iu<=$#file_seq;$iu++) { -# $result .= ' SSS '.$file_seq[$iu].' FFF '; -# } -# - -#-- produce an output string -### for (my $i=0;$i<=$#master_seq;$i++) { -### $_ = $master_seq[$i]; -### m/\"(.*)\"/; -### $_ = $1; -### my $urlp = $1; -### if (/\.(problem|exam|quiz|assess|survey|form|library)/) { -### my %moreenv; -### $moreenv{'form.grade_target'}='tex'; -### &Apache::lonnet::appenv(%moreenv); -### my $texversion=&Apache::lonnet::ssi($urlp); -### &Apache::lonnet::delenv('form.grade_target'); -### $result .= $texversion; -### } -### } -### $result = &additional_cleanup($result); - } elsif ($choice eq 'Subdirectory print') { - my $subdirtoprint = &Apache::lonnet::filelocation("",$ENV{'form.url'}); - $subdirtoprint =~ s/\/[^\/]+$//; - my @list_of_files = (); - if ($ENV{'request.role'}=~m/^au\./ or $ENV{'request.role'}=~m/^ca\./) { - $subdirtoprint =~ s/^[^~]*~(\w+)\//\/home\/$1\/public_html\//; - } else { - $subdirtoprint =~ s/.*(\/res\/)/$1/; - } - my @content_directory = (); - if ($ENV{'request.role'}=~m/^au\./ or $ENV{'request.role'}=~m/^ca\./) { - @content_directory = &Apache::lonnet::dirlist($subdirtoprint,$ENV{'user.domain'}, $ENV{'user.name'},''); - } else { - @content_directory = &Apache::lonnet::dirlist($subdirtoprint); - } - for (my $iy=0;$iy<=$#content_directory;$iy++) { - my @tempo_array = split(/&/,$content_directory[$iy]); - if ($tempo_array[0] =~ m/^[^\.]+\.(problem|exam|quiz|assess|survey|form|library)$/) { - push(@list_of_files,$tempo_array[0]); - } - } - $subdirtoprint =~ s/\/$//; - for (my $i=0;$i<=$#list_of_files;$i++) { - my $urlp = $subdirtoprint.'/'.$list_of_files[$i]; - my %moreenv; - $moreenv{'form.grade_target'}='tex'; - &Apache::lonnet::appenv(%moreenv); - if ($ENV{'request.role'}=~m/^au\./ or $ENV{'request.role'}=~m/^ca\./) { - $urlp =~ s/\/home\/([^\/]*)\/public_html/\/~$1/; - } - my $texversion=&Apache::lonnet::ssi($urlp); - &Apache::lonnet::delenv('form.grade_target'); - $texversion =~ s/(\\begin{document})/$1 {\\tiny\\begin{verbatim}$urlp\\end{verbatim}}/; - $result .= $texversion; - } - $result = &additional_cleanup($result); - - + my $file = &Apache::lonnet::filelocation( '', $pdf_uri ); + if ( !-e $file ) { + &Apache::lonnet::repcopy($file); + $file = &Apache::lonnet::filelocation( '', $pdf_uri ); + } + + # The file isn ow replicated locally.. or it did not exist in the first place + # (unlikely). If it did exist, add the pdf to the set of files/images that + # need tob e converted for this print job: + + $file =~ s|(.*)/res/|/home/httpd/html/res/|; + + open( FILE, +">>/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.dat" + ); + print FILE ("$file\n"); + close(FILE); + + # Construct the special to put out. To do this we need to get the + # resulting filename after conversion. The file will have the same name + # but will be in the user's spool directory with converted images. + + my $dirname = "/home/httpd/prtspool/$env{'user.name'}/"; + my ( $base, $path, $ext ) = &fileparse( $file, '.pdf' ); + +# my $destname = $dirname.'/'.$base.'.eps'; # Not really an eps but easier in printout.pl + $base =~ s/ /\_/g; + + my $output = &print_latex_header(); + $output .= + '\special{ps: _begin_job_ (' . $base . '.pdf.eps' . ')run _end_job_}'; + + return $output; + +} + +# +# ssi_with_retries- Does the server side include of a resource. +# if the ssi call returns an error we'll retry it up to +# the number of times requested by the caller. +# If we still have a proble, no text is appended to the +# output and we set some global variables. +# to indicate to the caller an SSI error occurred. +# All of this is supposed to deal with the issues described +# in LonCAPA BZ 5631 see: +# http://bugs.lon-capa.org/show_bug.cgi?id=5631 +# by informing the user that this happened. +# +# Parameters: +# resource - The resource to include. This is passed directly, without +# interpretation to lonnet::ssi. +# form - The form hash parameters that guide the interpretation of the resource +# +# retries - Number of retries allowed before giving up completely. +# Returns: +# On success, returns the rendered resource identified by the resource parameter. +# Side Effects: +# The following global variables can be set: +# ssi_error - If an unrecoverable error occurred this becomes true. +# It is up to the caller to initialize this to false +# if desired. +# ssi_last_error_resource - If an unrecoverable error occurred, this is the value +# of the resource that could not be rendered by the ssi +# call. +# ssi_last_error - The error string fetched from the ssi response +# in the event of an error. +# +sub ssi_with_retries { + my ( $resource, $retries, %form ) = @_; + + my $target = $form{'grade_target'}; + my $aom = $form{'answer_output_mode'}; + + my ( $content, $response ) = + &Apache::loncommon::ssi_with_retries( $resource, $retries, %form ); + if ( !$response->is_success ) { + $ssi_error = 1; + $ssi_last_error_resource = $resource; + $ssi_last_error = $response->code . " " . $response->message; + $content = '\section*{!!! An error occurred !!!}'; + &Apache::lonnet::logthis( + "Error in SSI resource: $resource Error: $ssi_last_error"); + } + return $content; +} - +sub get_student_view_with_retries { + my ( + $curresline, $retries, $username, $userdomain, + $courseid, $target, $moreenv + ) = @_; + + my ( $content, $response ) = + &Apache::loncommon::get_student_view_with_retries( + $curresline, $retries, $username, $userdomain, + $courseid, $target, $moreenv + ); + if ( !$response->is_success ) { + $ssi_error = 1; + $ssi_last_error_resource = + $curresline . ' for user ' . $username . ':' . $userdomain; + $ssi_last_error = $response->code . " " . $response->message; + $content = '\section*{!!! An error occurred !!!}'; + &Apache::lonnet::logthis( +"Error in SSI (student view) resource: $curresline Error: $ssi_last_error User: $username:$userdomain" + ); } -#-- corrections for the different page formats - if ($layout eq 'CBI' and $numberofcolumns eq '1') { - } elsif ($layout eq 'CBI' and $numberofcolumns eq '2') { - $result =~ s/\\begin{document}/\\setlength{\\oddsidemargin}{-40pt}\\setlength{\\evensidemargin}{-60pt}\\setlength{\\topmargin}{200pt}\\setlength{\\textwidth}{4\.4in}\\setlength{\\textheight}{6\.8in}\\setlength{\\parindent}{20pt}\\setlength{\\marginparwidth}{90pt}\\setlength{\\textfloatsep}{8pt plus 2\.0pt minus 4\.0pt} \\begin{document}/; - $laystyle = 'album'; - } elsif ($layout eq 'CAPA') { - my $courseidinfo = $ENV{'request.role'}; - $_ = $courseidinfo; - m/.*\/(.*)/; - $courseidinfo = $ENV{'course.physnet_'.$1.'.description'}; -# $result =~ s/\\documentclass\[letterpaper\]{article}/\\documentclass\[twocolumn\]{article}/; - $result =~ s/\\documentclass\[letterpaper\]{article}/\\documentclass{article}/; - $result =~ s/\\begin{document}/\\textheight 25\.9cm\\oddsidemargin = -0\.57in\\evensidemargin = -0\.57in\\textwidth= 9cm\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/$number_of_columns-0\.2cm}\\renewcommand{\\ref}{\\keephidden\}\\begin{document}\\voffset=-1\.8cm\\setcounter{page}{1}\\parbox{\\minipagewidth}{\\noindent\\fbox{\\textbf{$ENV{'environment.firstname'} $ENV{'environment.lastname'}}}\\hskip 1\.4in $courseidinfo} \\vskip 5 mm /; - $result =~ s/\\includegraphics{/\\includegraphics\[width=9\.0 cm\]{/g; -# $result =~ s/\\includegraphics{/\\includegraphics\[width=\\textwidth\]{/g; -# $result =~ s/(\\end{document})/\\newline\\noindent\\makebox\[9.0cm\]\[b\]{\\hrulefill}\\newline\\noindent\\tiny Dept\. of Physics and Astronomy, MSU\\makebox\[1.5cm\]\[b\]{\\hfill}LON-CAPA\\copyright MSU GNU\/GPL $1/; - $result =~ s/(\\end{document})/\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill}\\newline\\noindent\\tiny Dept\. of Physics and Astronomy, MSU\\makebox\[1.5cm\]\[b\]{\\hfill}LON-CAPA\\copyright MSU GNU\/GPL $1/; -# $result =~ s/(\\end{longtable}\s*)(\\newline\\noindent\\makebox\[9\.0cm\]\[b\]{\\hrulefill})/$2$1/g; - $result =~ s/(\\end{longtable}\s*)(\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill})/$2$1/g; - $result =~ s/(\\end{longtable}\s*)\\newline/$1/g; - $result =~ s/\$number_of_columns/$number_of_columns/g; - } -#-- LaTeX corrections - my $first_comment = index($result,'',$first_comment); - substr($result,$first_comment,$end_comment-$first_comment+3) = ''; - $first_comment = index($result,'', $first_comment ); + substr( $result, $first_comment, $end_comment - $first_comment + 3 ) = + ''; + $first_comment = index( $result, '