Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2008.05.11;
Скачать: [xml.tar.bz2];

Вниз

оцените пожалуйста код   Найти похожие ветки 

 
Игорь Шевченко ©   (2008-03-26 13:27) [40]

"ОО-языки упрощают абстракцию, возможно, даже слишком ее упрощают. Они поддерживают создание структур с большим количеством связующего кода и сложными уровнями.
Это может оказаться полезным в случае, если предметная область является
действительно сложной и требует множества абстракций, и вместе с тем такой подход может обернуться неприятностями, если программисты реализуют простые вещи сложными способами, просто потому что им известны эти способы и они умеют ими пользоваться.
Все ОО-языки несколько сколнны "втягивать" программистов в ловушку избыточной иерархии. Чрезмерное количество уровней разрушает прозрачность: крайне затрудняется их просмотр и анализ ментальной модели, которую по существу реализует код. Всецело нарушаются правила простоты, ясности и прозрачности, а в результате код наполняется скрытыми ошибками и создает постоянные проблемы при сопровождении.
Данная тенденция, вероятно, усугубляется тем, что множество курсов по
программированию преподают громоздкую иерархию как способ удовлетворения правила представления. С этой точки зрения множество классов приравнивается к внедрению знаний в данные. Проблема данного подхода заключается в том, что слишком часто "развитые данные" в связующих уровнях фактически не относятся у какому-либо естественному объекту в области действия программы - они предназначены только для связующего уровня.
Одной из причин того, что ОО-языки преуспели в большинстве характерных для них предметных областей (GUI-интерфейсы, моделирование, графические средства), возможно, является то, что в этих областях относительно трудно неправильно определить онтологию типов. Например, в GUI-интерфейсах и графических средствах присутствует довольно естественное соотвествие между манипулируемыми визуальными объектами и классами. Если выясняется, что создается большое количество классов, которые не имеют очевидного соответствия с тем, что
происходит на экране, то, соотвественно, легко заметить, что связующий уровень стал слишком большим."

(с) Эрик Реймонд, "Искусство программирования для Unix"


 
Mystic ©   (2008-03-26 13:29) [41]

> да ООП это вообще зло

Иногда, глядя на некоторые ООП архитектуры, я тоже думаю, что ООП это зло :) Возникает такое ООП-спагетти, что никакое goto с ним не может сравнится :)


 
@!!ex ©   (2008-03-26 13:44) [42]


> [37] Игорь Шевченко ©   (26.03.08 13:19)

В данном случае обертка упрощает работу с потоками.
ИМХО солянка из процедурно-ООП программирования - это гадость та еще...

> [40] Игорь Шевченко ©   (26.03.08 13:27)

Это скорее относится не к непосредственно использованию ООП, а к наследованию множества потомков, чатсь из которых не несут функционала, а лишь служат прослойкой.


 
Игорь Шевченко ©   (2008-03-26 13:46) [43]

@!!ex ©   (26.03.08 13:44) [42]

Я специально процитирую еще раз:


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


 
DVM ©   (2008-03-26 13:46) [44]


> DiamondShark ©   (26.03.08 12:29) [35]


> Странный вывод. Ви, таки, намекаете, что Борланд не написал
> ничего, кроме обёрток над простыми вещами?

Но и оберток над простыми вещами он написал множество. А так как по Вашему те, кто пишет обертки над простыми вещами = маразматики, то в борланде работают маразматики. Да и в MS тоже. А то, что маразматики написали и более сложные вещи это вообще к рассуждениям не относится, т.к. никто не утверждает, что маразматик не способен к созданию сложных вещей. Логично?


> Поток -- вещь примитивная (говорим, конечно, не о потрохах
> ядра, а об уровне прикладного ПО). Есть возражения?

Есть. Непонятно вообще как измерить примитивность данной вещи. О потрохах Вы предпочитаете не упоминать, об далеко не примитивном правильном применении потоков похоже тоже. Да, создать поток элементарно (и описание функции, создающей поток тоже примитивно). Но это ли главное?
Так что, похоже, о примитивности или нет потоков можно говорить только в свете их использования в программе. А это уже не так тривиально, как кажется на первый взгляд. Соответственно и написание грамотной обертки для этого дела тоже задача не совсем тривиальная.


> Да ладно! Сплошь и рядом слышатся уверения, что-де такой-
> то программный продукт "гибкий".

Если Вам не нравится слово гибкий, то давайте его заменим на удобный.
Использовать класс для контроля над потоком все же удобнее в Delphi, чем вызывать чистые функции WinAPI. Или не так?


> У меня, почему-то, SKLадывается ощущение, что Вы, таки,
> решили перейти на личности, не въехав толком в рассуждения.
>

Без обид. Мне так показалось.


 
@!!ex ©   (2008-03-26 14:10) [45]

> [43] Игорь Шевченко ©   (26.03.08 13:46)

Наличие своего интерфейса для потока НЕ УСЛОЖНЯЕТ, а упрощает.
Позволяет не заморачиваться с хэндлом потока, позволяет реализовать стандартные, общие вещи, типа Wait, Resume, Terminate, позволяет не заботиться о Callback процедуре, поскольку на уровне наследника TThread и неизвестно ни о какой процедуре.
Где усложнение?
Когда по коду разбросаны вызовы WinAPI кода, да еще в перемешку с *nix кодом, с кучей дефайнов - вот это - усложнение.

А вот если делать кучу промежуточных интерфейсов, просто потому что это можно, которые не используются - это и будет то, о чем писал Реймонд.


 
DVM ©   (2008-03-26 14:11) [46]


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

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


 
Mystic ©   (2008-03-26 14:19) [47]

> Позволяет не заморачиваться с хэндлом потока, позволяет
> реализовать стандартные, общие вещи, типа Wait, Resume,
> Terminate, позволяет не заботиться о Callback процедуре,
>  поскольку на уровне наследника TThread и неизвестно ни
> о какой процедуре.


В данном конкретном случае ты сам определил, что тебе нужно. В то же время твоя библиотека менее мощная, чем использование напрямую API. Сообще, я бы Handle потока (кстати, использовал бы тип THandle) сделал readonly public хотя бы для того, чтобы можно было его использовать в функции WaitForMultiplyObjects. Вообще, скрывать доступ к самому низкому уровню не очень хорошая идея. Лучше оставить возможность для конечного пользователя поковыряться в ухе отверкой, если этого будут требовать обстоятельства.


 
DiamondShark ©   (2008-03-26 14:19) [48]


> @!!ex ©   (26.03.08 12:53) [36]
> Интерфейс нужен хотя бы для того, чтобы избавиться от процедурного
> программирования.

А что оно мне такого плохого сделало, что надо от него избавляться?
Да и не избавиться от него ООПом, там призрак ПП тебя постоянно преследовать будет ;)
Избавляться надо не от процедурного программирования, а от низкоуровневых сущностей, а здесь ООП даёт только иллюзию избавления, постоянно подкладывая грабли сокрытой сложности и дырявых абстракций. Избавление нам дадуд неимперативные языки.


> ООП нагляднее однако. Поток легче контролировать.

Ой-вэй.
Берём первую попавшуюся "наглядность" -- TThread.Terminate. Ух ты! Как его легко контролировать! А вот дулечки. Успешность контролирования потока с помощью "наглядного" Terminate оказывается густо замешаной на особенностях реализации Execute: проверяется там Terminated, али на него известную крепёжную деталь забили... "Опаньки! Менты!" Здравствуй, дырявая абстракция.


> Нигде не надо хранить идентефикатор потока и т.д.

Детсад. См. далее.


> Mystic ©   (26.03.08 13:20) [38]
> Цели обверток:
>  (1) Придать программе единообразную структуру. Если у нас
> используются только объекты, то обращения к нативному API
> немного режут глаз.
>  (2) Завязка на кроссплатформенность. Если остальной код
> никак не завязан на особенности OS, то потратил вечер на
> написание обверток, то в будущем для портирования под другую
> OS мне понадобится тоже один вечер :)
>  (3) Type mapping. Постоянные приведения от string к PChar
> захламляют код. Точно так же и возвращаемые значения

Это резонно, если удалось избежать проблем.


>  (4) В обвертках также реализовываются наиболее часто встречающиеся
> сценарии использования объектов.

Примечание: по мнению разработчиков обёртки ;)
Я вот ни разу не пользовался ни Synchronize, ни шаблоном while not Terminated do.
У меня были другие сценарии.


> Например, ты сравнивал
> TThread и BeginThread. Хорошо, отвечу на вопрос, какие преимущества
> дает стандартный TThread:
>    (a) Контекст потока. Внутри потомка класса TThread мы
> можем объявить кучу полей, которые будут в дальнейшем легко
> доступны во всех вызовах методов TThread. В случае BeginThread
> контекст прийдется создавать самому: определять структуру,
>  объявлять переменную ctx типа указанной структуры, при
> всех вызовах передавать эту переменную, любое обращение
> к переменной контекста предварять ctx. и т. п.

Сомнительное преимущество. Какая разница, напишу я класс контекста с нуля, или забабахаю поля контекста в наследника TThread?


>    (b) Метод Synchronize

Чтоб он сдох.
Предъявляет требования к окружению и вносит нафиг не нужные зависимости. Кроме того, документация про него врёт:
"Synchronize causes the call specified by Method to be executed using the main VCL thread"
А на самом деле (в реализации Дельфи 5), Method исполняется не в main VCL thread, а в потоке, вызвавшем коструктор данного экземпляра TThread, да и то при условии, что в нём есть message loop.
А в Дельфи 7 (насколько я помню) Synchronize вообще представляет собой жуткий ахтунг, завязаный на поддерку от Forms. Бр-рр...


>    (c) Стандартный механизм для прерывания вычислений потока.

Который
а) фиговый
б) накладывает ограничения на Execute
в) в силу б) непригоден для оперирования абстрактными TThread, т.к. требует эзотерического знания о деталях реализации.


> Eraser ©   (26.03.08 13:22) [39]
>
> да ООП это вообще зло, а C# - недоязык )

Не перевирай классиков ;) Это C++ -- недоязык.
А про ООП, применённое без фанатизма, ничего плохого сказать не могу.


 
mephasm   (2008-03-26 14:32) [49]

DiamondShark ©   (26.03.08 14:19) [48]

>Избавление нам дадуд неимперативные языки.

Да, понимание этого приходит после знакомства с first class functions и closures. Но вот незадача. К примеру, нравится мне платформа Windows, так как лучше всего я ее знаю и распространена она весьма. Однако видели ли вы где-нибудь доступную реализацию Lisp или Scheme для windows с native threads?
А доступную реализацию C++ для windows найти не проблема. И посему приходится именно этот адский переязык использовать для реальных end-user приложений, и другого выхода не предвидится. Поэтому не в этой жизни они нам дадут.


 
@!!ex ©   (2008-03-26 14:34) [50]

> [48] DiamondShark ©   (26.03.08 14:19)

Ага. Давайте везде писать вот так:
 {$IFDEF WINDOWS}
 if stNONE<>StateTHRead then begin
WaitForSingleObject(THRead,INFINITE);
CloseHandle(THRead);    
 end;
 {$ENDIF}
 {$IFDEF UNIX}
 if stNONE<>StateTHRead then
   pthread_join(THRead,nil);
 {$ENDIF}


Вместо:
Thread1.Wait;
Thread2.Wait;

Замечательное упрощение.


 
Mystic ©   (2008-03-26 14:35) [51]

> Который
> а) фиговый
> б) накладывает ограничения на Execute
> в) в силу б) непригоден для оперирования абстрактными TThread,
>  т.к. требует эзотерического знания о деталях реализации.


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


> Сомнительное преимущество. Какая разница, напишу я класс
> контекста с нуля, или забабахаю поля контекста в наследника
> TThread?


Почти никакой, кроме дополнительного кода.


 
Mystic ©   (2008-03-26 14:37) [52]

> Однако видели ли вы где-нибудь доступную реализацию Lisp
> или Scheme для windows с native threads?


Функциональные языки распараллеливаются автоматически ;)


 
DiamondShark ©   (2008-03-26 14:39) [53]


> DVM ©   (26.03.08 13:46) [44]
>
> Логично?

Логично. Только это не опровергает исходный тезис. Вот если бы верно было утверждение: "В Борланде принципиально не может быть маразматиков", тогда да ;)
В принципе, упрёк за резкозть принимаю.


> Есть. Непонятно вообще как измерить примитивность данной
> вещи. О потрохах Вы предпочитаете не упоминать, об далеко
> не примитивном правильном применении потоков похоже тоже.
>  Да, создать поток элементарно (и описание функции, создающей
> поток тоже примитивно). Но это ли главное?

Именно это. Никаких других задач обсуждаемая обёртка не решает, значит и говорить можно только об элементарных задачах: создание, завершение/пауза, хранение контекста.

Примитивность измеряется очень просто: в количестве сущностей, в сложности структур/данных/типов,  в количестве операций.
Имеем: количество сущностей = 1, сложность структур = два атомарных значения, количество операций = пяток примерно.

Более примитивные вещи очень редко встречаются.


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

Если не сказать: неразрешимая.
Во всяком случае, решается она немножко иначе, чем пересказом API от третьего лица.


> Использовать класс для контроля над потоком все же удобнее
> в Delphi, чем вызывать чистые функции WinAPI. Или не так?

(*пожимает плечами*)
Кому как.
Тут говорили про чисто текстуальные красивости. Я нахожу ценность этого сомнительной.
А про проблемы я уже написал, повторяться не буду.


 
Eraser ©   (2008-03-26 14:42) [54]


> Mystic ©   (26.03.08 14:37) [52]


> Функциональные языки распараллеливаются автоматически ;)

думаю году к 2013-15 в Делфи появится языковая поддержка многопоточности.. правда как оно будет выглядеть не предполагаю..


 
DiamondShark ©   (2008-03-26 14:42) [55]


> Однако видели ли вы где-нибудь доступную реализацию Lisp
> или Scheme для windows с native threads?

А нафига козе баян?


 
mephasm   (2008-03-26 14:46) [56]

DiamondShark ©   (26.03.08 14:42) [55]

Попробуйте написать достаточно функциональный планировщик на Lisp.
Скажем, есть неизменяемый код самого планировщика, которому вы передаете некоторый алгоритм, по которому он передает сообщения или делает асинхронные вызовы. При этом, вы должны обеспечить определенное временное разрешение.
Как сделать это без многопоточности?


 
DiamondShark ©   (2008-03-26 14:53) [57]


> Mystic ©   (26.03.08 14:35) [51]
>
> Предложи лучше. Например, у меня есть сложное математическое
> вычисление, которое я хочу прервать в любой момент.

У меня пупок развяжется искать универсальное решение для абсолютно неопределённого множества сценариев ;)

Наверное, лучше никак не делать, и это будет наиболее гибко.

Впрочем, неплохой вариант ты сам же и предложил, и в .Net Thread.Abort() именно так и действует. Однако, для native-кода это не пройдёт, я не знаю, как вклиниться в произвольный момент времени в контекст другого потока.


> Почти никакой, кроме дополнительного кода.

По количеству строчек то же самое выходит.


 
Mystic ©   (2008-03-26 14:58) [58]

> думаю году к 2013-15 в Делфи появится языковая поддержка
> многопоточности.. правда как оно будет выглядеть не предполагаю.


Например как в Ada :)

Но я не о том. Дело в том, что в силу особенностей функциональные языки распараллеливаются без всякой языковой поддержки. В любом месте, где вызывается функция двух аргументов, один аргумент может считать один поток, второй---другой. Это делается автоматом. Т. е. если у нас есть некий алгоритм, написанный на ФЯ, то он будет исполнятся в стольки потоках, в скольки ты скажешь при настройке.

> mephasm   (26.03.08 14:46) [56]

У каждого языка своя ниша. Не уверен на 100% относительно Lisp, но для языка Haskell планировщики не имеют никакого смысла, язык и так распараллеливается без всяких усилий со стороны разработчик. Любые два аргумента функции могут вычисляться асинхронно.


 
DiamondShark ©   (2008-03-26 15:02) [59]


> mephasm   (26.03.08 14:46) [56]

А я не буду его на Лиспе писать, я его на Эрланге буду писать. ;)

А серьёзно -- озадачил. Пойду обрадую знакомых функциональщиков.


 
Mystic ©   (2008-03-26 15:04) [60]

> По количеству строчек то же самое выходит.

За исключением того, что эти строки тебе придется копировать из проекта в проект.

> Однако, для native-кода это не пройдёт, я не знаю, как вклиниться
> в произвольный момент времени в контекст другого потока.


Я хотел это исследовать... Но времени не было. Поэтому пока приходится постоянно вставлять строки

procedure TThread.CheckTerminated();
begin
 if Terminated then raise EArbotThread;
end;


 
@!!ex ©   (2008-03-26 15:16) [61]

> [48] DiamondShark ©   (26.03.08 14:19)
>
> > @!!ex ©   (26.03.08 12:53) [36]
> > Интерфейс нужен хотя бы для того, чтобы избавиться от
> процедурного
> > программирования.
>
> А что оно мне такого плохого сделало, что надо от него избавляться?
>
> Да и не избавиться от него ООПом, там призрак ПП тебя постоянно
> преследовать будет ;)
> Избавляться надо не от процедурного программирования, а
> от низкоуровневых сущностей, а здесь ООП даёт только иллюзию
> избавления, постоянно подкладывая грабли сокрытой сложности
> и дырявых абстракций. Избавление нам дадуд неимперативные
> языки.
>
>
> > ООП нагляднее однако. Поток легче контролировать.
>
> Ой-вэй.
> Берём первую попавшуюся "наглядность" -- TThread.Terminate.
> Ух ты! Как его легко контролировать! А вот дулечки. Успешность
> контролирования потока с помощью "наглядного" Terminate
> оказывается густо замешаной на особенностях реализации Execute:
> проверяется там Terminated, али на него известную крепёжную
> деталь забили... "Опаньки! Менты!" Здравствуй, дырявая абстракция.

Это скорее моя недоработка, чем проблема создания интерфейса.
Делаешь ExecuteWithTerminate:
while not FIsTerminated do
 Execute;

Execute - уже перекрывается наследниками.


 
Eraser ©   (2008-03-26 15:22) [62]


> Mystic ©   (26.03.08 15:04) [60]


> Я хотел это исследовать...

на сколько я знаю - только методом жесткого хака, т.е. непосредственно перезаписав код процесса и поменяв eip в контексте нужного потока. у MS-REM"а в его примерах внедрения в другие процессы без использования CreateRemoteThread есть реализация..


 
Mystic ©   (2008-03-26 15:31) [63]

> Eraser ©   (26.03.08 15:22) [62]

Поток может ждать результата WaitForSingleObject... Ну и смотреть надо что есть среди Zw функций такого... Или драйвер надо писать... Короче надо смотреть...


 
Anatoly Podgoretsky ©   (2008-03-26 15:39) [64]

> DiamondShark  (26.03.2008 14:39:53)  [53]

У Борланда встречаются, например вспомни обертку под названием IncDay
Если в АДА это естественно, поскольку там описываются операции над типом, например обязательно есть
+, Add и это естественно и обращаться можно так Day + 1, IncDay(Day, 1), "+"(Day,1) и не сможешь присвоить если это определено для TDate переменной типа TDateTime, то здесь это искуственно, просто пошли навстречу ламерам в Д7 и наплодили кучу искуственный функциек, наряду с действительно полезными.

Например наглядный пример

a, b: LinearMeasure; типа Integer
c: SqureMeasure; типа Integer
d: CubicalMeasure; типа Integer

C := A * B; не допустимо


 
Anatoly Podgoretsky ©   (2008-03-26 15:42) [65]

> Mystic  (26.03.2008 14:58:58)  [58]

> Например как в Ada :)

Хороший язык для создания особо надежных предложений.

Не знаю как сейчас, но в начале 90 требовалось не только сертифицировать каждую версию компилятора, но к тому же делать это для разных аппаратных платформ. Иначе это не считалось компилятором АДА.

Кстати а он жив сейчас?


 
Mystic ©   (2008-03-26 16:21) [66]

> Кстати а он жив сейчас?

Да, жив. Последний стандарт языка 2005.
http://www.adacore.com/home/


 
DiamondShark ©   (2008-03-26 17:09) [67]


> Eraser ©   (26.03.08 15:22) [62]
> на сколько я знаю - только методом жесткого хака, т.е. непосредственно
> перезаписав код процесса и поменяв eip в контексте нужного
> потока

Ну, не такого уж жёсткого, даже код перезаписывать не надо:


type
 EThreadAbort = class(Exception);

function ThreadFunc(Param: Pointer): Integer;
begin
 try
   while true do Sleep(1);
 except
   on EThreadAbort do
     Result := 1234;
   on Exception do
     Result := 555;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
label
 ExTh;
var
 hThread: THandle;
 ThreadId: DWORD;
 context: _CONTEXT;
 ExitCode: DWORD;
 Address: Cardinal;
begin
 hThread := BeginThread(nil, 0, ThreadFunc, nil, 0, ThreadId);
 ShowMessage("Thread started");
 SuspendThread(hThread);
 context.ContextFlags := CONTEXT_CONTROL;
 GetThreadContext(hThread, context);
 asm
   mov Address, offset ExTh
 end;
 context.Eip := Address;
 SetThreadContext(hThread, context);
 ResumeThread(hThread);
 WaitForSingleObject(hThread, INFINITE);
 GetExitCodeThread(hThread, ExitCode);
 ShowMessageFmt("%d", [ExitCode]);
 CloseHandle(hThread);
 Exit;
ExTh:
 raise EThreadAbort.Create("");
end;


 
DiamondShark ©   (2008-03-26 17:29) [68]


> DiamondShark ©   (26.03.08 17:09) [67]

Но так делать всё равно нельзя.

Обычно, установка SEH выглядит примерно так:

xor eax,eax
push ebp
push $00443165
push dword ptr fs:[eax]
mov fs:[eax],esp

и если SuspendThread и изменение EIP случается где-то в середине этого, то приходит белый северный зверёк.


 
Eraser ©   (2008-03-26 17:37) [69]


> DiamondShark ©   (26.03.08 17:09) [67]

а, ну да, если в своем процессе эти заниматься, то не нужно )))

если в чужом, то нужно где-то ж размещать код, которому передавать управление, но это конечно не наш случай..



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2008.05.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.64 MB
Время: 0.008 c
3-1196988932
Killka
2007-12-07 03:55
2008.05.11
Экспорт данных в ExcЁль


15-1206607633
Ламо777
2008-03-27 11:47
2008.05.11
Apache&amp;SSL - перенаправление


15-1206783905
builder
2008-03-29 12:45
2008.05.11
Посоветуйте программку для прослушивания радио через интернет


2-1208170710
djaUser
2008-04-14 14:58
2008.05.11
Загрузка файлов с инет.


4-1188108766
Bora.ru
2007-08-26 10:12
2008.05.11
Убрать значок процесса из TaskBar





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский