AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 13.09.2010, 12:38   #1  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 868 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Вопросы про RunBase
1. Есть некий серверный обработчик, который вызывается из основного меню и из формы. Один из параметров - код документа, при вызове из формы должен заполниться автоматически.
Как правильно реализовать?

2. В Tutorial_RunbaseBatch метод construct серверный. Таким образом, настройка RunOn в менюитем не играет никакой роли. Это так было задумано и считается правильным или просто так получилось в данном случаи?
Старый 13.09.2010, 12:59   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Wamr Посмотреть сообщение
1. Есть некий серверный обработчик, который вызывается из основного меню и из формы. Один из параметров - код документа, при вызове из формы должен заполниться автоматически.
Как правильно реализовать?
юзать диналинк.
при вызове из меню DataSource - не заполнен.
при вызове из формы DataSource - должен быть заполнен.

чтобы юзать диналинк ничего программировать не нужно, нужно в menuitem формы указать свойство Source. Дальше Аксапта сама свяжет.

Цитата:
Сообщение от Wamr Посмотреть сообщение
2. В Tutorial_RunbaseBatch метод construct серверный. Таким образом, настройка RunOn в менюитем не играет никакой роли. Это так было задумано и считается правильным или просто так получилось в данном случаи?
Есть технический аспект, есть идеологический.

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

Поэтому, я воспринимаю слово server в методе, как настоятельный совет следовать идеологии. Но не догму
__________________
полезное на axForum, github, vk, coub.
За это сообщение автора поблагодарили: Wamr (1).
Старый 13.09.2010, 13:24   #3  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2494 (89) +++++++++
Регистрация: 20.08.2005
Цитата:
Сообщение от Wamr Посмотреть сообщение
1. Есть некий серверный обработчик, который вызывается из основного меню и из формы. Один из параметров - код документа, при вызове из формы должен заполниться автоматически.
Как правильно реализовать?
Передавать через Args в main().

Цитата:
Сообщение от Wamr Посмотреть сообщение
2. В Tutorial_RunbaseBatch метод construct серверный. Таким образом, настройка RunOn в менюитем не играет никакой роли. Это так было задумано и считается правильным или просто так получилось в данном случаи?
Так задумано.
Дело в том, что если для класса указать RunOn=Called from и создавать экземпляр на сервере, то при вызове Prompt() будет создаваться клиентская копия класса.
__________________
Axapta v.3.0 sp5 kr2
За это сообщение автора поблагодарили: Wamr (1).
Старый 13.09.2010, 13:39   #4  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от AndyD Посмотреть сообщение
Передавать через Args в main().
только стоит не программировать, а просто поставить свойство
__________________
полезное на axForum, github, vk, coub.
Старый 13.09.2010, 13:45   #5  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2494 (89) +++++++++
Регистрация: 20.08.2005
Цитата:
Сообщение от mazzy Посмотреть сообщение
только стоит не программировать, а просто поставить свойство
Это зависит от задачи.
В общем случае может не быть датасорса
__________________
Axapta v.3.0 sp5 kr2
Старый 13.09.2010, 13:53   #6  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 868 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Прошу прощения за формулировки вопросов.

1. имелся в виду "один из параметров, который выводится в диалог и пользователь может его сменить".
Я сомневаюсь, что dynalink в классах работает без программирования, а добавлять в диалог DS, чтобы с ним подвязался исходный курсор, как-то тоже "нелегкое" решение.
То что args в main принесет мне данные, я понимаю. Что дальше с ними делать? Пихать в объект через parm метод? А как к этому отнесется getLast при вызове диалога (известно как потрет нафиг)?

2. У меня было мнение, что при установке свойства класса CalledFrom и RunOn=Server на менюитем, получается диалог с пользователем на клиенте без лишнего общения с АОСом и исполнения функционала на сервере. Таким образом, мы можем управлять местом исполнения настройками менюитема. А сделав construct серверным, мы лишаемся такой возможности, не понятно что получив взамен.
Старый 13.09.2010, 13:58   #7  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от Wamr Посмотреть сообщение
Прошу прощения за формулировки вопросов.

1. имелся в виду "один из параметров, который выводится в диалог и пользователь может его сменить".
Я сомневаюсь, что dynalink в классах работает без программирования, а добавлять в диалог DS, чтобы с ним подвязался исходный курсор, как-то тоже "нелегкое" решение.
То что args в main принесет мне данные, я понимаю. Что дальше с ними делать? Пихать в объект через parm метод? А как к этому отнесется getLast при вызове диалога (известно как потрет нафиг)?
потрет. использую в таких случаях в main()
.getLast()
.parmXXX(...)
.saveLast()
За это сообщение автора поблагодарили: Wamr (3).
Старый 13.09.2010, 14:13   #8  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,342 / 3563 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Wamr Посмотреть сообщение
2. У меня было мнение, что при установке свойства класса CalledFrom и RunOn=Server на менюитем, получается диалог с пользователем на клиенте без лишнего общения с АОСом и исполнения функционала на сервере. Таким образом, мы можем управлять местом исполнения настройками менюитема. А сделав construct серверным, мы лишаемся такой возможности, не понятно что получив взамен.
Вообще-то - для кода один фиг - как он был вызван на сервере - при помощи установки свойства RunOn у менюитема, у класса или жестко зашит в construct.
С т.з. разработки - в целом тоже не сильно разнится - изменение свойства менюитема также относится к программированию, как и редактирование текста кода класса.

Разница лишь в том, что выставляя свойство RunOn=Server у менюитема - мы можем создать второй менюитем, не трогая класс, у которого поставить RunOn=Client.
В коде же (метод promptPrim) идет проверка - что если класс запущен на сервере и нет ограничений для создания копии себя на клиенте - то создается копия себя на клиенте. А если класс запущен изначально на клиенте - то копия класса не создается в принципе.
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 13.09.2010 в 14:15.
Старый 13.09.2010, 14:30   #9  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 868 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
Вообще-то - для кода один фиг - как он был вызван на сервере - при помощи установки свойства RunOn у менюитема, у класса или жестко зашит в construct.
...
В коде же (метод promptPrim) идет проверка - что если класс запущен на сервере и нет ограничений для создания копии себя на клиенте - то создается копия себя на клиенте. А если класс запущен изначально на клиенте - то копия класса не создается в принципе.
а теперь смотрим метод canSwapBetweenCSPrim
и видим, что копия делается только если класс CalledFrom
Старый 13.09.2010, 14:37   #10  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,342 / 3563 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Wamr Посмотреть сообщение
2. В Tutorial_RunbaseBatch метод construct серверный. Таким образом, настройка RunOn в менюитем не играет никакой роли. Это так было задумано и считается правильным или просто так получилось в данном случаи?
Цитата:
Сообщение от Wamr Посмотреть сообщение
а теперь смотрим метод canSwapBetweenCSPrim
и видим, что копия делается только если класс CalledFrom
Согласен. Но наличие серверного construct никак не связано с настройкой runOn у класса. Т.е. да, согласен - что создание копии на клиенте - связано со свойством RunOn у класса. Но с т.з. создании копии без разницы - что побудило ее создать - свойство RunOn у менюитема или серверный construct
__________________
Возможно сделать все. Вопрос времени
Старый 13.09.2010, 14:38   #11  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,342 / 3563 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от Wamr Посмотреть сообщение
Прошу прощения за формулировки вопросов.

1. имелся в виду "один из параметров, который выводится в диалог и пользователь может его сменить".
То что args в main принесет мне данные, я понимаю. Что дальше с ними делать? Пихать в объект через parm метод? А как к этому отнесется getLast при вызове диалога (известно как потрет нафиг)?
Цитата:
Сообщение от db Посмотреть сообщение
потрет. использую в таких случаях в main()
.getLast()
.parmXXX(...)
.saveLast()
Обычно я всегда задаюсь предварительно вопросом - а нужно ли мне этот параметр сохранять? Если параметр сохранять не нужно - то в методе unpack() на этот конкретный параметр можно поставить условие - если параметр пустой - то его "распаковывать", если нет - не "распаковывать". Хорошо подходит, если параметр - курсор. Плохо подходит - если параметр - енум или какое-то значение, которое может быть пустым вполне осознанно.
Если параметр сохранять нужно - то тогда вопрос - а что первичнее - сохраненное или заданное значение?
На самый крайний случай - можно делать совсем просто. Кто сказал, что наследник runBase должен быть серверным? Пусть он будет клиентским. А вот метод run можно запустить и на сервере.
X++:
static void main(Args _args)
{
     RunBaseClass runClass;
     RunBaseClass runClassServer;
     runClass = new RunBaseClass();
     if (runClass.prompt())
     {
           runClassServer = RunBase::makeObjectOnServer(classidget(runClass));
           runClassServer.unpack(runClass.pack());
           runClassServer.parmXXX(runClass.parmXXX());  // Или еще как-то проинициализировать параметры
           runClassServer.run();
     }
}
См. \Classes\SysDataExportExcel\export
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 14.09.2010 в 09:06. Причина: Очепяточка
За это сообщение автора поблагодарили: Wamr (3).
Старый 13.09.2010, 14:51   #12  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
Обычно я всегда задаюсь предварительно вопросом - а нужно ли мне этот параметр сохранять? Если параметр сохранять не нужно - то в методе unpack() на этот конкретный параметр можно поставить условие - если параметр пустой - то его "распаковывать", если нет - не "распаковывать". Хорошо подходит, если параметр - курсор. Плохо подходит - если параметр - енум или какое-то значение, которое может быть пустым вполне осознанно.
Если параметр сохранять нужно - то тогда вопрос - а что первичнее - сохраненное или заданное значение?
То ли я не понял что ты этим хотел сказать, то ли все не слишком просто как кажется
Что значит не сохранять? Класс может переходить с клиента на сервер и обратно. Класс можно запустить в пакетную обработку. И как оно будет жить все если что то там не полностью сохраняется?
Старый 13.09.2010, 15:08   #13  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,342 / 3563 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от db Посмотреть сообщение
То ли я не понял что ты этим хотел сказать, то ли все не слишком просто как кажется
Что значит не сохранять? Класс может переходить с клиента на сервер и обратно. Класс можно запустить в пакетную обработку. И как оно будет жить все если что то там не полностью сохраняется?
Не сохранять - означает - что вызов класса с использованием сохраненного значения параметра не планируется. Отказ от сохранения может быть реализован как отказ от загрузки, а не напрямую отказ от сохранения.
Класс сам по себе не переходит между сервером и клиентом. За это отвечает программист.
Кстати - заметь - я не отказываюсь от сохранения. Я корректирую загрузку.
В пакетную обработку класс может уходить. Дык это же никому не мешает.
__________________
Возможно сделать все. Вопрос времени
Старый 13.09.2010, 15:26   #14  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
Не сохранять - означает - что вызов класса с использованием сохраненного значения параметра не планируется. Отказ от сохранения может быть реализован как отказ от загрузки, а не напрямую отказ от сохранения.
Класс сам по себе не переходит между сервером и клиентом. За это отвечает программист.
Кстати - заметь - я не отказываюсь от сохранения. Я корректирую загрузку.
В пакетную обработку класс может уходить. Дык это же никому не мешает.
Либо я сильно туплю в понедельник, либо не могу понять - зачем все эти извращения если можно просто предусмотреть нормальную работу класса с пустым параметром. Которая к тому же не накладывает никаких доп ограничений на вызовы/пакетную обработку и т.д.

Енумы можно определять как пустые (если соответствующего значения нет) по значению 255. Завести где нито макрос/метод класса/глобальную функцию которая это будет возвращать и в нужных местах инициализировать/сравнивать. 255 не может быть у енума ни в каком случае (если не ошибаюсь, то последнее допустимое 250). Ну а присвоить в енум число ни что не запрещает. Это как раз к вопросу (видел тут некоторое время назад пост про нулевые значения на енумах и обязательность енумов в полях) что значения типа None в енумах все таки полезны

Последний раз редактировалось db; 13.09.2010 в 15:32.
Старый 13.09.2010, 15:32   #15  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
Цитата:
Сообщение от db Посмотреть сообщение
...
Енумы можно определять как пустые (если соответствующего значения нет) по цифре 255. Завести где нито макрос/метод класса/глобальную функцию которая это будет возвращать и в нужных местах инициализировать/сравнивать. 255 не может быть у енума ни в каком случае (если не ошибаюсь, то последнее допустимое 250). ...
эээ, а если в какой нибудь из следующих версий вдруг решат увеличить максимальное число элементов в enum-е и сделают например 300? тогда такая доработка сразу внесет много лишней работы при переходе на новую версию.
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 13.09.2010, 16:57   #16  
titov is offline
titov
Участник
 
73 / 87 (3) ++++
Регистрация: 23.12.2005
Адрес: Казань
Цитата:
Сообщение от db Посмотреть сообщение
Завести где нито макрос/метод класса/глобальную функцию которая это будет возвращать и в нужных местах инициализировать/сравнивать. 255 не может быть у енума
AOT\Macros\Axd - строка #define.axdUnknownEnumValue(255) - уже есть!
За это сообщение автора поблагодарили: db (1), sukhanchik (3).
Старый 13.09.2010, 15:15   #17  
db is offline
db
Роман Долгополов (RDOL)
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
 
393 / 692 (24) +++++++
Регистрация: 01.04.2004
Адрес: Москва
Цитата:
Сообщение от sukhanchik Посмотреть сообщение
Хорошо подходит, если параметр - курсор
А вот за параметры-курсоры в том виде как их обычно лабают надо вообще руки отрывать. Ибо просто суют некий курсор в класс через parm-метод, а потов run() как то его юзают/обновляют.
Мало того что за время с момента вызова диалога и до фактического запуска обработки данные в бд на которые указывает этот курсор могли поменяться ,так еще и юзер вызвав диалог на одной строчке чего либо может вернуться в форму (не закрывая диалога) ткнуть в другую строчку (по любой причине - ну мало ли что ему там приспичило посмотреть) и потом нажать ОК на диалоге. Обработка будет выполнена по другой строке со всеми вытекающими последствиями. А так как авторы подобных обработок обычно всю проверку возможности выполнения их операций вещают на enable() менюайтема то последствия бывают просто разрушительными

Это я к тому что (за исключением особо хитрых обработчиков где все вышеуказанное учетно и обдумано)
  • Сохранять надо не записи а их коды, которые пакуются (JournalId. SalesId, RecId в конце концов)
  • Строчки повторно искать внутри транзакции и проверять что они еще удовлетворяют условиям выполнения операции
За это сообщение автора поблагодарили: sukhanchik (3), ziva (1).
Старый 13.09.2010, 15:32   #18  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,342 / 3563 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от db Посмотреть сообщение
А вот за параметры-курсоры в том виде как их обычно лабают надо вообще руки отрывать. Ибо просто суют некий курсор в класс через parm-метод, а потов run() как то его юзают/обновляют.

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

Но если класс из кода вызывается и запись жестко выбрана в коде - то с такими ограничениями - код работать сможет корректно.
Кстати - также ж можно не только курсор передавать. Я курсор привел в качестве примера нескалярного типа данных. Это ж и экземпляр класса может быть. При желании.
__________________
Возможно сделать все. Вопрос времени
Старый 20.06.2011, 15:19   #19  
leva is offline
leva
Участник
 
52 / 36 (2) +++
Регистрация: 03.08.2005
В сто пятидесятый раз попал в туже ситуацию и решил разобраться в вопросе.
Итак, изначальная постановка Wamr была: как правильно реализовать серверный обработчик (плюс который нормально будет работать в пакете) с параметрами, изменяемыми в диалоге. Само собой этот параметр будет в списке тех, которые сохраняются в pack() и поэтому если мы этот параметр parm-методом зададим он перетрётся старым значением.

Есть предложение db писать в таких случаях в main():
.getLast()
.parmXXX(...)
.saveLast()

Я так тоже делал, но такой метод мне не нравится, так как во-первых, сохраняет уже сразу после вызова, даже если мы отменим выполнение в диалоге и во-вторых, если класс сделан с запросом на QueryRun (который сохраняется в pack()), то нужно уже на этом этапе как-то его инициализировать.

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

Собственно я предлагаю такой вариант:
1. В classDeclaration добавить макрос со списком параметров, которые будут меняться в диалоге, например:
X++:
    #localmacro.ParamsList
        param1,
        param2
    #endmacro
2. В unpack() сохранять эти значения в контейнер и в случае, если метод был вызван для загрузки старых значений (определяется методом this.inGetSaveLast()) восстанавливать их, например:
X++:
public boolean unpack(container packedClass)
{
    Version version     = runbase::getVersion(packedClass);
    container   params = [#ParamsList];

    switch (version)
    {
        case #CurrentVersion:
            [version,#CurrentList] = packedClass;
            if (this.inGetSaveLast())
                [#ParamsList] = params;
            break;
        default:
            return false;
    }

    return true;
}
Таким образом, при загрузке значений клиентской копией и при создании объекта пакетного задания (в этих случаях inGetSaveLast = false) загрузится всё из упакованного контейнера, а случае запуска из меню с определёнными параметрами эти параметры не перетрутся.
Единственное надо проверить, чтобы на всех версиях аксапты параметр inGetSaveLast вёл себя одинаково. Ну и в минусы можно записать то, что этот список нужно не забывать пополнять по мере доработки класса (версионность тут вроде не нужна).

Подводных камней вроде не вижу. Что скажете?
Старый 20.06.2011, 15:29   #20  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,983 / 3273 (117) ++++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
2 leva
А не проще написать свой конструктор, а в нем :
X++:
static construct()
{
    ret = New runBase_...child();
    ;
    ret.getLast();
    return ret;
}
а затем в main вместо New runBase_...child()
писать
runBase_...child::construct()

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

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Глюк RunBase (AX40sp2) Alexx7 DAX: Программирование 7 22.01.2010 10:59
Inside Dynamics AX 4.0: RunBase Framework Extension Part IV Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part III Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part I Blog bot DAX Blogs 0 30.09.2007 09:20
Некоторые вопросы внедрения приложений. Часть 2 Михаил Ковалев DAX: Прочие вопросы 0 27.05.2002 10:43

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 17:44.