lilalo
diff l3-frontend @ 31:196c82b6e538
l3-cgi:
* Сделана поддержка кодировок клиента отличных от utf-8 (пока что почему-то не работает)
* Сделана поддержка комментирования из самой командной строки.
Комментарии вставлюятся с помощью символов #^, #v или #=
Комментарии записываются в элементы note и note_title
l3-frontend:
* Сделана поддержка комментирования из самой командной строки.
Комментарии вставлюятся с помощью символов #^, #v или #=
* Вместо использования программы mywi-client, обращение к mywi-серверу выполняется самостоятельно
* Выполняется разбор команды с целью выявления новых команд, ведения статистики, генерирования подсказок и т.д.
* Во всплывающих командах к подсказкам выводится информация от mywi
* Выводится статистическая информация о журнале
"Время первой команды журнала"
"Время последней команды журнала"
"Количество командных строк в журнале"
"Процент команд с кодом ненулевым кодом завершения, %"
"Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час"
"Количество командных строк в единицу времени, команда/мин"
"Частота использования команд"
"Частота использования команд"
"Частота использования этих команд < 0.5%"
* В заголовке страницы выводится информация о курсе и имя слушателя
* Расшифровка к информации о курсе выводится только если есть сама информация
* В оглавлении учитваются пометки notes, вставленные с помощью #=
* Добавлена справка по использованию журнала
Новые параметры:
show_notes - нужно ли показывать заметки "notes"
> note_width - ширина заметок "notes"
mywi_server - IP-адрес сервера mywi
mywi_port - порт сервера mywi
stat_inactivity_interval - при подсчёте времени работы с терминалом,
интервалы превышающие какую длительность не должны учитываться, сек
* Сделана поддержка кодировок клиента отличных от utf-8 (пока что почему-то не работает)
* Сделана поддержка комментирования из самой командной строки.
Комментарии вставлюятся с помощью символов #^, #v или #=
Комментарии записываются в элементы note и note_title
l3-frontend:
* Сделана поддержка комментирования из самой командной строки.
Комментарии вставлюятся с помощью символов #^, #v или #=
* Вместо использования программы mywi-client, обращение к mywi-серверу выполняется самостоятельно
* Выполняется разбор команды с целью выявления новых команд, ведения статистики, генерирования подсказок и т.д.
* Во всплывающих командах к подсказкам выводится информация от mywi
* Выводится статистическая информация о журнале
"Время первой команды журнала"
"Время последней команды журнала"
"Количество командных строк в журнале"
"Процент команд с кодом ненулевым кодом завершения, %"
"Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час"
"Количество командных строк в единицу времени, команда/мин"
"Частота использования команд"
"Частота использования команд"
"Частота использования этих команд < 0.5%"
* В заголовке страницы выводится информация о курсе и имя слушателя
* Расшифровка к информации о курсе выводится только если есть сама информация
* В оглавлении учитваются пометки notes, вставленные с помощью #=
* Добавлена справка по использованию журнала
Новые параметры:
show_notes - нужно ли показывать заметки "notes"
> note_width - ширина заметок "notes"
mywi_server - IP-адрес сервера mywi
mywi_port - порт сервера mywi
stat_inactivity_interval - при подсчёте времени работы с терминалом,
интервалы превышающие какую длительность не должны учитываться, сек
author | devi |
---|---|
date | Fri Nov 11 21:29:49 2005 +0200 (2005-11-11) |
parents | b3f5f5560802 |
children | 4d252e7dd478 |
line diff
1.1 --- a/l3-frontend Mon Nov 07 13:28:15 2005 +0200 1.2 +++ b/l3-frontend Fri Nov 11 21:29:49 2005 +0200 1.3 @@ -1,9 +1,15 @@ 1.4 #!/usr/bin/perl -w 1.5 1.6 +use IO::Socket; 1.7 use lib '.'; 1.8 use l3config; 1.9 +use locale; 1.10 1.11 our @Command_Lines; 1.12 +our @Command_Lines_Index; 1.13 +our %Commands_Description; 1.14 +our %Args_Description; 1.15 +our $Mywi_Socket; 1.16 1.17 # vvv Инициализация переменных выполняется процедурой init_variables 1.18 our @Day_Name; 1.19 @@ -13,12 +19,18 @@ 1.20 our %Elements_Visibility; 1.21 # ^^^ 1.22 1.23 +our %Stat; 1.24 +our %CommandsFDistribution; # Сколько раз в журнале встречается какая команда 1.25 + 1.26 sub search_buy; 1.27 sub make_comment; 1.28 sub load_command_lines_from_xml; 1.29 sub print_command_lines; 1.30 +sub sort_command_lines; 1.31 +sub process_command_lines; 1.32 sub init_variables; 1.33 sub main; 1.34 +sub collapse_list($); 1.35 1.36 main(); 1.37 1.38 @@ -29,8 +41,12 @@ 1.39 init_variables(); 1.40 init_config(); 1.41 1.42 + open_mywi_socket; 1.43 load_command_lines_from_xml($Config{"backend_datafile"}); 1.44 + sort_command_lines; 1.45 + process_command_lines; 1.46 print_command_lines($Config{"output"}); 1.47 + close_mywi_socket; 1.48 } 1.49 1.50 1.51 @@ -44,62 +60,139 @@ 1.52 $Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; 1.53 } 1.54 1.55 +sub extract_from_cline 1.56 +# Разобрать командную строку $_[1] и возвратить хэш, содержащий 1.57 +# номер первого появление команды в строке: 1.58 +# команда => первая позиция 1.59 +{ 1.60 + my $what = $_[0]; 1.61 + my $cline = $_[1]; 1.62 + my @lists = split /\;/, $cline; 1.63 + 1.64 + 1.65 + my @commands = (); 1.66 + for my $list (@lists) { 1.67 + push @commands, split /\|/, $list; 1.68 + } 1.69 + 1.70 + my %commands; 1.71 + my %args; 1.72 + my $i=0; 1.73 + for my $command (@commands) { 1.74 + $command =~ s@^\s*\S+/@@; 1.75 + $command =~ /\s*(\S+)\s*(.*)/; 1.76 + if ($1 && $1 eq "sudo" ) { 1.77 + $commands{"$1"}=$i++; 1.78 + $command =~ s/\s*sudo\s+//; 1.79 + } 1.80 + $command =~ s@^\s*\S+/@@; 1.81 + $command =~ /\s*(\S+)\s*(.*)/; 1.82 + if ($1 && !defined $commands{"$1"}) { 1.83 + $commands{"$1"}=$i++; 1.84 + }; 1.85 + if ($2) { 1.86 + my $args = $2; 1.87 + my @args = split (/\s+/, $args); 1.88 + for my $a (@args) { 1.89 + $args{"$a"}=$i++ 1.90 + if !defined $args{"$a"}; 1.91 + }; 1.92 + 1.93 + 1.94 + } 1.95 + } 1.96 + 1.97 + if ($what eq "commands") { 1.98 + return \%commands; 1.99 + } else { 1.100 + return \%args; 1.101 + } 1.102 + 1.103 +} 1.104 + 1.105 +sub open_mywi_socket 1.106 +{ 1.107 + $Mywi_Socket = IO::Socket::INET->new( 1.108 + PeerAddr => $Config{mywi_server}, 1.109 + PeerPort => $Config{mywi_port}, 1.110 + Proto => "tcp", 1.111 + Type => SOCK_STREAM); 1.112 +} 1.113 + 1.114 +sub close_mywi_socket 1.115 +{ 1.116 + close ($Mywi_Socket); 1.117 +} 1.118 + 1.119 + 1.120 +sub mywi_client 1.121 +{ 1.122 + my $query = $_[0]; 1.123 + my $mywi; 1.124 + 1.125 + open_mywi_socket; 1.126 + if ($Mywi_Socket) { 1.127 + local $| = 1; 1.128 + local $/ = ""; 1.129 + print $Mywi_Socket $query."\n"; 1.130 + $mywi = <$Mywi_Socket>; 1.131 + $mywi = "" if $mywi =~ /nothing app/; 1.132 + } 1.133 + close_mywi_socket; 1.134 + return $mywi; 1.135 +} 1.136 + 1.137 sub make_comment 1.138 { 1.139 - my $commands = $_[0]; 1.140 - my $files = $_[1]; 1.141 - chomp $commands; 1.142 - chomp $files; 1.143 - return if (!$commands && !$files); 1.144 + my $cline = $_[0]; 1.145 + #my $files = $_[1]; 1.146 1.147 - my $comment=""; 1.148 + my @comments=(); 1.149 + my @commands = keys %{extract_from_cline("commands", $cline)}; 1.150 + my @args = keys %{extract_from_cline("args", $cline)}; 1.151 + return if (!@commands && !@args); 1.152 + #return "commands=".join(" ",@commands)."; files=".join(" ",@files); 1.153 1.154 # Commands 1.155 - for my $command (split /\s+/,$commands) { 1.156 + for my $command (@commands) { 1.157 $command =~ s/'//g; 1.158 - my $description=""; 1.159 - eval { $description=`/home/devi/bin/mywi-client '$command'`; } ; 1.160 - $description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description))); 1.161 - $description =~ s/.*?-//; 1.162 - next if $description =~ /^\s*$/; 1.163 - 1.164 - my $query=$command." ".$Config{"keywords"}; 1.165 - $query =~ s/\ /+/g; 1.166 - my $search= search_by("opennet",$query). 1.167 - search_by("local",$command). 1.168 - search_by("google",$query); 1.169 + $CommandsFDistribution{$command}++; 1.170 + if (!$Commands_Description{$command}) { 1.171 + my $mywi; 1.172 + $mywi = mywi_client ($command); 1.173 + $mywi = join ("\n", grep(/\([18]\)/, split(/\n/, $mywi))); 1.174 + $mywi =~ s/\s+/ /; 1.175 + if ($mywi !~ /^\s*$/) { 1.176 + $Commands_Description{$command} = $mywi; 1.177 + } 1.178 + else { 1.179 + next; 1.180 + } 1.181 + } 1.182 1.183 - $comment .= "<tr><td class='note_title'>$command</td>". 1.184 - "<td class='note_search'>$search</td>". 1.185 - "</tr><tr><td width='100%' colspan='2' class='note_text'>". 1.186 - "$description</td></tr><tr/>"; 1.187 + push @comments, $Commands_Description{$command}; 1.188 } 1.189 + return join(" \n", @comments); 1.190 1.191 # Files 1.192 - for my $file (split /\s+/,$files) { 1.193 - $file =~ s@.*/@@; 1.194 - $file =~ s/'//g; 1.195 - next if $file =~ /^\s*$/; 1.196 - next if $file =~ /^-/; 1.197 - 1.198 - my $description=`mywi '$file'`; 1.199 - $description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description))); 1.200 - next if $description =~ /^\s*$/; 1.201 + for my $arg (@args) { 1.202 + $arg =~ s/'//g; 1.203 + if (!$Args_Description{$arg}) { 1.204 + my $mywi; 1.205 + $mywi = mywi_client ($arg); 1.206 + $mywi = join ("\n", grep(/\([5]\)/, split(/\n/, $mywi))); 1.207 + $mywi =~ s/\s+/ /; 1.208 + if ($mywi !~ /^\s*$/) { 1.209 + $Args_Description{$arg} = $mywi; 1.210 + } 1.211 + else { 1.212 + next; 1.213 + } 1.214 + } 1.215 1.216 - my $query=$file." ".$Config{"files_keywords"}; 1.217 - $query =~ s/\ /+/g; 1.218 - my $search= search_by("opennet",$query). 1.219 - search_by("local",$file). 1.220 - search_by("google",$query); 1.221 - 1.222 - $comment .= "<tr><td class='note_title'>$file</td>". 1.223 - "<td class='note_search'>$search</td>". 1.224 - "</tr><tr><td width='100%' colspan='2' class='note_text'>". 1.225 - "$description</td></tr><tr/>"; 1.226 + push @comments, $Args_Description{$arg}; 1.227 } 1.228 1.229 - 1.230 - return $comment; 1.231 } 1.232 1.233 =cut 1.234 @@ -130,6 +223,123 @@ 1.235 } 1.236 } 1.237 1.238 +sub sort_command_lines 1.239 +{ 1.240 + # Sort Command_Lines 1.241 + # Write Command_Lines to Command_Lines_Index 1.242 + 1.243 + my @index; 1.244 + for (my $i=0;$i<=$#Command_Lines;$i++) { 1.245 + $index[$i]=$i; 1.246 + } 1.247 + 1.248 + @Command_Lines_Index = sort { 1.249 + $Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"} 1.250 + } @index; 1.251 + 1.252 +} 1.253 + 1.254 +sub process_command_lines 1.255 +{ 1.256 + for my $i (@Command_Lines_Index) { 1.257 + 1.258 + my $cl = \$Command_Lines[$i]; 1.259 + @{${$cl}->{"new_commands"}} =(); 1.260 + @{${$cl}->{"new_files"}} =(); 1.261 + $$cl->{"class"} = ""; 1.262 + 1.263 + if ($$cl->{"err"}) { 1.264 + $$cl->{"class"}="wrong"; 1.265 + $$cl->{"class"}="interrupted" 1.266 + if ($$cl->{"err"} eq 130); 1.267 + } 1.268 + if (!$$cl->{"euid"}) { 1.269 + $$cl->{"class"}.="_root"; 1.270 + } 1.271 + 1.272 +#tab# my @tab_words=split /\s+/, $$cl->{"output"}; 1.273 +#tab# my $last_word= $$cl->{"cline"} =~ /(\S*)$/; 1.274 +#tab# $last_word =~ s@.*/@@; 1.275 +#tab# my $this_is_tab=1; 1.276 +#tab# 1.277 +#tab# if ($last_word && @tab_words >2) { 1.278 +#tab# for my $tab_words (@tab_words) { 1.279 +#tab# if ($tab_words !~ /^$last_word/) { 1.280 +#tab# $this_is_tab=0; 1.281 +#tab# last; 1.282 +#tab# } 1.283 +#tab# } 1.284 +#tab# } 1.285 +#tab# $$cl->{"class"}="tab" if $this_is_tab; 1.286 + 1.287 + 1.288 +# if ( !$$cl->{"err"}) { 1.289 +# # Command does not contain mistakes 1.290 +# 1.291 +# my %commands = extract_from_cline("commands", ${$cl}->{"cline"}); 1.292 +# my %files = extract_from_cline("files", ${$cl}->{"cline"}); 1.293 +# 1.294 +# # Searching for new commands only 1.295 +# for my $command (keys %commands) { 1.296 +# if (!defined $Commands_Stat{$command}) { 1.297 +# push @{$$cl->{new_commands}}, $command; 1.298 +# } 1.299 +# $Commands_Stat{$command}++; 1.300 +# } 1.301 +# 1.302 +# for my $file (keys %files) { 1.303 +# if (!defined $Files_Stat{$file}) { 1.304 +# push @{$$cl->{new_files}}, $file; 1.305 +# } 1.306 +# $Files_Stat{$file}++; 1.307 +# } 1.308 +# } 1.309 + 1.310 + if ($$cl->{cline}=~ m@cat[^#]*#([\^=v])\s*(.*)@) { 1.311 + if ($1 eq "=") { 1.312 + $$cl->{"class"} = "note"; 1.313 + $$cl->{"note"} = $$cl->{"output"}; 1.314 + $$cl->{"note_title"} = $2; 1.315 + } 1.316 + else { 1.317 + my $j = $i; 1.318 + if ($1 eq "^") { 1.319 + $j--; 1.320 + $j-- while ($j >=0 && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 1.321 + } 1.322 + elsif ($1 eq "v") { 1.323 + $j++; 1.324 + $j++ while ($j <= @Command_Lines && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 1.325 + } 1.326 + $Command_Lines[$j]->{note_title}="$2"; 1.327 + $Command_Lines[$j]->{note}=$$cl->{output}; 1.328 + $$cl=0; 1.329 + } 1.330 + } 1.331 + elsif ($$cl->{cline}=~ /#([\^=v])(.*)/) { 1.332 + if ($1 eq "=") { 1.333 + $$cl->{"class"} = "note"; 1.334 + $$cl->{"note"} = $2; 1.335 + } 1.336 + else { 1.337 + my $j=$i; 1.338 + if ($1 eq "^") { 1.339 + $j--; 1.340 + $j-- while ($j >=0 && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); 1.341 + } 1.342 + elsif ($1 eq "v") { 1.343 + $j++; 1.344 + $j++ while ($j <= @Command_Lines && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 1.345 + } 1.346 + $Command_Lines[$j]->{note}="$2"; 1.347 + $$cl=0; 1.348 + } 1.349 + } 1.350 + } 1.351 + 1.352 +} 1.353 + 1.354 + 1.355 =cut 1.356 Процедура print_command_lines выводит HTML-представление 1.357 разобранного lab-скрипта. 1.358 @@ -152,7 +362,8 @@ 1.359 # Результат выполнения процедуры равен 1.360 # join("", @Result{header,body,stat,help,about,footer}) 1.361 my %Result; 1.362 - my $toc =""; # Хранит оглавление по дням 1.363 + my @toc; # Хранит оглавление 1.364 + my $note_number=0; 1.365 1.366 $Result{"body"} = "<table width='100%'>\n"; 1.367 1.368 @@ -161,7 +372,12 @@ 1.369 my $last_day=""; 1.370 my $in_range=0; 1.371 1.372 - for my $cl (@Command_Lines) { 1.373 + my $i=0; 1.374 + for my $k (@Command_Lines_Index) { 1.375 + 1.376 + my $cl=$Command_Lines[$Command_Lines_Index[$i++]]; 1.377 + 1.378 + next unless $cl; 1.379 1.380 if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { 1.381 $in_range=1; 1.382 @@ -182,6 +398,20 @@ 1.383 #my @new_commands=@{$cl->{"new_commands"}}; 1.384 #my @new_files=@{$cl->{"new_files"}}; 1.385 1.386 + if ($cl->{class} eq "note") { 1.387 + my $note = $cl->{note}; 1.388 + $note = join ("\n", map ("<p>$_</p>", split (/-\n/, $note))); 1.389 + $Result{"body"} .= "<tr><td colspan='6'>"; 1.390 + $Result{"body"} .= "<h4 id='note$note_number'>".$cl->{note_title}."</h4>" if $cl->{note_title}; 1.391 + $Result{"body"} .= "".$note."<p/><p/></td></td>"; 1.392 + 1.393 + if ($cl->{note_title}) { 1.394 + push @{$toc[@toc]},"<a href='#note$note_number'>".$cl->{note_title}."</a>"; 1.395 + $note_number++; 1.396 + } 1.397 + next; 1.398 + } 1.399 + 1.400 my $cl_class="cline"; 1.401 my $out_class="output"; 1.402 if ($cl->{"class"}) { 1.403 @@ -233,6 +463,14 @@ 1.404 # <command> 1.405 1.406 my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); 1.407 + $Stat{FirstCommand} = $cl->{time} unless $Stat{FirstCommand}; 1.408 + $Stat{LastCommand} = 0 unless defined $Stat{LastCommand}; 1.409 + $Stat{TotalTime} += $cl->{time} - $Stat{LastCommand} 1.410 + if $cl->{time} - $Stat{LastCommand} < $Config{stat_inactivity_interval}; 1.411 + $Stat{LastCommand} = $cl->{time}; 1.412 + $Stat{TotalCommands} = 0 unless $Stat{TotalCommands}; 1.413 + $Stat{TotalCommands}++; 1.414 + 1.415 # Добавляем спереди 0 для удобочитаемости 1.416 $min = "0".$min if $min =~ /^.$/; 1.417 $hour = "0".$hour if $hour =~ /^.$/; 1.418 @@ -241,6 +479,8 @@ 1.419 $class=$cl->{"out_class"}; 1.420 $class =~ s/output$//; 1.421 1.422 + $Stat{ErrorCommands}++ 1.423 + if $class =~ /wrong/; 1.424 1.425 $Result{"body"} .= "<tr class='command'>\n"; 1.426 1.427 @@ -249,7 +489,7 @@ 1.428 if ( $last_day ne $day) { 1.429 #$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>"; 1.430 $Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>"; 1.431 - $toc .= "<li><a href='#day$day'>".$Day_Name[$wday]."</a></li>\n"; 1.432 + push @toc, "<a href='#day$day'>".$Day_Name[$wday]."</a>\n"; 1.433 $last_day=$day; 1.434 } 1.435 1.436 @@ -271,9 +511,12 @@ 1.437 # COMMAND 1.438 $Result{"body"} .= "<td class='script'>\n"; 1.439 $Result{"body"} .= "<pre class='${class}cline'>\n"; 1.440 - my $cline = $cl->{"cline"}; 1.441 + my $cline = $cl->{"prompt"}.$cl->{"cline"}; 1.442 $cline =~ s/\n//; 1.443 - $Result{"body"} .= $cl->{"prompt"}.$cl->{"cline"}; 1.444 + my $hint = make_comment($cl->{"cline"}); 1.445 + # join(" ",@new_commands), join (" ",@new_files)); 1.446 + $cline = "<div title='$hint'>$cline</div>" if $hint; 1.447 + $Result{"body"} .= $cline; 1.448 $Result{"body"} .= "</pre>\n"; 1.449 1.450 my $last_command = $cl->{"last_command"}; 1.451 @@ -294,10 +537,22 @@ 1.452 $Result{"body"} .= $cl->{"diff"}; 1.453 $Result{"body"} .= "</pre></td></tr></table>"; 1.454 } 1.455 + 1.456 + #NOTES 1.457 + if ( $Config{"show_notes"} =~ /^y/i && $cl->{"note"}) { 1.458 + my $note=$cl->{"note"}; 1.459 + $note =~ s/\n/<br\/>\n/msg; 1.460 + # Ширину пока не используем 1.461 + # $Result{"body"} .= "<table width='$Config{note_width}' class='note'>"; 1.462 + $Result{"body"} .= "<table class='note'>"; 1.463 + $Result{"body"} .= "<tr><td class='note_title'>".$cl->{note_title}."</td></tr>" if $cl->{note_title}; 1.464 + $Result{"body"} .= "<tr><td width='100%' class='note_text'>".$note."</td></tr>"; 1.465 + $Result{"body"} .= "</table>\n"; 1.466 + } 1.467 1.468 # COMMENT 1.469 if ( $Config{"show_comments"} =~ /^y/i) { 1.470 - my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files)); 1.471 + my $comment = make_comment($cl->{"cline"}); 1.472 if ($comment) { 1.473 $Result{"body"} .= "<table width='$Config{comment_width}'>". 1.474 "<tr><td width='5'/><td>"; 1.475 @@ -315,18 +570,100 @@ 1.476 1.477 $Result{"body"} .= "</table>\n"; 1.478 1.479 - $Result{"stat"} = "<hr/>"; 1.480 + #$Result{"stat"} = "<hr/>"; 1.481 + 1.482 + %StatNames = ( 1.483 + FirstCommand => "Время первой команды журнала", 1.484 + LastCommand => "Время последней команды журнала", 1.485 + TotalCommands => "Количество командных строк в журнале", 1.486 + ErrorsPercentage => "Процент команд с кодом ненулевым кодом завершения, %", 1.487 + TotalTime => "Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час", 1.488 + CommandsPerTime => "Количество командных строк в единицу времени, команда/мин", 1.489 + CommandsFDistribution => "Частота использования команд", 1.490 + CommandsFDistribution => "Частота использования команд", 1.491 + RareCommands => "Частота использования этих команд < 0.5%", 1.492 + ); 1.493 + @StatOrder = ( 1.494 + FirstCommand, 1.495 + LastCommand, 1.496 + TotalCommands, 1.497 + ErrorsPercentage, 1.498 + TotalTime, 1.499 + CommandsPerTime, 1.500 + CommandsFDistribution, 1.501 + RareCommands, 1.502 + ); 1.503 + 1.504 + # Подготовка статистики к выводу 1.505 + # Некоторые значения пересчитываются! 1.506 + # Дальше их лучше уже не использовать!!! 1.507 + 1.508 + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{FirstCommand}); 1.509 + $Stat{FirstCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; 1.510 + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{LastCommand}); 1.511 + $Stat{LastCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; 1.512 + $Stat{ErrorsPercentage} = sprintf "%5.2f", $Stat{ErrorCommands}*100/$Stat{TotalCommands} 1.513 + if $Stat{TotalCommands}; 1.514 + $Stat{CommandsPerTime} = sprintf "%5.2f", $Stat{TotalCommands}*60/$Stat{TotalTime} 1.515 + if $Stat{TotalTime}; 1.516 + $Stat{TotalTime} = sprintf "%5.2f", $Stat{TotalTime}/60/24; 1.517 + 1.518 + my $total_commands=0; 1.519 + for $command (keys %CommandsFDistribution){ 1.520 + $total_commands += $CommandsFDistribution{$command}; 1.521 + } 1.522 + if ($total_commands) { 1.523 + for $command (reverse sort {$CommandsFDistribution{$a} <=> $CommandsFDistribution{$b}} keys %CommandsFDistribution){ 1.524 + my $percentage = sprintf "%5.2f",$CommandsFDistribution{$command}*100/$total_commands; 1.525 + if ($percentage < 0.5) { 1.526 + my $hint = make_comment($command); 1.527 + my $command_html = "$command"; 1.528 + $command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; 1.529 + my $command_html = "<tt>$command_html</tt>"; 1.530 + $Stat{RareCommands} .= $command_html."<sub><font size='-2'>".$CommandsFDistribution{$command}."</font></sub> , "; 1.531 + } 1.532 + else { 1.533 + my $hint = make_comment($command); 1.534 + my $command_html = "$command"; 1.535 + $command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; 1.536 + my $command_html = "<tt>$command_html</tt>"; 1.537 + $percentage = sprintf "%5.2f",$percentage; 1.538 + $Stat{CommandsFDistribution} .= "<tr><td>".$command_html."</td><td>".$CommandsFDistribution{$command}."</td>". 1.539 + "<td>|".("="x int($CommandsFDistribution{$command}*100/$total_commands))."| $percentage%</td></tr>"; 1.540 + } 1.541 + } 1.542 + $Stat{CommandsFDistribution} = "<table>".$Stat{CommandsFDistribution}."</table>"; 1.543 + $Stat{RareCommands} =~ s/, $//; 1.544 + } 1.545 + 1.546 $Result{"stat"} .= "<h2 id='stat'>Статистика</h2>"; 1.547 - $Result{"stat"} .= "Статистическая информация о журнале<br/>"; 1.548 - $Result{"help"} .= "<hr/>"; 1.549 + $Result{"stat"} .= "<table>"; 1.550 + for my $stat (@StatOrder) { 1.551 + $Result{"stat"} .= "<tr valign='top'><td width='300'>".$StatNames{"$stat"}."</td><td>".$Stat{"$stat"}."</td></tr>"; 1.552 + } 1.553 + 1.554 + $Result{"stat"} .= "</table>"; 1.555 + $Result{"stat"} .= "<font size='-2'>____<br/>*) Интервалы неактивности длительностью ".($Config{stat_inactivity_interval}/60)." минут и более не учитываются</font></br>"; 1.556 + 1.557 + #$Result{"help"} .= "<hr/>"; 1.558 $Result{"help"} .= "<h2 id='help'>Справка</h2>"; 1.559 $Result{"help"} .= "$Html_Help<br/>"; 1.560 - $Result{"about"} .= "<hr/>"; 1.561 + #$Result{"about"} .= "<hr/>"; 1.562 $Result{"about"} .= "<h2 id='about'>О программе</h2>"; 1.563 $Result{"about"} .= "$Html_About"; 1.564 $Result{"footer"} .= "</body>\n"; 1.565 $Result{"footer"} .= "</html>\n"; 1.566 1.567 + $Result{"title"} = "Журнал лабораторных работ"; 1.568 + $Result{"title"}.= " -- ".$course_student if $course_student; 1.569 + if ($course_date) { 1.570 + $Result{"title"}.= " -- ".$course_date; 1.571 + $Result{"title"}.= "/".$course_code if $course_code; 1.572 + } 1.573 + else { 1.574 + $Result{"title"}.= " -- ".$course_code if $course_code; 1.575 + } 1.576 + 1.577 # Заголовок генерируется позже всего 1.578 # Тогда, когда известно уже, что должно быть написано в 1.579 # оглавлении 1.580 @@ -335,21 +672,27 @@ 1.581 <head> 1.582 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> 1.583 <link rel='stylesheet' href='$Config{frontend_css}' type='text/css'/> 1.584 + <title>$Result{title}</title> 1.585 </head> 1.586 <body> 1.587 <script> 1.588 $Html_JavaScript 1.589 </script> 1.590 - <h2>Журнал лабораторных работ</h2> 1.591 + <h1>Журнал лабораторных работ</h1> 1.592 1.593 - <p> 1.594 - Выполнил $course_student<br/> 1.595 - Проверил $course_trainer <br/> 1.596 - Курс $course_name ($course_code), 1.597 - $course_date<br/> 1.598 - Учебный центр $course_center <br/> 1.599 - </p> 1.600 +HEADER 1.601 + $Result{"header"} .= "<p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; 1.602 + $Result{"header"} .= "Выполнил $course_student<br/>" if $course_student; 1.603 + $Result{"header"} .= "Проверил $course_trainer <br/>" if $course_trainer; 1.604 + $Result{"header"} .= "Курс " if $course_name || $course_code || $course_date; 1.605 + $Result{"header"} .= "$course_name " if $course_name; 1.606 + $Result{"header"} .= "($course_code)" if $course_code; 1.607 + $Result{"header"} .= ", $course_date<br/>" if $course_date; 1.608 + $Result{"header"} .= "Учебный центр $course_center <br/>" if $course_center; 1.609 + $Result{"header"} .= "</p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; 1.610 1.611 + my $toc = collapse_list (\@toc); 1.612 + $Result{"header"} .= <<HEADER; 1.613 <ul> 1.614 <li><a href='#log'>Журнал</a></li> 1.615 <ul>$toc</ul> 1.616 @@ -360,7 +703,7 @@ 1.617 1.618 <h2 id="log">Журнал</h2> 1.619 HEADER 1.620 - $Result{"header"} .= "<table class='visibility_form'><tr><td><form>\n"; 1.621 + $Result{"header"} .= "<table id='visibility_form' class='visibility_form'><tr><td><form>\n"; 1.622 for my $element (keys %Elements_Visibility) 1.623 { 1.624 my @e = split /\s+/, $element; 1.625 @@ -385,13 +728,205 @@ 1.626 1.627 1.628 1.629 +sub collapse_list($) 1.630 +{ 1.631 + my $res = ""; 1.632 + for my $elem (@{$_[0]}) { 1.633 + if (ref $elem eq "ARRAY") { 1.634 + $res .= "<ul>".collapse_list($elem)."</ul>"; 1.635 + } 1.636 + else 1.637 + { 1.638 + $res .= "<li>".$elem."</li>"; 1.639 + } 1.640 + } 1.641 + return $res; 1.642 +} 1.643 + 1.644 1.645 1.646 1.647 sub init_variables 1.648 { 1.649 $Html_Help = <<HELP; 1.650 - Справка по использованию журнала 1.651 + Для того чтобы использовать LiLaLo, не нужно знать ничего особенного: 1.652 + всё происходит само собой. 1.653 + Однако, чтобы ведение и последующее использование журналов 1.654 + было как можно более эффективным, желательно иметь в виду следующее: 1.655 + <ul> 1.656 + <li><p> 1.657 + В журнал автоматически попадают все команды, данные в любом терминале системы. 1.658 + </p></li> 1.659 + <li><p> 1.660 + Для того чтобы убедиться, что журнал на текущем терминале ведётся, 1.661 + и команды записываются, дайте команду w. 1.662 + В поле WHAT, соответствующем текущему терминалу, 1.663 + должна быть указана программа script. 1.664 + </p></li> 1.665 + <li><p> 1.666 + Команды, код завершения которых отличен от нуля, выделяются цветом. 1.667 + Если код завершения команды равен нулю, 1.668 + команда была выполнена без ошибок. 1.669 +<table> 1.670 +<tr class='command'> 1.671 +<td class='script'> 1.672 +<pre class='wrong_cline'> 1.673 +\$ l s-l</pre> 1.674 +<pre class='wrong_output'>bash: l: command not found 1.675 +</pre> 1.676 +</td> 1.677 +</tr> 1.678 +</table> 1.679 +<br/> 1.680 + </p></li> 1.681 + <li><p> 1.682 + Команды, ход выполнения которых был прерван пользователем, выделяются цветом. 1.683 +<table> 1.684 +<tr class='command'> 1.685 +<td class='script'> 1.686 +<pre class='interrupted_cline'> 1.687 +\$ find / -name abc</pre> 1.688 +<pre class='interrupted_output'>find: /home/devi-orig/.gnome2: Keine Berechtigung 1.689 +find: /home/devi-orig/.gnome2_private: Keine Berechtigung 1.690 +find: /home/devi-orig/.nautilus/metafiles: Keine Berechtigung 1.691 +find: /home/devi-orig/.metacity: Keine Berechtigung 1.692 +find: /home/devi-orig/.inkscape: Keine Berechtigung 1.693 +^C 1.694 +</pre> 1.695 +</td> 1.696 +</tr> 1.697 +</table> 1.698 +<br/> 1.699 + </p></li> 1.700 + <li><p> 1.701 + Команды, выполненные с привилегиями суперпользователя, 1.702 + выделяются слева красной чертой. 1.703 +<table> 1.704 +<tr class='command'> 1.705 +<td class='script'> 1.706 +<pre class='_root_cline'> 1.707 +# id</pre> 1.708 +<pre class='_root_output'> 1.709 +uid=0(root) gid=0(root) Gruppen=0(root) 1.710 +</pre> 1.711 +</td> 1.712 +</tr> 1.713 +</table> 1.714 + <br/> 1.715 + </p></li> 1.716 + <li><p> 1.717 + Изменения, внесённые в текстовый файл с помощью редактора, 1.718 + запоминаются и показываются в журнале в формате ed. 1.719 + Строки, начинающиеся символом "<", удалены, а строки, 1.720 + начинающиеся символом ">" -- добавлены. 1.721 +<table> 1.722 +<tr class='command'> 1.723 +<td class='script'> 1.724 +<pre class='cline'> 1.725 +\$ vi ~/.bashrc</pre> 1.726 +<table><tr><td width='5'/><td class='diff'><pre>2a3,5 1.727 +> if [ -f /usr/local/etc/bash_completion ]; then 1.728 +> . /usr/local/etc/bash_completion 1.729 +> fi 1.730 +</pre></td></tr></table></td> 1.731 +</tr> 1.732 +</table> 1.733 + <br/> 1.734 + </p></li> 1.735 + <li><p> 1.736 + Для того чтобы получить краткую справочную информацию о команде, 1.737 + нужно подвести к ней мышь. Во всплывающей подсказке появится краткое 1.738 + описание команды. 1.739 + </p></li> 1.740 + <li><p> 1.741 + Время ввода команды, показанное в журнале, соответствует времени 1.742 + <i>начала ввода командной строки</i>, которое равно тому моменту, 1.743 + когда на терминале появилось приглашение интерпретатора 1.744 + </p></li> 1.745 + <li><p> 1.746 + Имя терминала, на котором была введена команда, показано в специальном блоке. 1.747 + Этот блок показывается только в том случае, если терминал 1.748 + текущей команды отличается от терминала предыдущей. 1.749 + </p></li> 1.750 + <li><p> 1.751 + Вывод не интересующих вас в настоящий момент элементов журнала, 1.752 + таких как время, имя терминала и других, можно отключить. 1.753 + Для этого нужно воспользоваться <a href='#visibility_form'>формой управления журналом</a> 1.754 + вверху страницы. 1.755 + </p></li> 1.756 + <li><p> 1.757 + Небольшие комментарии к командам можно вставлять прямо из командной строки. 1.758 + Комментарий вводится прямо в командную строку, после символов #^ или #v. 1.759 + Символы ^ и v показывают направление выбора команды, к которой относится комментарий: 1.760 + ^ - к предыдущей, v - к следующей. 1.761 + Например, если в командной строке было введено: 1.762 +<pre class='cline'> 1.763 +\$ whoami 1.764 +</pre> 1.765 +<pre class='output'> 1.766 +user 1.767 +</pre> 1.768 +<pre class='cline'> 1.769 +\$ #^ Интересно, кто я? 1.770 +</pre> 1.771 + в журнале это будет выглядеть так: 1.772 + 1.773 +<pre class='cline'> 1.774 +\$ whoami 1.775 +</pre> 1.776 +<pre class='output'> 1.777 +user 1.778 +</pre> 1.779 +<table class='note'><tr><td width='100%' class='note_text'> 1.780 +<tr> <td> Интересно, кто я?<br/> </td></tr></table> 1.781 + </p></li> 1.782 + <li><p> 1.783 + Если комментарий содержит несколько строк, 1.784 + его можно вставить в журнал следующим образом: 1.785 +<pre class='cline'> 1.786 +\$ whoami 1.787 +</pre> 1.788 +<pre class='output'> 1.789 +user 1.790 +</pre> 1.791 +<pre class='cline'> 1.792 +\$ cat > /dev/null #^ Интересно, кто я? 1.793 +</pre> 1.794 +<pre class='output'> 1.795 +Программа whoami выводит имя пользователя, под которым 1.796 +мы зарегистрировались в системе. 1.797 +- 1.798 +Она не может ответить на вопрос о нашем назначении 1.799 +в этом мире. 1.800 +</pre> 1.801 + В журнале это будет выглядеть так: 1.802 +<table> 1.803 +<tr class='command'> 1.804 +<td class='script'> 1.805 +<pre class='cline'> 1.806 +\$ whoami</pre> 1.807 +<pre class='output'>user 1.808 +</pre> 1.809 +<table class='note'><tr><td class='note_title'>Интересно, кто я?</td></tr><tr><td width='100%' class='note_text'> 1.810 +Программа whoami выводит имя пользователя, под которым<br/> 1.811 +мы зарегистрировались в системе.<br/> 1.812 +<br/> 1.813 +Она не может ответить на вопрос о нашем назначении<br/> 1.814 +в этом мире.<br/> 1.815 +</td></tr></table> 1.816 +</td> 1.817 +</tr> 1.818 +</table> 1.819 + Для разделения нескольких абзацев между собой 1.820 + используйте символ "-", один в строке. 1.821 + <br/> 1.822 +</p></li> 1.823 + <li><p> 1.824 + Комментарии, не относящиеся непосредственно ни к какой из команд, 1.825 + добавляются точно таким же способом, только вместо симолов #^ или #v 1.826 + нужно использовать символы #= 1.827 + </p></li> 1.828 +</ul> 1.829 HELP 1.830 1.831 $Html_About = <<ABOUT;