Ошибки-ловушки при программировании на Паскале

115 views
Skip to first unread message

Leo B.

unread,
Jun 16, 2017, 5:28:39 PM6/16/17
to БЭСМ-6
Что напечатает, если скомпилируется, эта программа:

PROGRAM MAIN(OUTPUT);
TYPE STRING=PACKED ARRAY[1..0]OF CHAR;
VAR L: STRING;
BEGIN WRITELN(L) END.

А эта?

PROGRAM MAIN(OUTPUT);
TYPE STRING=PACKED ARRAY[2..0]OF CHAR;
VAR L: STRING;
BEGIN WRITELN(L) END.

Leo

Mikhail Popov

unread,
Jun 18, 2017, 12:58:40 PM6/18/17
to be...@googlegroups.com
Leo, is it startindex must be less than or equal to endindex?



From: Leo B. <leo...@gmail.com>
To: БЭСМ-6 <be...@googlegroups.com>
Sent: Friday, June 16, 2017 2:28 PM
Subject: [besm-6] Ошибки-ловушки при программировании на Паскале

--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.


Leo B.

unread,
Jun 18, 2017, 4:43:49 PM6/18/17
to БЭСМ-6, mikh...@pacbell.net
Обе программы компилируются, но первая печатает много мусора, а вторая -

PUT(F) EOF=FALSE

 PASCAL PM DUMP
 STACK IS SPOILED

Leo


On Sunday, June 18, 2017 at 9:58:40 AM UTC-7, mikhailp wrote:
Leo, is it startindex must be less than or equal to endindex?



From: Leo B.
To: БЭСМ-6

Sent: Friday, June 16, 2017 2:28 PM
Subject: [besm-6] Ошибки-ловушки при программировании на Паскале
Что напечатает, если скомпилируется, эта программа:

PROGRAM MAIN(OUTPUT);
TYPE STRING=PACKED ARRAY[1..0]OF CHAR;
VAR L: STRING;
BEGIN WRITELN(L) END.

А эта?

PROGRAM MAIN(OUTPUT);
TYPE STRING=PACKED ARRAY[2..0]OF CHAR;
VAR L: STRING;
BEGIN WRITELN(L) END.

Leo

--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+unsubscribe@googlegroups.com.

Василий Долматов

unread,
Jun 19, 2017, 3:04:15 AM6/19/17
to be...@googlegroups.com, mikh...@pacbell.net
B глухой сибирской тайге мужики валили лес двуручными пилами.
Однажды прислали им японскую лесопилку, которую наши мужики
решили тут-же испытать на прочность. Взяли и положили на лесопилку
здоровую сосну.
-"Вж-ж-ж-жик!"-сказала японская лесопилкка.
-"Ух,ты!"-удивились мужики и положили на лесопилку здоровенный дуб.
-"Вж-ж-ж-жик!"-сказала японская лесопилка.
-"Ух,ты!!"-пуще прежнего удивились наши мужики и положили на лесопилку
железный лом.
-"Вж...Тр-р-пр-р-пук..."-сказала японская лесопилка.
-"АГА!!!!!"-восторженно заорали мужики и пошли валить лес двуручными
пилами.

18 июня 2017 г., в 23:43, Leo B. <leo...@gmail.com> написал(а):

Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
signature.asc

Leo Broukhis

unread,
Jun 19, 2017, 3:49:31 AM6/19/17
to БЭСМ-6
Вот ты смеешься, а восстанавливать исходник Паскаль-компилятора надо.

Leo

Макаров-Землянский Николай

unread,
Jun 19, 2017, 3:53:21 AM6/19/17
to be...@googlegroups.com
Восстановить, наверное, надо. Но исправлять ошибки компилятора НЕ НАДО!
Он должен остаться такой, как был.
Кстати, а как Делфи себя ведет? Если будет время, сегодня посмотрю.
 
 
19.06.2017, 10:49, "Leo Broukhis" <le...@mailcom.com>:
--

Leo B.

unread,
Jun 20, 2017, 2:01:44 PM6/20/17
to БЭСМ-6
С Делфи я никогда в жизни дела не имел, поэтому жду результатов.

На "историческом" образе диска, конечно, компилятор останется, какой был. А альтернативных версий, если будут,
можно будет на альтернативных дисках иметь сколько угодно.

Кстати, я, наконец, разобрался, как работал "оператор ветвления" в Паскале-Автокоде
(https://github.com/besm6/besm6.github.io/blob/master/wiki/pascal-autocode.txt строка 1649).
Это такое бросание исключений, в котором вместо типов, как в С++ - значения выражений,
и ноль - вместо catch(...).

Однако, невнятное описание, надуманный и содержащий не относящиеся к делу детали пример,
и странная диагностика "выход по ALT" заставляют думать,
что синтаксис и семантика не придуманы Пириным из головы, а откуда-то скопированы.

Leo
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+unsubscribe@googlegroups.com.

Serguei Tarassov

unread,
Jun 21, 2017, 9:04:39 AM6/21/17
to БЭСМ-6
Delphi такое просто не компилирует (тип STRING заменен на STRING1)
TYPE STRING1=PACKED ARRAY[1..0]OF CHAR;
[Error] Project2.dpr(3): Low bound exceeds high bound

Макаров-Землянский Николай

unread,
Jun 21, 2017, 10:25:25 AM6/21/17
to be...@googlegroups.com
У меня такое впечатление, что по Вирту так:
TYPE STRING=PACKED ARRAY[1..0]OF CHAR;
писать нельзя.
STRING - зарезервированное слово. Хотя, могу ошибаться.
Бегло посмотрел - точно нельзя. Хотя стандарта на Паскаль практически нет.
 
21.06.2017, 16:04, "Serguei Tarassov" <se...@arbinada.com>:
--

Макаров-Землянский Николай

unread,
Jun 21, 2017, 10:34:43 AM6/21/17
to be...@googlegroups.com
Про Паскаль на БЭСМ-6. Цитата из текстов Краба (Ф10, стр 42):
*      "ПРОГРАММЫ МОГУТ СОДЕРЖАТЬ ОШИБКИ И ОЧЕНЬ^
*   СЕРЬЕЗНЫЕ. НАЛИЧИЕ ОШИБОК В ПРОГРАММАХ МОЖНО^
*   СЧИТАТЬ НЕИЗБЕЖНЫМ; ПРОГРАММА, СВОБОДНАЯ ОТ^
*   ОШИБОК, ЯВЛЯЕТСЯ ТАКОЙ ЖЕ АБСТРАКЦИЕЙ, КАК В^
*   ТЕРМОДИНАМИКЕ АБСОЛЮТНЫЙ НУЛЬ, КОТОРЫЙ МОЖНО^
*   РАССМАТРИВАТЬ ТЕОРЕТИЧЕСКИ, НО КОТОРОГО НЕЛЬЗЯ^
*   ДОСТИГНУТЬ."^
*^
*                  JАСОВ Т. SСНWАRТZ.^
*      СОURАNТ INSТIТUТЕ ОF МАТНЕМАТIСАL SСIЕNСЕS^
*      NЕW УОRК UNIVЕRSIТУ.^
*^
 
 
 
 
21.06.2017, 17:25, "Макаров-Землянский Николай" <nv...@yandex.ru>:

Leo B.

unread,
Jun 21, 2017, 1:32:31 PM6/21/17
to БЭСМ-6


On Wednesday, June 21, 2017 at 6:04:39 AM UTC-7, Serguei Tarassov wrote:
Delphi такое просто не компилирует (тип STRING заменен на STRING1)
TYPE STRING1=PACKED ARRAY[1..0]OF CHAR;
[Error] Project2.dpr(3): Low bound exceeds high bound

Неудивительно. Интересно, как оно было в первых версиях Паскаля (UCSD), когда памяти было мало.
Диагностировать все семантические ошибки было бы довольно расточительно.

Leo

Leo B.

unread,
Jun 21, 2017, 5:44:45 PM6/21/17
to БЭСМ-6
Как раньше писали под некоторыми карикатурами в советских газетах, "Без слов".

 00001    1  0 PROGRAM MAIN(OUTPUT);
 00001    2  1 VAR P5, M5, P3, M3: INTEGER;
 00007    3  2 BEGIN
 00010    4  2  P5:=5; P3:=3; M5:=-5; M3:=-3;
 00014    5  2  WRITELN(’           5 MOD 3 | -5 MOD 3 | 5 MOD -3 | -5 MOD -3’);
 00017    6  2  WRITELN(’ CONST’, 5 MOD 3, -5 MOD 3, 5 MOD (-3), -5 MOD (-3));
 00032    7  2  WRITELN(’  VAR ’, P5 MOD P3, M5 MOD P3, P5 MOD M3, M5 MOD M3);
 00063    8  0  END.
           *EXECUTE
           5 MOD 3 | -5 MOD 3 | 5 MOD -3 | -5 MOD -3
 CONST         2        -2        -1         1
  VAR          2         1        -1        -2

Пояснение:
Вычисление модуля работает честно (знак соответствует знаку делителя) при делении
переменных, а сам компилятор вычисляет константные выражения уникальным способом:
ни в одном известном википедии языке программирования нет операции остатка/модуля,
знак результата которой соответствовал бы знаку произведения:
https://en.wikipedia.org/wiki/Modulo_operation

Leo

Serguei Tarassov

unread,
Jun 22, 2017, 9:12:07 AM6/22/17
to БЭСМ-6
Да, так нельзя.
STRING в Паскале не был зарезервирован, это точно. Введен он был, если не ошибаюсь, в Turbo Pascal в 1980-х. Сейчас входит в ANSI стандарт (http://www.pascal-central.com/iso7185.html)

Макаров-Землянский Николай

unread,
Jun 28, 2017, 4:26:00 AM6/28/17
to be...@googlegroups.com
Да. Все правильно. Ни String, ни Integer нерезервируемые слова. Однако Делфи выделяет String, как служебное слово.
Но вопрос другой.
Предыстория - где-то в 80-82 году был написан Краб для СМ-4 (PDP-11) на Паскале. Текстов не осталось.
Паскаль был Виртовский, т.е. на нем было очень сложно программировать реальные системы.
Вопрос - как Вы думаете, как описывался файл в оперативной памяти (.... array of char)?
Я не помню, хотя сам многое писал.
 
 
 
 
22.06.2017, 16:12, "Serguei Tarassov" <se...@arbinada.com>:

Leo B.

unread,
Jul 11, 2017, 2:06:16 PM7/11/17
to БЭСМ-6


On Wednesday, June 28, 2017 at 1:26:00 AM UTC-7, nvmz wrote:
Да. Все правильно. Ни String, ни Integer нерезервируемые слова. Однако Делфи выделяет String, как служебное слово.
Но вопрос другой.
Предыстория - где-то в 80-82 году был написан Краб для СМ-4 (PDP-11) на Паскале. Текстов не осталось.
Паскаль был Виртовский, т.е. на нем было очень сложно программировать реальные системы.
Вопрос - как Вы думаете, как описывался файл в оперативной памяти (.... array of char)?
Я не помню, хотя сам многое писал.

Я не совсем понял вопрос. array of char - это всё-таки массив, а не файл. 

Александр Томилин

unread,
Aug 2, 2017, 6:34:46 AM8/2/17
to be...@googlegroups.com



Среда, 28 июня 2017, 11:26 +03:00 от Макаров-Землянский Николай <nv...@yandex.ru>:

Leo B.

unread,
Aug 6, 2017, 4:14:29 PM8/6/17
to БЭСМ-6
Кстати об опасностях ручной реализации синтаксического разбора:

 00001    1  0 PROGRAM MAIN(OUTPUT);
 00001    2  1 VAR I:INTEGER;
 00007    3  2 FUNCTION FOO:INTEGER; BEGIN FOO := 0 END;
 00017    4  2 PROCEDURE BAR(I : INTEGER); BEGIN END;
 ******41 HET ЗAПЯT ИЛИ CKOБKИ ИЛИ MAЛO ПAPAMETPOB
 00025    5  2 BEGIN BAR(FOO + 1);
        *****                0
 00040    6  0 END.

В то же время

 00001    1  0 PROGRAM MAIN(OUTPUT);
 00001    2  1 VAR I:INTEGER;
 00007    3  2 FUNCTION FOO:INTEGER; BEGIN FOO := 0 END;
 00017    4  2 PROCEDURE BAR(I : INTEGER); BEGIN END;
 00025    5  2 BEGIN BAR(1 + FOO);
 00042    6  0 END.

компилируется успешно. Интересно, это у Вирта ошибка или у Пирина.

Michael Yaroslavtsev

unread,
Aug 7, 2017, 12:56:53 AM8/7/17
to be...@googlegroups.com
А автокодом не пробовал?

--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+unsubscribe@googlegroups.com.

Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.



--
Thanks,
-- Michael

Leo Broukhis

unread,
Aug 7, 2017, 2:42:36 AM8/7/17
to БЭСМ-6
В Паскаль-автокоде работает, но ПАСКАЛЬ-АВТОКОД 9.(17.05.88), а PASCAL COMPILER 15.0 (15.02.82) - так что еще неизвестно, то ли П-М пытались "оптимизировать", то ли в П-А исправили ошибку.

Василий Долматов

unread,
Aug 7, 2017, 2:54:47 AM8/7/17
to be...@googlegroups.com

6 авг. 2017 г., в 23:14, Leo B. <leo...@gmail.com> написал(а):

У Пирина… Сэкономил на разборе… :) 



--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
signature.asc

Leo B.

unread,
Aug 7, 2017, 11:19:21 PM8/7/17
to БЭСМ-6

Я так погляжу, Пирин много где "сэкономил":

 00001    1  0 PROGRAM MAIN(OUTPUT);
 00007    2  2 BEGIN
 00031    3  0 IF TRUE OR FALSE THEN WRITELN(’GOOD’) ELSE WRITELN(’BAD’) END.
           *EXECUTE
GOOD

 00001    1  0 PROGRAM MAIN(OUTPUT);
 00007    2  2 BEGIN
 00032    3  0 IF (1=1) OR FALSE THEN WRITELN(’GOOD’) ELSE WRITELN(’BAD’) END.
           *EXECUTE
BAD

Вот так, видимо, и писали кросс-систему программирования для Эльбруса-Б, регулярно чертыхаясь.

Michael Yaroslavtsev

unread,
Aug 7, 2017, 11:57:20 PM8/7/17
to be...@googlegroups.com
Когда писали ту систему, Кеша занимался поддержкой компилятора и, ЕМНИП, довольно оперативно устранял все замечания.

--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+unsubscribe@googlegroups.com.

Чтобы настроить другие параметры, перейдите по ссылке https://groups.google.com/d/optout.



--
Thanks,
-- Michael

Leo B.

unread,
Aug 8, 2017, 4:28:13 AM8/8/17
to БЭСМ-6
On Monday, August 7, 2017 at 8:57:20 PM UTC-7, BOPOHOK wrote:

Когда писали ту систему, Кеша занимался поддержкой компилятора и, ЕМНИП, довольно оперативно устранял все замечания.

В какой момент решили, что компилятор требует отдельной поддержки? Жаль, что правки не отдали обратно Пирину для включения
в стандартную поставку.

Leo B.

unread,
Aug 12, 2017, 1:51:29 AM8/12/17
to БЭСМ-6
Очередная "ошибка-ловушка", она же тренировка умения мыслить логически.

Как известно, по умолчанию в Паскале числа с плавающей точкой сравниваются приближенным образом 
c точностью до миллионной доли от абсолютного значения, поэтому если А "равно" В, а В "равно" С, то 
А вовсе не обязано быть "равно" С.

 00001    1  1 PROGRAM MAIN(OUTPUT);VAR A,B,C:REAL;
 00007    2  2 BEGIN
 00010    3  2 A := 10000015.0;
 00011    4  2 B := 10000007.0;
 00012    5  2 C := 10000000.0;
 00013    6  2 WRITELN(A = B, B = C, A > C);
 00042    7  0 END.
           *EXECUTE
    TRUE    TRUE    TRUE

Если это нежелательно, то можно выключить с помощью псевдокомментария:

 00001    1  1 PROGRAM MAIN(OUTPUT);VAR A,B,C:REAL;
 00007    2  2 BEGIN (*=R-*)
 00010    3  2 A := 10000015.0;
 00011    4  2 B := 10000007.0;
 00012    5  2 C := 10000000.0;
 00013    6  2 WRITELN(A = B, B = C, A > C);
 00046    7  0 END.
           *EXECUTE
   FALSE   FALSE    TRUE

Пока ничего удивительного, просто напоминание. А теперь....

 00001    1  1 PROGRAM MAIN(OUTPUT);VAR A,B,C:тип;
 00007    2  2 BEGIN
 00010    3  2 A := значение_1;
 00011    4  2 B := значение_2;
 00012    5  2 C := значение_3;
 00013    6  2 WRITELN(A > B, B > C, C > A);
 00050    7  0 END.
           *EXECUTE
    TRUE    TRUE    TRUE

Обратите внимание, что три сравнения - не транзитивные, а циклические. 
Внимание, вопрос: как так может быть? Какого типа переменные и какие, например, их значения?

Это не ошибка в компиляторе, а неотъемлемое свойство выбранной реализации. 

Leo

Leo B.

unread,
Aug 18, 2017, 4:04:54 AM8/18/17
to БЭСМ-6
Раз вы молчите, то и я не буду молчать!

Ответ на загадку такой:

 00001    1  0  PROGRAM MAIN(OUTPUT);
 00001    2  1  VAR A,B,C:ALFA;
 00007    3  2  BEGIN
 00010    4  2  A := ’_000_000_000_000_000_000’;
 00011    5  2  B := ’_200_000_000_000_000_000’;
 00012    6  2  C := ’_177_377_377_377_377_377’;
 00013    7  2  WRITELN(A > B, B > C, C > A);
 00050    8  0  END.
           *EXECUTE
    TRUE    TRUE    TRUE

К каким эффектам это может приводить, предлагается рассмотреть на досуге.

Leo

Leo B.

unread,
Aug 26, 2017, 12:44:08 PM8/26/17
to БЭСМ-6
Полный ответ на загадку:

Для полноразрядного сравнения в Паскале использовалась команда СЛЦ.

А больше В, если А - В больше нуля. СЛЦ реализует арифметику в обратном коде для отрицательных чисел, т.е. вычитание
делается так:
СЧ В
НТЖ всеед
СЛЦ А
ПЕ больше (48р == 0)

Тонкость в том, что при сравнении числа с самим собой получается "минус ноль" (всеед) с единицей в 48р.
Работает как надо это всё, естественно, только для "неотрицательных" значений А и В с нулем в 48р.

Для собственно массивов символов это еще куда ни шло, но в Паскаль-Мониторе это использовалось для сортировки
в реализации ассоциативного контейнера, отображающего литеральные константы в их позицию в секции данных, отчего
некоторые константы иногда могли дублироваться.

Правильный способ упорядочивать произвольные полноразрядные значения, конечно, такой:

СЧ А
НТЖ В
ЗП (15)
СЧМР
СБР (15) [выясним, какой бит был в А в самой старшей из позиций, где А и В различаются]
РЖА 16 [установка "группы умножения" для тестирования 48р]
ПО больше [там единица]

Leo

Leo B.

unread,
Mar 4, 2025, 7:07:26 PMMar 4
to БЭСМ-6
Внезапно нашлась ошибка в Паскале, на которую, возможно, никто при жизни БЭСМ-6 не натыкался:
структурные типы с файлами в качестве полей не работают.

program main(output);
var f: record f: file of integer end;
begin
end.

Компилируется, но при попытке выполнить её падает с делением на ноль. А всё из-за автоматической инициализации дескрипторов файлов:
при объявлении переменных компилятор использует "глубокий" предикат для проверки, нужно ли занести переменную в список файлов для последующей инициализации,
а собственно процедура инициализации думает, что все переменные в списке - файлового типа, из-за чего в процедура инициализации дескриптора вызывается с мусором в качестве аргументов.

Во всех прочих паскалях перед использованием файловых переменных нужно делать assign, где файловая переменная указывается явно.

Leo

Василий Долматов

unread,
Mar 5, 2025, 10:09:10 AMMar 5
to 'Кирилл Кобелев' via БЭСМ-6
вроде это где-то было описано… я про паскаль-автокод… потому и не падало :)

5 марта 2025 г., в 03:07, Leo B. <leo...@gmail.com> написал(а):

--
Данное сообщение отправлено Вам, как участнику группы "БЭСМ-6":
http://groups.google.com/group/besm6/topics
---
Вы получили это сообщение, поскольку подписаны на группу "БЭСМ-6".
Чтобы отменить подписку на эту группу и больше не получать от нее сообщения, отправьте письмо на электронный адрес besm6+un...@googlegroups.com.
Чтобы посмотреть обсуждение, перейдите по ссылке https://groups.google.com/d/msgid/besm6/35fb1575-7c7f-43ba-ac81-95ef2a417a5en%40googlegroups.com.

Leo B.

unread,
Mar 5, 2025, 10:45:06 AMMar 5
to БЭСМ-6
On Wednesday, March 5, 2025 at 7:09:10 AM UTC-8 ReedCat wrote:
вроде это где-то было описано… я про паскаль-автокод… потому и не падало :)

В паскале-автокод всё просто: Никакая компонента сложного
типа не может иметь тип файла. 
В процедуре, парсящей тип

и эта процедура вызывается из вспомогательной процедуры doFields с аргументом restrict,  равным 1.

А в паскале-монитор явно пытались сделать по стандарту, но недоделали. 

Leo

Leo B.

unread,
Mar 11, 2025, 3:37:38 PMMar 11
to БЭСМ-6
Я нашел и исправил (в С++-варианте компилятора) обе ошибки:


 00001 1 0 PROGRAM MAIN(OUTPUT);
 00001 2 1 VAR I:INTEGER;
 00007 3 2 FUNCTION FOO:INTEGER;
 BEGIN FOO := 0 END;
 00017 4 2 PROCEDURE BAR(I : INTEGER); BEGIN END;
 ******41 HET ЗAПЯT ИЛИ CKOБKИ ИЛИ MAЛO ПAPAMETPOB
 00025 5 2 BEGIN BAR(FOO + 1);
     *****               0
 00040 6 0 END.

(если при разборе фактического параметра после функции нет открывающей скобки, то нужно проверять на запятую или скобку после нее, чтобы решить, выражение это или передача функции как аргумента).


 00001 1 0 PROGRAM MAIN(OUTPUT);
 00007 2 2 BEGIN
 00032 3 0 IF (1=1) OR FALSE THEN WRITELN(’GOOD’) ELSE WRITELN(’BAD’) END.
 *EXECUTE
 BAD

(при преобразовании де Моргана для компиляции OR нужно инвертировать и переменные, в которых хранятся найденные константные значения операндов)

Обе ошибки - легко находимые в С++-варианте компилятора и правки - тривиальные. Они могли бы быть сделаны и лет 6 назад, если бы я не поленился потратить полчаса на поиски. :)

Leo
Reply all
Reply to author
Forward
0 new messages