lilalo

changeset 62:c4bea959dbb1

Beautyfication of l3-agent code. Many lines were erased. Need to be tested
author devi
date Thu Jan 26 00:00:53 2006 +0200 (2006-01-26)
parents 440d12c122d5
children 1864df6ccbfe
files README l3-agent l3-frontend
line diff
     1.1 --- a/README	Sat Jan 21 19:09:34 2006 +0200
     1.2 +++ b/README	Thu Jan 26 00:00:53 2006 +0200
     1.3 @@ -0,0 +1,154 @@
     1.4 +АТРИБУТЫ cline
     1.5 +СПИСОК ПОЛЕЙ, ХАРАКТЕРИЗУЮЩИХ КОМАНДНУЮ СТРОКУ
     1.6 +
     1.7 +    uid
     1.8 +        Идентификатор пользователя
     1.9 +    
    1.10 +    tty 
    1.11 +        Идентификатор терминала, на котором была вызвана команда
    1.12 +
    1.13 +    pid
    1.14 +        PID-процесса командного интерпретатора, 
    1.15 +        в котором была вызвана команда
    1.16 +    
    1.17 +    lab 
    1.18 +        лабораторная работа, к которой относится команда.
    1.19 +        Идентификатор текущей лабораторной работы 
    1.20 +        хранится в файле ~/.labmaker/lab
    1.21 +
    1.22 +    pwd (!)
    1.23 +        текущий каталог, из которого была вызвана команда
    1.24 +
    1.25 +    day
    1.26 +        время вызова, день
    1.27 +        В действительности здесь хранится не время вызова команды,
    1.28 +        а с момента появления приглашения командного интерпретатора
    1.29 +        для ввода команды
    1.30 +        
    1.31 +    
    1.32 +    hour
    1.33 +        время вызова, час
    1.34 +    
    1.35 +    min
    1.36 +        время вызова, минута
    1.37 +    
    1.38 +    sec
    1.39 +        время вызова, секунда
    1.40 +    
    1.41 +    time (!)
    1.42 +        время вызова команды в Unix-формате.
    1.43 +        Предпочтительнее использовать этот формат чем hour:min:sec,
    1.44 +        использовавшийся в Labmaker
    1.45 +    
    1.46 +    fullprompt
    1.47 +        Приглашение командной строки
    1.48 +    
    1.49 +    prompt
    1.50 +        Сокращённое приглашение командной строки
    1.51 +
    1.52 +    cline 
    1.53 +        Командная строка
    1.54 +    
    1.55 +    output
    1.56 +        Результат выполнения команды
    1.57 +    
    1.58 +    diff
    1.59 +        Указатель на ассоциированный с командой diff
    1.60 +    
    1.61 +    note (!)
    1.62 +        Текстовый комментарий к команде.
    1.63 +        Может генерироваться из самого лога с помощью команд
    1.64 +            #^ Комментарий  
    1.65 +            #= Комментарий
    1.66 +            #v Комментарий
    1.67 +        в том случае, если для комментирования достаточно одной строки,
    1.68 +        или с помощью команд
    1.69 +            cat > /dev/null #^ Заголовок
    1.70 +            Текст
    1.71 +            ^D
    1.72 +        в том случае, если комментарий развёрнутый.
    1.73 +        В последнем случае комментарий может содержать 
    1.74 +        заголовок, абзацы и несложное форматирование.
    1.75 +
    1.76 +        Символы ^, v или = после знака комментария # обозначает,
    1.77 +        к какой команде относится комментарий:
    1.78 +        к предыдущей (^), последующей (v)
    1.79 +        или это общий комментарий по тексту, не относящийся непосредственно
    1.80 +        ни к одной из них (=)
    1.81 +
    1.82 +    err 
    1.83 +        Код завершения командной строки
    1.84 +    
    1.85 +    histnum (!)
    1.86 +        Номер команды в истории командного интерпретатора
    1.87 +    
    1.88 +    status (!)
    1.89 +        Является ли данная команда вызванной (r), запомненной (s)
    1.90 +        или это подсказка completion (c).
    1.91 +        
    1.92 +        Команды, которые были вызваны и обработаны интерпретатором
    1.93 +        имеют состояние "r". К таким командам относится большинство 
    1.94 +        команд вводимых в интерпретатор.
    1.95 +
    1.96 +        Если команда набрана, но вызывать её по какой-либо причине
    1.97 +        не хочется (например, команда может быть не полной, вредоносной
    1.98 +        или просто бессмысленной в текущих условиях),
    1.99 +        её можно сбросить с помощью комбинации клавиш Ctrl-C
   1.100 +        (не путайте с прерыванием работающей команды! здесь она даже
   1.101 +        не запускается!).
   1.102 +        В таком случае она не выполняется, но попадает в журнал
   1.103 +        со статусом "s".
   1.104 +        
   1.105 +        Если команда появилась в журнале благодаря автопроолжению 
   1.106 +        -- когда было показано несколько вариантов --
   1.107 +        она имеет статус "c".
   1.108 +    
   1.109 +    euid
   1.110 +        Идентификатор пользователя от имени которого будет 
   1.111 +        выполняться команда.
   1.112 +        Может отличаться от реального uid в том случае,
   1.113 +        если вызывается с помощью sudo
   1.114 +
   1.115 +    
   1.116 +    version (!)
   1.117 +        Версия lilalo-prompt использовавшаяся при записи
   1.118 +        команды.
   1.119 +
   1.120 +        0 - версия использовавшая в labmaker.
   1.121 +            Отсутствует информация о текущем каталоге и номере в истории. 
   1.122 +            Информация о версии также не указана в приглашении.
   1.123 +            
   1.124 +        
   1.125 +        1 - версия использующаяся в lilalo
   1.126 +        
   1.127 +    raw_file
   1.128 +        Имя файла, в котором находится бинарное представление журнала.
   1.129 +        Может содержать ключевое слово HERE, 
   1.130 +        обозначающее что бинарное представление хранится
   1.131 +        непосредственно в базе данных в атрибуте raw_data
   1.132 +
   1.133 +    raw_start
   1.134 +        Начало блока командной строки в файле бинарного представления
   1.135 +    
   1.136 +    raw_output_start
   1.137 +        Начало блока вывода
   1.138 +    
   1.139 +    raw_end
   1.140 +        Конец блока командной строки в файле бинарного представления
   1.141 +
   1.142 +    raw_cline
   1.143 +        Необработанная командная строка (без приглашения) в бинарном виде
   1.144 +    
   1.145 +    raw_data (*)
   1.146 +        Бинарное представление команды и результатов её выполнения
   1.147 +
   1.148 +
   1.149 +
   1.150 +    
   1.151 +ТАБЛИЦА SESSION
   1.152 +    
   1.153 +    Информация о сеансах
   1.154 +
   1.155 +        (см. lm-install)
   1.156 +
   1.157 +
     2.1 --- a/l3-agent	Sat Jan 21 19:09:34 2006 +0200
     2.2 +++ b/l3-agent	Thu Jan 26 00:00:53 2006 +0200
     2.3 @@ -1,7 +1,7 @@
     2.4  #!/usr/bin/perl -w
     2.5  
     2.6  #
     2.7 -# (c) Igor Chubin, imchubin@mail.ru, 2004-2005
     2.8 +# (c) Igor Chubin, igor@chub.in, 2004-2006
     2.9  #
    2.10  
    2.11  
    2.12 @@ -24,26 +24,22 @@
    2.13  our %Diffs;
    2.14  our %Sessions;
    2.15  
    2.16 -our %Commands_Stat;		# Statistics about commands usage
    2.17 -our %Files_Stat;		# Statistics about commands usage
    2.18 +our %Script_Files;  # Информация о позициях в скрипт-файлах, 
    2.19 +                    # до которых уже выполнен разбор
    2.20 +                    # и информация о времени модификации файла
    2.21 +                    #   $Script_Files{$file}->{size}
    2.22 +                    #   $Script_Files{$file}->{tell}
    2.23  
    2.24 -our %Script_Files;		# Информация о позициях в скрипт-файлах, 
    2.25 -				# до которых уже выполнен разбор
    2.26 -				# и информация о времени модификации файла
    2.27 -				# 	$Script_Files{$file}->{size}
    2.28 -				# 	$Script_Files{$file}->{tell}
    2.29 -
    2.30 -our $Killed =0;			# В режиме демона -- процесс получил сигнал о завершении
    2.31 +our $Killed =0;     # В режиме демона -- процесс получил сигнал о завершении
    2.32  
    2.33  sub init_variables;
    2.34  sub main;
    2.35  
    2.36  sub load_diff_files;
    2.37  sub bind_diff;
    2.38 -sub extract_from_cline;
    2.39 +sub extract_commands_from_cline;
    2.40  sub load_command_lines;
    2.41  sub sort_command_lines;
    2.42 -sub process_command_lines;
    2.43  sub print_command_lines;
    2.44  sub printq;
    2.45  
    2.46 @@ -53,20 +49,20 @@
    2.47  
    2.48  sub load_diff_files
    2.49  {
    2.50 -	my @pathes = @_;
    2.51 -	
    2.52 -	for my $path (@pathes) {
    2.53 -		my $template = "*.diff";
    2.54 -		my @files = <$path/$template>;
    2.55 -		my $i=0;
    2.56 -		for my $file (@files) {
    2.57 +    my @pathes = @_;
    2.58 +    
    2.59 +    for my $path (@pathes) {
    2.60 +        my $template = "*.diff";
    2.61 +        my @files = <$path/$template>;
    2.62 +        my $i=0;
    2.63 +        for my $file (@files) {
    2.64  
    2.65 -			next if defined($Diffs{$file});
    2.66 -			
    2.67 -			my %diff;
    2.68 -			
    2.69 -			$diff{"path"}=$path;
    2.70 -			$diff{"uid"}="SET THIS";
    2.71 +            next if defined($Diffs{$file});
    2.72 +            
    2.73 +            my %diff;
    2.74 +            
    2.75 +            $diff{"path"}=$path;
    2.76 +            $diff{"uid"}="SET THIS";
    2.77  
    2.78  # Сейчас UID определяется из названия каталога
    2.79  # откуда берутся diff-файлы
    2.80 @@ -77,634 +73,381 @@
    2.81  # мз которых и будет определяться соответствие 
    2.82  # имён пользователей их uid'ам
    2.83  #
    2.84 -			$diff{"uid"} = 0 if $path =~ m@/root/@;	
    2.85 -			
    2.86 -			$diff{"bind_to"}="";
    2.87 -			$diff{"time_range"}=-1;
    2.88 -		
    2.89 -			next if not $file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@;
    2.90 -			$diff{"day"}=$1 || "";
    2.91 -			$diff{"hour"}=$2;
    2.92 -			$diff{"min"}=$3;
    2.93 -			$diff{"sec"}=$4 || 0;
    2.94 -			
    2.95 -			$diff{"index"}=$i;
    2.96 +            $diff{"uid"} = 0 if $path =~ m@/root/@; 
    2.97 +            
    2.98 +            $diff{"bind_to"}="";
    2.99 +            $diff{"time_range"}=-1;
   2.100 +        
   2.101 +            next if not $file=~m@/(D?[0-9][0-9]?[0-9]?)[^/]*?([0-9]*):([0-9]*):?([0-9]*)@;
   2.102 +            $diff{"day"}=$1 || "";
   2.103 +            $diff{"hour"}=$2;
   2.104 +            $diff{"min"}=$3;
   2.105 +            $diff{"sec"}=$4 || 0;
   2.106 +            
   2.107 +            $diff{"index"}=$i;
   2.108  
   2.109 -			print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n";
   2.110 -			
   2.111 -			local $/;
   2.112 -			open (F, "$file")
   2.113 -				or return "Can't open file $file ($_[0]) for reading";
   2.114 -			my $text = <F>;
   2.115 -			if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) {
   2.116 -				my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8");
   2.117 -				$text = $converter->convert($text);
   2.118 -			}
   2.119 -			close(F);	
   2.120 -			$diff{"text"}=$text;
   2.121 -			#print "$file loaded ($diff{day})\n";
   2.122 +            print "diff loaded: $diff{day} $diff{hour}:$diff{min}:$diff{sec}\n";
   2.123 +            
   2.124 +            local $/;
   2.125 +            open (F, "$file")
   2.126 +                or return "Can't open file $file ($_[0]) for reading";
   2.127 +            my $text = <F>;
   2.128 +            if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i) {
   2.129 +                my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8");
   2.130 +                $text = $converter->convert($text);
   2.131 +            }
   2.132 +            close(F);   
   2.133 +            $diff{"text"}=$text;
   2.134 +            #print "$file loaded ($diff{day})\n";
   2.135  
   2.136 -			#push @Diffs, \%diff;
   2.137 -			$Diffs{$file} = \%diff;
   2.138 -			$i++;
   2.139 -		}
   2.140 -	}	
   2.141 +            #push @Diffs, \%diff;
   2.142 +            $Diffs{$file} = \%diff;
   2.143 +            $i++;
   2.144 +        }
   2.145 +    }   
   2.146  }
   2.147  
   2.148  
   2.149  sub bind_diff
   2.150  {
   2.151 -#	my $path = shift;
   2.152 -#	my $pid = shift;
   2.153 -#	my $day = shift;
   2.154 -#	my $lab = shift;
   2.155 +#   my $path = shift;
   2.156 +#   my $pid = shift;
   2.157 +#   my $day = shift;
   2.158 +#   my $lab = shift;
   2.159  
   2.160 -	print "Trying to bind diff...\n";
   2.161 +    print "Trying to bind diff...\n";
   2.162  
   2.163 -	my $cl = shift;
   2.164 -	my $hour = $cl->{"hour"};
   2.165 -	my $min = $cl->{"min"};
   2.166 -	my $sec = $cl->{"sec"};
   2.167 +    my $cl = shift;
   2.168 +    my $hour = $cl->{"hour"};
   2.169 +    my $min = $cl->{"min"};
   2.170 +    my $sec = $cl->{"sec"};
   2.171  
   2.172 -	my $min_dt = 10000;
   2.173 +    my $min_dt = 10000;
   2.174  
   2.175 -	for my $diff_key (keys %Diffs) {
   2.176 -			my $diff = $Diffs{$diff_key};
   2.177 -			# Check here date, time and user
   2.178 -			next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"}));
   2.179 -			#next if (!$diff->{"uid"} && $cl->{"euid"} != $diff->{"uid"});
   2.180 -			
   2.181 -			my $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec);
   2.182 -			if ($dt >0  && $dt < $min_dt && ($diff->{"time_range"} <0 || $dt < $diff->{"time_range"})) {
   2.183 -				print "Approppriate diff found: dt=$dt\n";
   2.184 -				if ($diff->{"bind_to"}) {
   2.185 -					undef $diff->{"bind_to"}->{"diff"};
   2.186 -				};
   2.187 -				$diff->{"time_range"}=$dt;
   2.188 -				$diff->{"bind_to"}=$cl;
   2.189 +    for my $diff_key (keys %Diffs) {
   2.190 +            my $diff = $Diffs{$diff_key};
   2.191 +            # Check here date, time and user
   2.192 +            next if ($diff->{"day"} && $cl->{"day"} && ($cl->{"day"} ne $diff->{"day"}));
   2.193 +            #next if (!$diff->{"uid"} && $cl->{"euid"} != $diff->{"uid"});
   2.194 +            
   2.195 +            my $dt=($diff->{"hour"}-$hour)*3600 +($diff->{"min"}-$min)*60 + ($diff->{"sec"}-$sec);
   2.196 +            if ($dt >0  && $dt < $min_dt && ($diff->{"time_range"} <0 || $dt < $diff->{"time_range"})) {
   2.197 +                print "Approppriate diff found: dt=$dt\n";
   2.198 +                if ($diff->{"bind_to"}) {
   2.199 +                    undef $diff->{"bind_to"}->{"diff"};
   2.200 +                };
   2.201 +                $diff->{"time_range"}=$dt;
   2.202 +                $diff->{"bind_to"}=$cl;
   2.203  
   2.204 -				#$cl->{"diff"} = $diff->{"index"};
   2.205 -				$cl->{"diff"} = $diff_key;
   2.206 -				$min_dt = $dt;	
   2.207 -			}
   2.208 -		
   2.209 -	}
   2.210 +                $cl->{"diff"} = $diff_key;
   2.211 +                $min_dt = $dt;  
   2.212 +        }
   2.213 +    }
   2.214  }
   2.215  
   2.216  
   2.217 -sub extract_from_cline
   2.218 +sub extract_commands_from_cline
   2.219  # Разобрать командную строку $_[1] и возвратить хэш, содержащий 
   2.220  # номер первого появление команды в строке:
   2.221 -# 	команда => первая позиция
   2.222 +#   команда => первая позиция
   2.223  {
   2.224 -	my $what = $_[0];
   2.225 -	my $cline = $_[1];
   2.226 -	my @lists = split /\;/, $cline;
   2.227 -	
   2.228 -	
   2.229 -	my @commands = ();
   2.230 -	for my $list (@lists) {
   2.231 -		push @commands, split /\|/, $list;
   2.232 -	}
   2.233 +    my $cline = $_[0];
   2.234 +    my @lists = split /\;/, $cline;
   2.235 +    
   2.236 +    
   2.237 +    my @commands = ();
   2.238 +    for my $list (@lists) {
   2.239 +        push @commands, split /\|/, $list;
   2.240 +    }
   2.241  
   2.242 -	my %commands;
   2.243 -	my %files;
   2.244 -	my $i=0;
   2.245 -	for my $command (@commands) {
   2.246 -		$command =~ /\s*(\S+)\s*(.*)/;
   2.247 -		if ($1 && $1 eq "sudo" ) {
   2.248 -			$commands{"$1"}=$i++;
   2.249 -			$command =~ s/\s*sudo\s+//;
   2.250 -		}
   2.251 -		$command =~ /\s*(\S+)\s*(.*)/;
   2.252 -		if ($1 && !defined $commands{"$1"}) {
   2.253 -				$commands{"$1"}=$i++;
   2.254 -		};	
   2.255 -		if ($2) {
   2.256 -			my $args = $2;
   2.257 -			my @args = split (/\s+/, $args);
   2.258 -			for my $a (@args) {
   2.259 -				$files{"$a"}=$i++
   2.260 -					if !defined $files{"$a"};
   2.261 -			};	
   2.262 -
   2.263 -				
   2.264 -		}
   2.265 -	}
   2.266 -
   2.267 -	if ($what eq "commands") {
   2.268 -		return %commands;
   2.269 -	} else {
   2.270 -		return %files;
   2.271 -	}
   2.272 -	
   2.273 +    my %commands;
   2.274 +    my %files;
   2.275 +    my $i=0;
   2.276 +    for my $command (@commands) {
   2.277 +        $command =~ /\s*(\S+)\s*(.*)/;
   2.278 +        if ($1 && $1 eq "sudo" ) {
   2.279 +            $commands{"$1"}=$i++;
   2.280 +            $command =~ s/\s*sudo\s+//;
   2.281 +        }
   2.282 +        $command =~ /\s*(\S+)\s*(.*)/;
   2.283 +        if ($1 && !defined $commands{"$1"}) {
   2.284 +                $commands{"$1"}=$i++;
   2.285 +        };  
   2.286 +    }
   2.287 +    return %commands;
   2.288  }
   2.289  
   2.290  sub load_command_lines
   2.291  {
   2.292 -	my $lab_scripts_path = $_[0];
   2.293 -	my $lab_scripts_mask = $_[1];
   2.294 +    my $lab_scripts_path = $_[0];
   2.295 +    my $lab_scripts_mask = $_[1];
   2.296  
   2.297 -	my $cline_re_base = qq'
   2.298 -			(
   2.299 -			(?:\\^?([0-9]*C?))			# exitcode
   2.300 -			(?:_([0-9]+)_)?				# uid
   2.301 -			(?:_([0-9]+)_)				# pid
   2.302 -			(...?)					# day
   2.303 -			(.?.?)					# lab
   2.304 -			\\s					# space separator
   2.305 -			([0-9][0-9]):([0-9][0-9]):([0-9][0-9])	# time
   2.306 -			.\\[50D.\\[K				# killing symbols
   2.307 -			(.*?([\$\#]\\s?))			# prompt
   2.308 -			(.*)					# command line
   2.309 -			)
   2.310 -			';
   2.311 -	#my $cline_re = qr/$cline_re_base(?:$cline_re_base|$)/x;
   2.312 -	#my $cline_re = qr/(?:$cline_re_base)*$cline_re_base$/x;
   2.313 -	my $cline_re = qr/$cline_re_base/sx;
   2.314 -	my $cline_re1 = qr/$cline_re_base\x0D/sx;
   2.315 -	my $cline_re2 = qr/$cline_re_base$/sx;
   2.316 +    my $cline_re_base = qq'
   2.317 +            (
   2.318 +            (?:\\^?([0-9]*C?))          # exitcode
   2.319 +            (?:_([0-9]+)_)?             # uid
   2.320 +            (?:_([0-9]+)_)              # pid
   2.321 +            (...?)                  # day
   2.322 +            (.?.?)                  # lab
   2.323 +            \\s                 # space separator
   2.324 +            ([0-9][0-9]):([0-9][0-9]):([0-9][0-9])  # time
   2.325 +            .\\[50D.\\[K                # killing symbols
   2.326 +            (.*?([\$\#]\\s?))           # prompt
   2.327 +            (.*)                    # command line
   2.328 +            )
   2.329 +            ';
   2.330 +    #my $cline_re = qr/$cline_re_base(?:$cline_re_base|$)/x;
   2.331 +    #my $cline_re = qr/(?:$cline_re_base)*$cline_re_base$/x;
   2.332 +    my $cline_re = qr/$cline_re_base/sx;
   2.333 +    my $cline_re1 = qr/$cline_re_base\x0D/sx;
   2.334 +    my $cline_re2 = qr/$cline_re_base$/sx;
   2.335  
   2.336 -	my $vt = Term::VT102->new (	'cols' => $Config{"terminal_width"}, 
   2.337 -					'rows' => $Config{"terminal_height"});
   2.338 -	my $cline_vt = Term::VT102->new ('cols' => $Config{"terminal_width"}, 
   2.339 -					'rows' => $Config{"terminal_height"});
   2.340 +    my $vt = Term::VT102->new ( 'cols' => $Config{"terminal_width"}, 
   2.341 +                    'rows' => $Config{"terminal_height"});
   2.342 +    my $cline_vt = Term::VT102->new ('cols' => $Config{"terminal_width"}, 
   2.343 +                    'rows' => $Config{"terminal_height"});
   2.344  
   2.345 -	my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8")
   2.346 -		if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i);
   2.347 -		
   2.348 -	print "Loading lm-scripts...\n" if $Config{"verbose"} =~ /y/;
   2.349 +    my $converter = Text::Iconv->new($Config{"encoding"}, "utf-8")
   2.350 +        if ($Config{"encoding"} && $Config{"encoding"} !~ /^utf-8$/i);
   2.351 +        
   2.352 +    print "Loading lm-scripts...\n" if $Config{"verbose"} =~ /y/;
   2.353  
   2.354 -	my $file;
   2.355 -	my $skip_info;
   2.356 +    my $file;
   2.357 +    my $skip_info;
   2.358  
   2.359 -	my $commandlines_loaded =0;
   2.360 -	my $commandlines_processed =0;
   2.361 +    my $commandlines_loaded =0;
   2.362 +    my $commandlines_processed =0;
   2.363  
   2.364 -	my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>;
   2.365 -	for $file (@lab_scripts){
   2.366 -		
   2.367 -		# Пропускаем файл, если он не изменялся со времени нашего предудущего прохода
   2.368 -		my $size = (stat($file))[7];
   2.369 -		next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size);
   2.370 +    my @lab_scripts = <$lab_scripts_path/$lab_scripts_mask>;
   2.371 +    for $file (@lab_scripts){
   2.372  
   2.373 +        # Пропускаем файл, если он не изменялся со времени нашего предудущего прохода
   2.374 +        my $size = (stat($file))[7];
   2.375 +        next if ($Script_Files{$file} && $Script_Files{$file}->{size} && $Script_Files{$file}->{size} >= $size);
   2.376  
   2.377 -		my $local_session_id;
   2.378 -		# Начальное значение идентификатора текущего сеанса определяем из имени скрипта
   2.379 -		# Впоследствии оно может быть уточнено
   2.380 -		$file =~ m@.*/([^/]*)\.script$@;
   2.381 -		$local_session_id = $1;
   2.382  
   2.383 -		#Если файл только что появился, 
   2.384 -		#пытаемся найти и загрузить информацию о соответствующей ему сессии
   2.385 -		if (!$Script_Files{$file}) {
   2.386 -			my $session_file = $file;
   2.387 -			$session_file =~ s/\.script/.info/;
   2.388 -			if (open(SESSION, $session_file)) {
   2.389 -				local $/;
   2.390 -				my $data = <SESSION>;
   2.391 -				close(SESSION);
   2.392 +        my $local_session_id;
   2.393 +        # Начальное значение идентификатора текущего сеанса определяем из имени скрипта
   2.394 +        # Впоследствии оно может быть уточнено
   2.395 +        $file =~ m@.*/([^/]*)\.script$@;
   2.396 +        $local_session_id = $1;
   2.397  
   2.398 -				for my $session_data ($data =~ m@<session>(.*?)</session>@sg) {
   2.399 -					my %session;
   2.400 -					while ($session_data =~ m@<([^>]*?)>(.*?)</\1>@sg) {
   2.401 -						$session{$1} = $2;
   2.402 -					}
   2.403 -					$local_session_id = $session{"local_session_id"} if $session{"local_session_id"};
   2.404 -					$Sessions{$local_session_id}=\%session;
   2.405 -				}
   2.406 +        #Если файл только что появился, 
   2.407 +        #пытаемся найти и загрузить информацию о соответствующей ему сессии
   2.408 +        if (!$Script_Files{$file}) {
   2.409 +            my $session_file = $file;
   2.410 +            $session_file =~ s/\.script/.info/;
   2.411 +            if (open(SESSION, $session_file)) {
   2.412 +                local $/;
   2.413 +                my $data = <SESSION>;
   2.414 +                close(SESSION);
   2.415  
   2.416 -				#Загруженную информацию сразу же отправляем в поток
   2.417 -				print_session($Config{cache}, $local_session_id);
   2.418 -			}
   2.419 -		}
   2.420 -		
   2.421 -		open (FILE, "$file");
   2.422 -		binmode FILE;
   2.423 -		
   2.424 -		# Переходим к тому месту, где мы окончили разбор
   2.425 -		seek (FILE, $Script_Files{$file}->{tell}, 0) if $Script_Files{$file}->{tell};
   2.426 -		$Script_Files{$file}->{size} = $size;
   2.427 -		$Script_Files{$file}->{tell} = 0 unless $Script_Files{$file}->{tell};
   2.428 +                for my $session_data ($data =~ m@<session>(.*?)</session>@sg) {
   2.429 +                    my %session;
   2.430 +                    while ($session_data =~ m@<([^>]*?)>(.*?)</\1>@sg) {
   2.431 +                        $session{$1} = $2;
   2.432 +                    }
   2.433 +                    $local_session_id = $session{"local_session_id"} if $session{"local_session_id"};
   2.434 +                    $Sessions{$local_session_id}=\%session;
   2.435 +                }
   2.436  
   2.437 +                #Загруженную информацию сразу же отправляем в поток
   2.438 +                print_session($Config{cache}, $local_session_id);
   2.439 +            }
   2.440 +        }
   2.441  
   2.442 -		$file =~ m@.*/(.*?)-.*@;
   2.443 -		
   2.444 -		my $tty = $1;
   2.445 -		my $first_pass = 1;
   2.446 -		my %cl;
   2.447 -		my $last_output_length=0;
   2.448 -		while (<FILE>) {
   2.449 -			
   2.450 -			$commandlines_processed++;
   2.451 -				# time
   2.452 +        open (FILE, "$file");
   2.453 +        binmode FILE;
   2.454  
   2.455 -			next if s/^Script started on.*?\n//s;
   2.456 +        # Переходим к тому месту, где мы окончили разбор
   2.457 +        seek (FILE, $Script_Files{$file}->{tell}, 0) if $Script_Files{$file}->{tell};
   2.458 +        $Script_Files{$file}->{size} = $size;
   2.459 +        $Script_Files{$file}->{tell} = 0 unless $Script_Files{$file}->{tell};
   2.460  
   2.461 -			if (/[0-9][0-9]:[0-9][0-9]:[0-9][0-9].\[[0-9][0-9]D.\[K/ && m/$cline_re/) {
   2.462 -				s/.*\x0d(?!\x0a)//;
   2.463 -		#		print "!!!",$_,"!!!\n";
   2.464 -			#	next;
   2.465 -			#	while (m/$cline_re1/gs) {
   2.466 -			#	}
   2.467 -				m/$cline_re2/gs;
   2.468 +        $file =~ m@.*/(.*?)-.*@;
   2.469  
   2.470 -				$commandlines_loaded++;
   2.471 -				$last_output_length=0;
   2.472 +        my $tty = $1;
   2.473 +        my $first_pass = 1;
   2.474 +        my %cl;
   2.475 +        my $last_output_length=0;
   2.476 +        while (<FILE>) {
   2.477 +            $commandlines_processed++;
   2.478  
   2.479 -				# Previous command
   2.480 -				my %last_cl = %cl;
   2.481 -				my $err = $2 || "";
   2.482 +            next if s/^Script started on.*?\n//s;
   2.483  
   2.484 +            if (/[0-9][0-9]:[0-9][0-9]:[0-9][0-9].\[[0-9][0-9]D.\[K/ && m/$cline_re/) {
   2.485 +                s/.*\x0d(?!\x0a)//;
   2.486 +                m/$cline_re2/gs;
   2.487  
   2.488 -=cut 
   2.489 +                $commandlines_loaded++;
   2.490 +                $last_output_length=0;
   2.491  
   2.492 -Атрибуты cline
   2.493 -Список полей, характеризующих командную строку
   2.494 +                # Previous command
   2.495 +                my %last_cl = %cl;
   2.496 +                my $err = $2 || "";
   2.497  
   2.498 -	uid
   2.499 -		Идентификатор пользователя
   2.500 -	
   2.501 -	tty 
   2.502 -		Идентификатор терминала, на котором была вызвана команда
   2.503 +                $cl{"local_session_id"} = $local_session_id;
   2.504 +                # Parse new command 
   2.505 +                $cl{"uid"} = $3;
   2.506 +                $cl{"euid"} = $cl{"uid"};   # Если в команде обнаружится sudo, euid поменяем на 0
   2.507 +                $cl{"pid"} = $4;
   2.508 +                $cl{"day"} = $5;
   2.509 +                $cl{"lab"} = $6;
   2.510 +                $cl{"hour"} = $7;
   2.511 +                $cl{"min"} = $8;
   2.512 +                $cl{"sec"} = $9;
   2.513 +                $cl{"fullprompt"} = $10;
   2.514 +                $cl{"prompt"} = $11;
   2.515 +                $cl{"raw_cline"} = $12; 
   2.516  
   2.517 -	pid
   2.518 -		PID-процесса командного интерпретатора, 
   2.519 -		в котором была вызвана команда
   2.520 -	
   2.521 -	lab 
   2.522 -		лабораторная работа, к которой относится команда.
   2.523 -		Идентификатор текущей лабораторной работы 
   2.524 -		хранится в файле ~/.labmaker/lab
   2.525 +                {
   2.526 +                use bytes;
   2.527 +                $cl{"raw_start"} = tell (FILE) - length($1);
   2.528 +                $cl{"raw_output_start"} = tell FILE;
   2.529 +                }
   2.530 +                $cl{"raw_file"} = $file;
   2.531  
   2.532 -	pwd (!)
   2.533 -		текущий каталог, из которого была вызвана команда
   2.534 +                $cl{"err"} = 0;
   2.535 +                $cl{"output"} = "";
   2.536 +                $cl{"tty"} = $tty;
   2.537  
   2.538 -	day
   2.539 -		время вызова, день
   2.540 -		В действительности здесь хранится не время вызова команды,
   2.541 -		а с момента появления приглашения командного интерпретатора
   2.542 -		для ввода команды
   2.543 -		
   2.544 -	
   2.545 -	hour
   2.546 -		время вызова, час
   2.547 -	
   2.548 -	min
   2.549 -		время вызова, минута
   2.550 -	
   2.551 -	sec
   2.552 -		время вызова, секунда
   2.553 -	
   2.554 -	time (!)
   2.555 -		время вызова команды в Unix-формате.
   2.556 -		Предпочтительнее использовать этот формат чем hour:min:sec,
   2.557 -		использовавшийся в Labmaker
   2.558 -	
   2.559 -	fullprompt
   2.560 -		Приглашение командной строки
   2.561 -	
   2.562 -	prompt
   2.563 -		Сокращённое приглашение командной строки
   2.564 +                $cline_vt->process($cl{"raw_cline"}."\n");
   2.565 +                $cl{"cline"} = $cline_vt->row_plaintext (1);
   2.566 +                $cl{"cline"} =~ s/\s*$//;
   2.567 +                $cline_vt->reset();
   2.568  
   2.569 -	cline 
   2.570 -		Командная строка
   2.571 -	
   2.572 -	output
   2.573 -		Результат выполнения команды
   2.574 -	
   2.575 -	diff
   2.576 -		Указатель на ассоциированный с командой diff
   2.577 -	
   2.578 -	note (!)
   2.579 -		Текстовый комментарий к команде.
   2.580 -		Может генерироваться из самого лога с помощью команд
   2.581 -			#^ Комментарий  
   2.582 -			#= Комментарий
   2.583 -			#v Комментарий
   2.584 -		в том случае, если для комментирования достаточно одной строки,
   2.585 -		или с помощью команд
   2.586 -			cat > /dev/null #^ Заголовок
   2.587 -			Текст
   2.588 -			^D
   2.589 -		в том случае, если комментарий развёрнутый.
   2.590 -		В последнем случае комментарий может содержать 
   2.591 -		заголовок, абзацы и несложное форматирование.
   2.592 +                my %commands = extract_commands_from_cline($cl{"cline"});
   2.593 +                $cl{"euid"}=0 if defined $commands{"sudo"};
   2.594 +                my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands; 
   2.595 +                $cl{"last_command"} = $comms[$#comms] || ""; 
   2.596  
   2.597 -		Символы ^, v или = после знака комментария # обозначает,
   2.598 -		к какой команде относится комментарий:
   2.599 -		к предыдущей (^), последующей (v)
   2.600 -		или это общий комментарий по тексту, не относящийся непосредственно
   2.601 -		ни к одной из них (=)
   2.602 +                if (
   2.603 +                    $Config{"suppress_editors"} =~ /^y/i 
   2.604 +                        && grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}}) 
   2.605 +                    || $Config{"suppress_pagers"}  =~ /^y/i 
   2.606 +                        && grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}}) 
   2.607 +                    || $Config{"suppress_terminal"}=~ /^y/i 
   2.608 +                        && grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}})
   2.609 +                ) {
   2.610 +                    $cl{"suppress_output"} = "1";
   2.611 +                }
   2.612 +                else {
   2.613 +                    $cl{"suppress_output"} = "0";
   2.614 +                }
   2.615 +                $skip_info = 0;
   2.616  
   2.617 -	err 
   2.618 -		Код завершения командной строки
   2.619 -	
   2.620 -	histnum (!)
   2.621 -		Номер команды в истории командного интерпретатора
   2.622 -	
   2.623 -	status (!)
   2.624 -		Является ли данная команда вызванной (r), запомненной (s)
   2.625 -		или это подсказка completion (c).
   2.626 -		
   2.627 -		Команды, которые были вызваны и обработаны интерпретатором
   2.628 -		имеют состояние "r". К таким командам относится большинство 
   2.629 -		команд вводимых в интерпретатор.
   2.630  
   2.631 -		Если команда набрана, но вызывать её по какой-либо причине
   2.632 -		не хочется (например, команда может быть не полной, вредоносной
   2.633 -		или просто бессмысленной в текущих условиях),
   2.634 -		её можно сбросить с помощью комбинации клавиш Ctrl-C
   2.635 -		(не путайте с прерыванием работающей команды! здесь она даже
   2.636 -		не запускается!).
   2.637 -		В таком случае она не выполняется, но попадает в журнал
   2.638 -		со статусом "s".
   2.639 -		
   2.640 -		Если команда появилась в журнале благодаря автопроолжению 
   2.641 -		-- когда было показано несколько вариантов --
   2.642 -		она имеет статус "c".
   2.643 -	
   2.644 -	euid
   2.645 -		Идентификатор пользователя от имени которого будет 
   2.646 -		выполняться команда.
   2.647 -		Может отличаться от реального uid в том случае,
   2.648 -		если вызывается с помощью sudo
   2.649 +                print " ",$cl{"last_command"};
   2.650  
   2.651 -	
   2.652 -	version (!)
   2.653 -		Версия lilalo-prompt использовавшаяся при записи
   2.654 -		команды.
   2.655 +                # Processing previous command line
   2.656 +                if ($first_pass) {
   2.657 +                    $first_pass = 0;
   2.658 +                    next;
   2.659 +                }
   2.660  
   2.661 -		0 - версия использовавшая в labmaker.
   2.662 -			Отсутствует информация о текущем каталоге и номере в истории. 
   2.663 -			Информация о версии также не указана в приглашении.
   2.664 -			
   2.665 -		
   2.666 -		1 - версия использующаяся в lilalo
   2.667 -		
   2.668 -	raw_file
   2.669 -		Имя файла, в котором находится бинарное представление журнала.
   2.670 -		Может содержать ключевое слово HERE, 
   2.671 -		обозначающее что бинарное представление хранится
   2.672 -		непосредственно в базе данных в атрибуте raw_data
   2.673 +                # Error code
   2.674 +                $last_cl{"raw_end"} = $cl{"raw_start"};
   2.675 +                $last_cl{"err"}=$err;
   2.676 +                $last_cl{"err"}=130 if $err eq "^C";
   2.677  
   2.678 -	raw_start
   2.679 -		Начало блока командной строки в файле бинарного представления
   2.680 -	
   2.681 -	raw_output_start
   2.682 -		Начало блока вывода
   2.683 -	
   2.684 -	raw_end
   2.685 -		Конец блока командной строки в файле бинарного представления
   2.686 +                if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) {
   2.687 +                    bind_diff(\%last_cl);
   2.688 +                }
   2.689  
   2.690 -	raw_cline
   2.691 -		Необработанная командная строка (без приглашения) в бинарном виде
   2.692 -	
   2.693 -	raw_data (*)
   2.694 -		Бинарное представление команды и результатов её выполнения
   2.695 +                # Output
   2.696 +                if (!$last_cl{"suppress_output"} || $last_cl{"err"}) {
   2.697 +                    for (my $i=0; $i<$Config{"terminal_height"}; $i++) {
   2.698 +                        my $line= $vt->row_plaintext($i);
   2.699 +                        next if !defined ($line) ; #|| $line =~ /^\s*$/;
   2.700 +                        $line =~ s/\s*$//;
   2.701 +                        $line .= "\n" unless $line =~ /^\s*$/;
   2.702 +                        $last_cl{"output"} .= $line;
   2.703 +                    }
   2.704 +                }
   2.705 +                else {
   2.706 +                    $last_cl{"output"}= "";
   2.707 +                }
   2.708  
   2.709 +                $vt->reset();
   2.710  
   2.711  
   2.712 -	
   2.713 -ТАБЛИЦА SESSION
   2.714 -	
   2.715 -	Информация о сеансах
   2.716 +                # Classifying the command line
   2.717  
   2.718 -		(см. lm-install)
   2.719  
   2.720 +                # Save 
   2.721 +                if (!$Config{"lab"} || $cl{"lab"} eq $Config{"lab"}) {
   2.722 +                    # Changing encoding 
   2.723 +                    for (keys %last_cl) {
   2.724 +                        next if /raw/;
   2.725 +                        $last_cl{$_} = $converter->convert($last_cl{$_})
   2.726 +                            if ($Config{"encoding"} && 
   2.727 +                            $Config{"encoding"} !~ /^utf-8$/i);
   2.728 +                    }
   2.729 +                    push @Command_Lines, \%last_cl; 
   2.730  
   2.731 -=cut
   2.732 +                    # Сохранение позиции в файле, до которой выполнен
   2.733 +                    # успешный разбор
   2.734 +                    $Script_Files{$file}->{tell} = $last_cl{raw_end};
   2.735 +                }   
   2.736 +                next;
   2.737 +            }
   2.738 +            $last_output_length+=length($_);
   2.739 +            #if (!$cl{"suppress_output"} || $last_output_length < 5000) {
   2.740 +            if ($last_output_length < 50000) {
   2.741 +                $vt->process("$_"."\n") 
   2.742 +            }
   2.743 +            else
   2.744 +            {
   2.745 +                if (!$skip_info) {
   2.746 +                    print "($cl{last_command})";
   2.747 +                    $skip_info = 1;
   2.748 +                }
   2.749 +            }
   2.750 +        }   
   2.751 +        close(FILE);
   2.752  
   2.753 -				$cl{"local_session_id"} = $local_session_id;
   2.754 -				# Parse new command 
   2.755 -				$cl{"uid"} = $3;
   2.756 -				$cl{"euid"} = $cl{"uid"};	# Если в команде обнаружится sudo, euid поменяем на 0
   2.757 -				$cl{"pid"} = $4;
   2.758 -				$cl{"day"} = $5;
   2.759 -				$cl{"lab"} = $6;
   2.760 -				$cl{"hour"} = $7;
   2.761 -				$cl{"min"} = $8;
   2.762 -				$cl{"sec"} = $9;
   2.763 -				$cl{"fullprompt"} = $10;
   2.764 -				$cl{"prompt"} = $11;
   2.765 -				$cl{"raw_cline"} = $12;	
   2.766 -
   2.767 -				{
   2.768 -				use bytes;
   2.769 -				$cl{"raw_start"} = tell (FILE) - length($1);
   2.770 -				$cl{"raw_output_start"} = tell FILE;
   2.771 -				}
   2.772 -				$cl{"raw_file"} = $file;
   2.773 -
   2.774 -				$cl{"err"} = 0;
   2.775 -				$cl{"output"} = "";
   2.776 -				$cl{"tty"} = $tty;
   2.777 -
   2.778 -				$cline_vt->process($cl{"raw_cline"}."\n");
   2.779 -				$cl{"cline"} = $cline_vt->row_plaintext (1);
   2.780 -				$cl{"cline"} =~ s/\s*$//;
   2.781 -				$cline_vt->reset();
   2.782 -
   2.783 -				my %commands = extract_from_cline("commands", $cl{"cline"});
   2.784 -				$cl{"euid"}=0 if defined $commands{"sudo"};
   2.785 -				my @comms = sort { $commands{$a} cmp $commands{$b} } keys %commands; 
   2.786 -				$cl{"last_command"} = $comms[$#comms] || ""; 
   2.787 -		
   2.788 -				if (
   2.789 -				$Config{"suppress_editors"} =~ /^y/i 
   2.790 -					&& grep ($_ eq $cl{"last_command"}, @{$Config{"editors"}}) ||
   2.791 -				$Config{"suppress_pagers"}  =~ /^y/i 
   2.792 -					&& grep ($_ eq $cl{"last_command"}, @{$Config{"pagers"}}) ||
   2.793 -				$Config{"suppress_terminal"}=~ /^y/i 
   2.794 -					&& grep ($_ eq $cl{"last_command"}, @{$Config{"terminal"}})
   2.795 -				) {
   2.796 -					$cl{"suppress_output"} = "1";
   2.797 -				}
   2.798 -				else {
   2.799 -					$cl{"suppress_output"} = "0";
   2.800 -					
   2.801 -				}
   2.802 -				$skip_info = 0;
   2.803 -
   2.804 -
   2.805 -				print " ",$cl{"last_command"};
   2.806 -
   2.807 -				# Processing previous command line
   2.808 -				if ($first_pass) {
   2.809 -					$first_pass = 0;
   2.810 -					next;
   2.811 -				}
   2.812 -
   2.813 -				# Error code
   2.814 -				$last_cl{"raw_end"} = $cl{"raw_start"};
   2.815 -				$last_cl{"err"}=$err;
   2.816 -				$last_cl{"err"}=130 if $err eq "^C";
   2.817 -
   2.818 -				if (grep ($_ eq $last_cl{"last_command"}, @{$Config{"editors"}})) {
   2.819 -					bind_diff(\%last_cl);
   2.820 -				}
   2.821 -
   2.822 -				# Output
   2.823 -				if (!$last_cl{"suppress_output"} || $last_cl{"err"}) {
   2.824 -					for (my $i=0; $i<$Config{"terminal_height"}; $i++) {
   2.825 -						my $line= $vt->row_plaintext($i);
   2.826 -						next if !defined ($line) ; #|| $line =~ /^\s*$/;
   2.827 -						$line =~ s/\s*$//;
   2.828 -						$line .= "\n" unless $line =~ /^\s*$/;
   2.829 -						$last_cl{"output"} .= $line;
   2.830 -					}
   2.831 -				}
   2.832 -				else {
   2.833 -					$last_cl{"output"}= "";
   2.834 -				}
   2.835 -
   2.836 -				$vt->reset();
   2.837 -
   2.838 -
   2.839 -				# Classifying the command line
   2.840 -
   2.841 -
   2.842 -				# Save 
   2.843 -				if (!$Config{"lab"} || $cl{"lab"} eq $Config{"lab"}) {
   2.844 -					# Changing encoding 
   2.845 -					for (keys %last_cl) {
   2.846 -						next if /raw/;
   2.847 -						$last_cl{$_} = $converter->convert($last_cl{$_})
   2.848 -							if ($Config{"encoding"} && 
   2.849 -							$Config{"encoding"} !~ /^utf-8$/i);
   2.850 -					}
   2.851 -					push @Command_Lines, \%last_cl;	
   2.852 -
   2.853 -					# Сохранение позиции в файле, до которой выполнен
   2.854 -					# успешный разбор
   2.855 -					$Script_Files{$file}->{tell} = $last_cl{raw_end};
   2.856 -				}	
   2.857 -				next;
   2.858 -			}
   2.859 -			$last_output_length+=length($_);
   2.860 -			#if (!$cl{"suppress_output"} || $last_output_length < 5000) {
   2.861 -			if ($last_output_length < 50000) {
   2.862 -				#print "(",length($_),")" if (length($_) > 2000) ;
   2.863 -				$vt->process("$_"."\n") 
   2.864 -			}
   2.865 -			else
   2.866 -			{
   2.867 -				if (!$skip_info) {
   2.868 -					print "($cl{last_command})";
   2.869 -					$skip_info = 1;
   2.870 -				}
   2.871 -			}
   2.872 -		}	
   2.873 -		close(FILE);
   2.874 -
   2.875 -	}
   2.876 -	if ($Config{"verbose"} =~ /y/) {
   2.877 -		print "...finished." ;
   2.878 -		print "Lines loaded: $commandlines_processed\n";
   2.879 -		print "Command lines: $commandlines_loaded\n";
   2.880 -	}
   2.881 +    }
   2.882 +    if ($Config{"verbose"} =~ /y/) {
   2.883 +        print "...finished." ;
   2.884 +        print "Lines loaded: $commandlines_processed\n";
   2.885 +        print "Command lines: $commandlines_loaded\n";
   2.886 +    }
   2.887  }
   2.888  
   2.889  
   2.890  
   2.891 +
   2.892 +sub sort_command_lines
   2.893 +{
   2.894 +    print "Sorting command lines...\n" if $Config{"verbose"} =~ /y/;
   2.895 +
   2.896 +    # Sort Command_Lines
   2.897 +    # Write Command_Lines to Command_Lines_Index
   2.898 +
   2.899 +    my @index;
   2.900 +    for (my $i=0;$i<=$#Command_Lines;$i++) {
   2.901 +        $index[$i]=$i;
   2.902 +    }
   2.903 +
   2.904 +    @Command_Lines_Index = sort {
   2.905 +        $Command_Lines[$index[$a]]->{"day"} cmp $Command_Lines[$index[$b]]->{"day"} ||
   2.906 +        $Command_Lines[$index[$a]]->{"hour"} <=> $Command_Lines[$index[$b]]->{"hour"} ||
   2.907 +        $Command_Lines[$index[$a]]->{"min"} <=> $Command_Lines[$index[$b]]->{"min"} ||
   2.908 +        $Command_Lines[$index[$a]]->{"sec"} <=> $Command_Lines[$index[$b]]->{"sec"}
   2.909 +    } @index;
   2.910 +
   2.911 +    print "...finished\n" if $Config{"verbose"} =~ /y/;
   2.912 +
   2.913 +}
   2.914 +
   2.915  sub printq
   2.916  {
   2.917 -	my $TO = shift;
   2.918 -	my $text = join "", @_;
   2.919 -	$text =~ s/&/&amp;/g;
   2.920 -	$text =~ s/</&lt;/g;
   2.921 -	$text =~ s/>/&gt;/g;
   2.922 -	print $TO $text;
   2.923 -}
   2.924 -
   2.925 -
   2.926 -sub sort_command_lines
   2.927 -{
   2.928 -	print "Sorting command lines...\n" if $Config{"verbose"} =~ /y/;
   2.929 -
   2.930 -	# Sort Command_Lines
   2.931 -	# Write Command_Lines to Command_Lines_Index
   2.932 -
   2.933 -	my @index;
   2.934 -	for (my $i=0;$i<=$#Command_Lines;$i++) {
   2.935 -		$index[$i]=$i;
   2.936 -	}
   2.937 -
   2.938 -	@Command_Lines_Index = sort {
   2.939 -		$Command_Lines[$index[$a]]->{"day"} cmp $Command_Lines[$index[$b]]->{"day"} ||
   2.940 -		$Command_Lines[$index[$a]]->{"hour"} <=> $Command_Lines[$index[$b]]->{"hour"} ||
   2.941 -		$Command_Lines[$index[$a]]->{"min"} <=> $Command_Lines[$index[$b]]->{"min"} ||
   2.942 -		$Command_Lines[$index[$a]]->{"sec"} <=> $Command_Lines[$index[$b]]->{"sec"}
   2.943 -	} @index;
   2.944 -
   2.945 -	print "...finished\n" if $Config{"verbose"} =~ /y/;
   2.946 -
   2.947 -}
   2.948 -
   2.949 -sub process_command_lines
   2.950 -{
   2.951 -	for my $i (@Command_Lines_Index) {
   2.952 -
   2.953 -		my $cl = \$Command_Lines[$i];
   2.954 -		@{${$cl}->{"new_commands"}} =();
   2.955 -		@{${$cl}->{"new_files"}} =();
   2.956 -		$$cl->{"class"} = ""; 
   2.957 -
   2.958 -		if ($$cl->{"err"}) {
   2.959 -			$$cl->{"class"}="wrong";
   2.960 -			$$cl->{"class"}="interrupted"
   2.961 -				if ($$cl->{"err"} eq 130);
   2.962 -		}	
   2.963 -		if (!$$cl->{"euid"}) {
   2.964 -			$$cl->{"class"}.="_root";
   2.965 -		}
   2.966 -		
   2.967 -#tab#		my @tab_words=split /\s+/, $$cl->{"output"};
   2.968 -#tab#		my $last_word= $$cl->{"cline"} =~ /(\S*)$/;
   2.969 -#tab#		$last_word =~ s@.*/@@;
   2.970 -#tab#		my $this_is_tab=1;
   2.971 -#tab#
   2.972 -#tab#		if ($last_word && @tab_words >2) {
   2.973 -#tab#			for my $tab_words (@tab_words) {
   2.974 -#tab#				if ($tab_words !~ /^$last_word/) {
   2.975 -#tab#					$this_is_tab=0;
   2.976 -#tab#					last;
   2.977 -#tab#				}
   2.978 -#tab#			}
   2.979 -#tab#		}	
   2.980 -#tab#		$$cl->{"class"}="tab" if $this_is_tab;
   2.981 -		
   2.982 -
   2.983 -		if ( !$$cl->{"err"}) {
   2.984 -			# Command does not contain mistakes
   2.985 -			
   2.986 -			my %commands = extract_from_cline("commands", ${$cl}->{"cline"});
   2.987 -			my %files = extract_from_cline("files", ${$cl}->{"cline"});
   2.988 -
   2.989 -			# Searching for new commands only
   2.990 -			for my $command (keys  %commands) {
   2.991 -				if (!defined $Commands_Stat{$command}) {
   2.992 -					push @{$$cl->{new_commands}}, $command;
   2.993 -				}	
   2.994 -				$Commands_Stat{$command}++;
   2.995 -			}
   2.996 -			
   2.997 -			for my $file (keys  %files) {
   2.998 -				if (!defined $Files_Stat{$file}) {
   2.999 -					push @{$$cl->{new_files}}, $file;
  2.1000 -				}	
  2.1001 -				$Files_Stat{$file}++;
  2.1002 -			}
  2.1003 -		}	
  2.1004 -
  2.1005 -		#if ($$cl->{cline}=~ /#\^(.*)/) {
  2.1006 -		#	my $j=$i-1;
  2.1007 -		#	$j-- while ($j >=0 && $Command_Lines[$j]->{tty} ne $$cl->{tty});
  2.1008 -		#	$Command_Lines[$j]->{note_title}="Замечание";
  2.1009 -		#	$Command_Lines[$j]->{note}="$1";
  2.1010 -		#}
  2.1011 -	}	
  2.1012 -
  2.1013 +    my $TO = shift;
  2.1014 +    my $text = join "", @_;
  2.1015 +    $text =~ s/&/&amp;/g;
  2.1016 +    $text =~ s/</&lt;/g;
  2.1017 +    $text =~ s/>/&gt;/g;
  2.1018 +    print $TO $text;
  2.1019  }
  2.1020  
  2.1021  
  2.1022 @@ -712,218 +455,190 @@
  2.1023  Вывести результат обработки журнала.
  2.1024  =cut
  2.1025  
  2.1026 -
  2.1027  sub print_command_lines
  2.1028  {
  2.1029 -	my $output_filename=$_[0];
  2.1030 -	my $mode = ">";
  2.1031 -	$mode =">>" if $Config{mode} eq "daemon";
  2.1032 -	open(OUT, $mode, $output_filename)
  2.1033 -		or die "Can't open $output_filename for writing\n";
  2.1034 +    my $output_filename=$_[0];
  2.1035 +    my $mode = ">";
  2.1036 +    $mode =">>" if $Config{mode} eq "daemon";
  2.1037 +    open(OUT, $mode, $output_filename)
  2.1038 +        or die "Can't open $output_filename for writing\n";
  2.1039  
  2.1040  
  2.1041 +    my $cl;
  2.1042 +    my $in_range=0;
  2.1043 +    for my $i (@Command_Lines_Index) {
  2.1044 +        $cl = $Command_Lines[$i];
  2.1045  
  2.1046 -	#print OUT "<livelablog>\n";
  2.1047 +        if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) {
  2.1048 +            $in_range=1;
  2.1049 +            next;
  2.1050 +        }
  2.1051 +        if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) {
  2.1052 +            $in_range=0;
  2.1053 +            next;
  2.1054 +        }
  2.1055 +        next if ($Config{"from"} && $Config{"to"} && !$in_range) 
  2.1056 +            ||
  2.1057 +                ($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
  2.1058 +            ||
  2.1059 +            ($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
  2.1060 +            ||
  2.1061 +            ($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
  2.1062 +        
  2.1063 +        # Вырезаем из вывода только нужное количество строк
  2.1064  
  2.1065 -	my $cl;
  2.1066 -	my $in_range=0;
  2.1067 -	for my $i (@Command_Lines_Index) {
  2.1068 -		$cl = $Command_Lines[$i];
  2.1069 +        my $output="";
  2.1070 +        if ($Config{"head_lines"} || $Config{"tail_lines"}) {
  2.1071 +            # Partialy output
  2.1072 +            my @lines = split '\n', $cl->{"output"};
  2.1073 +            # head
  2.1074 +            my $mark=1;
  2.1075 +            for (my $i=0; $i<= $#lines && $i < $Config{"cache_head_lines"}; $i++) {
  2.1076 +                $output .= $lines[$i]."\n";
  2.1077 +            }
  2.1078 +            # tail
  2.1079 +            my $start=$#lines-$Config{"cache_tail_lines"}+1;
  2.1080 +            if ($start < 0) {
  2.1081 +                $start=0;
  2.1082 +                $mark=0;
  2.1083 +            }   
  2.1084 +            if ($start < $Config{"cache_head_lines"}) {
  2.1085 +                $start=$Config{"cache_head_lines"};
  2.1086 +                $mark=0;
  2.1087 +            }   
  2.1088 +            $output .= $Config{"skip_text"}."\n" if $mark;
  2.1089 +            for (my $i=$start; $i<= $#lines; $i++) {
  2.1090 +                $output .= $lines[$i]."\n";
  2.1091 +            }
  2.1092 +        } 
  2.1093 +        else {
  2.1094 +            # Full output
  2.1095 +            $output .= $cl->{"output"};
  2.1096 +        }   
  2.1097  
  2.1098 -		if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) {
  2.1099 -			$in_range=1;
  2.1100 -			next;
  2.1101 -		}
  2.1102 -		if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) {
  2.1103 -			$in_range=0;
  2.1104 -			next;
  2.1105 -		}
  2.1106 -		next if ($Config{"from"} && $Config{"to"} && !$in_range) 
  2.1107 -			||
  2.1108 -		    	($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
  2.1109 -			||
  2.1110 -			($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
  2.1111 -			||
  2.1112 -			($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
  2.1113 -		
  2.1114 -		my @new_commands=@{$cl->{"new_commands"}};
  2.1115 -		my @new_files=@{$cl->{"new_files"}};
  2.1116 +        # Совместимость с labmaker
  2.1117  
  2.1118 -		my $cl_class="cline";
  2.1119 -		my $out_class="output";
  2.1120 -		if ($cl->{"class"}) {
  2.1121 -			$cl_class = $cl->{"class"}."_".$cl_class;
  2.1122 -			$out_class = $cl->{"class"}."_".$out_class;
  2.1123 -		}
  2.1124 +        # Переводим в секунды Эпохи
  2.1125 +        # В labmaker'е данные хранились в неудобной форме: hour, min, sec, day of year
  2.1126 +        # Информация о годе отсутствовала
  2.1127 +        # Её можно внести: 
  2.1128 +        # Декабрь 2004 год; остальные -- 2005 год.
  2.1129  
  2.1130 -		# Вырезаем из вывода только нужное количество строк
  2.1131 +        my $year = 2005;
  2.1132 +        #$year = 2004 if ( $cl->{day} > 330 );
  2.1133 +        $year = $Config{year} if $Config{year};
  2.1134 +        # timelocal(            $sec,      $min,      $hour,      $mday,$mon,$year);
  2.1135 +        $cl->{time} = timelocal_nocheck($cl->{sec},$cl->{min},$cl->{hour},$cl->{day},0,$year);
  2.1136  
  2.1137 -		my $output="";
  2.1138 -		if ($Config{"head_lines"} || $Config{"tail_lines"}) {
  2.1139 -			# Partialy output
  2.1140 -			my @lines = split '\n', $cl->{"output"};
  2.1141 -			# head
  2.1142 -			my $mark=1;
  2.1143 -			for (my $i=0; $i<= $#lines && $i < $Config{"cache_head_lines"}; $i++) {
  2.1144 -				$output .= $lines[$i]."\n";
  2.1145 -			}
  2.1146 -			# tail
  2.1147 -			my $start=$#lines-$Config{"cache_tail_lines"}+1;
  2.1148 -			if ($start < 0) {
  2.1149 -				$start=0;
  2.1150 -				$mark=0;
  2.1151 -			}	
  2.1152 -			if ($start < $Config{"cache_head_lines"}) {
  2.1153 -				$start=$Config{"cache_head_lines"};
  2.1154 -				$mark=0;
  2.1155 -			}	
  2.1156 -			$output .= $Config{"skip_text"}."\n" if $mark;
  2.1157 -			for (my $i=$start; $i<= $#lines; $i++) {
  2.1158 -				$output .= $lines[$i]."\n";
  2.1159 -			}
  2.1160 -		} 
  2.1161 -		else {
  2.1162 -			# Full output
  2.1163 -			$output .= $cl->{"output"};
  2.1164 -		}	
  2.1165 -		#$output .= "^C\n" if ($cl->{"err"} eq "130");
  2.1166  
  2.1167 +        # Начинаем вывод команды
  2.1168 +        print OUT "<command>\n";
  2.1169 +        for my $element (qw(
  2.1170 +            local_session_id
  2.1171 +            time
  2.1172 +            raw_start
  2.1173 +            raw_output_start
  2.1174 +            raw_end
  2.1175 +            raw_file
  2.1176 +            tty
  2.1177 +            uid
  2.1178 +            err
  2.1179 +            last_command
  2.1180 +            )) {
  2.1181 +            next unless $cl->{"$element"};
  2.1182 +            print OUT "<$element>".$cl->{$element}."</$element>\n";
  2.1183 +        }
  2.1184 +        for my $element (qw(
  2.1185 +            prompt
  2.1186 +            cline
  2.1187 +            note
  2.1188 +            note_title
  2.1189 +            )) {
  2.1190 +            next unless $cl->{"$element"};
  2.1191 +            print OUT "<$element>";
  2.1192 +            printq(\*OUT,$cl->{"$element"});
  2.1193 +            print OUT "</$element>\n";
  2.1194 +        }
  2.1195 +        print OUT "<output>";
  2.1196 +        printq(\*OUT,$output);
  2.1197 +        print OUT "</output>\n";
  2.1198 +        if ($cl->{"diff"}) {
  2.1199 +            print OUT "<diff>";
  2.1200 +            printq(\*OUT,${$Diffs{$cl->{"diff"}}}{"text"});
  2.1201 +            print OUT "</diff>\n";
  2.1202 +        }
  2.1203 +        print OUT "</command>\n";
  2.1204  
  2.1205 -		# Совместимость с labmaker
  2.1206 +    }
  2.1207  
  2.1208 -		# Переводим в секунды Эпохи
  2.1209 -		# В labmaker'е данные хранились в неудобной форме: hour, min, sec, day of year
  2.1210 -		# Информация о годе отсутствовала
  2.1211 -		# Её можно внести: 
  2.1212 -		# Декабрь 2004 год; остальные -- 2005 год.
  2.1213 -
  2.1214 -		my $year = 2005;
  2.1215 -		#$year = 2004 if ( $cl->{day} > 330 );
  2.1216 -		$year = $Config{year} if $Config{year};
  2.1217 -		# timelocal(			$sec,	   $min,      $hour,      $mday,$mon,$year);
  2.1218 -		$cl->{time} = timelocal_nocheck($cl->{sec},$cl->{min},$cl->{hour},$cl->{day},0,$year);
  2.1219 -
  2.1220 -
  2.1221 -		# Начинаем вывод команды
  2.1222 -		print OUT "<command>\n";
  2.1223 -		print OUT "<local_session_id>",$cl->{local_session_id},"</local_session_id>\n";
  2.1224 -		print OUT "<time>",$cl->{time},"</time>\n";
  2.1225 -		print OUT "<raw_start>",$cl->{raw_start},"</raw_start>\n";
  2.1226 -		print OUT "<raw_output_start>",$cl->{raw_output_start},"</raw_output_start>\n";
  2.1227 -		print OUT "<raw_end>",$cl->{raw_end},"</raw_end>\n";
  2.1228 -		print OUT "<raw_file>",$cl->{raw_file},"</raw_file>\n";
  2.1229 -		print OUT "<tty>",$cl->{tty},"</tty>\n";
  2.1230 -		print OUT "<uid>",$cl->{uid},"</uid>\n";
  2.1231 -		print OUT "<out_class>",$out_class,"</out_class>\n";
  2.1232 -		print OUT "<err>",$cl->{err},"</err>\n";
  2.1233 -		print OUT "<prompt>";
  2.1234 -			printq(\*OUT,,$cl->{"prompt"});
  2.1235 -		print OUT "</prompt>";
  2.1236 -		print OUT "<cline>";
  2.1237 -			printq(\*OUT,$cl->{"cline"});
  2.1238 -		print OUT "</cline>\n";
  2.1239 -		print OUT "<last_command>",$cl->{"last_command"},"</last_command>\n";
  2.1240 -		if (@new_commands) {
  2.1241 -			print OUT "<new_commands>";
  2.1242 -			printq(\*OUT, join (" ", @new_commands));
  2.1243 -			print OUT "</new_commands>";
  2.1244 -		}
  2.1245 -		if (@new_files) {
  2.1246 -			print OUT "<new_files>";
  2.1247 -			printq(\*OUT, join (" ", @new_files));
  2.1248 -			print OUT "</new_files>";
  2.1249 -		}
  2.1250 -		print OUT "<output>";
  2.1251 -			printq(\*OUT,$output);
  2.1252 -		print OUT "</output>\n";
  2.1253 -		if ($cl->{"diff"}) {
  2.1254 -			print OUT "<diff>";
  2.1255 -				printq(\*OUT,${$Diffs{$cl->{"diff"}}}{"text"});
  2.1256 -			print OUT "</diff>\n";
  2.1257 -		}
  2.1258 -		if ($cl->{"note"}) {
  2.1259 -			print OUT "<note>";
  2.1260 -				printq(\*OUT,$cl->{"note"});
  2.1261 -			print OUT "</note>\n";
  2.1262 -		}
  2.1263 -		if ($cl->{"note_title"}) {
  2.1264 -			print OUT "<note_title>";
  2.1265 -				printq(\*OUT,$cl->{"note_title"});
  2.1266 -			print OUT "</note_title>\n";
  2.1267 -		}
  2.1268 -		print OUT "</command>\n";
  2.1269 -
  2.1270 -	}
  2.1271 -
  2.1272 -	#print OUT "</livelablog>\n";
  2.1273 -	close(OUT);
  2.1274 +    close(OUT);
  2.1275  }
  2.1276  
  2.1277  sub print_session
  2.1278  {
  2.1279 -	my $output_filename = $_[0];
  2.1280 -	my $local_session_id = $_[1];
  2.1281 -	return if not defined($Sessions{$local_session_id});
  2.1282 +    my $output_filename = $_[0];
  2.1283 +    my $local_session_id = $_[1];
  2.1284 +    return if not defined($Sessions{$local_session_id});
  2.1285  
  2.1286 -	open(OUT, ">>", $output_filename)
  2.1287 -		or die "Can't open $output_filename for writing\n";
  2.1288 -	print OUT "<session>\n";
  2.1289 -	my %session = %{$Sessions{$local_session_id}};
  2.1290 -	for my $key (keys %session) {
  2.1291 -		print OUT "<$key>".$session{$key}."</$key>\n"
  2.1292 -	}
  2.1293 -	print OUT "</session>\n";
  2.1294 -	close(OUT);
  2.1295 +    open(OUT, ">>", $output_filename)
  2.1296 +        or die "Can't open $output_filename for writing\n";
  2.1297 +    print OUT "<session>\n";
  2.1298 +    my %session = %{$Sessions{$local_session_id}};
  2.1299 +    for my $key (keys %session) {
  2.1300 +        print OUT "<$key>".$session{$key}."</$key>\n"
  2.1301 +    }
  2.1302 +    print OUT "</session>\n";
  2.1303 +    close(OUT);
  2.1304  }
  2.1305  
  2.1306  sub send_cache
  2.1307  {
  2.1308 -	# Если в кэше что-то накопилось, 
  2.1309 -	# попытаемся отправить это на сервер
  2.1310 -	#
  2.1311 -	my $cache_was_sent=0;
  2.1312 -	
  2.1313 -	if (open(CACHE, $Config{cache})) {
  2.1314 -		local $/;
  2.1315 -		my $cache = <CACHE>;
  2.1316 -		close(CACHE);
  2.1317 +    # Если в кэше что-то накопилось, 
  2.1318 +    # попытаемся отправить это на сервер
  2.1319 +    #
  2.1320 +    my $cache_was_sent=0;
  2.1321 +    
  2.1322 +    if (open(CACHE, $Config{cache})) {
  2.1323 +        local $/;
  2.1324 +        my $cache = <CACHE>;
  2.1325 +        close(CACHE);
  2.1326  
  2.1327 -		my $socket = IO::Socket::INET->new(
  2.1328 -							PeerAddr => $Config{backend_address},
  2.1329 -							PeerPort => $Config{backend_port},
  2.1330 -							proto	=> "tcp",
  2.1331 -							Type 	=> SOCK_STREAM
  2.1332 -						);
  2.1333 +        my $socket = IO::Socket::INET->new(
  2.1334 +                            PeerAddr => $Config{backend_address},
  2.1335 +                            PeerPort => $Config{backend_port},
  2.1336 +                            proto   => "tcp",
  2.1337 +                            Type    => SOCK_STREAM
  2.1338 +                        );
  2.1339  
  2.1340 -		if ($socket) {
  2.1341 -			print $socket $cache;
  2.1342 -			close($socket);
  2.1343 -			$cache_was_sent = 1;
  2.1344 -		}
  2.1345 -	}
  2.1346 -	return $cache_was_sent;
  2.1347 +        if ($socket) {
  2.1348 +            print $socket $cache;
  2.1349 +            close($socket);
  2.1350 +            $cache_was_sent = 1;
  2.1351 +        }
  2.1352 +    }
  2.1353 +    return $cache_was_sent;
  2.1354  }
  2.1355  
  2.1356  sub save_cache_stat
  2.1357  {
  2.1358 -	open (CACHE, ">$Config{cache_stat}");
  2.1359 -	for my $f (keys %Script_Files) {
  2.1360 -		print CACHE "$f\t",$Script_Files{$f}->{size},"\t",$Script_Files{$f}->{tell},"\n";
  2.1361 -	}
  2.1362 -	close(CACHE);
  2.1363 +    open (CACHE, ">$Config{cache_stat}");
  2.1364 +    for my $f (keys %Script_Files) {
  2.1365 +        print CACHE "$f\t",$Script_Files{$f}->{size},"\t",$Script_Files{$f}->{tell},"\n";
  2.1366 +    }
  2.1367 +    close(CACHE);
  2.1368  }
  2.1369  
  2.1370  sub load_cache_stat
  2.1371  {
  2.1372 -	if (open (CACHE, "$Config{cache_stat}")) {
  2.1373 -		while(<CACHE>) {
  2.1374 -			chomp;
  2.1375 -			my ($f, $size, $tell) = split /\t/;
  2.1376 -			$Script_Files{$f}->{size} = $size;
  2.1377 -			$Script_Files{$f}->{tell} = $tell;
  2.1378 -		}
  2.1379 -		close(CACHE);
  2.1380 -	};
  2.1381 +    if (open (CACHE, "$Config{cache_stat}")) {
  2.1382 +        while(<CACHE>) {
  2.1383 +            chomp;
  2.1384 +            my ($f, $size, $tell) = split /\t/;
  2.1385 +            $Script_Files{$f}->{size} = $size;
  2.1386 +            $Script_Files{$f}->{tell} = $tell;
  2.1387 +        }
  2.1388 +        close(CACHE);
  2.1389 +    };
  2.1390  }
  2.1391  
  2.1392  
  2.1393 @@ -931,102 +646,102 @@
  2.1394  
  2.1395  sub process_was_killed
  2.1396  {
  2.1397 -	$Killed = 1;
  2.1398 +    $Killed = 1;
  2.1399  }
  2.1400  
  2.1401  sub main
  2.1402  {
  2.1403  
  2.1404 -	$| = 1;
  2.1405 +    $| = 1;
  2.1406  
  2.1407 -	init_variables();
  2.1408 -	init_config();
  2.1409 +    init_variables();
  2.1410 +    init_config();
  2.1411  
  2.1412  
  2.1413 -	if ($Config{"mode"} ne "daemon") {
  2.1414 +    if ($Config{"mode"} ne "daemon") {
  2.1415  
  2.1416  =cut
  2.1417 -	В нормальном режиме работы нужно
  2.1418 -	считать скрипты, обработать их и записать
  2.1419 -	результат выполнения в результриующий файл.
  2.1420 -	После этого завершить работу.
  2.1421 +    В нормальном режиме работы нужно
  2.1422 +    считать скрипты, обработать их и записать
  2.1423 +    результат выполнения в результирующий файл.
  2.1424 +    После этого завершить работу.
  2.1425  =cut
  2.1426 -		for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
  2.1427 -			load_diff_files($lab_log);
  2.1428 -		}
  2.1429 -		load_command_lines($Config{"input"}, $Config{"input_mask"});
  2.1430 -		sort_command_lines;
  2.1431 -		process_command_lines;
  2.1432 -		print_command_lines($Config{"cache"});
  2.1433 -	} 
  2.1434 -	else {
  2.1435 -		if (open(PIDFILE, $Config{agent_pidfile})) {
  2.1436 -			my $pid = <PIDFILE>;
  2.1437 -			close(PIDFILE);
  2.1438 -			if ($^O eq 'linux' && $pid &&(! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`)) {
  2.1439 -				print "Removing stale pidfile\n";
  2.1440 -				unlink $Config{agent_pidfile}
  2.1441 -					or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
  2.1442 -			}
  2.1443 -			elsif ($^O eq 'freebsd' && $pid && `ps axo uid,pid,command | grep '$<\\s*$pid\\s*$Config{"l3-agent"}' 2> /dev/null`) {
  2.1444 -				print "Removing stale pidfile\n";
  2.1445 -				unlink $Config{agent_pidfile}
  2.1446 -					or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
  2.1447 -			}
  2.1448 -			elsif ($^O eq 'linux' || $^O eq 'freebsd' ) {
  2.1449 -				print "l3-agent is already running: pid=$pid; pidfile=$Config{agent_pidfile}\n";
  2.1450 -				exit(0);
  2.1451 -			}
  2.1452 -			else {
  2.1453 -				print "Unknown operating system";
  2.1454 -				exit(0);
  2.1455 -			}
  2.1456 -		}
  2.1457 -		if ($Config{detach} =~ /^y/i) {
  2.1458 -			#$Config{verbose} = "no";
  2.1459 -			my $pid = fork;
  2.1460 -			exit if $pid;
  2.1461 -			die "Couldn't fork: $!" unless defined ($pid);
  2.1462 +        for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
  2.1463 +            load_diff_files($lab_log);
  2.1464 +        }
  2.1465 +        load_command_lines($Config{"input"}, $Config{"input_mask"});
  2.1466 +        sort_command_lines;
  2.1467 +        #process_command_lines;
  2.1468 +        print_command_lines($Config{"cache"});
  2.1469 +    } 
  2.1470 +    else {
  2.1471 +        if (open(PIDFILE, $Config{agent_pidfile})) {
  2.1472 +            my $pid = <PIDFILE>;
  2.1473 +            close(PIDFILE);
  2.1474 +            if ($^O eq 'linux' && $pid &&(! -e "/proc/$pid" || !`grep $Config{"l3-agent"} /proc/$pid/cmdline && grep "uid:.*\b$<\b" /proc/$pid/status`)) {
  2.1475 +                print "Removing stale pidfile\n";
  2.1476 +                unlink $Config{agent_pidfile}
  2.1477 +                    or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
  2.1478 +            }
  2.1479 +            elsif ($^O eq 'freebsd' && $pid && `ps axo uid,pid,command | grep '$<\\s*$pid\\s*$Config{"l3-agent"}' 2> /dev/null`) {
  2.1480 +                print "Removing stale pidfile\n";
  2.1481 +                unlink $Config{agent_pidfile}
  2.1482 +                    or die "Can't remove stale pidfile ". $Config{agent_pidfile}. " : $!";
  2.1483 +            }
  2.1484 +            elsif ($^O eq 'linux' || $^O eq 'freebsd' ) {
  2.1485 +                print "l3-agent is already running: pid=$pid; pidfile=$Config{agent_pidfile}\n";
  2.1486 +                exit(0);
  2.1487 +            }
  2.1488 +            else {
  2.1489 +                print "Unknown operating system";
  2.1490 +                exit(0);
  2.1491 +            }
  2.1492 +        }
  2.1493 +        if ($Config{detach} =~ /^y/i) {
  2.1494 +            #$Config{verbose} = "no";
  2.1495 +            my $pid = fork;
  2.1496 +            exit if $pid;
  2.1497 +            die "Couldn't fork: $!" unless defined ($pid);
  2.1498  
  2.1499 -			open(PIDFILE, ">", $Config{agent_pidfile})
  2.1500 -				or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!";
  2.1501 -			print PIDFILE $$;
  2.1502 -			close(PIDFILE);
  2.1503 +            open(PIDFILE, ">", $Config{agent_pidfile})
  2.1504 +                or die "Can't open pidfile ". $Config{agent_pidfile}. " for wrting: $!";
  2.1505 +            print PIDFILE $$;
  2.1506 +            close(PIDFILE);
  2.1507  
  2.1508 -			for my $handle (*STDIN, *STDOUT, *STDERR) {
  2.1509 -				open ($handle, "+<", "/dev/null")
  2.1510 -					or die "can't reopen $handle to /dev/null: $!"
  2.1511 -			}
  2.1512 +            for my $handle (*STDIN, *STDOUT, *STDERR) {
  2.1513 +                open ($handle, "+<", "/dev/null")
  2.1514 +                    or die "can't reopen $handle to /dev/null: $!"
  2.1515 +            }
  2.1516  
  2.1517 -			POSIX::setsid()
  2.1518 -				or die "Can't start a new session: $!";
  2.1519 +            POSIX::setsid()
  2.1520 +                or die "Can't start a new session: $!";
  2.1521  
  2.1522 -			$0 = $Config{"l3-agent"};
  2.1523 -			
  2.1524 -			$SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed;
  2.1525 -		}
  2.1526 -		while (not $Killed) {
  2.1527 -			@Command_Lines = ();
  2.1528 -			@Command_Lines_Index = ();
  2.1529 -			for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
  2.1530 -				load_diff_files($lab_log);
  2.1531 -			}
  2.1532 -			load_cache_stat();
  2.1533 -			load_command_lines($Config{"input"}, $Config{"input_mask"});
  2.1534 -			if (@Command_Lines) {
  2.1535 -				sort_command_lines;
  2.1536 -				process_command_lines;
  2.1537 -				print_command_lines($Config{"cache"});
  2.1538 -			}
  2.1539 -			save_cache_stat();
  2.1540 -			if (-e $Config{cache} && (stat($Config{cache}))[7]) {
  2.1541 -				send_cache() && unlink($Config{cache});
  2.1542 -			}
  2.1543 -			sleep($Config{"daemon_sleep_interval"} || 1);
  2.1544 -		}
  2.1545 -		
  2.1546 -		unlink $Config{agent_pidfile};
  2.1547 -	}
  2.1548 +            $0 = $Config{"l3-agent"};
  2.1549 +            
  2.1550 +            $SIG{INT} = $SIG{TERM} = $SIG{HUP} = \&process_was_killed;
  2.1551 +        }
  2.1552 +        while (not $Killed) {
  2.1553 +            @Command_Lines = ();
  2.1554 +            @Command_Lines_Index = ();
  2.1555 +            for my $lab_log (split (/\s+/, $Config{"diffs"} || $Config{"input"})) {
  2.1556 +                load_diff_files($lab_log);
  2.1557 +            }
  2.1558 +            load_cache_stat();
  2.1559 +            load_command_lines($Config{"input"}, $Config{"input_mask"});
  2.1560 +            if (@Command_Lines) {
  2.1561 +                sort_command_lines;
  2.1562 +                process_command_lines;
  2.1563 +                print_command_lines($Config{"cache"});
  2.1564 +            }
  2.1565 +            save_cache_stat();
  2.1566 +            if (-e $Config{cache} && (stat($Config{cache}))[7]) {
  2.1567 +                send_cache() && unlink($Config{cache});
  2.1568 +            }
  2.1569 +            sleep($Config{"daemon_sleep_interval"} || 1);
  2.1570 +        }
  2.1571 +        
  2.1572 +        unlink $Config{agent_pidfile};
  2.1573 +    }
  2.1574  
  2.1575  }
  2.1576  
     3.1 --- a/l3-frontend	Sat Jan 21 19:09:34 2006 +0200
     3.2 +++ b/l3-frontend	Thu Jan 26 00:00:53 2006 +0200
     3.3 @@ -771,7 +771,22 @@
     3.4      <script>
     3.5      $Html_JavaScript
     3.6      </script>
     3.7 -    <h1>Журнал лабораторных работ</h1>
     3.8 +
     3.9 +<!-- vvv Tigra Hints vvv -->
    3.10 +<script language="JavaScript" src="/tigra/hints.js"></script>
    3.11 +<script language="JavaScript" src="/tigra/hints_cfg.js"></script>
    3.12 +<style>
    3.13 +/* a class for all Tigra Hints boxes, TD object */
    3.14 +    .hintsClass
    3.15 +        {text-align: center; font-family: Verdana, Arial, Helvetica; padding: 0px 0px 0px 0px;}
    3.16 +/* this class is used by Tigra Hints wrappers */
    3.17 +    .row
    3.18 +        {background: white;}
    3.19 +</style>
    3.20 +<!-- ^^^ Tigra Hints ^^^ -->
    3.21 +
    3.22 +
    3.23 +    <h1 onmouseover="myHint.show('1')" onmouseout="myHint.hide()">Журнал лабораторных работ</h1>
    3.24  HEADER
    3.25      if (    $course_student 
    3.26              || $course_trainer