devi@23: #!/usr/bin/perl -w devi@23: devi@23: use lib '.'; devi@23: use l3config; devi@23: devi@23: our @Command_Lines; devi@23: devi@23: # vvv Инициализация переменных выполняется процедурой init_variables devi@23: our @Day_Name; devi@23: our @Month_Name; devi@23: our @Of_Month_Name; devi@23: our %Search_Machines; devi@23: our %Elements_Visibility; devi@23: # ^^^ devi@23: devi@23: sub search_buy; devi@23: sub make_comment; devi@23: sub load_command_lines_from_xml; devi@23: sub print_command_lines; devi@23: sub init_variables; devi@23: sub main; devi@23: devi@23: main(); devi@23: devi@23: sub main devi@23: { devi@23: $| = 1; devi@23: devi@23: init_variables(); devi@23: init_config(); devi@23: devi@23: load_command_lines_from_xml($Config{"cache"}); devi@23: print_command_lines($Config{"output"}); devi@23: } devi@23: devi@23: devi@23: sub search_by devi@23: { devi@23: my $sm = shift; devi@23: my $topic = shift; devi@23: $topic =~ s/ /+/; devi@23: devi@23: return "<a href='". $Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='". devi@23: $Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; devi@23: } devi@23: devi@23: sub make_comment devi@23: { devi@23: my $commands = $_[0]; devi@23: my $files = $_[1]; devi@23: chomp $commands; devi@23: chomp $files; devi@23: return if (!$commands && !$files); devi@23: devi@23: my $comment=""; devi@23: devi@23: # Commands devi@23: for my $command (split /\s+/,$commands) { devi@23: $command =~ s/'//g; devi@23: my $description=""; devi@23: eval { $description=`mywi-client '$command'`; } ; devi@23: $description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description))); devi@23: $description =~ s/.*?-//; devi@23: next if $description =~ /^\s*$/; devi@23: devi@23: my $query=$command." ".$Config{"keywords"}; devi@23: $query =~ s/\ /+/g; devi@23: my $search= search_by("opennet",$query). devi@23: search_by("local",$command). devi@23: search_by("google",$query); devi@23: devi@23: $comment .= "<tr><td class='note_title'>$command</td>". devi@23: "<td class='note_search'>$search</td>". devi@23: "</tr><tr><td width='100%' colspan='2' class='note_text'>". devi@23: "$description</td></tr><tr/>"; devi@23: } devi@23: devi@23: # Files devi@23: for my $file (split /\s+/,$files) { devi@23: $file =~ s@.*/@@; devi@23: $file =~ s/'//g; devi@23: next if $file =~ /^\s*$/; devi@23: next if $file =~ /^-/; devi@23: devi@23: my $description=`mywi '$file'`; devi@23: $description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description))); devi@23: next if $description =~ /^\s*$/; devi@23: devi@23: my $query=$file." ".$Config{"files_keywords"}; devi@23: $query =~ s/\ /+/g; devi@23: my $search= search_by("opennet",$query). devi@23: search_by("local",$file). devi@23: search_by("google",$query); devi@23: devi@23: $comment .= "<tr><td class='note_title'>$file</td>". devi@23: "<td class='note_search'>$search</td>". devi@23: "</tr><tr><td width='100%' colspan='2' class='note_text'>". devi@23: "$description</td></tr><tr/>"; devi@23: } devi@23: devi@23: devi@23: return $comment; devi@23: } devi@23: devi@23: =cut devi@23: Процедура load_command_lines_from_xml выполняет загрузку разобранного lab-скрипта devi@23: из XML-документа в переменную @Command_Lines devi@23: devi@23: Предупреждение! devi@23: Процедура не в состоянии обрабатывать XML-документ любой структуры. devi@23: В действительности файл cache из которого загружаются данные devi@23: просто напоминает XML с виду. devi@23: =cut devi@23: sub load_command_lines_from_xml devi@23: { devi@23: my $datafile = $_[0]; devi@23: devi@23: open (CLASS, $datafile) devi@23: or die "Can't open file of the class ",$datafile,"\n"; devi@23: local $/; devi@23: $data = <CLASS>; devi@23: close(CLASS); devi@23: devi@23: for $command ($data =~ m@<command>(.*?)</command>@sg) { devi@23: my %cl; devi@23: while ($command =~ m@<([^>]*?)>(.*?)</\1>@sg) { devi@23: $cl{$1} = $2; devi@23: } devi@23: push @Command_Lines, \%cl; devi@23: } devi@23: } devi@23: devi@23: =cut devi@23: Процедура print_command_lines выводит HTML-представление devi@23: разобранного lab-скрипта. devi@23: devi@23: Разобранный lab-скрипт должен находиться в массиве @Command_Lines devi@23: =cut devi@23: devi@23: sub print_command_lines devi@23: { devi@23: my $output_filename=$_[0]; devi@23: devi@23: my $course_name = $Config{"course-name"}; devi@23: my $course_code = $Config{"course-code"}; devi@23: my $course_date = $Config{"course-date"}; devi@23: my $course_center = $Config{"course-center"}; devi@23: my $course_trainer = $Config{"course-trainer"}; devi@23: my $course_student = $Config{"course-student"}; devi@23: devi@23: devi@23: # Результат выполнения процедуры равен devi@23: # join("", @Result{header,body,stat,help,about,footer}) devi@23: my %Result; devi@23: my $toc =""; # Хранит оглавление по дням devi@23: devi@23: $Result{"body"} = "<table width='100%'>\n"; devi@23: devi@23: my $cl; devi@23: my $last_tty=""; devi@23: my $last_day=""; devi@23: my $in_range=0; devi@23: devi@23: for my $cl (@Command_Lines) { devi@23: devi@23: if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { devi@23: $in_range=1; devi@23: next; devi@23: } devi@23: if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { devi@23: $in_range=0; devi@23: next; devi@23: } devi@23: next if ($Config{"from"} && $Config{"to"} && !$in_range) devi@23: || devi@23: ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) devi@23: || devi@23: ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) devi@23: || devi@23: ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); devi@23: devi@23: #my @new_commands=@{$cl->{"new_commands"}}; devi@23: #my @new_files=@{$cl->{"new_files"}}; devi@23: devi@23: my $cl_class="cline"; devi@23: my $out_class="output"; devi@23: if ($cl->{"class"}) { devi@23: $cl_class = $cl->{"class"}."_".$cl_class; devi@23: $out_class = $cl->{"class"}."_".$out_class; devi@23: } devi@23: devi@23: my @new_commands; devi@23: my @new_files; devi@23: @new_commands = split (/\s+/, $cl->{"new_commands"}) if defined $cl->{"new_commands"}; devi@23: @new_files = split (/\s+/, $cl->{"new_files"}) if defined $cl->{"new_files"}; devi@23: devi@23: my $output=""; devi@23: if ($Config{"head_lines"} || $Config{"tail_lines"}) { devi@23: # Partialy output devi@23: my @lines = split '\n', $cl->{"output"}; devi@23: # head devi@23: my $mark=1; devi@23: for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { devi@23: $output .= $lines[$i]."\n"; devi@23: } devi@23: # tail devi@23: my $start=$#lines-$Config{"tail_lines"}+1; devi@23: if ($start < 0) { devi@23: $start=0; devi@23: $mark=0; devi@23: } devi@23: if ($start < $Config{"head_lines"}) { devi@23: $start=$Config{"head_lines"}; devi@23: $mark=0; devi@23: } devi@23: $output .= $Config{"skip_text"}."\n" if $mark; devi@23: for (my $i=$start; $i<= $#lines; $i++) { devi@23: $output .= $lines[$i]."\n"; devi@23: } devi@23: } devi@23: else { devi@23: # Full output devi@23: $output .= $cl->{"output"}; devi@23: } devi@23: #$output .= "^C\n" if ($cl->{"err"} eq "130"); devi@23: devi@23: # devi@23: ## devi@23: ## Начинается собственно вывод devi@23: ## devi@23: # devi@23: devi@23: # <command> devi@23: devi@23: my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); devi@23: # Добавляем спереди 0 для удобочитаемости devi@23: $min = "0".$min if $min =~ /^.$/; devi@23: $hour = "0".$hour if $hour =~ /^.$/; devi@23: $sec = "0".$sec if $sec =~ /^.$/; devi@23: devi@23: $class=$cl->{"out_class"}; devi@23: $class =~ s/output$//; devi@23: devi@23: devi@23: $Result{"body"} .= "<tr class='command'>\n"; devi@23: devi@23: devi@23: # DAY CHANGE devi@23: if ( $last_day ne $day) { devi@23: #$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>"; devi@23: $Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>"; devi@23: $toc .= "<li><a href='#day$day'>".$Day_Name[$wday]."</a></li>\n"; devi@23: $last_day=$day; devi@23: } devi@23: devi@23: # CONSOLE CHANGE devi@23: if ( $last_tty ne $cl->{"tty"}) { devi@23: $Result{"body"} .= "<td colspan='6'><table><tr><td class='ttychange' width='140' align='center'>".$cl->{"tty"}."</td><td/></tr></table></td></tr><tr>"; devi@23: $last_tty=$cl->{"tty"}; devi@23: } devi@23: devi@23: # TIME devi@23: if ($Config{"show_time"} =~ /^y/i) { devi@23: $Result{"body"} .= "<td valign='top' class='time' width='$Config{time_width}'><pre>". devi@23: $hour. ":". $min. ":". $sec. devi@23: "</td>"; devi@23: } else { devi@23: $Result{"body"} .= "<td width='0'/>" devi@23: } devi@23: devi@23: # COMMAND devi@23: $Result{"body"} .= "<td class='script'>\n"; devi@23: $Result{"body"} .= "<pre class='${class}cline'>\n"; devi@23: my $cline = $cl->{"cline"}; devi@23: $cline =~ s/\n//; devi@23: $Result{"body"} .= $cl->{"prompt"}.$cl->{"cline"}; devi@23: $Result{"body"} .= "</pre>\n"; devi@23: devi@23: my $last_command = $cl->{"last_command"}; devi@23: if (!( devi@23: $Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || devi@23: $Config{"suppress_pagers"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || devi@23: $Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) devi@23: )) { devi@23: devi@23: $Result{"body"} .= "<pre class='".$cl->{out_class}."'>"; devi@23: $Result{"body"} .= $output; devi@23: $Result{"body"} .= "</pre>\n"; devi@23: } devi@23: devi@23: # DIFF devi@23: if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { devi@23: $Result{"body"} .= "<table><tr><td width='5'/><td class='diff'><pre>"; devi@23: $Result{"body"} .= $cl->{"diff"}; devi@23: $Result{"body"} .= "</pre></td></tr></table>"; devi@23: } devi@23: devi@23: # COMMENT devi@23: if ( $Config{"show_comments"} =~ /^y/i) { devi@23: my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files)); devi@23: if ($comment) { devi@23: $Result{"body"} .= "<table width='$Config{comment_width}'>". devi@23: "<tr><td width='5'/><td>"; devi@23: $Result{"body"} .= "<table class='note' width='100%'>"; devi@23: $Result{"body"} .= $comment; devi@23: $Result{"body"} .= "</table>\n"; devi@23: $Result{"body"} .= "</td></tr></table>"; devi@23: } devi@23: else { devi@23: $Result{"body"} .= "<table width='$Config{comment_width}'>". devi@23: "<tr><td width='5'/><td>"; devi@23: $Result{"body"} .= "<table class='note' width='100%'>"; devi@23: $Result{"body"} .= "commands ".join(" ",@new_commands)."<br/>"; devi@23: $Result{"body"} .= "files ".join(" ",@new_files)."<br/>"; devi@23: $Result{"body"} .= "</table>\n"; devi@23: $Result{"body"} .= "</td></tr></table>"; devi@23: } devi@23: } devi@23: devi@23: # Вывод очередной команды окончен devi@23: $Result{"body"} .= "</td>\n"; devi@23: $Result{"body"} .= "</tr>\n"; devi@23: } devi@23: devi@23: $Result{"body"} .= "</table>\n"; devi@23: devi@23: $Result{"stat"} = "<hr/>"; devi@23: $Result{"stat"} .= "<h2 id='stat'>Статистика</h2>"; devi@23: $Result{"stat"} .= "Статистическая информация о журнале<br/>"; devi@23: $Result{"help"} .= "<hr/>"; devi@23: $Result{"help"} .= "<h2 id='help'>Справка</h2>"; devi@23: $Result{"help"} .= "$Html_Help<br/>"; devi@23: $Result{"about"} .= "<hr/>"; devi@23: $Result{"about"} .= "<h2 id='about'>О программе</h2>"; devi@23: $Result{"about"} .= "$Html_About"; devi@23: $Result{"footer"} .= "</body>\n"; devi@23: $Result{"footer"} .= "</html>\n"; devi@23: devi@23: # Заголовок генерируется позже всего devi@23: # Тогда, когда известно уже, что должно быть написано в devi@23: # оглавлении devi@23: $Result{"header"} = <<HEADER; devi@23: <html> devi@23: <head> devi@23: <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> devi@23: <link rel='stylesheet' href='labmaker.css' type='text/css'/> devi@23: </head> devi@23: <body> devi@23: <script> devi@23: $Html_JavaScript devi@23: </script> devi@23: <h2>Журнал лабораторных работ</h2> devi@23: devi@23: <p> devi@23: Выполнил $course_student<br/> devi@23: Проверил $course_trainer <br/> devi@23: Курс $course_name ($course_code), devi@23: $course_date<br/> devi@23: Учебный центр $course_center <br/> devi@23: </p> devi@23: devi@23: <ul> devi@23: <li><a href='#log'>Журнал</a></li> devi@23: <ul>$toc</ul> devi@23: <li><a href='#stat'>Статистика</a></li> devi@23: <li><a href='#help'>Справка</a></li> devi@23: <li><a href='#about'>О программе</a></li> devi@23: </ul> devi@23: devi@23: <h2 id="log">Журнал</h2> devi@23: HEADER devi@23: $Result{"header"} .= "<table class='visibility_form'><tr><td><form>\n"; devi@23: for my $element (keys %Elements_Visibility) devi@23: { devi@23: my @e = split /\s+/, $element; devi@23: my $showhide = join "", map { "ShowHide('$_');" } @e ; devi@23: $Result{"header"} .= "<input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>". devi@23: $Elements_Visibility{$element}. devi@23: "</input><br>\n"; devi@23: } devi@23: devi@23: $Result{"header"} .= "</form></td></tr></table>\n"; devi@23: devi@23: open(OUT, ">", $output_filename) devi@23: or die "Can't open $output_filename for writing\n"; devi@23: print OUT $Result{"header"}, $Result{"body"}, $Result{"stat"}, $Result{"help"}, $Result{"about"}, $Result{"footer"}; devi@23: close(OUT); devi@23: } devi@23: devi@23: devi@23: devi@23: devi@23: devi@23: devi@23: sub init_variables devi@23: { devi@23: $Html_Help = <<HELP; devi@23: Справка по использованию журнала devi@23: HELP devi@23: devi@23: $Html_About = <<ABOUT; devi@23: <p> devi@23: LiLaLo (L3) расшифровывается как Live Lab Log.<br/> devi@23: Программа разработана для повышения эффективности обучения<br/> devi@23: Unix/Linux-системам.<br/> devi@23: (c) Игорь Чубин, 2004-2005<br/> devi@23: </p> devi@23: ABOUT devi@23: $Html_About.='$Id$ </p>'; devi@23: devi@23: $Html_JavaScript = <<JS; devi@23: function getElementsByClassName(Class_Name) devi@23: { devi@23: var Result=new Array(); devi@23: var All_Elements=document.all || document.getElementsByTagName('*'); devi@23: for (i=0; i<All_Elements.length; i++) devi@23: if (All_Elements[i].className==Class_Name) devi@23: Result.push(All_Elements[i]); devi@23: return Result; devi@23: } devi@23: function ShowHide (name) devi@23: { devi@23: elements=getElementsByClassName(name); devi@23: for(i=0; i<elements.length; i++) devi@23: if (elements[i].style.display == "none") devi@23: elements[i].style.display = ""; devi@23: else devi@23: elements[i].style.display = "none"; devi@23: //if (elements[i].style.visibility == "hidden") devi@23: // elements[i].style.visibility = "visible"; devi@23: //else devi@23: // elements[i].style.visibility = "hidden"; devi@23: } devi@23: function filter_by_output(text) devi@23: { devi@23: devi@23: var jjj=0; devi@23: devi@23: elements=getElementsByClassName('command'); devi@23: for(i=0; i<elements.length; i++) { devi@23: subelems = elements[i].getElementsByTagName('pre'); devi@23: for(j=0; j<subelems.length; j++) { devi@23: if (subelems[j].className = 'output') { devi@23: var str = new String(subelems[j].nodeValue); devi@23: if (jjj != 1) { devi@23: alert(str); devi@23: jjj=1; devi@23: } devi@23: if (str.indexOf(text) >0) devi@23: subelems[j].style.display = "none"; devi@23: else devi@23: subelems[j].style.display = ""; devi@23: devi@23: } devi@23: devi@23: } devi@23: } devi@23: devi@23: } devi@23: JS devi@23: devi@23: %Search_Machines = ( devi@23: "google" => { "query" => "http://www.google.com/search?q=" , devi@23: "icon" => "google.ico" }, devi@23: "freebsd" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", devi@23: "icon" => "freebsd.ico" }, devi@23: "linux" => { "query" => "http://man.he.net/?topic=", devi@23: "icon" => "linux.ico"}, devi@23: "opennet" => { "query" => "http://www.opennet.ru/search.shtml?words=", devi@23: "icon" => "opennet.ico"}, devi@23: "local" => { "query" => "http://www.freebsd.org/cgi/man.cgi?query=", devi@23: "icon" => "freebsd.ico" }, devi@23: devi@23: ); devi@23: devi@23: %Elements_Visibility = ( devi@23: "note" => "замечания", devi@23: "diff" => "редактор", devi@23: "time" => "время", devi@23: "ttychange" => "терминал", devi@23: "wrong_output wrong_cline wrong_root_output wrong_root_cline" devi@23: => "команды с ошибками", devi@23: "interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" devi@23: => "прерванные команды", devi@23: "tab_completion_output tab_completion_cline" devi@23: => "продолжение с помощью tab" devi@23: ); devi@23: devi@23: @Day_Name = qw/ Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота /; devi@23: @Month_Name = qw/ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь /; devi@23: @Of_Month_Name = qw/ Января Февраля Марта Апреля Мая Июня Июля Августа Сентября Октября Ноября Декабря /; devi@23: } devi@23: