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

Вниз

Подскажите почему я не могу освободить поток   Найти похожие ветки 

 
KyRo   (2006-12-01 11:30) [0]

Я создаю поток
 StatusATMT:=TStatusATMThread.Create(False);


constructor TStatusATMThread.Create(CreateSuspennded: Boolean);
  begin
     inherited Create(CreateSuspennded) ;
      // Создаем сервер
    ServerS:=TServerSocket.Create(nil);
    ServerS.OnClientError:=ServerClientError;
    ServerS.OnClientRead:=ServerClientRead;
    ClientS:=TClientSocket.Create(nil);
    ClientS.OnError:=ClientError;
    ClientS.OnConnect:=ClientConnect;
    ClientS.ClientType:=ctNonBlocking;
    //priority:=tpLowest;
    Resume;
  end;


В EXECUTE есть соответственно цикл который запускает сокет сервер и клиент и начинает работать по сети с клиентами

While not Terminated do
  begin
       ATML:=TStringList.Create;
   {Запрашиваем список ай пи адресов клиентов которых надо опросить}
   if  LoadATMList(ATML) =False
      then
         begin
          ATML.Free;
          Terminate;
         end;
   {Запускаем опрос}
   For i := 0 to ATML.Count -1 do
       begin
         {Запускаем сервер}
          ServerS.ServerType:=stNonBlocking;
          ServerS.Port:=50018;
          ServerS.Active:=True;
          и.т.д

При выходе из этого цикла (то есть в конце экзекют) я освобождаю сервер и клиент


ServerS.Free;
   ClientS.Free;
   ATML.Free;


И вот из основной программы я пытаюсь его освободить и на этом программа залипает !!!

StatusATMT.Terminate;
StatusATMT.Free;


StatusATMT -это глобальная переменная С типом TStatusATMThread

Подскажите из за чего это может происходить ?


 
clickmaker ©   (2006-12-01 11:34) [1]


> if  LoadATMList(ATML) =False
>       then
>          begin
>           ATML.Free;
>           Terminate;
>          end;

а почему не просто Break? И зачем свойства в цикле каждый раз по новой назначать?


 
С   (2006-12-01 11:39) [2]

Причина в "и. т. д."


 
KyRo   (2006-12-01 11:40) [3]


> а почему не просто Break?


Можно и Break? не спорю но тогда надо освободить сервер и клиент или они вместе с потоком освободятся автоматом когда я его уничтожу?


> И зачем свойства в цикле каждый раз по новой назначать?


Свойства чего сервера ? Если да то для разных клиентов разные параметры.


 
KyRo   (2006-12-01 11:42) [4]


> Причина в "и. т. д."

:)

Держите расшифровку (весь execute)


var
ATML:TStringList;
i:Integer;
ipclientIMG:String;
//**************************************************
{Функция определяет количество банкоматов с прописаным ай пи адресом}
Function LoadATMList(var ATML:TStringList):Boolean;
var
  DBCONNECT:TADOConnection;
  ADOQUERY:TADOQuery;
  ConnectionReg:Tregistry;
  ConString:String;
  i:Integer;
begin
   // Создаем компонент соединения с бд
   DBCONNECT:=TADOConnection.Create(nil);
   With DBCONNECT do
    begin
     ConnectionReg:=TRegistry.Create;
     ConnectionReg.RootKey:=HKEY_CURRENT_USER;
     ConnectionReg.OpenKey("\SOFTWARE\LogBn\Settings\", false);
     ConnectionString:=ConnectionReg.ReadString("ConnectionString");
     DBCONNECT.LoginPrompt:=False;
     Connected := True;
   end;
     ConnectionReg.Free;
  //Создаем кмпонент АДО ТЕЙБЛ
    ADOQUERY:=TADOQuery.Create(nil);
  // Задаем параметры соединения
  With ADOQUERY do
   begin
     Connection:= DBCONNECT;
     ADOQUERY.SQL.Add("Select * from ATM_NAME where IP_CLIENT IS NOT NULL order by NAME");
     Active:=True;
   end;
   if ADOQUERY.RecordCount = 0
      then
        begin
          ADOQUERY.Free;
          DBCONNECT.Connected:=False;
          DBCONNECT.Free;
          Result:=False;
          Exit;
        end;
   ADOQUERY.First;
  For i:= 1 to ADOQUERY.RecordCount do
    begin
      ATML.Add(ADOQUERY.FieldValues["IP_CLIENT"]);
      ADOQUERY.Next;
    end;
  if ATML.Count > 0
     then
       begin
         Result:=True;
         ADOQUERY.Free;
         DBCONNECT.Connected:=False;
         DBCONNECT.Free;
       end
     else
       begin
          ADOQUERY.Free;
          DBCONNECT.Connected:=False;
          DBCONNECT.Free;
          Result:=False;
       end;
end;
//**************************************************
{Функция модификации записи статуса клиента в базе данных}
Procedure ModifyBD(IPADDR:String);
  var
  DBCONNECT:TADOConnection;
  ADOQUERY:TADOQuery;
  ConnectionReg:Tregistry;
  ConString:String;
 begin
     // Создаем компонент соединения с бд
   DBCONNECT:=TADOConnection.Create(nil);
   With DBCONNECT do
    begin
     ConnectionReg:=TRegistry.Create;
     ConnectionReg.RootKey:=HKEY_CURRENT_USER;
     ConnectionReg.OpenKey("\SOFTWARE\LogBn\Settings\", false);
     ConnectionString:=ConnectionReg.ReadString("ConnectionString");
     DBCONNECT.LoginPrompt:=False;
     Connected := True;
   end;
     ConnectionReg.Free;
  //Создаем кмпонент АДО ТЕЙБЛ
    ADOQUERY:=TADOQuery.Create(nil);
  // Задаем параметры соединения
  With ADOQUERY do
   begin
     Connection:= DBCONNECT;
     ADOQUERY.SQL.Add("Select * from ATM_NAME where IP_CLIENT="+#39+IPADDR+#39);
     Active:=True;
   end;
   if ADOQUERY.RecordCount = 0
      then
        begin
          ADOQUERY.Free;
          DBCONNECT.Free;
          Exit;
        end;
  If ResMassag<>""
  then
    begin
     ADOQUERY.Edit;
     ADOQUERY.FieldByName("STATUS_CLIENT").Value:="Работает";
     ADOQUERY.Post;
    end
  else
    begin
     ADOQUERY.Edit;
     ADOQUERY.FieldByName("STATUS_CLIENT").Value:="Не доступен";
     ADOQUERY.Post;
    end;
 ADOQUERY.Active:=False;
 DBCONNECT.Connected:=False;
 ADOQUERY.Free;
 DBCONNECT.Free;
 end;
//**************************************************
begin
While not Terminated do
  begin
       ATML:=TStringList.Create;
   {Запрашиваем список ай пи адресов клиентов которых надо опросить}
   if  LoadATMList(ATML) =False
      then
         begin
          ATML.Free;
          Terminate;
         end;
   {Запускаем опрос}
   For i := 0 to ATML.Count -1 do
       begin
         {Запускаем сервер}
          ServerS.ServerType:=stNonBlocking;
          ServerS.Port:=50018;
          ServerS.Active:=True;
         // Cоздаем клиент
         ClientS.Active:=False;
         ipclientIMG:=ATML.Strings[i];
         DelSpacesUn(ipclientIMG);
         Messag:=ipclientIMG;
         ClientS.Address:=ipclientIMG;
         ClientS.Port:=50017;
         ClientS.Tag:=0;
         ResMassag:="";
         StatusWake:=0;
          Application.ProcessMessages ;
        try
          ClientS.Active:=True;
          Application.ProcessMessages ;
        Except
         Continue;
        end;
        {---! Запускаем таймер который будет следить за работай сервера }
        TimerServerWork:=TTimer.Create(nil);
        TimerServerWork.OnTimer:=TimerServerWorkOnTimer;
        TimerServerWork.Interval:=10000;
        TimerServerWork.Enabled:=True;
        //Ожидаем ответа или выхода таймаута
        While (StatusWake = 0)and(not Terminated) do Application.ProcessMessages ;
        //Тушим сервер и таймер
        TimerServerWork.Enabled:=False;
        TimerServerWork.Free;
        ServerS.Active:=False;
        //Модифицируем базу данных
        ModifyBD(Messag);
      end;
  ATML.Free;
  end;
  ServerS.Active:=False;
  ClientS.Active:=False;
  try
   ServerS.Free;
   ClientS.Free;
   ATML.Free;
  except
   Break;
  end;


 
clickmaker ©   (2006-12-01 11:45) [5]

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


 
sniknik ©   (2006-12-01 11:46) [6]

[1] +
> из за чего это может происходить ?
в цикле, который выполняется долго, нет проверки на Terminated и выхода если установлен, вот он его до конца и прокручивает.

++
ATML:=TStringList.Create;
try
//все остальное сдесь
//например
if  LoadATMList(ATML) = False then Break; //или Exit если вдруг вложенных циклов станет больше одного, и нужно выйти а Break этого уже позволит.

....

finally
 ATML.Free;
end;


 
Сергей М. ©   (2006-12-01 11:48) [7]


> KyRo


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

p.s.
Насколько мне помнится, ты уже получал граблями за обращение к VCL-компонентам в доп.потоке, и теперь вновь на них наступаешь.


 
sniknik ©   (2006-12-01 11:48) [8]

> Application.ProcessMessages ;
в потоке ????? убери пока больше никто не видел...


 
KyRo   (2006-12-01 11:52) [9]


> try
> //все остальное сдесь
> //например
> if  LoadATMList(ATML) = False then Break; //или Exit если
> вдруг вложенных циклов станет больше одного, и нужно выйти
> а Break этого уже позволит.
>
> ....
>
> finally
>  ATML.Free;
> end;


Так да можно сделать.
> [1] +
> > из за чего это может происходить ?
> в цикле, который выполняется долго, нет проверки на Terminated
> и выхода если установлен, вот он его до конца и прокручивает.
>



> //Ожидаем ответа или выхода таймаута
>         While (StatusWake = 0)and(not Terminated) do Application.
> ProcessMessages ;


Имеете ввиду вот этот цикл ? Поставить после него проверку на Terminated
и если есть то Exit ? Я правильно понял ?


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


Залипает на строке которй я его пытаюсь освободить


 
KyRo   (2006-12-01 11:54) [10]


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

Это легче всего сказать !!


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


> > Application.ProcessMessages ;
> в потоке ????? убери пока больше никто не видел...


Я не обращаюсь в всл Application.ProcessMessages ; для того что бы работали события таймера ,клиента и сервера которые функционируют в этом потоке


 
clickmaker ©   (2006-12-01 11:58) [11]


> Залипает на строке которй я его пытаюсь освободить

procedure TThread.Terminate;
begin
 FTerminated := True;
end;

здесь залипать нечему, как видишь

destructor TThread.Destroy;
begin
 if (FThreadID <> 0) and not FFinished then
 begin
   Terminate;
   if FCreateSuspended then
     Resume;
   WaitFor;
 end;

а вот здесь может залипнуть на WaitFor. Значит, где-то внутри Execute


 
Сергей М. ©   (2006-12-01 12:07) [12]


> Я не обращаюсь в всл Application.ProcessMessages


Здрасть-приехали !

Application - это что по-твоему ? Не VCL-объект, надо понимать ?


> для того что бы работали события таймера ,клиента и сервера
> которые функционируют в этом потоке


Насчет таймера в код не вникал, но более чем уверен - он там нафиг не нужен.

По поводу же клиента и сервера тебе, как помнится, уже приводили код:

while not Terminated and GetMessage(Msg, 0, 0, 0) do
 DispatchMessage(Msg);

И все ! И никаких Application.ProcessMessages тут не нужно ! Все при этом расчудесно работает)


 
sniknik ©   (2006-12-01 12:09) [13]

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

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


 
Сергей М. ©   (2006-12-01 12:11) [14]

Ну и еще один крайне важный момент:

CoInitialize(nil);
try
.. работа с АДО, от начала и до конца ...
finally
 CoUninitialize;
end;

Выделенное жирным обязательно для исполнения в каждом доп.потоке, в котором осуществляется работа с АДО (и не только с ним)

В противном случае будет возбуждено исключение и твой поток "залипнет", поскольку в нем нет общей обработки исключений.


 
sniknik ©   (2006-12-01 12:13) [15]

Сергей М. ©   (01.12.06 12:07) [12]
> while not Terminated and GetMessage(Msg, 0, 0, 0) do
> DispatchMessage(Msg);
это у него не сработает, т.к. до этого просто не дойдет, до него куча кода который уже "залипает", тут для этого при такой структуре нужен отдельный поток обрабатывающий рабочий, и вот в нем уже можно делать так. (но лучше конечно делать правильно ;)


 
Сергей М. ©   (2006-12-01 12:16) [16]


> sniknik ©   (01.12.06 12:13) [15]


> это у него не сработает, т.к. до этого просто не дойдет,
>  до него куча кода который уже "залипает"


Это понятно.

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


 
sniknik ©   (2006-12-01 12:16) [17]

> Имеете ввиду вот этот цикл ? Поставить после него проверку на Terminated
> и если есть то Exit ? Я правильно понял ?
нет. я имел ввиду первый показанный цикл, и не после него а в нем. разница однако!

>  {Запускаем опрос}
>    For i := 0 to ATML.Count -1 do
>        begin
>          {Запускаем сервер}
>           ServerS.ServerType:=stNonBlocking;
>           ServerS.Port:=50018;
>           ServerS.Active:=True;
>           и.т.д


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


 
KyRo   (2006-12-01 12:22) [18]


> CoInitialize(nil);
> try
> .. работа с АДО, от начала и до конца ...
> finally
>  CoUninitialize;
> end;

Что это такое можно по подробнее ?


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


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


 
Сергей М. ©   (2006-12-01 12:27) [19]


> Что это такое можно по подробнее ?
>


Подробности - в справке и msdn.

А вкратце - эти ф-ции инициализируют/деинициализируют COM-подсистему для работы в текущем код.потоке. АДО как раз и базируется на OLE/COM.


 
clickmaker ©   (2006-12-01 12:27) [20]


> А таймер мне нужен что бы сделать тайм аут на то сколько
> сервер будет ожидать ответа от клиента

а почему бы Sleep не сделать? или через события? TEvent, WaitFor


 
sniknik ©   (2006-12-01 12:38) [21]

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

про CoInitialize(nil); все правда, не веришь твое дело.

clickmaker ©   (01.12.06 12:27) [20]
> а почему бы Sleep не сделать? или через события? TEvent, WaitFor
;о)) опять же, а как оно будет работать если уже чтото выполняется и до Sleep или ожидания событий попросту не доходит дело?

тут парой изменений не обойдешься, нужно в корне чтото менять.


 
Сергей М. ©   (2006-12-01 12:42) [22]


> KyRo


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

Но даже если на это есть серьезные причины (в чем сомневаюсь) возьми себе за правило при разработке не самой тривиальной поточной логики заключать тело метода Execute в try..except, чтобы можно было протоколировать неожиданные исключения, о которых ты изначально не подозреваешь.

Вот так:

procedure TMyThread.Execute;
begin
 try
.. все что угодно ...
 except
   on e:exception do
     WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " + e.Classname + " " + e.Message);
 end;
end;


 
KyRo   (2006-12-01 12:53) [23]


> а почему бы Sleep не сделать?

Не подходит потому что тайм аут у меня 2 -е минуты а сообщение от клиента может прийти через 3 сек в зависимости от работы канала


> про CoInitialize(nil); все правда, не веришь твое дело.

Про CoInitialize(nil); не чего плохого  не говорил !! Просто не знал про это , щас буду делать! Вот только вопрос чего тогда у меня ADO работает в потоке без инициализации ?


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


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


 
KyRo   (2006-12-01 13:02) [24]


> Вот так:
>
> procedure TMyThread.Execute;
> begin
>  try
> .. все что угодно ...
>  except
>    on e:exception do
>      WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " +
> e.Classname + " " + e.Message);
>  end;
> end;
> <Цитата>

Щас так и сделаю

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

Имееш в виду брек поинты ? Ими пользуюсь


 
Leonid Troyanovsky ©   (2006-12-01 13:12) [25]


> Сергей М. ©   (01.12.06 12:42) [22]

>      WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " +
> e.Classname + " " + e.Message);


Лучше, IMHO, OutputDebugString, чтобы приучаться к
отладочным средствам, таким как, например, EventLog.

--
Regards, LVT.


 
sniknik ©   (2006-12-01 13:17) [26]

> Вот только вопрос чего тогда у меня ADO работает в потоке без инициализации?
используется инициализация из основного потока в котором она делается при подключении какогото модуля (не помню какого).


 
Сергей М. ©   (2006-12-01 13:52) [27]


> sniknik ©   (01.12.06 13:17) [26]


> не помню какого


ComObj

Скорей всего у автора этот юнит задействован, раз он миновал засаду с исключением по этому поводу.


> KyRo   (01.12.06 13:02) [24]


> Имееш в виду брек поинты ? Ими пользуюсь


Не заметно.


 
icWasya ©   (2006-12-01 13:59) [28]

а как вот после вот этого
  if  LoadATMList(ATML) =False
     then
        begin
         ATML.Free; // <<==-- вот это
         Terminate;
        end;
выполняется вот это
  {Запускаем опрос}
  For i := 0 to ATML.Count -1 do


 
KyRo   (2006-12-01 14:01) [29]


> > KyRo   (01.12.06 13:02) [24]
>
>
> > Имееш в виду брек поинты ? Ими пользуюсь
>
>
> Не заметно.


Я ж говорю что весь код внутри у меня работает . То есть сам алгоритм опроса клиентов полностью функционирует и цикл проходит по всей выборке из базы и потом начинает все с начала ! А вот прервать из основного потока(А точнее не прервать потому что Тerminate выполняется ) А вызвать Thread.Free что бы освободить память не получается программа на этом зависает. При этом брикпоинты не чего не показывают


 
Сергей М. ©   (2006-12-01 14:04) [30]


> внутри у меня


Я даже боюсь предположить, где в тебе находится это самое "внутри")


> брикпоинты не чего не показывают
>


Значит не там их расставляешь.


 
KyRo   (2006-12-01 14:05) [31]


> ComObj
>
> Скорей всего у автора этот юнит задействован, раз он миновал
> засаду с исключением по этому поводу.


Нету его вот все модули
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, DBCtrls, fDBCtrls, Grids, ValEdit, ExtCtrls, ComCtrls,
 Buttons, CheckLst, fCtrls, ImgList, ParsM, IniFiles, Registry, Menus,
 DBGrids, Tray ,ADOConEd ,ADODB ,ClipBrd, AppEvnts ,CopyFile, ScktComp,
 Gauges, Winsock, TrayIconU ,ShellApi,StatusATMThread,db;


> icWasya ©   (01.12.06 13:59) [28]
> а как вот после вот этого
>   if  LoadATMList(ATML) =False
>      then
>         begin
>          ATML.Free; // <<==-- вот это
>          Terminate;
>         end;
> выполняется вот это
>   {Запускаем опрос}
>   For i := 0 to ATML.Count -1 do


Вот это происходит только тогда когда функция вернула пустой список и Фалсе после этого фор выполнять нет смысла


 
Сергей М. ©   (2006-12-01 14:18) [32]


> KyRo   (01.12.06 14:05) [31]
> Нету его вот все модули


Это не модули, а юниты.

Значит один из этих юнитов использует ComObj в uses.
Либо где-то среди них явно вызывается сабж.
Только так, третьего не дано.


 
KyRo   (2006-12-01 15:07) [33]


> Это не модули, а юниты.
>
> Значит один из этих юнитов использует ComObj в uses.
> Либо где-то среди них явно вызывается сабж.
> Только так, третьего не дано.


Ну в любом случае если вы говорите что так будет правильно, сделаю так.


 
Сергей М. ©   (2006-12-01 15:28) [34]

В любом случае пара CoInitialize/CoUninitialize не помешает.


 
Anatoly Podgoretsky ©   (2006-12-01 16:00) [35]

> clickmaker  (01.12.2006 11:34:01)  [1]

> а почему не просто Break?

Что бы выполнить еще раз цикл I


 
KyRo   (2006-12-01 16:00) [36]

Все сделал  просто надо было выйти из цикла и вызвать Break и раставить еще по некоторым процедурам exit как тут советовали.
всем спасибо


 
Anatoly Podgoretsky ©   (2006-12-01 16:02) [37]

> sniknik  (01.12.2006 11:48:08)  [8]

> убери пока больше никто не видел...

Поздно.


 
KyRo   (2006-12-01 16:23) [38]

CoInitialize(nil);
try
.. работа с АДО, от начала и до конца ...
finally
CoUninitialize;
end;


Я щас начал добовлять эту инициализацию пишет не известный идентификатор ! В каком юните находятся эти функции ?


 
Сергей М. ©   (2006-12-01 16:26) [39]

ActiveX


 
KyRo   (2006-12-01 16:33) [40]

ок спасибо



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

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

Наверх




Память: 0.59 MB
Время: 0.044 c
4-1153296002
shake-c
2006-07-19 12:00
2006.12.17
Связь с порождаемым процессом


1-1162383327
GEN++
2006-11-01 15:15
2006.12.17
Закрытие процесса


9-1140419696
VK
2006-02-20 10:14
2006.12.17
DelphiX на разных машинах - полупрозрачность и скорость


10-1126883726
TStas
2005-09-16 19:15
2006.12.17
Как ответить экселю "не сохранять"?


3-1160383233
svt
2006-10-09 12:40
2006.12.17
Подскажите пожайлусата как выбрать из базы все повторяющиеся





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