MetaTrader 5 build 2005: Экономический календарь, MQL5-программы в виде сервисов и API для языка R

Полностью обновлен встроенный экономический календарь. Экономический календарь — наша собственная разработка

21 февраля 2019

Terminal

  1. Полностью обновлен встроенный экономический календарь.

    Экономический календарь — наша собственная разработка. В нем доступны более 600 показателей и индикаторов 13 крупнейших экономик мира: США, Евросоюза, Японии, Великобритании, Канады, Австралии, Китая и т.д. Все данные собираются в режиме реального времени из открытых источников.

    Помимо обновления содержимого, в календаре стали доступны расширенные фильтры событий: по времени, приоритету, валютам и странам.

    Также данные календаря теперь можно запрашивать из MQL5-программ. Более подробная информация об этом приведена ниже.




  2. Добавлен новый тип MQL5-программ — Сервисы. Они позволяют создавать собственные источники ценовых данных для терминала — передавать цены от внешних систем в режиме реального времени так, как это делают торговые серверы брокеров.

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

    Для управления сервисами в Навигатор добавлен отдельный подраздел:





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

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

    Выберите в навигаторе сервис и нажмите "Добавить сервис" в его контекстном меню. Будет открыт стандартный диалог MQL5-программы, где вы можете разрешить/запретить торговлю и доступ к сигналам, а также задать параметры.




    Для запуска и остановки экземпляра сервиса используйте его меню. Для управления всеми экземплярами, используйте меню самого сервиса.

  3. Добавлена система обучения.

    Теперь новички смогут легко научиться работать с платформой. Мы добавили более 100 интерактивных советов по ее основным функциям.

    • Советы не будут отвлекать от работы с платформой — они аккуратно встроены на панель инструментов в виде прогресс-бара.
    • Советы показываются только для действий, которые вы еще не выполняли в платформе.
    • В советы встроены интерактивные ссылки для перехода к определенным элементам интерфейса платформы. Например, прямо из совета можно открыть торговый диалог или меню с нужной командой.

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




  4. История торгового счета может быть представлена в виде позиций — платформа собирает данные по сделкам, относящимся к позиции (открытие, наращивание, частичное и полное закрытие), и группирует эти данные в единую запись. Это позволяет легко посмотреть время открытия и закрытия позиции, ее объем, цену и суммарный результат. Теперь это представление доступно и в отчетах по истории, экспортируемых в файлы.




  5. Добавлено API для запроса данных из терминала MetaTrader 5 через приложения, использующие язык R.

    Для работы мы подготовили специальный пакет MetaTrader. В нем содержатся DLL для взаимодействия между R и терминалом MetaTrader 5, документация и вспомогательные r-файлы. Сейчас пакет находится в процессе регистрации в репозитории CRAN, и в ближайшее время станет доступен для скачивания и установки.




    Для установки пакета используйте следующую команду:
    R CMD INSTALL --build MetaTrader

    На текущий момент для запроса данных доступны следующие команды:

    • MT5Initialize — инициализация и установка соединения с терминалом MetaTrader 5. При выполнении команды при необходимости происходит запуск терминала.
    • MT5Shutdown — деинициализация и разрыв соединения с терминалом MetaTrader 5.
    • MT5Version — получение версии терминала MetaTrader 5.
    • MT5TerminalInfo — получение состояния и параметров подключения терминала к серверу брокера (номер счета и адрес сервера).
    • MT5WaitTerminal — ожидание соединения терминала MetaTrader 5 с сервером брокера.
    • MT5CopyTicksFrom(symbol, from, count, flags) — копирование тиков с указанной даты в указанном количестве. Дата указывается в миллисекундах с 1970.01.01.
    • MT5CopyTicksRange(symbol, from, to, flags) — копирование тиков из указанного периода дат. Даты указываются в миллисекундах с 1970.01.01.
    • MT5CopyRatesFrom(symbol, timeframe, from, count) — копирование минутных баров с указанной даты в указанном количестве. Дата указывается в секундах с 1970.01.01.
    • MT5CopyRatesFromPos(symbol, timeframe, start_pos, count) — копирование минутных баров с указанной позиции от последнего бара.
    • MT5CopyRatesFromRange(symbol, timeframe, date_from, date_to) — копирование баров из указанного периода дат. Даты указываются в секундах с 1970.01.01.

    В будущем список поддерживаемых команд будет расширен.

  6. Оптимизирован диалог закрытия торговой позиции встречной. Теперь его работа не замедляется при большом количестве открытых позиций.
  7. Исправлены ошибки расчета синтетических инструментов, приводившие к образованию пропусков данных.
  8. Теперь при удалении пользовательского инструмента удаляются файлы с его тиковой и баровой историей. Это позволяет избежать накапливания неиспользуемых данных на жестком диске.
  9. Исправлено отображение результатов поиска на мониторах High DPI.

MQL5

  1. Добавлен доступ к данным экономического календаря через MQL5-программы.

    Новые функции

    CalendarCountryById — получение описания страны по идентификатору.
    bool CalendarCountryById(
       const long           country_id,    // идентификатор страны
       MqlCalendarCountry&  country        // описание страны
       );
    CalendarEventById — получение описания события по идентификатору.
    bool CalendarEventById(
       const long           event_id,      // идентификатор события
       MqlCalendarEvent&    event          // описание события
       );
    CalendarValueById — получение описания значения события по идентификатору.
    bool CalendarValueById(
       const long           value_id,      // идентификатор значения
       MqlCalendarValue&    value          // описание значения
       );
    CalendarEventByCountry — получение массива доступных новостей по стране.
    bool CalendarEventByCountry(
       string               country_code,  // код страны
       MqlCalendarEvent&    events[]       // массив событий
       );
    CalendarEventByCurrency — получение массива доступных новостей по валюте, на которую они влияют.
    bool CalendarEventByCurrency(
       string               currency,      // валюта
       MqlCalendarEvent&    events[]       // массив событий
       );
    CalendarValueHistoryByEvent — получение массива значений за указанный период времени по идентификатору события.
    bool CalendarValueHistoryByEvent(
       ulong                event_id,      // идентификатор события
       MqlCalendarValue&    values[],      // массив значений
       datetime             datetime_from, // начальная дата
       datetime             datetime_to=0  // конечная дата
       );
    CalendarValueHistory — получение массива значений по всем событиям за заданный период времени с фильтрацией по стране и/или валюте.
    bool CalendarValueHistory(
       MqlCalendarValue&    values[],          // массив значений
       datetime             datetime_from,     // начало периода
       datetime             datetime_to=0,     // конец периода
       string               country_code=NULL, // код страны
       string               currency=NULL      // валюта
       );
    CalendarValueLastByEvent — получение массива последних значений события по идентификатору. Эта функция позволяет запрашивать только те значения, которые изменились с момента последнего запроса. Для этого используется ее in/out параметр "change_id".

    При каждом изменении базы данных календаря у него обновляется свойство "change_id" — идентификатор последнего изменения. При запросе данных вы указываете "change_id" и терминал возвращает вам события, появившиеся в календаре, начиная с этого момента, а также текущее значение "change_id", которое можно использовать для следующего запроса. При первом вызове функции укажите нулевой "change_id", функция при этом не вернет никаких событий, но передаст вам текущий "change_id" для последующих запросов.
    bool CalendarValueHistory(
       ulong                event_id,          // идентификатор события
       ulong&               change_id,         // идентификатор последнего изменения календаря
       MqlCalendarValue&    values[]           // массив значений
       );
    CalendarValueLast — получение массива последних значений по всем событиям с фильтрацией по стране и/или валюте. Эта функция позволяет запрашивать только те значения, которые изменились с момента последнего запроса. Аналогично CalendarValueLastByEvent, для запроса используется свойство "change_id".
    bool CalendarValueHistory(
       ulong                event_id,          // идентификатор события
       ulong&               change_id,         // идентификатор последнего изменения календаря
       MqlCalendarValue&    values[],          // массив значений
       string               country_code=NULL, // код страны
       string currency=NULL                    // валюта
       );

    Новые структуры

    MqlCalendarCountry — описание страны.
    struct MqlCalendarCountry
      {
       ulong             id;                        // идентификатор страны ISO 3166-1
       string            name;                      // текстовое название страны
       string            code;                      // кодовое имя страны ISO 3166-1 alpha-2
       string            currency;                  // код валюты страны
       string            currency_symbol;           // символ/знак валюты страны
       string            url_name;                  // имя страны, используемое в URL на сайте mql5.com
      };
    MqlCalendarEvent — описание события.
    struct MqlCalendarEvent
      {
       ulong                          id;           // идентификатор события
       ENUM_CALENDAR_EVENT_TYPE       type;         // тип события
       ENUM_CALENDAR_EVENT_SECTOR     sector;       // сектор, к которому относится событие
       ENUM_CALENDAR_EVENT_FREQUENCY  frequency;    // периодичность публикации события
       ENUM_CALENDAR_EVENT_TIMEMODE   time_mode;    // режим публикции события по времени
       ulong                          country_id;   // идентификатор страны
       ENUM_CALENDAR_EVENT_UNIT       unit;         // единица измерения значения события
       ENUM_CALENDAR_EVENT_IMPORTANCE importance;   // важность события
       ENUM_CALENDAR_EVENT_MULTIPLIER multiplier;   // множитель значения события
       uint                           digits;       // количество знаков после запятой в значении события
       string                         source_url;   // URL источника
       string                         event_code;   // код события
       string                         name;         // текстовое имя события на языке терминала
      };
    MqlCalendarValue — описание значения события.
    struct MqlCalendarValue
      {
       ulong             id;                        // идентификатор значения
       ulong             event_id;                  // идентификатор события
       datetime          time;                      // время и дата события
       datetime          period;                    // отчетный период события
       int               revision;                  // ревизия публикуемого индикатора по отношению к отчетному периоду
       long              actual_value;              // актуальное значение события
       long              prev_value;                // предыдущее значение события
       long              revised_prev_value;        // пересмотренное предыдущее значение события
       long              forecast_value;            // прогнозное значение события
       ENUM_CALENDAR_EVENT_IMPACRT impact_type;     // потенциальное влияние на курс валюты
      };

    Новые перечисления

    enum ENUM_CALENDAR_EVENT_FREQUENCY
      {
       CALENDAR_FREQUENCY_NONE            =0,   // не используется
       CALENDAR_FREQUENCY_WEEK            =1,   // неделя
       CALENDAR_FREQUENCY_MONTH           =2,   // месяц
       CALENDAR_FREQUENCY_QUARTER         =3,   // квартал
       CALENDAR_FREQUENCY_YEAR            =4,   // год
       CALENDAR_FREQUENCY_DAY             =5,   // день
      };
    
    enum ENUM_CALENDAR_EVENT_TYPE
      {
       CALENDAR_TYPE_EVENT                =0,   // событие(митинг, речь и т.д.)
       CALENDAR_TYPE_INDICATOR            =1,   // индикатор
       CALENDAR_TYPE_HOLIDAY              =2,   // праздник
      };
    
    enum ENUM_CALENDAR_EVENT_SECTOR
      {
       CALENDAR_SECTOR_NONE               =0,   // нет
       CALENDAR_SECTOR_MARKET             =1,   // рынок
       CALENDAR_SECTOR_GDP                =2,   // GDP
       CALENDAR_SECTOR_JOBS               =3,   // труд
       CALENDAR_SECTOR_PRICES             =4,   // цены
       CALENDAR_SECTOR_MONEY              =5,   // деньги
       CALENDAR_SECTOR_TRADE              =6,   // торговля
       CALENDAR_SECTOR_GOVERNMENT         =7,   // правительство
       CALENDAR_SECTOR_BUSINESS           =8,   // бизнес
       CALENDAR_SECTOR_CONSUMER           =9,   // потребитель
       CALENDAR_SECTOR_HOUSING            =10,  // жилье
       CALENDAR_SECTOR_TAXES              =11,  // налоги
       CALENDAR_SECTOR_HOLIDAYS           =12,  // праздники
      };
      
    enum ENUM_CALENDAR_EVENT_IMPORTANCE
      {
       CALENDAR_IMPORTANCE_NONE           =0,   // нет
       CALENDAR_IMPORTANCE_LOW            =1,   // низкая
       CALENDAR_IMPORTANCE_MODERATE       =2,   // средняя
       CALENDAR_IMPORTANCE_HIGH           =3,   // высокая
      };
    
    enum ENUM_CALENDAR_EVENT_UNIT
      {
       CALENDAR_UNIT_NONE                 =0,   // нет
       CALENDAR_UNIT_PERCENT              =1,   // проценты
       CALENDAR_UNIT_CURRENCY             =2,   // национальная валюта
       CALENDAR_UNIT_HOUR                 =3,   // количество часов
       CALENDAR_UNIT_JOB                  =4,   // количество рабочих мест
       CALENDAR_UNIT_RIG                  =5,   // количество вышек
       CALENDAR_UNIT_USD                  =6,   // доллары США
       CALENDAR_UNIT_PEOPLE               =7,   // число людей
       CALENDAR_UNIT_MORTGAGE             =8,   // количество ипотечных кредитов
       CALENDAR_UNIT_VOTE                 =9,   // число голосов
       CALENDAR_UNIT_BARREL               =10,  // количество баррелей
       CALENDAR_UNIT_CUBICFEET            =11,  // объем в кубических футах
       CALENDAR_UNIT_POSITION             =12,  // количество рабочих мест
       CALENDAR_UNIT_BUILDING             =13   // количество строений
      };
      
    enum ENUM_CALENDAR_EVENT_MULTIPLIER
      {
       CALENDAR_MULTIPLIER_NONE           =0,   // нет    
       CALENDAR_MULTIPLIER_THOUSANDS      =1,   // тысячи
       CALENDAR_MULTIPLIER_MILLIONS       =2,   // миллионы
       CALENDAR_MULTIPLIER_BILLIONS       =3,   // миллиарды
       CALENDAR_MULTIPLIER_TRILLIONS      =4,   // триллионы
      };
      
    enum ENUM_CALENDAR_EVENT_IMPACRT
      {
       CALENDAR_IMPACT_NA                 =0,   // неизвестно
       CALENDAR_IMPACT_POSITIVE           =1,   // положительное
       CALENDAR_IMPACT_NEGATIVE           =2,   // отрицательное
      };
    
    enum ENUM_CALENDAR_EVENT_TIMEMODE
      {
       CALENDAR_TIMEMODE_DATETIME         =0,   // источник публикует точное время
       CALENDAR_TIMEMODE_DATE             =1,   // событие занимает весь день
       CALENDAR_TIMEMODE_NOTIME           =2,   // источник не публикует время по событию
       CALENDAR_TIMEMODE_TENTATIVE        =3,   // источник не публикует заранее точного времени события, только день, время уточняется по факту наступления события
      };

    Новые коды ошибок

    ERR_CALENDAR_MORE_DATA             =5400,   // массив мал для всего результата (отданы значения, которые поместились в массив)
    ERR_CALENDAR_TIMEOUT               =5401,   // превышен таймаут ожидания ответа на запрос данных из календаря
    ERR_CALENDAR_NO_DATA               =5402,   // данные не обнаружены

  2. Исправлена и значительно ускорена работа с тиковой и баровой историей.
  3. Исправлены и значительно ускорены функции изменения тиковой и баровой истории у пользовательских торговых инструментов CustomTicks* и CustomRates*.
  4. Добавлены новые функции преобразования данных.

    CharArrayToStruct — копирует массив типа uchar в POD-структуру.
    bool  CharArrayToStruct(
       void&         struct_object,    // структура
       const uchar&  char_array[],     // массив
       uint          start_pos=0       // начальная позиция в массиве
       );
    StructToCharArray — копирует POD-структуру в массив типа uchar.
    bool  StructToCharArray(
       const void&  struct_object,     // структура
       uchar&       char_array[],      // массив
       uint         start_pos=0        // начальная позиция в массиве
       );

  5. Добавлена функция MathSwap для смены порядка байт в значении ushort, uint и ulong.
    ushort MathSwap(ushort value);
    uint   MathSwap(uint   value);
    ulong  MathSwap(ulong  value);

  6. Добавлены сетевые функции для создания TCP-соединений с удаленными хостами через системные сокеты:

    • SocketCreate — создает сокет с указанными флагами и возвращает его хэндл
    • SocketClose — закрывает сокет
    • SocketConnect — выполняет подключение к серверу с контролем таймаута
    • SocketIsConnected — проверяет, подключен ли сокет в текущий момент времени
    • SocketIsReadable — получает количество байт, которое можно прочитать из сокета
    • SocketIsWritable — проверяет, возможна ли запись данных в сокет в текущий момент времени
    • SocketTimeouts — устанавливает таймауты получения и отправки данных для системного объекта сокета
    • SocketRead — читает данные из сокета
    • SocketSend — записывает данные в сокете
    • SocketTlsHandshake — инициирует защищенное TLS (SSL)-соединение с указанным хостом по протоколу TLS Handshake
    • SocketTlsCertificate — получает данные о сертификате, используемом для защиты сетевого соединения
    • SocketTlsRead — читает данные из защищенного TLS-соединения
    • SocketTlsReadAvailable — читает все доступные данные из защищенного TLS-соединения
    • SocketTlsSend — отправляет данные через защищенное TLS-соединение

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

    Для работы с сетевыми функциями добавлены новые коды ошибок:

    • ERR_NETSOCKET_INVALIDHANDLE (5270) — в функцию передан неверный хэндл сокета
    • ERR_NETSOCKET_TOO_MANY_OPENED (5271) — открыто слишком много сокетов (максимум 128)
    • ERR_NETSOCKET_CANNOT_CONNECT (5272) — ошибка соединения с удаленным хостом
    • ERR_NETSOCKET_IO_ERROR (5273) — ошибка отправки/получения данных из сокета
    • ERR_NETSOCKET_HANDSHAKE_FAILED (5274) — ошибка установления защищенного соединения (TLS Handshake)
    • ERR_NETSOCKET_NO_CERTIFICATE (5275) — отсутствуют данные о сертификате, которым защищено подключение

  7. Добавлены новые функции для работы со строками:

    StringReserve — резервирует в памяти для строки буфер указанного размера.
    bool  StringReserve(
       string&        string_var,          // строка
       uint           new_capacity         // размер буфера для хранения строки
       );
    StringSetLength — устанавливает для строки указанную длину в символах.
    bool  StringSetLength(
       string&        string_var,          // строка
       uint           new_length           // новая длина строки
       );

  8. Добавлены новые функции для работы с массивами:

    ArrayRemove — удаляет из массива указанное число элементов, начиная с указанного индекса.
    bool  ArrayRemove(
       void&         array[],              // массив любого типа
       uint          start,                // с какого индекса начинаем удалять
       uint          count=WHOLE_ARRAY     // количество элементов
       );
    ArrayInsert — вставляет в массив-приемник из массива-источника указанное число элементов, начиная с указанного индекса.
    bool  ArrayInsert(
       void&         dst_array[],          // массив-приемник
       const void&   src_array[],          // массив источник
       uint          dst_start,            // индекс в массиве-приемнике для вставки
       uint          src_start=0,          // индекс в массиве-источнике для копирования
       uint          count=WHOLE_ARRAY     // количество вставляемых элементов
       );
    ArrayReverse — разворачивает в массиве указанное число элементов, начиная с указанного индекса.
    bool  ArrayReverse(
       void&         array[],              // массив любого типа
       uint          start=0,              // с какого индекса начинаем переворачивать массив
       uint          count=WHOLE_ARRAY     // количество элементов
       );

  9. В функции CustomRatesUpdate, CustomRatesReplace, CustomTicksAdd и CustomTicksReplace добавлен параметр "uint count" для указания количества элементов передаваемого массива, которые будут использованы. По умолчанию для параметра используется значение WHOLE_ARRAY. Оно означает, что будет использован весь массив.
  10. Добавлена функция CustomBookAdd — передает состояние стакана цен по пользовательскому инструменту. Функция позволяет транслировать стакан цен так, как если бы он приходил от сервера брокера.
    int  CustomBookAdd(
       const string        symbol,            // имя символа
       const MqlBookInfo&  books[]            // массив с описаниями элементов стакана цен
       uint                count=WHOLE_ARRAY  // количество элементов, которые будут использованы
       );
  11. Добавлена перегрузка функции CustomSymbolCreate, позволяющая создать пользовательский торговый инструмент на основе уже имеющегося. После создания любое свойство символа можно поменять на нужное значение соответствующими функциями.
    bool  CustomSymbolCreate(
       const string        symbol_name,       // имя пользовательского символа
       const string        symbol_path="",    // название группы, в которой будет создан символ
       const string        symbol_origin=NULL // имя символа, на основе которого будет создан пользовательский символ
       );
    Имя символа, из которого будут скопированы свойства создаваемого пользовательского символа, указывается в параметре "symbol_origin".

  12. Обновлена функция StringToTime, преобразующая строку с датой/временем в значение типа datetime. Теперь она поддерживает следующие форматы дат:

    • yyyy.mm.dd [hh:mi]
    • yyyy.mm.dd [hh:mi:ss]
    • yyyymmdd [hh:mi:ss]
    • yyyymmdd [hhmiss]
    • yyyy/mm/dd [hh:mi:ss]
    • yyyy-mm-dd [hh:mi:ss]

  13. В перечисление ENUM_TERMINAL_INFO_INTEGER добавлено свойство TERMINAL_VPS — признак того, что терминал запущен на виртуальном сервере MetaTrader Virtual Hosting (MetaTrader VPS). Если программа запущена на хостинге, вы можете отключать все ее визуальные функции, поскольку на виртуальном сервере отсутствует графический пользовательский интерфейс.
  14. В перечисление ENUM_SYMBOL_INFO_INTEGER добавлено новое свойство SYMBOL_EXIST — признак того, что символ с таким именем существует.
  15. Исправлена типизация при использовании предварительного объявления шаблонной функции.
  16. Добавлена переинициализация индикаторов при смене торгового счета.
  17. Оптимизирована работа функции StringSplit.
  18. Исправлены ошибки в стандартной библиотеке.

Tester

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

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

  2. Отключена возможность тестирования и оптимизации экспертов через MQL5 Cloud Network в режиме использования реальных тиков. Такой режим можно использовать только на локальных агентах и фермах в локальной сети.
  3. Улучшена работа с индикаторами при визуальном тестировании. Теперь ценовой график и индикаторные линии отрисовываются синхронно даже при максимальной скорости визуализации.
  4. Оптимизированы и значительно ускорены тестирование и оптимизация.
  5. Исправлена отладка индикаторов на исторических данных. Теперь функции OnInit и OnDeinit индикаторов можно отлаживать корректно.
  6. Ускорен доступ к историческим данным при тестировании мультивалютных экспертов.
  7. Исправлены ошибки, приводящие к зависанию визуального тестера при отладке на исторических данных.
  8. Ускорен запуск проходов оптимизации при обработке агентом пакета заданий.
  9. Изменена политика раздачи пакетов заданий агентам тестирования. Размер пакета был увеличен, что привело к значительному снижению накладных расходов на сетевые операции.
  10. Изменено поведение опции использования локальных, сетевых и облачных агентов. Теперь при отключении этих опций уже выданные задания обрабатываются до конца, а новые перестают выдаваться. Ранее эти опции работали аналогично команде "Отключить", которая останавливала работу агентов сразу.




MetaEditor

  1. Добавлена поддержка не-ANSI символов в отладчике. Теперь наблюдаемые выражения отображаются корректно, даже если имя переменной указано кириллицей.
  2. Исправлено отображение результатов поиска на мониторах High DPI.

Добавлен перевод пользовательского интерфейса на Хорватский язык.

Обновлена документация.