Re[25]: Checked exceptions... зло или добро?
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 21.07.05 18:03
Оценка:
Здравствуйте, IT, Вы писали:

V>>Далее, при ошибке сохранения данных формы на сервер, было бы неплохо не потерять введенные пользователем данные. Ошибка могла возникнуть не только по причине отсутствия связи. Все гораздо интересней, если связь есть, но сервак выплевывает ошибку. Наверно, Пашин совет касается подобных вещей.


IT>Согласись, что сохранение данных формы — это не дело сервера.

Это ещё почему?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[20]: Checked exceptions... зло или добро?
От: IT Россия linq2db.com
Дата: 21.07.05 18:12
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Это иногда невозможно, если у нас гетерогенная среда (CORBA, например). Мы вынуждены ловить ексепшены, чтобы "завернуть" их в транспортный вид.


И протолкнуть его дальше. Тоже самое в случае ремоутинга. Такие среды это делают неявно, без нашего вмешательства. Другой пример — логирование исключений. В случае ремоутинга это тоже можно сделать прозрачно для прикладного программиста, иначе придётся ловить, логировать и прокидывать дальше. Надеюсь, AOP в скором времени сможет закрыть эту дырку.

IT>>Другими словами — контекст вызова умирает вместе с вызовом и никаким существенным образом на работоспособность сервера это влиять не должно ни при удачном, ни при не очень исходе.


V>Тоже не все так просто. В нашей системе редактируется некая сущность. Затем вызывается процедура валидации данных. Процедура сложная и зависит от многих вещей — короче, делаем валиадцию на серваке. Результат валидации — не просто yes/No — а тоже вполне осмысленный набор записей. И вот что характерно — мы хотим валидировать подобным образом текущие редактируемые данные ДО сохранения в базе. И как тут поможет stateless?


State всегда есть, в твоём примере он находится на клиенте. Сервер же остаётся stateless.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[26]: Checked exceptions... зло или добро?
От: IT Россия linq2db.com
Дата: 21.07.05 18:22
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

V>>>Далее, при ошибке сохранения данных формы на сервер, было бы неплохо не потерять введенные пользователем данные. Ошибка могла возникнуть не только по причине отсутствия связи. Все гораздо интересней, если связь есть, но сервак выплевывает ошибку. Наверно, Пашин совет касается подобных вещей.


IT>>Согласись, что сохранение данных формы — это не дело сервера.

ГВ>Это ещё почему?

Смотрим контекст. Я не о методе сервера SaveWhatever, а о хранении введённых данных пока этот вызов не завершиться успешно.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[23]: Checked exceptions... зло или добро?
От: alexeiz  
Дата: 21.07.05 19:16
Оценка: +4
dshe wrote:

> Вариант 1.

>
> interface PersonFinder {
> /**
> * returns null if person has not been found
> */
> Person findPersonByName(String name);
> }
>

> В этом варианте PersonFinder возвращает null если человек не был
> найден. При этом вызывающий код обязан проверить полученный результат
> на null. Причем, он обязан исходя из неявного соглашения описанного в
> комментариях, которые не все и не всегда читают и пишут. Компилятор
> не выдаст ни error'а, ни warning'а если результат не будет проверен
> на null. Это основной недостаток данного подхода.

Т.е. основной недостаток — это то, что программист невнимателен. Он даже не
удосужился прочитать документацию по тем API, которые использует.

Я достаточно времени провел программируя на C#. И в нём не допустить, что
значения могут быть null, нельзя. Просто сразу привыкаешь к этому факту.
После чего всё происходит на автомате: "ага, метод возвращает значение, а
если null?". Никаких проблем. Это как, например, привыкнуть к тому, что в
C++ нужно вызывать ++iter для итератора. Сильно подозреваю, что и в Java
такая привычка вырабатывается сразу.

> Вариант 3.

>
> interface PersonFinder {
> /**
> * throws checked PatientNotFoundException if person has not been
> found,
> * never returns null
> */
> Person findPersonByName(String name) throws PatientNotFoundException;
> }
>

>
> Этот вариант также является усовершенствованием второго, однако в
> другом направлении. PatientNotFoundException становится checked. Т.е.
> вызывающий код обязан его обработать (это гарантируется
> компилятором). Он может выдать user friendly диалог, а может просто
> перебросить его как unchecked, для того, чтобы оно обработалось как
> ошибка на самом внешнем уровне обработки ошибок.

Начну из далека. Представь, что ты работаешь в support'е. И вот нужно тебе
найти баг в незнакомом тебе приложении. Запускаешь ты его под отладчиком.
Exception tracing включены. Вот приложение стартует, и ты наблюдаешь
сообщения отладчика о сотнях и сотнях выбрасываемых исключениях... Да,
ощущение возникает не из приятных. Программа вроде работает, но откуда весь
этот мусор? А может она просто делает вид, что работает? Задаёшься
вопросом: какого хрена думали её создатели.

Возвращаясь к нашим баранам, это в точности то, к чему приводит вариант #3.

Теперь более конкретно. Какой код нужно написать при использовании
интерфейса в варианте 1 и 3:
// 1:
for each (String name in names) {
    Person p = personFinder.findPersonByName(name);
    if (p != null) {
        // ...
        // do something (2 screens of code)
        // ...
    }
}

// 3:
for each (String name in names) {
    try {
        Person p = personFinder.findPersonByName(name);
        // ...
        // do something (2 screens of code)
        // ...
    } catch (PatientNotFoundException) {
    }
}

Допустим, человек, не знакомый с этим кодом, читает его. Что он думает в
случае 1: "ага, берём имена, ищем по ним людей, if (p != null) — если нашли,
делаем..." В случае 3: "ага, берём имена, ищем по ним людей, с человеком p
делаем — стоп! а если p==null?". Листаем 2 экрана вперёд, получаем ответ на
этот вопрос.

Т.е. действий нужно совершать гораздо больше, так как интерфейс в варианте
3 — не интуитивный.

Кстати, узнаёшь: catch (PatientNotFoundException) {} — знаменитый Java
anti-pattern. Поймал исключение и пропустил его. Тут как тут. И никуда от
него не деться.
Posted via RSDN NNTP Server 1.9
Re[24]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 21.07.05 20:26
Оценка: 7 (2) +4
alexeiz,

>
> // 3:
> for each (String name in names) {
>     try {
>         Person p = personFinder.findPersonByName(name);
>         // ...
>         // do something (2 screens of code)
>         // ...
>     } catch (PatientNotFoundException) {
>     }
> }
>

> <...>
> Кстати, узнаёшь: catch (PatientNotFoundException) {} — знаменитый Java
> anti-pattern. Поймал исключение и пропустил его. Тут как тут. И никуда от
> него не деться.

Еще интереснее, когда у нас будет не только PatientNotFoundException, но код станет сложнее, и будет запрашивать много разных вещей, которых может не существовать. При этом очень быстро может надоесть выписывать все эти различные типы исключений, и в итоге запросто напишут catch(Exception), игнорируя не только исключения, сигнализирующие о не найденном объекте, но и исключения, сигнализирующие об ошибках. Например (названия условные):
for each (Record r in records) {
     try {
         City city = cityFinder.findCityByName(r.cityName);
         // ...
         // do something
         // ...

         Hospital hospital = city.findHospitalByName(r.hospitalName);
         // ...
         // do something
         // ...

         Person patient = hospital.findPersonByName(r.patientName);
         // ...
         // do something
         // ...
     } catch (Exception) {
     }
}
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[24]: Checked exceptions... зло или добро?
От: dshe  
Дата: 22.07.05 07:33
Оценка: 6 (1) +1 -1
Здравствуйте, alexeiz, Вы писали:

A>dshe wrote:


A>Т.е. основной недостаток — это то, что программист невнимателен. Он даже не

A>удосужился прочитать документацию по тем API, которые использует. Я достаточно
A>времени провел программируя на C#.

Тогда, должно быть, тебе крупно повезло поскольку в реальной жизни (судя, правда, по моему опыту) чаще происходит что-то из следующего:
1. программист, который использует API, не читает документацию по API потому, что ее просто нет. Наиболее частое обоснование для ненаписания документации -- это отсутствие на это времени.
2. программист, который использует API, читает документацию, но эта документация устарела. Наиболее частое обоснование для поддержания документации up-to-date -- это отсутствие на это времени.
3. программист, который использует API, читает документацию, но эта документация не содержит информации, которая ему нужна. Вот пример такой документации:
/**
 * This method gets bitrate.
 * This method is part of the SuperPuper System 
 * Copyright (c) SuperPuper, Inc.  2000, 2001, 2002, 2003, 2004, 2005, 2006
 *    All Rights Reserved
 * This method contains unpublished, confidential and proprietary 
 * information of SuperPuper, Inc. No disclosure or use of 
 * any portion of the contents of these materials may be made without the 
 * express written consent of SuperPuper, Inc.
 * 
 * Author: Vasia Pupkin
 * Description: 
 */
public void getBitrate();

Обычно такая документация появляется когда начальство (осознавая важность документирования) навязывает писать хоть какую-то документацию.
4. программист, который использует API, не читает документацию, поскольку не надеется увидеть там что-нибудь для себя полезное (в силу приведенных выше пунктов).

Поэтому, на мой взгляд, полагаться только на документацию как средства передачи информации о том, как использовать API, -- просто легкомысленно. Не менее важно делать API юзабельным и интуитивным, т.е. каким, чтобы было сразу понятно как его использовать и чтобы неправильно использовать было просто невозможно. А для этого можно использовать различные методы, такие как соглашение об именовании, строгий контроль типов, checked исключения (?). Вот те три варианта, которые я привел, и были попыткой найти наиболее интутивный интерфейс.

A>Начну из далека. Представь, что ты работаешь в support'е. И вот нужно тебе

A>найти баг в незнакомом тебе приложении. Запускаешь ты его под отладчиком.
A>Exception tracing включены. Вот приложение стартует, и ты наблюдаешь
A>сообщения отладчика о сотнях и сотнях выбрасываемых исключениях... Да,
A>ощущение возникает не из приятных. Программа вроде работает, но откуда весь
A>этот мусор? А может она просто делает вид, что работает? Задаёшься
A>вопросом: какого хрена думали её создатели.

Должно быть язык и платформа действительно сильно влияют на мировоззрение. Отлаживая программу на Java, у меня бы особого желания ставить breakpoint на все исключения не было бы. Слава богу, поставить breakpoint на java.lang.RuntimeException (программные ошибки, большинство unchecked исключений) не намного сложнее, чем на java.lang.Throwable (все исключения). Впрочем, когда я буду писать на C# я воспользуюсь твоим и IT советом включать Exception tracing.

A>Возвращаясь к нашим баранам, это в точности то, к чему приводит вариант #3.

A>Допустим, человек, не знакомый с этим кодом, читает его. Что он думает в
A>случае 1: "ага, берём имена, ищем по ним людей, if (p != null) — если нашли,
A>делаем..." В случае 3: "ага, берём имена, ищем по ним людей, с человеком p
A>делаем — стоп! а если p==null?". Листаем 2 экрана вперёд, получаем ответ на
A>этот вопрос.

Человек, незнакомый с этим кодом, читая его, сразу видит наиболее типичный сценарий использования (не отвлекаясь на его ответвления-вариации), а пролистав 2 экрана вперед видит, что происходит в редких, исключительных случаях.

A>Кстати, узнаёшь: catch (PatientNotFoundException) {} — знаменитый Java

A>anti-pattern. Поймал исключение и пропустил его.

Да, есть такое дело. Еще более опасный антипаттерн это
1.
catch(Exception exc) {}

поскольку что ловятся и игнорируются также и RuntimeException (ошибки программирования)
и
2. throws Exception в декларации методов, поскольку это вынуждает писать catch(Exception exc).

Я ни в коем случае не агитирую за использования данных антипаттернов.
--
Дмитро
Re[25]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 22.07.05 07:51
Оценка: +1
dshe,

d> поскольку что ловятся и игнорируются также и RuntimeException (ошибки

d> программирования) и

Интересно, насколько разные вещи, вплоть до противоположных, называются одинаково в разных языках...
В C++ исключения, обозначающие ошибки программирования, берут свое начало от std::logic_error (выход
за границы, неправильные аргументы и т.п.), а исключения, унаследованные от std::runtime_error,
означают как раз таки вполне обычные исключения (переполнение в вычислениях и т.п.)...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[21]: Checked exceptions... зло или добро?
От: vdimas Россия  
Дата: 22.07.05 11:15
Оценка:
V>>Тоже не все так просто. В нашей системе редактируется некая сущность. Затем вызывается процедура валидации данных. Процедура сложная и зависит от многих вещей — короче, делаем валиадцию на серваке. Результат валидации — не просто yes/No — а тоже вполне осмысленный набор записей. И вот что характерно — мы хотим валидировать подобным образом текущие редактируемые данные ДО сохранения в базе. И как тут поможет stateless?

IT>State всегда есть, в твоём примере он находится на клиенте. Сервер же остаётся stateless.


Я бы поспрашивал подробнее именно этот момент, ибо ситуация у нас более чем частовстречающаяся. Итак, юзверь редактирует некие данные (например, набивает в список некое множество из объектов другого типа, т.е. ассоциирует объекты). Я говорил, у нас есть некий EntityWrapper ("entity view" в будущем), который предназначен для удаленного взаимодействия с сущностью. Именно он хранит у нас текущие измененные значения в описываемом случае. Я передаю данные из клиентского адаптера на этот серверный, но команду "Save" не вызываю (может и не вызову, если валидация не пройдет). Таим образом, на стороне сервера в момент валидации есть вся информация о том, в каком состоянии будет объект после операции Save. Разве это стателесс?
Re[19]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.05 13:04
Оценка:
Здравствуйте, vdimas, Вы писали:

VD>>Вот за "прикладные исключения" нужно морду бить. Причем сильно и жестоко.


V>А куда же без них в серверном приложении? У тебя есть сервер, кто-то вызывает методы, параметры не так передал или просто невовремя вызвал метод, или операцию нельзя совершить... — серверу только и остается, что плюнуть ексепшеном в вызывателя.


Это норальное использование исключений. Здесь же я говорил об использовании исключений в целях управления потоком выполнения программы.
... << RSDN@Home 1.2.0 alpha rev. 578>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[17]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.05 13:04
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>А RSDN.NNTP не ты писал, случайно?


Не я. А что?
... << RSDN@Home 1.2.0 alpha rev. 578>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[28]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.05 13:04
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Интересный вариант... Только, боюсь, в моем случае не прокатит: у меня три машины (десктопы в офисе и дома, плюс лаптоп). Лаптоп ношу не всегда. Но мысль очень интересная... В общем, как соберусь с духом, опять в Янус полезу, наверное... "Ежики кололись, плакали, но лезли на кактус"


Купи себе USB2-винт. Положи на него БД от януса и пользуйся с любой машины.
... << RSDN@Home 1.2.0 alpha rev. 578>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[22]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.05 13:04
Оценка:
Здравствуйте, Andrei N.Sobchuck, Вы писали:

VD>> Янус как раз при проблемах со связью умудряется работать даже когда к серверу нельзя пробиться из броузера или через почту.


ANS>И умудряется не работать при отсутсвии оных проблем. Как это было в понедельник.


Незнаю. У меня работает. Хотя я пользуюсь альфами. У тебя же вроде вообще стабильная сборка.
... << RSDN@Home 1.2.0 alpha rev. 578>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[22]: Checked exceptions... зло или добро?
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.05 13:04
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Дык, вот эта Auto Recovery Record и есть один из вариантов того, что подразумевалось...


Ты видмо плохо знаком с вордом. Auto Recovery в нем — это попытка при вылете востановить данные и скинуть их во временный файл, чтобы при повторном вызове дать возможность пользователю их сохранить. Вот только в ворде очень часто память портится и сохраненные таким образом документы в дальнейшем начинают вылетать постоянно.
... << RSDN@Home 1.2.0 alpha rev. 578>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[29]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 22.07.05 13:09
Оценка:
VladD2,

V> Купи себе USB2-винт. Положи на него БД от януса и пользуйся с любой

V> машины.

Идея хорошая... Еще лучше, что подходит не только для Януса, но и для Оперы... Нужно обмозговать
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[23]: Checked exceptions... зло или добро?
От: Павел Кузнецов  
Дата: 22.07.05 13:14
Оценка:
VladD2,

ПК>> Дык, вот эта Auto Recovery Record и есть один из вариантов того, что

ПК>> подразумевалось...

V> Ты видмо плохо знаком с вордом. Auto Recovery в нем — это попытка при

V> вылете востановить данные и скинуть их во временный файл, чтобы при
V> повторном вызове дать возможность пользователю их сохранить. Вот только
V> в ворде очень часто память портится и сохраненные таким образом
V> документы в дальнейшем начинают вылетать постоянно.

Ну, мы с тобой точно не знаем, почему именно документ получается "плохим". Я бы, скорее предположил,
что дело в порче инвариантов. В случае же продолжения работы было бы не лучше: пользователь успел бы
много наредактировать, прежде чем стало бы ясно, что документ уже ни к черту. В случае "вылета", если
Auto Recovery приводит к проблемам (чего я на своих документах не замечал, но и Word у меня сам по себе
не вылетает, за исключением отключения питания машины без shut down), то можно воспользоваться последней
autosaved версией.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[20]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 22.07.05 13:34
Оценка:
VladD2 wrote:

> VD>>Вот за "прикладные исключения" нужно морду бить. Причем сильно и

> жестоко.
> V>А куда же без них в серверном приложении? У тебя есть сервер, кто-то
> вызывает методы, параметры не так передал или просто невовремя вызвал
> метод, или операцию нельзя совершить... — серверу только и остается,
> что плюнуть ексепшеном в вызывателя.
> Это норальное использование исключений. Здесь же я говорил об
> использовании исключений в целях управления потоком выполнения программы.

Является ли выброс исключения для индикации ошибки — управлением потоком?

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Re[21]: Checked exceptions... зло или добро?
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.07.05 14:01
Оценка: 10 (1) :)
Здравствуйте, IT, Вы писали:

V>>Тоже не все так просто. В нашей системе редактируется некая сущность. Затем вызывается процедура валидации данных. Процедура сложная и зависит от многих вещей — короче, делаем валиадцию на серваке. Результат валидации — не просто yes/No — а тоже вполне осмысленный набор записей. И вот что характерно — мы хотим валидировать подобным образом текущие редактируемые данные ДО сохранения в базе. И как тут поможет stateless?


IT>State всегда есть, в твоём примере он находится на клиенте. Сервер же остаётся stateless.

Хм. Что-то мне это напоминает
Автор: Tom
Дата: 04.12.03
. Дежа-вю, что-ли?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[21]: Checked exceptions... зло или добро?
От: WolfHound  
Дата: 22.07.05 14:04
Оценка: 1 (1) +1 :)))
Здравствуйте, Cyberax, Вы писали:

C>Является ли выброс исключения для индикации ошибки — управлением потоком?

И думаю Влад имеет в виду чтото типа
class IsFibonacciNumberException : Exception
{
}
class IsNotFibonacciNumberException : Exception
{
}
static void TestNumber(int n)
{
    TestNumberImpl(n, 1, 1);
}
static void TestNumberImpl(int n, int x1, x2)
{
    if (n == x1)
        throw new IsFibonacciNumberException();
    if (n < x1)
        throw new IsNotFibonacciNumberException();
    int x3;
    try
    {
        checked
        {
            x3 = x1 + x2;
        }
    }
    catch
    {
        throw new IsNotFibonacciNumberException();
    }
    TestNumberImpl(n, x2, x3);
}
static void Foo()
{
    try
    {
        TestNumber(141234);
    }
    catch(IsFibonacciNumberException ex)
    {
        Console.WriteLine("IsFibonacciNumberException");
    }
    catch(IsNotFibonacciNumberException ex)
    {
        Console.WriteLine("IsNotFibonacciNumberException");
    }
}

... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[27]: Checked exceptions... зло или добро?
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 22.07.05 14:11
Оценка:
Здравствуйте, IT, Вы писали:

V>>>>Далее, при ошибке сохранения данных формы на сервер, было бы неплохо не потерять введенные пользователем данные. Ошибка могла возникнуть не только по причине отсутствия связи. Все гораздо интересней, если связь есть, но сервак выплевывает ошибку. Наверно, Пашин совет касается подобных вещей.

IT>>>Согласись, что сохранение данных формы — это не дело сервера.
ГВ>>Это ещё почему?

IT>Смотрим контекст. Я не о методе сервера SaveWhatever, а о хранении введённых данных пока этот вызов не завершиться успешно.


Я и говорю, что это спорный вопрос. Никто не мешает, и ИМХО, это полезно: хранить промежуточные, возможно невалидные данные в специальных таблицах/файлах и т.п., которые никак не упоминаются в "основных" таблицах до выполнения валидации. Короче говоря — хранить сеанс пользователя.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[18]: Checked exceptions... зло или добро?
От: Cyberax Марс  
Дата: 22.07.05 15:10
Оценка:
VladD2 wrote:

> C>А RSDN.NNTP не ты писал, случайно?

> Не я. А что?

Так и быть, лопату дарить не буду.

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 1.9
Sapienti sat!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.