Студопедия

КАТЕГОРИИ:


Архитектура-(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)

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




34(1). В следующей строке содержится вызов функции Alert():

Alert ("Новый тик ",Count," Цена = ",Price);// Сообщение

Функция напечатает все константы и переменные, перечисленные в круглых скобках.

При первом выполнении функции start() программа напечатает Новый тик, затем обратится к переменной Count, чтобы получить её значение, (при первом выполнении это значение равно 1), напечатает это значение, вслед за этим напечатает Цена =, и, наконец, обратится к переменной Price, получит её значение (в нашем примере это значение 1.2744) и напечатает его.

В результате будет напечатана строка:

Новый тик 1 Цена = 1.2744

35(1). Оператор

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

заканчивает работу специальной функции start().

36. Управление возвращается клиентскому терминалу (на период до прихода очередного тика).

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

37. С момента прихода нового тика последовательность действий по пп 32 - 36 повторяется. Однако, повторяется лишь последовательность выполняемых операторов, но переменные всякий раз получают новые значения. Рассмотрим отличия между первым и вторым исполнением специальной функции start().

32 (2). В строке

double Price = Bid; // Локальная переменная

производятся следующие действия:

32.1(2). Объявление локальной переменной Price (без изменений).

32.2(2). Выполнение оператора присваивания. Переменной Price будет присвоено значение текущей цены Bid (новое значение цены появляется всякий раз с приходом очередного тика, например, на втором тике цена финансового инструмента окажется равной 1.2745). (есть изменения).

33(2). Далее будет выполняться строка:

Count++;

В момент, предшествующий передаче управления в эту строку, значение переменной Count (после первого выполнения функции start()) равно 1. В результате выполнения оператора Count++ значение Count будет увеличено на единицу. Таким образом, при втором выполнении значение Count будет равно 2 (есть изменения).

34(2). Функция Alert():

Alert ("Новый тик ",Count," Цена = ",Price);// Сообщение

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

При втором выполнении функции start() программа напечатает Новый тик, затем обратится к переменной Count, чтобы получить её значение, (при втором выполнении это значение равно 2), напечатает это значение, вслед за этим напечатает Цена =, и, наконец, обратится к переменной Price, получит её значение (в нашем примере значение цены при втором выполнении равно 1.2745) и напечатает его (есть изменения).

В результате будет напечатана строка:

Новый тик 2 Цена = 1.2745

35(2). Оператор

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

заканчивает работу специальной функции start() (без изменений).

36(2). Управление возвращается клиентскому терминалу на ожидание нового тика.

37(2). В дальнейшем всё повторяется снова. При третьем выполнении специальной функции start() переменные получат новые значения и неминуемо будут снова напечатаны с помощью функции Alert(), т.е. программа снова выполнится по п.п. 32 - 36(3). И далее снова и снова.. 32 - 36(4), 32 - 36(5),..(6)..(7)..(8)... Если пользователь не предпримет никаких действий, то этот процесс будет повторяться бесконечно. В результате работы специальной функции start() рассматриваемой программы на экране можно наблюдать тиковую историю изменения цены.

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

4. Клиентский терминал передаст управление специальной функции deinit() (в соответствии с её свойствами).

int deinit() // Спец. ф-ия deinit()

{

Alert ("Сработала ф-ия deinit() при выгрузке"); // Сообщение

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

}

В теле функции содержится всего два оператора.

41. Функция Alert() напечатает сообщение:

Сработала ф-ия deinit() при выгрузке

42. Оператор return заканчивает работу специальной функции deinit().

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

5. На этом история исполнения эксперта заканчивается.

 

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


Рис. 35. Результат работы программы simple.mq4.

 

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

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

Примеры реализации

 

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

Пример правильной структуры программы

Как правило, описания функций в программе указываются в той последовательности, в которой они вызываются для исполнения клиентским терминалом, а именно, сначала приводится описание специальной функции init(), затем специальной функции start() и последним указывается описание специальной функции deinit(). Однако, специальные функции вызываются для исполнения клиентским терминалом в соответствии с их собственными свойствами, поэтому не имеет значения в каком месте программы указано описание той или иной функции. Давайте переставим местами специальные функции и посмотрим что из этого получится (эксперт possible.mq4).

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

// possible.mq4

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

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

int Count=0; // Глобальная перемен.

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

int start() // Спец. ф-ия start()

{

double Price = Bid; // Локальная перемен.

Count++;

Alert("Новый тик ",Count," Цена = ",Price);// Сообщение

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

}

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

int init() // Спец. ф-ия init()

{

Alert ("Сработала ф-ия init() при запуске"); // Сообщение

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

}

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

int deinit() // Спец. ф-ия deinit()

{

Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение

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

}

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

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

Пример неправильной структуры программы

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

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

// incorrect.mq4

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

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

int start() // Спец. ф-ия start()

{

double Price = Bid; // Локальная перемен.

Count++;

Alert ("Новый тик ",Count," Цена = ",Price);// Сообщение

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

}

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

int Count=0; // Глобальная перемен.

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

int init() // Спец. ф-ия init()

{

Alert ("Сработала ф-ия init() при запуске"); // Сообщение

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

}

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

int deinit() // Спец. ф-ия deinit()

{

Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение

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

}

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

При попытке компиляции этого эксперта редактор MetaEditor выдаст сообщение об ошибке:


Рис. 36. Сообщение об ошибках при компиляции программы incorrect.mq4.

В данном случае строка

int Count=0; // Глобальная перемен.

написана за пределами всех функций, но находится не в первых строках программы, а где-то в середине.

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

Пример применения пользовательской функции

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

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

// userfunction.mq4

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

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

int Count=0; // Глобальная перемен.

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

int init() // Спец. ф-ия init()

{

Alert ("Сработала ф-ия init() при запуске"); // Сообщение

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

}

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

int start() // Спец. ф-ия start()

{

double Price = Bid; // Локальная перемен.

My_Function(); // Вызов польз. ф-ии

Alert("Новый тик ",Count," Цена = ",Price);// Сообщение

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

}

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

int deinit() // Спец. ф-ия deinit()

{

Alert ("Сработала ф-ия deinit() при выгрузке");// Сообщение

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

}

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

int My_Function() // Описание польз.ф-ии

{

Count++; // Счётчик обращений

}

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

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

Остались без изменений:

1. Головная часть осталась без изменений.

// userfunction.mq4

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

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

int Count=0; // Глобальная перемен.

2. Специальная функция init() осталась без изменений.

int init() // Спец. ф-ия init()

{

Alert ("Сработала ф-ия init() при запуске"); // Сообщение

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

}

3. Специальная функция deinit() осталась без изменений.

int deinit() // Спец. ф-ия deinit()

{

Alert("Сработала ф-ия deinit() при выгрузке");// Сообщение

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

}

Изменения:

1. Добавилась пользовательская функция My_Function().

int My_Function() // Описание польз.ф-ии

{

Count++; // Счётчик обращений

}

2. Претерпел изменение код специальной функции start(): в нём появилось обращение к пользовательской функции, а также отсутствует строка вычисления переменной Count.

int start() // Спец. ф-ия start()

{

double Price = Bid; // Локальная перемен.

My_Function(); // Вызов польз. ф-ии

Alert("Новый тик ",Count," Цена = ",Price);// Сообщение

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

}

В разделе Выполнение программы рассматривался порядок исполнения специальных функций init() и deinit(). В данном примере исполнение этих функций будет происходить так же, поэтому здесь нет необходимости останавливаться на их работе. Рассмотрим исполнение специальной функции start() и пользовательской функции My_Function(). Описание пользовательской функции расположено за пределами всех специальных функций, как и должно быть. Вызов пользовательской функции указан в коде специальной функции start(), что тоже верно.

После того, как исполнится специальная функция init(), программа будет исполняться так:

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

32 (1). В строке

double Price = Bid; // Локальная перемен.

производятся те же действия:

32.1(1). Инициализация локальной переменной Price (см. Виды переменных). Значение этой локальной переменной будет доступно из любого места специальной функции start().

32.2(1). Выполнение оператора присваивания. Переменной Price будет присвоено последнее известное значение текущей цены Bid (например, на первом тике цена финансового инструмента окажется равной 1.2744).

33(1). Следующей записью в коде является обращение к пользовательской функции My_Function():

My_Function(); // Вызов польз. ф-ии

Эта строка будет исполнена в рамках продолжающейся работы специальной функции start(). Результатом выполнения этой части кода (обращение к пользовательской функции) будет передача управления в тело (описание) пользовательской функции с последующим возвратом управления в место вызова.

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

Count++;

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

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

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

35(1). В этой строке содержится вызов функции Alert():

Alert ("Новый тик ",Count," Цена = ",Price);// Сообщение

Функция Alert() выведет в окно сообщения все константы и переменные, перечисленные в круглых скобках:

Новый тик 1 Цена = 1.2744

36(1). Оператор

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

заканчивает работу специальной функции start().

37. Управление передаётся клиентскому терминалу на ожидание нового тика.

При следующих исполнениях специальной функции start() переменные получат новые значения и снова будут выведены в окно сообщения функции Alert(), т.е. программа снова выполнится по пп 32 - 36. В том числе, при каждом исполнении функции start() (на каждом тике) будет срабатывать обращение к пользовательской функции My_Function(), и эта функция будет выполняться. Исполнение специальной функции start() будет продолжаться до тех пор, пока пользователь не примет решение о прекращении работы программы. В этом случае отработает специальная функция deinit() и программа прекратит свою работу.

Запущенная на исполнение программа userfunction.ех4 отобразит на экране окно, в котором будут выводиться сообщения функции Alert(). Обратите внимание, результат работы программы будет таким же, как и результат работы простого эксперта simple.mq4. Легко увидеть, что структура программы userfunction.mq4 составлена в соответствии с обычным порядком расположения функциональных блоков. Если же этот порядок изменить на другой допустимый порядок, то результат работы программы не изменится.

Операторы

 

В разделе представлены правила форматирования и исполнения операторов, используемых в языке MQL4. В каждом параграфе приводятся простые примеры, демонстрирующие исполнение операторов. С целью полного усвоения материала все представленные программы рекомендуется скомпилировать и запустить на исполнение. Это позволит также закрепить навыки работы с редактором MetaEditor.

 

Оператор присваивания.
Самый простой и интуитивно понятный оператор. Операцию присваивания мы все знаем из школьного курса математики: слева от знака равенства стоит имя переменной, справа - назначаемое ей значение.

Условный оператор if-else.
Часто необходимо направлять работу программы в ту или иную сторону в зависимости от некоторых условий. В таких случаях будет полезен оператор управления if-else.

Оператор цикла while.
Обработка больших однотипных массивов данных обычно требует многочисленного повторения одних и тех же операций. Можно организовать цикл таких операций в операторе цикла while. Каждое однократное выполнение операций в цикле называется итерацией.

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

Оператор break.
Если вам необходимо прервать работу оператора цикла и не выполнять оставшиеся итерации, то вам необходим оператор прерывания break. Он применяется в операторах while, for, switch и более нигде.

Оператор continue.
Еще один полезный оператор - оператор перехода к следующей итерации в цикле. Позволяет пропустить все оставшиеся операторы в текущей итерации и перейти к следующей.

Переключатель switch.
Этот оператор является "переключателем", который позволяет выбрать один из множества возможных вариантов. Для каждого варианта описывается своя заданная константа, которая является ключом (case) к этому варианту.

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

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

Оператор присваивания

 

Оператор присваивания - самый простой и наиболее распространённый оператор.

Формат оператора присваивания

 

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

Переменная = Выражение; // Оператор присваивания

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

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

 

Вычислить значение выражения справа от знака равенства и полученное значение присвоить переменной, указанной слева от знака равенства.

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

Примеры операторов присваивания

 

В операторе присваивания допускается объявление типа переменной слева от знака равенства:

int In = 3; // Переменной In присвоено значение константы

double Do = 2.0; // Переменной Do присвоено значение константы

bool Bo = true; // Переменной Bo присвоено значение константы

color Co = 0x008000; // Переменной Co присвоено значение константы

string St = "sss"; // Переменной St присвоено значение константы

datetime Da= D'01.01.2004';// Переменной Da присвоено значение константы

Ранее объявленные переменные используются в операторе присваивания без указания типа.

In = 7; // Переменной In присвоено значение константы

Do = 23.5; // Переменной Do присвоено значение константы

Bo = 0; // Переменной Bo присвоено значение константы

В операторе присваивания не допускается объявление типа переменной в правой части от знака равенства:

In = int In_2; // Объявление типа переменных в правой части запрещено
Do = double Do_2; // Объявление типа переменных в правой части запрещено

В операторе присваивания не допускается повторное объявление типа переменных.

int In; // Объявление типа переменной In
int In = In_2; // Не допускается повторное объявление переменной (In)

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

In = My_Function(); // In присвоено значение пользоват. функции

Do = Gipo(Do1,Do1); // Do присвоено значение пользоват. функции

Bo = IsConnected(); // Bo присвоено значение стандартн. функции

St = ObjectName(0); // St присвоено значение стандартн. функции

Da = TimeCurrent(); // Da присвоено значение стандартн. функции

Примеры использования в правой части выражений:

In = (My_Function()+In2)/2; // Переменной In присвоено

//..значение выражения

Do = MathAbs(Do1+Gipo(Do2,5)+2.5); // Переменной Do присвоено

//..значение выражения

При вычислениях в операторе присваивания применяются правила приведения типов данных (см. Приведение типов).

Примеры операторов присваивания краткой формы

 

В MQL4 используется также краткая форма записи операторов присваивания. Это - форма операторов присваивания, в которой используются операции присвоения, отличные от операции присвоения = (знак равенства) (см. Операции и выражения). На операторы краткой формы распространяются те же правила и ограничения. Краткая форма операторов присваивания используется в коде для наглядности. Программист по своему усмотрению может использовать ту или иную форму оператора присваивания. Любой оператор присваивания краткой формы может быть легко переписан в полноформатный, при этом результат исполнения оператора не изменится.

In /= 33; // Краткая форма записи оператора присваивания

In = In/33; // Полная форма записи оператора присваивания

St += "_exp7"; // Краткая форма записи оператора присваивания

St = St + "_exp7"; // Полная форма записи оператора присваивания

Условный оператор if - else

 

Как правило, при программировании прикладных программ возникает необходимость закодировать в одной программе несколько вариантов решений. Для решения подобных задач в программе может быть использован условный оператор if-else.

Формат оператора if-else

 

Полный формат

 

Полноформатный оператор if-else содержит заголовок, включающий условие, тело 1, ключевое слово else и тело 2. Тела оператора могут состоять из одного или нескольких операторов и обрамляются фигурными скобками.

if ( Условие ) // Заголовок оператора и условие
{
Блок операторов 1, // Если условие истинно, то..
составляющих тело1 //..выполняются операторы тела 1
}else // А если условие ложно..
{
Блок операторов 2, //..то выполняются..
составляющих тело 2 //..операторы тела 2
}

Формат с отсутствующей частью else

 

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

if ( Условие ) // Заголовок оператора и условие
{
Блок операторов 1, // Если условие истинно, то..
составляющих тело1 //..выполняются операторы тела 1
}

Формат с отсутствующими фигурными скобками

 

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

if ( Условие ) // Заголовок оператора и условие
Оператор; // Если условие истинно, то..
//..выполняется этот оператор

 

Правило исполнения оператора if-else

 

Если условие оператора if-else является истинным, то передать управление первому оператору тела 1, а после выполнения всех операторов тела 1 передать управление оператору, следующему за оператором if-else. Если условие оператора if-else является ложным, то: - если в операторе if-else имеется ключевое слово else, то передать управление первому оператору тела 2, а после выполнения всех операторов тела 2 передать управление оператору, следующему за оператором if-else; - если в операторе if-else нет ключевого слова else, то передать управление оператору, следующему за оператором if-else.

 




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


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


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



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




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