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

Вниз

как определить- закончена перекачка файла или нет?   Найти похожие ветки 

 
Van   (2002-03-11 11:40) [0]

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


 
Polevi   (2002-03-11 11:42) [1]

а как ты его качаешь


 
Shaman_Naydak   (2002-03-11 12:07) [2]

открывай файл для отображения в эксклюзиве.. если открылся, значит никто его не трогаеть, во


 
Van   (2002-03-11 13:31) [3]

В эксклюзиве - это как (прошу извинить чайника), какой-то параметр при открытии установить? Какой, если, не трудно подскажите.

А по поводу качания (для Polevi)- качаться может по сети или через COM порт, а может и через USB, собственно это не важно. Важно что задержка есть и она не определена.


 
Polevi   (2002-03-11 13:44) [4]

в имени файла передавай его размер :-)


 
Van   (2002-03-11 14:08) [5]

Передавать размер файла в имени - дело хорошее, но я не имею доступа к передающей программе. Кроме того как опрдеделить размер файла если он еще не перекачался?

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

, но я что-то не врублюсь как открыть в эксклюзиве, может API-я функция какая-то есть, но я ее не знаю.


 
Van   (2002-03-11 15:23) [6]

Похоже врубаюсь, буду пробовать.


 
Shaman_Naydak   (2002-03-11 15:27) [7]

>> Van
Скажи мне как ты открываешь файл, подскажу какие флаги выставить


 
Polevi   (2002-03-11 15:54) [8]

Shaman_Naydak © дело говорит
Если файл еше не докачен - он открыт операционной системой...


 
Van   (2002-03-11 16:14) [9]

Всем спасибо.
Наконец-то разобрался.
Проще всего оказалось сделать так:

repeat //проверка занятости файла
HndFile:=FileOpen(SR.Name,fmShareExclusive);
Sleep(1);
until HndFile<>-1;
FileClose(HndFile);


 
Юрий Зотов   (2002-03-11 18:30) [10]

FindFirst/Next/CloseChangeNotification - ожидание завершения записи файла.


 
Suntechnic   (2002-03-12 08:23) [11]

>Юрий Зотов © (11.03.02 18:30)
Использовать FindFirstChangeNotification(and etc.) не получится. Т.к. они не смогут проинформировать об окончании записи файла, они срабатывают в момент начала записи.

>Van (11.03.02 16:14)
Проще то оно проще, но это не самое эффективное решение. Всё дело в том, что данный цикл будет просто "забивать" процессор. Sleep(1) конечно немного облегчит дело, но явно в ущерб твоему потоку (ставить большую задержку тоже плохо, так как если это основной поток процесса, то процесс просто будет казаться зависшим в периоды ожидания). Конечно, может овчинка выделки и не стоит, но если делать всё красиво, то тебе самому надо читать файл с помощью ReadFileEx и использовать Wait-ф-ции.


 
panov   (2002-03-12 11:33) [12]

>Suntechnic © (12.03.02 08:23)
Использовать FindFirstChangeNotification(and etc.) не получится. Т.к. они не смогут проинформировать об окончании записи файла, они срабатывают в момент начала записи.

FILE_NOTIFY_CHANGE_SIZE
Any file-size change in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change in file size only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.
FILE_NOTIFY_CHANGE_LAST_WRITE Any change to the last write-time of files in the watched directory or subtree causes a change notification wait operation to return. The operating system detects a change to the last write-time only when the file is written to the disk. For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed.



 
Юрий Зотов   (2002-03-12 11:52) [13]

> Suntechnic © (12.03.02 08:23)
> они срабатывают в момент начала записи.

Если бы это было так... Как легко тогда перехватывалась бы любое изменение любого файла любой программой, несмотря на кэширование. Но увы!

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

Но для данной задачи (см. вопрос) это как раз то, что и нужно.


 
Van   (2002-03-12 13:14) [14]


> Suntechnic © (12.03.02 08:23)


> Проще то оно проще, но это не самое эффективное решение.
> Всё дело в том, что данный цикл будет просто "забивать"
> процессор. Sleep(1) конечно немного облегчит дело, но явно
> в ущерб твоему потоку (ставить большую задержку тоже плохо,
> так как если это основной поток процесса, то процесс просто
> будет казаться зависшим в периоды ожидания). Конечно, может
> овчинка выделки и не стоит, но если делать всё красиво,
> то тебе самому надо читать файл с помощью ReadFileEx и использовать
> Wait-ф-ции.

Спасибо за подсказку. Возможно я использую функцию ReadFileEx позже, а пока меня вполне устраивает то как я сделал. Конечно цикл и Sleep останавливают мой поток, но в данном случае мне это не важно.


 
Suntechnic   (2002-03-12 16:18) [15]

>Юрий Зотов © (12.03.02 11:52)
>Согласно документации, они срабатывают в момент сброса файла на диск. На практике - в момент его закрытия пишущей >программой, в чем уже пришлось убедиться. Несложно проверить, рекомендую...

Я именно и писал Вам про практику. Как понятно из названия уведомления, оно произойдёт когда изменится размер файла(трактовка в грубом приближении, конечно). Запустите проводник и проэкспериментируйте. Попробуйте скопировать большой файл из одной папки в другую. Сначала будет создан файл, а затем начнётся его копирование. И посмотрите в этот момент размер этого файла. А заодно и попробуйте поймать это уведомление. Вообщем Вы сами попробуйте... Так что для данной задачи это как раз и не подойдёт...

>panov © (12.03.02 11:33)
А по-русски мог ёшь? Хелпы читать я и так умею, хотелось бы с живими людьми пообщаться, если им конечно есть что сказать...


 
panov   (2002-03-12 16:30) [16]

>Suntechnic © (12.03.02 16:18)
Если по русски, то вот здесь:
http://delphi.mastak.ru/articles/panov/index.html - 2.4. Создание Execute

Достаточно указать соответствующие параметры в функции FindFirstChangeNotification


 
Юрий Зотов   (2002-03-12 16:44) [17]

> Suntechnic © (12.03.02 16:18)


1.
> Как понятно из названия уведомления, оно произойдёт когда
> изменится размер файла

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


2.
> Сначала будет создан файл, а затем начнётся его копирование

И все это время файл будет ОТКРЫТ. Поэтому уведомлений не поступит, несмотря на якобы увеличивающийся размер. А по завершении копирования файл будет ЗАКРЫТ - вот в этот момент и поступит уведомление. Что и требовалось автору вопроса.


3.
> Вообщем Вы сами попробуйте...

Докладываю - делал это многократно. Пробовать еще раз не вижу смысла.


4.
> Так что для данной задачи это как раз и не подойдёт...

Как раз для данной задачи - отловить момент завершения копирования - это именно то, что нужно (см. п. 2).


 
Suntechnic   (2002-03-12 18:07) [18]

>Юрий Зотов © (12.03.02 16:44)
>И все это время файл будет ОТКРЫТ. Поэтому уведомлений не поступит, несмотря на якобы увеличивающийся размер.

Должен Вам заметить, если Вы ещё не в курсе, что никакой размер увеличивать не будет. Он увеличится только один раз: в момент начала копирования. Потому как нет смысла копировать файл, а потом вдруг выяснить, что места на диске нет... Поэтому сначала на диске резервируют место, а уж затем производят копирование как таковое.

>Но не ранее, чем файл будет закрыт и сброшен на диск. Это и в хелпе написано, и на практике так и есть.

Неправда. Необязательно файл должен быть закрыт, чтобы произошло уведомление об изменении его размера. А в хеле написано буквально следующее
The operating system detects a change in file size only when the file is written to the disk.
Фраза is written это не есть file must be closed. Это можно понимать,и как то, что файл должен физически существовать. Что вкладывалось в это понятие я рассуждать не хочу, тем более, что вопрос не заключается в обсуждении работы FindFirstChangeNotification, а лишь в том, можно её использовать или нет....

>Докладываю - делал это многократно. Пробовать еще раз не вижу смысла

А вот это Вы зря. Если вам конечно лень, я могу и сам вам тестовый примерчик набрасать. С двумя проектами, один будет следить, а другой писать, чтобы вы лично убедились когда всё-таки происходит уведомление от FindFirstChangeNotification. Но если это и произойдёт то только на VC++, потому как для меня на Delphi будет дольше.

>panov © (12.03.02 16:30)
К твоей демагогии я уже просто привык, так что no comments


 
panov   (2002-03-12 18:15) [19]

>Suntechnic © (12.03.02 18:07
Должен Вам заметить, если Вы ещё не в курсе, что никакой размер увеличивать не будет. Он увеличится только один раз: в момент начала копирования. Потому как нет смысла копировать файл, а потом вдруг выяснить, что места на диске нет... Поэтому сначала на диске резервируют место, а уж затем производят копирование как таковое.

Полная чушь. ( без комментариев)

А вот это Вы зря. Если вам конечно лень, я могу и сам вам тестовый примерчик набрасать.

Да ради бога, хоть на C.

И я, и Ю.Зотов это УЖЕ попробовали сделать.

К твоей демагогии я уже просто привык, так что no comments

Когда успел?


 
Suntechnic   (2002-03-12 18:28) [20]

> panov © (12.03.02 18:15)
>Полная чушь. (без комментариев)

Очередная демагогия(no comments)



 
Suntechnic   (2002-03-12 18:49) [21]

>Юрий Зотов © (12.03.02 16:44)
В Delphi переведёте сами:

Первый проект следит за директорией с:\temp

Код:

DWORD dwWaitStatus;
HANDLE dwChangeHandle;


dwChangeHandle = FindFirstChangeNotification(
"C:\\temp", // directory to watch
FALSE, // do not watch the subtree
FILE_NOTIFY_CHANGE_SIZE);

if (dwChangeHandle == INVALID_HANDLE_VALUE)
ExitProcess(GetLastError());


while (TRUE)
{

// Wait for notification.

dwWaitStatus = WaitForSingleObject( dwChangeHandle, INFINITE);

switch (dwWaitStatus)
{
case WAIT_OBJECT_0:
if ( FindNextChangeNotification( dwChangeHandle) == FALSE )
ExitProcess(GetLastError());
break;

default:
ExitProcess(GetLastError());
}
}


Второй проект манипуляции с файлом:

HANDLE hf = CreateFile("C:\\temp\\bigfile.big", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
SetFilePointer(hf, 1048576, 0, FILE_BEGIN);
SetEndOfFile(hf);// Notification right after this line!!!!! File is still open
CloseHandle(hf);


Как я упоминал ранее мы сначала резервируем место на диске, а копирование будем производить позже. Например сразу после строчки SetEndOfFile(hf) мы выполним SetFilePointer(hf, 0, 0, FILE_BEGIN); И начнём писать с помощью WriteFile. В итоге: событие получено, файл реально на диск не записан.

Переведите в Delphi расставьте breakpoint-ы и сами посмотрите, что за чем происходит.


 
panov   (2002-03-12 18:58) [22]

Нужно только правильно воспользоваться вышеописанной функцией.

Чтобы определить, кто демагог, достаточно заменить
FILE_NOTIFY_CHANGE_SIZE на
FILE_NOTIFY_CHANGE_LAST_WRITE


 
panov   (2002-03-12 19:00) [23]

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


 
Suntechnic   (2002-03-12 19:10) [24]

>panov © (12.03.02 18:58)
Да не надо мне ничего высылать. Ты мой примерчик переведи в Delphi и ставь там, что душа пожелает: хоть FILE_NOTIFY_CHANGE_SIZE, хоть FILE_NOTIFY_CHANGE_LAST_WRITE... Только я тебя прошу. Не надо лишних слов. Запусти мой пример и посмотри.


 
Юрий Зотов   (2002-03-12 22:50) [25]

Перевел, а заодно убрал лишнее. Вот код для желающих:

Монитор:

program Project1;
{$APPTYPE CONSOLE}

uses
Windows;

var
dwChangeHandle: THandle;

begin
dwChangeHandle := FindFirstChangeNotification("D:\Temp", False, FILE_NOTIFY_CHANGE_SIZE);
if dwChangeHandle <> INVALID_HANDLE_VALUE then
try
while WaitForSingleObject(dwChangeHandle, INFINITE) = WAIT_OBJECT_0 do
begin
WriteLn("Notification!");
FindNextChangeNotification(dwChangeHandle)
end
finally
FindCloseChangeNotification(dwChangeHandle)
end
end.


Пишущая программа:

procedure TForm1.FormCreate(Sender: TObject);
begin
WinExec("..\SMonitor\Project1.exe", SW_SHOWNORMAL)
end;

procedure TForm1.Button1Click(Sender: TObject);
var
H: THandle;
begin
H := CreateFile("D:\Temp\TestFile.tst", GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_RANDOM_ACCESS, 0);
try
SetFilePointer(H, 1048576, nil, FILE_BEGIN);
SetEndOfFile(H)
finally
CloseHandle(H)
end
end;

Запустил под W2K. Действительно, все работает так, как Вы сказали. Но есть одно маленькое "но".

После выпонения SetEndOfFile файл на диске УЖЕ реально существует и его размер равен заказанному - а это значит, что система УЖЕ сбросила его на диск.

О чем я и говорил - уведомление приходит В МОМЕНТ РЕАЛЬНОЙ ЗАПИСИ ФАЙЛА. Не записи в файл, а записи САМОГО файла.

То же самое сказано и в хелпе. Расшифровка простая:
"For operating systems that use extensive caching, detection occurs only when the cache is sufficiently flushed".

Просто после выполнения SetEndOfFile система решила, что пора сбрасывать кэш - вот уведомление и возникло.

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


 
Suntechnic   (2002-03-12 23:03) [26]

>Юрий Зотов © (12.03.02 22:50)
>После выпонения SetEndOfFile файл на диске УЖЕ реально существует и его размер равен заказанному - а это значит, что система УЖЕ сбросила его на диск.

В этом то и суть проблемы. Т.е. файл реально существует. Размер его равен исходному. Но данных там нет!!! Данные будут записаны позже. Такое происходит не всегда, но Explorer именно так и производит копирование и пермещение файлов, так что всё-таки думаю автора вопроса этот вариант не устроит.


 
panov   (2002-03-13 07:14) [27]

>Suntechnic ©
>Юрий Зотов ©
Заменив FILE_NOTIFY_CHANGE_SIZE на
FILE_NOTIFY_CHANGE_LAST_WRITE,
получим в точности тот результат, который нужен,
т.к. время последнего изменения файла будет записано системой только после закрытия файла.


 
Suntechnic   (2002-03-13 07:46) [28]

>panov © (13.03.02 07:14)
У меня нет слов :(
Многоуважаемый Панов! Не вводите в заблуждение участников форума. Если после всего сказанного, написанного и продемонстрированного у тебя остались какие-то сомнения, то оставь их при себе. Я конечно прошу прощения за подобные высказывания в публичном форуме, но когда на чёрное говорят белое, это уже чересчур. Ладно мне ты не доверяешь(даже с написанным примером), но к мнению Юрия Зотова ты вроде должен прислушаться!?


 
panov   (2002-03-13 09:46) [29]

У меня нет сомнений, так как программа, что написана у меня, выполняет НУЖНУЮ работу КАК НУЖНО.
Закончим флейм и останемся при своем мнении.

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

PS.

Желающие могут протестировать 2 программы, написанные Suntechnic © и мной, и вынести беспристрастную оценку.

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


 
panov   (2002-03-13 09:56) [30]

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

У меня задача решена.

Так вызывается функция:

HandleChange :=
FindFirstChangeNotification(
PChar(FPath),
False,
FILE_NOTIFY_CHANGE_LAST_WRITE);

Так записывается файл:

for i := 0 to 100000 do
begin
FileWrite(FileHandle,Buf,1024);
Application.ProcessMessages;
end;


 
Юрий Зотов   (2002-03-13 10:48) [31]

Есть новая информация по сабжу, но это вечером - сейчас некогда.


 
Suntechnic   (2002-03-13 15:39) [32]

>panov © (13.03.02 09:56)
>Еще хочу заметить, что Вы привели код, который не работает.

Хватит нести ерунду. У меня работает, у Юрия Зотова работает, а у тебя вдруг нет.... это даже не смешно.

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

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

И последнее:

"ОСКОРБИТЬ, блю, бишь; блённый (ён, ена); сов., кого-что. Тяжело обидеть, унизить." (С.И. Ожегов "Толковый словарь русского языка")

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


 
Юрий Зотов   (2002-03-13 15:48) [33]

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


 
panov   (2002-03-13 16:01) [34]

>Suntechnic © (13.03.02 15:39)
Да, я написал его так, чтобы он работал, чтобы получить желаемый результат.
Вы же не удосужились вникнуть в это.
А разве не это требовалось?
Или требовалось просто РАСТОПЫРИТЬ ПАЛЬЦЫ ВЕЕРОМ?

Еще раз повторяю.
Метод, используемый в panov © (13.03.02 09:56),
решает поставленную задачу.

Ваш метод доказательства нелогичен.

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

И ведите дискуссию, пожалуйста. Вы не на базаре.


 
Andrey   (2002-03-13 16:04) [35]

>Юрий Зотов © (13.03.02 15:48)

Пришли евреи к старому равину.
- Это мой баран. - говорит один еврей.
- Нет! Это мой баран. - говорит другой еврей.
- Вы оба правы. - отвечает равин.
- Но этого не может быть. - восклицает третий еврей.
- И ты прав. - отвечает мудрый равин.

P.S. Извените, вырвалось ;)


 
Suntechnic   (2002-03-13 16:15) [36]

>panov © (13.03.02 16:01)
Мне надоело доказывать кому-либо, что либо. Ещё раз повторяю: с помощью этой ф-ции решить задачу в общем случае нельзя. В частном(при наложении опеределённых условий на запись файла) можно. Если вы сами не удосужились вникнуть, нечего в этом обвинять других. Попробуйте написать пример, удовлетворяющий условиям задачи(задача это не то, что вы себе придумали, а то, что спрашивал автор вопроса), когда упрётесь в стену, тогда до вас и дойдёт. Вообщем я более не собираюсь вести бесполезных споров, если у Юрия Зотова есть конструктивная информация, я готов её обсудить. С вами товарищ Панов дискутировать по поводу этой задачи я более не намерен.

P.S.
>panov ©
Кстати, Вы получали моё письмо относительно статьи?


 
panov   (2002-03-13 16:35) [37]

>Suntechnic © (13.03.02 16:15)
Письмо получил и сразу ответил.


 
Suntechnic   (2002-03-13 17:07) [38]

>panov © (13.03.02 16:35)
>Письмо получил и сразу ответил.
??? ...странно... я ничего не получал...



 
panov   (2002-03-13 17:21) [39]

>Suntechnic © (13.03.02 17:07)
Умение признавать свои ошибки порой ценится гораздо выше, чем умение их не делать...
Для того, для того, чтобы признать ошибку, нужно понять, в чем она состоит.

Приношу свои извинения, если мои попытки выяснить истину Вас оскорбили.

Действительно, уведомление системы возникает при сбрасывании буферов на диск и при изменении позиции указателя файла.

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

Вторая ошибка - тестирование на NTFS, которую WinMe, конечно, не поддерживает.
Для NTFS в этом случае прекасно работает уведомление FILE_NOTIFY_CHANGE_LAST_ACCESS, использование которого решает задачу.

Похоже, у Ю. Зотова, все-таки, есть мысли, как решить эту задачу. Подождем...


 
Юрий Зотов   (2002-03-13 18:53) [40]

Ну, вот, выкроил окошко...

Как я уже говорил, я тестировал код Suntechnic под W2K и получил совсем не те результаты, которые получал ранее, работая под 9х. Поэтому я решил прогнать его еще раз дома, под ME.

Результаты оказались ТОЧНО такими же, что я получал и ранее - уведомления _SIZE и _LAST_WRITE приходят в момент закрытия файла. То есть, не после SetEndOfFile, а после CloseHandle - проход под отладчиком это четко показывает. В этот же момент сам файл появляется на диске.

Вывод напрашивается - уведомление, как и написано в хелпе, в любом случае приходит В МОМЕНТ РЕАЛЬНОЙ ЗАПИСИ ФАЙЛА НА ДИСК. Но линейки NT и 9х (или NTFS и FAT ?) по-разному определяют, когда следует сбрасывать кэш - отсюда и различия. В случает NT кэш сбрасывается по SetEndOfFile, а в случае 9х - по CloseHandle.

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

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

Вот такие пироги. Если выкрою время, попробую набросать реально работающий код. А в свете последнего постинга panov"а есть смысл сначала проверить _LAST_ACCESS - возможно, все окажется совсем просто.

Есть конструктивные мнения? Только конструктивные , pls.



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

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

Наверх





Память: 0.58 MB
Время: 0.009 c
1-69901
d_oleg
2002-04-09 11:44
2002.04.22
передача объектов из dll в вызыващщее приложение


4-70065
NiGth
2002-02-19 15:11
2002.04.22
WIN API


3-69675
IronHawk
2002-03-28 13:34
2002.04.22
Приветствую Мастеров ! Всевозможные операции в базе !


14-69994
Дмитрий
2002-03-15 12:24
2002.04.22
Документооборот?


14-69996
Oleg Gashev
2002-03-14 22:46
2002.04.22
Release Notes





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