| rev | line source | 
| devi@23 | 1 #!/usr/bin/perl -w | 
| devi@23 | 2 | 
| devi@31 | 3 use IO::Socket; | 
| devi@23 | 4 use lib '.'; | 
| devi@23 | 5 use l3config; | 
| devi@31 | 6 use locale; | 
| devi@23 | 7 | 
| devi@23 | 8 our @Command_Lines; | 
| devi@31 | 9 our @Command_Lines_Index; | 
| devi@31 | 10 our %Commands_Description; | 
| devi@31 | 11 our %Args_Description; | 
| devi@31 | 12 our $Mywi_Socket; | 
| devi@32 | 13 our %Sessions; | 
| devi@23 | 14 | 
| devi@23 | 15 # vvv Инициализация переменных выполняется процедурой init_variables | 
| devi@23 | 16 our @Day_Name; | 
| devi@23 | 17 our @Month_Name; | 
| devi@23 | 18 our @Of_Month_Name; | 
| devi@23 | 19 our %Search_Machines; | 
| devi@23 | 20 our %Elements_Visibility; | 
| devi@23 | 21 # ^^^ | 
| devi@23 | 22 | 
| devi@31 | 23 our %Stat; | 
| devi@31 | 24 our %CommandsFDistribution;	# Сколько раз в журнале встречается какая команда | 
| devi@31 | 25 | 
| devi@23 | 26 sub search_buy; | 
| devi@23 | 27 sub make_comment; | 
| devi@23 | 28 sub load_command_lines_from_xml; | 
| devi@32 | 29 sub load_sessions_from_xml; | 
| devi@23 | 30 sub print_command_lines; | 
| devi@31 | 31 sub sort_command_lines; | 
| devi@31 | 32 sub process_command_lines; | 
| devi@23 | 33 sub init_variables; | 
| devi@23 | 34 sub main; | 
| devi@31 | 35 sub collapse_list($); | 
| devi@23 | 36 | 
| devi@23 | 37 main(); | 
| devi@23 | 38 | 
| devi@23 | 39 sub main | 
| devi@23 | 40 { | 
| devi@23 | 41 	$| = 1; | 
| devi@23 | 42 | 
| devi@23 | 43 	init_variables(); | 
| devi@23 | 44 	init_config(); | 
| devi@23 | 45 | 
| devi@32 | 46 	open_mywi_socket(); | 
| devi@27 | 47 	load_command_lines_from_xml($Config{"backend_datafile"}); | 
| devi@32 | 48 	load_sessions_from_xml($Config{"backend_datafile"}); | 
| devi@31 | 49 	sort_command_lines; | 
| devi@31 | 50 	process_command_lines; | 
| devi@23 | 51 	print_command_lines($Config{"output"}); | 
| devi@31 | 52 	close_mywi_socket; | 
| devi@23 | 53 } | 
| devi@23 | 54 | 
| devi@23 | 55 | 
| devi@23 | 56 sub search_by | 
| devi@23 | 57 { | 
| devi@23 | 58 	my $sm = shift; | 
| devi@23 | 59 	my $topic = shift; | 
| devi@23 | 60 	$topic =~ s/ /+/; | 
| devi@23 | 61 | 
| devi@23 | 62 	return "<a href='".	$Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='". | 
| devi@23 | 63 				$Search_Machines{$sm}->{"icon"}."' border='0'/></a>"; | 
| devi@23 | 64 } | 
| devi@23 | 65 | 
| devi@31 | 66 sub extract_from_cline | 
| devi@31 | 67 # Разобрать командную строку $_[1] и возвратить хэш, содержащий | 
| devi@31 | 68 # номер первого появление команды в строке: | 
| devi@31 | 69 # 	команда => первая позиция | 
| devi@31 | 70 { | 
| devi@31 | 71 	my $what = $_[0]; | 
| devi@31 | 72 	my $cline = $_[1]; | 
| devi@31 | 73 	my @lists = split /\;/, $cline; | 
| devi@31 | 74 | 
| devi@31 | 75 | 
| devi@31 | 76 	my @commands = (); | 
| devi@31 | 77 	for my $list (@lists) { | 
| devi@31 | 78 		push @commands, split /\|/, $list; | 
| devi@31 | 79 	} | 
| devi@31 | 80 | 
| devi@31 | 81 	my %commands; | 
| devi@31 | 82 	my %args; | 
| devi@31 | 83 	my $i=0; | 
| devi@31 | 84 	for my $command (@commands) { | 
| devi@31 | 85 		$command =~ s@^\s*\S+/@@; | 
| devi@31 | 86 		$command =~ /\s*(\S+)\s*(.*)/; | 
| devi@31 | 87 		if ($1 && $1 eq "sudo" ) { | 
| devi@31 | 88 			$commands{"$1"}=$i++; | 
| devi@31 | 89 			$command =~ s/\s*sudo\s+//; | 
| devi@31 | 90 		} | 
| devi@31 | 91 		$command =~ s@^\s*\S+/@@; | 
| devi@31 | 92 		$command =~ /\s*(\S+)\s*(.*)/; | 
| devi@31 | 93 		if ($1 && !defined $commands{"$1"}) { | 
| devi@31 | 94 				$commands{"$1"}=$i++; | 
| devi@31 | 95 		}; | 
| devi@31 | 96 		if ($2) { | 
| devi@31 | 97 			my $args = $2; | 
| devi@31 | 98 			my @args = split (/\s+/, $args); | 
| devi@31 | 99 			for my $a (@args) { | 
| devi@31 | 100 				$args{"$a"}=$i++ | 
| devi@31 | 101 					if !defined $args{"$a"}; | 
| devi@31 | 102 			}; | 
| devi@31 | 103 | 
| devi@31 | 104 | 
| devi@31 | 105 		} | 
| devi@31 | 106 	} | 
| devi@31 | 107 | 
| devi@31 | 108 	if ($what eq "commands") { | 
| devi@31 | 109 		return \%commands; | 
| devi@31 | 110 	} else { | 
| devi@31 | 111 		return \%args; | 
| devi@31 | 112 	} | 
| devi@31 | 113 | 
| devi@31 | 114 } | 
| devi@31 | 115 | 
| devi@31 | 116 sub open_mywi_socket | 
| devi@31 | 117 { | 
| devi@31 | 118 	$Mywi_Socket = IO::Socket::INET->new( | 
| devi@31 | 119 				PeerAddr => $Config{mywi_server}, | 
| devi@31 | 120 				PeerPort => $Config{mywi_port}, | 
| devi@31 | 121 				Proto	 => "tcp", | 
| devi@31 | 122 				Type	 => SOCK_STREAM); | 
| devi@31 | 123 } | 
| devi@31 | 124 | 
| devi@31 | 125 sub close_mywi_socket | 
| devi@31 | 126 { | 
| devi@31 | 127 	close ($Mywi_Socket); | 
| devi@31 | 128 } | 
| devi@31 | 129 | 
| devi@31 | 130 | 
| devi@31 | 131 sub mywi_client | 
| devi@31 | 132 { | 
| devi@31 | 133 	my $query = $_[0]; | 
| devi@31 | 134 	my $mywi; | 
| devi@31 | 135 | 
| devi@31 | 136 	open_mywi_socket; | 
| devi@31 | 137 	if ($Mywi_Socket) { | 
| devi@31 | 138 		local $| = 1; | 
| devi@31 | 139 		local $/ = ""; | 
| devi@31 | 140 		print $Mywi_Socket $query."\n"; | 
| devi@31 | 141 		$mywi = <$Mywi_Socket>; | 
| devi@31 | 142 		$mywi = "" if $mywi =~ /nothing app/; | 
| devi@31 | 143 	} | 
| devi@31 | 144 	close_mywi_socket; | 
| devi@31 | 145 	return $mywi; | 
| devi@31 | 146 } | 
| devi@31 | 147 | 
| devi@23 | 148 sub make_comment | 
| devi@23 | 149 { | 
| devi@31 | 150 	my $cline = $_[0]; | 
| devi@31 | 151 	#my $files = $_[1]; | 
| devi@23 | 152 | 
| devi@31 | 153 	my @comments=(); | 
| devi@31 | 154 	my @commands = keys %{extract_from_cline("commands", $cline)}; | 
| devi@31 | 155 	my @args = keys %{extract_from_cline("args", $cline)}; | 
| devi@31 | 156 	return if (!@commands && !@args); | 
| devi@31 | 157 	#return "commands=".join(" ",@commands)."; files=".join(" ",@files); | 
| devi@23 | 158 | 
| devi@23 | 159 	# Commands | 
| devi@31 | 160 	for my $command (@commands) { | 
| devi@23 | 161 		$command =~ s/'//g; | 
| devi@31 | 162 		$CommandsFDistribution{$command}++; | 
| devi@31 | 163 		if (!$Commands_Description{$command}) { | 
| devi@35 | 164 			my $mywi=""; | 
| devi@31 | 165 			$mywi = mywi_client ($command); | 
| devi@31 | 166 			$mywi = join ("\n", grep(/\([18]\)/, split(/\n/, $mywi))); | 
| devi@31 | 167 			$mywi =~ s/\s+/ /; | 
| devi@31 | 168 			if ($mywi !~ /^\s*$/) { | 
| devi@31 | 169 				$Commands_Description{$command} = $mywi; | 
| devi@31 | 170 			} | 
| devi@31 | 171 			else { | 
| devi@31 | 172 				next; | 
| devi@31 | 173 			} | 
| devi@31 | 174 		} | 
| devi@23 | 175 | 
| devi@31 | 176 		push @comments, $Commands_Description{$command}; | 
| devi@23 | 177 	} | 
| devi@31 | 178 	return join("
\n", @comments); | 
| devi@23 | 179 | 
| devi@23 | 180 	# Files | 
| devi@31 | 181 	for my $arg (@args) { | 
| devi@31 | 182 		$arg =~ s/'//g; | 
| devi@31 | 183 		if (!$Args_Description{$arg}) { | 
| devi@31 | 184 			my $mywi; | 
| devi@31 | 185 			$mywi = mywi_client ($arg); | 
| devi@31 | 186 			$mywi = join ("\n", grep(/\([5]\)/, split(/\n/, $mywi))); | 
| devi@31 | 187 			$mywi =~ s/\s+/ /; | 
| devi@31 | 188 			if ($mywi !~ /^\s*$/) { | 
| devi@31 | 189 				$Args_Description{$arg} = $mywi; | 
| devi@31 | 190 			} | 
| devi@31 | 191 			else { | 
| devi@31 | 192 				next; | 
| devi@31 | 193 			} | 
| devi@31 | 194 		} | 
| devi@23 | 195 | 
| devi@31 | 196 		push @comments, $Args_Description{$arg}; | 
| devi@23 | 197 	} | 
| devi@23 | 198 | 
| devi@23 | 199 } | 
| devi@23 | 200 | 
| devi@23 | 201 =cut | 
| devi@23 | 202 Процедура load_command_lines_from_xml выполняет загрузку разобранного lab-скрипта | 
| devi@23 | 203 из XML-документа в переменную @Command_Lines | 
| devi@23 | 204 | 
| devi@23 | 205 Предупреждение! | 
| devi@23 | 206 Процедура не в состоянии обрабатывать XML-документ любой структуры. | 
| devi@23 | 207 В действительности файл cache из которого загружаются данные | 
| devi@23 | 208 просто напоминает XML с виду. | 
| devi@23 | 209 =cut | 
| devi@23 | 210 sub load_command_lines_from_xml | 
| devi@23 | 211 { | 
| devi@23 | 212 	my $datafile = $_[0]; | 
| devi@23 | 213 | 
| devi@23 | 214 	open (CLASS, $datafile) | 
| devi@23 | 215 		or die "Can't open file of the class ",$datafile,"\n"; | 
| devi@23 | 216 	local $/; | 
| devi@23 | 217 	$data = <CLASS>; | 
| devi@23 | 218 	close(CLASS); | 
| devi@23 | 219 | 
| devi@23 | 220 	for $command ($data =~ m@<command>(.*?)</command>@sg) { | 
| devi@23 | 221 		my %cl; | 
| devi@23 | 222 		while ($command =~ m@<([^>]*?)>(.*?)</\1>@sg) { | 
| devi@23 | 223 			$cl{$1} = $2; | 
| devi@23 | 224 		} | 
| devi@23 | 225 		push @Command_Lines, \%cl; | 
| devi@23 | 226 	} | 
| devi@23 | 227 } | 
| devi@23 | 228 | 
| devi@32 | 229 sub load_sessions_from_xml | 
| devi@32 | 230 { | 
| devi@32 | 231 	my $datafile = $_[0]; | 
| devi@32 | 232 | 
| devi@32 | 233 	open (CLASS, $datafile) | 
| devi@32 | 234 		or die "Can't open file of the class ",$datafile,"\n"; | 
| devi@32 | 235 	local $/; | 
| devi@32 | 236 	my $data = <CLASS>; | 
| devi@32 | 237 	close(CLASS); | 
| devi@32 | 238 | 
| devi@32 | 239 	for my $session ($data =~ m@<session>(.*?)</session>@sg) { | 
| devi@32 | 240 		my %session; | 
| devi@32 | 241 		while ($session =~ m@<([^>]*?)>(.*?)</\1>@sg) { | 
| devi@32 | 242 			$session{$1} = $2; | 
| devi@32 | 243 		} | 
| devi@32 | 244 		$Sessions{$session{local_session_id}} = \%session; | 
| devi@32 | 245 	} | 
| devi@32 | 246 } | 
| devi@32 | 247 | 
| devi@32 | 248 | 
| devi@32 | 249 | 
| devi@31 | 250 sub sort_command_lines | 
| devi@31 | 251 { | 
| devi@31 | 252 	# Sort Command_Lines | 
| devi@31 | 253 	# Write Command_Lines to Command_Lines_Index | 
| devi@31 | 254 | 
| devi@31 | 255 	my @index; | 
| devi@31 | 256 	for (my $i=0;$i<=$#Command_Lines;$i++) { | 
| devi@31 | 257 		$index[$i]=$i; | 
| devi@31 | 258 	} | 
| devi@31 | 259 | 
| devi@31 | 260 	@Command_Lines_Index = sort { | 
| devi@31 | 261 		$Command_Lines[$index[$a]]->{"time"} <=> $Command_Lines[$index[$b]]->{"time"} | 
| devi@31 | 262 	} @index; | 
| devi@31 | 263 | 
| devi@31 | 264 } | 
| devi@31 | 265 | 
| devi@31 | 266 sub process_command_lines | 
| devi@31 | 267 { | 
| devi@31 | 268 	for my $i (@Command_Lines_Index) { | 
| devi@31 | 269 | 
| devi@31 | 270 		my $cl = \$Command_Lines[$i]; | 
| devi@35 | 271 		#@{${$cl}->{"new_commands"}} =(); | 
| devi@35 | 272 		#@{${$cl}->{"new_files"}} =(); | 
| devi@31 | 273 		$$cl->{"class"} = ""; | 
| devi@31 | 274 | 
| devi@31 | 275 		if ($$cl->{"err"}) { | 
| devi@31 | 276 			$$cl->{"class"}="wrong"; | 
| devi@31 | 277 			$$cl->{"class"}="interrupted" | 
| devi@31 | 278 				if ($$cl->{"err"} eq 130); | 
| devi@31 | 279 		} | 
| devi@31 | 280 		if (!$$cl->{"euid"}) { | 
| devi@31 | 281 			$$cl->{"class"}.="_root"; | 
| devi@31 | 282 		} | 
| devi@31 | 283 | 
| devi@31 | 284 #tab#		my @tab_words=split /\s+/, $$cl->{"output"}; | 
| devi@31 | 285 #tab#		my $last_word= $$cl->{"cline"} =~ /(\S*)$/; | 
| devi@31 | 286 #tab#		$last_word =~ s@.*/@@; | 
| devi@31 | 287 #tab#		my $this_is_tab=1; | 
| devi@31 | 288 #tab# | 
| devi@31 | 289 #tab#		if ($last_word && @tab_words >2) { | 
| devi@31 | 290 #tab#			for my $tab_words (@tab_words) { | 
| devi@31 | 291 #tab#				if ($tab_words !~ /^$last_word/) { | 
| devi@31 | 292 #tab#					$this_is_tab=0; | 
| devi@31 | 293 #tab#					last; | 
| devi@31 | 294 #tab#				} | 
| devi@31 | 295 #tab#			} | 
| devi@31 | 296 #tab#		} | 
| devi@31 | 297 #tab#		$$cl->{"class"}="tab" if $this_is_tab; | 
| devi@31 | 298 | 
| devi@31 | 299 | 
| devi@31 | 300 #		if ( !$$cl->{"err"}) { | 
| devi@31 | 301 #			# Command does not contain mistakes | 
| devi@31 | 302 # | 
| devi@31 | 303 #			my %commands = extract_from_cline("commands", ${$cl}->{"cline"}); | 
| devi@31 | 304 #			my %files = extract_from_cline("files", ${$cl}->{"cline"}); | 
| devi@31 | 305 # | 
| devi@31 | 306 #			# Searching for new commands only | 
| devi@31 | 307 #			for my $command (keys  %commands) { | 
| devi@31 | 308 #				if (!defined $Commands_Stat{$command}) { | 
| devi@31 | 309 #					push @{$$cl->{new_commands}}, $command; | 
| devi@31 | 310 #				} | 
| devi@31 | 311 #				$Commands_Stat{$command}++; | 
| devi@31 | 312 #			} | 
| devi@31 | 313 # | 
| devi@31 | 314 #			for my $file (keys  %files) { | 
| devi@31 | 315 #				if (!defined $Files_Stat{$file}) { | 
| devi@31 | 316 #					push @{$$cl->{new_files}}, $file; | 
| devi@31 | 317 #				} | 
| devi@31 | 318 #				$Files_Stat{$file}++; | 
| devi@31 | 319 #			} | 
| devi@31 | 320 #		} | 
| devi@31 | 321 | 
| devi@31 | 322 		if ($$cl->{cline}=~ m@cat[^#]*#([\^=v])\s*(.*)@) { | 
| devi@31 | 323 			if ($1 eq "=") { | 
| devi@31 | 324 				$$cl->{"class"} = "note"; | 
| devi@31 | 325 				$$cl->{"note"} = $$cl->{"output"}; | 
| devi@31 | 326 				$$cl->{"note_title"} = $2; | 
| devi@31 | 327 			} | 
| devi@31 | 328 			else { | 
| devi@31 | 329 				my $j = $i; | 
| devi@31 | 330 				if ($1 eq "^") { | 
| devi@31 | 331 					$j--; | 
| devi@32 | 332 					$j-- while ($j >=0  && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); | 
| devi@31 | 333 				} | 
| devi@31 | 334 				elsif ($1 eq "v") { | 
| devi@31 | 335 					$j++; | 
| devi@32 | 336 					$j++ while ($j <= @Command_Lines  && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); | 
| devi@31 | 337 				} | 
| devi@31 | 338 				$Command_Lines[$j]->{note_title}="$2"; | 
| devi@31 | 339 				$Command_Lines[$j]->{note}=$$cl->{output}; | 
| devi@31 | 340 				$$cl=0; | 
| devi@31 | 341 			} | 
| devi@31 | 342 		} | 
| devi@31 | 343 		elsif ($$cl->{cline}=~ /#([\^=v])(.*)/) { | 
| devi@31 | 344 			if ($1 eq "=") { | 
| devi@31 | 345 				$$cl->{"class"} = "note"; | 
| devi@31 | 346 				$$cl->{"note"} = $2; | 
| devi@31 | 347 			} | 
| devi@31 | 348 			else { | 
| devi@31 | 349 				my $j=$i; | 
| devi@31 | 350 				if ($1 eq "^") { | 
| devi@31 | 351 					$j--; | 
| devi@31 | 352 					$j-- while ($j >=0  && (!$Command_Lines[$j] || $Command_Lines[$j]->{tty} ne $$cl->{tty})); | 
| devi@31 | 353 				} | 
| devi@31 | 354 				elsif ($1 eq "v") { | 
| devi@31 | 355 					$j++; | 
| devi@31 | 356 					$j++ while ($j <= @Command_Lines  && $Command_Lines[$j]->{tty} ne $$cl->{tty} || !$Command_Lines[$j]); | 
| devi@31 | 357 				} | 
| devi@37 | 358 				$Command_Lines[$j]->{note}.="$2\n"; | 
| devi@31 | 359 				$$cl=0; | 
| devi@31 | 360 			} | 
| devi@31 | 361 		} | 
| devi@31 | 362 	} | 
| devi@31 | 363 | 
| devi@31 | 364 } | 
| devi@31 | 365 | 
| devi@31 | 366 | 
| devi@23 | 367 =cut | 
| devi@23 | 368 Процедура print_command_lines выводит HTML-представление | 
| devi@23 | 369 разобранного lab-скрипта. | 
| devi@23 | 370 | 
| devi@23 | 371 Разобранный lab-скрипт должен находиться в массиве @Command_Lines | 
| devi@23 | 372 =cut | 
| devi@23 | 373 | 
| devi@23 | 374 sub print_command_lines | 
| devi@23 | 375 { | 
| devi@23 | 376 	my $output_filename=$_[0]; | 
| devi@23 | 377 | 
| devi@23 | 378 	my $course_name = $Config{"course-name"}; | 
| devi@23 | 379 	my $course_code = $Config{"course-code"}; | 
| devi@23 | 380 	my $course_date = $Config{"course-date"}; | 
| devi@23 | 381 	my $course_center = $Config{"course-center"}; | 
| devi@23 | 382 	my $course_trainer = $Config{"course-trainer"}; | 
| devi@23 | 383 	my $course_student = $Config{"course-student"}; | 
| devi@23 | 384 | 
| devi@23 | 385 | 
| devi@23 | 386 	# Результат выполнения процедуры равен | 
| devi@23 | 387 	# join("", @Result{header,body,stat,help,about,footer}) | 
| devi@23 | 388 	my %Result; | 
| devi@31 | 389 	my @toc;  # Хранит оглавление | 
| devi@31 | 390 	my $note_number=0; | 
| devi@23 | 391 | 
| devi@23 | 392 	$Result{"body"} = "<table width='100%'>\n"; | 
| devi@23 | 393 | 
| devi@23 | 394 	my $cl; | 
| devi@23 | 395 	my $last_tty=""; | 
| devi@23 | 396 	my $last_day=""; | 
| devi@23 | 397 	my $in_range=0; | 
| devi@23 | 398 | 
| devi@31 | 399 	my $i=0; | 
| devi@32 | 400 | 
| devi@32 | 401 COMMAND_LINE: | 
| devi@31 | 402 	for my $k (@Command_Lines_Index) { | 
| devi@31 | 403 | 
| devi@31 | 404 		my $cl=$Command_Lines[$Command_Lines_Index[$i++]]; | 
| devi@31 | 405 | 
| devi@31 | 406 		next unless $cl; | 
| devi@23 | 407 | 
| devi@32 | 408 | 
| devi@32 | 409 		if ($Config{filter}) { | 
| devi@32 | 410 			# Инициализация фильтра | 
| devi@32 | 411 			my %filter; | 
| devi@32 | 412 			for (split /&/,$Config{filter}) { | 
| devi@32 | 413 				my ($var, $val) = split /=/; | 
| devi@32 | 414 				$filter{$var} = $val; | 
| devi@32 | 415 			} | 
| devi@32 | 416 | 
| devi@37 | 417 			for my $filter_key (keys %filter) { | 
| devi@37 | 418 				next COMMAND_LINE unless $Sessions{$cl->{local_session_id}}->{$filter_key} eq $filter{$filter_key}; | 
| devi@32 | 419 			} | 
| devi@32 | 420 | 
| devi@37 | 421 			#if ($filter{user}) { | 
| devi@37 | 422 			#	next COMMAND_LINE unless $Sessions{$cl->{local_session_id}}->{user} eq $filter{user}; | 
| devi@37 | 423 			#} | 
| devi@35 | 424 | 
| devi@32 | 425 			#for my $filter_field (keys %filter) { | 
| devi@32 | 426 			#	next COMMAND_LINE unless $Sessions{$cl->{local_session_id}}->{$filter_field} eq $filter{$filter_field}; | 
| devi@32 | 427 			#} | 
| devi@32 | 428 		} | 
| devi@32 | 429 | 
| devi@23 | 430 		if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) { | 
| devi@23 | 431 			$in_range=1; | 
| devi@23 | 432 			next; | 
| devi@23 | 433 		} | 
| devi@23 | 434 		if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) { | 
| devi@23 | 435 			$in_range=0; | 
| devi@23 | 436 			next; | 
| devi@23 | 437 		} | 
| devi@23 | 438 		next if ($Config{"from"} && $Config{"to"} && !$in_range) | 
| devi@23 | 439 			|| | 
| devi@23 | 440 		    	($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ ) | 
| devi@23 | 441 			|| | 
| devi@23 | 442 			($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0) | 
| devi@23 | 443 			|| | 
| devi@23 | 444 			($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130); | 
| devi@23 | 445 | 
| devi@23 | 446 		#my @new_commands=@{$cl->{"new_commands"}}; | 
| devi@23 | 447 		#my @new_files=@{$cl->{"new_files"}}; | 
| devi@23 | 448 | 
| devi@31 | 449 		if ($cl->{class} eq "note") { | 
| devi@31 | 450 			my $note = $cl->{note}; | 
| devi@31 | 451 			$note = join ("\n", map ("<p>$_</p>", split (/-\n/, $note))); | 
| devi@35 | 452 			$note =~ s@(http:[a-zA-Z.0-9/?%-]*)@<a href='$1'>$1</a>@g; | 
| devi@35 | 453 			$note =~ s@(www\.[a-zA-Z.0-9/?%-]*)@<a href='$1'>$1</a>@g; | 
| devi@31 | 454 			$Result{"body"} .= "<tr><td colspan='6'>"; | 
| devi@31 | 455 			$Result{"body"} .= "<h4 id='note$note_number'>".$cl->{note_title}."</h4>" if $cl->{note_title}; | 
| devi@31 | 456 			$Result{"body"} .= "".$note."<p/><p/></td></td>"; | 
| devi@31 | 457 | 
| devi@31 | 458 			if ($cl->{note_title}) { | 
| devi@31 | 459 				push @{$toc[@toc]},"<a href='#note$note_number'>".$cl->{note_title}."</a>"; | 
| devi@31 | 460 				$note_number++; | 
| devi@31 | 461 			} | 
| devi@31 | 462 			next; | 
| devi@31 | 463 		} | 
| devi@31 | 464 | 
| devi@23 | 465 		my $cl_class="cline"; | 
| devi@23 | 466 		my $out_class="output"; | 
| devi@23 | 467 		if ($cl->{"class"}) { | 
| devi@23 | 468 			$cl_class = $cl->{"class"}."_".$cl_class; | 
| devi@23 | 469 			$out_class = $cl->{"class"}."_".$out_class; | 
| devi@23 | 470 		} | 
| devi@23 | 471 | 
| devi@23 | 472 		my @new_commands; | 
| devi@23 | 473 		my @new_files; | 
| devi@23 | 474 		@new_commands = split (/\s+/, $cl->{"new_commands"}) if defined $cl->{"new_commands"}; | 
| devi@23 | 475 		@new_files = split (/\s+/, $cl->{"new_files"}) if defined $cl->{"new_files"}; | 
| devi@23 | 476 | 
| devi@23 | 477 		my $output=""; | 
| devi@23 | 478 		if ($Config{"head_lines"} || $Config{"tail_lines"}) { | 
| devi@23 | 479 			# Partialy output | 
| devi@23 | 480 			my @lines = split '\n', $cl->{"output"}; | 
| devi@23 | 481 			# head | 
| devi@23 | 482 			my $mark=1; | 
| devi@23 | 483 			for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) { | 
| devi@23 | 484 				$output .= $lines[$i]."\n"; | 
| devi@23 | 485 			} | 
| devi@23 | 486 			# tail | 
| devi@23 | 487 			my $start=$#lines-$Config{"tail_lines"}+1; | 
| devi@23 | 488 			if ($start < 0) { | 
| devi@23 | 489 				$start=0; | 
| devi@23 | 490 				$mark=0; | 
| devi@23 | 491 			} | 
| devi@23 | 492 			if ($start < $Config{"head_lines"}) { | 
| devi@23 | 493 				$start=$Config{"head_lines"}; | 
| devi@23 | 494 				$mark=0; | 
| devi@23 | 495 			} | 
| devi@23 | 496 			$output .= $Config{"skip_text"}."\n" if $mark; | 
| devi@23 | 497 			for (my $i=$start; $i<= $#lines; $i++) { | 
| devi@23 | 498 				$output .= $lines[$i]."\n"; | 
| devi@23 | 499 			} | 
| devi@23 | 500 		} | 
| devi@23 | 501 		else { | 
| devi@23 | 502 			# Full output | 
| devi@23 | 503 			$output .= $cl->{"output"}; | 
| devi@23 | 504 		} | 
| devi@23 | 505 		#$output .= "^C\n" if ($cl->{"err"} eq "130"); | 
| devi@23 | 506 | 
| devi@23 | 507 		# | 
| devi@23 | 508 		## | 
| devi@23 | 509 		## Начинается собственно вывод | 
| devi@23 | 510 		## | 
| devi@23 | 511 		# | 
| devi@23 | 512 | 
| devi@23 | 513 		# <command> | 
| devi@23 | 514 | 
| devi@23 | 515 		my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time}); | 
| devi@38 | 516 		next if $Stat{LastCommand} == $cl->{time}; | 
| devi@31 | 517 		$Stat{FirstCommand} = $cl->{time} unless $Stat{FirstCommand}; | 
| devi@31 | 518 		$Stat{LastCommand} = 0 unless defined $Stat{LastCommand}; | 
| devi@31 | 519 		$Stat{TotalTime} += $cl->{time} - $Stat{LastCommand} | 
| devi@31 | 520 			if $cl->{time} - $Stat{LastCommand} < $Config{stat_inactivity_interval}; | 
| devi@31 | 521 		$Stat{LastCommand} = $cl->{time}; | 
| devi@31 | 522 		$Stat{TotalCommands} = 0 unless $Stat{TotalCommands}; | 
| devi@31 | 523 		$Stat{TotalCommands}++; | 
| devi@31 | 524 | 
| devi@23 | 525 		# Добавляем спереди 0 для удобочитаемости | 
| devi@23 | 526 		$min = "0".$min if $min =~ /^.$/; | 
| devi@23 | 527 		$hour = "0".$hour if $hour =~ /^.$/; | 
| devi@23 | 528 		$sec = "0".$sec if $sec =~ /^.$/; | 
| devi@23 | 529 | 
| devi@23 | 530 		$class=$cl->{"out_class"}; | 
| devi@23 | 531 		$class =~ s/output$//; | 
| devi@23 | 532 | 
| devi@31 | 533 		$Stat{ErrorCommands}++ | 
| devi@31 | 534 			if $class =~ /wrong/; | 
| devi@23 | 535 | 
| devi@23 | 536 		$Result{"body"} .= "<tr class='command'>\n"; | 
| devi@23 | 537 | 
| devi@23 | 538 | 
| devi@23 | 539 		# DAY CHANGE | 
| devi@23 | 540 		if ( $last_day ne $day) { | 
| devi@23 | 541 			#$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>"; | 
| devi@23 | 542 			$Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>"; | 
| devi@31 | 543 			push @toc, "<a href='#day$day'>".$Day_Name[$wday]."</a>\n"; | 
| devi@23 | 544 			$last_day=$day; | 
| devi@23 | 545 		} | 
| devi@23 | 546 | 
| devi@23 | 547 		# CONSOLE CHANGE | 
| devi@23 | 548 		if ( $last_tty ne $cl->{"tty"}) { | 
| devi@32 | 549 			my $host; | 
| devi@32 | 550 			#$host = $Sessions{$cl->{local_session_id}}->{user}."@".$Sessions{$cl->{local_session_id}}->{hostname}; | 
| devi@32 | 551 			$Result{"body"} .= "<td colspan='6'><table><tr><td class='ttychange' width='140' align='center'>".$cl->{"tty"}."</td><td>$host</td></tr></table></td></tr><tr>"; | 
| devi@23 | 552 			$last_tty=$cl->{"tty"}; | 
| devi@23 | 553 		} | 
| devi@23 | 554 | 
| devi@23 | 555 		# TIME | 
| devi@23 | 556 		if ($Config{"show_time"} =~ /^y/i) { | 
| devi@23 | 557 			$Result{"body"} .= "<td valign='top' class='time' width='$Config{time_width}'><pre>". | 
| devi@23 | 558 				$hour. ":". $min. ":". $sec. | 
| devi@23 | 559 				"</td>"; | 
| devi@23 | 560 		} else { | 
| devi@23 | 561 			$Result{"body"} .= "<td width='0'/>" | 
| devi@23 | 562 		} | 
| devi@23 | 563 | 
| devi@23 | 564 		# COMMAND | 
| devi@23 | 565 		$Result{"body"} .= "<td class='script'>\n"; | 
| devi@23 | 566 		$Result{"body"} .= "<pre class='${class}cline'>\n"; | 
| devi@31 | 567 		my $cline = $cl->{"prompt"}.$cl->{"cline"}; | 
| devi@23 | 568 		$cline =~ s/\n//; | 
| devi@32 | 569 | 
| devi@32 | 570 		#$cline .= "(".$Sessions{$cl->{local_session_id}}.")"; | 
| devi@32 | 571 | 
| devi@31 | 572 		my $hint = make_comment($cl->{"cline"}); | 
| devi@31 | 573 		$cline = "<div title='$hint'>$cline</div>" if $hint; | 
| devi@31 | 574 		$Result{"body"} .= $cline; | 
| devi@23 | 575 		$Result{"body"} .= "</pre>\n"; | 
| devi@23 | 576 | 
| devi@23 | 577 		my $last_command = $cl->{"last_command"}; | 
| devi@23 | 578 		if (!( | 
| devi@23 | 579 		$Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) || | 
| devi@23 | 580 		$Config{"suppress_pagers"}  =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) || | 
| devi@23 | 581 		$Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}}) | 
| devi@23 | 582 			)) { | 
| devi@23 | 583 | 
| devi@23 | 584 			$Result{"body"} .= "<pre class='".$cl->{out_class}."'>"; | 
| devi@23 | 585 			$Result{"body"} .= $output; | 
| devi@23 | 586 			$Result{"body"} .= "</pre>\n"; | 
| devi@23 | 587 		} | 
| devi@23 | 588 | 
| devi@23 | 589 		# DIFF | 
| devi@23 | 590 		if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) { | 
| devi@23 | 591 			$Result{"body"} .= "<table><tr><td width='5'/><td class='diff'><pre>"; | 
| devi@23 | 592 			$Result{"body"} .= $cl->{"diff"}; | 
| devi@23 | 593 			$Result{"body"} .= "</pre></td></tr></table>"; | 
| devi@23 | 594 		} | 
| devi@31 | 595 | 
| devi@31 | 596 		#NOTES | 
| devi@31 | 597 		if ( $Config{"show_notes"} =~ /^y/i && $cl->{"note"}) { | 
| devi@31 | 598 			my $note=$cl->{"note"}; | 
| devi@31 | 599 			$note =~ s/\n/<br\/>\n/msg; | 
| devi@35 | 600 			$note =~ s@(http:[a-zA-Z.0-9/?%-]*)@<a href='$1'>$1</a>@g; | 
| devi@35 | 601 			$note =~ s@(www\.[a-zA-Z.0-9/?%-]*)@<a href='$1'>$1</a>@g; | 
| devi@31 | 602 		#	Ширину пока не используем | 
| devi@31 | 603 		#	$Result{"body"} .= "<table width='$Config{note_width}' class='note'>"; | 
| devi@31 | 604 			$Result{"body"} .= "<table class='note'>"; | 
| devi@31 | 605 			$Result{"body"} .= "<tr><td class='note_title'>".$cl->{note_title}."</td></tr>" if $cl->{note_title}; | 
| devi@31 | 606 			$Result{"body"} .= "<tr><td width='100%' class='note_text'>".$note."</td></tr>"; | 
| devi@31 | 607 			$Result{"body"} .= "</table>\n"; | 
| devi@31 | 608 		} | 
| devi@23 | 609 | 
| devi@23 | 610 		# COMMENT | 
| devi@23 | 611 		if ( $Config{"show_comments"} =~ /^y/i) { | 
| devi@31 | 612 			my $comment = make_comment($cl->{"cline"}); | 
| devi@23 | 613 			if ($comment) { | 
| devi@23 | 614 				$Result{"body"} .= "<table width='$Config{comment_width}'>". | 
| devi@23 | 615 						"<tr><td width='5'/><td>"; | 
| devi@23 | 616 				$Result{"body"} .= "<table class='note' width='100%'>"; | 
| devi@23 | 617 				$Result{"body"} .= $comment; | 
| devi@23 | 618 				$Result{"body"} .= "</table>\n"; | 
| devi@23 | 619 				$Result{"body"} .= "</td></tr></table>"; | 
| devi@23 | 620 			} | 
| devi@23 | 621 		} | 
| devi@23 | 622 | 
| devi@23 | 623 		# Вывод очередной команды окончен | 
| devi@23 | 624 		$Result{"body"} .= "</td>\n"; | 
| devi@23 | 625 		$Result{"body"} .= "</tr>\n"; | 
| devi@23 | 626 	} | 
| devi@23 | 627 | 
| devi@23 | 628 	$Result{"body"} .= "</table>\n"; | 
| devi@23 | 629 | 
| devi@31 | 630 	#$Result{"stat"} = "<hr/>"; | 
| devi@31 | 631 | 
| devi@31 | 632 	%StatNames = ( | 
| devi@31 | 633 		FirstCommand => "Время первой команды журнала", | 
| devi@31 | 634 		LastCommand => "Время последней команды журнала", | 
| devi@31 | 635 		TotalCommands => "Количество командных строк в журнале", | 
| devi@32 | 636 		ErrorsPercentage => "Процент команд с ненулевым кодом завершения, %", | 
| devi@31 | 637 		TotalTime => "Суммарное время работы с терминалом <sup><font size='-2'>*</font></sup>, час", | 
| devi@31 | 638 		CommandsPerTime => "Количество командных строк в единицу времени, команда/мин", | 
| devi@37 | 639 		CommandsFrequency => "Частота использования команд", | 
| devi@31 | 640 		RareCommands	=> "Частота использования этих команд < 0.5%", | 
| devi@31 | 641 	); | 
| devi@31 | 642 	@StatOrder = ( | 
| devi@31 | 643 		FirstCommand, | 
| devi@31 | 644 		LastCommand, | 
| devi@31 | 645 		TotalCommands, | 
| devi@31 | 646 		ErrorsPercentage, | 
| devi@31 | 647 		TotalTime, | 
| devi@31 | 648 		CommandsPerTime, | 
| devi@37 | 649 		CommandsFrequency, | 
| devi@31 | 650 		RareCommands, | 
| devi@31 | 651 	); | 
| devi@31 | 652 | 
| devi@31 | 653 	# Подготовка статистики к выводу | 
| devi@31 | 654 	# Некоторые значения пересчитываются! | 
| devi@31 | 655 	# Дальше их лучше уже не использовать!!! | 
| devi@31 | 656 | 
| devi@37 | 657 	my %CommandsFrequency = %CommandsFDistribution; | 
| devi@37 | 658 | 
| devi@31 | 659 	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{FirstCommand}); | 
| devi@31 | 660 	$Stat{FirstCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec,  $year+1900, $mon+1, $mday; | 
| devi@31 | 661 	($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($Stat{LastCommand}); | 
| devi@31 | 662 	$Stat{LastCommand} = sprintf "%02i:%02i:%02i %04i-%2i-%2i", $hour, $min, $sec,  $year+1900, $mon+1, $mday; | 
| devi@31 | 663 	$Stat{ErrorsPercentage} = sprintf "%5.2f", $Stat{ErrorCommands}*100/$Stat{TotalCommands} | 
| devi@31 | 664 		if $Stat{TotalCommands}; | 
| devi@31 | 665 	$Stat{CommandsPerTime} = sprintf "%5.2f", $Stat{TotalCommands}*60/$Stat{TotalTime} | 
| devi@31 | 666 		if $Stat{TotalTime}; | 
| devi@32 | 667 	$Stat{TotalTime} = sprintf "%5.2f", $Stat{TotalTime}/60/60; | 
| devi@31 | 668 | 
| devi@31 | 669 	my $total_commands=0; | 
| devi@37 | 670 	for $command (keys %CommandsFrequency){ | 
| devi@37 | 671 		$total_commands += $CommandsFrequency{$command}; | 
| devi@31 | 672 	} | 
| devi@31 | 673 	if ($total_commands) { | 
| devi@37 | 674 		for $command (reverse sort {$CommandsFrequency{$a} <=> $CommandsFrequency{$b}} keys %CommandsFrequency){ | 
| devi@32 | 675 			my $command_html; | 
| devi@37 | 676 			my $percentage = sprintf "%5.2f",$CommandsFrequency{$command}*100/$total_commands; | 
| devi@31 | 677 			if ($percentage < 0.5) { | 
| devi@31 | 678 				my $hint = make_comment($command); | 
| devi@32 | 679 				$command_html = "$command"; | 
| devi@31 | 680 				$command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; | 
| devi@31 | 681 				my $command_html = "<tt>$command_html</tt>"; | 
| devi@37 | 682 				$Stat{RareCommands} .= $command_html."<sub><font size='-2'>".$CommandsFrequency{$command}."</font></sub> , "; | 
| devi@31 | 683 			} | 
| devi@31 | 684 			else { | 
| devi@31 | 685 				my $hint = make_comment($command); | 
| devi@32 | 686 				$command_html = "$command"; | 
| devi@31 | 687 				$command_html = "<span title='$hint' class='hint'>$command_html</span>" if $hint; | 
| devi@31 | 688 				my $command_html = "<tt>$command_html</tt>"; | 
| devi@31 | 689 				$percentage = sprintf "%5.2f",$percentage; | 
| devi@37 | 690 				$Stat{CommandsFrequency} .= "<tr><td>".$command_html."</td><td>".$CommandsFrequency{$command}."</td>". | 
| devi@37 | 691 					"<td>|".("="x int($CommandsFrequency{$command}*100/$total_commands))."| $percentage%</td></tr>"; | 
| devi@31 | 692 			} | 
| devi@31 | 693 		} | 
| devi@37 | 694 		$Stat{CommandsFrequency} = "<table>".$Stat{CommandsFrequency}."</table>"; | 
| devi@32 | 695 		$Stat{RareCommands} =~ s/, $// if $Stat{RareCommands}; | 
| devi@31 | 696 	} | 
| devi@31 | 697 | 
| devi@23 | 698 	$Result{"stat"} .= "<h2 id='stat'>Статистика</h2>"; | 
| devi@31 | 699 	$Result{"stat"} .= "<table>"; | 
| devi@31 | 700 	for my $stat (@StatOrder) { | 
| devi@32 | 701 	$Result{"stat"} .= "<tr valign='top'><td width='300'>".$StatNames{"$stat"}."</td><td>".$Stat{"$stat"}."</td></tr>" | 
| devi@32 | 702 		if $Stat{"$stat"}; | 
| devi@31 | 703 	} | 
| devi@31 | 704 | 
| devi@31 | 705 	$Result{"stat"} .= "</table>"; | 
| devi@31 | 706 	$Result{"stat"} .= "<font size='-2'>____<br/>*) Интервалы неактивности длительностью ".($Config{stat_inactivity_interval}/60)." минут и более не учитываются</font></br>"; | 
| devi@31 | 707 | 
| devi@31 | 708 	#$Result{"help"} .= "<hr/>"; | 
| devi@23 | 709 	$Result{"help"} .= "<h2 id='help'>Справка</h2>"; | 
| devi@23 | 710 	$Result{"help"} .= "$Html_Help<br/>"; | 
| devi@31 | 711 	#$Result{"about"} .= "<hr/>"; | 
| devi@23 | 712 	$Result{"about"} .= "<h2 id='about'>О программе</h2>"; | 
| devi@23 | 713 	$Result{"about"} .= "$Html_About"; | 
| devi@23 | 714 	$Result{"footer"} .= "</body>\n"; | 
| devi@23 | 715 	$Result{"footer"} .= "</html>\n"; | 
| devi@23 | 716 | 
| devi@31 | 717 	$Result{"title"} = "Журнал лабораторных работ"; | 
| devi@31 | 718 	$Result{"title"}.= " -- ".$course_student if $course_student; | 
| devi@31 | 719 	if ($course_date) { | 
| devi@31 | 720 		$Result{"title"}.= " -- ".$course_date; | 
| devi@31 | 721 		$Result{"title"}.= "/".$course_code if $course_code; | 
| devi@31 | 722 	} | 
| devi@31 | 723 	else { | 
| devi@31 | 724 		$Result{"title"}.= " -- ".$course_code if $course_code; | 
| devi@31 | 725 	} | 
| devi@31 | 726 | 
| devi@23 | 727 	# Заголовок генерируется позже всего | 
| devi@23 | 728 	# Тогда, когда известно уже, что должно быть написано в | 
| devi@23 | 729 	# оглавлении | 
| devi@23 | 730 	$Result{"header"} = <<HEADER; | 
| devi@23 | 731 	<html> | 
| devi@23 | 732 	<head> | 
| devi@23 | 733 	<meta content='text/html; charset=utf-8' http-equiv='Content-Type' /> | 
| devi@27 | 734 	<link rel='stylesheet' href='$Config{frontend_css}' type='text/css'/> | 
| devi@31 | 735 	<title>$Result{title}</title> | 
| devi@23 | 736 	</head> | 
| devi@23 | 737 	<body> | 
| devi@23 | 738 	<script> | 
| devi@23 | 739 	$Html_JavaScript | 
| devi@23 | 740 	</script> | 
| devi@31 | 741 	<h1>Журнал лабораторных работ</h1> | 
| devi@23 | 742 | 
| devi@31 | 743 HEADER | 
| devi@31 | 744 	$Result{"header"} .= "<p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; | 
| devi@31 | 745 	$Result{"header"} .= "Выполнил $course_student<br/>" if $course_student; | 
| devi@31 | 746 	$Result{"header"} .= "Проверил $course_trainer <br/>" if $course_trainer; | 
| devi@31 | 747 	$Result{"header"} .= "Курс " if $course_name || $course_code || $course_date; | 
| devi@31 | 748 	$Result{"header"} .= "$course_name " if $course_name; | 
| devi@31 | 749 	$Result{"header"} .= "($course_code)" if $course_code; | 
| devi@31 | 750 	$Result{"header"} .= ", $course_date<br/>" if $course_date; | 
| devi@31 | 751 	$Result{"header"} .= "Учебный центр $course_center <br/>" if $course_center; | 
| devi@31 | 752 	$Result{"header"} .= "</p>" if $course_student || $course_trainer || $course_name || $course_code || $course_date || $course_center; | 
| devi@23 | 753 | 
| devi@31 | 754 	my $toc = collapse_list (\@toc); | 
| devi@31 | 755 	$Result{"header"} .= <<HEADER; | 
| devi@23 | 756 	<ul> | 
| devi@23 | 757 		<li><a href='#log'>Журнал</a></li> | 
| devi@23 | 758 		<ul>$toc</ul> | 
| devi@23 | 759 		<li><a href='#stat'>Статистика</a></li> | 
| devi@23 | 760 		<li><a href='#help'>Справка</a></li> | 
| devi@23 | 761 		<li><a href='#about'>О программе</a></li> | 
| devi@23 | 762 	</ul> | 
| devi@23 | 763 | 
| devi@23 | 764 	<h2 id="log">Журнал</h2> | 
| devi@23 | 765 HEADER | 
| devi@31 | 766 	$Result{"header"} .= "<table id='visibility_form' class='visibility_form'><tr><td><form>\n"; | 
| devi@23 | 767 	for my $element (keys %Elements_Visibility) | 
| devi@23 | 768 	{ | 
| devi@23 | 769 		my @e = split /\s+/, $element; | 
| devi@23 | 770 		my $showhide = join "", map { "ShowHide('$_');" } @e ; | 
| devi@23 | 771 		$Result{"header"} .= "<input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>". | 
| devi@23 | 772 				$Elements_Visibility{$element}. | 
| devi@23 | 773 				"</input><br>\n"; | 
| devi@23 | 774 	} | 
| devi@23 | 775 | 
| devi@23 | 776 	$Result{"header"} .= "</form></td></tr></table>\n"; | 
| devi@23 | 777 | 
| devi@27 | 778 	if ($output_filename eq "-") { | 
| devi@27 | 779 		print $Result{"header"}, $Result{"body"}, $Result{"stat"}, $Result{"help"}, $Result{"about"}, $Result{"footer"}; | 
| devi@27 | 780 	} | 
| devi@27 | 781 	else { | 
| devi@27 | 782 		open(OUT, ">", $output_filename) | 
| devi@27 | 783 			or die "Can't open $output_filename for writing\n"; | 
| devi@27 | 784 		print OUT $Result{"header"}, $Result{"body"}, $Result{"stat"}, $Result{"help"}, $Result{"about"}, $Result{"footer"}; | 
| devi@27 | 785 		close(OUT); | 
| devi@27 | 786 	} | 
| devi@23 | 787 } | 
| devi@23 | 788 | 
| devi@23 | 789 | 
| devi@23 | 790 | 
| devi@31 | 791 sub collapse_list($) | 
| devi@31 | 792 { | 
| devi@31 | 793 	my $res = ""; | 
| devi@31 | 794 	for my $elem (@{$_[0]}) { | 
| devi@31 | 795 		if (ref $elem eq "ARRAY") { | 
| devi@31 | 796 			$res .= "<ul>".collapse_list($elem)."</ul>"; | 
| devi@31 | 797 		} | 
| devi@31 | 798 		else | 
| devi@31 | 799 		{ | 
| devi@31 | 800 			$res .= "<li>".$elem."</li>"; | 
| devi@31 | 801 		} | 
| devi@31 | 802 	} | 
| devi@31 | 803 	return $res; | 
| devi@31 | 804 } | 
| devi@31 | 805 | 
| devi@23 | 806 | 
| devi@23 | 807 | 
| devi@23 | 808 | 
| devi@23 | 809 sub init_variables | 
| devi@23 | 810 { | 
| devi@23 | 811 $Html_Help = <<HELP; | 
| devi@31 | 812 	Для того чтобы использовать LiLaLo, не нужно знать ничего особенного: | 
| devi@31 | 813 	всё происходит само собой. | 
| devi@31 | 814 	Однако, чтобы ведение и последующее использование журналов | 
| devi@31 | 815 	было как можно более эффективным, желательно иметь в виду следующее: | 
| devi@31 | 816 	<ul> | 
| devi@31 | 817 	<li><p> | 
| devi@31 | 818 	В журнал автоматически попадают все команды, данные в любом терминале системы. | 
| devi@31 | 819 	</p></li> | 
| devi@31 | 820 	<li><p> | 
| devi@31 | 821 	Для того чтобы убедиться, что журнал на текущем терминале ведётся, | 
| devi@31 | 822 	и команды записываются, дайте команду w. | 
| devi@31 | 823 	В поле WHAT, соответствующем текущему терминалу, | 
| devi@31 | 824 	должна быть указана программа script. | 
| devi@31 | 825 	</p></li> | 
| devi@31 | 826 	<li><p> | 
| devi@31 | 827 	Если код завершения команды равен нулю, | 
| devi@31 | 828 	команда была выполнена без ошибок. | 
| devi@36 | 829 	Команды, код завершения которых отличен от нуля, выделяются цветом. | 
| devi@31 | 830 <table> | 
| devi@31 | 831 <tr class='command'> | 
| devi@31 | 832 <td class='script'> | 
| devi@31 | 833 <pre class='wrong_cline'> | 
| devi@31 | 834 \$ l s-l</pre> | 
| devi@31 | 835 <pre class='wrong_output'>bash: l: command not found | 
| devi@31 | 836 </pre> | 
| devi@31 | 837 </td> | 
| devi@31 | 838 </tr> | 
| devi@31 | 839 </table> | 
| devi@31 | 840 <br/> | 
| devi@31 | 841 	</p></li> | 
| devi@31 | 842 	<li><p> | 
| devi@31 | 843 	Команды, ход выполнения которых был прерван пользователем, выделяются цветом. | 
| devi@31 | 844 <table> | 
| devi@31 | 845 <tr class='command'> | 
| devi@31 | 846 <td class='script'> | 
| devi@31 | 847 <pre class='interrupted_cline'> | 
| devi@31 | 848 \$ find / -name abc</pre> | 
| devi@31 | 849 <pre class='interrupted_output'>find: /home/devi-orig/.gnome2: Keine Berechtigung | 
| devi@31 | 850 find: /home/devi-orig/.gnome2_private: Keine Berechtigung | 
| devi@31 | 851 find: /home/devi-orig/.nautilus/metafiles: Keine Berechtigung | 
| devi@31 | 852 find: /home/devi-orig/.metacity: Keine Berechtigung | 
| devi@31 | 853 find: /home/devi-orig/.inkscape: Keine Berechtigung | 
| devi@31 | 854 ^C | 
| devi@31 | 855 </pre> | 
| devi@31 | 856 </td> | 
| devi@31 | 857 </tr> | 
| devi@31 | 858 </table> | 
| devi@31 | 859 <br/> | 
| devi@31 | 860 	</p></li> | 
| devi@31 | 861 	<li><p> | 
| devi@31 | 862 	Команды, выполненные с привилегиями суперпользователя, | 
| devi@31 | 863 	выделяются слева красной чертой. | 
| devi@31 | 864 <table> | 
| devi@31 | 865 <tr class='command'> | 
| devi@31 | 866 <td class='script'> | 
| devi@31 | 867 <pre class='_root_cline'> | 
| devi@31 | 868 # id</pre> | 
| devi@31 | 869 <pre class='_root_output'> | 
| devi@31 | 870 uid=0(root) gid=0(root) Gruppen=0(root) | 
| devi@31 | 871 </pre> | 
| devi@31 | 872 </td> | 
| devi@31 | 873 </tr> | 
| devi@31 | 874 </table> | 
| devi@31 | 875 	<br/> | 
| devi@31 | 876 	</p></li> | 
| devi@31 | 877 	<li><p> | 
| devi@31 | 878 	Изменения, внесённые в текстовый файл с помощью редактора, | 
| devi@31 | 879 	запоминаются и показываются в журнале в формате ed. | 
| devi@31 | 880 	Строки, начинающиеся символом "<", удалены, а строки, | 
| devi@31 | 881 	начинающиеся символом ">" -- добавлены. | 
| devi@31 | 882 <table> | 
| devi@31 | 883 <tr class='command'> | 
| devi@31 | 884 <td class='script'> | 
| devi@31 | 885 <pre class='cline'> | 
| devi@31 | 886 \$ vi ~/.bashrc</pre> | 
| devi@31 | 887 <table><tr><td width='5'/><td class='diff'><pre>2a3,5 | 
| devi@31 | 888 > 	if [ -f /usr/local/etc/bash_completion ]; then | 
| devi@31 | 889 >         . /usr/local/etc/bash_completion | 
| devi@31 | 890 >     	fi | 
| devi@31 | 891 </pre></td></tr></table></td> | 
| devi@31 | 892 </tr> | 
| devi@31 | 893 </table> | 
| devi@31 | 894 	<br/> | 
| devi@31 | 895 	</p></li> | 
| devi@31 | 896 	<li><p> | 
| devi@31 | 897 	Для того чтобы получить краткую справочную информацию о команде, | 
| devi@31 | 898 	нужно подвести к ней мышь. Во всплывающей подсказке появится краткое | 
| devi@31 | 899 	описание команды. | 
| devi@31 | 900 	</p></li> | 
| devi@31 | 901 	<li><p> | 
| devi@31 | 902 	Время ввода команды, показанное в журнале, соответствует времени | 
| devi@31 | 903 	<i>начала ввода командной строки</i>, которое равно тому моменту, | 
| devi@31 | 904 	когда на терминале появилось приглашение интерпретатора | 
| devi@31 | 905 	</p></li> | 
| devi@31 | 906 	<li><p> | 
| devi@31 | 907 	Имя терминала, на котором была введена команда, показано в специальном блоке. | 
| devi@31 | 908 	Этот блок показывается только в том случае, если терминал | 
| devi@31 | 909 	текущей команды отличается от терминала предыдущей. | 
| devi@31 | 910 	</p></li> | 
| devi@31 | 911 	<li><p> | 
| devi@31 | 912 	Вывод не интересующих вас в настоящий момент элементов журнала, | 
| devi@31 | 913 	таких как время, имя терминала и других, можно отключить. | 
| devi@31 | 914 	Для этого нужно воспользоваться <a href='#visibility_form'>формой управления журналом</a> | 
| devi@31 | 915 	вверху страницы. | 
| devi@31 | 916 	</p></li> | 
| devi@31 | 917 	<li><p> | 
| devi@31 | 918 	Небольшие комментарии к командам можно вставлять прямо из командной строки. | 
| devi@31 | 919 	Комментарий вводится прямо в командную строку, после символов #^ или #v. | 
| devi@31 | 920 	Символы ^ и v показывают направление выбора команды, к которой относится комментарий: | 
| devi@31 | 921 	^ - к предыдущей, v - к следующей. | 
| devi@31 | 922 	Например, если в командной строке было введено: | 
| devi@31 | 923 <pre class='cline'> | 
| devi@31 | 924 \$ whoami | 
| devi@31 | 925 </pre> | 
| devi@31 | 926 <pre class='output'> | 
| devi@31 | 927 user | 
| devi@31 | 928 </pre> | 
| devi@31 | 929 <pre class='cline'> | 
| devi@31 | 930 \$ #^ Интересно, кто я? | 
| devi@31 | 931 </pre> | 
| devi@31 | 932 	в журнале это будет выглядеть так: | 
| devi@31 | 933 | 
| devi@31 | 934 <pre class='cline'> | 
| devi@31 | 935 \$ whoami | 
| devi@31 | 936 </pre> | 
| devi@31 | 937 <pre class='output'> | 
| devi@31 | 938 user | 
| devi@31 | 939 </pre> | 
| devi@31 | 940 <table class='note'><tr><td width='100%' class='note_text'> | 
| devi@31 | 941 <tr> <td> Интересно, кто я?<br/> </td></tr></table> | 
| devi@31 | 942 	</p></li> | 
| devi@31 | 943 	<li><p> | 
| devi@31 | 944 	Если комментарий содержит несколько строк, | 
| devi@31 | 945 	его можно вставить в журнал следующим образом: | 
| devi@31 | 946 <pre class='cline'> | 
| devi@31 | 947 \$ whoami | 
| devi@31 | 948 </pre> | 
| devi@31 | 949 <pre class='output'> | 
| devi@31 | 950 user | 
| devi@31 | 951 </pre> | 
| devi@31 | 952 <pre class='cline'> | 
| devi@31 | 953 \$ cat > /dev/null #^ Интересно, кто я? | 
| devi@31 | 954 </pre> | 
| devi@31 | 955 <pre class='output'> | 
| devi@31 | 956 Программа whoami выводит имя пользователя, под которым | 
| devi@31 | 957 мы зарегистрировались в системе. | 
| devi@31 | 958 - | 
| devi@31 | 959 Она не может ответить на вопрос о нашем назначении | 
| devi@31 | 960 в этом мире. | 
| devi@31 | 961 </pre> | 
| devi@31 | 962 	В журнале это будет выглядеть так: | 
| devi@31 | 963 <table> | 
| devi@31 | 964 <tr class='command'> | 
| devi@31 | 965 <td class='script'> | 
| devi@31 | 966 <pre class='cline'> | 
| devi@31 | 967 \$ whoami</pre> | 
| devi@31 | 968 <pre class='output'>user | 
| devi@31 | 969 </pre> | 
| devi@31 | 970 <table class='note'><tr><td class='note_title'>Интересно, кто я?</td></tr><tr><td width='100%' class='note_text'> | 
| devi@31 | 971 Программа whoami выводит имя пользователя, под которым<br/> | 
| devi@31 | 972 мы зарегистрировались в системе.<br/> | 
| devi@31 | 973 <br/> | 
| devi@31 | 974 Она не может ответить на вопрос о нашем назначении<br/> | 
| devi@31 | 975 в этом мире.<br/> | 
| devi@31 | 976 </td></tr></table> | 
| devi@31 | 977 </td> | 
| devi@31 | 978 </tr> | 
| devi@31 | 979 </table> | 
| devi@31 | 980 	Для разделения нескольких абзацев между собой | 
| devi@31 | 981 	используйте символ "-", один в строке. | 
| devi@31 | 982 	<br/> | 
| devi@31 | 983 </p></li> | 
| devi@31 | 984 	<li><p> | 
| devi@31 | 985 	Комментарии, не относящиеся непосредственно ни к какой из команд, | 
| devi@31 | 986 	добавляются точно таким же способом, только вместо симолов #^ или #v | 
| devi@31 | 987 	нужно использовать символы #= | 
| devi@31 | 988 	</p></li> | 
| devi@31 | 989 </ul> | 
| devi@23 | 990 HELP | 
| devi@23 | 991 | 
| devi@23 | 992 $Html_About = <<ABOUT; | 
| devi@23 | 993 	<p> | 
| devi@23 | 994 	LiLaLo (L3) расшифровывается как Live Lab Log.<br/> | 
| devi@29 | 995 	Программа разработана для повышения эффективности обучения Unix/Linux-системам.<br/> | 
| devi@23 | 996 	(c) Игорь Чубин, 2004-2005<br/> | 
| devi@23 | 997 	</p> | 
| devi@23 | 998 ABOUT | 
| devi@23 | 999 $Html_About.='$Id$ </p>'; | 
| devi@23 | 1000 | 
| devi@23 | 1001 $Html_JavaScript = <<JS; | 
| devi@23 | 1002 	function getElementsByClassName(Class_Name) | 
| devi@23 | 1003 	{ | 
| devi@23 | 1004 		var Result=new Array(); | 
| devi@23 | 1005 		var All_Elements=document.all || document.getElementsByTagName('*'); | 
| devi@23 | 1006 		for (i=0; i<All_Elements.length; i++) | 
| devi@23 | 1007 			if (All_Elements[i].className==Class_Name) | 
| devi@23 | 1008 		Result.push(All_Elements[i]); | 
| devi@23 | 1009 		return Result; | 
| devi@23 | 1010 	} | 
| devi@23 | 1011 	function ShowHide (name) | 
| devi@23 | 1012 	{ | 
| devi@23 | 1013 		elements=getElementsByClassName(name); | 
| devi@23 | 1014 		for(i=0; i<elements.length; i++) | 
| devi@23 | 1015 			if (elements[i].style.display == "none") | 
| devi@23 | 1016 				elements[i].style.display = ""; | 
| devi@23 | 1017 			else | 
| devi@23 | 1018 				elements[i].style.display = "none"; | 
| devi@23 | 1019 			//if (elements[i].style.visibility == "hidden") | 
| devi@23 | 1020 			//	elements[i].style.visibility = "visible"; | 
| devi@23 | 1021 			//else | 
| devi@23 | 1022 			//	elements[i].style.visibility = "hidden"; | 
| devi@23 | 1023 	} | 
| devi@23 | 1024 	function filter_by_output(text) | 
| devi@23 | 1025 	{ | 
| devi@23 | 1026 | 
| devi@23 | 1027 		var jjj=0; | 
| devi@23 | 1028 | 
| devi@23 | 1029 		elements=getElementsByClassName('command'); | 
| devi@23 | 1030 		for(i=0; i<elements.length; i++) { | 
| devi@23 | 1031 			subelems = elements[i].getElementsByTagName('pre'); | 
| devi@23 | 1032 			for(j=0; j<subelems.length; j++) { | 
| devi@23 | 1033 				if (subelems[j].className = 'output') { | 
| devi@23 | 1034 					var str = new String(subelems[j].nodeValue); | 
| devi@23 | 1035 					if (jjj != 1) { | 
| devi@23 | 1036 						alert(str); | 
| devi@23 | 1037 						jjj=1; | 
| devi@23 | 1038 					} | 
| devi@23 | 1039 					if (str.indexOf(text) >0) | 
| devi@23 | 1040 						subelems[j].style.display = "none"; | 
| devi@23 | 1041 					else | 
| devi@23 | 1042 						subelems[j].style.display = ""; | 
| devi@23 | 1043 | 
| devi@23 | 1044 				} | 
| devi@23 | 1045 | 
| devi@23 | 1046 			} | 
| devi@23 | 1047 		} | 
| devi@23 | 1048 | 
| devi@23 | 1049 	} | 
| devi@23 | 1050 JS | 
| devi@23 | 1051 | 
| devi@23 | 1052 %Search_Machines = ( | 
| devi@23 | 1053 		"google" => 	{ 	"query" => 	"http://www.google.com/search?q=" , | 
| devi@28 | 1054 					"icon" 	=> 	"$Config{frontend_google_ico}" }, | 
| devi@23 | 1055 		"freebsd" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=", | 
| devi@28 | 1056 					"icon"	=>	"$Config{frontend_freebsd_ico}" }, | 
| devi@23 | 1057 		"linux"  => 	{ 	"query" => 	"http://man.he.net/?topic=", | 
| devi@28 | 1058 					"icon"	=>	"$Config{frontend_linux_ico}"}, | 
| devi@23 | 1059 		"opennet"  => 	{ 	"query" => 	"http://www.opennet.ru/search.shtml?words=", | 
| devi@28 | 1060 					"icon"	=>	"$Config{frontend_opennet_ico}"}, | 
| devi@23 | 1061 		"local" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=", | 
| devi@28 | 1062 					"icon"	=>	"$Config{frontend_local_ico}" }, | 
| devi@23 | 1063 | 
| devi@23 | 1064 	); | 
| devi@23 | 1065 | 
| devi@23 | 1066 %Elements_Visibility = ( | 
| devi@23 | 1067 		"note"		=>	"замечания", | 
| devi@23 | 1068 		"diff"		=>	"редактор", | 
| devi@23 | 1069 		"time"		=>	"время", | 
| devi@23 | 1070 		"ttychange" 	=>	"терминал", | 
| devi@23 | 1071 		"wrong_output wrong_cline wrong_root_output wrong_root_cline" | 
| devi@23 | 1072 				=>	"команды с ошибками", | 
| devi@23 | 1073 		"interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" | 
| devi@23 | 1074 				=>	"прерванные команды", | 
| devi@23 | 1075 		"tab_completion_output tab_completion_cline" | 
| devi@23 | 1076 				=> 	"продолжение с помощью tab" | 
| devi@23 | 1077 ); | 
| devi@23 | 1078 | 
| devi@23 | 1079 @Day_Name      = qw/ Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота /; | 
| devi@23 | 1080 @Month_Name    = qw/ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь /; | 
| devi@23 | 1081 @Of_Month_Name = qw/ Января Февраля Марта Апреля Мая Июня Июля Августа Сентября Октября Ноября Декабря /; | 
| devi@23 | 1082 } | 
| devi@23 | 1083 |