Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Названия цветов 10 страница




default: Alert("Задан неправильный номер");// С case не совпало

} // Конец тела switch

//--------------------------------------------------------------------

return; // Оператор выхода из start()

}

//--------------------------------------------------------------------

В операторе switch будет производиться перебор вариантов case до тех пор, пока не обнаружится равенство Выражения и Константы. Когда значение Выражения (здесь - это целое число 3) совпадает с одной из Констант (в данном случае - case 3), то исполнятся все операторы, которые следуют за двоеточием (case 3:), а именно: оператор вызова функции Alert("Бар 3"), следующие за ним Alert("Бар 4"), Alert("Бар 5") и т.д., пока не встретится оператор break, завершающий работу оператора switch.

В случае если значение Выражения не совпадает ни с одной из Констант, управление передаётся оператору, соответствующую варианту default:


Рис. 50. Функциональная схема оператора switch в скрипте barnumber.mq4.

В отличие от алгоритма, реализованного в предыдущей программе, в данном случае (рис. 50) в каждом варианте case не используется оператор break. Поэтому при совпадении значения Выражения со значением одной из Констант будут исполнены все операторы, начиная с операторов соответствующего варианта case. Использование оператора break в последнем варианте case имеет другую цель - не допустить исполнение операторов, соответствующих варианту default. Если же среди значений Констант не найдётся ни одной, равной Выражению, то управление будет передано оператору, соответствующему метке default.

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

Обратите внимание, Константы вариантов case не обязательно должны быть указаны в программе в порядке возрастания. Порядок следования вариантов case с соответствующими Константами определяется необходимостью программного алгоритма.

Вызов функции

 

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

Формат вызова функции

 

Вызов функции состоит из названия функции и списка передаваемых параметров, обрамлённого круглыми скобками:

Название_функции ( Список_параметров ) // Собственно вызов функции

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

My_function (Alf, Bet) // Пример вызова функции

// Здесь:

My_function // Название вызываемой функции

Alf // Первый передаваемый параметр

Bet // Второй передаваемый параметр

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

My_function () // Пример вызова функции

// Здесь:

My_function // Название вызываемой функции

// Передаваемые параметры отсутствуют

При вызове функции, имеющей умолчательные параметры, список передаваемых параметров может быть ограничен (указан не полностью). Список параметров можно ограничить начиная с первого умолчательного параметра. В данном примере локальные переменные b, c и d имеют умолчательные значения.

// Для функции с описанием:

int My_function (int a, bool b=true, int c=1, double d=0.5)

{

Операторы

}

//.. допустимы следующие вызовы:

My_function (Alf, Bet, Ham, Del) // Допустимый вызов функции

My_function (Alf) // Допустимый вызов функции

My_function (3) // Допустимый вызов функции

My_function (Alf, 0) // Допустимый вызов функции

My_function (3, Tet) // Допустимый вызов функции

My_function (17, Bet, 3) // Допустимый вызов функции

My_function (17, Bet, 3, 0.5) // Допустимый вызов функции

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

// Для функции с описанием:
int My_function (int a, bool b=true, int c=1, double d=0.5)
{
Операторы
}
//..следующие вызовы являются ошибочными:
My_function () // Недопустимый вызов функции: неумолчательные..
//..параметры опускать нельзя (первый)
My_function (17, Bet,, 0.5) // Недопустимый вызов функции: пропущен..
//..умолчательный параметр (третий)

 

Вызываемые функции делятся на две группы: возвращающие некоторое значение заранее определённого типа и не возвращающие никакого значения.

Формат вызова функции, не возвращающей значение

 

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

Название_функции ( Список_параметров ); // Оператор вызова функции,не возвращающей знач

Func_no_ret (Alfa, Betta, Gamma); // Пример оператора вызова функции,..
//.. не возвращающей значение

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

Формат вызова функции, возвращающей значение

 

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

В случае оформления в виде отдельного оператора вызов функции заканчивается знаком; (точка с запятой):

Название_функции ( Список_параметров ); // Оператор вызова функции, возвращающей знач

Func_yes_ret (Alfa, Betta, Delta); // Пример оператора вызова функции,..
//.. возвращающей значение

Правила исполнения вызова функции

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

Использование вызова функции в составе других операторов определяется форматом этих операторов.

Задача 20. Составить программу, в которой реализуются следующие условия: - если текущее время больше 15:00, то выполнить 10 итераций в цикле for;- в остальных случаях выполнить 6 итераций.

Ниже приведен пример скрипта callfunction.mq4, в котором используются: вызов функции в заголовке оператора for (в составе Выражения_1, согласно формату оператора for, см. Оператор цикла for), вызов стандартной функции в виде отдельного оператора, в правой части оператора присваивания (см. Оператор присваивания) и в заголовке оператора if-else (в Условии, согласно формату оператора if-else, см. Условный оператор if-else).

///--------------------------------------------------------------------

// callfunction.mq4

// Предназначен для использования в качестве примера в учебнике MQL4.

//--------------------------------------------------------------------

int start() // Описание функции start()

{ // Начало тела ф-ии start()

int n; // Объявление переменной

int T=15; // Заданное время

for(int i=Func_yes_ret(T);i<=10;i++) // Использование функции в..

//.заголовке оператора цикла

{ // Начало тела цикла for

n=n+1; // Счётчик итераций

Alert ("Итерация n=",n," i=",i); // Оператор вызова функции

} // Конец тела цикла for

return; // Выход из функции start()

} // Конец тела ф-ии start()

//--------------------------------------------------------------------

int Func_yes_ret (int Times_in) // Описание пользоват. ф-ии

{ // Начало тела польз. ф-ии

datetime T_cur=TimeCurrent(); // Использование функции в..

//..операторе присваивания

if(TimeHour(T_cur) > Times_in) // Использование функции в..

//..заголовке операт.if-else

return(1); // Возврат значения 1

return(5); // Возврат значения 5

} // Конец тела пользов. ф-ии

//--------------------------------------------------------------------

В приведенном примере использованы вызовы следующих функций с такими передаваемыми параметрами:

в вызове функции Func_yes_ret(T) - переменная T;

в вызове функции Alert () - строковые константы "Итерация n=" и " i=", переменные n и i;

вызов функции TimeCurrent() не предусматривает передаваемых параметров;

в вызове функции TimeHour(T_cur) - переменная T_cur.

В программе реализован очень простой алгоритм. В переменной Т задаётся время в часах, относительно которого производятся вычисления. В заголовке оператора for указан вызов пользовательской функции Func_yes_ret(), которая может возвращать одно из двух значений: 1 или 5. В зависимости от этого значения изменяется количество итераций в цикле: либо их будет 10 (i изменяется от 1 до 10), либо 6 (i изменяется от 5 до 10). Для наглядности в теле цикла используется счётчик итераций, каждое значение которого выводится на экран с помощью функции Alert().

В описании пользовательской функции сначала вычисляется время в секундах, прошедших после 00:00 1 января 1970 года (обращение к функции TimeCurrent()), а затем текущее время в часах (обращение к функции TimeHour()). Разветвление алгоритма осуществляется с помощью оператора if (вызов функции TimeHour() указан в его условии). Если текущее время оказывается больше, чем переданное в пользовательскую функцию (локальная переменная Times_in), то пользовательская функция возвращает 1, иначе - возвращает 5.

Обратите внимание:

В программе нет описаний стандартных функций и вызова специальной функции start().

Ниже показана функциональная схема скрипта callfunction.mq4:

 


Рис. 51. Функциональная схема программы, использующей обращение к функциям.

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

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

Описание функции и оператор return

 

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

Формат описания функции

 

Описание функции состоит из двух основных частей - заголовка функции и тела функции.

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

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

Тип_возвращаемого_значения Название_функции ( Список формальных параметров ) //Заголовок
{ // Открывающая фигурная скобка
Программный код, // Тело функции может состоять..
составляющий тело //.. из операторов и..
функции //.. обращений к другим функциям
} // Закрывающая фигурная скобка

Список параметров указывается через запятую. Количество параметров, передаваемых в функцию, ограничено и не может превышать 64. В качестве формальных параметров в заголовке функции могут быть указаны только переменные (но не константы, вызовы других функций или выражения). Количество, тип и порядок упоминания передаваемых параметров в вызове функции должны совпадать с количеством, типом и порядком упоминания формальных параметров, указанных в описании функции (исключение составляет вызов функции, имеющей параметры со значением по умолчанию):

int My_function (int a, double b) // Пример описания функции

{

int c = a * b + 3; // Оператор тела функции

return (c); // Оператор выхода из функции

}

// Здесь (слева направо в заголовке):

int // Тип возвращаемого значения

My_function // Название функции

int a // Первый формальный параметр а целого типа

double b // Второй формальный параметр b дествит. типа

Параметры, передаваемые в функцию, могут иметь значения по умолчанию, которые задаются константами соответствующего типа:

int My_function (int a, bool b=true, int c=1, double d=0.5)//Пример описания функции

{

a = a + b*c + d2; // Оператор тела функции

int k = a * 3; // Оператор тела функции

return (k); // Оператор выхода из функции

}

// Здесь (слева направо в заголовке):

int // Тип возвращаемого значения

My_function // Название функции

int a // Первый формальный параметр а целого типа

bool b // Второй формальный параметр b логическ.типа

true // Константа - умолчательное значение для b

int c // Третий формальный параметр c целого типа

1 // Константа - умолчательное значение для c

double d // Четвёрт. формальный параметр d действ.типа

0.5 // Константа - умолчательное значение для d

 

a,b,c,d,k // Локальные переменные

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

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

Правила исполнения функции

 

Место в программе для описания функции:

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

Исполнение функции:

Вызванная для исполнения функция исполняется в соответствии с кодом, составляющим тело функции.

 

Формат оператора return

 

Возвращаемое функцией значение - это значение параметра, указанного в скобках оператора return. Оператор return состоит из ключевого слова return, Выражения, обрамлённого круглыми скобками, и заканчивается знаком; (точка с запятой). Полноформатный оператор return:

return ( Выражение ); // Оператор return

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

Правило исполнения оператора return

 

Оператор return прекращает исполнение ближайшей внешней функции и передаёт управление в вызывающую программу в соответствии с правилами, определёнными для вызова функции. Значением, возвращаемым функцией, является значение выражения, указанного в операторе return. Если тип значения параметра, указанного в операторе return, не совпадает с типом возвращаемого значения, указанным в заголовке функции, то значение приводится к типу возвращаемого значения, указанному в заголовке.

Пример использования оператора return, возвращающего значение:

bool My_function (int Alpha) // Описание пользовательской функции

{ // Начало тела функции

if(Alpha>0) // Оператор if

{ // Начало тела оператора if

Alert("Значение положительно"); // Вызов стандартной функции

return (true); // Первый выход из функции

} // Конец тела оператора if

return (false); // Второй выход из функции

} // Конец тела функции

В функциях с типом возвращаемого значения void необходимо использовать оператор return без выражения:

return; // Оператор return без выражения в круглых скобках

Пример использования оператора return без возврата значения:

void My_function (double Price_Sell) // Описание пользовательской функции

{ // Начало тела функции

if(Price_Sell-Ask >100) // Оператор if

Alert("Прибыль по ордеру более 100 п");// Вызов стандартной функции

return; // Выход из функции

} // Конец тела функции

В описании функции допускается отсутствие оператора return. В этом случае функция автоматически завершает работу, если (в соответствии с исполняемым алгоритмом) в теле функции исполнился последний оператор. Пример описания функции, в которой не указан оператор return:

void My_function (int Alpha) // Описание пользовательской функции

{ // Начало тела функции

for (int i=1; i<=Alpha; i++) // Оператор цикла

{ // Начало тела цикла

int a = 2*i + 3; // Оператор присваивания

Alert ("a=", a); // Оператор вызова станд. функции

} // Конец тела цикла

} // Конец тела функции

В данном случае функция завершит работу в момент окончания исполнения оператора цикла for. Последним движением при исполнении функции будет проверка условия в операторе цикла. Как только Условие в заголовке оператора цикла for станет ложным, управление будет передано за пределы оператора цикла. Но в связи с тем, что оператор цикла является последним исполняемым оператором в теле функции My_function (), пользовательская функция завершит работу, а управление будет передано за пределы функции, именно в то место, откуда функция была вызвана на исполнение.

Переменные

 

 

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

Предопределённые переменные и функция RefreshRates.
В первую очередь необходимо познакомиться с предопределенными переменными. Имена предопределенных переменных зарезервированы и не могут использоваться пользователем для создания своих переменных. Именно предопределенные переменные несут основную информацию, необходимую для анализа текущей рыночной ситуации. Для обновления этой информации используется функция RefreshRates().

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

Переменные GlobalVariable.
Кроме глобальных переменных на уровне отдельно взятой программы, значения которых доступны из любого места этой программы, существуют глобальные переменные на уровне терминала. Эти глобальные переменные называются GlobalVariables и позволют наладить взаимодествия между независимыми программи на языке MQL4. С их помощью можно передавать значения между скриптами, индикаторами и советниками. При выключении терминала значения GlobalVariables также сохраняются, чтобы быть доступными при новом запуске MetaTrader 4. Необходимо помнить, что если к глобальной переменной не было обращения в течение 4 недель, то она уничтожается.

Массивы.
Если Вам необходимо хранить или обрабатывать большие объемы значений одного типа, то тут без массивов не обойтись. Прежде чем использовать массив, его, как и переменную, необходимо объявить. Обращения к элементам массива происходит через указание индекса(ов) элемента, при этом индексация массивов начинается с нуля. Количество измерений массива называется его размерностью. Допускаются не более чем четрырехмерные массивы. Всегда явно инициализируйте значения массивов, чтобы не делать ошибок, которые потом очень трудно обнаружить.

Предопределённые переменные и функция RefreshRates

 

В языке MQL4 существуют переменные с предопределёнными именами.

Предопределённая переменная - это переменная с предопределённым названием, значение которой определяется клиентским терминалом и не может быть изменено программным способом. Предопределённые переменные отражают состояние текущего ценового графика на момент запуска программы (эксперта, скрипта или пользовательского индикатора) или в результате исполнения функции RefreshRates().

Перечень простых предопределённых имён переменных

 

Ask - последняя известная цена продажи по текущему финансовому инструменту;

Bid - последняя известная цена покупки по текущему финансовому инструменту;

Bars - количество баров на текущем графике;

Point - размер пункта текущего финансового инструмента в валюте котировки;

Digits - количество цифр после десятичной точки в цене текущего финансового инструмента.

Перечень предопределённых имён массивов-таймсерий

 

Time - время открытия каждого бара текущего графика;

Open - цена открытия каждого бара текущего графика;

Close - цена закрытия каждого бара текущего графика;

High - максимальная цена каждого бара текущего графика;

Low - минимальная цена каждого бара текущего графика;

Volume - тиковый объем каждого бара текущего графика.

(понятия "массив" и "массив-таймсерия" рассматриваются в разделе Массивы).

 

Свойства предопределённых переменных

 

Название предопределённой переменной не может быть использовано для идентификации пользовательской переменной. Предопределённые переменные могут использоваться в выражениях наравне с другими переменными по тем же правилам, но изменить значение предопределённой переменной нельзя. При попытке компилировать программу, содержащую оператор присваивания, в котором слева от знака равенства указана предопределённая переменная, редактор MetaEditor выдаст сообщение об ошибке. По области видимости предопределённые переменные относятся к глобальным, т.е. доступны из любой части программы (см. Виды переменных).

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

Значения всех предопределённых переменных автоматически обновляются клиентским терминалом в момент запуска на исполнение специальных функций.

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

//--------------------------------------------------------------------

// predefined.mq4

// Предназначен для использования в качестве примера в учебнике MQL4.

//--------------------------------------------------------------------

int start() // Спец. функция start

{

Alert("Bid = ", Bid); // Текущий курс

return; // Выход из start()

}

//--------------------------------------------------------------------

Запустив эту простую программу на выполнение легко убедиться, что значения переменной Bid, отражаемые в сообщениях, всякий раз будут соответствовать значениям текущего курса. Аналогичным способом можно проверить и значения других переменных, зависящих от сложившихся условий. Например, переменная Ask также прямо зависит от текущего курса. Значение переменной Bars тоже изменится, если изменится количество баров. Это может произойти на том тике, на котором в окне текущего финансового инструмента образуется новый бар. Значение Point зависит от спецификации финансового инструмента. Например, для валютной пары EUR/USD это значение равно 0.0001, а для валютной пары USD/JPY - равно 0.01. Значение Digits для тех же валютных инструментов равно соответственно целым числам 4 и 2.

Другим важным свойством предопределённых переменных является следующее:

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

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

 


Рис. 52. Время работы функции start() может быть больше или меньше интервала времени между тиками.

 

Эксперты отличаются друг от друга временем исполнения специальной функции start(). Для обычных экспертов средней сложности это время составляет приблизительно от 1 до 100 миллисекунд. Другие эксперты могут исполняться значительно дольше, например несколько секунд или даже десятков секунд. Промежуток времени между тиками также колеблется от миллисекунд до минут, а в редких случаях - нескольких десятков минут. Проследим на представленном примере как повлияет частота поступления тиков на работу экспертов Эксперт 1 и Эксперт 2, имеющих различное время исполнения специальной функции start().




Поделиться с друзьями:


Дата добавления: 2014-12-29; Просмотров: 283; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.121 сек.