lilalo

diff l3-frontend @ 23:6d93c5f1d0e5

Выполнен шаг (2) в плане (N05) по построению распределённой системы lilalo.

Программа lm-report разрезана на две: l3-agent и l3-frontend.
Агент выполняет анализ script-файлов и записывает
результаты анализа в файл обмена (cache).
Фронтенд читает данные из файла обмена и представляет
их в требуемом формате (в настоящий момент только html).

Сейчас взаимодействие agent'а и frontend'а выполняется так:


. ^ . +-------+ . ^^ .
/ \ | | / \
( agent )-->| cache |--->( frontend )
\ / | | \ /
' . ' +-------+ ' .. '


Добавлены файлы:
l3-agent - агент
l3-frontend - фронтенд
l3-report - замена lm-report, использующая l3-agent и l3-frontend
l3-config.pm - модуль конфигурации системы

Новые конфигурационные параметры:
cache - Путь к временному XML-файлу, предназначенному
для обмена информацией между агентом и фронтендом

cache_head_lines - Количество строк вывода команды сверху, которые
должны быть сохранены в промежуточном XML-файле

cache_tail_lines - Количество строк вывода команды снизу, которые
должны быть сохранены в промежуточном XML-файле

Устаревшие параметры:
output_mask - Использование output_mask осуждается.
Параметр будет удалён из будущих версий

Использование lm-report осуждается.
В будущих версиях программа lm-report будет удалена из дистрибутива.
Вместо неё нужно использовать l3-report.
author devi
date Wed Nov 02 19:16:11 2005 +0200 (2005-11-02)
parents
children ba4d6515b8fd
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/l3-frontend	Wed Nov 02 19:16:11 2005 +0200
     1.3 @@ -0,0 +1,493 @@
     1.4 +#!/usr/bin/perl -w
     1.5 +
     1.6 +use lib '.';
     1.7 +use l3config;
     1.8 +
     1.9 +our @Command_Lines;
    1.10 +
    1.11 +# vvv Инициализация переменных выполняется процедурой init_variables
    1.12 +our @Day_Name;
    1.13 +our @Month_Name;
    1.14 +our @Of_Month_Name;
    1.15 +our %Search_Machines;
    1.16 +our %Elements_Visibility;
    1.17 +# ^^^
    1.18 +
    1.19 +sub search_buy;
    1.20 +sub make_comment;
    1.21 +sub load_command_lines_from_xml;
    1.22 +sub print_command_lines;
    1.23 +sub init_variables;
    1.24 +sub main;
    1.25 +
    1.26 +main();
    1.27 +
    1.28 +sub main
    1.29 +{
    1.30 +	$| = 1;
    1.31 +
    1.32 +	init_variables();
    1.33 +	init_config();
    1.34 +
    1.35 +	load_command_lines_from_xml($Config{"cache"});
    1.36 +	print_command_lines($Config{"output"});
    1.37 +}
    1.38 +
    1.39 +
    1.40 +sub search_by
    1.41 +{
    1.42 +	my $sm = shift;
    1.43 +	my $topic = shift;
    1.44 +	$topic =~ s/ /+/;
    1.45 +	
    1.46 +	return "<a href='".	$Search_Machines{$sm}->{"query"}."$topic'><img width='16' height='16' src='".
    1.47 +				$Search_Machines{$sm}->{"icon"}."' border='0'/></a>";
    1.48 +}
    1.49 +
    1.50 +sub make_comment
    1.51 +{
    1.52 +	my $commands = $_[0];
    1.53 +	my $files = $_[1];
    1.54 +	chomp $commands;
    1.55 +	chomp $files;
    1.56 +	return if (!$commands && !$files);
    1.57 +
    1.58 +	my $comment=""; 
    1.59 +
    1.60 +	# Commands
    1.61 +	for my $command (split /\s+/,$commands) {
    1.62 +		$command =~ s/'//g;
    1.63 +		my $description="";
    1.64 +		eval { $description=`mywi-client '$command'`; } ;
    1.65 +		$description = join ("<br>\n", grep(/\([18]\)/, split(/\n/, $description)));
    1.66 +		$description =~ s/.*?-//;
    1.67 +		next if $description =~ /^\s*$/; 
    1.68 +		
    1.69 +		my $query=$command." ".$Config{"keywords"};
    1.70 +		$query =~ s/\ /+/g;
    1.71 +		my $search= 	search_by("opennet",$query).
    1.72 +				search_by("local",$command).
    1.73 +				search_by("google",$query);
    1.74 +
    1.75 +		$comment .=     "<tr><td class='note_title'>$command</td>".
    1.76 +				"<td class='note_search'>$search</td>".
    1.77 +				"</tr><tr><td width='100%' colspan='2' class='note_text'>".
    1.78 +				"$description</td></tr><tr/>";
    1.79 +	}
    1.80 +	
    1.81 +	# Files
    1.82 +	for my $file (split /\s+/,$files) {
    1.83 +		$file =~ s@.*/@@;
    1.84 +		$file =~ s/'//g;
    1.85 +		next if $file =~ /^\s*$/;
    1.86 +		next if $file =~ /^-/;
    1.87 +		
    1.88 +		my $description=`mywi '$file'`;
    1.89 +		$description = join ("<br>\n", grep(/\(5\)/, split(/\n/, $description)));
    1.90 +		next if $description =~ /^\s*$/; 
    1.91 +
    1.92 +		my $query=$file." ".$Config{"files_keywords"};
    1.93 +		$query =~ s/\ /+/g;
    1.94 +		my $search= 	search_by("opennet",$query).
    1.95 +				search_by("local",$file).
    1.96 +				search_by("google",$query);
    1.97 +
    1.98 +		$comment .=     "<tr><td class='note_title'>$file</td>".
    1.99 +				"<td class='note_search'>$search</td>".
   1.100 +				"</tr><tr><td width='100%' colspan='2' class='note_text'>".
   1.101 +				"$description</td></tr><tr/>";
   1.102 +	}
   1.103 +
   1.104 +
   1.105 +	return $comment;
   1.106 +}
   1.107 +
   1.108 +=cut
   1.109 +Процедура load_command_lines_from_xml выполняет загрузку разобранного lab-скрипта
   1.110 +из XML-документа в переменную @Command_Lines
   1.111 +
   1.112 +Предупреждение!
   1.113 +Процедура не в состоянии обрабатывать XML-документ любой структуры.
   1.114 +В действительности файл cache из которого загружаются данные 
   1.115 +просто напоминает XML с виду.
   1.116 +=cut
   1.117 +sub load_command_lines_from_xml
   1.118 +{
   1.119 +	my $datafile = $_[0];
   1.120 +
   1.121 +	open (CLASS, $datafile)
   1.122 +		or die "Can't open file of the class ",$datafile,"\n";
   1.123 +	local $/;
   1.124 +	$data = <CLASS>;
   1.125 +	close(CLASS);
   1.126 +
   1.127 +	for $command ($data =~ m@<command>(.*?)</command>@sg) {
   1.128 +		my %cl;
   1.129 +		while ($command =~ m@<([^>]*?)>(.*?)</\1>@sg) {
   1.130 +			$cl{$1} = $2;
   1.131 +		}
   1.132 +		push @Command_Lines, \%cl;
   1.133 +	}
   1.134 +}
   1.135 +
   1.136 +=cut
   1.137 +Процедура print_command_lines выводит HTML-представление
   1.138 +разобранного lab-скрипта. 
   1.139 +
   1.140 +Разобранный lab-скрипт должен находиться в массиве @Command_Lines
   1.141 +=cut
   1.142 +
   1.143 +sub print_command_lines
   1.144 +{
   1.145 +	my $output_filename=$_[0];
   1.146 +
   1.147 +	my $course_name = $Config{"course-name"};
   1.148 +	my $course_code = $Config{"course-code"};
   1.149 +	my $course_date = $Config{"course-date"};
   1.150 +	my $course_center = $Config{"course-center"};
   1.151 +	my $course_trainer = $Config{"course-trainer"};
   1.152 +	my $course_student = $Config{"course-student"};
   1.153 +	
   1.154 +
   1.155 +	# Результат выполнения процедуры равен 
   1.156 +	# join("", @Result{header,body,stat,help,about,footer})
   1.157 +	my %Result;
   1.158 +	my $toc ="";  # Хранит оглавление по дням
   1.159 +
   1.160 +	$Result{"body"} = "<table width='100%'>\n";
   1.161 +	
   1.162 +	my $cl;
   1.163 +	my $last_tty="";
   1.164 +	my $last_day="";
   1.165 +	my $in_range=0;
   1.166 +
   1.167 +	for my $cl (@Command_Lines) {
   1.168 +
   1.169 +		if ($Config{"from"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"from"}/) {
   1.170 +			$in_range=1;
   1.171 +			next;
   1.172 +		}
   1.173 +		if ($Config{"to"} && $cl->{"cline"} =~ /$Config{"signature"}\s*$Config{"to"}/) {
   1.174 +			$in_range=0;
   1.175 +			next;
   1.176 +		}
   1.177 +		next if ($Config{"from"} && $Config{"to"} && !$in_range) 
   1.178 +			||
   1.179 +		    	($Config{"skip_empty"} =~ /^y/i && $cl->{"cline"} =~ /^\s*$/ )
   1.180 +			||
   1.181 +			($Config{"skip_wrong"} =~ /^y/i && $cl->{"err"} != 0)
   1.182 +			||
   1.183 +			($Config{"skip_interrupted"} =~ /^y/i && $cl->{"err"} == 130);
   1.184 +		
   1.185 +		#my @new_commands=@{$cl->{"new_commands"}};
   1.186 +		#my @new_files=@{$cl->{"new_files"}};
   1.187 +
   1.188 +		my $cl_class="cline";
   1.189 +		my $out_class="output";
   1.190 +		if ($cl->{"class"}) {
   1.191 +			$cl_class = $cl->{"class"}."_".$cl_class;
   1.192 +			$out_class = $cl->{"class"}."_".$out_class;
   1.193 +		}
   1.194 +
   1.195 +		my @new_commands;
   1.196 +		my @new_files;
   1.197 +		@new_commands = split (/\s+/, $cl->{"new_commands"}) if defined $cl->{"new_commands"};
   1.198 +		@new_files = split (/\s+/, $cl->{"new_files"}) if defined $cl->{"new_files"};
   1.199 +
   1.200 +		my $output="";
   1.201 +		if ($Config{"head_lines"} || $Config{"tail_lines"}) {
   1.202 +			# Partialy output
   1.203 +			my @lines = split '\n', $cl->{"output"};
   1.204 +			# head
   1.205 +			my $mark=1;
   1.206 +			for (my $i=0; $i<= $#lines && $i < $Config{"head_lines"}; $i++) {
   1.207 +				$output .= $lines[$i]."\n";
   1.208 +			}
   1.209 +			# tail
   1.210 +			my $start=$#lines-$Config{"tail_lines"}+1;
   1.211 +			if ($start < 0) {
   1.212 +				$start=0;
   1.213 +				$mark=0;
   1.214 +			}	
   1.215 +			if ($start < $Config{"head_lines"}) {
   1.216 +				$start=$Config{"head_lines"};
   1.217 +				$mark=0;
   1.218 +			}	
   1.219 +			$output .= $Config{"skip_text"}."\n" if $mark;
   1.220 +			for (my $i=$start; $i<= $#lines; $i++) {
   1.221 +				$output .= $lines[$i]."\n";
   1.222 +			}
   1.223 +		} 
   1.224 +		else {
   1.225 +			# Full output
   1.226 +			$output .= $cl->{"output"};
   1.227 +		}	
   1.228 +		#$output .= "^C\n" if ($cl->{"err"} eq "130");
   1.229 +
   1.230 +		#
   1.231 +		##
   1.232 +		## Начинается собственно вывод
   1.233 +		##
   1.234 +		#
   1.235 +
   1.236 +		# <command>
   1.237 +
   1.238 +		my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst) = localtime($cl->{time});
   1.239 +		# Добавляем спереди 0 для удобочитаемости
   1.240 +		$min = "0".$min if $min =~ /^.$/;
   1.241 +		$hour = "0".$hour if $hour =~ /^.$/;
   1.242 +		$sec = "0".$sec if $sec =~ /^.$/;
   1.243 +
   1.244 +		$class=$cl->{"out_class"};
   1.245 +		$class =~ s/output$//;
   1.246 +
   1.247 +		
   1.248 +		$Result{"body"} .= "<tr class='command'>\n";
   1.249 +						
   1.250 +		
   1.251 +		# DAY CHANGE
   1.252 +		if ( $last_day ne $day) {
   1.253 +			#$Result{"body"} .= "<td colspan='6'><p></p><h3>День ",$day,"</h4></td></tr><tr>";
   1.254 +			$Result{"body"} .= "<td colspan='6'><p></p><h3 id='day$day'>".$Day_Name[$wday]."</h4></td></tr><tr>";
   1.255 +			$toc .= "<li><a href='#day$day'>".$Day_Name[$wday]."</a></li>\n";
   1.256 +			$last_day=$day;
   1.257 +		}
   1.258 +
   1.259 +		# CONSOLE CHANGE
   1.260 +		if ( $last_tty ne $cl->{"tty"}) {
   1.261 +			$Result{"body"} .= "<td colspan='6'><table><tr><td class='ttychange' width='140' align='center'>".$cl->{"tty"}."</td><td/></tr></table></td></tr><tr>";
   1.262 +			$last_tty=$cl->{"tty"};
   1.263 +		}
   1.264 +
   1.265 +		# TIME
   1.266 +		if ($Config{"show_time"} =~ /^y/i) {
   1.267 +			$Result{"body"} .= "<td valign='top' class='time' width='$Config{time_width}'><pre>".
   1.268 +				$hour. ":". $min. ":". $sec.
   1.269 +				"</td>";
   1.270 +		} else {
   1.271 +			$Result{"body"} .= "<td width='0'/>"
   1.272 +		}
   1.273 +
   1.274 +		# COMMAND
   1.275 +		$Result{"body"} .= "<td class='script'>\n";
   1.276 +		$Result{"body"} .= "<pre class='${class}cline'>\n";
   1.277 +		my $cline = $cl->{"cline"};
   1.278 +		$cline =~ s/\n//;
   1.279 +		$Result{"body"} .= $cl->{"prompt"}.$cl->{"cline"};
   1.280 +		$Result{"body"} .= "</pre>\n";
   1.281 +
   1.282 +		my $last_command = $cl->{"last_command"};
   1.283 +		if (!( 
   1.284 +		$Config{"suppress_editors"} =~ /^y/i && grep ($_ eq $last_command, @{$Config{"editors"}}) ||
   1.285 +		$Config{"suppress_pagers"}  =~ /^y/i && grep ($_ eq $last_command, @{$Config{"pagers"}}) ||
   1.286 +		$Config{"suppress_terminal"}=~ /^y/i && grep ($_ eq $last_command, @{$Config{"terminal"}})
   1.287 +			)) {
   1.288 +
   1.289 +			$Result{"body"} .= "<pre class='".$cl->{out_class}."'>";
   1.290 +			$Result{"body"} .= $output;
   1.291 +			$Result{"body"} .= "</pre>\n";
   1.292 +		}	
   1.293 +
   1.294 +		# DIFF
   1.295 +		if ( $Config{"show_diffs"} =~ /^y/i && $cl->{"diff"}) {
   1.296 +			$Result{"body"} .= "<table><tr><td width='5'/><td class='diff'><pre>";
   1.297 +			$Result{"body"} .= $cl->{"diff"};
   1.298 +			$Result{"body"} .= "</pre></td></tr></table>";
   1.299 +		}
   1.300 +
   1.301 +		# COMMENT
   1.302 +		if ( $Config{"show_comments"} =~ /^y/i) {
   1.303 +			my $comment = make_comment(join(" ",@new_commands), join (" ",@new_files));
   1.304 +			if ($comment) {
   1.305 +				$Result{"body"} .= "<table width='$Config{comment_width}'>".
   1.306 +						"<tr><td width='5'/><td>";
   1.307 +				$Result{"body"} .= "<table class='note' width='100%'>";
   1.308 +				$Result{"body"} .= $comment;
   1.309 +				$Result{"body"} .= "</table>\n";
   1.310 +				$Result{"body"} .= "</td></tr></table>";
   1.311 +			}
   1.312 +			else {
   1.313 +				$Result{"body"} .= "<table width='$Config{comment_width}'>".
   1.314 +						"<tr><td width='5'/><td>";
   1.315 +				$Result{"body"} .= "<table class='note' width='100%'>";
   1.316 +				$Result{"body"} .= "commands ".join(" ",@new_commands)."<br/>";
   1.317 +				$Result{"body"} .= "files ".join(" ",@new_files)."<br/>";
   1.318 +				$Result{"body"} .= "</table>\n";
   1.319 +				$Result{"body"} .= "</td></tr></table>";
   1.320 +			}
   1.321 +		}
   1.322 +
   1.323 +		# Вывод очередной команды окончен
   1.324 +		$Result{"body"} .= "</td>\n";
   1.325 +		$Result{"body"} .= "</tr>\n";
   1.326 +	}
   1.327 +
   1.328 +	$Result{"body"} .= "</table>\n";
   1.329 +
   1.330 +	$Result{"stat"} = "<hr/>";
   1.331 +	$Result{"stat"} .= "<h2 id='stat'>Статистика</h2>";
   1.332 +	$Result{"stat"} .= "Статистическая информация о журнале<br/>";
   1.333 +	$Result{"help"} .= "<hr/>";
   1.334 +	$Result{"help"} .= "<h2 id='help'>Справка</h2>";
   1.335 +	$Result{"help"} .= "$Html_Help<br/>";
   1.336 +	$Result{"about"} .= "<hr/>";
   1.337 +	$Result{"about"} .= "<h2 id='about'>О программе</h2>";
   1.338 +	$Result{"about"} .= "$Html_About";
   1.339 +	$Result{"footer"} .= "</body>\n";
   1.340 +	$Result{"footer"} .= "</html>\n";
   1.341 +
   1.342 +	# Заголовок генерируется позже всего
   1.343 +	# Тогда, когда известно уже, что должно быть написано в 
   1.344 +	# оглавлении
   1.345 +	$Result{"header"} = <<HEADER;
   1.346 +	<html>
   1.347 +	<head>
   1.348 +	<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
   1.349 +	<link rel='stylesheet' href='labmaker.css' type='text/css'/>
   1.350 +	</head>
   1.351 +	<body>
   1.352 +	<script>
   1.353 +	$Html_JavaScript
   1.354 +	</script>
   1.355 +	<h2>Журнал лабораторных работ</h2>
   1.356 +
   1.357 +	<p>
   1.358 +	Выполнил $course_student<br/>
   1.359 +	Проверил $course_trainer <br/>
   1.360 +	Курс $course_name ($course_code),
   1.361 +	$course_date<br/>
   1.362 +	Учебный центр $course_center <br/>
   1.363 +	</p>
   1.364 +
   1.365 +	<ul>
   1.366 +		<li><a href='#log'>Журнал</a></li>
   1.367 +		<ul>$toc</ul>
   1.368 +		<li><a href='#stat'>Статистика</a></li>
   1.369 +		<li><a href='#help'>Справка</a></li>
   1.370 +		<li><a href='#about'>О программе</a></li>
   1.371 +	</ul>
   1.372 +
   1.373 +	<h2 id="log">Журнал</h2>
   1.374 +HEADER
   1.375 +	$Result{"header"} .= "<table class='visibility_form'><tr><td><form>\n";
   1.376 +	for my $element (keys %Elements_Visibility)
   1.377 +	{
   1.378 +		my @e = split /\s+/, $element;
   1.379 +		my $showhide = join "", map { "ShowHide('$_');" } @e ;
   1.380 +		$Result{"header"} .= "<input type='checkbox' name='$e[0]' onclick=\"$showhide\" checked>".
   1.381 +				$Elements_Visibility{$element}.
   1.382 +				"</input><br>\n";
   1.383 +	}
   1.384 +
   1.385 +	$Result{"header"} .= "</form></td></tr></table>\n";
   1.386 +
   1.387 +	open(OUT, ">", $output_filename)
   1.388 +		or die "Can't open $output_filename for writing\n";
   1.389 +	print OUT $Result{"header"}, $Result{"body"}, $Result{"stat"}, $Result{"help"}, $Result{"about"}, $Result{"footer"};
   1.390 +	close(OUT);
   1.391 +}
   1.392 +
   1.393 +
   1.394 +
   1.395 +
   1.396 +
   1.397 +
   1.398 +sub init_variables
   1.399 +{
   1.400 +$Html_Help = <<HELP;
   1.401 +	Справка по использованию журнала
   1.402 +HELP
   1.403 +
   1.404 +$Html_About = <<ABOUT;
   1.405 +	<p>
   1.406 +	LiLaLo (L3) расшифровывается как Live Lab Log.<br/>
   1.407 +	Программа разработана для повышения эффективности обучения<br/>
   1.408 +	Unix/Linux-системам.<br/>
   1.409 +	(c) Игорь Чубин, 2004-2005<br/>
   1.410 +	</p>
   1.411 +ABOUT
   1.412 +$Html_About.='$Id$ </p>';
   1.413 +
   1.414 +$Html_JavaScript = <<JS;
   1.415 +	function getElementsByClassName(Class_Name)
   1.416 +	{
   1.417 +		var Result=new Array();
   1.418 +		var All_Elements=document.all || document.getElementsByTagName('*');
   1.419 +		for (i=0; i<All_Elements.length; i++)
   1.420 +			if (All_Elements[i].className==Class_Name)
   1.421 +		Result.push(All_Elements[i]);
   1.422 +		return Result;
   1.423 +	}
   1.424 +	function ShowHide (name)
   1.425 +	{
   1.426 +		elements=getElementsByClassName(name);
   1.427 +		for(i=0; i<elements.length; i++)
   1.428 +			if (elements[i].style.display == "none")
   1.429 +				elements[i].style.display = "";
   1.430 +			else
   1.431 +				elements[i].style.display = "none";
   1.432 +			//if (elements[i].style.visibility == "hidden")
   1.433 +			//	elements[i].style.visibility = "visible";
   1.434 +			//else
   1.435 +			//	elements[i].style.visibility = "hidden";
   1.436 +	}
   1.437 +	function filter_by_output(text)
   1.438 +	{
   1.439 +		
   1.440 +		var jjj=0;
   1.441 +		
   1.442 +		elements=getElementsByClassName('command');
   1.443 +		for(i=0; i<elements.length; i++) {
   1.444 +			subelems = elements[i].getElementsByTagName('pre');
   1.445 +			for(j=0; j<subelems.length; j++) {
   1.446 +				if (subelems[j].className = 'output') {
   1.447 +					var str = new String(subelems[j].nodeValue);
   1.448 +					if (jjj != 1) { 
   1.449 +						alert(str);
   1.450 +						jjj=1;
   1.451 +					}
   1.452 +					if (str.indexOf(text) >0) 
   1.453 +						subelems[j].style.display = "none";
   1.454 +					else
   1.455 +						subelems[j].style.display = "";
   1.456 +
   1.457 +				}
   1.458 +					
   1.459 +			}
   1.460 +		}		
   1.461 +
   1.462 +	}
   1.463 +JS
   1.464 +
   1.465 +%Search_Machines = (
   1.466 +		"google" => 	{ 	"query" => 	"http://www.google.com/search?q=" ,
   1.467 +					"icon" 	=> 	"google.ico" },
   1.468 +		"freebsd" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=",
   1.469 +					"icon"	=>	"freebsd.ico" },
   1.470 +		"linux"  => 	{ 	"query" => 	"http://man.he.net/?topic=",
   1.471 +					"icon"	=>	"linux.ico"},
   1.472 +		"opennet"  => 	{ 	"query" => 	"http://www.opennet.ru/search.shtml?words=",
   1.473 +					"icon"	=>	"opennet.ico"},
   1.474 +		"local" => 	{ 	"query" => 	"http://www.freebsd.org/cgi/man.cgi?query=",
   1.475 +					"icon"	=>	"freebsd.ico" },
   1.476 +
   1.477 +	);
   1.478 +
   1.479 +%Elements_Visibility = (
   1.480 +		"note"		=>	"замечания",
   1.481 +		"diff"		=>	"редактор",
   1.482 +		"time"		=>	"время",
   1.483 +		"ttychange" 	=>	"терминал",
   1.484 +		"wrong_output wrong_cline wrong_root_output wrong_root_cline" 
   1.485 +				=>	"команды с ошибками",
   1.486 +		"interrupted_output interrupted_cline interrupted_root_output interrupted_root_cline" 
   1.487 +				=>	"прерванные команды",
   1.488 +		"tab_completion_output tab_completion_cline"	
   1.489 +				=> 	"продолжение с помощью tab"
   1.490 +);
   1.491 +
   1.492 +@Day_Name      = qw/ Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота /;
   1.493 +@Month_Name    = qw/ Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь /;
   1.494 +@Of_Month_Name = qw/ Января Февраля Марта Апреля Мая Июня Июля Августа Сентября Октября Ноября Декабря /;
   1.495 +}
   1.496 +