The OpenNET Project
 
Поиск (теги):    НОВОСТИ (+) КОНТЕНТ WIKI MAN'ы ФОРУМ twitter

Создание интерактивных графических моделей в CAS MAXIMA при использовании ОС GNU Linux
Предисловие.
Не так давно я посмотрел фильм: Конрад Вольфрам. "Как учить детей
настоящей математике с помощью компьютеров", в котором автор использовал некие
программы для улучшения процесса обучения детей, представляющие собой математические
модели, управляемые с помощью интерфейсных графических элементов, таких как кнопки,
шкалы, меню. Я слышал, что подобные интерфейсные элементы встречаются в других
математических пакетах и, естественно, знал, что в максиме ничего подобного нет, не считая,
конечно, wxMaxima, которая является небольшой графической надстройкой над максимой, но
и она не позволяет встраивать подобные элементы в расчетный документ, тем самым не
позволяя создать математическую модель, управление расчетом в которой можно было бы
производить с помощью графических интерфейсных элементов. Поэтому вопрос о создании
интерактивных интерфейсов в максиме долгое время оставался для меня открытым и, не видя
очевидных путей его решения, я решил поизучать, как работает графическая система
отображения в Максиме.
Предпосылки.
В максиме имеются два основных способа отображения графической информации - это
функции plot и draw, простейший график рисуется вызовом функции plot2d(x^2,[x,-9,9]);. Оба
этих класса функций используют другой математический пакет - gnuplot, как раз и
специализирующийся на построении и выводе графиков. Поэтому я занялся изучением
возможностей данного пакета и, в процессе изучения документации, наткнулся на один очень
интересный параметр, который сыграл ключевую роль в успешной реализации задуманного.
При установке типа терминала в gnuplot, для типа терминала X11, допускается параметр
window, описан он плохо, и для чего необходим можно было лишь догадываться,
поэтому я провел эксперимент по изучению возможности использования этого параметра:
было бы очень приятно если бы gnuplot мог выводить графики в любое окно, которое мы ему
укажем. Для эксперимента я написал простейшую программу на питоне, в
которой создавал фрейм заданного размера и пару кнопок. Идентификатор этого окна, а
вернее - фрейма, очень легко узнать командой:
 xwininfo -tree

 Root window id: 0xbd (the root window) (has no name)
 Parent window id: 0x12559b9 (has no name)
 1 child:
 0x3c0000e (has no name): () 640x509+0+0 +2+80
 3 children:
 0x3c00012 (has no name): () 67x29+109+480 +111+560
 0x3c00011 (has no name): () 109x29+0+480 +2+560
 0x3c00010 (has no name): () 640x480+0+0 +2+80

Теперь запустим gnuplot и дадим там несколько команд:
 gnuplot> set terminal x11 window "3c00010"
 Terminal type set to 'x11'
 Options are 'XID 0x3C00010 nopersist'
 gnuplot> plot(sin(x));

вуаля!!! гнуплот рисует график функции в указанном окне, при этом все кнопки
приложения работают . Вот так и выяснилось, что этот параметр является ключевым в
возможности интеграции gnuplot в различные графические приложения в системе Xwindow.
Реализация.
Идея построения интерактивной графической параметрической модели родилась
после этого эксперимента довольно быстро, суть ее состояла в том, что мы добавим в
максиму функцию, позволяющую строить интерактивные графики, организованные по
принципу Модель-Вид-Контроллер, в которой maxima будет отвечать за модель, gnuplot
отвечать за вид, а управлять всем этим и реализовывать контроллер будет программа на
питоне(замечу, выбор питона - это чисто мое предпочтение, контроллер можно организовать
на любом, приятном для вас языке). Здесь я приведу окончательный и полный текст
программы на максиме и опишу что делает каждая ее строчка, но для начала опишу, что
нужно от пользователя, чтобы получить интерактивную графическую модель: во первых
ее надо определить на языке максима, а так же указать параметры, их начальные значения и
диапазон значений(не обязательно, но я не проверял, что будет, если это не
сделать :-) ), а также указать, где в файловой системе находится вид-контроллер
для данной модели.
Создаем модель в максиме:
к примеру это будет график функции n*sin(x) и график функции sin(b*x).
Допустим, в нашей модели n*sin(x), n должен меняться от 0.1 до 10.0 с шагом 0.2, поскольку я
намереваюсь управлять этим значением при помощи шкалы значений целых чисел, то в
формулу надо внести изменения (a/10.)*sin(x), а диапазон значений, передаваемый в контроллер, будет
от 1 до 100, с начальным значением 1 и шагом изменения 2(для демонстрации).
Параметр b: начальное значение 1, диапазон от 1 до 12, и зададим параметр, меняющий
диапазон расчета графиков от 2 до 5, с начальным значением 2
 g1:explicit((a/10.)*sin(x),x,-c*%pi,c*%pi);
 g2:explicit(sin(b*x),x,-c*%pi,c*%pi);
 model:'draw2d(color=red,g1, color=blue,g2);
 param_set:[[a,1,"1:100:2"],[b,1,"1:12"],[c,2,"2:5"]];
 name_model:sconcat(maxima_tempdir,"/work/maxima/gnuplot/mvc_3scale.py"); 

model - это наша параметризованная модель, param_set - это набор параметров с заданием
начальных значений и диапазона возможных значений, name_model - это имя контроллера,
который будет вызываться для отображения нашей модели вместо стандартной программы
отображения графиков gnuplot. Всё, модель задана, осталось только запустить ее в обработку.
Для обработки я выбрал имя функции idraw, в смысле интерактивное рисование.
 idraw(model,param_set,name_model);

Итак, функция idraw:
/* i -означает интерактивный */
 idraw(model,param_set,name_model) := block(
 [old_plot_format,t1,pipe_view_name,pipe_view,plt_fmt,cmd,ll],
 pipe_view_inter_n:sconcat(maxima_tempdir, "/maxima.pipe_interact"),
 pipe_view_param_n:sconcat(maxima_tempdir, "/maxima.pipe_param"),

/*подготовим канал для взаимодействия с процессом интерактивного представления
модели вид-контроллер и канал для передачи параметров от модели в контроллер*/
 if not probe_file(pipe_view_inter_n) then system(sconcat("mkfifo ", pipe_view_inter_n)),
 if not probe_file(pipe_view_param_n) then system(sconcat("mkfifo ", pipe_view_param_n)),

/*запомним предыдущий способ отрисовки графиков и установим свой*/
 old_plot:gnuplot_command,
 gnuplot_command:name_model,
 guplot_close(), 
/*надо обязательно закрыть предыдущую сессию gnuplot, иначе максима не
вызовет новую модель*/
/*выполним отрисовку интерактивной модели с установками по умолчанию*/
 t1:map(lambda([x],x[1]=x[2]),param_set), 
 ev(model,nouns,t1),
/*через канал передачи параметров максимы и интерактивного вида-контроллера настроим контроллер*/
/*с обратной стороны канала уже должен работать процесс, считывающий данные из
него, костыль с |cat >file приделан т.к. максима почему-то не может открыть на запись файл fifo*/
 pipe_view:openw(sconcat("| cat >",pipe_view_param_n)),

/*в цикле передадим имеющиеся параметры*/
 map(lambda([x],printf(pipe_view,"~a:~d:~a~%", x[1],x[2],x[3]),0),param_set),
 printf(pipe_view,"end~%"),
 close(pipe_view),

/*теперь открываем на чтение канал интерактивной передачи параметров*/
 kill(pipe_view),
 pipe_view:openr(pipe_view_inter_n),

/*запускаем цикл чтения данных из канала управления моделью*/
 cmd:1,
 while cmd=1 do block(
 if stringp(ll : readline(pipe_view)) then block (
 print("read from pipe_view: ", ll), /*для отладки*/
 /*вид приходящей строки (cmd:1,t1:[a = 1,b = 1,c = 2])*/

 eval_string(ll), /*устанавливаем переменные t1,cmd*/

/*получая новые значения параметров, пересчитываем модель и перерисовываем view*/
 if cmd=1 then
 ev(model,nouns,t1 )
 )
 else
 cmd:0
 ),
 close(pipe_view),
 gnuplot_close(),
 gnuplot_command:old_plot
 ); 

view в gnuplot не нуждается в какой либо программе, это полностью управляемый элемент
через stdin в который может писать команды и maxima и контроллер.
Что же должен представлять собой контроллер? У нас это программа на питоне, которая с
одной стороны должна принимать команды от максимы и передавать их в gnuplot, с другой
- она должна передавать установленные в контроллере новые значения параметров
обратно в максиму. Вкратце опишу, что в ней происходит:
0) Поскольку функция idraw заменила название основной утилиты для отрисовки графиков,
то вместо gnuplot будет вызвана наша программа, так создается main_controller_process
1) create_Tk_interface() Создаем графический интерфейс, как-то фрейм в который будет
выводить gnuplot построенные на основе данных из максимы, элементы управления - Scale,
которые затем будут инициализироваться принятыми из максимы параметрами, и значения
которых впоследствии будут передаваться обратно в максму, и пара кнопок(пересчитать и
выход).
2)create_gnuplot_pipe() создаем процесс gnuplot и получаем два канала к нему для ввода и
вывода данных.
3)change_terminal() поскольку интерфес Тк мы построили, гнуплот запустили, можем дать
команду в гнуплот об установке типа терминала X11 и конкретного окна для вывода графиков.
4)make_process_reader() Запускаем дочерний питон процесс, который будет читать данные из
stdin потока и передавать их в процесс gnuplot, таким образом обеспечиваем передачу данных
из максимы в гнуплот.
5)open_pipe_param(read) открываем канал для чтения значений параметров из максимы
5.1) do_read_param() читаем построчно данные из максимы, разбираем ввод и формируем
хеш массив param
6) do_set_widget_param() используя ранее полученные значения параметров, сохраненные в
хеш массиве param
7) open_pipe_interact(write) открываем на запись канал для интерактивной передачи команд в
максиму, где сейчас должна работать функция idraw, читающая и интерпретирующая эти
команды.
8)do_main_Tkloop() запускаем цикл обработки сообщений Tk интерфейса
В процессе работы Тк интерфейса могут происходить следующие события:
8.1) set_param() Пользователь установил новое значение параметра, это новое значение
просто сохраняется в хеш массиве param
8.2) recalc() Пользователь нажал на кнопку "пересчитать", при этом все текущие значения,
сохраненные в массиве param, оформляются в командную строку, которую способна
интерпретировать максима и через канал передаются туда, в максиме, эти данные
интерпретируются моделью, после чего сформированные команды для gnuplot передаются
через процесс-посредник в gnuplot, таким образом, гнуплот выводит новое графическое
представление модели, в соответствии с установленными значениями параметров.
8.3) quit() пользователь нажал на кнопку "выйти" или другим образом завершил работу
контроллера, при этом в максиму передается команда, завершающая цикл чтения канала
интерактивной передачи значений параметров, сигналом kill завершается работа процесса
посредника child_reader_process, затем закрывается и сеанс gnuplot.
На этом программа работы контроллера и завершается.
Для лучшего понимания процесса взаимодействия всех участников данной системы, я
нарисовал диаграмму взаимодействия процессов рис 1. Данной модели соответствует работа
программ mvc_2edit_1scale.py и mvc_3scale.py, их я здесь приводить не буду, т.к. с ними вы
сможете ознакомиться, изучив прилагаемы к этому документу файлы.
Собираем все вместе: определяем модель в каком нибудь файле, например model2.mac
содержащий:
 work_dir:sconcat(maxima_tempdir,"/work/maxima/gnuplot/");
 /*загружаем функцию интерактивного рисования*/
 load(sconcat(work_dir,"idraw"));
 /*описание модели*/
 g1:implicit(a=x^2+y^2+z^2,x,-c,c,y,-c,c,z,-c,c);
 g2:explicit(sin(b*x)*sin(2*y),x,-2*c,2*c,y,-2*c,2*c);
 model:'draw3d(surface_hide=true,color=red,g1, color=blue,g2);
 param_set:[[a,1,"1:6:1"],[b,1,"1:12"],[c,1,"1:15"]];
 name_model:sconcat(work_dir,"mvc_3scale.py");

корректируем файл контроллера или создаем новый, меняя состав виджетов и названия
параметров, соответствующих нашей модели.
Загружаем максиму, и даем команду:
 load(sconcat(maxima_tempdir,"/maxima/gnuplot/model3.mac"));

и теперь выполняем отрисовку модели, и управление моделью через полученный
интерфейс.
 idraw(model,param_set,name_model);

Рисунок 1

В результате мы должны получить нечто подобное рис 2.
Рисунок 2.

Пример использующий контроллер mvc_2edit_1scale.py допускает изменение параметров с
помощью полей ввода целых чисел и чисел с плавающей запятой (вернее точкой), но для
того, чтобы он заработал, пришлось слегка изменить формат передачи параметров и начать
указывать в них, какого типа значение будет принимать параметр.
Пример создадим файл model2_1.mac
 work_dir:sconcat(maxima_tempdir,"/work/maxima/gnuplot/");
 load(sconcat(work_dir,"idraw"));
 g1:explicit(a*sin(x),x,-c*%pi,c*%pi);
 g2:explicit(sin(b*x),x,-c*%pi,c*%pi);
 call_d:'draw2d(color=red,g1, color=blue,g2);
 model:call_d;
 param_set:[[a,55.0,"f:0.1:100.0"], [b,17,"i:1:100"], [c,2,"1:10"]];
 name_model:sconcat(work_dir,"mvc_2edit_1scale.py");

в определении параметров добавили столбец, определяющий тип параметра int(i) или
float(f).
 load(sconcat(maxima_tempdir,"/work/maxima/gnuplot/model2_1.mac"));

и запустим интерпретацию нашей модели модели
 idraw(model,param_set,name_model);

должны получить нечто подобное рис.3
Рисунок 3.

Ну и в завершении я представлю программу mvc_any_param.py, которая идеально подойдет
для людей, не желающих программировать для каждой модели еще и контроллер, она
способна в минимальном представлении отрисовать любое передаваемое ей количество
параметров любого типа. Для того, чтобы она работала, необходимо опять изменить формат
передаваемых параметров, и для каждого параметра указывать, какого типа виджет мы
желаем использовать для его редактирования. Добавим в начало каждой строки параметров,
там где мы ранее задавали диапазон, еще одно поле со значениями s - Scale
или e - Entry.
Изучаем пример, файл model4.mac:
 work_dir:sconcat(maxima_tempdir,"/work/maxima/gnuplot/");
 load(sconcat(work_dir,"idraw"));
 g1:explicit((a/10.)*sin(x),x,-c*%pi,c*%pi);
 g2:explicit(sin(b*x),x,-c*%pi,c*%pi);
 model:'draw2d(color=red,g1, color=blue,g2);
 param_set:[[a,55.0,"e:f:10.0:1000.0"], [b,17,"e:i:1:100"], [c,2,"s:1:10"]];
 param_set1:[[a,55.0,"e:f:10.0:1000.0"], [b,17,"e:i:1:100"], [c,2,"s:1:10"],
 [da,55,"s:10:1000"], [bi,17,"e:f:1:100"], [ca,2,"s:0:20"]];
 param_set2:[[a,55.0,"e:f:10.0:1000.0"], [b,17,"e:i:1:100"], [c,2,"s:1:10"],
 [da,55,"s:10:1000"], [bi,17,"e:f:1:100"], [ca,2,"s:0:20"],
 [w,55,"s:10:1000"], [bu,17,"e:f:1:100"]];
 name_model:sconcat(work_dir,"mvc_any_param.py");

Загрузив нашу модель командой:
 load(sconcat(maxima_tempdir,"/work/maxima/gnuplot/model4.mac"));

запустим интерпретацию нашей модели
 idraw(model,param_set2,name_model);

Мы должны получить что то подобное рисунку 4
Я не стал изменять саму модель, просто продемонстрировал простоту добавления
параметров.
Рисунок 4.

Заключение.
Ну вот, собственно говоря, и все. В принципе, в программе можно еще много что
делать и совершенствовать. Но, как говорится, лучшее враг хорошего, к нему можно
бесконечно приближаться, а работу надо рано или поздно заканчивать. Удачи вам,
удосужившимся ознакомиться с моим трудом, надеюсь знакомство с максимой, линуксом и
питоном обогатят вашу жизнь, сделают шире ваши возможности, как это произошло со мной.
Разработал Гагин Михаил ака NuINu c благодарностью к разработчикам Maxima, Gnuplot,
Python, Linux и всему сообществу OpenSource.
Примеры кода к статье и версию статьи в формате PDF можно загрузить здесь.
 
23.02.2015 , Автор: NuINu
Раздел:    Корень / Программисту и web-разработчику / Системы контроля версий и управления исходными текстами

Обсуждение [ Линейный режим | Показать все | RSS ]
 
  • 1.1, StainlessRat, 20:54, 28/02/2015 [ответить] [смотреть все]
  • +/
    "Искусство программирования (англ. The Art of Computer Programming) — фундаментальная монография известного американского математика и специалиста в области компьютерных наук Дональда Кнута"
    Обложка третьего издания первого тома книги содержит цитату Билла Гейтса: «Если вы считаете себя действительно хорошим программистом…, прочитайте „Искусство программирования“ (Кнута)… Если вы сможете прочесть весь этот труд, то вам определённо следует отправить мне резюме»
     
     
  • 2.7, pavlinux, 14:59, 07/03/2015 [^] [ответить] [смотреть все]
  • +/
    Сам-то все примеры из заданий выполнил?
     
  • 1.2, myhand, 18:37, 02/03/2015 [ответить] [смотреть все]
  • +/
    Пожизненный эцих с гвоздями.

    Не, я серьезно, в следующий раз прежде чем страдать фигней (а тем более ее публиковать) - автору категорически рекомендуется познакомиться как аналогичную задачу решают нормальные люди.  Использовать python и пройти мимо возможностей IPython notebook - верх безграмотности.

    PS: Отдельный привет модераторам.  Раздел "я плакаль" не собираетесь организовать?

     
     
  • 2.3, NuINu, 14:06, 05/03/2015 [^] [ответить] [смотреть все]
  • +/
    вам известен пакет Maxima? прежде чем писать мне отзывы, прочитали бы для чего я разработал данную технологию. Пока еще проекту SymPy до максмы, как вам до луны пешком. А вместе с ним и всему проекту  ipython notebook. моей целью не стояло разрабатывать интегрированную среду на питоне, для работы с максимой, этот проект уже есть wxMaxima, я лишь добавил одну не очень может нужную, но интересную возможность. И если вы уж встряли, я так понимаю вы знаток этой среды ipython notebook, расскажите как в ней создать параметризованную интерактивную математическую модель. хотя бы для двух функций, с тремя параметрами.
     
     
  • 3.4, myhand, 21:19, 05/03/2015 [^] [ответить] [смотреть все]
  • +/
    > вам известен пакет Maxima? прежде чем писать мне отзывы, прочитали бы для
    > чего я разработал данную технологию.

    Из текста "статьи" не понятна не только суть "технологии", но и вообще - причем здесь любые CAS.  Вашу "задачу" способен решить голый питон (емм, ну с matplotlib...) с IPython notebook в качестве интерфейса.

    > Пока еще проекту SymPy до максмы, как вам до луны пешком.

    Почему пешком?  Причем тут вообще SymPy...

    > А вместе с ним и всему проекту  ipython notebook.

    И нафейхоа IPython какой-то sympy...

    > И если вы уж встряли, я так понимаю вы знаток этой
    > среды ipython notebook, расскажите как в ней создать параметризованную интерактивную математическую модель. хотя бы для двух функций, с тремя параметрами.

    Если вам лень лезть в документацию - посмотрите недавние презентации IPython с интерактивными виджетами (на SciPy 2014 что-то было).

     
     
  • 4.5, NuINu, 09:39, 06/03/2015 [^] [ответить] [смотреть все]  
  • +/
    суть технологии в том что есть среда Максима или вхМаксима, не важно, в ней очен... весь текст скрыт [показать]
     
     
  • 5.6, myhand, 18:56, 06/03/2015 [^] [ответить] [смотреть все]  
  • +/
    А можно научиться работать с тем, что уже создали люди в очень приличном виде ... весь текст скрыт [показать]
     
  • 1.8, pavlinux, 15:02, 07/03/2015 [ответить] [смотреть все]  
  • –1 +/
    Ваще жуть, пост из 80-х годов. B Maple иль Matlab подобные графики строятся за 10 сек.

    Я когда в универах учился, забил нах на Linux и Опянсоурс,
    ибо эта еботня с кодом отнимает 95% времени на решение задач.

     
     
  • 2.9, myhand, 16:46, 07/03/2015 [^] [ответить] [смотреть все]  
  • +/
    > Ваще жуть, пост из 80-х годов. B Maple иль Matlab подобные графики
    > строятся за 10 сек.

    Жутковато, конечно, но речь не о построении графиков.  Т.е. ты тупо не понял.

    Кстати, не вполне уверен что необходимый функционал в Maple есть (в Mathematica и Matlab - да).

    > Я когда в универах учился, забил нах на Linux и Опянсоурс

    Ну либо ты патологический дурак, либо уж очень давно учился.  Linux давно стал де-факто стандартом в сфере качественного образования (рашен ПТУ^Wтехнические университеты - не считаются).

     
     
  • 3.11, pavlinux, 16:56, 08/03/2015 [^] [ответить] [смотреть все]  
  • +/
    >... но речь не о построении графиков.  Т.е. ты тупо не понял.

    Название темы прочти.

     
     
  • 4.14, NuINu, 18:50, 08/03/2015 [^] [ответить] [смотреть все]  
  • +/
    >>... но речь не о построении графиков.  Т.е. ты тупо не понял.
    > Название темы прочти.

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

     
  • 4.15, myhand, 18:05, 09/03/2015 [^] [ответить] [смотреть все]  
  • +/
    >>... но речь не о построении графиков.  Т.е. ты тупо не понял.
    > Название темы прочти.

    Без посторонней помощи не можешь?

     
  • 2.10, NuINu, 20:23, 07/03/2015 [^] [ответить] [смотреть все]  
  • +/
    универ окончил? много денег заработал? сколько стоит maple? или matlab? матлаб за 2000баксов, по нынешим курсам за 120тысяч рублей а мэпл 1500, т.е около за 90 тысяч. В принцепе наверное не много, смотря у кого какая зарплата. Но я просто потратил время и освоил максиму, мне для математических расчетов, коими я ранее даже не занимался(долгое время), хватает. Ну если ты такой стал удачливый, флаг тебе в руки и виндовс в систему, сразу десятый.
     
     
  • 3.12, pavlinux, 16:56, 08/03/2015 [^] [ответить] [смотреть все]  
  • +/
    Maple студентам нахаляву раздают http://www.maplesoft.com/products/maple/students

    Правда там тест на IQ надо пройти, но для тупичков можно за 124$

     
     
  • 4.13, NuINu, 18:44, 08/03/2015 [^] [ответить] [смотреть все]  
  • +/
    ну ты же уже не студент, почитай внимательно лицензию, там будет написано можешь пользоваться пока учишься, как закончил обучение, давай плати. Знаешь же что халявы не бывает.
     

    Ваш комментарий
    Имя:         
    E-Mail:      
    Заголовок:
    Текст:

     Добавить заметку
     Версия для печати
     
     Поиск заметки:
     

    Последние заметки
    - 18.03 Подготовка качественных GIF-файлов из видео при помощи FFmpeg
    - 13.03 Обновление Debian Wheezy до Debian Jessie, не дожидаясь официального релиза
    - 12.03 Подавление шумов средствами PulseAudio
    - 23.02 Создание интерактивных графических моделей в CAS MAXIMA при использовании ОС GNU Linux
    - 05.02 Мониторинг температуры в Zabbix с использованием Digitemp
    - 07.01 Настройка SSH для использования наиболее защищённых алгоритмов шифрования
    - 06.01 Как установить AMD Catalyst в Fedora 21, не ломая GNOME и другие вещи
    - 15.12 Организация входа по SSH в окружение Live-диска FreeBSD
    - 28.11 Ubuntu как сервер Zentyal + MyDLP + Webmin + SAMS2
    - 26.11 Скрипт для резервного копирования EC2-серверов в AMI
    RSS | Следующие 15 записей >>



      Закладки на сайте
      Проследить за страницей
    Created 1996-2015 by Maxim Chirkov  
    ДобавитьРекламаВебмастеруГИД  
    RUNNet TopList
    п╡п╣я│п╣п╩я▀п╣ п╨п╟я─я┌п╦п╫п╨п╦ я─п╟п╥п╡п╩п╣п╨п╟я┌п╣п╩я▄п╫я▀п╣ пЁп╦я└п╨п╦ п╦п╫я┌я─п╣я│п╫я▀п╣ я└п╟п╨я┌я▀ я│п╪п╣я┬п╫я▀п╣ п╡п╦п╢п╣п╬ я│п╪п╣я┬п╫я▀п╣ п╦я│я┌п╬я─п╦п╦ п╦п╥ я│п╬я├я│п╣я┌п╣п╧