Русский
Русский
English
Статистика
Реклама

Visualization

Гидродинамическое моделирование (CFD) на рельефе с помощью MantaFlow и визуализация результатов в ParaView

03.08.2020 08:09:56 | Автор: admin

Дисциплина Computational fluid dynamics(CFD) или, на русском языке, Вычислительная гидродинамика изучает поведение различных потоков, в том числе вихревых. Это и моделирование цунами, и лавовых потоков, и выбрасываемых из жерла вулкана камней вместе с лавой и газами и многое другое. Посмотрим, как можно использовать совместно MantaFlow и ParaView, реализовав на встроенном в MantaFlow языке Python необходимые функции конвертации данных. Как обычно, исходный код смотрите в моем GitHub репозитории: MantaFlow-ParaView.


Tambora Volcano Plume Simulation


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


Введение


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


Как и в случае с методами спутниковой интерферометрии, см. предыдущую статью Геология XXI века как наука данных о Земле, методы моделирования потоков позволяют узнать многое о происходивших процессах именно узнать, а не предположить. Действительно, моделируя лавовые потоки на палеорельефе (построенным, к примеру, путем решения обратной задачи геофизики), мы можем сравнить полученную модель с реально существующими [застывшими] лавовыми потоками и полями, поскольку они достаточно прочные и могут хорошо сохраняться многие и многие миллионы лет. Построенная модель позволяет изучить залегание различных слоев там, где у нас нет геологической информации, зачастую, один и то же вулкан извергался многократно из разных жерл, при этом потоки лавы разных извержений [и разного состава] могут перекрываться. Кроме того, эта же модель покажет неувязки между используемой моделью палеорельефа и существующими лавовыми проявлениями и позволит внести уточнения. То есть, вместо сложно формализуемой геологической интуиции, мы можем работать с моделью в том числе, изменять параметры и оценивать, насколько разные геологические предположения вообще разумны. Поскольку я сам не геолог, а физик, для меня путь моделирования представляет вполне понятный интерес. В результате, геолог может точнее оценить возможные области залегания полезных ископаемых и их потенциал разумеется, в геологическом исследовании вовсе не ставится задача обойтись без геолога, но, как и везде, ценность результатов согласуется с известным принципом информатики: "Мусор на входе мусор на выходе", поэтому каждая возможность уточнить, заверить и дополнить имеющиеся данные в буквальном смысле на вес золота (или нефти, или воды,...).


MantaFlow


Как уже сказано выше, MantaFlow это хорошо известный и поддерживаемый программный пакет, а также, на его основе есть несколько интересных производных проектов: с большим акцентом на использование машинного обучения PhiFlow, с возможностью вычисления параметров процесса по набору снимков reconstructScalarFlows и другие.


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



А это модель заполнения потоком воды заданного рельефа:



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


Добавим рельеф в MantaFlow


Для меня самый удобный вариант это использование ParaView с моим расширением N-Cube ParaView plugin for 3D/4D GIS Data Visualization для построения 3D модели рельефа в ParaView на основе NetCDF или GeoTIFF данных и сохранение нужного участка в формате OBJ для его использования в MantaFlow. Поскольку MantaFlow умеет этот формат загружать и работать с ним в безразмерных координатах, нам потребуется лишь указать нужный размер в безразмерных координатах (скажем, 100% по горизонтальным координатам и 25% по вертикальной чтобы было достаточно места для моделирования столба дыма) и сохранить параметры преобразования для экспорта результатов в физических координатах. Вот скрипт репозитория с реализацией соответствующей функции: mesh2manta.py


Сохраним результаты моделирования в MantaFlow для ParaView


Поскольку мы задаем исходное пространство моделирования в физических координатах (файл OBJ и коэффициенты его масштабирования), у нас есть все необходимое, чтобы и результаты сохранить в физических координатах. По умолчанию, MantaFlow сохраняет безразмерные результаты в формате сжатых массивов Numpy, поэтому мы добавим сохранение в формат с поддержкой физических координат (VTK), см. скрипт репозитория npz2vtk.py. Добавлю, что в скрипте создается массив xarray: N-D labeled arrays and datasets in Python, из которого одной командой можно сохранить данные в формате NetCDF и некоторых других.


Визуализация в ParaView


Как мы уже рассмотрели в предыдущих статьях (с примерами), ParaView поддерживает работу с сериями данных, так что мы можем работать с 4D данными например, в виде 3D анимации. Вот пример анимации вулканического дыма из серии файлов VTK, экспортированных из MantaFlow:



Модели высокой детализации


Увеличение детальности моделей требует и больше ресурсов для их построения. Если модели на сетке 64х64х64 вычисляются за несколько минут на ноутбуке, то при удвоении разрешения по каждой координате время увеличивается в 8 раз (третья степень двойки).


Ниже показана намного более детальная модель на примере турбулентного торнадо с сайта проекта MantaFlow:



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


Заключение


Хотя именно о построении моделей мне и хотелось написать ранее, но пришлось начинать с серии статей про визуализацию данных и потом постепенно переходить уже непосредственно к моделированию. В самом деле, если не рассказать заранее, как хотя бы посмотреть результаты, получится не интересно. Хотя и можно использовать MantaFlow в Blender, но с последним я сам не работаю и не уверен, многие ли из читателей с ним достаточно знакомы. Так что пусть будет как есть знакомство с ParaView ранее и рассказ про MantaFlow и ParaView, а те читатели, кому этого захочется смогут попробовать MantaFlow и Blender.


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

Подробнее..

Перевод Использование переменных Grafana для большей интерактивности дашбордов

20.07.2020 18:22:00 | Автор: admin

Flowers and butterflies by marijeberting

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

Команда Mail.ru Cloud Solutions перевела статью, которая поможет добавить в Grafana функции, позволяющие пользователям создавать собственные интерактивные дашборды, чтобы углубиться в конкретные детали.

Общая проблема унылые статические дашборды


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

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

Решение: сделайте свои дашборды интерактивными (и удобными для пользователей)


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

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


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

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

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

Попробуйте сами: реализация интерактивных дашбордов в Grafana


Готовы научиться использовать переменные в дашбордах Grafana для модификации запросов PostgreSQL?

Что нам нужно:

  • инстанс Grafana;
  • PostgreSQL с включенным движком TimescaleDB, подключенный к Grafana как источник данных; (Прим. переводчика: также можно использовать базы данных вроде InfluxDB.)
  • дашборд, использующий PostgreSQL в качестве источника данных.

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

У меня есть существующая настройка дашборда Grafana World Map, изображенная ниже. Чтобы скопировать мою первоначальную настройку, вы можете клонировать этот репозиторий GitHub и выполнить шаги, описанные в нем.

Вот как выглядел мой дашборд, прежде чем мы сделаем его интерактивным (вы можете скачать JSON дашборда в этом репозитории GitHub).


Дашборд Первоначальная карта, показывающая местоположение автобусов в Нью-Йорке в реальном времени, без каких-либо интерактивных элементов

Вот SQL-запрос, который используется для получения данных для этого дашборда:

SELECT max(time) as "time", vid AS "vehicle_id", route_id, CASE WHEN route_id LIKE 'M%' THEN 1      WHEN route_id LIKE 'B%' THEN 2      WHEN route_id LIKE 'Q%' THEN 3      WHEN route_id LIKE 'S%' THEN 4      ELSE 0  END AS "color", ST_X(geom) AS "longitude", ST_Y(geom) AS "latitude"FROM mta WHERE time > now()-interval '1.5 minutes'GROUP BY vid, route_id, geomORDER BY 1;

В приведенном выше запросе обратите внимание, что я использую переменную цвета, чтобы различать разные типы автобусов в зависимости от их маршрута. Существует четыре типа автобусных маршрутов: M, B, S и Q в соответствии с районами Нью-Йорка: Манхеттен (M), Бронкс и Бруклин (B), Стейтен Айленд (S) и Куинс (Q).

Затем я использую настройки Grafana, чтобы назначить цвет каждому маршруту:



Обратите внимание, что используется пять цветов один для каждого автобусного маршрута M, B, Q и S, а также один для маршрутов, которые не попадают в эти категории.

Стандартный дашборд сообщает нам о местонахождении автобусов в реальном времени. Мы мало что можем сделать, чтобы лучше исследовать данные, кроме увеличения и уменьшения числа маршрутов.

Давайте создадим переменную, которая определяет, какие автобусные маршруты мы отображаем на карте.

Шаг 1. Создаем переменную как запрос


Наша цель создать переменную, которая управляет автобусами, отображаемыми в дашборде, на основе маршрута автобуса.

Для простоты давайте определим четыре типа автобусных маршрутов: M, B, Q и S.

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

Чтобы создать новую переменную, зайдите в настройки панели инструментов Grafana, перейдите к параметру Переменная в боковом меню и нажмите кнопку Добавить переменную.

В этом случае мы используем тип Query, где наша переменная будет определена как результат запроса SQL.


Как создать переменную типа Query

В разделе General мы назовем нашу переменную route. Затем мы присвоим ей метку MTA Bus Route.


Имя, метка и тип нашей переменной route

Метки в Grafana это удобочитаемые дескрипторы, которые отображаются рядом с выпадающим меню в дашборде:



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

Затем напишем запрос, который определяет значение переменной, в разделе Query options.


Настройки для создания переменной route

Нам нужно выбрать источник данных для нашей переменной им будет база данных, в которой будет выполняться запрос. В этом случае мы используем MTA Bus DB, базу данных PostgreSQL, в которой хранятся наши данные MTA Bus.

Теперь мы определим SQL-запрос, результаты которого будут определять нашу переменную route:

SELECT * from (values ('M'),('B'),('Q'),('S')) v;

Этот запрос возвращает буквы M, B, Q, S которые являются типами маршрутов на основе их route_id (для понимания см. запрос SQL в разделе предварительных требований).

Можно использовать более продвинутый запрос, который дает дополнительное преимущество в виде удобочитаемых имен, а не использование символов или аббревиатур:

SELECT k AS "__text", v AS "__value" FROM (VALUES ('Manhattan', 'M'),('Bronx/Brooklyn', 'B'), ('Queens', 'Q'), ('Staten Island', 'S')) v(k, v);

Мы определяем четыре пары ключ-значение как набор возможных значений для нашей переменной маршрута, где ключ это читабельное имя маршрута, а значение буква, соответствующая типу маршрута:

  1. Напомним, что эта переменная также могла иметь тип Custom, поскольку у нас есть статический список значений, который никогда не изменяется, что позволяет задавать значения напрямую, без необходимости указывать их через SQL.
  2. Однако если нужно отображение ключ/значение, чтобы отображать как символы, так и понятные человеку имена, требуется запрос SQL. Я использовал SQL-запрос, поскольку на практике часто нужно, чтобы переменные принимали значения, которые не жестко запрограммированы, а изменяются в зависимости от данных в базе данных, таких как имена клиентов, имена кластеров и так далее.

Теперь давайте определим, как использовать нашу переменную.

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

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

Внизу, в разделе Предварительный запрос, можно увидеть предварительный набор результирующих значений. В нашем случае у нас есть Все, M, B, Q, S (то есть, наши четыре отдельных автобусных маршрута и опция Выбрать все).


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

Шаг 2: Измените запрос для построения графиков с учетом новой переменной


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

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

Вот модифицированный запрос:

SELECT max(time) as "time", vid AS "vehicle_id", route_id, CASE WHEN route_id LIKE 'M%' THEN 1      WHEN route_id LIKE 'B%' THEN 2      WHEN route_id LIKE 'Q%' THEN 3      WHEN route_id LIKE 'S%' THEN 4      ELSE 0  END AS "color", ST_X(geom) AS "longitude", ST_Y(geom) AS "latitude"FROM mta WHERE time > now()-interval '1.5 minutes'AND substring(route_id,1,1) IN ($route)GROUP BY vid, route_id, geomORDER BY 1;

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

SELECT...WHERE time > now()-interval '1.5 minutes'AND substring(route_id,1,1) IN ($route)

Эти строки говорят, что наша визуализация отображается только, если первая буква ее route_id находится в наборе разрешенных маршрутов (выбирается пользователем с помощью раскрывающегося списка, определяемого переменной маршрута). Значения, выбранные в списке, будут определять нашу переменную $route.

Например:

  1. Если пользователь выбирает все маршруты, то route = (M, B, S, Q), набор всех возможных типов маршрутов.
  2. Если пользователь выбирает только маршруты M и B, то route = (M, B). Мы автоматически отфильтровываем маршруты S и Q и отображаем только автобусы с route_id, начинающимся с M и B.

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

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


Наш новый интерактивный дашборд, где карта обновляется на основе маршрутов, которые мы выбираем в выпадающем меню

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

Мы успешно создали интерактивный дашборд Grafana с использованием переменных.

Успехов!

Что еще почитать по теме:

  1. Подборка из 90+ полезных инструментов Kubernetes.
  2. Наблюдаемость SRE: пространство имен и структура метрик.
  3. Наш канал Вокруг Kubernetes в Телеграме.
Подробнее..

Перевод Минимизируем наложение лейблов в интерактивных визуализациях

28.07.2020 14:05:45 | Автор: admin

Перевод статьи подготовлен в преддверии старта курса Промышленный ML на больших данных. Интересно развиваться в данном направлении? Смотрите записи трансляций бесплатных онлайн-мероприятий: День Открытых Дверей, Вывод ML моделей в промышленную среду на примере онлайн-рекомендаций.





Визуализация новых случаев заражения COVID-19 по дням для каждого штата США без алгоритма позиционирования лейблов


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


Моя визуализация 91-DIVOC пандемии COVID-19 позволяет пользователям получить самые последние данные о коронавирусе из Университета Джона Хопкинса с помощью интерактивной визуализации, построенной на библиотеке d3.js. Поскольку визуализация использует данные, которые обновляются несколько раз в день, а пользователи имеют возможность изучать данные и создавать более миллиона различных визуализаций, все должно рендериться программно.


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


  • Линий может быть много, и они все могут заканчиваться в одной точке.
  • Некоторые линии важнее, чем другие. В визуализации 91-DIVOC пользователь может выделить одну или несколько стран, тогда линия станет темнее и толще, а лейбл увеличится в размерах.
  • Большинство пользователей используют мобильные устройства, что ограничивает вычислительные ресурсы.

Без использования алгоритма позиционирования лейблов, визуализация новых случаев COVID-19 выводит несколько нечитаемых выделенных лейблов и еще более нечитаемых невыделенных.


Популярный подход: Силовые алгоритмы визуализации графов



Этапы моделирования силового алгоритма размещения лейблов на трех лейблах. На третьем этапе лейблы Mississippi и Virginia наконец разделились.


Распространенный подход к решению проблемы позиционирования лейблов это компонент force в d3.js, который реализует force-directed граф. Force-directed граф это модель, основанная на физике, в которой у всех элементов есть сила притяжения и отталкивания относительно других элементов. Если говорить об алгоритмах позиционирования лейблов, то у каждого элемента появляется небольшая сила отталкивания от других элементов, в результате чего симуляция отталкивает элементы друг от друга, когда это возможно, создавая читаемые лейблы. Когда в результате моделирования симуляция достигает стабильного конечного состояния, итог получается довольно хорошим, поэтому такой подход признан вполне рабочим.


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


Быстрое решение: Render или Nudge


Меня постигла неудача с force-directed графами, которые оказались слишком медленными. Нужно было, чтобы время выполнения любого решения было минимальным. Дабы сэкономить время на позиционирование одного лейбла, размещение каждого из них сводилось к решению render или nudge:


  1. Если в данный момент в области не отображается ни один лейбл, отрендерите его. Такое решение сработает незамедлительно, а местоположение не будет изменено.
  2. Если другой лейбл, который был отрендерен раньше, теперь перекрывается новым лейблом, подтолкните (nudge) его, чтобы попробовать найти позицию получше.


Стратегия позиционирования лейблов Render или Nudge, показанная на примере трех меток, где подталкивается лейбл Mississippi


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


Если лейблы просматриваются единожды, то алгоритм выполняется за линейное время O(n) и будет отнесен к жадным алгоритмам позиционирования лейблов.


Результат


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



Визуализация количества заражений COVID-19 в день для каждого штата США с позиционированием лейблов по стратегии render или nudge


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


(Кстати, мою визуализацию с этим алгоритмом позиционирования лейблов вы можете посмотреть тут: 91-DIVOC #01: An interactive visualization of the exponential spread of COVID-19)




Узнать подробнее о курсе Промышленный ML на больших данных



Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru