]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWGLF/FORWARD/analysis2/qa/RunQAMT.sh
Fixed the -L option
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / analysis2 / qa / RunQAMT.sh
1 #!/bin/bash
2 #
3 # This script runs the Forward QA for the specified production number
4 #
5 # The scripts downloads and runs the single run QA in parallel 
6 #
7
8 # --- Some aux files -------------------------------------------------
9 style=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/style.css 
10 favicon=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/fmd_favicon.png
11 logo=$ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/fmd_logo.png
12
13 # --- Help output ----------------------------------------------
14 usage()
15 {
16     cat <<EOF
17 Usage: $0 [OPTIONS] -j [JOBID]
18        $0 [OPTIONS] -p PRODUCTION -P PASS 
19
20 Options:
21         -h,--help                  This help 
22         -j,--jobid      NUMBER     The master job id of the production [$jobid]
23         -v,--verbose               Increase verbosity [$verb]
24         -m,--max-files  NUMBER     Max number of files to get [$maxf]
25         -M,--max-jobs   NUMBER     Max number of consequtive jobs [$maxjobs]
26         -t,--top        DIRECTORY  Output directory [$top]
27         -R,--also-results          Also get QAresults.root for each run
28         -Q,--qa-number  NUMBER     Custom QA id [$qanumber]
29         -p,--production IDENTIFIER Production identifier [$prodfull]
30         -P,--pass       IDENTIFIER Pass identifier [$passfull]
31         -l,--log-file              Log file output [$redir]
32         -b,--barrel     MODE       Fetch barrel data  [$barrel]
33         -f,--force                 Force re-run analysis [$force]
34         -V,--variance              Errors=variance (not min/max) [$variance]
35         -L,--local                 Local trending_<X>.root files [$from_local]
36         -d,--directory  DIR        Search custom AliEn directory [$path]
37
38 Note the option -j and the options -p and -P are mutually exclusive,
39 The option -Q is only used if the options -p and -P are given.
40 Production identifiers are of the form LHC11h, LHC11h3, or LHC11h_2. 
41 Pass identifers are of the form pass2, pass1_HLT, or cpass1.  
42 If barrel mode>0, then do not assume ESD directory.  
43 If barrel mode>1, then get trending_barrel.root and QAresults_barrel.root
44 Option -d is for hand-made QA passes. 
45 If optiond -d is not specified then official QA passes are assumed.
46 EOF
47 }
48
49 # --- Check AliEn token ----------------------------------------------
50 check_token()
51 {
52     uid=`id -u`
53     genv_file=/tmp/gclient_env_${uid}
54     
55     if test ! -f ${genv_file} ; then 
56         echo "No such file: ${genv_file}, please do alien-token-init" \
57             >/dev/stderr
58         exit 1
59     fi
60     . ${genv_file}
61     alien-token-info | grep -q "Token is still valid"
62     if test $? -ne 0 ; then 
63         echo "Token not valid, please re-new" > /dev/stderr 
64         exit 1
65     fi
66 }
67
68 # --- Diagnostics output ---------------------------------------------
69 verb=0
70 mess()
71 {
72     if test $1 -gt $verb ; then return ; fi 
73     shift
74     echo $*
75 }
76
77 # --- Handling of exit -----------------------------------------------
78 lock=
79 handle_exit()
80 {
81     if test "x$lock" = "x" ; then return ; fi 
82     if test "x$store" != "x" && test "x${top}" != "x" ; then 
83         chmod -R g+rwX ${top}/${proddir} >> ${redir} 2>&1
84         chmod -R g+rwX ${top}/$store >> ${redir} 2>&1
85     fi
86     rm -rf $lock 
87 }
88 trap handle_exit EXIT
89
90 # --- Handling of errors ---------------------------------------------
91 last=
92 handle_err()
93 {
94     echo "Error: $last" 
95     exit 1
96 }
97 enable_trap()
98 {
99     trap handle_err ERR
100 }
101 disable_trap()
102 {
103     trap - ERR
104 }
105
106 # --- Check the lock -------------------------------------------------
107 check_lock()
108 {
109     local loc=$1 
110     lock=$loc/.lock
111
112     if test -f $lock ; then 
113         echo "Another QA process is already running:" > /dev/stderr 
114         echo "Content of ${lock}:" > /dev/stderr 
115         cat $lock > /dev/stderr 
116         trap - EXIT
117     exit 1
118     local now=`date` 
119     cat <<EOF > $lock
120 Process: $$
121 User:    $USER
122 Start:   $now
123 EOF
124     fi
125 }
126
127 # --- Parse production information -----------------------------------
128 parse_prod()
129 {
130     prodyear=`echo $prodfull | sed 's/LHC\(..\).*/\1/'` 
131     prodletter=`echo $prodfull | sed "s/LHC${prodyear}\(.\).*/\1/"` 
132     prodpost=`echo $prodfull | sed "s/LHC${prodyear}${prodletter}//"` 
133 }
134
135 parse_pass()
136 {
137     passno=`echo $passfull | sed 's/.*pass\([0-9]*\).*/\1/'`  
138     passpost=`echo $passfull | sed -n "s/.*pass${passno}_//p"` 
139     passpre=`echo $passfull | sed -n "s/pass.*//p"` 
140 }
141
142 # --- Extract parts from the found path ------------------------------
143 force=0
144 year=0
145 passfull=
146 passno=0
147 passpost=
148 passpre=
149 prodfull=
150 prodyear=0
151 prodletter=
152 prodpost=
153 remainder=
154 qanumber=0
155 barrel=0
156 get_parts()
157 {
158     mess 1 "Parsing information from job $@" 
159     year=$1 ; shift 
160     prodfull=$1 ; shift 
161     local lrunn=$1 ; shift
162     local ltype=$1 ; shift 
163     passfull=$1 ; shift 
164     remainder=$1 
165
166     mess 10 "year=$year" 
167     mess 10 "prodfull=$prodfull" 
168     mess 10 "lrunn=$lrunn" 
169     mess 10 "ltype=$ltype" 
170     mess 10 "passfull=$passfull" 
171     mess 10 "remainder=$remainder"
172
173     if test "x$passfull" = "x" ; then 
174         remainder=
175         passfull=$ltype 
176     fi
177     case x$passfull in 
178         *pass*) ;; 
179         *) remainder=$passfull 
180             passfull= 
181             ;;
182     esac
183     parse_pass 
184     parse_prod
185
186     case x$remainder in 
187         xQA*) qanumber=`echo $remainder | sed 's/QA//'`  ;; 
188         *) ;; 
189     esac
190
191 }
192 # --- Get the index for information ----------------------------------
193 skip=0
194 jobu="http://alimonitor.cern.ch/prod/jobs.jsp?t="
195 jobid=
196 get_job() 
197
198     mess 1 "Getting the job information" 
199     wget -q ${jobu}${jobid} -O job.html
200     local lskip
201     let lskip=$skip+1
202     p=`grep "/catalogue/index.jsp?path" job.html | head -n $lskip | tail -n 1 | sed -e 's,.*/alice/\(data\|sim\)/\([^<]*\)<.*,\2,' | tr '/' ' '` 
203     rm -f job.html
204     get_parts $p 
205 }
206
207 # --- Append path element --------------------------------------------
208 append_to_path()
209 {
210     local tmp=$1 ; shift 
211     local add=$1
212     if test "x$tmp" != "x" ; then tmp="${tmp}/" ; fi 
213     echo ${tmp}${add}
214 }
215
216 # --- Get a list of files to get -------------------------------------
217 file=trending.root
218 other=QAresults.root
219 files=
220 path=
221 numf=0
222 from_local=0
223 get_filelist()
224 {
225     mess 3 "Getting file list" 
226
227     local datd=data
228     local esdd=ESDs/
229     if test ${barrel} -gt 0 ; then
230         esdd=
231     fi
232     if test ${barrel} -gt 1 ; then      
233         file=trending_barrel.root
234         other=QAresults_barrel.root
235     fi
236     case x$prodpost in 
237         x_*) ;; 
238         x) ;; 
239         *)  mess 3 "Assuming simulation output"
240             datd=sim 
241             esdd= 
242             ;; 
243     esac
244     
245     local paid=
246     if echo "$passno" | grep -q -E '^[0-9]*[.]?[0-9]*$' ; then 
247         if test "x$passfull" != "x" && test $passno -gt 0 ; then 
248             paid=pass${passno}
249         fi
250     else
251         paid=${passfull}
252         passpre=
253         post=
254     fi
255     local post=${passpost}
256     case x$post in 
257         x_*) ;; 
258         x) ;; 
259         *) post="_${post}" ;; 
260     esac
261
262     local search=
263     if test "x$path" = "x" ; then 
264         # Assume official productions 
265         path=/alice/${datd}/${year}/${prodfull}/
266         search="${esdd}${passpre}${paid}${post}"
267     else
268         search="*"
269     fi
270
271     if test $qanumber -gt 0 ; then 
272         qapost=`printf "QA%02d" $qanumber` 
273         search=`append_to_path "$search" $qapost` 
274     fi
275     
276     search=`append_to_path "$search" $file` 
277
278     cat <<EOF
279         Path:                   $path
280         Search:                 $search
281 EOF
282     if test $from_local -lt 1 ; then 
283
284         mess 1 "Getting list of files from AliEn - can take minutes - be patient"
285         mess 2 "alien_find ${path} ${search}"
286         files=`alien_find ${path} ${search} | grep -v "\(files found\|AND THE\)" 2>> ${redir}` 
287     else 
288         files=`ls ${top}/${store}/trending_*.root | sed 's,${top}/${store}/,,g'`
289     fi
290     for i in $files ; do 
291         let numf=$numf+1
292     done 
293     mess 1 -n "Total of $numf files ... "
294     if test $maxf -lt 0 ; then 
295         mess 1 "using all" 
296     else
297         mess 1 "using $maxf first of these"
298     fi
299 }
300
301 # --- Change permissions on files ------------------------------------
302 fix_perm()
303 {
304     # if test ! -f $1 ; then return ; fi 
305     chmod g+rwX $1 >> /dev/null 2>&1 
306     chmod o+rX $1 >> /dev/null 2>&1 
307     # 
308     # chmod g+rwX $1 >> ${redir} 2>&1 
309     # chmod o+rX $1 >> ${redir} 2>&1 
310 }
311
312 # --- Check if a file is OK ------------------------------------------
313 docheck=1
314 check_file()
315 {
316     if test $docheck -lt 1 ; then return 0; fi 
317     root -l -b  <<EOF >> ${redir} 2>&1 
318 .L $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/CheckQAFile.C
319 CheckQAFile("$1");
320 .q
321 EOF
322     local ret=$? 
323     mess 2 "Check of $1 -> $ret"
324     # rm -f ${scr}.C 
325     return $ret
326 }
327
328 # --- Analyse a file -------------------------------------------------
329 analyse_file()
330 {
331     local dir=`dirname $1` 
332     local inp=`basename $1` 
333     local out=`echo $inp | sed 's/trending_/tree_/'` 
334     local ret=0
335     mess 2 -n "Analysing $inp -> $out ... "
336
337     if test -f $dir/$out ; then 
338         if test $force -lt 1 ; then 
339             mess 2 "exits"
340             return 0
341         fi
342         rm -f $dir/$out
343     fi
344
345     (cd $dir 
346         root -l -b  <<EOF 
347 .L RunFileQA.C
348 RunFileQA("$inp", "$out", $prodyear, "$prodletter");
349 .q
350 EOF
351         ret=$? 
352         mess 2 " -> $ret"
353         # rm -f ${scr}.C 
354     ) 2>> $redir
355     return $ret
356 }
357
358 # --- Download a single file -----------------------------------------
359 also_results=0
360 analyse_run()
361 {
362     local source=$1 ; shift 
363     local store=$1 ; shift 
364     local r=$1 ; shift 
365     local o=${store}/`basename $file .root`_${r}.root 
366
367     mess 2 -n "$source -> $o ... "
368     if test -f $o && test $force -lt 2; then 
369         mess 2 "exists" 
370         # sleep 1
371     else
372         rm -f ${o}
373         mess 2 -n "copying ... " 
374         alien_cp alien:${source} file:${o} >> ${redir} 2>&1 
375         fix_perm $o 
376         mess 2 "done"
377     fi
378     if test ! -f $o ; then return 1 ; fi 
379
380     if test $also_results -gt 0 ; then 
381         local s=`dirname ${source}`/${other}
382         local q=${store}/`basename $other .root`_${r}.root
383
384         mess 2 -n "$s -> $q ... "
385         if test -f $q && test $force -lt 2 ; then 
386             mess 2 "exists" 
387         else
388             rm -rf ${q}
389             mess 2 -n "copying ... " 
390             alien_cp alien:${s} file:${q} >> ${redir} 2>&1 
391             fix_perm $q
392             mess 2 "done"
393         fi
394     fi
395
396         
397     check_file ${o} 
398     local ret=$? 
399     case $ret in 
400         0|2) ;; 
401         1|3|4|5|6) return 2 ;; 
402     esac
403
404     analyse_file ${o}
405
406     return 0
407 }
408
409 # --- Submit run analysis to background ------------------------------
410 submit_runs()
411 {
412     local out=$1 ; shift
413     local sta=$1 ; shift 
414     local max=$1 ; shift
415     
416     local joblist=
417     local counter=0
418     mess 5 "Submitting $maxjobs jobs from $sta/$maxf" 
419     for i in $@ ; do 
420         let cur=$sta+$counter
421
422         local r
423         if test $from_local -lt 1 ; then 
424             local b=`echo $i | sed -e "s,${path},,"` 
425             r=`echo $b | sed -e "s,/.*,,"` 
426         else
427             r=`basename $i .root | sed 's/trending_//'` 
428         fi
429
430         printf "%3d/%3d: %s\n" $cur $max $r 
431         runs[$counter]=$r
432
433         let counter=$counter+1
434         
435         analyse_run $i $out $r &
436         j=`jobs %% | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'` 
437         joblist="$joblist $j"
438     done
439     
440     counter=0
441     mess 5 "will wait for jobs $joblist"
442     for i in $joblist ; do 
443         mess 5 "waiting for $i of $joblist"
444         wait %$i
445         mess 5 "Analysing ${runs[$counter]} returned $?" 
446         let counter=$counter+1
447     done
448 }
449     
450 # --- Analyse each run in turn ---------------------------------------
451 maxjobs=`grep "processor" /proc/cpuinfo | wc -l`
452 analyse_runs()
453 {
454     local out=$1 ; shift 
455     local max=$1 ; shift 
456     
457     local queued=0
458     local counter=0
459     local start=0
460     local list=
461     while test $# -gt 0 ; do 
462         if test $counter -ge $max ; then 
463             break;
464         fi
465
466         list="$list $1" 
467         shift 
468         let queued=$queued+1 
469         let counter=$counter+1 
470
471         if test $queued -eq 1 ; then 
472             start=$counter
473         fi
474         
475         if test $queued -ge $maxjobs ; then 
476             mess 1 "Submitting $queued jobs from $start/$max"
477             submit_runs $out $start $max $list 
478             list=
479             queued=0 
480         fi
481     done
482     if test $queued -gt 0 ; then 
483         mess 1 "Submitting $queued jobs from $start/$max"
484         submit_runs $out $start $max $list 
485     fi
486 }
487
488 # --- Copy style -----------------------------------------------------
489 copy_aliroot_file()
490 {
491     local file=$1 
492     if test ! -f $file ; then return ; fi 
493     base=`basename $file`
494     rm -f $base 
495     cp $file $base 
496     fix_perm $base
497 }
498 copy_style()
499 {
500     copy_aliroot_file $style
501 }       
502
503 # --- Run the final trending -----------------------------------------
504 variance=0
505 make_trend()
506 {
507     local dir=$1 
508     local ret=0
509     mess 1 -n "Analysing for trend $dir ... "
510     (cd $dir 
511         rm -f trend_*_*.html 
512         rm -f trend_*_*.pdf
513         rm -f trend_*_*.root
514
515         root -l -b <<EOF 
516 .L RunFinalQA.C
517 RunFinalQA(".", $prodyear, "$prodletter", $variance);
518 .q
519 EOF
520         mess 1 -n " ... "
521         # mess 3 -n "root -l -b -q ${scr}.C "
522         # root -l -b -q ${scr}.C  > /dev/null 2>&1 
523         # local ret=$? 
524         # mess 1 " -> $ret"
525         # rm -f ${scr}.C 
526
527         # do the index file 
528         local idx=`ls trend_*_*.html 2> /dev/null` 
529         for i in $idx ; do 
530             mess 1 "Making index.html point to $i" 
531             sed -e 's,index.html,../index.html,' \
532                 -e "s,!--JOBID--,a target='_blank' href='${jobu}${jobid}'>Job</a," \
533                 < $i > index.html 
534             cp index.html $i
535         done
536         
537         if test ! -f index.html ; then 
538             echo "No index file found" 
539             ret=1
540         else 
541             fix_perm index.html 
542             fix_perm . > /dev/null 2>&1 
543         fi
544
545         copy_style
546         copy_aliroot_file $favicon
547         copy_aliroot_file $logo
548     ) 2>> $redir
549     return $ret
550 }
551
552 # --- Make index file ------------------------------------------------
553 make_index()
554 {
555     local dir=$1   ; shift  
556     local title=$1 ; shift
557     local desc=$1  ; shift 
558     mess 1 "Making index in $dir ($title)"
559     
560     (cd $dir
561         local date=`date` 
562         
563         rm -f index.html 
564
565         cat <<EOF > index.html
566 <!DOCTYPE html>
567 <html>
568   <head>
569     <title>$title</title>
570     <link rel='stylesheet' href='style.css'>
571     <link rel='shortcut icon' href='fmd_favicon.png' type='image/x-png'>
572   </head>
573   <body>
574     <h1><img style='width: 200px;' src='fmd_logo.png'>  &nbsp;$title</h1>
575 EOF
576         if test ! "x$desc" = "x" ; then 
577             echo "<p>$desc</p>" >> index.html
578         fi
579         echo "      <ul>" >> index.html
580         for i in * ; do 
581             if test ! -d $i ; then continue ; fi 
582             echo "      <li><a href='$i'>$i</a></li>" >> index.html
583         done
584         echo "      </ul>" >> index.html 
585         if test "x$desc" = "x" ; then 
586             echo "      <div class='back'><a href='../'>Back</a></div>" \
587                 >> index.html
588         fi
589         cat <<EOF >> index.html    
590     <div class='change'>Last update: $date</div>
591   </body>
592 </html>
593 EOF
594         copy_style 
595         copy_aliroot_file $favicon
596         copy_aliroot_file $logo
597         fix_perm index.html
598         fix_perm . > /dev/null 2>&1 
599     )
600 }
601
602
603 # --- Pass command line options --------------------------------------
604 redir=/dev/null
605 maxf=-1
606 top=.
607 while test $# -gt 0 ; do 
608     case $1 in 
609         -h|--help) usage ; exit 0 ;; 
610         -v|--verbose)      let verb=$verb+1   ;; 
611         -j|--jobid)        jobid=$2           ; shift ;; 
612         -m|--max-files)    maxf=$2            ; shift ;; 
613         -M|--max-jobs)     maxjobs=$2         ; shift ;;
614         -t|--top)          top=$2             ; shift ;;
615         -R|--also-results) also_results=1     ;; 
616         -Q|--qa-number)    qanumber=$2        ; shift ;;
617         -l|--log-file)     redir=             ;; 
618         -L|--local)        from_local=1       ;;
619         -V|--variance)     variance=1         ;;
620         -b|--barrel)       barrel=$2          ; shift ;;
621         -f|--force)        let force=$force+1 ;; 
622         -p|--production) 
623             prodfull=$2; shift; parse_prod ; year=20${prodyear} ;;
624         -P|--pass) 
625             passfull=$2; shift; parse_pass ;;
626         -d|--directory)    path=$2              ; shift ;;
627         *) echo "$0: Unknown argument: $1" > /dev/stderr ; exit 1 ;; 
628     esac
629     shift
630 done
631 # --- Initial setup --------------------------------------------------
632 # First, check we have a valid AliEn token, then retrieve the job 
633 # information to parse out the location of the files we need, and 
634 # finally make our output directory and check the lock 
635 check_token
636
637 if test ! "x$jobid" = x ; then 
638     if test ! "x$prodfull" = "x" || test ! "x$passfull" = "x" ; then 
639         cat <<EOF > /dev/stderr
640 Option -j ${jobid} and options -p and -P are mutually exclusive 
641 EOF
642         exit 1
643     fi
644     get_job
645 else 
646     if test "x$prodfull" = "x" || test "x$passfull" = "x" ; then 
647         cat<<EOF > /dev/stderr
648 When specifying prodcution and/or pass both options -p and -P _must_ 
649 be specified. 
650 EOF
651         exit 1
652     elif test ! "x$jobid"  = "x" ; then 
653         cat <<EOF > /dev/stderr
654 Option -j and options -p ${prodfull} and -P ${passfull} are mutually exclusive 
655 EOF
656         exit 1
657     fi
658 fi      
659
660 proddir=LHC${prodyear}${prodletter}
661 store=${proddir}
662 if test ! "x$passno" = "x" ; then 
663     if test "x${passpre}" = "xv" || test "x${passpre}" = "xc"; then 
664         store=${store}/${passpre}pass${passno}
665     else
666         store=${store}/pass${passno}
667     fi
668 elif test ! "x$prodpost" = "x" ; then 
669     proddir=${proddir}${prodpost}
670     store=${proddir}/sim
671 elif test ! "x$remainder" = "x" ; then 
672     store=${store}/${remainder}
673 fi
674 if test ! "x$qanumber" = "x" && test $qanumber -gt 0 ; then 
675     store=${store}_QA${qanumber}
676 fi
677 mkdir -p ${top}/$store 
678 fix_perm ${top}/${proddir}
679 fix_perm ${top}/$store
680
681 if test "x$redir" = "x" ; then 
682     redir=${top}/$store/qa.log 
683     rm -f $redir
684     fix_perm $redir
685 fi
686
687 check_lock ${top}/$store
688
689 # --- Some friendly information --------------------------------------
690 cat <<EOF
691         Year:                   $year
692         Production:             $prodfull 
693           Year:                 $prodyear
694           Letter:               $prodletter
695           Suffix:               $prodpost
696         Pass:                   $passfull
697           Number:               $passno
698           Prefix:               $passpre
699           Postfix:              $passpost
700         Remainder               $remainder
701           QA number             $qanumber
702         Output directory:       ${store}
703         Lock file:              ${lock}
704         Log:                    ${redir}
705         Force:                  ${force}
706         Use variance:           ${variance}
707         Use pre-downloaded:     ${from_local}
708 EOF
709 # --- Do a search to find our files ----------------------------------
710 get_filelist
711
712 if test $maxf -gt 0 && test $maxf -lt $numf ; then 
713     numf=$maxf 
714 fi
715
716 # --- Copy scripts to target and compile -----------------------------
717 for i in QABase.h QAPlotter.C QARing.h QAStructs.h QATrender.C \
718     RunFileQA.C RunFinalQA.C ; do
719     cp $ALICE_ROOT/PWGLF/FORWARD/analysis2/qa/$i ${store}/${i}
720     rm -f ${store}/`echo $i | tr '.' '_'`.{so,d}
721     fix_perm ${store}/${i}
722 done
723 mess 1 "Compiling QATrender.C"
724 (cd $store && root -l -b <<EOF 
725 gROOT->LoadMacro("QABase.h++g");
726 gROOT->LoadMacro("QATrender.C++g");
727 .q
728 EOF
729 )
730 mess 1 "Compiling QAPlotter.C"
731 (cd $store && root -l -b <<EOF 
732 gROOT->LoadMacro("QABase.h++g");
733 gROOT->LoadMacro("QAPlotter.C++g");
734 .q
735 EOF
736 )
737 (cd ${store} && for i in *.so *.d ; do fix_perm $i ; done)
738
739 # --- Now get and analyse each run -----------------------------------
740 analyse_runs ${top}/$store $numf $files
741
742 # --- Now analyse all runs -------------------------------------------
743 make_trend ${top}/$store
744
745 # --- Make index files -----------------------------------------------
746 make_index ${top}/${proddir} ${proddir}
747 make_index ${top} "QA for the FMD" \
748     "For more information see <a href='https://twiki.cern.ch/twiki/bin/viewauth/ALICE/FMDQA'>TWiki pages</a>."
749
750 chmod -R g+rwX ${top}/${proddir} >> ${redir} 2>&1
751
752 #
753 # EOF
754 #