|
|
|
| Ответ 003 на задачу N 21.
С условиями задачи можно ознакомится по ссылке.
мой вариант этого скрипта состоит из 4 файлов
#index.php
#function.php
#config.php
#script.js
Полная версия http://ifolder.ru/2188559 пароль от архива: zahtet
#index.php
<?php
session_start(); //старт сессиии
require "config.php"; //подключаем файл конфига
require "function.php"; //подключаем файл функций
$db = @mysql_connect($config['dbhost'],$config['dbuser'],$config['dbpassword']) or die(html_out("<p><font color='red'>Ошибка соединения с базой!</font></p>")); //соеденяемся с базой
@mysql_select_db($config['dbname'],$db) or die(html_out("<p><font color='red'>Ошибка выбора таблицы из базы данных!</font></p>")); //выбираем таблицу
$ath = array(); //массив результатов от запросов
$out = ""; //переменная в которую заносятся HTML фрагменты
if(!$_SESSION['name']) { //если нет в сессии такого ключа
$name = $_POST['user'];
if(empty($name)) { //если нет значения переданного POST методом,то печатаем форму
$out .= <<<EOF
<form method='POST'>
Введите ваше имя:<input type='text' name='user'>
<input type='submit' value='Отправить'>
</form>
EOF;
}
else { //если есть значение переданное POST методом,то заносим это значение в сессию
$_SESSION['name'] = $name;
header("Location:index.php"); //и перенаправляем на главную
}
}
else { //если есть такой ключв сессии
$lenght = strlen($_SESSION['name']); //длина имени
$out .= <<<EOF
Привет, {$_SESSION['name']}! Вы знаете, что в Вашем имени {$lenght} символов?<br><br>Нас уже посетили:<br>
EOF;
$search = $_GET['search']; //если будем искать
$delrec = $_GET['delrec']; // если будет удалять запись
$exit = $_GET['exit']; //если выходим
if($search) { //сработает в том случае если ищем
$search = trim($search); //удаляем ненужные пробелы в строке
$out = <<<EOF
<p><b>Результаты поиска</b></p>
EOF;
if($search == "") { //если строка пустая то выводим сообщение об этом
$out .= <<<EOF
<p>Необходимо ввести текст для поиска!</p><br>
<a href='index.php'>Вернуться назад</a><br>
(<a href='index.php?exit=1'>Выход</a>)
EOF;
print html_out($out); //так как дальше мы не собираемся выводить таблицу с данными,то делаем слудующие вещи
mysql_close($db);
exit();
}
else {
$ath = mquery("SELECT id,guestname,visits FROM guests WHERE guestname='{$search}'",$db); //ищем в базе значение равное строке
$guest = mysql_fetch_array($ath,MYSQL_ASSOC); //переводим в массив
if(!$guest) { //если массив пустой,значит нечего не нашли,следовательно вывоим сообщение об этом
$out .= <<<EOF
<p>По вашему запросу ничего не найдено!</p><br>
<a href='index.php'>Вернуться назад</a><br>
(<a href='index.php?exit=1'>Выход</a>)
EOF;
}
else { //если нашли что то,то записывает в HTML фрагмент
$out .= <<<EOF
<table border='1' cellpadding='0' cellspacing='0' width='100%'>
<tr>
<td align='center'>Гость</td>
<td align='center'>Визит</td>
<td align='center'>X</td>
</tr>
<tr>
<td align='center'>{$guest['guestname']}</td>
<td align='center'>{$guest['visits']}</td>
<td align='center'><a href='javascript:delrecord("{$guest['guestname']}","{$guest['id']}")'>Удалить</a></td>
</tr>
</table><br>
<a href='index.php'>Вернуться назад</a><br>
(<a href='index.php?exit=1'>Выход</a>)
EOF;
}
print html_out($out); //так как дальше мы не собираемся выводить таблицу с данными,то делаем слудующие вещи
mysql_close($db);
exit();
}
}
if($delrec) { //если будем удалять запись
if(!is_numeric($delrec)) { //проверяем является ли параметр числом
header("Location:{$_SERVER['HTTP_REFERER']}"); //если нет,то возвращаем туда откуда пришли
}
else {
$ath = mquery("SELECT id FROM guests WHERE id='{$delrec}'",$db); //проверяем есть ли такая запись
if(mysql_num_rows($ath)) {
mquery("DELETE FROM guests WHERE id='{$delrec}'",$db); //если да то выполняем запрос на удаление
header("Location:{$_SERVER['HTTP_REFERER']}");
}
else {
header("Location:{$_SERVER['HTTP_REFERER']}"); //если нет такой записи,то возвращаем туда откуда пришли
}
}
}
if($exit) { //если собираемя выходить
session_destroy(); //уничтожаем сессию
header("Location:index.php"); //перенаправляем на главную страницу
}
if(!$_SESSION['visited']) { //проверяем сколько раз зашел гость,соответственно сейчас он еще официально не зашел,если пустое значение в сесиии
$ath = mquery("SELECT id FROM guests WHERE guestname='{$_SESSION['name']}'",$db); //проверяем есть ли такое значение в базе
if(!mysql_num_rows($ath)) {
mquery("INSERT INTO guests(guestname,visits) VALUES('{$_SESSION['name']}','1')",$db); //если нет то записывает в базу данные
}
else {
$ath = mquery("SELECT visits FROM guests WHERE guestname='{$_SESSION['name']}'",$db); //если есть то выбираем сколько раз посещал гость страницу
$visits = mysql_result($ath,0); //если каким то образом не получилось выбрать значние,то оно будет равно нулю
if(!$visits) {
$visits = 0;
}
$visits++; //увеличиваем на единицу,так как зашли
mquery("UPDATE guests SET visits='{$visits}' WHERE guestname='{$_SESSION['name']}'",$db); //обновляем данные
}
$_SESSION['visited'] = 1; //это означает что пользователь точно зашел)))
}
$out .= <<<EOF
<table border='1' cellpadding='0' cellspacing='0' width='100%'>
<tr>
<td align='center'>N</td>
<td align='center'>Гость</td>
<td align='center'>Визит</td>
<td align='center'>X</td>
</tr>
EOF;
$npos = 1; //Начальное значение нумерации
$guests = array(); //массив с данными
$ath = mquery("SELECT id,guestname,visits FROM guests ORDER BY id DESC",$db); //запрос но выбор всех данных
while($all = mysql_fetch_array($ath,MYSQL_ASSOC)) {
$guests[] = array('pos' => $npos,'id' => $all['id'],'guestname' => $all['guestname'],'visits' => $all['visits']); //выбранные данные в цикле,заносим в массив
$npos++;
}
if(!$guests) { //если массив пустой,значит что значений в базе нет.Выводим соответствующее сообщение
$out .= <<<EOF
<tr>
<td align='center' colspan='4'><b>Нет записей</b></td>
</tr>
EOF;
}
else { //если есть то в цикле,заносим в HTML фрагменты
foreach ($guests as $gst) {
$out .= <<<EOF
<tr>
<td align='center'>{$gst['pos']}</td>
<td align='center'>{$gst['guestname']}</td>
<td align='center'>{$gst['visits']}</td>
<td align='center'><a href='javascript:delrecord("{$gst['guestname']}","{$gst['id']}")'>Удалить</a></td>
</tr>
EOF;
}
}
$out .= <<<EOF
</table><br>
<form method='GET'>
Поиск гостя:<input type='text' name='search'>
<input type='submit' value='Искать'>
</form><br>
(<a href='index.php?exit=1'>Выход</a>)
EOF;
}
print html_out($out); //выводи получившиеся фрагменты
mysql_close($db);
?>
|
#function.php
?php
//функция для внесения HTML обьектов в правильный формат
function html_out($code) {
return <<<EOF
<html>
<head>
<title>Список Гостей</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<script language="JavaScript" src="script.js"></script>
</head>
<body>
{$code}
</body>
</html>
EOF;
}
//функция для запросов,в случае false,выведет красиво сообщение об ошибке))
function mquery($sql,$link) {
$result = @mysql_query($sql,$link);
if(!$result) {
print html_out("<b>Ошибка запроса!</b></br><pre>{$sql}</pre><br><font color='red'>Ответ MySQL:" .mysql_error() ."</font><br>");
exit();
}
else {
return $result;
}
}
?>
|
#config.php
<?php
$config['dbhost'] = ""; //хост
$config['dbname'] = ""; //имя базы
$config['dbuser'] = ""; //имя пользователя базы
$config['dbpassword'] = ""; //пароль от базы
?>
|
#script.js
function delrecord(name,id) {
if (confirm(name+'! Вы действительно желаете себя удалить?')) {
top.location = 'index.php?delrec='+id;
}
}
|
http://www.softtime.ru/info/task.php?id_article=110 | |
|
|
|
|
|
|
|
для: SoftTime
(30.05.2007 в 22:50)
| | 1) 234 строк в 4 файлах, читабельность средняя, комментарии присутствуют.
2) Много файлов, это не критично, так как задача объёмная - скорее своеобразный Notice :)
3) При создании динамических запросов не обрабатываются кавычки - это приводит к тому, что возможна SQL-инъекция http://www.softtime.ru/article/index.php?id_article=81. Кроме того, пользователи вида "i don't know" войти уже не смогут. Все тектовые строки перед помещением в SQL-запрос следует обрабатывать при помощи конструкции
<?php
if (!get_magic_quotes_gpc())
{
$_POST['guestname'] = mysql_escape_string($_POST['guestname']);
}
?>
|
А собственно одна из главных особенностей этого задания - корректная вставка текста в СУБД.
4) Привязка к названию файла (index.php) - плохо.
5) Зря используете конструкцию <<<EOF - она достаточно капризная, у меня например запустить скрипт не удалось
6) Есть обработка ошибок SQL-запросов - хорошо.
7) Зря ориентируетесь на $_SERVER['HTTP_REFERER'] - например FireWall Outpost может его просто отсекать, да и ряд браузеров эти промышляют при должной настройке. | |
|
|
|
|
|
|
|
для: cheops
(01.06.2007 в 12:11)
| | Насчет <<<EOF ,помоему ничего плохого в нем нет,а наоборот даже хорошо,если например сочитать JavaScript с php где нужны кавычки.И еще быть такого не может чтобы из за этой конструкции не могло запустится.Я проверял везде работало нормально!
А если про последний пункт это да,тут я просто не подумал что может неправильно работать | |
|
|
|
|
|
|
|
для: SoftTime
(30.05.2007 в 22:50)
| | автор ответа 003 оказался первым, чей скрипт просто не захотел у меня работать.
Сжалившись, ну и из интереса тоже, я отключил диагностику нотайсов. Только тогда скрипт стал что-то делать.
В отличие от cheops'а, у меня с примененными heredoc-строками проблем не было.
Всё пошло как надо.
Скрипт не работает с символами процента и с амперсендами...
Хочу отметить очень приятный вид таблицы. :) У меня самого такой не получился.
Немного скриншотов процесса проверки см. в аттаче | |
|
|
|
|
|
|
|
для: Trianon
(01.06.2007 в 18:44)
| | возможно они не работали потому что после EOF; были пробелы
А где аттач взять? | |
|
|
|
|
|
|
|
для: ZAHTET
(01.06.2007 в 18:49)
| | >возможно они не работали потому что после EOF; были пробелы
ну а у меня они тогда куда делись? :)))
>А где аттач взять?
Не берут у меня архивы.
Глядите здесь. | |
|
|
|
|
|
|
|
для: Trianon
(01.06.2007 в 20:56)
| | Ну раз разрешили исправить,то я воспользуюсь этим
вот новое решение
4 файла
#главный файл(любое название)
#function.php
#config.php
#script.js
#главный файл(любое название)
<?php
ob_start(); //включаем буфферизированный вывод,для обхода ошибок header'а
session_start(); //старт сессиии
require "config.php"; //подключаем файл конфига
require "function.php"; //подключаем файл функций
$db = @mysql_connect($config['dbhost'],$config['dbuser'],$config['dbpassword']) or die(html_out("<p><font color='red'>Ошибка соединения с базой!</font></p>")); //соеденяемся с базой
@mysql_select_db($config['dbname'],$db) or die(html_out("<p><font color='red'>Ошибка выбора таблицы из базы данных!</font></p>")); //выбираем таблицу
$ath = array(); //массив результатов от запросов
$out = ""; //переменная в которую заносятся HTML фрагменты
$url = "http://". $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; //полный адрес на котором расположен скрипт
if(!$_SESSION['name']) { //если нет в сессии такого ключа
$name = trim($_POST['user']);
if(empty($name)) { //если нет значения переданного POST методом,то печатаем форму
$out .= "
<form method='POST'>
Введите ваше имя:<input type='text' name='user'>
<input type='submit' value='Отправить'>
</form>
";
}
else { //если есть значение переданное POST методом,то заносим это значение в сессию
$_SESSION['name'] = text('do',$name);
$_SESSION['lenght'] = strlen(text('view',$name)); //записываем длину имени в сессию
header("Location:{$url}"); //и перенаправляем
}
}
else { //если есть такой ключв сессии
$out .= "Привет, {$_SESSION['name']}! Вы знаете, что в Вашем имени {$_SESSION['lenght']} символов?<br><br>Нас уже посетили:<br>";
$search = text('do',$_GET['search']); //если будем искать
$delrec = intval($_GET['delrec']); // если будет удалять запись,преобраховываем в чило на всякий случай
$exit = $_GET['exit']; //если выходим
if($search) { //сработает в том случае если ищем
$search = trim($search); //удаляем ненужные пробелы в строке
$out = "<p><b>Результаты поиска</b></p>";
if($search == "") { //если строка пустая то выводим сообщение об этом
$out .= "
<p>Необходимо ввести текст для поиска!</p><br>
<a href='{$url}'>Вернуться назад</a><br>
(<a href='{$url}?exit=1'>Выход</a>)
";
print html_out($out); //так как дальше мы не собираемся выводить таблицу с данными,то делаем слудующие вещи
mysql_close($db);
exit();
}
else {
$ath = mquery("SELECT id,guestname,visits FROM guests WHERE guestname='{$_SESSION['name']}'",$db); //ищем в базе значение равное строке
$guest = mysql_fetch_array($ath,MYSQL_ASSOC); //переводим в массив
if(!$guest) { //если массив пустой,значит нечего не нашли,следовательно вывоим сообщение об этом
$out .= "
<p>По вашему запросу ничего не найдено!</p><br>
<a href='{$url}'>Вернуться назад</a><br>
(<a href='{$url}?exit=1'>Выход</a>)
";
}
else { //если нашли что то,то записывает в HTML фрагмент
$out .= "
<table border='1' cellpadding='0' cellspacing='0' width='100%'>
<tr>
<td align='center'>Гость</td>
<td align='center'>Визит</td>
<td align='center'>X</td>
</tr>
<tr>
<td align='center'>{$guest['guestname']}</td>
<td align='center'>{$guest['visits']}</td>
<td align='center'><a href=\"javascript:delrecord('{$guest['guestname']}','{$guest['id']}')\">Удалить</a></td>
</tr>
</table><br>
<a href='{$url}'>Вернуться назад</a><br>
(<a href='{$url}?exit=1'>Выход</a>)
";
}
print html_out($out); //так как дальше мы не собираемся выводить таблицу с данными,то делаем слудующие вещи
mysql_close($db);
exit();
}
}
if($delrec) { //если будем удалять запись
if(!is_numeric($delrec)) { //проверяем является ли параметр числом
header("Location:{$url}"); //если нет,то возвращаем туда откуда пришли
}
else {
$ath = mquery("SELECT id FROM guests WHERE id='{$delrec}'",$db); //проверяем есть ли такая запись
if(mysql_num_rows($ath)) {
mquery("DELETE FROM guests WHERE id='{$delrec}'",$db); //если да то выполняем запрос на удаление
header("Location:{$url}");
}
else {
header("Location:{$url}"); //если нет такой записи,то возвращаем туда откуда пришли
}
}
}
elseif($exit) { //если собираемя выходить
session_destroy(); //уничтожаем сессию
header("Location:{$url}"); //перенаправляем на главную страницу
}
else {
if(!$_SESSION['visited']) { //проверяем сколько раз зашел гость,соответственно сейчас он еще официально не зашел,если пустое значение в сесиии
$ath = mquery("SELECT id FROM guests WHERE guestname='{$_SESSION['name']}'",$db); //проверяем есть ли такое значение в базе
if(!mysql_num_rows($ath)) {
mquery("INSERT INTO guests(guestname,visits) VALUES('{$_SESSION['name']}','1')",$db); //если нет то записывает в базу данные
}
else {
$ath = mquery("SELECT visits FROM guests WHERE guestname='{$_SESSION['name']}'",$db); //если есть то выбираем сколько раз посещал гость страницу
$visits = mysql_result($ath,0); //если каким то образом не получилось выбрать значние,то оно будет равно нулю
if(!$visits) {
$visits = 0;
}
$visits++; //увеличиваем на единицу,так как зашли
mquery("UPDATE guests SET visits='{$visits}' WHERE guestname='{$_SESSION['name']}'",$db); //обновляем данные
}
$_SESSION['visited'] = 1; //это означает что пользователь точно зашел)))
}
$out .= "
<table border='1' cellpadding='0' cellspacing='0' width='100%'>
<tr>
<td align='center'>N</td>
<td align='center'>Гость</td>
<td align='center'>Визит</td>
<td align='center'>X</td>
</tr>
";
$npos = 1; //Начальное значение нумерации
$guests = array(); //массив с данными
$ath = mquery("SELECT id,guestname,visits FROM guests ORDER BY id DESC",$db); //запрос но выбор всех данных
while($all = mysql_fetch_array($ath,MYSQL_ASSOC)) {
$guests[] = array('pos' => $npos,'id' => $all['id'],'guestname' => $all['guestname'],'visits' => $all['visits']); //выбранные данные в цикле,заносим в массив
$npos++;
}
if(!$guests) { //если массив пустой,значит что значений в базе нет.Выводим соответствующее сообщение
$out .= "
<tr>
<td align='center' colspan='4'><b>Нет записей</b></td>
</tr>
";
}
else { //если есть то в цикле,заносим в HTML фрагменты
foreach ($guests as $gst) {
$out .= "
<tr>
<td align='center'>{$gst['pos']}</td>
<td align='center'>{$gst['guestname']}</td>
<td align='center'>{$gst['visits']}</td>
<td align='center'><a href=\"javascript:delrecord('{$gst['guestname']}','{$gst['id']}')\">Удалить</a></td>
</tr>
";
}
}
$out .= "
</table><br>
<form method='GET'>
Поиск гостя:<input type='text' name='search'>
<input type='submit' value='Искать'>
</form><br>
(<a href='{$url}?exit=1'>Выход</a>)
";
}
}
print html_out($out); //выводи получившиеся фрагменты
mysql_close($db);
?>
|
#function.php
<?php
//функция для внесения HTML обьектов в правильный формат
function html_out($code) {
return <<<EOF
<html>
<head>
<title>Список Гостей</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<script language="JavaScript" src="script.js"></script>
</head>
<body>
{$code}
</body>
</html>
EOF;
}
//функция для запросов,в случае false,выведет красиво сообщение об ошибке))
function mquery($sql,$link) {
$result = @mysql_query($sql,$link);
if(!$result) {
print html_out("<b>Ошибка запроса!</b></br><pre>{$sql}</pre><br><font color='red'>Ответ MySQL:" .mysql_error() ."</font><br>");
exit();
}
else {
return $result;
}
}
//функция для обработки строки теста,используется своя замена
function text($type,$str) {
if($type == 'do') {
$str = trim($str);
$str = strtr($str,
array(
'"'=>'"',
'$'=>'$',
'%' => '%',
"'" => '"',
" " => ' ',
'-' => '-',
'&' => '&',
'<' => '<',
'>' => '>',
'^' => '^',
'_' => '_',
'`' => '`',
'{' => '{',
'|' => '|',
'}' => '}',
'~' => '~',
'‘' => '‘',
'’' => '’',
'“' => '“',
'”' => '”',
'–' => '–',
'—' => '—',
'¦' => '¦',
' ' => ' '
));
$str = stripslashes($str);
return $str;
}
elseif($type == 'view') {
$str = stripslashes($str);
return $str;
}
}
?>
|
#config.php
<?php
$config['dbhost'] = ""; //хост
$config['dbname'] = ""; //имя базы
$config['dbuser'] = ""; //имя пользователя базы
$config['dbpassword'] = ""; //пароль от базы
?>
|
#script.php
function delrecord(name,id) {
if (confirm(name+'! Вы действительно желаете себя удалить?')) {
top.location = '?delrec='+id;
}
}
|
| |
|
|
|
|
|
|
|
для: ZAHTET
(04.06.2007 в 22:18)
| | /DELETED/
---------
Не могу удалить ни одного юзера, в имени которого есть двойная кавычка ("). | |
|
|
|
|
|
|
|
для: sms-send
(04.06.2007 в 22:36)
| | А где вы это увидели?У меня нет в моем коде этого))
Да и двойные удаляются нормально,без ошибки | |
|
|
|
|
|
|
|
для: ZAHTET
(04.06.2007 в 22:39)
| | Сорри, проглючило. | |
|
|
|
|
|
|
|
для: ZAHTET
(04.06.2007 в 22:18)
| | script.php - лишний файл. Я воспользовался старым script.js
В этот раз мне и вправду пришлось подправлять heredoc.
Но как я понимаю, это вина автора не скрипта, а скорее движка форума,
точнее той его части, которая выполняет построение [code]-фрагментов.
тег <br /> следует располагать в конце теркущей строки, а не вначале следующей.
Тогда текст, выделенный в окне, копируется без добавления пробелов.
А еще компилятор просто встал на коде функции text().
Не знаю, на что расчитывал автор, но при попытке взять копи-пастом текст в FAR,
в нем искажается изрядно символов.
Я долго пытался понять, в чем загвоздка, и чем вытаскивать код.
Потом сделал копи-паст через phpExpertEditor и всё встало на свои места.
Заодно выяснилось, что и хвостовые пробелы не вызывали проблем
в прошлый раз тоже именно в phpExpertEditor.
По делу.
Скрипт всё также некорректно отображает символы в таблице.
например имена & и & он выводит одинаково - одним амперсендом.
И точно также глотает символы в имени total %25 of sales (в js-алерте).
Так что по главному требованию увы - незачет.
Зато скрипт устойчиво переносит разного рода издевательства,
направленные на вскрытие побочных эффектов.
F5, Go forward, Go back и т.п. ему не страшны. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 14:14)
| | Щас попробую протестировать заного
странно,у меня работало в js все фразы разной сложности,и с & не было проблем | |
|
|
|
|
|
|
|
для: ZAHTET
(05.06.2007 в 14:19)
| | напоминаю, дамп из http://softtime.ru/forum/read.php?id_forum=7&id_theme=38452 (01.06.2007 в 21:41) вполне может пригодиться. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 14:27)
| | Ну вот я щас все эти предложения и слова протестировал,все работает и нормально удаляется
Ну раз у вас не работает то ладно,если так решили | |
|
|
|
|
|
|
|
для: ZAHTET
(05.06.2007 в 14:33)
| | И в таблице БД создаются такие же строки?
Очень я сомневаюсь. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 14:40)
| | Я просто думаю что в Бд лежали старые данные со старой проверки,которые не были обработаны,естественно ошибка могла возикнуть))
Я наверное не так понял,в этом дампе данные которые нужно ввести в имя гостя или они уже заранее в базе лежат? | |
|
|
|
|
|
|
|
для: ZAHTET
(05.06.2007 в 14:33)
| | Вот я вхожу именем Mc'robbins, будь он неладен.
Скрипт приветствует меня как Mc"robbins
и заводит еще одну запись в таблице.
Причем в таблице имя выглядит как Mc"robbins
Вы полагаете - это нормальная работа?
Я ничего не решаю. Решает cheops. Я показываю ошибки. | |
|
|
|
|
|
|
|
для: Trianon
(05.06.2007 в 14:48)
| | Какую кодировку база использует?
Вопрос к обоим. | |
|
|
|
|
|
|
|
для: Eugene77
(05.06.2007 в 19:33)
| | А если не секрет то для чего эта информация нужна?
у меня utf8 используется | |
|
|
|
|
|
|
|
для: ZAHTET
(05.06.2007 в 20:13)
| | Вот и я тоже ума не приложу.
Дамп я специально в текстовом виде положил.
Имена в нем никакой кириллицы не содержат.
Настройки определяются скриптом соединения с базой.
В чем хошь - в том и применяй.... | |
|
|
|
|