lilalo

changeset 0:18b21f6918f0

Initial revision
author devi
date Sun May 22 16:29:55 2005 +0300 (2005-05-22)
parents
children ff93ad94d73b 787e9f11de51
files .lm.swo .lm.swp .tarball FILES INSTALL README TODO labmaker.conf lm lm-install lm-report lm-ssh share/freebsd.ico share/google.ico share/labmaker.css share/opennet.ico share/ug.xsl taillast.pl ug2db
line diff
     1.1 Binary file .lm.swo has changed
     2.1 Binary file .lm.swp has changed
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/.tarball	Sun May 22 16:29:55 2005 +0300
     3.3 @@ -0,0 +1,11 @@
     3.4 +INSTALL
     3.5 +lm-install
     3.6 +lm-report
     3.7 +lm-report.conf
     3.8 +Makefile
     3.9 +.tarball
    3.10 +freebsd.ico
    3.11 +google.ico
    3.12 +opennet.ico
    3.13 +labmaker.css
    3.14 +
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/FILES	Sun May 22 16:29:55 2005 +0300
     4.3 @@ -0,0 +1,26 @@
     4.4 +lm		- labmaker's frontend
     4.5 +		  Отвечает за инсталляцию lm-агшентов, сбор данных для журналов, 
     4.6 +		  вызов lm-report для генерирования журналов и т.д.
     4.7 +		  
     4.8 +lm-install	- инсталлирует labmaker на машину.
     4.9 +		  Должен вызываться для тех пользователей, где необходимо вести запись
    4.10 +		  журналов действий 
    4.11 +		  
    4.12 +lm-report	- генератор отчётов labmaker
    4.13 +
    4.14 +lm-ssh		- expect-скрипт, предназначенный для автоматический инсталляции 
    4.15 +		  labmaker на удалённую машину посредством ssh. Автоматически
    4.16 +		  вводит пароль и отвечает 'yes' на вопрос об открытх ключах
    4.17 +		  хоста
    4.18 +		  
    4.19 +taillast.pl	- показать хвост последнего изменённого журнала lm
    4.20 +ug2db		- сконвертировать из UG Labmaker XML в DocBook XML
    4.21 +
    4.22 +labmaker.conf	- конфигурационный файл программ lm и lm-report
    4.23 +share/		- файлы иконок, картинок, стилей
    4.24 +
    4.25 +FILES		- список файлов в дистрибутиве LabMaker
    4.26 +INSTALL		- описание процедуры инсталляции
    4.27 +README		- информация о программе
    4.28 +TODO		- список вещей, которые нужно сделать
    4.29 +
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/INSTALL	Sun May 22 16:29:55 2005 +0300
     5.3 @@ -0,0 +1,9 @@
     5.4 +Инсталляция LabMaker 
     5.5 +
     5.6 +1. Проинсталлировать все необходимые модули Perl
     5.7 +2. Выполнить lm-install, указав в качестве параметров 
     5.8 +   имена домашних каталогов пользователей, для которых
     5.9 +   должны вестись журналы
    5.10 +3. Использовать lm-report для генерирования журналов   
    5.11 +   
    5.12 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/TODO	Sun May 22 16:29:55 2005 +0300
     6.3 @@ -0,0 +1,42 @@
     6.4 +TODO LIST
     6.5 +
     6.6 +lm-report:
     6.7 +
     6.8 +general:		Отметка фрагментов + якоря из командной строки
     6.9 +
    6.10 +user:			Поддержка su и sudo
    6.11 +diff:			FIX	не показывать плавающий бокс
    6.12 +фрагменты:		отмечать фрагменты для комментирования
    6.13 +html:			управление деталями
    6.14 +html:			навести порядок в css
    6.15 +
    6.16 +web:			индекс активности
    6.17 +web:			централизованный доступ
    6.18 +web:			периодическое обновление
    6.19 +web:			информация о лабе
    6.20 +
    6.21 +
    6.22 +
    6.23 +lm:
    6.24 +	ls [[user@]host]
    6.25 +	list [[user@]host]
    6.26 +			показывает список ведщихся журналов
    6.27 +	cat журнал
    6.28 +	show журнал		
    6.29 +			показывает заданный журнал
    6.30 +
    6.31 +	<журнал> указывается в форме console@host
    6.32 +
    6.33 +
    6.34 +	save host
    6.35 +			сохраняет журналы указанной машины
    6.36 +
    6.37 +	
    6.38 +	do		выполнение команды
    6.39 +			+ стандартный набор команд (в т.ч. инсталляция)
    6.40 +	
    6.41 +DONE
    6.42 +
    6.43 +xml:			поддержка формата xml
    6.44 +html:			заполлзающие блоки	(ИСКЛЮЧЕНО)
    6.45 +general:		Конфигурация через файл и командную строку
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/labmaker.conf	Sun May 22 16:29:55 2005 +0300
     7.3 @@ -0,0 +1,4 @@
     7.4 +## Specify configurable parameters here
     7.5 +## in form
     7.6 +## variable = value
     7.7 +#terminal_width=100
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/lm	Sun May 22 16:29:55 2005 +0300
     8.3 @@ -0,0 +1,494 @@
     8.4 +#!/usr/bin/perl
     8.5 +
     8.6 +
     8.7 +use strict;
     8.8 +use Inline::Files;
     8.9 +use Data::Dumper;
    8.10 +use Switch;
    8.11 +use XML::Simple;
    8.12 +use Getopt::Long;
    8.13 +
    8.14 +our $XMLClass;
    8.15 +our $XMLCourse;
    8.16 +our @Labs;
    8.17 +
    8.18 +our %Machines;			# Machines list from class.xml
    8.19 +our @SelectedMachines;		# Machines list given as the command line argument
    8.20 +
    8.21 +our $Config_File = "labmaker.conf";
    8.22 +our %Config = (
    8.23 +	"show_host" 	=> "no",
    8.24 +
    8.25 +	# Каталоги
    8.26 +	"path_labmaker" => "/var/labmaker/",
    8.27 +	"path_classes"	=> "/var/labmaker/classes/",
    8.28 +	"lablogs_path"	=> "/var/labmaker/lablogs/",
    8.29 +	"courses_path"	=> "/var/labmaker/courses/",
    8.30 +	"outpath"	=> "/var/labmaker/out/",
    8.31 +
    8.32 +	# Файлы
    8.33 +	"runfile"	=> "lm.run", 
    8.34 +	"logfile"	=> "lm.log", 
    8.35 +
    8.36 +	"class" 	=> "class", 				# Имя файла класса
    8.37 +	"class_suffix" 	=> ".xml", 				# Cуффикс файла класса
    8.38 +
    8.39 +	"sshkey"	=> "$ENV{HOME}/.ssh/id_dsa.pub",
    8.40 +	"lmssh"		=> "./lm-ssh",
    8.41 +	"lminstall"	=> "./lm-install",
    8.42 +	"ssh_user"	=> "r",
    8.43 +);
    8.44 +
    8.45 +our %Run = (
    8.46 +	"lab" => ""
    8.47 +);
    8.48 +
    8.49 +our %Scripts;
    8.50 +
    8.51 +sub load_class;
    8.52 +sub load_config;
    8.53 +sub load_course;
    8.54 +sub load_scripts;
    8.55 +
    8.56 +sub lm_next;
    8.57 +sub lm_prev;
    8.58 +sub lm_start;
    8.59 +sub lm_stop;
    8.60 +sub lm_set;
    8.61 +sub lm_do;
    8.62 +sub lm_report;
    8.63 +sub lm_show_hosts;
    8.64 +sub lm_show_labs;
    8.65 +
    8.66 +sub load_run;
    8.67 +sub save_run;
    8.68 +sub print_log;
    8.69 +sub print_usage_info;
    8.70 +sub main();
    8.71 +
    8.72 +main();
    8.73 +
    8.74 +sub main()
    8.75 +{
    8.76 +	binmode STDOUT, ":utf8";
    8.77 +
    8.78 +	if (! @ARGV) {
    8.79 +		print_usage_info();
    8.80 +		exit(0);
    8.81 +	}
    8.82 +
    8.83 +	load_config;
    8.84 +	load_run;
    8.85 +	load_scripts;
    8.86 +	load_class;
    8.87 +	load_course;
    8.88 +	
    8.89 +	my $arg = join " ", @ARGV;
    8.90 +
    8.91 +	# Getting @SelectedMachines if any
    8.92 +	if ($arg =~ s/@(.*?)\s//) {
    8.93 +		my $machines = $1;
    8.94 +		my @list = split /,/, $machines;
    8.95 +		for my $interval (@list) {
    8.96 +			my ($first, $last) = split /-/, $interval;
    8.97 +
    8.98 +			push @SelectedMachines, $first;
    8.99 +			while ($first < $last) {
   8.100 +				push @SelectedMachines, ++$first;
   8.101 +			}	
   8.102 +		}
   8.103 +	}
   8.104 +
   8.105 +	# Choose command to do
   8.106 +	switch ($arg) {
   8.107 +		case "next"	{ lm_next }
   8.108 +		case "prev"	{ lm_prev }
   8.109 +		case /set /	{ $arg =~ /set (.*)/; lm_set $1 }
   8.110 +		case "report"	{ lm_report }
   8.111 +		case "start"	{ lm_start }
   8.112 +		case "stop"	{ lm_stop }
   8.113 +		case "show hosts" { lm_show_hosts }
   8.114 +		case "show labs" { lm_show_labs }
   8.115 +		case /do /  { $arg =~ /do (.*)/;  lm_do "$1" }
   8.116 +		else 		{ print_usage_info() }
   8.117 +	}
   8.118 +	save_run;
   8.119 +	exit(0);
   8.120 +}
   8.121 +
   8.122 +sub load_scripts
   8.123 +{
   8.124 +	local $/;
   8.125 +	$_=<SCRIPTS>;
   8.126 +	%Scripts = ("empty-element", split (/###(.*)\n/));
   8.127 +	delete($Scripts{"empty-element"});
   8.128 +}
   8.129 +
   8.130 +sub load_config
   8.131 +{
   8.132 +	my %file_config;
   8.133 +	my %argv_config;
   8.134 +	#read_config_file(\%file_config, $Config_File);
   8.135 +	GetOptions(\%argv_config, map "$_=s", keys %Config);
   8.136 +	%Config = (%Config, %file_config, %argv_config);
   8.137 +}
   8.138 +
   8.139 +sub load_course
   8.140 +{
   8.141 +	$XMLCourse = XMLin($Config{"courses_path"}.$XMLClass->{"course"}.".xml", ForceArray => 1 )  
   8.142 +		or die "Can't open file of the course ",$XMLClass->{"course"}," [with .xml extension]\n";
   8.143 +#	print Dumper($XMLCourse);
   8.144 +	for my $lab (@{$XMLCourse->{"module"}}) {
   8.145 +		push @Labs, $lab->{"code"};
   8.146 +	}
   8.147 +}
   8.148 +
   8.149 +sub load_class
   8.150 +{
   8.151 +	my $classfile =
   8.152 +	$Config{"path_classes"}."/".$Config{"class"}.$Config{"class_suffix"};
   8.153 +	$XMLClass = XMLin($classfile , ForceArray => [ 'student' ] )  
   8.154 +		or die "Can't open file of the class ",$classfile,"\n";
   8.155 +
   8.156 +	for my $student (@{$XMLClass->{"student"}}) {
   8.157 +		$Machines{$student->{"host"}} = {
   8.158 +			"name"	=> "$student->{firstname} $student->{surname}",
   8.159 +			"user"	=> "$student->{user}",
   8.160 +			"student" => $student,
   8.161 +		}	
   8.162 +	}
   8.163 +#	print Dumper($XMLClass);
   8.164 +#	print Dumper(\%Machines);
   8.165 +}
   8.166 +
   8.167 +
   8.168 +sub lm_next
   8.169 +{
   8.170 +	for(my $i=0; $i<=$#Labs; $i++){
   8.171 +		if ( $Labs[$i] eq $Run{"lab"} ) {
   8.172 +			if ($i < $#Labs) {
   8.173 +				lm_set($Labs[$i+1]);
   8.174 +				return ;
   8.175 +			} else {
   8.176 +				die "Lab ", $Run{"lab"}, " is the last. Switch to next lab is impossible"
   8.177 +			}
   8.178 +		}
   8.179 +		
   8.180 +	}
   8.181 +	die "Lab ", $Run{"lab"}, " not found. Don't know which is next"
   8.182 +}
   8.183 +
   8.184 +sub lm_prev
   8.185 +# Switch to previous lab
   8.186 +{
   8.187 +	for(my $i=0; $i<=$#Labs; $i++){
   8.188 +		if ( $Labs[$i] eq $Run{"lab"} ) {
   8.189 +			if ($i > 0) {
   8.190 +				lm_set($Labs[$i-1]);
   8.191 +				return ;
   8.192 +			} else {
   8.193 +				die "Lab ", $Run{"lab"}, " is the first. Switch to previous lab is impossible"
   8.194 +			}
   8.195 +		}
   8.196 +		
   8.197 +	}
   8.198 +	die "Lab ", $Run{"lab"}, " not found. Don't know which is previous"
   8.199 +}
   8.200 +
   8.201 +sub lm_set
   8.202 +# Switch to $_[0] lab
   8.203 +# FIXME
   8.204 +{
   8.205 +	my $lab = shift;
   8.206 +	print "Current lab is $lab\n";
   8.207 +	$Run{"lab"} = "$lab";
   8.208 +	lm_do "setlab", $lab;
   8.209 +}
   8.210 +
   8.211 +
   8.212 +sub lm_start
   8.213 +# Start new training day
   8.214 +{
   8.215 +	print_log(`date`." STARTED\n");
   8.216 +	if ($Run{"lab"}) {
   8.217 +		lm_next;
   8.218 +	}
   8.219 +	else
   8.220 +	{
   8.221 +		# First lab in the course
   8.222 +		lm_set($Labs[0]);
   8.223 +	}
   8.224 +}
   8.225 +
   8.226 +sub lm_stop
   8.227 +# Stop this training day
   8.228 +{
   8.229 +	print_log(`date`." STOPPED\n");
   8.230 +}
   8.231 +
   8.232 +
   8.233 +sub lm_show_hosts
   8.234 +# Show hosts used to run a commands
   8.235 +{
   8.236 +	my $i=1;
   8.237 +	for my $m (sort keys %Machines) {
   8.238 +		if (!@SelectedMachines || grep /^$i$/, @SelectedMachines) {
   8.239 +			print "($i)","\t",$m,"\t",$Machines{$m}->{"name"},"\n";
   8.240 +		}	
   8.241 +		$i++;
   8.242 +	}
   8.243 +}
   8.244 +
   8.245 +sub lm_show_labs
   8.246 +# Show hosts used to run a commands
   8.247 +{
   8.248 +	my $i=1;
   8.249 +	for my $lab (@Labs) {
   8.250 +		print $lab;
   8.251 +		print "*" if $lab eq $Run{"lab"};
   8.252 +		print "\n";
   8.253 +	}
   8.254 +}
   8.255 +
   8.256 +sub lm_do
   8.257 +# Do the $_[0] command on all of the hosts 
   8.258 +{
   8.259 +	my $command = shift;
   8.260 +	my $arg = join " ", @_;
   8.261 +	my $i=1;
   8.262 +	for my $m (sort keys %Machines) {
   8.263 +		if (!@SelectedMachines || grep $_ eq $i, @SelectedMachines) {
   8.264 +			print "$m:\n" if $Config{"show_host"} =~ /y/i;
   8.265 +
   8.266 +			my %myenv = ( %Config, 
   8.267 +				host 	=>	$m,
   8.268 +				dirs	=>	"/root /home/".$Machines{$m}->{"user"},
   8.269 +				lablogs =>	$Config{"lablogs_path"}."/".
   8.270 +						$XMLClass->{"course"}."/".
   8.271 +						$XMLClass->{"date"}."/".
   8.272 +						"$m",
   8.273 +				lab	=> 	$arg,			
   8.274 +				
   8.275 +				email	=>	$Machines{$m}->{"student"}->{"email"},
   8.276 +				company	=>	$Machines{$m}->{"student"}->{"company"},
   8.277 +				center 	=>	$XMLClass->{"center"},
   8.278 +				course 	=>	$XMLClass->{"course"},
   8.279 +				date 	=>	$XMLClass->{"date"},
   8.280 +				name	=> 	$Machines{$m}->{"name"},
   8.281 +				coursepath =>	$XMLCourse->{"path"},
   8.282 +
   8.283 +			);
   8.284 +			if (grep { $_ eq $command} keys %Scripts) {
   8.285 +				$_=$Scripts{"$command"};
   8.286 +				s/\$(\w+)/$myenv{$1}/ge;
   8.287 +				open(SHELL, "|/bin/sh -s");
   8.288 +				binmode SHELL, ":utf8";
   8.289 +				print SHELL $_;
   8.290 +				close (SHELL);
   8.291 +			}
   8.292 +			else {
   8.293 +				my $res = `ssh $Config{"ssh_user"}\@$m $command`;
   8.294 +				if ($res) {
   8.295 +					my $count = ($res =~ s/(^)/$m: /mg);
   8.296 +					print $res;
   8.297 +					print "\n" if ($count > 1);
   8.298 +				}
   8.299 +			}	
   8.300 +		}	
   8.301 +		$i++;
   8.302 +	}
   8.303 +}
   8.304 +
   8.305 +
   8.306 +sub lm_report
   8.307 +{
   8.308 +
   8.309 +	print "Not implemented yet\n";
   8.310 +	exit(1);
   8.311 +
   8.312 +=cut comment
   8.313 +
   8.314 +Дальше идут скрипты, код которых нужно реализовать здесь.
   8.315 +Как минимум.
   8.316 +
   8.317 +=cut 
   8.318 +
   8.319 +	my $lm_script_make_report_web = <<'SCRIPT';
   8.320 +
   8.321 +#!/bin/sh
   8.322 +
   8.323 +####cd /home/devi/lm
   8.324 +./lm do copy-lablogs
   8.325 +##./lm-report --input /home/murk/.labmaker --output /var/www/lm/murk.html
   8.326 +##exit
   8.327 +
   8.328 +COURSE=ug-h
   8.329 +DATE=2005-04-25
   8.330 +SUFF=".linux.nt"
   8.331 +#MACHINES="m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15"
   8.332 +#MACHINES="m1 m2 m3 m4 m5 m6 m7 f1 f2 f3 f4 f5"
   8.333 +MACHINES="m01 m02 m03 m04 m05 m06 m07 m08"
   8.334 +#MACHINES="m1"
   8.335 +USERS="user root"
   8.336 +WEBDIR=/var/www/lm
   8.337 +
   8.338 +for u in $USERS
   8.339 +	do
   8.340 +		for m in $MACHINES
   8.341 +			do
   8.342 +				e=utf-8
   8.343 +				[ "${m##f}" = "$m" ] || e=koi8-r
   8.344 +				#e=koi8-r
   8.345 +				mkdir -p $WEBDIR/$DATE/$m
   8.346 +				cp share/*.ico share/*.css $WEBDIR/$m
   8.347 +				#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   8.348 +				./lm-report\
   8.349 +					--input	Lablogs/$COURSE/$DATE/$m$SUFF/$u/ \
   8.350 +					--diffs "Lablogs/$COURSE/$DATE/$m$SUFF/$u/ Lablogs/$COURSE/$DATE/$m$SUFF/root/"\
   8.351 +					--output /var/www/lm/$DATE/$m/$u.html \
   8.352 +					--encoding $e
   8.353 +			done
   8.354 +	done
   8.355 +					
   8.356 +
   8.357 +SCRIPT
   8.358 +
   8.359 +	my $lm_script_make_report_all = <<'SCRIPT';
   8.360 +
   8.361 +#!/bin/sh
   8.362 +WEBDIR=/var/www/lm
   8.363 +
   8.364 +find . -type d -maxdepth 5 -mindepth 5 |\
   8.365 +	while read dir
   8.366 +	do
   8.367 +		subdir=${dir##Lablogs/}
   8.368 +		e=utf-8
   8.369 +		echo $dir | grep -qi bsd && e=koi8-r
   8.370 +		echo $dir | grep -qi /f && e=koi8-r
   8.371 +
   8.372 +		mkdir -p $WEBDIR/${subdir%/*}
   8.373 +		cp share/*.ico share/*.css $WEBDIR/${subdir%/*}
   8.374 +		#echo Processing Lablogs/$COURSE/$DATE/$m$SUFF/$u/
   8.375 +		./lm-report\
   8.376 +			--input $dir	 \
   8.377 +			--diffs "${dir%/user}/root $dir"\
   8.378 +			--output $WEBDIR/$subdir.html \
   8.379 +			--encoding $e
   8.380 +	done
   8.381 +
   8.382 +SCRIPT
   8.383 +}
   8.384 +
   8.385 +sub load_run
   8.386 +{
   8.387 +	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   8.388 +	open (RUN, $runfile)
   8.389 +		or return;
   8.390 +	while (<RUN>) {
   8.391 +		chomp;
   8.392 +		my ($var, $val) = split /\s+/,$_,2;
   8.393 +		$Run{$var}=$val;
   8.394 +	}
   8.395 +	close (RUN);	
   8.396 +}
   8.397 +
   8.398 +sub save_run
   8.399 +{
   8.400 +	my $runfile = $Config{"path_labmaker"}."/".$Config{"path_runfile"};
   8.401 +	open (RN, "$runfile")
   8.402 +		or die "Can't save running state to $runfile";
   8.403 +	for my $var (keys %Run) {
   8.404 +		print RN $var,"\t",$Run{$var},"\n";
   8.405 +	}
   8.406 +	close (RN);	
   8.407 +}
   8.408 +
   8.409 +sub print_log
   8.410 +{
   8.411 +	my $logfile = $Config{"path_labmaker"}."/".$Config{"path_logfile"};
   8.412 +	open (LOG, ">>$logfile")
   8.413 +		or die "Can't open logfile $logfile for writing";
   8.414 +	print LOG  @_;
   8.415 +	close (LOG);	
   8.416 +}
   8.417 +
   8.418 +
   8.419 +sub print_usage_info
   8.420 +{
   8.421 +	print "Usage:\n\n\t$0 [host-list] command\n";
   8.422 +	while (<USAGE>) {
   8.423 +		print $_;
   8.424 +	}
   8.425 +}
   8.426 +
   8.427 +__USAGE__
   8.428 +
   8.429 +Commands:
   8.430 +
   8.431 +	next		-- next lab
   8.432 +	prev		-- prev lab
   8.433 +	set LAB		-- set current lab to LAB
   8.434 +	start		-- start this day training
   8.435 +	stop		-- stop this day training
   8.436 +	show hosts	-- show available hosts in the class
   8.437 +	show labs	-- show available labs in the course
   8.438 +	do COMMAND	-- do specified command on the hosts of hostlist
   8.439 +	report		-- generate XML/HTML reports
   8.440 +
   8.441 +	
   8.442 +do commands:
   8.443 +	
   8.444 +	install [PROFILE] -- install profile 
   8.445 +	
   8.446 +Host list:	
   8.447 +
   8.448 +	@N		-- machine N
   8.449 +	@N1-N2		-- all of the machines from N1 to N2
   8.450 +	@N1,N2,N3	-- machine N1, N2 and N3
   8.451 +
   8.452 +	N* is numbers or domain names of the machines.
   8.453 +	
   8.454 +	If host list is not specified, 
   8.455 +	command is executed on all of the machines
   8.456 +
   8.457 +
   8.458 +
   8.459 +__SCRIPTS__
   8.460 +###install
   8.461 +cat $sshkey | $lmssh $ssh_user@$host /bin/sh -c '"mkdir -p ~/.ssh; cat >>~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys"'
   8.462 +
   8.463 +###install-lm
   8.464 +cat $lminstall | ssh $ssh_user@$host /bin/sh -s $dirs
   8.465 +
   8.466 +###copy-lablogs
   8.467 +for i in $dirs
   8.468 +do
   8.469 +	mkdir -p $lablogs/${i##*/}
   8.470 +	scp -q $ssh_user@$host:${i}/.labmaker/* $lablogs/${i##*/}
   8.471 +done
   8.472 +
   8.473 +###setlab
   8.474 +for i in $dirs
   8.475 +do
   8.476 +	echo $lab | ssh $ssh_user@$host "cat > "${i}"/.labmaker/lab"
   8.477 +done
   8.478 +
   8.479 +###makeout
   8.480 +common=$course-$date
   8.481 +personal=$course-$date-$email
   8.482 +mkdir -p $outpath/${common}/{Lablogs,Docs}
   8.483 +mkdir -p $outpath/${personal}/{Course,Files}
   8.484 +cd $outpath/${personal}
   8.485 +ln -s ../${common}/Lablogs .
   8.486 +ln -s ../${common}/Docs .
   8.487 +cd ~-
   8.488 +export UG_PERSONAL=${PWD}/$outpath/${personal}/Course
   8.489 +export UG_CENTER="$center"
   8.490 +export UG_COURSE="$course"
   8.491 +export UG_DATE="$date"
   8.492 +export UG_STUDENT="$name"
   8.493 +export UG_COMPANY="$company"
   8.494 +cd $coursepath; make personal; cd ~-
   8.495 +
   8.496 +###watch
   8.497 +cat taillast.pl | ssh $ssh_user@$host perl - /root/.labmaker
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/lm-install	Sun May 22 16:29:55 2005 +0300
     9.3 @@ -0,0 +1,227 @@
     9.4 +#!/bin/sh
     9.5 +
     9.6 +# Use -d to deinstall labmaker
     9.7 +# You can specify directory list to install LabMaker as command line parameters
     9.8 +# or set it in $users_to_install variable
     9.9 +
    9.10 +# CONFIGURABLE SECTION start
    9.11 +#users_to_install="/home/your-user-here /root"
    9.12 +# CONFIGURABLE SECTION stop
    9.13 +
    9.14 +first_lab=T1
    9.15 +editors_to_install='/bin/vi /usr/bin/vi /usr/bin/vim /bin/ee /usr/bin/ee /usr/bin/pico /usr/bin/nano /usr/local/bin/vim'
    9.16 +temp_file=/tmp/lm-install-$$
    9.17 +arg=$@
    9.18 +
    9.19 +show_usage()
    9.20 +{
    9.21 +	cat << USAGE 
    9.22 +
    9.23 +$0 [-d] path...
    9.24 +
    9.25 +	* Use -d to deinstall labmaker
    9.26 +	* You can specify directory list to install LabMaker as command line parameters
    9.27 +	  or set it in \$users_to_install variable in the script
    9.28 +
    9.29 +Example:
    9.30 +
    9.31 +	Command
    9.32 +	# $0 /root /home/user
    9.33 +	installs labmaker to /root and /home/user directories 
    9.34 +
    9.35 +USAGE
    9.36 +}
    9.37 +
    9.38 +install_to_profile()
    9.39 +{
    9.40 +	profile=$1
    9.41 +	cat $profile \
    9.42 +		| sed '/LabMaker:START/,/LabMaker:END/ d' \
    9.43 +		> $temp_file
    9.44 +	cat <<'LM_bash_profile' >> $temp_file
    9.45 +	# LabMaker:START
    9.46 +	#LMHOME=~/.labmaker
    9.47 +	#mkdir -p ${LMHOME}
    9.48 +	#TTY=`tty`
    9.49 +	#flush="-f"
    9.50 +	#exec script $flush -q $LMHOME/${TTY##*/}-$$.script
    9.51 +	# LabMaker:END
    9.52 +LM_bash_profile
    9.53 +	cat $temp_file > $profile
    9.54 +	rm $temp_file
    9.55 +}
    9.56 +
    9.57 +uninstall_from_profile()
    9.58 +{
    9.59 +	profile=$1
    9.60 +	cat $profile \
    9.61 +		| sed '/LabMaker:START/,/LabMaker:END/ d' \
    9.62 +		> $temp_file
    9.63 +	cat $temp_file > $profile
    9.64 +	rm $temp_file
    9.65 +}
    9.66 +
    9.67 +install_to_bashrc()
    9.68 +{
    9.69 +	profile=$1
    9.70 +	cat $profile \
    9.71 +		| sed '/LabMaker:START/,/LabMaker:END/ d' \
    9.72 +		> $temp_file
    9.73 +	cat <<'LM_bash_profile' >> $temp_file
    9.74 +	# LabMaker:START
    9.75 +	TTY=`tty` 
    9.76 +
    9.77 +	this_term=`w | grep "${TTY##/dev/}" | awk '{print $8;}'`
    9.78 +	# freeBSD: 
    9.79 +	this_term=`w | grep "${TTY##/dev/tty}" | awk '{print $6;}'`
    9.80 +	if [ -n "$this_term" ] && echo $this_term | grep -qv script
    9.81 +	then	
    9.82 +		LMHOME=~/.labmaker
    9.83 +		mkdir -p ${LMHOME}
    9.84 +		flush="-f"	#linux
    9.85 +		flush="-t 0"	#freebsd
    9.86 +		exec script $flush -q $LMHOME/${TTY##*/}-$$.script
    9.87 +	fi
    9.88 +	PS1='\[`	a="$?";
    9.89 +		HIDDEN=$([ "$a" = 0 ] || echo -n ^"$a")$(echo -n _${UID}_)$(echo -n _$$_)$(date\
    9.90 +			+"%j$(cat ~/.labmaker/lab 2>/dev/null) %H:%M:%S");
    9.91 +		echo $HIDDEN`\033[50D\033[K\][\u@\h:\W]\$ '
    9.92 +	# LabMaker:END
    9.93 +LM_bash_profile
    9.94 +	cat $temp_file > $profile
    9.95 +	rm $temp_file
    9.96 +}
    9.97 +
    9.98 +uninstall_from_bashrc()
    9.99 +{
   9.100 +	profile=$1
   9.101 +	cat $profile \
   9.102 +		| sed '/LabMaker:START/,/LabMaker:END/ d' \
   9.103 +		> $temp_file
   9.104 +	cat $temp_file > $profile
   9.105 +	rm $temp_file
   9.106 +}
   9.107 +
   9.108 +install_editor()
   9.109 +{
   9.110 +editor=$1
   9.111 +[ -e $editor.orig ] && cp $editor.orig $editor
   9.112 +cp $editor $editor.orig
   9.113 +cat <<'editor_wrapper' | sed "s@EDITOR@$editor@" > $editor
   9.114 +#!/bin/sh
   9.115 +
   9.116 +LMHOME=~/.labmaker
   9.117 +if [ "${1#-}" = "$1" -a -d "$LMHOME" ]
   9.118 +then
   9.119 +	LAB=`cat $LMHOME/lab`
   9.120 +	TIME="`date +%j${LAB}_%H:%M:%S`"
   9.121 +	DIR=""
   9.122 +	[ "${1#/}" = "$1" ] && DIR=$PWD/
   9.123 +	DIFFNAME=$PPID_${TIME}_`echo $DIR$1| sed s@_@__@ | sed 's@/@_@g'`.diff
   9.124 +	tmp="/tmp/lm-saved-$$"
   9.125 +	touch $1
   9.126 +	cp -- "$1" $tmp 2> /dev/null
   9.127 +	EDITOR.orig "$@" || ERR=1
   9.128 +	diff $tmp $1 > $LMHOME/$DIFFNAME 2> /dev/null
   9.129 +	rm $tmp 2> /dev/null
   9.130 +	if [ "$ERR" = 1 ]
   9.131 +	then
   9.132 +		false
   9.133 +	else
   9.134 +		true
   9.135 +	fi	
   9.136 +else
   9.137 +	exec EDITOR.orig "$@"
   9.138 +fi
   9.139 +editor_wrapper
   9.140 +
   9.141 +}
   9.142 +
   9.143 +
   9.144 +uninstall_editor()
   9.145 +{
   9.146 +	editor=$1
   9.147 +	[ -e $editor.orig ] && mv $editor.orig $editor
   9.148 +}
   9.149 +
   9.150 +if [ "$1" != "-d" ] 
   9.151 +then 
   9.152 +	# INSTALLING LM
   9.153 +	if [ $# -gt 0 ] 
   9.154 +	then
   9.155 +		users_to_install="$*"
   9.156 +	fi
   9.157 +
   9.158 +	if [ -z "$users_to_install" ]
   9.159 +	then 
   9.160 +		show_usage
   9.161 +		exit
   9.162 +	fi	
   9.163 +
   9.164 +	for user in $users_to_install
   9.165 +	do 
   9.166 +		home=$user		# fix this!
   9.167 +		mkdir -p $home/.labmaker
   9.168 +		echo $first_lab > $home/.labmaker/lab
   9.169 +		chown -R ${user##*/} $home/.labmaker
   9.170 +
   9.171 +		if [ ! -e $home/.bash_profile ] 
   9.172 +		then
   9.173 +			echo '. ~/.bashrc' >> ~/.bash_profile
   9.174 +		fi
   9.175 +		[ -e $home/.bash_profile ] \
   9.176 +			&& install_to_profile $home/.bash_profile \
   9.177 +			&& echo LabMaker is installed to $home/.bash_profile
   9.178 +
   9.179 +		[ -e $home/.profile ] && install_to_profile $home/.profile \
   9.180 +			&& install_to_profile $home/.profile \
   9.181 +			&& echo LabMaker is installed to $home/.profile
   9.182 +
   9.183 +		touch $home/.bashrc
   9.184 +		[ -e $home/.bashrc ] && install_to_bashrc $home/.bashrc \
   9.185 +			&& install_to_bashrc $home/.bashrc \
   9.186 +			&& echo LabMaker is installed to $home/.bashrc
   9.187 +	done
   9.188 +
   9.189 +	for editor in $editors_to_install
   9.190 +	do
   9.191 +		[ -e $editor ] \
   9.192 +			&& install_editor $editor \
   9.193 +			&& echo LabMaker is installed to $editor
   9.194 +	done
   9.195 +else
   9.196 +# UNINSTALLING LM
   9.197 +	shift
   9.198 +	users_to_install="$*"
   9.199 +	for user in $users_to_install
   9.200 +	do 
   9.201 +		home=$user		
   9.202 +		mkdir -p $home/.labmaker
   9.203 +		echo $first_lab > $home/.labmaker/lab
   9.204 +		chown -R ${user##*/} $home/.labmaker
   9.205 +
   9.206 +		if [ ! -e $home/.bash_profile ] 
   9.207 +		then
   9.208 +			echo '. ~/.bashrc' >> ~/.bash_profile
   9.209 +		fi
   9.210 +		[ -e $home/.bash_profile ] \
   9.211 +			&& uninstall_from_profile $home/.bash_profile \
   9.212 +			&& echo LabMaker is uninstalled from $home/.bash_profile
   9.213 +
   9.214 +		[ -e $home/.profile ] && uninstall_from_profile $home/.profile \
   9.215 +			&& uninstall_from_profile $home/.profile \
   9.216 +			&& echo LabMaker is uninstalled from $home/.profile
   9.217 +
   9.218 +		touch $home/.bashrc
   9.219 +		[ -e $home/.bashrc ] && uninstall_from_bashrc $home/.bashrc \
   9.220 +			&& uninstall_from_bashrc $home/.bashrc \
   9.221 +			&& echo LabMaker is uninstalled from $home/.bashrc
   9.222 +	done
   9.223 +
   9.224 +	for editor in $editors_to_install
   9.225 +	do
   9.226 +		[ -e $editor ] \
   9.227 +			&& uninstall_editor $editor \
   9.228 +			&& echo LabMaker is uninstalled from $editor
   9.229 +	done
   9.230 +fi	
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/lm-report	Sun May 22 16:29:55 2005 +0300
    10.3 @@ -0,0 +1,912 @@
    10.4 +#!/usr/bin/perl -w
    10.5 +
    10.6 +#
    10.7 +# (c) Igor Chubin, imchubin@mail.ru, 2004
    10.8 +#
    10.9 +
   10.10 +use strict;
   10.11 +use Getopt::Long;
   10.12 +use Term::VT102;
   10.13 +use Text::Iconv;
   10.14 +use Data::Dumper;
   10.15 +
   10.16 +our $Config_File = "labmaker.conf";
   10.17 +our %Config = (
   10.18 +		"skip_empty" 			=> 	"yes",
   10.19 +		"skip_interrupted" 		=>	"no",
   10.20 +		"skip_wrong" 			=>	"no",
   10.21 +		"editors"			=>	["vi", "pico", "ee", "vim"],
   10.22 +		"pagers"			=>	["more", "less", "zmore", "zless", "info", 
   10.23 +							"man", "mc", "trafshow", "screen", "cfdisk",
   10.24 +							"trafshow-bsd", "yes", "lynx", "links", "centericq"
   10.25 +							],
   10.26 +		"terminal"			=>	["mc"],
   10.27 +		"suppress_editors"		=>	"yes",
   10.28 +		"suppress_pagers"		=>	"yes",
   10.29 +		"suppress_terminal"		=>	"yes",
   10.30 +
   10.31 +		"terminal_width"		=> 	100,
   10.32 +		"terminal_height"		=> 	100,
   10.33 +		"verbose"			=>	"yes",
   10.34 +
   10.35 +		"head_lines"			=> 	5,
   10.36 +		"tail_lines"			=>	5,
   10.37 +		"skip_text"			=>	"...",
   10.38 +		"show_time"			=>	"yes",
   10.39 +		"show_diffs"			=>	"yes",
   10.40 +		"show_comments"			=>	"yes",
   10.41 +
   10.42 +		"input"				=>	"/root/.labmaker",
   10.43 +		"diffs"				=>	"",
   10.44 +		"input_mask"			=>	"*.script",
   10.45 +		"encoding"			=> 	"utf-8",
   10.46 +
   10.47 +		"output"			=>	"/var/www/lm/reportINDEX.html",
   10.48 +		#"output"			=>	"report.xml",
   10.49 +		"output_mask"			=>	"INDEX",
   10.50 +		"output_format"			=>	"html",
   10.51 +
   10.52 +		"signature"			=>	"#lm:",
   10.53 +		"from"				=>	"",
   10.54 +		"to"				=>	"",
   10.55 +		"lab"				=>	"",
   10.56 +		"keywords"			=>	"linux command",
   10.57 +		"files_keywords"		=>	"linux file",
   10.58 +		
   10.59 +		comment_width			=>	"300",
   10.60 +		time_width			=>	"60",
   10.61 +
   10.62 +		);
   10.63 +
   10.64 +our @Command_Lines;
   10.65 +our @Command_Lines_Index;
   10.66 +our @Diffs;
   10.67 +
   10.68 +our %Commands_Stat;		# Statistics about commands usage
   10.69 +our %Files_Stat;		# Statistics about commands usage
   10.70 +
   10.71 +our %Search_Machines = (
   10.72 +		"google" => 	{ 	"query" => 	"http://www.google.com/search?q=" ,
   10.73 +					"icon" 	=> 	"google.ico" },
   10.74 +		"freebsd" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=",
   10.75 +					"icon"	=>	"freebsd.ico" },
   10.76 +		"linux"  => 	{ 	"query" => 	"http://man.he.net/?topic=",
   10.77 +					"icon"	=>	"linux.ico"},
   10.78 +		"opennet"  => 	{ 	"query" => 	"http://www.opennet.ru/search.shtml?words=",
   10.79 +					"icon"	=>	"opennet.ico"},
   10.80 +		"local" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=",
   10.81 +					"icon"	=>	"freebsd.ico" },
   10.82 +
   10.83 +	);
   10.84 +
   10.85 +our %Elements_Visibility = (
   10.86 +		"note"		=>	"замечания",
   10.87 +		"diff"		=>	"редактор",
   10.88 +		"time"		=>	"время",
   10.89 +		"ttychange" 	=>	"терминал",
   10.90 +		"wrong_output wrong_cline wrong_root_output wrong_root_cline" 
   10.91 +				=>	"команды с ошибками",
   10.92 +		"interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" 
   10.93 +				=>	"прерванные команды",
   10.94 +		"tab_completion_output tab_completion_cline"	
   10.95 +				=> 	"продолжение с помощью tab"
   10.96 +);
   10.97 +
   10.98 +
   10.99 +sub load_diff_files
  10.100 +{
  10.101 +	my @pathes = @_;
  10.102 +	
  10.103 +	for my $path (@pathes) {
  10.104 +		my $template = "*.diff";
  10.105 +		my @files = <$path/$template>;
  10.106 +		my $i=0;
  10.107 +		for my $file (@files) {
  10.108 +			my %diff;
  10.109 +			
  10.110 +			$diff{"path"}=$path;
  10.111 +			$diff{"uid"}="SET THIS";
  10.112 +
  10.113 +# Сейчас UID определяется из названия каталога
  10.114 +# откуда берутся diff-файлы
  10.115 +# Это неправильно
  10.116 +#
  10.117 +# ВАРИАНТ:
  10.118 +# К файлам жураналам должны прилагаться ситемны файлы, 
  10.119 +# мз которых и будет определяться соответствие 
  10.120 +# имён пользователей их uid'ам
  10.121 +#
  10.122 +			$diff{"uid"} = 0 if $path =~ m@/root/@;	
  10.123 +			
  10.124 +			$diff{"bind_to"}="";
  10.125 +			$diff{"time_range"}=-1;
  10.126 +		
  10.127 +			next if not $file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@;
  10.128 +			$diff{"day"}=$1 || "";
  10.129 +			$diff{"hour"}=$2;
  10.130 +			$diff{"min"}=$3;
  10.131 +			$diff{"sec"}=$4 || 0;
  10.132 +			
  10.133 +			$diff{"index"}=$i;
  10.134 +
  10.135 +			print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n";
  10.136 +			
  10.137 +			local $/;
  10.138 +			open (F, "$file")
  10.139 +				or return "Can't open file $file ($_[0]) for reading";
  10.140 +			my $text = <F>;
  10.141 +			if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) {
  10.142 +				my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8");
  10.143 +				$text = $converter->convert($text);
  10.144 +			}
  10.145 +			close(F);	
  10.146 +			$diff{"text"}=$text;
  10.147 +			#print "$file loaded ($diff{day})\n";
  10.148 +
  10.149 +			push @Diffs, \%diff;
  10.150 +			$i++;
  10.151 +		}
  10.152 +	}	
  10.153 +}
  10.154 +
  10.155 +
  10.156 +sub bind_diff
  10.157 +{
  10.158 +#	my $path = shift;
  10.159 +#	my $pid = shift;
  10.160 +#	my $day = shift;
  10.161 +#	my $lab = shift;
  10.162 +
  10.163 +	print "Trying to bind diff...\n";
  10.164 +
  10.165 +	my $cl = shift;
  10.166 +	my $hour = $cl->{"hour"};
  10.167 +	my $min = $cl->{"min"};
  10.168 +	my $sec = $cl->{"sec"};
  10.169 +
  10.170 +	my $min_dt = 10000;
  10.171 +
  10.172 +	for my $diff (@Diffs) {
  10.173 +			# Check here date, time and user
  10.174 +			next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"}));
  10.175 +			#next if (!$diff->{"uid"} && $cl->{"euid"} != $diff->{"uid"});
  10.176 +			
  10.177 +			my $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec);
  10.178 +			if ($dt >0  && $dt < $min_dt && ($diff->{"time_range"} <0 || $dt < $diff->{"time_range"})) {
  10.179 +				print "Approppriate diff found: dt=$dt\n";
  10.180 +				if ($diff->{"bind_to"}) {
  10.181 +					undef $diff->{"bind_to"}->{"diff"};
  10.182 +				};
  10.183 +				$diff->{"time_range"}=$dt;
  10.184 +				$diff->{"bind_to"}=$cl;
  10.185 +
  10.186 +				$cl->{"diff"} = $diff->{"index"};
  10.187 +				$min_dt = $dt;	
  10.188 +			}
  10.189 +		
  10.190 +	}
  10.191 +}
  10.192 +
  10.193 +
  10.194 +sub extract_from_cline
  10.195 +# Разобрать командную строку $_[1] и возвратить хэш, содержащий 
  10.196 +# номер первого появление команды в строке:
  10.197 +# 	команда => первая позиция
  10.198 +{
  10.199 +	my $what = $_[0];
  10.200 +	my $cline = $_[1];
  10.201 +	my @lists = split /\;/, $cline;
  10.202 +	
  10.203 +	
  10.204 +	my @commands = ();
  10.205 +	for my $list (@lists) {
  10.206 +		push @commands, split /\|/, $list;
  10.207 +	}
  10.208 +
  10.209 +	my %commands;
  10.210 +	my %files;
  10.211 +	my $i=0;
  10.212 +	for my $command (@commands) {
  10.213 +		$command =~ /\s*(\S+)\s*(.*)/;
  10.214 +		if ($1 && $1 eq "sudo" ) {
  10.215 +			$commands{"$1"}=$i++;
  10.216 +			$command =~ s/\s*sudo\s+//;
  10.217 +		}
  10.218 +		$command =~ /\s*(\S+)\s*(.*)/;
  10.219 +		if ($1 && !defined $commands{"$1"}) {
  10.220 +				$commands{"$1"}=$i++;
  10.221 +		};	
  10.222 +		if ($2) {
  10.223 +			my $args = $2;
  10.224 +			my @args = split (/\s+/, $args);
  10.225 +			for my $a (@args) {
  10.226 +				$files{"$a"}=$i++
  10.227 +					if !defined $files{"$a"};
  10.228 +			};	
  10.229 +
  10.230 +				
  10.231 +		}
  10.232 +	}
  10.233 +
  10.234 +	if ($what eq "commands") {
  10.235 +		return %commands;
  10.236 +	} else {
  10.237 +		return %files;
  10.238 +	}
  10.239 +	
  10.240 +}
  10.241 +
  10.242 +sub load_command_lines
  10.243 +{
  10.244 +	my $lab_scripts_path = $_[0];
  10.245 +	my $lab_scripts_mask = $_[1];
  10.246 +
  10.247 +	my $cline_re_base = qq'
  10.248 +			(?:\\^?([0-9]*C?))					# exitcode
  10.249 +			(?:_([0-9]+)_)?				# uid
  10.250 +			(?:_([0-9]+)_)				# pid
  10.251 +			(...?)					# day
  10.252 +			(..)					# lab
  10.253 +			\\s					# space separator
  10.254 +			([0-9][0-9]):([0-9][0-9]):([0-9][0-9])	# time
  10.255 +			.\\[50D.\\[K				# killing symbols
  10.256 +			(.*?([\$\#]\\s?))			# prompt
  10.257 +			(.*)					# command line
  10.258 +			';
  10.259 +	#my $cline_re = qr/$cline_re_base(?:$cline_re_base|$)/x;
  10.260 +	#my $cline_re = qr/(?:$cline_re_base)*$cline_re_base$/x;
  10.261 +	my $cline_re = qr/$cline_re_base/sx;
  10.262 +	my $cline_re1 = qr/$cline_re_base\x0D/sx;
  10.263 +	my $cline_re2 = qr/$cline_re_base$/sx;
  10.264 +
  10.265 +	my $vt = Term::VT102->new (	'cols' => $Config{"terminal_width"}, 
  10.266 +					'rows' => $Config{"terminal_height"});
  10.267 +	my $cline_vt = Term::VT102->new ('cols' => $Config{"terminal_width"}, 
  10.268 +					'rows' => $Config{"terminal_height"});
  10.269 +
  10.270 +	my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8")
  10.271 +		if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i);
  10.272 +		
  10.273 +	print "Loading lm-scripts...\n" if $Config{"verbose"} =~ /y/;
  10.274 +
  10.275 +	my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>;
  10.276 +	my $file;
  10.277 +	my $files_number = $#lab_scripts;
  10.278 +	my $ii = 0;
  10.279 +	my $skip_info;
  10.280 +
  10.281 +	my $commandlines_loaded =0;
  10.282 +	my $commandlines_processed =0;
  10.283 +
  10.284 +	for $file (@lab_scripts){
  10.285 +		#printf "\t%i %3.2f\n", $ii, (100*$ii++/$files_number) if $Config{"verbose"} =~ /y/;
  10.286 +
  10.287 +		open (FILE, "$file");
  10.288 +		binmode FILE;
  10.289 +		$file =~ m@.*/(.*?)-.*@;
  10.290 +		
  10.291 +		my $tty = $1;
  10.292 +		my $first_pass = 1;
  10.293 +		my %cl;
  10.294 +		my $last_output_length=0;
  10.295 +		while (<FILE>) {
  10.296 +			$commandlines_processed++;
  10.297 +				# time
  10.298 +
  10.299 +			if (/[0-9][0-9]:[0-9][0-9]:[0-9][0-9].\[[0-9][0-9]D.\[K/ && m/$cline_re/) {
  10.300 +				s/.*\x0d(?!\x0a)//;
  10.301 +		#		print "!!!",$_,"!!!\n";
  10.302 +			#	next;
  10.303 +			#	while (m/$cline_re1/gs) {
  10.304 +			#	}
  10.305 +				m/$cline_re2/gs;
  10.306 +
  10.307 +				$commandlines_loaded++;
  10.308 +				$last_output_length=0;
  10.309 +
  10.310 +				# Previous command
  10.311 +				my %last_cl = %cl;
  10.312 +				my $err = $1 || "";
  10.313 +
  10.314 +				# Parse new command 
  10.315 +				$cl{"uid"} = $2;
  10.316 +				$cl{"euid"} = $cl{"uid"};	# Если в команде обнаружится sudo, euid поменяем на 0
  10.317 +				$cl{"pid"} = $3;
  10.318 +				$cl{"day"} = $4;
  10.319 +				$cl{"lab"} = $5;
  10.320 +				$cl{"hour"} = $6;
  10.321 +				$cl{"min"} = $7;
  10.322 +				$cl{"sec"} = $8;
  10.323 +				$cl{"fullprompt"} = $9;
  10.324 +				$cl{"prompt"} = $10;
  10.325 +				$cl{"raw_cline"} = $11;	
  10.326 +
  10.327 +				$cl{"err"} = 0;
  10.328 +				$cl{"output"} = "";
  10.329 +				$cl{"tty"} = $tty;
  10.330 +
  10.331 +				$cline_vt->process($cl{"raw_cline"}."\n");
  10.332 +				$cl{"cline"} = $cline_vt->row_plaintext (1);
  10.333 +				$cl{"cline"} =~ s/\s*$//;
  10.334 +				$cline_vt->reset();
  10.335 +
  10.336 +				my %commands = extract_from_cline("commands", $cl{"cline"});
  10.337 +				$cl{"euid"}=0 if defined $commands{"sudo"};
  10.338 +				my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands; 
  10.339 +				$cl{"last_command"} = $comms[$#comms] || ""; 
  10.340 +		
  10.341 +				if (
  10.342 +				$Config{"suppress_editors"} =~ /^y/i 
  10.343 +					&& grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}}) ||
  10.344 +				$Config{"suppress_pagers"}  =~ /^y/i 
  10.345 +					&& grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}}) ||
  10.346 +				$Config{"suppress_terminal"}=~ /^y/i 
  10.347 +					&& grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}})
  10.348 +				) {
  10.349 +					$cl{"suppress_output"} = "1";
  10.350 +				}
  10.351 +				else {
  10.352 +					$cl{"suppress_output"} = "0";
  10.353 +					
  10.354 +				}
  10.355 +				$skip_info = 0;
  10.356 +
  10.357 +
  10.358 +				print " ",$cl{"last_command"};
  10.359 +
  10.360 +				# Processing previous command line
  10.361 +				if ($first_pass) {
  10.362 +					$first_pass = 0;
  10.363 +					next;
  10.364 +				}
  10.365 +
  10.366 +				# Error code
  10.367 +				$last_cl{"err"}=$err;
  10.368 +				$last_cl{"err"}=130 if $err eq "^C";
  10.369 +
  10.370 +				if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) {
  10.371 +					bind_diff(\%last_cl);
  10.372 +				}
  10.373 +
  10.374 +				# Output
  10.375 +				if (!$last_cl{"suppress_output"} || $last_cl{"err"}) {
  10.376 +					for (my $i=0; $i<$Config{"terminal_height"}; $i++) {
  10.377 +						my $line= $vt->row_plaintext($i);
  10.378 +						next if !defined ($line) || $line =~ /^\s*$/;
  10.379 +						$line =~ s/\s*$//;
  10.380 +						$last_cl{"output"} .= $line."\n";
  10.381 +					}
  10.382 +				}
  10.383 +				else {
  10.384 +					$last_cl{"output"}= "";
  10.385 +				}
  10.386 +
  10.387 +				$vt->reset();
  10.388 +
  10.389 +
  10.390 +				# Classifying the command line
  10.391 +
  10.392 +
  10.393 +				# Save 
  10.394 +				if (!$Config{"lab"} || $cl{"lab"} eq $Config{"lab"}) {
  10.395 +					# Changing encoding 
  10.396 +					for (keys %last_cl) {
  10.397 +						$last_cl{$_} = $converter->convert($last_cl{$_})
  10.398 +							if ($Config{"encoding"} && 
  10.399 +							$Config{"encoding"} !~ /^utf-8$/i);
  10.400 +					}
  10.401 +					push @Command_Lines, \%last_cl;	
  10.402 +				}	
  10.403 +				next;
  10.404 +			}
  10.405 +			$last_output_length+=length($_);
  10.406 +			#if (!$cl{"suppress_output"} || $last_output_length < 5000) {
  10.407 +			if ($last_output_length < 5000) {
  10.408 +				#print "(",length($_),")" if (length($_) > 2000) ;
  10.409 +				$vt->process("$_"."\n") 
  10.410 +			}
  10.411 +			else
  10.412 +			{
  10.413 +				if (!$skip_info) {
  10.414 +					print "($cl{last_command})";
  10.415 +					$skip_info = 1;
  10.416 +				}
  10.417 +			}
  10.418 +		}	
  10.419 +		close(FILE);
  10.420 +
  10.421 +	}
  10.422 +	if ($Config{"verbose"} =~ /y/) {
  10.423 +		print "...finished." ;
  10.424 +		print "Lines loaded: $commandlines_processed\n";
  10.425 +		print "Command lines: $commandlines_loaded\n";
  10.426 +	}
  10.427 +}
  10.428 +
  10.429 +sub search_by
  10.430 +{
  10.431 +	my $sm = shift;
  10.432 +	my $topic = shift;
  10.433 +	$topic =~ s/ /+/;
  10.434 +	
  10.435 +	return "<a href='".	$Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='".
  10.436 +				$Search_Machines{$sm}->{"icon"}."' border='0'/></a>";
  10.437 +}
  10.438 +
  10.439 +sub make_comment
  10.440 +{
  10.441 +	my $commands = $_[0];
  10.442 +	my $files = $_[1];
  10.443 +	chomp $commands;
  10.444 +	chomp $files;
  10.445 +	return if (!$commands && !$files);
  10.446 +
  10.447 +	my $comment=""; 
  10.448 +
  10.449 +	# Commands
  10.450 +	for my $command (split /\s+/,$commands) {
  10.451 +		$command =~ s/'//g;
  10.452 +		my $description="";
  10.453 +		eval { $description=`mywi-client '$command'`; } ;
  10.454 +		$description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description)));
  10.455 +		$description =~ s/.*?-//;
  10.456 +		next if $description =~ /^\s*$/; 
  10.457 +		
  10.458 +		my $query=$command." ".$Config{"keywords"};
  10.459 +		$query =~ s/\ /+/g;
  10.460 +		my $search= 	search_by("opennet",$query).
  10.461 +				search_by("local",$command).
  10.462 +				search_by("google",$query);
  10.463 +
  10.464 +		$comment .=     "<tr><td class='note_title'>$command</td>".
  10.465 +				"<td class='note_search'>$search</td>".
  10.466 +				"</tr><tr><td width='100%' colspan='2' class='note_text'>".
  10.467 +				"$description</td></tr><tr/>";
  10.468 +	}
  10.469 +	
  10.470 +	# Files
  10.471 +	for my $file (split /\s+/,$files) {
  10.472 +		$file =~ s@.*/@@;
  10.473 +		$file =~ s/'//g;
  10.474 +		next if $file =~ /^\s*$/;
  10.475 +		next if $file =~ /^-/;
  10.476 +		
  10.477 +		my $description=`mywi '$file'`;
  10.478 +		$description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description)));
  10.479 +		next if $description =~ /^\s*$/; 
  10.480 +
  10.481 +		my $query=$file." ".$Config{"files_keywords"};
  10.482 +		$query =~ s/\ /+/g;
  10.483 +		my $search= 	search_by("opennet",$query).
  10.484 +				search_by("local",$file).
  10.485 +				search_by("google",$query);
  10.486 +
  10.487 +		$comment .=     "<tr><td class='note_title'>$file</td>".
  10.488 +				"<td class='note_search'>$search</td>".
  10.489 +				"</tr><tr><td width='100%' colspan='2' class='note_text'>".
  10.490 +				"$description</td></tr><tr/>";
  10.491 +	}
  10.492 +
  10.493 +
  10.494 +	return $comment;
  10.495 +}
  10.496 +
  10.497 +sub printq
  10.498 +{
  10.499 +	my $TO = shift;
  10.500 +	my $text = join "", @_;
  10.501 +	$text =~ s/&/&amp;/g;
  10.502 +	$text =~ s/</&lt;/g;
  10.503 +	$text =~ s/>/&gt;/g;
  10.504 +	print $TO $text;
  10.505 +}
  10.506 +
  10.507 +
  10.508 +sub sort_command_lines
  10.509 +{
  10.510 +	print "Sorting command lines...\n" if $Config{"verbose"} =~ /y/;
  10.511 +
  10.512 +	# Sort Command_Lines
  10.513 +	# Write Command_Lines to Command_Lines_Index
  10.514 +
  10.515 +	my @index;
  10.516 +	for (my $i=0;$i<=$#Command_Lines;$i++) {
  10.517 +		$index[$i]=$i;
  10.518 +	}
  10.519 +
  10.520 +	@Command_Lines_Index = sort {
  10.521 +		$Command_Lines[$index[$a]]->{"day"} cmp $Command_Lines[$index[$b]]->{"day"} ||
  10.522 +		$Command_Lines[$index[$a]]->{"hour"} <=> $Command_Lines[$index[$b]]->{"hour"} ||
  10.523 +		$Command_Lines[$index[$a]]->{"min"} <=> $Command_Lines[$index[$b]]->{"min"} ||
  10.524 +		$Command_Lines[$index[$a]]->{"sec"} <=> $Command_Lines[$index[$b]]->{"sec"}
  10.525 +	} @index;
  10.526 +
  10.527 +	print "...finished\n" if $Config{"verbose"} =~ /y/;
  10.528 +
  10.529 +}
  10.530 +
  10.531 +sub process_command_lines
  10.532 +{
  10.533 +	my $lab_scripts_path = $_[0];
  10.534 +	
  10.535 +	for my $i (@Command_Lines_Index) {
  10.536 +
  10.537 +		my $cl = \$Command_Lines[$i];
  10.538 +		@{${$cl}->{"new_commands"}} =();
  10.539 +		@{${$cl}->{"new_files"}} =();
  10.540 +		$$cl->{"class"} = ""; 
  10.541 +
  10.542 +		if ($$cl->{"err"}) {
  10.543 +			$$cl->{"class"}="wrong";
  10.544 +			$$cl->{"class"}="interrupted"
  10.545 +				if ($$cl->{"err"} eq 130);
  10.546 +		}	
  10.547 +		if (!$$cl->{"euid"}) {
  10.548 +			$$cl->{"class"}.="_root";
  10.549 +		}
  10.550 +		
  10.551 +#tab#		my @tab_words=split /\s+/, $$cl->{"output"};
  10.552 +#tab#		my $last_word= $$cl->{"cline"} =~ /(\S*)$/;
  10.553 +#tab#		$last_word =~ s@.*/@@;
  10.554 +#tab#		my $this_is_tab=1;
  10.555 +#tab#
  10.556 +#tab#		if ($last_word && @tab_words >2) {
  10.557 +#tab#			for my $tab_words (@tab_words) {
  10.558 +#tab#				if ($tab_words !~ /^$last_word/) {
  10.559 +#tab#					$this_is_tab=0;
  10.560 +#tab#					last;
  10.561 +#tab#				}
  10.562 +#tab#			}
  10.563 +#tab#		}	
  10.564 +#tab#		$$cl->{"class"}="tab" if $this_is_tab;
  10.565 +		
  10.566 +
  10.567 +		if ( !$$cl->{"err"}) {
  10.568 +			# Command does not contain mistakes
  10.569 +			
  10.570 +			my %commands = extract_from_cline("commands", ${$cl}->{"cline"});
  10.571 +			my %files = extract_from_cline("files", ${$cl}->{"cline"});
  10.572 +
  10.573 +			# Searching for new commands only
  10.574 +			for my $command (keys  %commands) {
  10.575 +				if (!defined $Commands_Stat{$command}) {
  10.576 +					push @{$$cl->{new_commands}}, $command;
  10.577 +				}	
  10.578 +				$Commands_Stat{$command}++;
  10.579 +			}
  10.580 +			
  10.581 +			for my $file (keys  %files) {
  10.582 +				if (!defined $Files_Stat{$file}) {
  10.583 +					push @{$$cl->{new_files}}, $file;
  10.584 +				}	
  10.585 +				$Files_Stat{$file}++;
  10.586 +			}
  10.587 +		}	
  10.588 +	}	
  10.589 +
  10.590 +}
  10.591 +
  10.592 +sub print_command_lines
  10.593 +{
  10.594 +	my $output_filename=$_[0];
  10.595 +	my $format = $Config{"output_format"};
  10.596 +	
  10.597 +	open(OUT, ">", $output_filename)
  10.598 +		or die "Can't open $output_filename for writing\n";
  10.599 +
  10.600 +
  10.601 +
  10.602 +	if ($format eq "html") {
  10.603 +	# vvvv HTML Header 
  10.604 +		print OUT <<HEADER;
  10.605 +		<html>
  10.606 +		<head>
  10.607 +		<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
  10.608 +		<link rel='stylesheet' href='labmaker.css' type='text/css'/>
  10.609 +		</head>
  10.610 +		<body>
  10.611 +		<script>
  10.612 +		function getElementsByClassName(Class_Name)
  10.613 +		{
  10.614 +			var Result=new Array();
  10.615 +			var All_Elements=document.all || document.getElementsByTagName('*');
  10.616 +			for (i=0; i<All_Elements.length; i++)
  10.617 +				if (All_Elements[i].className==Class_Name)
  10.618 +			Result.push(All_Elements[i]);
  10.619 +			return Result;
  10.620 +		}
  10.621 +		function ShowHide (name)
  10.622 +		{
  10.623 +			elements=getElementsByClassName(name);
  10.624 +			for(i=0; i<elements.length; i++)
  10.625 +				if (elements[i].style.display == "none")
  10.626 +					elements[i].style.display = "";
  10.627 +				else
  10.628 +					elements[i].style.display = "none";
  10.629 +				//if (elements[i].style.visibility == "hidden")
  10.630 +				//	elements[i].style.visibility = "visible";
  10.631 +				//else
  10.632 +				//	elements[i].style.visibility = "hidden";
  10.633 +		}
  10.634 +		function filter_by_output(text)
  10.635 +		{
  10.636 +			
  10.637 +			var jjj=0;
  10.638 +			
  10.639 +			elements=getElementsByClassName('command');
  10.640 +			for(i=0; i<elements.length; i++) {
  10.641 +				subelems = elements[i].getElementsByTagName('pre');
  10.642 +				for(j=0; j<subelems.length; j++) {
  10.643 +					if (subelems[j].className = 'output') {
  10.644 +						var str = new String(subelems[j].nodeValue);
  10.645 +						if (jjj != 1) { 
  10.646 +							alert(str);
  10.647 +							jjj=1;
  10.648 +						}
  10.649 +						if (str.indexOf(text) >0) 
  10.650 +							subelems[j].style.display = "none";
  10.651 +						else
  10.652 +							subelems[j].style.display = "";
  10.653 +
  10.654 +					}
  10.655 +						
  10.656 +				}
  10.657 +			}		
  10.658 +
  10.659 +		}
  10.660 +		</script>
  10.661 +HEADER
  10.662 +		print OUT "<table class='visibility_form'><tr><td><form>\n";
  10.663 +		for my $element (keys %Elements_Visibility)
  10.664 +		{
  10.665 +			my @e = split /\s+/, $element;
  10.666 +			my $showhide = join "", map { "ShowHide('$_');" } @e ;
  10.667 +			print OUT "<input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>",
  10.668 +					$Elements_Visibility{$element},
  10.669 +					"</input><br>\n";
  10.670 +		}
  10.671 +		#print OUT "<input type='text' size='10' name=\"by_command\"/>".
  10.672 +		#"<input type='button' value='фильтр по командам' onclick=\"filter_by_command()\"/> <br>\n";
  10.673 +		#print OUT "<input type='text' size='10' name=\"by_output\"/>".
  10.674 +		#"<input type='button' value='фильтр по результату' ".
  10.675 +		#"onclick=\"filter_by_output(this.form.by_output.value)\"/> <br>\n";
  10.676 +
  10.677 +		print OUT "</form></td></tr></table>\n";
  10.678 +		print OUT "<table width='100%'>\n";
  10.679 +	# ^^^^ HTML Header 
  10.680 +	}
  10.681 +	else {
  10.682 +		# XML Header
  10.683 +		print OUT "<script>\n"
  10.684 +	}
  10.685 +	
  10.686 +	my $cl;
  10.687 +	my $last_tty="";
  10.688 +	my $in_range=0;
  10.689 +	for my $i (@Command_Lines_Index) {
  10.690 +
  10.691 +		$cl = $Command_Lines[$i];
  10.692 +
  10.693 +		if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) {
  10.694 +			$in_range=1;
  10.695 +			next;
  10.696 +		}
  10.697 +		if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) {
  10.698 +			$in_range=0;
  10.699 +			next;
  10.700 +		}
  10.701 +		next if ($Config{"from"} && $Config{"to"} && !$in_range) 
  10.702 +			||
  10.703 +		    	($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
  10.704 +			||
  10.705 +			($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
  10.706 +			||
  10.707 +			($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
  10.708 +		
  10.709 +		my @new_commands=@{$cl->{"new_commands"}};
  10.710 +		my @new_files=@{$cl->{"new_files"}};
  10.711 +
  10.712 +		my $cl_class="cline";
  10.713 +		my $out_class="output";
  10.714 +		if ($cl->{"class"}) {
  10.715 +			$cl_class = $cl->{"class"}."_".$cl_class;
  10.716 +			$out_class = $cl->{"class"}."_".$out_class;
  10.717 +		}
  10.718 +
  10.719 +		my $output="";
  10.720 +		if ($Config{"head_lines"} || $Config{"tail_lines"}) {
  10.721 +			# Partialy output
  10.722 +			my @lines = split '\n', $cl->{"output"};
  10.723 +			# head
  10.724 +			my $mark=1;
  10.725 +			for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) {
  10.726 +				$output .= $lines[$i]."\n";
  10.727 +			}
  10.728 +			# tail
  10.729 +			my $start=$#lines-$Config{"tail_lines"}+1;
  10.730 +			if ($start < 0) {
  10.731 +				$start=0;
  10.732 +				$mark=0;
  10.733 +			}	
  10.734 +			if ($start < $Config{"head_lines"}) {
  10.735 +				$start=$Config{"head_lines"};
  10.736 +				$mark=0;
  10.737 +			}	
  10.738 +			$output .= $Config{"skip_text"}."\n" if $mark;
  10.739 +			for (my $i=$start; $i<= $#lines; $i++) {
  10.740 +				$output .= $lines[$i]."\n";
  10.741 +			}
  10.742 +		} 
  10.743 +		else {
  10.744 +			# Full output
  10.745 +			$output .= $cl->{"output"};
  10.746 +		}	
  10.747 +		$output .= "^C\n" if ($cl->{"err"} eq "130");
  10.748 +
  10.749 +
  10.750 +# Printing out
  10.751 +
  10.752 +		# <command>
  10.753 +		print OUT $format eq "html" 
  10.754 +				? "<tr class='command'>\n"
  10.755 +				: "\n<action time='$cl->{hour}:$cl->{min}:$cl->{sec}' tty='$cl->{tty}'>\n";
  10.756 +						
  10.757 +		
  10.758 +		if ($format eq "html") {
  10.759 +			# CONSOLE CHANGE
  10.760 +			if ( $last_tty ne $cl->{"tty"}) {
  10.761 +				print OUT "<td colspan='6'><table><tr><td class='ttychange' width='140' align='center'>",$cl->{"tty"},"</td><td/></tr></table></td></tr><tr>";
  10.762 +				$last_tty=$cl->{"tty"};
  10.763 +			}
  10.764 +
  10.765 +			# TIME
  10.766 +			if ($Config{"show_time"} =~ /^y/i) {
  10.767 +				print OUT "<td valign='top' class='time' width='$Config{time_width}'><pre>",
  10.768 +					$cl->{"hour"}, ":", $cl->{"min"}, ":", $cl->{"sec"},
  10.769 +					"</td>";
  10.770 +			} else {
  10.771 +				print OUT "<td width='0'/>"
  10.772 +			}
  10.773 +		}	
  10.774 +
  10.775 +		# COMMAND
  10.776 +
  10.777 +
  10.778 +		if ($format eq "html") {
  10.779 +			print OUT "<td class='script'>\n";
  10.780 +			print OUT "<pre class='$cl_class'>\n";
  10.781 +			my $cline = $cl->{"cline"};
  10.782 +			$cline =~ s/\n//;
  10.783 +			printq(\*OUT,$cl->{"prompt"},$cl->{"cline"});
  10.784 +#			printq(\*OUT,"(sudo ".$cl->{"last_command"}.")\n") if !$cl->{"euid"};
  10.785 +			print OUT "</pre>\n";
  10.786 +		} 
  10.787 +		else {
  10.788 +			print OUT "<line class='$cl_class'>\n";
  10.789 +			print OUT "<prompt>";
  10.790 +			printq(\*OUT,$cl->{"prompt"});
  10.791 +			print OUT "</prompt>";
  10.792 +			print OUT "<command>";
  10.793 +			printq(\*OUT,$cl->{"cline"});
  10.794 +			print OUT "</command>";
  10.795 +			print OUT "\n</line>\n";
  10.796 +		}
  10.797 +
  10.798 +		my $last_command = $cl->{"last_command"};
  10.799 +		if (!( 
  10.800 +		$Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) ||
  10.801 +		$Config{"suppress_pagers"}  =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) ||
  10.802 +		$Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}})
  10.803 +			)) {
  10.804 +
  10.805 +			if ($format eq "html") {
  10.806 +				print OUT "<pre class='$out_class'>";
  10.807 +				printq(\*OUT,$output);
  10.808 +				print OUT "</pre>\n";
  10.809 +			} 
  10.810 +			else {
  10.811 +				print OUT "<output class='$out_class'>\n";
  10.812 +				printq(\*OUT,$output);
  10.813 +				print OUT "</output>\n";
  10.814 +			}
  10.815 +		}	
  10.816 +
  10.817 +		# DIFF
  10.818 +		if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) {
  10.819 +			if ($format eq "html") {
  10.820 +				#print Dumper(%{$cl->{"diff"}});
  10.821 +				print OUT "<table><tr><td width='5'/><td class='diff'><pre>";
  10.822 +				printq(\*OUT,${$Diffs[$cl->{"diff"}]}{"text"});
  10.823 +				print OUT "</pre></td></tr></table>";
  10.824 +			}
  10.825 +			else {
  10.826 +				print OUT "<diff>\n";
  10.827 +				printq(\*OUT,${$Diffs[$cl->{"diff"}]}{"text"});
  10.828 +				print OUT "</diff>\n";
  10.829 +			}
  10.830 +		}
  10.831 +
  10.832 +		# COMMENT
  10.833 +		if ( $Config{"show_comments"} =~ /^y/i) {
  10.834 +			my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files));
  10.835 +			if ($comment) {
  10.836 +				if ($format eq "html") {
  10.837 +					print OUT "<table width='$Config{comment_width}'>".
  10.838 +							"<tr><td width='5'/><td>";
  10.839 +					print OUT "<table class='note' width='100%'>";
  10.840 +					print OUT $comment;
  10.841 +					print OUT "</table>\n";
  10.842 +					print OUT "</td></tr></table>";
  10.843 +				}
  10.844 +			#	else {
  10.845 +			#		print OUT "<comment>";
  10.846 +			#		printq(\*OUT,$comment);
  10.847 +			#		print OUT "</comment>";
  10.848 +			#	}
  10.849 +			}
  10.850 +		}
  10.851 +
  10.852 +		if ($format eq "html") {
  10.853 +			print OUT "</td>\n";
  10.854 +			print OUT "</tr>\n";
  10.855 +		}
  10.856 +		else {
  10.857 +			print OUT "</action>\n";
  10.858 +		}
  10.859 +		
  10.860 +	}
  10.861 +	if ($format eq "html") {
  10.862 +		print OUT "</table>\n";
  10.863 +		print OUT "</body>\n";
  10.864 +		print OUT "</html>\n";
  10.865 +	} 
  10.866 +	else {
  10.867 +		print OUT "</script>\n";
  10.868 +	}
  10.869 +	close(OUT);
  10.870 +}
  10.871 +
  10.872 +sub read_config_file
  10.873 +{
  10.874 +	my $config = $_[0];
  10.875 +	my $filename = $_[1];
  10.876 +	open(CONFIG, "$filename")
  10.877 +		or return;
  10.878 +	while (<CONFIG>) {
  10.879 +		s/#.*//;
  10.880 +		next if /^\s*$/;
  10.881 +		my ($var, $val) =  split /\s*=\s*/, $_, 2;
  10.882 +		$var =~ s/\s*//;
  10.883 +		$config->{$var} = $val;
  10.884 +	}
  10.885 +	close(CONFIG);
  10.886 +}
  10.887 +
  10.888 +$| = 1;
  10.889 +
  10.890 +my %file_config;
  10.891 +my %argv_config;
  10.892 +read_config_file(\%file_config, $Config_File);
  10.893 +GetOptions(\%argv_config, map "$_=s", keys %Config);
  10.894 +%Config = (%Config, %file_config, %argv_config);
  10.895 +
  10.896 +
  10.897 +my $i=0;
  10.898 +
  10.899 +for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) 
  10.900 +{
  10.901 +	load_diff_files($lab_log);
  10.902 +}
  10.903 +
  10.904 +for my $lab_log (split /\s+/, $Config{"input"}) 
  10.905 +{
  10.906 +	my $tofile=$Config{"output"};
  10.907 +	$tofile =~ s/$Config{"output_mask"}/$i/;
  10.908 +	#load_diff_files($lab_log);
  10.909 +	load_command_lines($lab_log, $Config{"input_mask"});
  10.910 +	sort_command_lines;
  10.911 + 	process_command_lines($lab_log);
  10.912 +	print_command_lines($tofile);
  10.913 +	$i++;
  10.914 +}
  10.915 +
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/lm-ssh	Sun May 22 16:29:55 2005 +0300
    11.3 @@ -0,0 +1,31 @@
    11.4 +#!/bin/sh
    11.5 +#\
    11.6 +exec expect -- "$0" ${1+"$@"}
    11.7 +eval spawn ssh $argv
    11.8 +set timeout 1
    11.9 +expect {
   11.10 +	eof { 
   11.11 +	}
   11.12 +	"(yes/no)? " {
   11.13 +		send "yes\n"
   11.14 +		exp_continue 
   11.15 +	}
   11.16 +	assword: {
   11.17 +		send "rootpass\n"
   11.18 +	}
   11.19 +	timeout {
   11.20 +		interact -nobuffer
   11.21 +	}
   11.22 +}
   11.23 +expect {	
   11.24 +	eof { 
   11.25 +	}
   11.26 +	assword: {
   11.27 +		send "rootpass\n"
   11.28 +	}
   11.29 +
   11.30 +	timeout {
   11.31 +		interact -nobuffer
   11.32 +	}
   11.33 +}	
   11.34 +
    12.1 Binary file share/freebsd.ico has changed
    13.1 Binary file share/google.ico has changed
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/share/labmaker.css	Sun May 22 16:29:55 2005 +0300
    14.3 @@ -0,0 +1,89 @@
    14.4 +.cline,.wrong_cline,.interrupted_cline,.output,.wrong_output,.interrupted_output,.tab_cline, ._root_cline,.wrong_root_cline,.interrupted_root_cline,._root_output,.wrong_root_output,.interrupted_root_output,.tab_root_cline
    14.5 +		{ 
    14.6 +        		margin		: 0px 0px 0px 0px;
    14.7 +        		padding		: 0px 0px 0px 10px; 
    14.8 +			vertical-align	: top;
    14.9 +								}
   14.10 +.cline,.wrong_cline,.interrupted_cline,.tab_cline,._root_cline,.wrong_root_cline,.interrupted_root_cline,.tab_root_cline
   14.11 +		{ 	font-weight	: bold;			}
   14.12 +.wrong_output,.wrong_root_output	
   14.13 +		{ 	color		: #cc6666;		}
   14.14 +.interrupted_output,.interrupted_root_output
   14.15 +		{ 	color		: #aaaaaa;		}
   14.16 +.wrong_cline, .wrong_root_cline	
   14.17 +		{ 	color		: #ee7777; 		}
   14.18 +.interrupted_cline, .interrupted_root_cline
   14.19 +		{ 	color		: #777777; 		}
   14.20 +
   14.21 +._root_cline,.wrong_root_cline,.interrupted_root_cline,._root_output,.wrong_root_output,.interrupted_root_output,.tab_root_cline
   14.22 +		{
   14.23 +			border-left	: #ff0000 solid thin;
   14.24 +			
   14.25 +		}
   14.26 +
   14.27 +.note 		{ 
   14.28 +	color		: black;
   14.29 +	background 	: #d8fcff; 
   14.30 +        margin		: 12px 12px 12px 12px;
   14.31 +        padding		: 6px 6px 6px 6px; 
   14.32 +        border-style	: dashed;
   14.33 +        border-width	: thin;
   14.34 +	border-color 	: #a8eaff; 
   14.35 +	vertical-align	: top;
   14.36 +}
   14.37 +
   14.38 +.note_title,.note_text,.note_search	
   14.39 +		{ 
   14.40 +			color		: black;
   14.41 +        		margin		: 0px 0px 0px 0px;
   14.42 +        		padding		: 0px 0px 0px 0px; 
   14.43 +			vertical-align	: top;
   14.44 +								}
   14.45 +.note_title	{ 	font-family	: sans-serif; 		}
   14.46 +.note_text 	{ 	font-size	: 80%;			}
   14.47 +.note_search 	{ 	text-align	: right; 		}
   14.48 +
   14.49 +
   14.50 +.diff 		{ 
   14.51 +	color		: black;
   14.52 +	background 	: #fdffcd;
   14.53 +        margin		: 16px 16px 16px 16px;
   14.54 +        padding		: 6px 6px 6px 6px; 
   14.55 +        border-style	: dashed;
   14.56 +        border-width	: thin;
   14.57 +}
   14.58 +
   14.59 +.ttychange 		{ 
   14.60 +	color		: #9a9a9a;
   14.61 +	background 	: #e7e7e7;
   14.62 +        margin		: 0px 0px 0px 0px;
   14.63 +        padding		: 0px 0px 0px 0px; 
   14.64 +	vertical-align	: top;
   14.65 +	font-family	: monospace;
   14.66 +}
   14.67 +
   14.68 +.time 		{ 
   14.69 +	color		: #999999;
   14.70 +        margin		: 0px 0px 0px 0px;
   14.71 +        padding		: 0px 10px 0px 0px; 
   14.72 +	vertical-align	: top;
   14.73 +	font-size	: 80%;
   14.74 +	vertical-align	: top;
   14.75 + /*       border-right	: #9a9a9a solid thin; */
   14.76 +}
   14.77 +
   14.78 +.script 		{ 
   14.79 +        margin		: 0px 0px 0px 0px;
   14.80 +        padding		: 0px 0px 0px 0px; 
   14.81 +	vertical-align	: top;
   14.82 +}
   14.83 +
   14.84 +.visibility_form 		{ 
   14.85 +	color		: #9a9a9a;
   14.86 +	background 	: #e7e7e7;
   14.87 +        margin		: 0px 0px 0px 0px;
   14.88 +        padding		: 0px 0px 0px 0px; 
   14.89 +	vertical-align	: top;
   14.90 +	font-size	: 80%;
   14.91 +	font-family	: sans-serif;
   14.92 +}
    15.1 Binary file share/opennet.ico has changed
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/share/ug.xsl	Sun May 22 16:29:55 2005 +0300
    16.3 @@ -0,0 +1,41 @@
    16.4 +<?xml version="1.0" encoding="UTF-8"?>
    16.5 +
    16.6 +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    16.7 +
    16.8 +<xsl:output method="html"
    16.9 +            encoding="UTF-8"
   16.10 +	    indent="yes"/>
   16.11 +			
   16.12 +<!--
   16.13 +XSLT ug TO docbook
   16.14 +Igor Chubin, 
   16.15 +Wed Dec 29 17:23:43 EET 2004
   16.16 +-->
   16.17 +
   16.18 +
   16.19 +<xsl:template match='script'>
   16.20 +<sect1>
   16.21 +	<xsl:apply-templates/>
   16.22 +</sect1>
   16.23 +</xsl:template>
   16.24 +
   16.25 +<xsl:template match="action">
   16.26 +<screen role="command"><xsl:text>
   16.27 +</xsl:text>
   16.28 +	<emphasis role="cline"><xsl:value-of select="line/prompt"/>
   16.29 +	<xsl:value-of select="line/command"/></emphasis>
   16.30 +	<xsl:value-of select="output"/>
   16.31 +</screen>
   16.32 +	<xsl:apply-templates select="diff"/>
   16.33 +</xsl:template>
   16.34 +
   16.35 +<xsl:template match="diff"><xsl:text>
   16.36 +</xsl:text>
   16.37 +<screen role="diff">
   16.38 +	<xsl:value-of select="."/>
   16.39 +</screen>
   16.40 +</xsl:template>
   16.41 +
   16.42 +
   16.43 +</xsl:stylesheet>
   16.44 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/taillast.pl	Sun May 22 16:29:55 2005 +0300
    17.3 @@ -0,0 +1,8 @@
    17.4 +#!/usr/bin/perl
    17.5 +
    17.6 +for $d (@ARGV) {
    17.7 +	push @d, glob("$d/*");
    17.8 +}
    17.9 +@{f} =  sort { (stat(${a}))[9] <=> (stat(${b}))[9] } (@d); 
   17.10 +print "tail -f ${f[$#f]}\n";
   17.11 +__END__
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/ug2db	Sun May 22 16:29:55 2005 +0300
    18.3 @@ -0,0 +1,7 @@
    18.4 +#!/bin/sh
    18.5 +
    18.6 +from=$1
    18.7 +to=$2
    18.8 +xsl=ug.xsl
    18.9 +xsltproc -o $to $xsl $from
   18.10 +