Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / await,async и TASK - не получается. / 25 сообщений из 25, страница 1 из 1
01.11.2013, 02:13
    #38449170
Monochromatique
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Понимаю, что позорно,заблудился в трех словах, но ведь и на самом деле не выходит.

Есть метод

Код: c#
1.
2.
3.
4.
public String someStringFromServer()
{
//Здесь надо спросить вебсервер и вернуть то, что он прислал
}



Есть модный класс (какой-нибудь из httpClient или WebClient c Extensions), который имеет метод DownloadStringTaskAsync<String>() (кажется так)

Вопрос - как из метода, обозначенного выше вернуть строку, которую асинхронно возвращает ВебКлиент в виде задачи?

Я рыл инет - ловлю deadlock-и при любых раскладах. Пробовал и configureAwaits(false) и Wait() и пытался распространять асинхронность по всему коду (этот момент кстати не до конца понял). В примерах часто приводится код с использованием CTP - так он вообще не компилируется (await-ы в методах без async-ов)

В идеале хочется, не морозя UI получить ответ и дальше с ним работать. С помощью TPL я так понял это можно сделать. Но я не понимаю как.

Про распространение асинхронности - но ведь все равно когда-то придется получить результат. А результат у меня получить ни разу не удалось.
...
Рейтинг: 0 / 0
01.11.2013, 02:29
    #38449175
beg-in-er
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Monochromatique,

что бы не заморачиваться , если есть доступ к серверу , то можно использовать WCF.
а метод someStringFromServer сделать асинхроным, в конце которого запустить событие окончания приёма.
на всё провсё 15-20 минут.

WCF по шагам годно описан в msdn. даже новичёк поймёт.

по шагам
или тут
тынц2
...
Рейтинг: 0 / 0
01.11.2013, 04:21
    #38449191
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Monochromatique,

вот как-то примерно так:

ваш UI

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
        private MyClient _client = new MyClient();
        private CancellationTokenSource _currentWork;
 
        private async void button1_Click(object sender, EventArgs e)
        {
            // что делать если задача ещё выполняется
            if (_currentWork != null)
            {
                // или отменить задачу, или показать сообщение или что-нибудь ещё
                return;
            }

            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }
        }



метод MyClient

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
        public async Task<string> DoSomeAsync(CancellationToken cancellationToken)
        {
            try
            {
                using (var http = new HttpClient())
                {
                    var response = await http.GetAsync(_hostUri, cancellationToken);
                    if (!response.IsSuccessStatusCode)
                    {
                        // обработка HTTP ошибки
                        return null;
                    }
                    var data = await resp.Content.ReadAsStringAsync();
                    return data;
                }
            }
            catch (HttpRequestException ex)
            {
                var webEx = ex.InnerException;
                if (webEx is WebException)
                {
                    // обработка WebException
                }
                return null;
            }
        }



таким образом нажатие на кнопку не приводит к блокировке UI, асинхронно приложение ломится куда-то там и что-то делает через HttpClient (полностью асинхронный клиент). работу можно отменить через CancellationTokenSource. ну и поменьше заморочек с контекcтом.
...
Рейтинг: 0 / 0
01.11.2013, 07:36
    #38449228
Monochromatique
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
beg-in-erMonochromatique,

что бы не заморачиваться , если есть доступ к серверу , то можно использовать WCF.
а метод someStringFromServer сделать асинхроным, в конце которого запустить событие окончания приёма.
на всё провсё 15-20 минут.

WCF по шагам годно описан в msdn. даже новичёк поймёт.

по шагам
или тут
тынц2

Нееее, доступа к веб-серверу нету. Наглухо.
Да и потом, webClient сам по себе имеет Async метод с событием по окончании. Так что WCF тут без нужды, но на совет спасибо.
...
Рейтинг: 0 / 0
01.11.2013, 07:39
    #38449230
Monochromatique
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVosttMonochromatique,

вот как-то примерно так:

ваш UI

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
        private MyClient _client = new MyClient();
        private CancellationTokenSource _currentWork;
 
        private async void button1_Click(object sender, EventArgs e)
        {
            // что делать если задача ещё выполняется
            if (_currentWork != null)
            {
                // или отменить задачу, или показать сообщение или что-нибудь ещё
                return;
            }

            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }
        }



метод MyClient

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
        public async Task<string> DoSomeAsync(CancellationToken cancellationToken)
        {
            try
            {
                using (var http = new HttpClient())
                {
                    var response = await http.GetAsync(_hostUri, cancellationToken);
                    if (!response.IsSuccessStatusCode)
                    {
                        // обработка HTTP ошибки
                        return null;
                    }
                    var data = await resp.Content.ReadAsStringAsync();
                    return data;
                }
            }
            catch (HttpRequestException ex)
            {
                var webEx = ex.InnerException;
                if (webEx is WebException)
                {
                    // обработка WebException
                }
                return null;
            }
        }



таким образом нажатие на кнопку не приводит к блокировке UI, асинхронно приложение ломится куда-то там и что-то делает через HttpClient (полностью асинхронный клиент). работу можно отменить через CancellationTokenSource. ну и поменьше заморочек с контекcтом.

Я правильно понимаю, что в вашем примере применен подход - " async повсюду"? И основное правило тут - async должен оканчиваться методом c возвратом void?
...
Рейтинг: 0 / 0
01.11.2013, 07:56
    #38449236
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
MonochromatiqueЯ правильно понимаю, что в вашем примере применен подход - " async повсюду"? И основное правило тут - async должен оканчиваться методом c возвратом void?

в ином случае использование async бесмысленно. если вы хотите создать асинхронное приложение, т.е. чтобы работа в фоне не блокировало работу UI интерфейса (как вы говорите, не морозило), то вам придётся применить один из подходов для разработки асинхронных приложений. их есть несколько. async — самый простой на сегодняшний день.

async метод должен возвращать Task или Task<T>. возврат void это сахар.

если метод Method() возвращает Task<string>, то вот такой вызов:

var result = await Method();

в результате result сохранит string.
...
Рейтинг: 0 / 0
01.11.2013, 09:59
    #38449348
МСУ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVostt async метод должен возвращать Task или Task<T>. возврат void это сахар.
Какой же это сахар, ты что. Классический пример с "void button1_Click". Но рекомендация MS гласит, что по возможности нужно возвращать Task.

http://msdn.microsoft.com/ru-ru/library/vstudio/hh524395.aspx Основное использование возвращаемого значения void (процедуры Sub в Visual Basic) — в обработчиках событий, где требуется возвращать значение типа void. Возврат void также можно использовать для переопределения возвращающих void методов или для методов, выполняющих действия, которые подчиняются принципу "отправить и забыть". Однако необходимо возвращать Task всегда, когда это возможно, поскольку асинхронные методы, возвращающие void, ожидать невозможно. Любой вызывающий объект такого метода должен иметь возможность продолжить работу до завершения, не дожидаясь завершения вызванного асинхронного метода, и он не должен зависеть ни от каких значений и исключений, создаваемых асинхронным методом.
...
Рейтинг: 0 / 0
01.11.2013, 10:32
    #38449391
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
МСУ,

а ну я имел в виду, что Task в любом случае создается, только если использовать void он теряется. однако "сахар" потому что для button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task. исходников нет, чтобы посмотреть.
...
Рейтинг: 0 / 0
01.11.2013, 10:34
    #38449396
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
у меня по ходу дела встречный вопрос возник

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
            using (_currentWork = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
            {
                try
                {
                    var result = await _client.DoSomeAsync(_currentWork.Token));
                    // сделать что-нибудь с результатом
                }
                catch (TaskCanceledException)
                {
                    // выполнение задачи было отменено
                    ShowWarning(CommonMessages.Cancelled);
                }
                catch (Exception ex)
                {
                    ShowError(ex);
                }
                finally
                {
                    _currentWork = null;
                }
            }



если вот так в finally обнулять используемое в using значение, не потеряется ли вызов Dispose ?
...
Рейтинг: 0 / 0
01.11.2013, 10:41
    #38449408
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVosttМСУ,

а ну я имел в виду, что Task в любом случае создается, только если использовать void он теряется. однако "сахар" потому что для button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task. исходников нет, чтобы посмотреть.

т.е. не в целом фреймворк, а конкретно WinForms. ему Task от обработчика события нужен, чтобы правильно завершить приложения, если юзер нажмёт на крестик в углу.
...
Рейтинг: 0 / 0
01.11.2013, 10:54
    #38449441
МСУ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVosttдля button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task
Откуда информация о тасковых выковыриваниях?
...
Рейтинг: 0 / 0
01.11.2013, 11:17
    #38449488
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
МСУhVosttдля button_Click фреймворк его или обёртывает в прокси-метод или ещё как-то, но выковыривает Task
Откуда информация о тасковых выковыриваниях?

информации нет, я типо просто так утверждаю, на основе логических рассужденей. может и не выковыривает. тогда хз, что должно произойти при закрытии приложения, если в таске что-нибудь крутится. как винформс пошлёт мессадж в поток об экстренном завершении? или просто грохнет? я просто винформс не очень глубоко изучал. делаю иногда несложные утилиты для выковыривания и отображения данных из сервисов и БД. без асинка вообще ужас был, прям ненависть ненависть. а щас хорошо ))
...
Рейтинг: 0 / 0
01.11.2013, 13:03
    #38449780
Monochromatique
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVosttМСУпропущено...

Откуда информация о тасковых выковыриваниях?

из сервисов и БД. без асинка вообще ужас был, прям ненависть ненависть. а щас хорошо ))

А в чем, пардон, ужас?
...
Рейтинг: 0 / 0
01.11.2013, 13:51
    #38449907
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
MonochromatiqueА в чем, пардон, ужас?

в бэкграундворкере и в ручном разруливании контекстов.
...
Рейтинг: 0 / 0
01.11.2013, 17:36
    #38450361
LR
LR
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
MonochromatiqueВ идеале хочется, не морозя UI получить ответ и дальше с ним работать. С помощью TPL я так понял это можно сделать. Но я не понимаю как.
Для WPF можно задействовать Dispatcher.PushFrame
см. Samples for Parallel Programming Samples for Parallel Programming
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
    public static class WebClientExtensions
    {
        public static Task<string> DownloadStringTask(this WebClient webClient, Uri address)
        {
            TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
            DownloadStringCompletedEventHandler handler = null;
            handler = (sender, e) => WebClientExtensions.HandleCompletion(tcs, e, () => e.Result, () => webClient.DownloadStringCompleted -= handler);
            webClient.DownloadStringCompleted += handler;
            try {
                webClient.DownloadStringAsync(address, tcs);
            } catch (Exception exc) {
                webClient.DownloadStringCompleted -= handler;
                tcs.TrySetException(exc);
            }
            return tcs.Task;
        }
        public static void HandleCompletion<T>(
            TaskCompletionSource<T> tcs, AsyncCompletedEventArgs e, Func<T> getResult, Action unregisterHandler)
        {
            if (e.UserState == tcs) {
                if (e.Cancelled) tcs.TrySetCanceled();
                else if (e.Error != null) tcs.TrySetException(e.Error);
                else tcs.TrySetResult(getResult());
                unregisterHandler();
            }
        }
        public static void WaitWithPumping(this Task task)
        {
            if (task == null) throw new ArgumentNullException("task");
            var nestedFrame = new DispatcherFrame();
            task.ContinueWith(_ => nestedFrame.Continue = false);
            Dispatcher.PushFrame(nestedFrame);
            task.Wait();
        }
    }


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
        public String someStringFromServer()
        {
            //Здесь надо спросить вебсервер и вернуть то, что он прислал
            string result = null;
            (new WebClient()).DownloadStringTask(new Uri("http://www.sql.ru/forum/1056514/await-async-i-task-ne-poluchaetsya")).ContinueWith(task => {
                switch (task.Status) {
                    case TaskStatus.RanToCompletion:
                        result = task.Result;
                        break;
                    case TaskStatus.Faulted:
                        System.Diagnostics.Debug.WriteLine("Request failed: {0}", task.Exception.InnerException);
                        break;
                    case TaskStatus.Canceled:
                        System.Diagnostics.Debug.WriteLine("Request was canceled");
                        break;
                }
            }).WaitWithPumping();//.Wait();
            return result;
        }


...
Рейтинг: 0 / 0
01.11.2013, 20:18
    #38450509
LR
LR
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
hVosttесли вот так в finally обнулять используемое в using значение, не потеряется ли вызов Dispose ?
"Свою" переменную using не позволит обнулить, ведь он для того и придуман, чтобы гарантированно вызвать Dispose (т.е., обнулится переменная, объявленная выше using)
...
Рейтинг: 0 / 0
25.02.2014, 13:54
    #38571571
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Прицеплюсь к теме, чтобы не плодить новых.

Не понимаю деталей выполнения async методов, а точнее того, в каком потоке будет выполнятся "окончание" асинхронного метода (то, что ожидает результата вызова await и все после него). В букварях утверждают что окончание метода будет выполнено в потоке, который вызвал асинхронный метод. Однако или это не всегда так, или я люто туплю. Пожалуйста растолкуйте.

Есть форма с асинхронным методом:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Console.WriteLine("Start Form1 in thread {0}", Thread.CurrentThread.ManagedThreadId);
            btnCallMethod_Click(null, null);
            Console.WriteLine("End Form1 in thread {0}", Thread.CurrentThread.ManagedThreadId);
        }

        public async void btnCallMethod_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start btnCallMethod_Click in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var t = await DoWork();
            this.Text = t;
            Console.WriteLine("End btnCallMethod_Click in thread {0} with result {1}", Thread.CurrentThread.ManagedThreadId, t);
        }
        // See below for code walkthrough...
        public Task<string> DoWork()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("Start DoWork in thread {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("End DoWork in thread {0}", Thread.CurrentThread.ManagedThreadId);
                return "Done with work!";
            });
        }
    }


При ее запуске в InitializeComponent будет вызван btnCallMethod_Click (просто чтобы на кнопку не давить. по кнопке происходит то же самое), который является асинхронным методом. Строка
Код: c#
1.
 Console.WriteLine("End btnCallMethod_Click... 

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

Однако если использовать консольное приложение со следующим кодом:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
public class Program
    {
        public Task<int> MyTask()
        {
            return Task.Run(() =>
            {
                Console.WriteLine("Start MyTask in thread {0}", Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(5000);
                Console.WriteLine("End MyTask in thread {0}", Thread.CurrentThread.ManagedThreadId);
                return 5;
            });
        }

        public async void MyAsyncMethod(object sender, EventArgs e)
        {
            Console.WriteLine("Start MyAsyncMethod in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var result = await MyTask();
            Console.WriteLine("End MyAsyncMethod in thread {0} with result {1}", Thread.CurrentThread.ManagedThreadId, result);
        }

        static void Main()
        {
            Console.WriteLine("Start Main in thread {0}", Thread.CurrentThread.ManagedThreadId);
            var p = new Program();
            p.MyAsyncMethod(null, null);
            Console.WriteLine("End Main in thread {0}", Thread.CurrentThread.ManagedThreadId);
            Console.ReadKey();
        }
    }


то строка
Код: c#
1.
Console.WriteLine("End MyAsyncMethod 

будет выполнена в потоке, который выполнял MyTask, т.е. отличном от того, в котором выполнялась строка
Код: c#
1.
Console.WriteLine("Start MyAsyncMethod

.
Почему так происходит?
...
Рейтинг: 0 / 0
25.02.2014, 17:26
    #38572010
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
up
...
Рейтинг: 0 / 0
25.02.2014, 17:30
    #38572024
Lelouch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
...
Рейтинг: 0 / 0
25.02.2014, 19:57
    #38572204
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Lelouch,

Суть в "По умолчанию используется текущий SynchronizationContext, т.е. если задача запущена из UI-потока, то продолжение будет тоже выполнено в UI потоке (по аналогии с Dispatcher.BeginInvoke). Если текущий sync-контекст пустой, то используется TaskScheduler.Current." ?
...
Рейтинг: 0 / 0
25.02.2014, 20:10
    #38572214
Lelouch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Lamo2012,

а где у вас в примере поток UI ?
...
Рейтинг: 0 / 0
25.02.2014, 20:18
    #38572218
Lelouch
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Lamo2012,

проверьте значение SynchronizationContext.Current . Что то мне подсказывает, что оно пустое. Поток, в котором выполняется метод Main не имеет контекста синхронизации.
...
Рейтинг: 0 / 0
25.02.2014, 20:30
    #38572226
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Lelouch,

Спасибо! Похоже дело именно в этом. Вот в этой статье вопрос планирования продолжений рассмотрен чуть более детально.
...
Рейтинг: 0 / 0
25.02.2014, 21:27
    #38572264
MsSql_Study
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Отвечая на вопрос Monochromatique из первого поста (будет полезно тем, кто потом случайно будет находить эту тему поиском), добавлю ссылки на эти 2 полезные статьи

http://blogs.msdn.com/b/pfxteam/archive/2009/06/09/9716439.aspx
http://msdn.microsoft.com/ru-ru/magazine/ff959203.aspx

В первой статье кратко, сжато (и сложно), а во второй полно, описан переход от старых моделей многопоточного программирования, к новой, с блэкджеком и Task'ами.

В частности рассмотрен метод Task.Factory.FromAsync позволяющий обернуть асинхронные Begin End в Task с последующем ожиданием в async.

Там еще много чего полезного.
...
Рейтинг: 0 / 0
28.02.2014, 00:59
    #38574849
Monochromatique
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
await,async и TASK - не получается.
Парни, а можно как-то незамороченно ловить исключения?

Каждую залипуху в других потоках надо специально ловить - код превращается черте-во-что.

Пока выяснил, почему не работает банальный LINQ2SQL - три блока пришлось расставить.
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / await,async и TASK - не получается. / 25 сообщений из 25, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]