lilalo
changeset 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 | f5f07049bd4f |
children | 4d252e7dd478 |
files | l3-agent l3-cgi l3-frontend l3config.pm |
line diff
1.1 --- a/l3-agent Tue Nov 08 12:16:20 2005 +0200 1.2 +++ b/l3-agent Fri Nov 11 21:29:49 2005 +0200 1.3 @@ -543,9 +543,10 @@ 1.4 if (!$last_cl{"suppress_output"} || $last_cl{"err"}) { 1.5 for (my $i=0; $i<$Config{"terminal_height"}; $i++) { 1.6 my $line= $vt->row_plaintext($i); 1.7 - next if !defined ($line) || $line =~ /^\s*$/; 1.8 + next if !defined ($line) ; #|| $line =~ /^\s*$/; 1.9 $line =~ s/\s*$//; 1.10 - $last_cl{"output"} .= $line."\n"; 1.11 + $line .= "\n" unless $line =~ /^\s*$/; 1.12 + $last_cl{"output"} .= $line; 1.13 } 1.14 } 1.15 else { 1.16 @@ -690,6 +691,13 @@ 1.17 $Files_Stat{$file}++; 1.18 } 1.19 } 1.20 + 1.21 + #if ($$cl->{cline}=~ /#\^(.*)/) { 1.22 + # my $j=$i-1; 1.23 + # $j-- while ($j >=0 && $Command_Lines[$j]->{tty} ne $$cl->{tty}); 1.24 + # $Command_Lines[$j]->{note_title}="Замечание"; 1.25 + # $Command_Lines[$j]->{note}="$1"; 1.26 + #} 1.27 } 1.28 1.29 } 1.30 @@ -773,7 +781,7 @@ 1.31 # Full output 1.32 $output .= $cl->{"output"}; 1.33 } 1.34 - $output .= "^C\n" if ($cl->{"err"} eq "130"); 1.35 + #$output .= "^C\n" if ($cl->{"err"} eq "130"); 1.36 1.37 1.38 # Совместимость с labmaker 1.39 @@ -825,6 +833,16 @@ 1.40 printq(\*OUT,${$Diffs{$cl->{"diff"}}}{"text"}); 1.41 print OUT "</diff>\n"; 1.42 } 1.43 + if ($cl->{"note"}) { 1.44 + print OUT "<note>"; 1.45 + printq(\*OUT,$cl->{"note"}); 1.46 + print OUT "</note>\n"; 1.47 + } 1.48 + if ($cl->{"note_title"}) { 1.49 + print OUT "<note_title>"; 1.50 + printq(\*OUT,$cl->{"note_title"}); 1.51 + print OUT "</note_title>\n"; 1.52 + } 1.53 print OUT "</command>\n"; 1.54 1.55 }
2.1 --- a/l3-cgi Tue Nov 08 12:16:20 2005 +0200 2.2 +++ b/l3-cgi Fri Nov 11 21:29:49 2005 +0200 2.3 @@ -72,6 +72,13 @@ 2.4 print "Template to load files: ".$l3config::Config{"path_classes"}."*".$l3config::Config{"class_suffix"}."\n" 2.5 } 2.6 } 2.7 +elsif ($ENV{PATH_INFO} eq "/current") { 2.8 + open (FRONTEND, "./l3-frontend --output - --show_comments no |"); 2.9 + while (<FRONTEND>) { 2.10 + print; 2.11 + } 2.12 + close(FRONTEND); 2.13 +} 2.14 else { 2.15 # Вызов производится по URL 2.16 my ($skip, $course, $host, $user) = split /\//,$ENV{PATH_INFO},4; 2.17 @@ -88,6 +95,7 @@ 2.18 "--course-code" => $XMLTraining->{course}, 2.19 "--course-date" => $XMLTraining->{date}, 2.20 "--backend_datafile" => "/var/lilalo/lablogs-xml/$course/$host/$user.xml", 2.21 + "--encoding" => $XMLTraining->{host}->{$host}->{charset}, 2.22 ); 2.23 2.24 open (FRONTEND, "./l3-frontend ".join(" ",map("\"$_\"",@args))." |");
3.1 --- a/l3-frontend Tue Nov 08 12:16:20 2005 +0200 3.2 +++ b/l3-frontend Fri Nov 11 21:29:49 2005 +0200 3.3 @@ -1,9 +1,15 @@ 3.4 #!/usr/bin/perl -w 3.5 3.6 +use IO::Socket; 3.7 use lib '.'; 3.8 use l3config; 3.9 +use locale; 3.10 3.11 our @Command_Lines; 3.12 +our @Command_Lines_Index; 3.13 +our %Commands_Description; 3.14 +our %Args_Description; 3.15 +our $Mywi_Socket; 3.16 3.17 # vvv Инициализация переменных выполняется процедурой init_variables 3.18 our @Day_Name; 3.19 @@ -13,12 +19,18 @@ 3.20 our %Elements_Visibility; 3.21 # ^^^ 3.22 3.23 +our %Stat; 3.24 +our %CommandsFDistribution; # Сколько раз в журнале встречается какая команда 3.25 + 3.26 sub search_buy; 3.27 sub make_comment; 3.28 sub load_command_lines_from_xml; 3.29 sub print_command_lines; 3.30 +sub sort_command_lines; 3.31 +sub process_command_lines; 3.32 sub init_variables; 3.33 sub main; 3.34 +sub collapse_list($); 3.35 3.36 main(); 3.37 3.38 @@ -29,8 +41,12 @@ 3.39 init_variables(); 3.40 init_config(); 3.41 3.42 + open_mywi_socket; 3.43 load_command_lines_from_xml($Config{"backend_datafile"}); 3.44 + sort_command_lines; 3.45 + process_command_lines; 3.46 print_command_lines($Config{"output"}); 3.47 + close_mywi_socket; 3.48 } 3.49 3.50 3.51 @@ -44,62 +60,139 @@ 3.52 $Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; 3.53 } 3.54 3.55 +sub extract_from_cline 3.56 +# Разобрать командную строку $_[1] и возвратить хэш, содержащий 3.57 +# номер первого появление команды в строке: 3.58 +# команда => первая позиция 3.59 +{ 3.60 + my $what = $_[0]; 3.61 + my $cline = $_[1]; 3.62 + my @lists = split /\;/, $cline; 3.63 + 3.64 + 3.65 + my @commands = (); 3.66 + for my $list (@lists) { 3.67 + push @commands, split /\|/, $list; 3.68 + } 3.69 + 3.70 + my %commands; 3.71 + my %args; 3.72 + my $i=0; 3.73 + for my $command (@commands) { 3.74 + $command =~ s@^\s*\S+/@@; 3.75 + $command =~ /\s*(\S+)\s*(.*)/; 3.76 + if ($1 && $1 eq "sudo" ) { 3.77 + $commands{"$1"}=$i++; 3.78 + $command =~ s/\s*sudo\s+//; 3.79 + } 3.80 + $command =~ s@^\s*\S+/@@; 3.81 + $command =~ /\s*(\S+)\s*(.*)/; 3.82 + if ($1 && !defined $commands{"$1"}) { 3.83 + $commands{"$1"}=$i++; 3.84 + }; 3.85 + if ($2) { 3.86 + my $args = $2; 3.87 + my @args = split (/\s+/, $args); 3.88 + for my $a (@args) { 3.89 + $args{"$a"}=$i++ 3.90 + if !defined $args{"$a"}; 3.91 + }; 3.92 + 3.93 + 3.94 + } 3.95 + } 3.96 + 3.97 + if ($what eq "commands") { 3.98 + return \%commands; 3.99 + } else { 3.100 + return \%args; 3.101 + } 3.102 + 3.103 +} 3.104 + 3.105 +sub open_mywi_socket 3.106 +{ 3.107 + $Mywi_Socket = IO::Socket::INET->new( 3.108 + PeerAddr => $Config{mywi_server}, 3.109 + PeerPort => $Config{mywi_port}, 3.110 + Proto => "tcp", 3.111 + Type => SOCK_STREAM); 3.112 +} 3.113 + 3.114 +sub close_mywi_socket 3.115 +{ 3.116 + close ($Mywi_Socket); 3.117 +} 3.118 + 3.119 + 3.120 +sub mywi_client 3.121 +{ 3.122 + my $query = $_[0]; 3.123 + my $mywi; 3.124 + 3.125 + open_mywi_socket; 3.126 + if ($Mywi_Socket) { 3.127 + local $| = 1; 3.128 + local $/ = ""; 3.129 + print $Mywi_Socket $query."\n"; 3.130 + $mywi = <$Mywi_Socket>; 3.131 + $mywi = "" if $mywi =~ /nothing app/; 3.132 + } 3.133 + close_mywi_socket; 3.134 + return $mywi; 3.135 +} 3.136 + 3.137 sub make_comment 3.138 { 3.139 - my $commands = $_[0]; 3.140 - my $files = $_[1]; 3.141 - chomp $commands; 3.142 - chomp $files; 3.143 - return if (!$commands && !$files); 3.144 + my $cline = $_[0]; 3.145 + #my $files = $_[1]; 3.146 3.147 - my $comment=""; 3.148 + my @comments=(); 3.149 + my @commands = keys %{extract_from_cline("commands", $cline)}; 3.150 + my @args = keys %{extract_from_cline("args", $cline)}; 3.151 + return if (!@commands && !@args); 3.152 + #return "commands=".join(" ",@commands)."; files=".join(" ",@files); 3.153 3.154 # Commands 3.155 - for my $command (split /\s+/,$commands) { 3.156 + for my $command (@commands) { 3.157 $command =~ s/'//g; 3.158 - my $description=""; 3.159 - eval { $description=`/home/devi/bin/mywi-client '$command'`; } ; 3.160 - $description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description))); 3.161 - $description =~ s/.*?-//; 3.162 - next if $description =~ /^\s*$/; 3.163 - 3.164 - my $query=$command." ".$Config{"keywords"}; 3.165 - $query =~ s/\ /+/g; 3.166 - my $search= search_by("opennet",$query). 3.167 - search_by("local",$command). 3.168 - search_by("google",$query); 3.169 + $CommandsFDistribution{$command}++; 3.170 + if (!$Commands_Description{$command}) { 3.171 + my $mywi; 3.172 + $mywi = mywi_client ($command); 3.173 + $mywi = join ("\n", grep(/\([18]\)/, split(/\n/, $mywi))); 3.174 + $mywi =~ s/\s+/ /; 3.175 + if ($mywi !~ /^\s*$/) { 3.176 + $Commands_Description{$command} = $mywi; 3.177 + } 3.178 + else { 3.179 + next; 3.180 + } 3.181 + } 3.182 3.183 - $comment .= "<tr><td class='note_title'>$command</td>". 3.184 - "<td class='note_search'>$search</td>". 3.185 - "</tr><tr><td width='100%' colspan='2' class='note_text'>". 3.186 - "$description</td></tr><tr/>"; 3.187 + push @comments, $Commands_Description{$command}; 3.188 } 3.189 + return join(" \n", @comments); 3.190 3.191 # Files 3.192 - for my $file (split /\s+/,$files) { 3.193 - $file =~ s@.*/@@; 3.194 - $file =~ s/'//g; 3.195 - next if $file =~ /^\s*$/; 3.196 - next if $file =~ /^-/; 3.197 - 3.198 - my $description=`mywi '$file'`; 3.199 - $description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description))); 3.200 - next if $description =~ /^\s*$/; 3.201 + for my $arg (@args) { 3.202 + $arg =~ s/'//g; 3.203 + if (!$Args_Description{$arg}) { 3.204 + my $mywi; 3.205 + $mywi = mywi_client ($arg); 3.206 + $mywi = join ("\n", grep(/\([5]\)/, split(/\n/, $mywi))); 3.207 + $mywi =~ s/\s+/ /; 3.208 + if ($mywi !~ /^\s*$/) { 3.209 + $Args_Description{$arg} = $mywi; 3.210 + } 3.211 + else { 3.212 + next; 3.213 + } 3.214 + } 3.215 3.216 - my $query=$file." ".$Config{"files_keywords"}; 3.217 - $query =~ s/\ /+/g; 3.218 - my $search= search_by("opennet",$query). 3.219 - search_by("local",$file). 3.220 - search_by("google",$query); 3.221 - 3.222 - $comment .= "<tr><td class='note_title'>$file</td>". 3.223 - "<td class='note_search'>$search</td>". 3.224 - "</tr><tr><td width='100%' colspan='2' class='note_text'>". 3.225 - "$description</td></tr><tr/>"; 3.226 + push @comments, $Args_Description{$arg}; 3.227 } 3.228 3.229 - 3.230 - return $comment; 3.231 } 3.232 3.233 =cut 3.234 @@ -130,6 +223,123 @@ 3.235 } 3.236 } 3.237 3.238 +sub sort_command_lines 3.239 +{ 3.240 + # Sort Command_Lines 3.241 + # Write Command_Lines to Command_Lines_Index 3.242 + 3.243 + my @index; 3.244 + for (my $i=0;$i<=$#Command_Lines;$i++) { 3.245 + $index[$i]=$i; 3.246 + } 3.247 + 3.248 + @Command_Lines_Index = sort { 3.249 + $Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"} 3.250 + } @index; 3.251 + 3.252 +} 3.253 + 3.254 +sub process_command_lines 3.255 +{ 3.256 + for my $i (@Command_Lines_Index) { 3.257 + 3.258 + my $cl = \$Command_Lines[$i]; 3.259 + @{${$cl}->{"new_commands"}} =(); 3.260 + @{${$cl}->{"new_files"}} =(); 3.261 + $$cl->{"class"} = ""; 3.262 + 3.263 + if ($$cl->{"err"}) { 3.264 + $$cl->{"class"}="wrong"; 3.265 + $$cl->{"class"}="interrupted" 3.266 + if ($$cl->{"err"} eq 130); 3.267 + } 3.268 + if (!$$cl->{"euid"}) { 3.269 + $$cl->{"class"}.="_root"; 3.270 + } 3.271 + 3.272 +#tab# my @tab_words=split /\s+/, $$cl->{"output"}; 3.273 +#tab# my $last_word= $$cl->{"cline"} =~ /(\S*)$/; 3.274 +#tab# $last_word =~ s@.*/@@; 3.275 +#tab# my $this_is_tab=1; 3.276 +#tab# 3.277 +#tab# if ($last_word && @tab_words >2) { 3.278 +#tab# for my $tab_words (@tab_words) { 3.279 +#tab# if ($tab_words !~ /^$last_word/) { 3.280 +#tab# $this_is_tab=0; 3.281 +#tab# last; 3.282 +#tab# } 3.283 +#tab# } 3.284 +#tab# } 3.285 +#tab# $$cl->{"class"}="tab" if $this_is_tab; 3.286 + 3.287 + 3.288 +# if ( !$$cl->{"err"}) { 3.289 +# # Command does not contain mistakes 3.290 +# 3.291 +# my %commands = extract_from_cline("commands", ${$cl}->{"cline"}); 3.292 +# my %files = extract_from_cline("files", ${$cl}->{"cline"}); 3.293 +# 3.294 +# # Searching for new commands only 3.295 +# for my $command (keys %commands) { 3.296 +# if (!defined $Commands_Stat{$command}) { 3.297 +# push @{$$cl->{new_commands}}, $command; 3.298 +# } 3.299 +# $Commands_Stat{$command}++; 3.300 +# } 3.301 +# 3.302 +# for my $file (keys %files) { 3.303 +# if (!defined $Files_Stat{$file}) { 3.304 +# push @{$$cl->{new_files}}, $file; 3.305 +# } 3.306 +# $Files_Stat{$file}++; 3.307 +# } 3.308 +# } 3.309 + 3.310 + if ($$cl->{cline}=~ m@cat[^#]*#([\^=v])\s*(.*)@) { 3.311 + if ($1 eq "=") { 3.312 + $$cl->{"class"} = "note"; 3.313 + $$cl->{"note"} = $$cl->{"output"}; 3.314 + $$cl->{"note_title"} = $2; 3.315 + } 3.316 + else { 3.317 + my $j = $i; 3.318 + if ($1 eq "^") { 3.319 + $j--; 3.320 + $j-- while ($j >=0 && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 3.321 + } 3.322 + elsif ($1 eq "v") { 3.323 + $j++; 3.324 + $j++ while ($j <= @Command_Lines && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 3.325 + } 3.326 + $Command_Lines[$j]->{note_title}="$2"; 3.327 + $Command_Lines[$j]->{note}=$$cl->{output}; 3.328 + $$cl=0; 3.329 + } 3.330 + } 3.331 + elsif ($$cl->{cline}=~ /#([\^=v])(.*)/) { 3.332 + if ($1 eq "=") { 3.333 + $$cl->{"class"} = "note"; 3.334 + $$cl->{"note"} = $2; 3.335 + } 3.336 + else { 3.337 + my $j=$i; 3.338 + if ($1 eq "^") { 3.339 + $j--; 3.340 + $j-- while ($j >=0 && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); 3.341 + } 3.342 + elsif ($1 eq "v") { 3.343 + $j++; 3.344 + $j++ while ($j <= @Command_Lines && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); 3.345 + } 3.346 + $Command_Lines[$j]->{note}="$2"; 3.347 + $$cl=0; 3.348 + } 3.349 + } 3.350 + } 3.351 + 3.352 +} 3.353 + 3.354 + 3.355 =cut 3.356 Процедура print_command_lines выводит HTML-представление 3.357 разобранного lab-скрипта. 3.358 @@ -152,7 +362,8 @@ 3.359 # Результат выполнения процедуры равен 3.360 # join("", @Result{header,body,stat,help,about,footer}) 3.361 my %Result; 3.362 - my $toc =""; # Хранит оглавление по дням 3.363 + my @toc; # Хранит оглавление 3.364 + my $note_number=0; 3.365 3.366 $Result{"body"} = "<table width='100%'>\n"; 3.367 3.368 @@ -161,7 +372,12 @@ 3.369 my $last_day=""; 3.370 my $in_range=0; 3.371 3.372 - for my $cl (@Command_Lines) { 3.373 + my $i=0; 3.374 + for my $k (@Command_Lines_Index) { 3.375 + 3.376 + my $cl=$Command_Lines[$Command_Lines_Index[$i++]]; 3.377 + 3.378 + next unless $cl; 3.379 3.380 if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { 3.381 $in_range=1; 3.382 @@ -182,6 +398,20 @@ 3.383 #my @new_commands=@{$cl->{"new_commands"}}; 3.384 #my @new_files=@{$cl->{"new_files"}}; 3.385 3.386 + if ($cl->{class} eq "note") { 3.387 + my $note = $cl->{note}; 3.388 + $note = join ("\n", map ("<p>$_</p>", split (/-\n/, $note))); 3.389 + $Result{"body"} .= "<tr><td colspan='6'>"; 3.390 + $Result{"body"} .= "<h4 id='note$note_number'>".$cl->{note_title}."</h4>" if $cl->{note_title}; 3.391 + $Result{"body"} .= "".$note."<p/><p/></td></td>"; 3.392 + 3.393 + if ($cl->{note_title}) { 3.394 + push @{$toc[@toc]},"<a href='#note$note_number'>".$cl->{note_title}."</a>"; 3.395 + $note_number++; 3.396 + } 3.397 + next; 3.398 + } 3.399 + 3.400 my $cl_class="cline"; 3.401 my $out_class="output"; 3.402 if ($cl->{"class"}) { 3.403 @@ -233,6 +463,14 @@ 3.404 # <command> 3.405 3.406 my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); 3.407 + $Stat{FirstCommand} = $cl->{time} unless $Stat{FirstCommand}; 3.408 + $Stat{LastCommand} = 0 unless defined $Stat{LastCommand}; 3.409 + $Stat{TotalTime} += $cl->{time} - $Stat{LastCommand} 3.410 + if $cl->{time} - $Stat{LastCommand} < $Config{stat_inactivity_interval}; 3.411 + $Stat{LastCommand} = $cl->{time}; 3.412 + $Stat{TotalCommands} = 0 unless $Stat{TotalCommands}; 3.413 + $Stat{TotalCommands}++; 3.414 + 3.415 # Добавляем спереди 0 для удобочитаемости 3.416 $min = "0".$min if $min =~ /^.$/; 3.417 $hour = "0".$hour if $hour =~ /^.$/; 3.418 @@ -241,6 +479,8 @@ 3.419 $class=$cl->{"out_class"}; 3.420 $class =~ s/output$//; 3.421 3.422 + $Stat{ErrorCommands}++ 3.423 + if $class =~ /wrong/; 3.424 3.425 $Result{"body"} .= "<tr class='command'>\n"; 3.426 3.427 @@ -249,7 +489,7 @@ 3.428 if ( $last_day ne $day) { 3.429 #$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>"; 3.430 $Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>"; 3.431 - $toc .= "<li><a href='#day$day'>".$Day_Name[$wday]."</a></li>\n"; 3.432 + push @toc, "<a href='#day$day'>".$Day_Name[$wday]."</a>\n"; 3.433 $last_day=$day; 3.434 } 3.435 3.436 @@ -271,9 +511,12 @@ 3.437 # COMMAND 3.438 $Result{"body"} .= "<td class='script'>\n"; 3.439 $Result{"body"} .= "<pre class='${class}cline'>\n"; 3.440 - my $cline = $cl->{"cline"}; 3.441 + my $cline = $cl->{"prompt"}.$cl->{"cline"}; 3.442 $cline =~ s/\n//; 3.443 - $Result{"body"} .= $cl->{"prompt"}.$cl->{"cline"}; 3.444 + my $hint = make_comment($cl->{"cline"}); 3.445 + # join(" ",@new_commands), join (" ",@new_files)); 3.446 + $cline = "<div title='$hint'>$cline</div>" if $hint; 3.447 + $Result{"body"} .= $cline; 3.448 $Result{"body"} .= "</pre>\n"; 3.449 3.450 my $last_command = $cl->{"last_command"}; 3.451 @@ -294,10 +537,22 @@ 3.452 $Result{"body"} .= $cl->{"diff"}; 3.453 $Result{"body"} .= "</pre></td></tr></table>"; 3.454 } 3.455 + 3.456 + #NOTES 3.457 + if ( $Config{"show_notes"} =~ /^y/i && $cl->{"note"}) { 3.458 + my $note=$cl->{"note"}; 3.459 + $note =~ s/\n/<br\/>\n/msg; 3.460 + # Ширину пока не используем 3.461 + # $Result{"body"} .= "<table width='$Config{note_width}' class='note'>"; 3.462 + $Result{"body"} .= "<table class='note'>"; 3.463 + $Result{"body"} .= "<tr><td class='note_title'>".$cl->{note_title}."</td></tr>" if $cl->{note_title}; 3.464 + $Result{"body"} .= "<tr><td width='100%' class='note_text'>".$note."</td></tr>"; 3.465 + $Result{"body"} .= "</table>\n"; 3.466 + } 3.467 3.468 # COMMENT 3.469 if ( $Config{"show_comments"} =~ /^y/i) { 3.470 - my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files)); 3.471 + my $comment = make_comment($cl->{"cline"}); 3.472 if ($comment) { 3.473 $Result{"body"} .= "<table width='$Config{comment_width}'>". 3.474 "<tr><td width='5'/><td>"; 3.475 @@ -315,18 +570,100 @@ 3.476 3.477 $Result{"body"} .= "</table>\n"; 3.478 3.479 - $Result{"stat"} = "<hr/>"; 3.480 + #$Result{"stat"} = "<hr/>"; 3.481 + 3.482 + %StatNames = ( 3.483 + FirstCommand => "Время первой команды журнала", 3.484 + LastCommand => "Время последней команды журнала", 3.485 + TotalCommands => "Количество командных строк в журнале", 3.486 + ErrorsPercentage => "Процент команд с кодом ненулевым кодом завершения, %", 3.487 + TotalTime => "Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час", 3.488 + CommandsPerTime => "Количество командных строк в единицу времени, команда/мин", 3.489 + CommandsFDistribution => "Частота использования команд", 3.490 + CommandsFDistribution => "Частота использования команд", 3.491 + RareCommands => "Частота использования этих команд < 0.5%", 3.492 + ); 3.493 + @StatOrder = ( 3.494 + FirstCommand, 3.495 + LastCommand, 3.496 + TotalCommands, 3.497 + ErrorsPercentage, 3.498 + TotalTime, 3.499 + CommandsPerTime, 3.500 + CommandsFDistribution, 3.501 + RareCommands, 3.502 + ); 3.503 + 3.504 + # Подготовка статистики к выводу 3.505 + # Некоторые значения пересчитываются! 3.506 + # Дальше их лучше уже не использовать!!! 3.507 + 3.508 + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{FirstCommand}); 3.509 + $Stat{FirstCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; 3.510 + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{LastCommand}); 3.511 + $Stat{LastCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec, $year+1900, $mon+1, $mday; 3.512 + $Stat{ErrorsPercentage} = sprintf "%5.2f", $Stat{ErrorCommands}*100/$Stat{TotalCommands} 3.513 + if $Stat{TotalCommands}; 3.514 + $Stat{CommandsPerTime} = sprintf "%5.2f", $Stat{TotalCommands}*60/$Stat{TotalTime} 3.515 + if $Stat{TotalTime}; 3.516 + $Stat{TotalTime} = sprintf "%5.2f", $Stat{TotalTime}/60/24; 3.517 + 3.518 + my $total_commands=0; 3.519 + for $command (keys %CommandsFDistribution){ 3.520 + $total_commands += $CommandsFDistribution{$command}; 3.521 + } 3.522 + if ($total_commands) { 3.523 + for $command (reverse sort {$CommandsFDistribution{$a} <=> $CommandsFDistribution{$b}} keys %CommandsFDistribution){ 3.524 + my $percentage = sprintf "%5.2f",$CommandsFDistribution{$command}*100/$total_commands; 3.525 + if ($percentage < 0.5) { 3.526 + my $hint = make_comment($command); 3.527 + my $command_html = "$command"; 3.528 + $command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; 3.529 + my $command_html = "<tt>$command_html</tt>"; 3.530 + $Stat{RareCommands} .= $command_html."<sub><font size='-2'>".$CommandsFDistribution{$command}."</font></sub> , "; 3.531 + } 3.532 + else { 3.533 + my $hint = make_comment($command); 3.534 + my $command_html = "$command"; 3.535 + $command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; 3.536 + my $command_html = "<tt>$command_html</tt>"; 3.537 + $percentage = sprintf "%5.2f",$percentage; 3.538 + $Stat{CommandsFDistribution} .= "<tr><td>".$command_html."</td><td>".$CommandsFDistribution{$command}."</td>". 3.539 + "<td>|".("="x int($CommandsFDistribution{$command}*100/$total_commands))."| $percentage%</td></tr>"; 3.540 + } 3.541 + } 3.542 + $Stat{CommandsFDistribution} = "<table>".$Stat{CommandsFDistribution}."</table>"; 3.543 + $Stat{RareCommands} =~ s/, $//; 3.544 + } 3.545 + 3.546 $Result{"stat"} .= "<h2 id='stat'>Статистика</h2>"; 3.547 - $Result{"stat"} .= "Статистическая информация о журнале<br/>"; 3.548 - $Result{"help"} .= "<hr/>"; 3.549 + $Result{"stat"} .= "<table>"; 3.550 + for my $stat (@StatOrder) { 3.551 + $Result{"stat"} .= "<tr valign='top'><td width='300'>".$StatNames{"$stat"}."</td><td>".$Stat{"$stat"}."</td></tr>"; 3.552 + } 3.553 + 3.554 + $Result{"stat"} .= "</table>"; 3.555 + $Result{"stat"} .= "<font size='-2'>____<br/>*) Интервалы неактивности длительностью ".($Config{stat_inactivity_interval}/60)." минут и более не учитываются</font></br>"; 3.556 + 3.557 + #$Result{"help"} .= "<hr/>"; 3.558 $Result{"help"} .= "<h2 id='help'>Справка</h2>"; 3.559 $Result{"help"} .= "$Html_Help<br/>"; 3.560 - $Result{"about"} .= "<hr/>"; 3.561 + #$Result{"about"} .= "<hr/>"; 3.562 $Result{"about"} .= "<h2 id='about'>О программе</h2>"; 3.563 $Result{"about"} .= "$Html_About"; 3.564 $Result{"footer"} .= "</body>\n"; 3.565 $Result{"footer"} .= "</html>\n"; 3.566 3.567 + $Result{"title"} = "Журнал лабораторных работ"; 3.568 + $Result{"title"}.= " -- ".$course_student if $course_student; 3.569 + if ($course_date) { 3.570 + $Result{"title"}.= " -- ".$course_date; 3.571 + $Result{"title"}.= "/".$course_code if $course_code; 3.572 + } 3.573 + else { 3.574 + $Result{"title"}.= " -- ".$course_code if $course_code; 3.575 + } 3.576 + 3.577 # Заголовок генерируется позже всего 3.578 # Тогда, когда известно уже, что должно быть написано в 3.579 # оглавлении 3.580 @@ -335,21 +672,27 @@ 3.581 <head> 3.582 <meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> 3.583 <link rel='stylesheet' href='$Config{frontend_css}' type='text/css'/> 3.584 + <title>$Result{title}</title> 3.585 </head> 3.586 <body> 3.587 <script> 3.588 $Html_JavaScript 3.589 </script> 3.590 - <h2>Журнал лабораторных работ</h2> 3.591 + <h1>Журнал лабораторных работ</h1> 3.592 3.593 - <p> 3.594 - Выполнил $course_student<br/> 3.595 - Проверил $course_trainer <br/> 3.596 - Курс $course_name ($course_code), 3.597 - $course_date<br/> 3.598 - Учебный центр $course_center <br/> 3.599 - </p> 3.600 +HEADER 3.601 + $Result{"header"} .= "<p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; 3.602 + $Result{"header"} .= "Выполнил $course_student<br/>" if $course_student; 3.603 + $Result{"header"} .= "Проверил $course_trainer <br/>" if $course_trainer; 3.604 + $Result{"header"} .= "Курс " if $course_name || $course_code || $course_date; 3.605 + $Result{"header"} .= "$course_name " if $course_name; 3.606 + $Result{"header"} .= "($course_code)" if $course_code; 3.607 + $Result{"header"} .= ", $course_date<br/>" if $course_date; 3.608 + $Result{"header"} .= "Учебный центр $course_center <br/>" if $course_center; 3.609 + $Result{"header"} .= "</p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; 3.610 3.611 + my $toc = collapse_list (\@toc); 3.612 + $Result{"header"} .= <<HEADER; 3.613 <ul> 3.614 <li><a href='#log'>Журнал</a></li> 3.615 <ul>$toc</ul> 3.616 @@ -360,7 +703,7 @@ 3.617 3.618 <h2 id="log">Журнал</h2> 3.619 HEADER 3.620 - $Result{"header"} .= "<table class='visibility_form'><tr><td><form>\n"; 3.621 + $Result{"header"} .= "<table id='visibility_form' class='visibility_form'><tr><td><form>\n"; 3.622 for my $element (keys %Elements_Visibility) 3.623 { 3.624 my @e = split /\s+/, $element; 3.625 @@ -385,13 +728,205 @@ 3.626 3.627 3.628 3.629 +sub collapse_list($) 3.630 +{ 3.631 + my $res = ""; 3.632 + for my $elem (@{$_[0]}) { 3.633 + if (ref $elem eq "ARRAY") { 3.634 + $res .= "<ul>".collapse_list($elem)."</ul>"; 3.635 + } 3.636 + else 3.637 + { 3.638 + $res .= "<li>".$elem."</li>"; 3.639 + } 3.640 + } 3.641 + return $res; 3.642 +} 3.643 + 3.644 3.645 3.646 3.647 sub init_variables 3.648 { 3.649 $Html_Help = <<HELP; 3.650 - Справка по использованию журнала 3.651 + Для того чтобы использовать LiLaLo, не нужно знать ничего особенного: 3.652 + всё происходит само собой. 3.653 + Однако, чтобы ведение и последующее использование журналов 3.654 + было как можно более эффективным, желательно иметь в виду следующее: 3.655 + <ul> 3.656 + <li><p> 3.657 + В журнал автоматически попадают все команды, данные в любом терминале системы. 3.658 + </p></li> 3.659 + <li><p> 3.660 + Для того чтобы убедиться, что журнал на текущем терминале ведётся, 3.661 + и команды записываются, дайте команду w. 3.662 + В поле WHAT, соответствующем текущему терминалу, 3.663 + должна быть указана программа script. 3.664 + </p></li> 3.665 + <li><p> 3.666 + Команды, код завершения которых отличен от нуля, выделяются цветом. 3.667 + Если код завершения команды равен нулю, 3.668 + команда была выполнена без ошибок. 3.669 +<table> 3.670 +<tr class='command'> 3.671 +<td class='script'> 3.672 +<pre class='wrong_cline'> 3.673 +\$ l s-l</pre> 3.674 +<pre class='wrong_output'>bash: l: command not found 3.675 +</pre> 3.676 +</td> 3.677 +</tr> 3.678 +</table> 3.679 +<br/> 3.680 + </p></li> 3.681 + <li><p> 3.682 + Команды, ход выполнения которых был прерван пользователем, выделяются цветом. 3.683 +<table> 3.684 +<tr class='command'> 3.685 +<td class='script'> 3.686 +<pre class='interrupted_cline'> 3.687 +\$ find / -name abc</pre> 3.688 +<pre class='interrupted_output'>find: /home/devi-orig/.gnome2: Keine Berechtigung 3.689 +find: /home/devi-orig/.gnome2_private: Keine Berechtigung 3.690 +find: /home/devi-orig/.nautilus/metafiles: Keine Berechtigung 3.691 +find: /home/devi-orig/.metacity: Keine Berechtigung 3.692 +find: /home/devi-orig/.inkscape: Keine Berechtigung 3.693 +^C 3.694 +</pre> 3.695 +</td> 3.696 +</tr> 3.697 +</table> 3.698 +<br/> 3.699 + </p></li> 3.700 + <li><p> 3.701 + Команды, выполненные с привилегиями суперпользователя, 3.702 + выделяются слева красной чертой. 3.703 +<table> 3.704 +<tr class='command'> 3.705 +<td class='script'> 3.706 +<pre class='_root_cline'> 3.707 +# id</pre> 3.708 +<pre class='_root_output'> 3.709 +uid=0(root) gid=0(root) Gruppen=0(root) 3.710 +</pre> 3.711 +</td> 3.712 +</tr> 3.713 +</table> 3.714 + <br/> 3.715 + </p></li> 3.716 + <li><p> 3.717 + Изменения, внесённые в текстовый файл с помощью редактора, 3.718 + запоминаются и показываются в журнале в формате ed. 3.719 + Строки, начинающиеся символом "<", удалены, а строки, 3.720 + начинающиеся символом ">" -- добавлены. 3.721 +<table> 3.722 +<tr class='command'> 3.723 +<td class='script'> 3.724 +<pre class='cline'> 3.725 +\$ vi ~/.bashrc</pre> 3.726 +<table><tr><td width='5'/><td class='diff'><pre>2a3,5 3.727 +> if [ -f /usr/local/etc/bash_completion ]; then 3.728 +> . /usr/local/etc/bash_completion 3.729 +> fi 3.730 +</pre></td></tr></table></td> 3.731 +</tr> 3.732 +</table> 3.733 + <br/> 3.734 + </p></li> 3.735 + <li><p> 3.736 + Для того чтобы получить краткую справочную информацию о команде, 3.737 + нужно подвести к ней мышь. Во всплывающей подсказке появится краткое 3.738 + описание команды. 3.739 + </p></li> 3.740 + <li><p> 3.741 + Время ввода команды, показанное в журнале, соответствует времени 3.742 + <i>начала ввода командной строки</i>, которое равно тому моменту, 3.743 + когда на терминале появилось приглашение интерпретатора 3.744 + </p></li> 3.745 + <li><p> 3.746 + Имя терминала, на котором была введена команда, показано в специальном блоке. 3.747 + Этот блок показывается только в том случае, если терминал 3.748 + текущей команды отличается от терминала предыдущей. 3.749 + </p></li> 3.750 + <li><p> 3.751 + Вывод не интересующих вас в настоящий момент элементов журнала, 3.752 + таких как время, имя терминала и других, можно отключить. 3.753 + Для этого нужно воспользоваться <a href='#visibility_form'>формой управления журналом</a> 3.754 + вверху страницы. 3.755 + </p></li> 3.756 + <li><p> 3.757 + Небольшие комментарии к командам можно вставлять прямо из командной строки. 3.758 + Комментарий вводится прямо в командную строку, после символов #^ или #v. 3.759 + Символы ^ и v показывают направление выбора команды, к которой относится комментарий: 3.760 + ^ - к предыдущей, v - к следующей. 3.761 + Например, если в командной строке было введено: 3.762 +<pre class='cline'> 3.763 +\$ whoami 3.764 +</pre> 3.765 +<pre class='output'> 3.766 +user 3.767 +</pre> 3.768 +<pre class='cline'> 3.769 +\$ #^ Интересно, кто я? 3.770 +</pre> 3.771 + в журнале это будет выглядеть так: 3.772 + 3.773 +<pre class='cline'> 3.774 +\$ whoami 3.775 +</pre> 3.776 +<pre class='output'> 3.777 +user 3.778 +</pre> 3.779 +<table class='note'><tr><td width='100%' class='note_text'> 3.780 +<tr> <td> Интересно, кто я?<br/> </td></tr></table> 3.781 + </p></li> 3.782 + <li><p> 3.783 + Если комментарий содержит несколько строк, 3.784 + его можно вставить в журнал следующим образом: 3.785 +<pre class='cline'> 3.786 +\$ whoami 3.787 +</pre> 3.788 +<pre class='output'> 3.789 +user 3.790 +</pre> 3.791 +<pre class='cline'> 3.792 +\$ cat > /dev/null #^ Интересно, кто я? 3.793 +</pre> 3.794 +<pre class='output'> 3.795 +Программа whoami выводит имя пользователя, под которым 3.796 +мы зарегистрировались в системе. 3.797 +- 3.798 +Она не может ответить на вопрос о нашем назначении 3.799 +в этом мире. 3.800 +</pre> 3.801 + В журнале это будет выглядеть так: 3.802 +<table> 3.803 +<tr class='command'> 3.804 +<td class='script'> 3.805 +<pre class='cline'> 3.806 +\$ whoami</pre> 3.807 +<pre class='output'>user 3.808 +</pre> 3.809 +<table class='note'><tr><td class='note_title'>Интересно, кто я?</td></tr><tr><td width='100%' class='note_text'> 3.810 +Программа whoami выводит имя пользователя, под которым<br/> 3.811 +мы зарегистрировались в системе.<br/> 3.812 +<br/> 3.813 +Она не может ответить на вопрос о нашем назначении<br/> 3.814 +в этом мире.<br/> 3.815 +</td></tr></table> 3.816 +</td> 3.817 +</tr> 3.818 +</table> 3.819 + Для разделения нескольких абзацев между собой 3.820 + используйте символ "-", один в строке. 3.821 + <br/> 3.822 +</p></li> 3.823 + <li><p> 3.824 + Комментарии, не относящиеся непосредственно ни к какой из команд, 3.825 + добавляются точно таким же способом, только вместо симолов #^ или #v 3.826 + нужно использовать символы #= 3.827 + </p></li> 3.828 +</ul> 3.829 HELP 3.830 3.831 $Html_About = <<ABOUT;
4.1 --- a/l3config.pm Tue Nov 08 12:16:20 2005 +0200 4.2 +++ b/l3config.pm Fri Nov 11 21:29:49 2005 +0200 4.3 @@ -22,18 +22,19 @@ 4.4 "suppress_pagers" => "yes", 4.5 "suppress_terminal" => "yes", 4.6 4.7 - "terminal_width" => 100, 4.8 + "terminal_width" => 400, 4.9 "terminal_height" => 100, 4.10 "verbose" => "yes", 4.11 4.12 "head_lines" => 5, 4.13 "tail_lines" => 5, 4.14 - "cache_head_lines" => 5, 4.15 - "cache_tail_lines" => 5, 4.16 + "cache_head_lines" => 50, 4.17 + "cache_tail_lines" => 50, 4.18 "skip_text" => "...", 4.19 "show_time" => "yes", 4.20 "show_diffs" => "yes", 4.21 "show_comments" => "yes", 4.22 + "show_notes" => "yes", 4.23 4.24 "input" => "/root/.labmaker", 4.25 "diffs" => "", 4.26 @@ -54,6 +55,11 @@ 4.27 "frontend_opennet_ico" => "/l3/opennet.ico", 4.28 "frontend_local_ico" => "/l3/freebsd.ico", 4.29 4.30 + "mywi_server" => "127.0.0.1", 4.31 + "mywi_port" => "19800", 4.32 + 4.33 + "stat_inactivity_interval" => "1800", 4.34 + 4.35 "signature" => "#lm:", 4.36 "from" => "", 4.37 "to" => "", 4.38 @@ -62,6 +68,7 @@ 4.39 "files_keywords" => "linux file", 4.40 4.41 comment_width => "300", 4.42 + note_width => "500", 4.43 time_width => "60", 4.44 4.45 "mode" => "daemon", # daemon | normal