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

Вниз

Оптимизация скорости вывода на екран с помощью Label   Найти похожие ветки 

 
GVas ©   (2009-01-04 14:53) [0]

Добрый день.
На форме вывожу информацию вот так

procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
begin
 For i:=1 to 100000 do
   Begin
     Label1.Caption:=IntToStr(i);
     Label1.Refresh;
   End;
end;

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


 
sniknik ©   (2009-01-04 15:08) [1]

> оптимальна ли с точки быстродействия такая конструкция
а подумать? ты там все цифры разглядеть успеваешь?

> 8 секунд
а вот такая

procedure TForm1.Button1Click(Sender: TObject);
var
i:Integer;
begin
For i:=1 to 100000 do
  Begin
    //Label1.Caption:=IntToStr(i);
    //Label1.Refresh;
  End;
 Label1.Caption:=IntToStr(100000);
end;

0 сек. при том же конечном результате.


 
GVas ©   (2009-01-04 16:03) [2]

ну мб я просто неправильно выразил мысль но существует ли в делфи способ вывода на экран отличный от Label, но работающий быстрее брал я 100000 просто для того чтобы приблизительно высчитать скорость вывода на экран и даже если взять Label1.Caption:=IntToStr(100000) то это получатся почти те же самые 200к тактов процесора (чуть меньше) а если программа каждую секунду обновляет пару сотен таких Label и перед этим обсчитывает какие-то головоломные масивы информации хотелось бы немного оптимизировать работу. Подскажите, или я занимаюсь ерундой и на нынешних скоростях процессора это будет не очень заметно?


 
sniknik ©   (2009-01-04 16:34) [3]

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


 
AndreyV ©   (2009-01-04 16:47) [4]

> [3] sniknik ©   (04.01.09 16:34)

Кстати, и 0.5 секунд для лейбл, а тем более для "пары сотен", - слишком часто, тут надо стрелки рисовать.


 
GVas ©   (2009-01-04 17:26) [5]

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


 
{RASkov} ©   (2009-01-04 17:30) [6]

> а такая же функция для вещественных чисел присутствует??

Да, FloatToStr()

> нельзя нажать на какую либо другую кнопку, как выйти из
> такого положения?

Application.Processmessage;
или доппотоки....


 
GVas ©   (2009-01-04 17:47) [7]

Вот решил проверить как работает математика в делфе взял вещественное число 1Е-17 прибавил его 100000 раз получается 9,99999988197267E-13 а должно быть 1е-12 почему такая разница получается????


 
GVas ©   (2009-01-04 17:53) [8]

Мдя, все извините за беспокойство оказалось что real48 мало знаков в числе поддерживает, значит ли это что если прибавлять к очень большому числу очень маленькое, будет погрешность??


 
AndreyV ©   (2009-01-04 18:00) [9]

> [8] GVas ©   (04.01.09 17:53)

Раз в неделю появляется этот вопрос
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374


 
GVas ©   (2009-01-04 19:39) [10]

Ну из статьи я ситуацию понял, но пути ее решения кроме того что лучше вместо реала использовать екстендед, ну это по правде говоря я и експерементально получил, а вот что делать если мне нужно больше чем 20 знаков после запятой??


 
Сергей М. ©   (2009-01-04 19:56) [11]


> что делать если мне нужно больше чем 20 знаков после запятой?


Ты что, Левша лесковский ?


 
sniknik ©   (2009-01-04 19:58) [12]

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


 
Anatoly Podgoretsky ©   (2009-01-04 21:01) [13]

> GVas  (04.01.2009 19:39:10)  [10]

Ситуация простая, никогда не использовать Real48 и читать что по этому поводу говорит справка,


 
Anatoly Podgoretsky ©   (2009-01-04 21:03) [14]

> GVas  (04.01.2009 19:39:10)  [10]

Что то не то, то хватало Real48, а теперь не хватает Extended?
И объясни почему тебе нужна такая большая точность или ты просто так, что вижу, то и пою.


 
GVas ©   (2009-01-04 21:29) [15]

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


 
GVas ©   (2009-01-04 21:45) [16]

to Anatoly Podgoretsky
первый раз я использовал реал48 для того чтоб создать переменную вещественного типа потом узнал каким способом ее можно преобразовать, после того как начал считать число мелкое получилось не то какое я хотел, начал разбираться почему не то, сменил тип на екстендед, когда нет превышения все нормально, а когда есть то снова погрешность получается вот так.


 
sniknik ©   (2009-01-04 22:00) [17]

> Application.Processmessage
это к параллельности процессов имеет слабое отношение... (если вообще хоть какое то)

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


 
GVas ©   (2009-01-04 22:26) [18]

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


 
sniknik ©   (2009-01-04 22:53) [19]

таймер. однозначно.


 
Anatoly Podgoretsky ©   (2009-01-04 23:45) [20]

> GVas  (04.01.2009 22:26:18)  [18]

Да тут сначала надо думать об смене индикации, обновление 200 меток раз в секунду, да пользователь свихнется. Цифровое представление не подходит, никто не в силах даже заметить в каких метках изменилась информация. Переходи на гистограммы.


 
GVas ©   (2009-01-05 00:05) [21]

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


 
GVas ©   (2009-01-05 00:07) [22]

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


 
Германн ©   (2009-01-05 00:22) [23]


> или для новых нужно открывать отдельную?

Если "новые" вопросы будут на темы не связанные никак с сабжем, то новую.


 
GVas ©   (2009-01-13 22:51) [24]

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


 
anonims   (2009-01-14 10:55) [25]

const pi=3.14;
       x2pi=2*pi;
       halfpi=pi/2;

var:=pi/2;
var:=halfpi;
в любом случае вычисление правой части берет на себя транслятор, т.е. в программном коде будет использовано уже вычисленное значение.
использвать вариант при котором читаемость программы будет выше

TiniFile Кead... Write...


 
GVas ©   (2009-01-14 22:41) [26]

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


 
han_malign ©   (2009-01-15 13:21) [27]


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


State: Структура данных описывающих Состояние модели.
Slide: Метод получения следующего Состояния
Show: Метод визуализации Состояниия

1.
TForm1.OnTimer(Sender: TObject);
var state: TState;
begin
   state:= Slide(FState, Now);
   FState:= state.
   Show(FState);
end;
- предпочтителен если Slide - явная функция от времени(то бишь "шаг" между состояними произвольный, например: прямолинейное равноускренное движение) и/или вычисление занимет мало времени...
ВНИМАНИЕ: Если в Slide вызывать ProcessMessages - может возникнуть рекурсия, если метод не уложится в интервал таймера
OnTimer{ Slide{ ProcessMessages{ GetMessage:WM_TIMER{ далее понятно } } } }
лечится флагом
if( FOnSlide = 0 )then begin
    inc(FOnSlide);
    ...
    dec(FOnSlide);
end;

2.
TThread1.Create(synchronous: boolean);
begin
   FSync:= CreateEvent(nil, not synchronous, true, nil);
   InitializeCriticalSection(FCrit);
   inherited Create(false);
end;
TThread1.Destroy;
begin
   Terminate;
   WakeUp;
   inherited;
end;
TThread1.Sleep;
begin
   ResetEvent(FSync);
end;
TThread1.WakeUp;
begin
   SetEvent(FSync);
end;
TThread1.Execute;
var nextFrame: integer;
begin
  while not Terminated of begin
      WaitForSingleObject(FSync, INFINITE);
      nextFrame:= FFrame + 1;
      if(nextFrame > High(FState))then nextFrame:= Low(FState);
      FState[nextFrame]:= Slide({in}FState[FFrame]);
      EnterCriticalSection(FCrit);
      FFrame:= nextFrame;
      LeaveCriticalSection(FCrit);
      Sleep(0);//take a chance for other threads
  end;
end;
TTread1.Snapshot: TState;
begin
    EnterCriticalSection(FCrit);
    Result:= FState[FFrame];
    LeaveCriticalSection(FCrit);
    WakeUp;
end;
..............
TForm1.OnTimer(Sender: TObject);
begin
   Show(FThread1.Snapshot);
end;


2.1.
TForm1.Show(state: TState);
begin
   if(FState.Ticker <> state.Ticker)then begin
     FState:= state;
     Invalidate;
   end;
end;
TForm1.OnPaint(Sender: TObject);
begin
    Draw(FState);
end;


 
tesseract ©   (2009-01-15 13:28) [28]


> Sleep(0);//take a chance for other threads


индусятина, при  waitforsingleobject  не нужен. Использовать желательно WaitForMultipleObject  где одно из событий - приказ потоку сгинуть.


 
han_malign ©   (2009-01-15 13:47) [29]


> индусятина, при  waitforsingleobject  не нужен.

FSync:= CreateEvent(nil, not synchronous, true, nil);
если FSync - всегда взведен получим 100% загрузку CPU, что - в случае одного ядра - приведет как минимум к тормозам...
WaitForMultipleObject - согласен, но это ж сколько лишних строк писать(если уж меня заломало ветвление по флагу (FSynchronous:= synchronous) прописывать)...

З.Ы. в TThread1.Destroy - не забыть прибить FSync и FCrit(дабы не изменять религии)...


 
tesseract ©   (2009-01-15 13:59) [30]


> WaitForMultipleObject - согласен, но это ж сколько лишних
> строк писать(если уж меня заломало ветвление по флагу


Около 15 вроде. Считая интеграцию в класс потока.


 
GVas ©   (2009-01-15 21:08) [31]

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

procedure TForm1.Button1Click(Sender: TObject);

begin
 ModelThread.Create(False);
end;

это в подключаемом модуле

procedure ReactorThread.ShowResult;
begin
Form1.Edit1.Text := IntToStr(answer);
end;

цикл для примера взят, потом вместо него модель будет
procedure ModelThread.Execute;
var
i: Integer;
begin
for i := 1 to 10000 do
begin
answer := answer + 1;
Synchronize(ShowResult);
end;
end;


 
GVas ©   (2009-01-23 19:58) [32]

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


 
GVas ©   (2009-01-23 21:12) [33]

И в догонку пытаюсь присвоить переменной имя файла с помощью АssignFile(F,"C:\Program Files\Borland\Delphi7\Projects\1.txt")
Значение переменной не изменяется почему то, как быть???


 
GVas ©   (2009-01-23 21:19) [34]

с присваиванием имени файла разобрался, почему то в Watch list не отображалось значение переменной


 
sniknik ©   (2009-01-23 21:27) [35]

> я же сделал вот так
т.е. все объяснения впустую... ;(, скорблю по так и не состоявшемуся программисту, и да здравствует будущий дворник! ;)

> вывести на экран колонку строк размером хотя бы пару десятков строк.
дбгрид

> Значение переменной не изменяется почему то, как быть???
бери упорством, меняй пока она не согласится с новым значением... :)


 
AndreyV ©   (2009-01-23 21:28) [36]

> [32] GVas ©   (23.01.09 19:58)
> Подскажите пожалуйста как и с помощью чего лучше вывести
> на экран колонку строк размером хотя бы пару десятков строк.
> Спасибо за ответы.

А TLable уже не устраивает?
Если количество меняется, можно попробовать TStringGrid, как наиболее универсальный.


 
tesseract ©   (2009-01-23 21:34) [37]


> почему то в Watch list не отображалось значение переменной


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


 
GVas ©   (2009-01-23 21:46) [38]


> т.е. все объяснения впустую... ;(, скорблю по так и не состоявшемуся
> программисту, и да здравствует будущий дворник! ;)

Ну ИМХО в том что я написал (скопировал, а потом переделал) я хотя бы приблизительно разобрался, а вот то что было написано уважаемым han_malign я больше половины не понимаю, как можно использовать код не понимая, что он делает
AndreyV спасибо за ответ, будем пытаться,

tesseract вот как хорошо получилось, продлил жизнь еще одному человеку))


 
sniknik ©   (2009-01-23 22:03) [39]

> Ну ИМХО в том что я написал (скопировал, а потом переделал) я хотя бы приблизительно разобрался, а вот то что было написано уважаемым han_malign я
> больше половины не понимаю, как можно использовать код не понимая, что он делает
а то, что сам написал говоришь понимаешь? а то что я в первом, третьем посте написал, это по китайски? с чего у тебя в 31м посте та же ахинея что и в 0-м?


 
GVas ©   (2009-01-23 22:23) [40]

sniknik

> с чего у тебя в 31м посте та же ахинея что и в 0-м?


У меня там такие строки просто для проверки работоспособности потока, я во время работы цикла жал на вторую кнопку на форме и программа заканчивала свою работу, вот поэтому у меня там и цикл, просто чтоб проверить как поток работает, и смогу ли я выйти из программы во время работы цикла, а написал я насчет "я хотя бы приблизительно разобрался, а вот то что было написано уважаемым han_malign" имея ввиду пост № 27, я просто неправильно выразился((

Ну и в догонку, каким образом можно в поток ввести какие либо данные из основной программы???

И еще как сделать свой тип данных, например, чтоб он назывался myarrey и состоял из двух массивов заданного размера i1:array[1..10] of Integer; i2:array[1..10] of Real. обращение я так понимаю к отдельному елементу будет что то типа т1.и1 или т1.и2.


 
AndreyV ©   (2009-01-23 22:33) [41]

> [40] GVas ©   (23.01.09 22:23)
> Ну и в догонку, каким образом можно в поток ввести какие
> либо данные из основной программы???

Читай о Critical Section

> И еще как сделать свой тип данных, например, чтоб он назывался
> myarrey и состоял из двух массивов заданного размера i1:
> array[1..10] of Integer; i2:array[1..10] of Real. обращение
> я так понимаю к отдельному елементу будет что то типа т1.и1
> или т1.и2.

Определи тип Record
а потом массив этих типов.


 
GVas ©   (2009-01-23 22:42) [42]

Я так понял что-то вроде этого:
type
Atom =record
 i1:array[1..10] of integer;
 i2:array[1..20] of Real;

обращение к конкретному елементу Atom.i1[1]:=23 Atom.i2[3]:=25.6


 
AndreyV ©   (2009-01-23 22:53) [43]

> [42] GVas ©   (23.01.09 22:42)
> Я так понял что-то вроде этого:
> type
> Atom =record
> i1:array[1..10] of integer;
> i2:array[1..20] of Real;
>
> обращение к конкретному елементу Atom.i1[1]:=23 Atom.i2[3]:
> =25.6


type
 Atom = record
 i : integer;
 r : Real;
 end;

var
 a : array[1..10] of Atom;


 
GVas ©   (2009-01-23 23:09) [44]

Ясно, спасибо Вам за подсказку (но если количество параметров (i1 и i2) разное тогда каким образом поступить? так как у меня или как то по другому???). И второй момент почитал хелп о Critical Section в делфе, приблизительно понял что это секция с защищенными от изменения переменными, но я еще немного подумал и решил все таки конкретезировать, мб я неправильно выразился, есть начальные параметры системы, при срабатывании таймера образуется поток который должен взять начальные параметры, обработать их и записать на место старых значений значения новые, но тогда получается что для хранения переменных я буду использовать в два раза больше памяти, для основного и второстепенного потока, или я где то ошибаюсь?


 
AndreyV ©   (2009-01-23 23:33) [45]

> [44] GVas ©   (23.01.09 23:09)
> Ясно, спасибо Вам за подсказку (но если количество параметров
> (i1 и i2) разное тогда каким образом поступить? так как
> у меня или как то по другому???).

Может тебе надо что-то такое

 Atom = record
 i : integer;
 x, y, z : Real;
 end;

Ты про модель ничего не уточнял.

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

Поток уже есть

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

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


 
GVas ©   (2009-01-23 23:42) [46]

и еще момент увидел при работе цикла
for i := 1 to 1992 do
 begin
   readln(F_DM_ATOM,S_DM_ATOM);
   readln(F_Z_ATOM,S_Z_ATOM);
   readln(F_N_ATOM,S_N_ATOM);
   i1[i,1]:=StrToInt(S_N_ATOM);
   i1[i,2]:=StrToFloat(S_Z_ATOM);
   i1[i,3]:=StrToFloat(S_DM_ATOM);
 end;
смотрел значение переменной i почему то значение шло не от единицы до 1992 а наоборот с 1992 до 1 почему так, и как исправить такую ситуацию??? хотя масив заполнялся правильно с начала и до конца, но вопрос стоит в том что если будет условие на i вроде если и больше единицы то то то и то то, получается что это условие будет неправильно работать, и второй момент при создании массива я его не обнулял, при просмотре значений почти все значения были нулями, но некоторые были заполнены вещественными числами, хотя я кажись вычитывал в этой ветке обсуждение насчет того что необходимсоти обнуления нет.


 
GVas ©   (2009-01-23 23:46) [47]

AndreyV
Спасибо Вам за ответы


 
Servy ©   (2009-01-24 00:07) [48]

> смотрел значение переменной i почему то значение шло не
> от единицы до 1992 а наоборот с 1992 до 1 почему так

Потому что процессору проще проверять, сравнялось ли i с нулем, чем с 1992. Выключи галку Optimization в настройках компилятора, будет все по-честному. Условия будут работать правильно, это отдается на откуп компилятору, верь в него :). Для отладки оптимизацию как правило выключают.


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


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

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


 
GVas ©   (2009-01-24 00:18) [49]

Servy
Спасибо за совет, действительно, наблюдается нехватка теоретических знаний, и я склоняюсь к тому, что придется браться за какую-то серьезную книгу.



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

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

Наверх




Память: 0.61 MB
Время: 0.043 c
15-1231283649
Alkid
2009-01-07 02:14
2009.03.15
Из системы "пропал" DVD-RW


15-1231149171
***mikle***
2009-01-05 12:52
2009.03.15
Какую среду вы используете?


3-1216026097
Костик
2008-07-14 13:01
2009.03.15
Какую выбрать технологию?


2-1232948305
charoey_mag
2009-01-26 08:38
2009.03.15
Скриншот Рабочего стола


2-1232616459
jetus
2009-01-22 12:27
2009.03.15
Circular unit reference - как быть?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский