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

Open source

CrowdSec современная альтернатива Fail2Ban и коллективный иммунитет для Интернета

16.11.2020 12:07:26 | Автор: admin

CrowdSec

Инструмент Fail2Ban хорошо известен админам. Программа анализирует логи на сервере и подсчитывает количество попыток доступа с конкретных IP-адресов по указанным протоколам. В случае нарушения правила данный IP-адрес блокируется на заданный отрезок времени. Например, джейл для авторизации по SSH включён с дефолтными настройками 5 попыток авторизации за 10 минут, после чего происходит бан IP-адреса на 10 минут. Отличный способ отфильтровать мусорный трафик от разных сканеров и защита от DDoS.

Fail2Ban и SSHGuard лучшие инструменты в своей области. Однако новый опенсорсный проект CrowdSec представляется интересной альтернативой. Это локальная замена Fail2Ban, а потенциально нечто большее глобальная база репутации IP-адресов типа иммунной системы интернета.

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



Разработчики CrowdSec называют следующие ключевые особенности:

  • обнаружение атак и реагирование на всех уровнях (логи могут лежать в любом месте);
  • простота в установке и обслуживании (установка с визардом в консоли);

    git clone https://github.com/crowdsecurity/crowdsec/releases/latest
    

    sudo ./wizard.sh -i
    


    Установка CrowdSec. Визард в консоли помогает выбрать и предлагает, какие демоны/логи нужно мониторить, хотя возможна и последующая настройка через обычные конфиги
  • интеграция с другими компонентами (чтение логов и автоматическая блокировка нарушителей на уровне CDN);
  • общий доступ (опционально): метаданные можно отправлять в центральный API, так что данные о вредоносных IP-адресах получат все пользователи. Нужно подчеркнуть, что это опциональная фича, и никто не заставляет передавать метаданные в общий доступ;
  • лёгкий вес: автономная работа, минимум оперативной памяти и CPU;
  • возможность обработки холодных логов (из архива) для своеобразной симуляции;
  • предустановленные панели мониторинга.

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

Ещё один интересный момент инструмент написан на языке программирования Go.

С архитектурной точки зрения система состоит из трёх основных компонентов:

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

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



На данный момент разработано пять модулей интеграции (bouncers):
cs-cloudflare-blocker, cs-custom-blocker (пользовательские сценарии), cs-netfilter-blocker, cs-nginx-blocker и cs-wordpress-blocker. Например, модуль для Nginx сверяет каждый неизвестный IP-адрес с базой данных, прежде чем веб-сервер ответит на запрос или выдаст ошибку 403. Модуль Netfilter просто добавляет вредоносные IP-адреса в чёрный список nftables/ipset.

Для простоты настройки на сайте собраны коллекции и конфигурации.

Коллекции это, по сути, просто наборы парсеров и сценариев для разных ситуаций. Например, в коллекцию Nginx входит парсер логов nginx-logs и базовые http-сценарии для определения типичных вредоносных ботов (агрессивный краулинг, сканирование/пробирование портов, чёрный список user-agent'ов, а также определение попыток проведения атаки path traversal).

Полный список коллекций:


Один из вариантов работы с CrowdSec через консольную программу cscli:

cscli metrics

Эта команда выдаёт основные метрики о работе парсеров, объёме обработанных логов, количестве обнаруженных и заблокированных угроз по каждой коллекции (перечень коллекций см. выше).

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

cscli ban list



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

Но кроме cscli, конфигурацию можно изменить и традиционным способом, путём редактирования текстового файла в формате YAML:

vi /etc/crowdsec/config/profiles.yaml

Естественно, кастомные сценарии тоже поддерживаются.

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

Сейчас компания пытается предложить пользователям платный доступ к облачному API и базе данных с репутацией IP-адресов, которая составляется совместными усилиями. При этом поставщики информации в эту базу освобождаются от оплаты, а платят только чистые потребители, которые не хотят делиться информацией из своих логов. Планируется два тарифных плана: premium и enterprise с услугами по поддержке, специальными служебными инструментами (типа развёртывания системы на несколько локаций из одного центрального места), применением дата-майнинга и машинного обучения (обнаружение тенденций в глобальных данных), более продвинутом анализе холодных логов (форензика, криминалистика, расследования хотя данное направление бизнеса в Европе затруднено из-за закона GDPR).

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



Разработчики обращают внимание, что программа пока в бета-версии, но никаких проблем на продакшне ни у кого не возникало. Они также говорят, что программа на Go элементарно портируется на другие платформы вроде Windows и Mac.

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



На правах рекламы


Виртуальные серверы с защитой от DDoS-атак и новейшим железом, серверы размещены в одном из лучших российских дата-центров DataPro. Всё это про наши эпичные серверы. Максимальная конфигурация 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe! Поспешите заказать.

Подробнее..

Перевод bdshemu эмулятор шелл-кода в Bitdefender

16.11.2020 16:04:47 | Автор: admin
Совсем скоро, 19 ноября, у нас стартует курс Этичный хакер, а специально к этому событию мы подготовили этот перевод о bdshemu написанном на языке C эмуляторе с открытым исходным кодом в Bitdefender для обнаружения эксплойтов на 32- и 64-битной архитектуре. Эмулятор очень прост, а благодаря нацеленности на уровень инструкций он работает с любой операционной системой. Кроме того, этот эмулятор зачастую сохраняет расшифрованный эксплойт в бинарный файл. Подробности и пример обнаружения Metasploit под катом, ссылка на репозиторий проекта на Github в конце статьи.





Введение


Обнаружение эксплойтов одна из основных сильных сторон Hypervisor Memory Introspection (HVMI). Возможность мониторинга гостевых страниц физической памяти на предмет различных видов доступа, таких как запись или выполнение, позволяет HVMI накладывать ограничения на критические области памяти: например, страницы стека или кучи могут быть помечены как невыполняемыми на уровне EPT, поэтому, когда эксплойту удается получить доступ к произвольному выполнению кода, вмешивается логика интроспекции и блокирует выполнение шелл-кода.

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

В этом посте поговорим об эмуляторе Bitdefender Shellcode Emulator, или, для краткости, bdshemu. Это библиотека, способная эмулировать базовые инструкции x86, наблюдая при этом похожее на шелл-код поведение. Легальный код например JIT-код будет выглядеть иначе, чем традиционный шелл-код, bdshemu пытается определить, ведёт ли себя код в эмуляции, как шелл-код.

Обзор bdshemu


bdshemu библиотека на C, частью проекта bddisasm (и, конечно же, она использует bddisasm для расшифровки инструкций). Библиотека bdshemu создана только для эмуляции кода x86, поэтому не имеет поддержки вызовов API. На самом деле, среда эмуляции сильно ограничена и урезана, доступны только две области памяти:

  1. Содержащие эмулируемый код страницы.
  2. Стек.

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

Хотя bdshemu предоставляет основную инфраструктуру для обнаружения шелл-кодов внутри гостевой операционной системы, стоит отметить, что это не единственный способ, которым HVMI определяет, что выполнение определённой страницы является вредоносным. Используются ещё два важных индикатора:

  1. Выполняемая страница находится в стеке это обычное дело для уязвимостей на основе стека.
  2. Подделка стека когда страница выполняется впервые, а регистр RSP указывает за пределы выделенного для потока обычного стека.

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

Архитектура bdshemu


bdshemu создаётся как отдельная библиотека C и зависит только от bddisasm. Работать с bdshemu довольно просто, поскольку у этих двух библиотек имеется общий API:

SHEMU_STATUSShemuEmulate(    SHEMU_CONTEXT *Context    );

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

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

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

  1. Входные регистры, такие как сегменты, регистры общего назначения, регистры MMX и SSE; их можно оставить в значении 0, если они неизвестны или не актуальны.
  2. Входной код, то есть код для эмуляции.
  3. Входной стек, который может содержать фактическое содержимое стека, или может быть оставлен со значением 0.
  4. Информация о среде, например режим (32 или 64 бита) или кольцо (0, 1, 2 или 3).
  5. Параметры управления: минимальная длина строки стека, минимальная длина цепочки NOP или максимальное количество инструкций, которые должны быть эмулированы.

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

bdshemu построен как быстрый и простой эмулятор инструкций x86. Поскольку он работает только с самим шелл-кодом и небольшим виртуальным стеком, ему не нужно имитировать какие-то архитектурные особенности прерывания или исключения, таблицы дескрипторов, таблицы страниц. Кроме того, поскольку мы имеем дело только с шелл-кодом и стековой памятью, bdshemu не выполняет проверку доступа к памяти потому, что не разрешает доступ даже к другим адресам. Единственное состояние, кроме регистров, к которому можно получить доступ, это сам шелл-код и стек, и они оба копии фактического содержимого памяти. То есть состояние системы никогда не изменяется во время эмуляции, изменяется только предоставленный SHEMU_CONTEXT. Это делает bdshemu чрезвычайно быстрым, простым и позволяет сосредоточиться на его основной цели: обнаружении шелл-кода.

Что касается поддержки инструкций, bdshemu поддерживает все основные инструкции x86, такие как ветвления, арифметика, логика, сдвиг, манипуляции с битами, умножение и деление, доступ к стеку и инструкции передачи данных. Кроме того, он также поддерживает другие инструкции, например, некоторые базовые инструкции MMX или AVX. Два хороших примера PUNPCKLBW и VPBROADCAST.

Методы обнаружения bdshemu


Есть несколько индикаторов, которые использует bdshemu. Чтобы определить, ведёт ли себя эмулируемый фрагмент кода как шелл-код.

NOP Sled


Это классическое представление шелл-кода; поскольку точка его входа при выполнении может быть неизвестна точно, злоумышленники обычно добавляют длинную последовательность инструкций NOP, закодированную 0x90. Параметры длины последовательностей NOP можно контролировать при вызове эмулятора через контекстное поле NopThreshold. Значение SHEMU_DEFAULT_NOP_THRESHOLD по умолчанию равно 75. Это означает, что минимум 75 % всех эмулируемых инструкций должны быть инструкциями NOP.

RIP Load


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

  1. CALL $ + 5/POP ebp выполнение этих двух инструкций приведёт к тому, что значение указателя инструкции сохранится в регистре ebp; затем можно получить доступ к данным внутри шелл-кода, используя смещения относительно значения ebp
  2. FNOP/FNSTENV [esp-0xc]/POP edi первая инструкция это любая инструкция FPU (не обязательно FNOP), а вторая инструкция FNSTENV сохраняет среду FPU в стеке; третья инструкция получит указатель инструкции FPU из esp-0xc, который является частью среды FPU и содержит адрес последнего выполненного FPU в нашем случае FNOP. С этого момента для доступа к данным шелл-кода можно использовать адресацию относительно edi
  3. Внутренне bdshemu отслеживает все экземпляры указателя инструкции, сохранённые в стеке. Последующая загрузка указателя инструкции из стека каким-либо образом приведёт к срабатыванию этого обнаружения. Благодаря тому, что bdshemu отслеживает сохранённые указатели инструкций, не имеет значения, когда, где и как шелл-код пытается загрузить регистр RIP и использовать его: bdshemu всегда будет запускать обнаружение.

В 64-битном режиме относительная адресация RIP может использоваться напрямую: это позволяет кодировка инструкций. Однако, как ни странно, большое количество шелл-кода по-прежнему использует классический метод получения указателя инструкций (обычно технику CALL/POP), но, вероятно, указывает на то, что 32-битные шелл-коды были перенесены на 64-битные с минимальными изменениями.

Запись шелл-кода самим шелл-кодом


Чаще всего шелл-код закодирован или зашифрован, чтобы избежать некоторых плохих символов (например 0x00, который должен напоминать строку, может сломать эксплойт), или чтобы избежать обнаружения технологиями безопасности например, AV-сканерами. Это означает, что во время выполнения шелл-код должен декодировать себя обычно на месте изменяя свое собственное содержимое, а затем выполняя текстовый код. Типичные методы декодирования включают алгоритмы дешифрования на основе XOR или ADD.

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

Доступ к TIB


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

  1. Блок среды потока (TEB), который расположен в fs: [0] (32-битный поток) или gs: [0] (64-битный поток).
  2. Блок среды процесса (PEB), который расположен по адресу TEB + 0x30 (32 бит) или TEB + 0x60 (64 бит).
  3. Информация о загрузчике (PEB_LDR_DATA), расположенная внутри PEB.


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

При каждом обращении к памяти bdshemu увидит, пытается ли предполагаемый шелл-код получить доступ к полю PEB внутри TEB. bdshemu отслеживает обращения к памяти, даже если они выполняются без классических префиксов сегментов fs/gs до тех пор, пока идентифицирован доступ к полю PEB внутри TEB, будет срабатывать обнаружение доступа к TIB.

Направленный вызов SYSCALL


Легитимный код будет полагаться на несколько библиотек для вызова служб операционной системы например для создания процесса в Windows обычный код будет вызывать одну из функций CreateProcess. Легитимный код редко вызывает SYSCALL напрямую, поскольку интерфейс SYSCALL со временем может измениться. По этой причине bdshemu запускает обнаружение SYSCALL всякий раз, когда обнаруживает, что предполагаемый шелл-код напрямую вызывает системную службу с помощью инструкций SYSCALL, SYSENTER или INT.

Строки стека


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

push 0x6578652Epush 0x636C6163

В приведённом выше коде в стеке сохраняется строка calc.exe, которую затем можно использовать как обычную строку во всем шелл-коде.

Для каждого сохранённого в стеке значения, напоминающего строку, bdshemu отслеживает общую длину созданной в стеке строки. Как только порог, указанный полем StrLength внутри контекста, будет превышен, будет запущено обнаружение строки стека. Значение по умолчанию для этого поля SHEMU_DEFAULT_STR_THRESHOLD равно 8. Это означает, что динамическое построение строки длиной не менее 8 символов в стеке вызовет это обнаружение.

Методы обнаружения для шелл-кода режима ядра


Хотя вышеупомянутые методы общие и могут применяться к любому шелл-коду, в любой операционной системе, как в 32-, так и в 64-битной версии (за исключением обнаружения доступа к TIB, которое специфично для Windows) bdshemu может определять специфичное для ядра поведение шелл-кода.

Доступ KPCR


Область управления процессором ядра (KPCR) это структура для каждого процессора в системах Windows, которая содержит много критически важной для ядра информации, но также может быть полезной для злоумышленника. Обычно шелл-код может ссылаться на текущий выполняющийся поток, который можно получить, обратившись к структуре KPCR, со смещением 0x124 в 32-битных системах и 0x188 в 64-битных системах. Так же, как и в методе обнаружения доступа к TIB, bdshemu отслеживает обращения к памяти, и когда эмулируемый код считывает текущий поток из KPCR, он запускает обнаружение доступа к KPCR.

Выполнение SWAPGS


SWAPGS это системная инструкция, которая выполняется только при переходе из пользовательского режима в режим ядра, и наоборот. Иногда, из-за специфики определенных эксплойтов ядра злоумышленнику в конечном счёте нужно выполнить SWAPGS например, полезная нагрузка ядра EternalBlues, как известно, перехватывает обработчик SYSCALL, поэтому нужно выполнить SWAPGS, когда состоялся SYSCALL, подобно тому, как это сделал бы обычный системный вызов.

bdshemu запускает обнаружение SWAPGS всякий раз, когда инструкция SWAPGS выполняется подозрительным шелл-кодом.

Чтение и запись MSR


Иногда шелл-код (например вышеупомянутая полезная нагрузка ядра EternalBlue) должен изменить обработчик SYSCALL, чтобы перейти в стабильную среду выполнения (например, потому что исходный шелл-код выполняется в высоких значениях диапазона IRQL, которые необходимо снизить перед вызовом полезных подпрограмм). Это делается путём изменения MSR SYSCALL с помощью инструкции WRMSR, а затем ожидания выполнения системного вызова (который находится на более низком уровне IRQL) для продолжения выполнения (здесь также пригодится метод SWAPGS потому, что на 64-битной версии SWAPGS должна выполняться после каждого SYSCALL).

Кроме того, чтобы найти образ ядра в памяти и, следовательно, полезные процедуры ядра, быстрый и простой способ запросить SYSCALL MSR (которая обычно указывает на обработчик SYSCALL внутри образа ядра), а затем пройти по страницам назад, пока не будет найдено начало образа ядра.

bdshemu будет запускает обнаружение доступа MSR всякий раз, когда подозрительный шелл-код обращается к MSR SYSCALL, (как в 32-, так и в 64-битном режиме).

Пример


Проект bdshemu содержит несколько синтетических тестовых примеров, но лучший способ продемонстрировать его функциональность использовать реальный шелл-код. В этом отношении Metasploit замечателен в создании разных видов полезной нагрузки с использованием всех видов кодировщиков. В качестве чисто дидактического [прим. перев. назидательного] примера возьмём такой код:

DA C8 D9 74 24 F4 5F 8D 7F 4A 89 FD 81 ED FE FFFF FF B9 61 00 00 00 8B 75 00 C1 E6 10 C1 EE 10 83 C5 02 FF 37 5A C1 E2 10 C1 EA 10 89 D3 09 F3 21 F2 F7 D2 21 DA 66 52 66 8F 07 6A 02 03 3C 24 5B 49 85 C9 0F 85 CD FF FF FF 1C B3 E0 5B 62 5B 62 5B 02 D2 E7 E3 27 87 AC D7 9C 5C CE 50 45 02 51 89 23 A1 2C 16 66 30 57 CF FB F3 9A 8F 98 A3 B8 62 77 6F 76 A8 94 5A C6 0D 4D 5F 5D D4 17 E8 9C A4 8D DC 6E 94 6F 45 3E CE 67 EE 66 3D ED 74 F5 97 CF DE 44 EA CF EB 19 DA E6 76 27 B9 2A B8 ED 80 0D F5 FB F6 86 0E BD 73 99 06 7D 5E F6 06 D2 07 01 61 8A 6D C1 E6 99 FA 98 29 13 2D 98 2C 48 A5 0C 81 28 DA 73 BB 2A E1 7B 1E 9B 41 C4 1B 4F 09 A4 84 F9 EE F8 63 7D D1 7D D1 7D 81 15 B0 9E DF 19 20 CC 9B 3C 2E 9E 78 F6 DE 63 63 FE 9C 2B A0 2D DC 27 5C DC BC A9 B9 12 FE 01 8C 6E E6 6E B5 91 60 F2 01 9E 62 B0 07 C8 62 C8 8C

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



В disasmtool инструменте проекта bddisasm, для запуска эмулятора шелл-кода на входе можно воспользоваться параметром -shemu.

disasmtool -b32 -shemu -f shellcode.bin

Выполнение отобразит пошаговую информацию о каждой эмулируемой команде, но так как эта трассировка длинная, давайте перейдем непосредственно к концу if:

Emulating: 0x0000000000200053 XOR       eax, eax        RAX = 0x0000000000000000 RCX = 0x0000000000000000 RDX = 0x000000000000ee00 RBX = 0x0000000000000002        RSP = 0x0000000000100fd4 RBP = 0x0000000000100fd4 RSI = 0x0000000000008cc8 RDI = 0x000000000020010c        R8  = 0x0000000000000000 R9  = 0x0000000000000000 R10 = 0x0000000000000000 R11 = 0x0000000000000000        R12 = 0x0000000000000000 R13 = 0x0000000000000000 R14 = 0x0000000000000000 R15 = 0x0000000000000000        RIP = 0x0000000000200055 RFLAGS = 0x0000000000000246Emulating: 0x0000000000200055 MOV       edx, dword ptr fs:[eax+0x30]Emulation terminated with status 0x00000001, flags: 0xe, 0 NOPs        SHEMU_FLAG_LOAD_RIP        SHEMU_FLAG_WRITE_SELF        SHEMU_FLAG_TIB_ACCESS

Мы видим, что последняя эмулированная инструкция MOV edx, dword ptr fs: [eax + 0x30] это инструкция доступа к TEB, но она также запускает эмуляцию, которая должна быть остановлена, поскольку это доступ за пределы памяти шелл-кода (вспомним, что bdshemu остановится при первом обращении к памяти вне шелл-кода или стека). Более того, этот небольшой шелл-код (сгенерированный с помощью Metasploit) вызвал 3 обнаружения в bdshemu:

  1. SHEMU_FLAG_LOAD_RIP шелл-код загружает RIP в регистр общего назначения, чтобы определить его позицию в памяти.
  2. SHEMU_FLAG_WRITE_SELF расшифровывает сам себя, а затем выполняет расшифрованные фрагменты.
  3. SHEMU_FLAG_TIB_ACCESS обращается к PEB, чтобы найти важные библиотеки и функции.


Этих срабатываний более чем достаточно, чтобы сделать вывод, что эмулируемый код, без сомнения, является шелл-кодом. Что еще более удивительно в bdshemu, так это то, что обычно в конце эмуляции память содержит расшифрованную форму шелл-кода. disasmtool достаточно хорош, чтобы сохранить память шелл-кода после завершения эмуляции: создаётся новый файл с именем shellcode.bin_decoded.bin, содержащий декодированный шелл-код. Давайте посмотрим на него:



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

Заключение


В этом посте мы представили эмулятор шелл-кода Bitdefender, который является важной частью технологии обнаружения эксплойтов HVMI. bdshemu построен для обнаружения индикаторов шелл-кода на уровне двоичного кода, без необходимости эмулировать сложные вызовы API, сложное расположение памяти или архитектурные объекты, такие как таблицы страниц, таблицы дескрипторов и т. д. bdshemu фокусируется на том, что имеет наибольшее значение, эмулируя инструкции и определяя шелл-код по поведению.

Благодаря своей простоте bdshemu работает с шелл-кодом, нацеленным на любую операционную систему: большинство методов обнаружения определены на уровне поведения инструкций, а не на высокоуровневом поведении (например на уровне вызовов API). Кроме того, он работает как с 32-битным, так и с 64-битным кодом, а также с кодом, специфичным для режимов пользователя или ядра.

Ссылка на Github

На тот случай если вы задумали сменить сферу или повысить свою квалификацию промокод HABR даст вам дополнительные 10 % к скидке указанной на баннере.

image



Рекомендуемые статьи


Подробнее..

Переведут ли госсофт на open source технологии возможности для развития этого тренда в США

22.11.2020 00:21:34 | Автор: admin

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

Unsplash / Ayrus HillUnsplash / Ayrus Hill

Развитие в кризис

В качестве мер противодействия Великой депрессии конца 1920-х первой половины 1930-х годов Франклин Рузвельт, ставший президентом на пике кризиса, принял новый курс, включавший множество законодательных актов и экономических инициатив. Наиболее заметные из них предусматривали строительство и ремонт шоссе, транспортной инфраструктуры, зданий общественных и государственных организаций по всей стране. Позже при участии Дуайта Эйзенхауэра из этих начинаний, вовремя задействовавших сотни тысяч безработных граждан, вырос знаменитый Interstate c межштатными автомагистралями, связавшими всю страну.

Модернизации сетевых коммуникаций скорее всего станет частью аналогичной большой антикризисной стройки, которая растянется на несколько десятилетий в США. Уже сейчас на нее планируют выделить до 1,5 миллиардов долларов.

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

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

Двигатель всего нового

Есть мнение, что с помощью повышенного внимания и поддержки open source технологий можно не только сократить расходы на проприетарный софт со стороны государства, но и мощнейшим образом стимулировать развитие всей технологической отрасли. Такую оценку высказал представитель бизнес-школы Гарварда в научной статье с обзором результатов внедрения подобных мер во Франции. Там всего за год добились роста доли организаций, использующих открытые решения, с 0,6 до 5,4%; повысили занятость в сфере информационных технологий с 6,6 до 14% и отметили косвенные эффекты вроде увеличения числа IT-стартапов с 9 до 18%.

Если говорить о рентабельности инвестиций в open source, то только для Apache этот показатель составил более 17%, не говоря о возможных оценках общего вклада в ВВП (таблица 1, стр. 29) за счет массового внедрения подобных технологий.

Эксперты предлагают учитывать и развивать такое влияние за счет косвенной поддержки контрибьюторов например, предоставлять им налоговый вычет. Законопроект, содержащий данную меру, а именно вычет в размере 200 долларов за расходы на разработку open source решений, выдвигают в Ассамблее штата Нью-Йорк ежегодно, начиная с 2009 года.

Unsplash / Markus WinklerUnsplash / Markus Winkler

Но пока существенного прогресса по этому вопросу не наблюдается. Более того, неизвестно, включат ли что-то в этом роде в новый законопроект по масштабному развитию инфраструктуры.

Что выделяет сообщество

В обсуждении этой темы на Hacker News заметили, что Федеральное правительство США постепенно открывает миру разработки, выполненные по его заказу. Этим занимаются сразу несколько агентств вроде GSA (General Services Administration), специального подразделения исполнительного офиса президента под названием US Digital Service и даже DARPA.

Еще резиденты HN поделились репозиториями нескольких лабораторий: в Ок-Ридже, Ливерморе, Ричленде, Аргоннской национальной лаборатории рядом с Чикаго и еще одной в штате Айдахо. Плюс вспомнили про один из старейших open source фондов в Европе NLnet.

В качестве опасений они выделили возможные проблемы со сложной отчетностью и ограничениями на участие иностранных граждан, которые могут возникнуть, если власти США все-таки решатся на прямое финансирование открытых проектов. Во-вторых в треде несколько раз указали на то, что подобная поддержка часто заканчивается разработкой всевдостандартов, а не заметными для общества прикладными проектами. Из отраслей, где последние действительно пригодились бы, пользователи Hacker News отметили образовательную нишу.

Unsplash / Annie SprattUnsplash / Annie Spratt

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


Дополнительное чтение в нашем блоге на Хабре:


Подробнее..

Новая функциональность в RESTinio и опять с помощью Cных шаблонов

12.11.2020 10:07:10 | Автор: admin

Увидело свет очередное обновление небольшой библиотеки для встраивания асинхронного HTTP-сервера в C++ приложения: RESTinio-0.6.12. Хороший повод рассказать о том, как в этой версии с помощью C++ных шаблонов был реализован принцип "не платишь за то, что не используешь".



Заодно в очередной раз можно напомнить о RESTinio, т.к. временами складывается ощущение, что многие C++ники думают, что для встраивания HTTP-сервера в современном C++ есть только Boost.Beast. Что несколько не так, а список существующих и заслуживающих внимания альтернатив приведен в конце статьи.


О чем речь пойдет сегодня?


Изначально библиотека RESTinio никак не ограничивала количество подключений к серверу. Поэтому RESTinio, приняв очередное новое входящее подключение, сразу же делала новый вызов accept() для принятия следующего. Так что если вдруг на какой-то RESTinio-сервер придет сразу 100500 подключений, то RESTinio не заморачиваясь постарается принять их все.


На такое поведение до сих пор никто не жаловался. Но в wish-list-е фича по ограничению принимаемых подключений маячила. Вот дошли руки и до нее.


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


Проблема


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


Проблема состояла в том, что в RESTinio есть две сущности: постоянно живущий объект Acceptor, который принимает новые подключения, и временно живущие объекты Connection, которые существуют пока соединение используется для взаимодействия с клиентом. При этом Acceptor порождает Connection, но далее Connection живет своей собственной жизнью и Acceptor ничего больше о Connection не знает. В том числе не знает когда Connection умирает.


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


Фактор "не платишь за то, что не используешь"


Итак, в Acceptor нужно добавить функциональность подсчета количества живых подключений, причем этот подсчет должен быть thread safe, если RESTinio работает в многопоточном режиме. А в Connection нужно добавить обратную ссылку на Acceptor, которая будет использоваться когда Connection разрушается.


Это дополнительные действия и дополнительные расходы. Пусть и небольшие, но если кто-то использует RESTinio в условиях, когда нет смысла ограничивать количество подключений, то зачем нести эти расходы? Правильно, незачем.


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


Решение


Ограничение на количество подключений включается/выключается через traits


Как и практически все остальное, включение connection_count_limiter-а в RESTinio осуществляется посредством свойств (traits) сервера. Для того, чтобы connection_count_limiter заработал нужно определить свой класс свойств, в котором должен быть статический constexpr член use_connection_count_limiter выставленный в true:


struct my_traits : public restinio::default_traits_t {   static constexpr bool use_connection_count_limiter = true;};

Если теперь задать максимальное количество параллельных подключений и запустить RESTinio-сервер с my_traits в качестве свойств сервера, то RESTinio начнет считать и ограничивать количество подключений:


restinio::run(   restinio::on_thread_pool<my_traits>(16)      .max_parallel_connections(1000u)      .request_handler(...));

Тут используется простой фокус: в предоставляемых RESTinio типах default_traits_t и default_single_thread_traits_t уже есть use_connection_count_limiter, который содержит значение false. Что означает, что connection_count_limiter работать не должен.


Если же пользователь наследуется от default_traits_t (или от default_single_thread_traits_t) и определяет use_connection_count_limiter в своем типе свойств, то пользовательское значение перекрывает старое значение от RESTinio. Но когда пользователь в своем типе свойств не определят свой собственный use_connection_count_limiter, то остается виден use_connection_count_limiter из базового типа.


Таким образом RESTinio ожидает, что в traits всегда есть use_connection_count_limiter. И в зависимости от значения use_connection_count_limiter уже определяются типы, которые реализуют подсчет количества соединений. Ну или ничего не делают, если use_connection_count_limiter равен false.


Что происходит, если пользователь задает use_connection_count_limiter=true?


Актуальный connection_count_limiter


Если пользователь задает use_connection_count_limiter со значением true, то в объекте Acceptor должен появится объект connection_count_limiter, который и будет заниматься подсчетом количества подключений и разрешением/запрещением вызова accept-ов.


Однако, тут нужно учесть, что RESTinio-сервер может работать в двух режимах:


  • однопоточном. Все, включая I/O и обработку принятых запросов, выполняется на одной единственной рабочей нити. В этом случае RESTinio не использует механизмов обеспечения thread safety. Соответственно, и connection_count_limiter-у незачем применять реальный mutex для защиты своих внутренностей;
  • многопоточном. И I/O, и обработка принятых запросов может выполняться на разных рабочих нитях. Например, RESTinio сразу запускается на пуле рабочих потоков, на котором выполняются I/O операции и работают обработчики запросов. Либо же RESTinio работает на одной рабочей нити, а реальная обработка запросов делегируется какой-то другой рабочей нити (пулу рабочих нитей). Либо же RESTinio работает на одном пуле рабочих нитей, а обработка запросов делегируется на другой пул рабочих нитей. В этом случае RESTinio задействует механизм strand-ов из Asio для обеспечения thread safety. А connection_count_limiter должен использовать mutex, чтобы не допустить порчи собственных данных когда его начнут дергать из разных нитей.

Поэтому реализация connection_count_limiter-а выполнена в виде шаблонного класса, который параметризуется типом mutex. А нужная реализация выбирается благодаря специализации шаблона:


template< typename Strand >class connection_count_limiter_t;template<>class connection_count_limiter_t< noop_strand_t >   :  public connection_count_limits::impl::actual_limiter_t< null_mutex_t >{   using base_t = connection_count_limits::impl::actual_limiter_t< null_mutex_t >;public:   using base_t::base_t;};template<>class connection_count_limiter_t< default_strand_t >   :  public connection_count_limits::impl::actual_limiter_t< std::mutex >{   using base_t = connection_count_limits::impl::actual_limiter_t< std::mutex >;public:   using base_t::base_t;};

Тип strand-а задается в traits, поэтому достаточно параметризовать connection_count_limiter_t типом traits::strand_t и автоматически получается либо версия для однопоточного, либо версия для многопоточного режимов.


Экземпляр connection_count_limiter-а теперь содержится в объекте Acceptor и Acceptor обращается к этому connection_count_limiter-у для того, чтобы узнать, можно ли делать очередной вызов accept. А connection_count_limiter либо разрешает вызвать accept, либо нет.


Объект connection_count_limiter получает уведомления от разрушаемых объектов Connection. Если connection_count_limiter видит, что вызовы accept были заблокированы, а сейчас появилась возможность возобновить прием новых подключений, то connection_count_limiter отсылает нотификацию Acceptor-у. И получив эту нотификацию Acceptor возобновляет вызовы accept.


А уведомления о разрушении объектов Connection к connection_count_limiter приходят благодаря объектам connection_lifetime_monitor, о которых речь пойдет дальше.


Актуальный connection_lifetime_monitor


В Acceptor-е есть connection_count_limiter который должен узнавать о моментах разрушения объектов Connection.


Очевидным решением было бы реализовать информирование connection_count_limiter-а прямо в деструкторе Connection. Но дело в том, что в RESTinio Connection может преобразовываться в WS_Connection в случае перевода соединения в режим WebSocket-а. Так что аналогичное информирование потребовалось бы делать и в деструкторе WS_Connection-а.


Дублировать же одну и ту же функциональность в двух разных местах не хотелось, поэтому задача информирования connection_count_limiter-а об исчезновении подключения была делегирована новому объекту connection_lifetime_monitor.


Это Noncopyable, но зато Movable объект, который создается внутри Connection. Соответственно, и разрушается он вместе с объектом Connection.


Если же Connection преобразуется в WS_Connection, то экземпляр connection_lifetime_monitor перемещается из Connection в WS_Connection. И затем разрушается уже вместе с владеющим WS_Connection.


Т.е. итоговая схема такая:


  • в Acceptor-е живет connection_count_limiter;
  • когда Acceptor принимает новое подключение, то вместе с новым Connection создается и новый экземпляр connection_lifetime_monitor;
  • когда Connection умирает, то разрушается и connection_lifetime_monitor;
  • умирающий connection_lifetime_monitor информирует connection_count_limiter о том, что количество соединений уменьшилось.

Если Connection преобразуется в WS_Connection, то ничего принципиально не меняется, просто актуальную информацию о живом соединении начинает держать у себя connection_lifetime_monitor из WS_Connection.


Подчеркнем, что connection_lifetime_monitor вынужден держать у себя внутри указатель на connection_count_limiter. Иначе он не сможет дернуть connection_count_limiter при своем разрушении.


Фиктивные connection_count_limiter и connection_lifetime_monitor


Выше было показано, что стоит за connection_count_limiter и connection_lifetime_monitor в случае, когда ограничение на количество подключений задано.


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


Тем не менее, внутри Acceptor-а все еще живет экземпляр connection_count_limiter, пусть даже и фиктивный. А внутри Connection (и WS_Connection) есть пустой connection_lifetime_monitor.


Можно было, конечно, попробовать упороться шаблонами по полной программе и постараться избавиться от присутствия пустого connection_lifetime_monitor в Connection. Но, имхо, наличие лишнего байта в Connection (WS_Connection) не стоит сложности кода, который позволяет от этого байта избавиться. Тем более, что в C++20 добавили атрибут no_unique_address, так что со временем эта проблема должна решиться гораздо более простым и наглядным способом. Впрочем, если для кого-то дополнительный байт в Connection это реальная проблема, то откройте Issue, будем ее решать :)


Выбор подходящих connection_count_limiter и connection_lifetime_monitor


После того, как появились актуальный и фиктивные реализации connection_count_limiter и connection_lifetime_monitor осталось научиться выбирать между ними в зависимости от содержимого traits. Делается это так:


template< typename Traits >struct connection_count_limit_types{   using limiter_t = typename std::conditional      <         Traits::use_connection_count_limiter,         connection_count_limits::connection_count_limiter_t<               typename Traits::strand_t >,         connection_count_limits::noop_connection_count_limiter_t      >::type;   using lifetime_monitor_t =         connection_count_limits::connection_lifetime_monitor_t< limiter_t >;};

Т.е. для того, чтобы получить актуальный тип connection_count_limiter-а достаточно написать что-то вроде:


typename connection_count_limit_types<traits>::limiter_t

Хранение ограничения на количество подключений в server_settings


Осталось рассмотреть еще один небольшой момент: параметры для RESTinio сервера хранятся в server_settings_t<Traits> и, по хорошему, надо бы сделать так, чтобы ограничение на количество подключений нельзя было задавать, если в traits use_connection_count_limiter выставлен в false.


Тут используется фокус, к которому мы уже прибегали раньше:


  • создается шаблонный тип, который должен использоваться в качестве примеси (mixin);
  • у этого шаблонного типа есть специализация для фиктивного connection_count_limiter-а;
  • этот шаблонный тип подмешивается в качестве базы в server_settings_t.

В самом же server_settings_t делается метод max_parallel_connections, который содержит внутри static_assert. Этот static_assert ведет к ошибке компиляции, если в Traits запрещено использовать ограничение на количество подключений. Такой подход, имхо, ведет к более понятным сообщениям об ошибках, нежели отсутствие метода max_parallel_connections когда use_connection_count_limiter равен false.


Вместо заключения


RESTinio продолжает развивается по мере наших сил и возможностей. Некоторые планы по дальнейшему развитию есть. Но как-то углубляться в них не хочется из-за суеверных соображений. Уж очень жизненным оказывается афоризм про озвучивание планов и Господа Бога. Такое ощущение, что он срабатывает в 99% случаев :)


Что можно точно сказать, так это то, что мы внимательно прислушиваемся к пожеланиям. Если вам чего-то не хватает в RESTinio, то расскажите нам об этом. Либо прямо здесь, в комментариях, либо на GitHub-е через Issues.


HTTP-клиент в RESTinio?


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


Тут все просто. Мы делали RESTinio под конкретные сценарии использования. И это были сценарии использования RESTinio для реализации HTTP-входа в C++ приложения. Клиент нам не был нужен.


Вероятно, реализация клиента в RESTinio может быть добавлена.


Вероятно.


С определенностью сложно сказать, т.к. эту тему мы никогда глубоко не прорабатывали. Если бы кто-то рискнул профинансировать эту работу, то можно было бы всерьез за реализацию клиента взяться. Но за собственный счет мы этот объем просто не поднимем. Поэтому HTTP-клиента в RESTinio нет.


Bonus track: Так Boost.Beast-ом ли единым?


Действительно очень часто на просторах Интернета на вопрос "А что есть в C++ для реализации HTTP-сервера" отвечают Boost.Beast. К моему удивлению часто все еще вспоминают CROW, который уже несколько лет как мертв.


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



Ну и не забудем про возможности фреймворка POCO.


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

Подробнее..

Open Source синтез речи SOVA

18.11.2020 00:09:51 | Автор: admin

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



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


Введение в задачу синтеза


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


Терминология

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


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


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


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


  1. Конкатенативный синтез (unit selection) заранее готовится база дифонов и полуфонов, которые потом склеиваются между собой. Недавнно на хабре как раз вышла статья о самом известном подобном синтезаторе на русском языке;
  2. Параметрический вычисление на основе текста набора акустических признаков, по которым генерируется аудио сигнал. Естественно, что самым популярным представителем параметрического метода являются нейронные сети.

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


  1. Популярная архитектура, хорошо справляющаяся со своей задачей. Её рекомендацией являлись, как минимум, её использование банком Тинькофф для своего чат-бота Олега (см. статью выше), а также неявные намёки на её использование у Яндекса.
  2. Конечно же ещё одной немаловажной причиной стало то, что NVIDIA любезно предоставила свою реализацию Tacotron 2 (репозиторий) с её же вокодером Waveglow (статья, репозиторий), и всё это на pytorch (мы симпатизируем ему больше, чем tensorflow и keras).

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


Так как сперва нашей задачей было обучение синтеза для русского языка, и собственным набором данных мы ещё не обзавелись, естественно, что для начала работы мы взяли единственный (на тот момент) приемлемый датасет для обучения синтеза на русском языке RUSLAN (прим. автора: есть подозрение, что это не имя диктора, а акроним от RUSsian LANguage).


Какие проблемы сразу же бросаются в глаза (в уши) при синтезе после обучения на оригинальном датасете с помощью кода NVIDIA:


  • Проскакивает случайная простановка ударений даже в тех словах, где ударение единственно возможное


Текст

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


Также попадается озвучка графем, а не фонем (синтез вместо синтэз)



Текст

Синтез речи это увлекательно


  • Нестабильность механизма внимания (который занимается, грубо говоря, выявлением соответствия символов входного текста и фреймов мел-спектрограммы), особенно на длинных входных текстах. Такая нестабильность, а другими словами, разрыв линии внимания, как на картинке:


приводит к появлению различных артефактов в речи



Текст

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


  • Нестабильность срабатывания гейт слоя, генерирующего сигнал об окончании генерации


Текст

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


  • Все предыдущие моменты касались движка синтеза (так мы называем Tacotron 2 у себя), а что касается самого датасета, то там можно отметить плохие условия записи диктора слышите это эхо?


Разберём, как мы боролись с каждым из этих пунктов.


Работы по улучшению


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


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


Данные


Вот тут-то нам и пригодился наш отдел разметчиков: чтобы проставить ударения, над текстом трудились 5 разметчиков в течение двух недель. Результат полностью размеченный ударениями датасет Руслан (ссылку см. ниже), который мы предоставляем сообществу для экспериментов. Но это касается только обучения, а что с инференсом? Тут всё просто: мы нашли словарь ударений (сначала аналог CMU dict для русского языка, а потом полную акцентуированную парадигму по А.А. Зализняку). Дальше нужно было подготовить код для использования этого словаря, и вуаля получаем контроль ударений для нашей системы синтеза.


Что касается более естественного озвучивания с помощью фонем, то мы рассматривали два репозитория для решения этой задачи: RusPhonetizer и russian_g2p. В итоге, первый не завёлся, второй оказался слишком медленным (0.24 секунды на предложение из 100 символов), а тут ещё и CMU словарь содержит не только ударения, но и фонетические записи слов, так что решили использовать его. Честно сказать, из-за отсутствия чёткого понимания, какие же всё-таки фонемы нужны, работа с этим словарём вылилась в обычную транслитерацию текста с периодически встречающейся редуцированной "о". Сейчас мы экспериментируем с фонетизатором на основе фонем из russian_g2p.


NLP-препроцессор


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


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

Документация к репозиторию пока что находится в разработке.


Примеры


Контроль ударений:



Текст

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



Текст

Тв+орог или твор+ог, к+озлы или козл+ы, з+амок или зам+ок.


Фонемы вместо графем:


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




Заодно приведём ещё пару синтезированных на open source модели примеров:



Текст

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



Текст

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



Текст

В чащах юга жил бы цитрус? Да, но фальш+ивый экземпляр!


Нестабильность механизма внимания


Решение этой проблемы потребовало изучения статей по теме и имплементацию методик, представленных в них. Вот что мы нашли:


  1. Diagonal guided attention (DGA) здесь идея простая: так как в синтезе, в отличие от машинного перевода, соответствие выходов энкодера и декодера последовательное, то есть система воспроизводит звуки по мере их появления в тексте, то давайте штрафовать матрицу внимания тем больше, чем больше она отступает от диагонального вида. Можно, конечно, возразить, а что если звук тянется и на линии внимания появляется полка, но мы решили не рассматривать подобные экстремальные случаи. В качестве бонуса получаем ускорение процесса схождения матрицы внимания;
  2. Pre-alignment guided attention в этой статье изложен более сложный подход: требуется с помощью стороннего инструмента (например, Montreal-Forced-Aligner) получить временные метки каждой фонемы на аудиозаписи и составить из них матрицу внимания, которая будет являться для системы целевой;
  3. Maximizing Mutual Information for Tacotron авторы статьи утверждают, что подобные артефакты в матрице внимания возникают из-за недостаточной связи декодера с текстом. Для укрепления этой связи вводится модуль примитивного предсказания текста из итоговой мел-спектрограммы (эдакая asr в миниатюре) и расчёт ошибки с помощью CTC. Также ускоряет сходимость матрицы внимания.

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



Текст

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


Как видите, на протяжении всей записи движок уверенно держал своё внимание: фраза не "разваливается", не возникает артефактов и мычания.


Нестабильность срабатывания гейт слоя


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


Эта проблема решается несколькими небольшими уловками:


  • Символ EOS вводится для каждого предложения, даже если у него в конце уже проставлен знак препинания из набора [., !, ?];
  • В конце каждой аудиозаписи добавляется небольшой участок тишины;
  • При расчёте функции потерь для гейт слоя нужно увеличить вес его положительных выходов, чтобы они играли бОльшую роль.

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


Некачественный датасет


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




Также стоит отметить, что в датасете немного почищена пунктуация, так как движок реагирует на неё весьма чувствительно.


Дополнительные эксперименты


После решения всех насущных вопросов встала задача улучшить и разнообразить звучание, придать ему изюминки. Любой знакомый с темой скажет Ок, посмотрите в сторону GST и VAE [ссылка раз, ссылка два], и мы посмотрели.


Введение в пайплайн GST, на субъективный слух автора, не давало каких-то особых запоминающихся изменений, пока мы не попробовали подход, описанный в Text predicted GST предлагается модели самой подбирать комбинацию стилистических токенов, чтобы добиться лучшего звучания для текущего текста. Для демонстрации работы этого модуля приведём аудио, полученные моделью, которая обучалась на датасете реплик персонажей из популярных зарубежных сериалов (актриса озвучки Екатерина). Уточним, что датасет изначально не предназначался для синтеза.




В общем, как и в жизни: главное найти подход к человеку.


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


Сложности VAE

Проблема posterior collapse (KL loss vanishing), характерная для вариационных моделей в сочетании с авторегрессионным декодером.


В начале обучения, декодер может отставать от вариацинного энкодера и научиться игнорировать неосмысленные латентные переменные, что приводит к почти нулевой ошибке KL для VAE (расстояние КульбакаЛейблера). Апостериорная оценка латентной переменной p(z|x) ослабевает и становится неотличимой от априорного Гауссовского шума p(z) ~ N(0, 1). Как следствие, вариационный энкодер не моделирует значимые свойства аудио и модель не предоставляет контроль над стилем и эмоцями речи.


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


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


SOVA


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


  • sova-tts-engine движок на базе Tacotron 2 от NVIDIA. Всё вышеперечисленное, за исключением text predicted GST и VAE, было опубликовано в этом репозитории, плюс проведён избирательный рефакторинг кода;
  • sova-tts-tps тот самый nlp-препроцессор;
  • sova-tts-vocoder практически не изменённый вокодер от NVIDIA, но всё-таки с отличиями;
  • sova-tts-binding пакет для связывания nlp-препроцессора, движка и вокодера в единый инференс-пайплайн. Реализован с прицелом на добавление новых движков и вокодеров;
  • sova-tts упакованный в докер стенд синтеза с простеньким GUI интерфейсом;
  • Почищенный датасет и веса Руслана (This work, "SOVA Dataset (TTS RUSLAN)", is a derivative of "RUSLAN: Russian Spoken Language Corpus For Speech Synthesis" by Lenar Gabdrakhmanov, Rustem Garaev, Evgenii Razinkov, used under CC BY-NC-SA 4.0. "SOVA Dataset (TTS RUSLAN)" is licensed under CC BY-NC-SA 4.0 by Virtual Assistant, LLC)
  • Датасет и веса Наталии ("SOVA Dataset (TTS Natasha)" is licensed under CC BY 4.0 by Virtual Assistant, LLC)

Наш SOVA TTS (весь код + модель и датасет Наталии) вы можете свободно использовать для коммерческих задач бесплатно.


Планы


Планы у нас грандиозные, а именно:


  1. Полноценный нормализатор текста для раскрытия чисел, аббревиатур и сокращений;
  2. Модуль для решения неоднозначностей в ударениях и словах с буквой ё;
  3. Добавление поддержки ssml;
  4. Дальнейшие эксперименты с VAE, получение контроля над отдельными словами и фонемами;
  5. Подготовка эмоционального синтеза, по возможности с контролем уровня эмоции;
  6. Мультидикторный синтез на одной модели;
  7. Новые голоса;
  8. Клонирование голоса;
  9. Возможный переход на более современные архитектуры типа Flowtron или FastSpeech2;
  10. Эксперименты с вокодерами: дообучение Waveglow, обучение LPCNet, тестирование MelGAN;
  11. Оптимизация архитектуры для работы в реальном времени на CPU.

На текущий момент мы продолжаем двигаться в сторону улучшения качества синтеза речи. Если то, что мы делаем, вам интересно пишите, можем посотрудничать. Как на коммерческих проектах, так и в Open Source.


Все наши наработки доступны тут: наш GitHub
Распознавание речи: SOVA ASR
Синтез речи: SOVA TTS


Спасибо за внимание, впереди еще много интересного!

Подробнее..

FOSS News 42 дайджест новостей и других материалов о свободном и открытом ПО за 9-15 ноября 2020 года

15.11.2020 18:09:06 | Автор: admin


Всем привет!

Продолжаем дайджесты новостей и других материалов о свободном и открытом ПО и немного о железе. Всё самое главное про пингвинов и не только, в России и мире. Госорганы России начали переход на Astra Linux; Canonical Group Limited представила финансовые показатели за 2019 г.; ВКонтакте снова выкладывает KPHP; обсуждение факторов, улучшающих инновационный потенциал организации; описание попытки использовать Raspberry Pi 4 в качестве десктопа; произвол HP и многое другое.

Оглавление


  1. Главное
    1. Госорганы России начали переход на Astra Linux
    2. Canonical Group Limited представила финансовые показатели за 2019 г.
    3. ВКонтакте снова выкладывает KPHP
    4. Открытые окружения это места, где процветают инновационные идеи
    5. Попытка использовать Raspberry Pi 4 в качестве десктопа
    6. Фонд EFF возмущен решением HP удалённо блокировать принтеры неплательщикам сервиса Бесплатные чернила на всю жизнь
  2. Короткой строкой
    1. Новости
      1. Мероприятия
      2. Новости FOSS организаций
      3. Специальное
      4. Безопасность
      5. DevOps
      6. Web
      7. Для разработчиков
      8. Железо
      9. Пользовательское
      10. Разное
    2. Статьи
      1. DIY
      2. Ядро и дистрибутивы
      3. Специальное
      4. Безопасность
      5. DevOps
      6. AI & Data Science
      7. Для разработчиков
      8. Менеджмент
      9. Пользовательское
      10. Разное
    3. Релизы
      1. Ядро и дистрибутивы
      2. Системное
      3. Специальное
      4. Мультимедиа
      5. Безопасность
      6. Web
      7. Для разработчиков
      8. Пользовательское
      9. Игры
      10. Разное
  3. Что ещё посмотреть


Главное



Госорганы России начали переход на Astra Linux



Категория: Новости/Внедрения



CNews пишет: В Ивановской области начался масштабный переход госорганов на отечественный софт. Как сообщил региональный Департамент развития информационного общества, 26 исполнительных органов госвласти (ИОГВ) перейдут на операционные системы семейства Astra Linux и другие отечественные программные продукты.

Подробности (1, 2)

Прошлые важные новости, связанные с Astra Linux:
  1. Росатом потратит 820 млн руб. на внедрение Astra Linux
  2. Группа компаний Astra Linux намерена инвестировать 3 млрд руб. в экосистему Linux
  3. МВД провело крупнейшую закупку ОС Astra Linux


Canonical Group Limited представила финансовые показатели за 2019 г.



Категория: Новости/Новости FOSS организаций



Linux.org.ru пишет: Canonical Group Limited представила документы за 2019 финансовый год в Регистрационную палату Великобритании. Их выручка в 2019 году составила 119 миллионов долларов США, по сравнению с 97 миллионами долларов в предыдущем году. Их убытки составили всего 2 миллиона долларов, что гораздо лучше, чем 11 миллионов долларов в 2018 году. Средняя численность персонала Canonical в 2019 году составила 473 человека по сравнению с 437 в предыдущем году. Несмотря на то, что они добавили еще около сорока сотрудников, это всё ещё меньше их численности в 500 с лишним человек до реструктуризации, когда они отказались от смартфонов и других проектов.

Подробности

ВКонтакте снова выкладывает KPHP



Категория: Новости/Открытие кода и данных



ВКонтакте пишет в своём блоге на Хабре: Мы снова выложили на GitHub наш PHP-компилятор KPHP. Он проделал большой путь, и чтобы рассказать о нём, сначала телепортируемся на шесть лет назад. Поясню для тех, кто не в теме: платформа ВКонтакте изначально была написана на PHP. Со временем нас перестала устраивать производительность, и мы решили ускорить VK. Сделали компилятор KPHP, который поддерживал узкое подмножество PHP. Это было давно, и с тех пор мы о нём не рассказывали, так как KPHP почти не развивался до 2018-го года. Но два года назад мы взялись за него, чтобы вдохнуть в эту разработку новую жизнь. Что сделали и какой получили результат расскажу в этой статье. Она будет не о громком релизе, который можно прямо сейчас внедрять в свои проекты, а о внутренней разработке ВКонтакте, которую мы показываем сообществу и продолжаем развивать.

Подробности

Открытые окружения это места, где процветают инновационные идеи



Категория: Статьи/Разное



Рон МакФарланд пишет на opensource.com: Определённые среды более благоприятны для инноваций. Лучшее понимание истинной природы инноваций может помочь нам в их создании. В первой статье этой серии я подробно рассмотрел природу инновационного процесса. Я также обсудил некоторые препятствия этому. В этой второй части моего обзора книги Мэтта Ридли Как работают инновации я объясню идеальную среду, в которой открытия зарождаются, защищаются и превращаются в полезные продукты и услуги, с учетом определенных необходимых условий для процветания инноваций. И я буду утверждать, что принципы открытой организации являются ключом к созданию этих условий.

Подробности (en)

Предыдущая статья серии Когда побеждают лучшие идеи, узнаем ли мы всех, кто их придумал? (en)

Попытка использовать Raspberry Pi 4 в качестве десктопа



Категория: Статьи/Пользовательское



DmitrySpb79 пишет в своём блоге на Хабре: С момента появления Raspberry Pi 4 стало значительно больше желающих использовать этот микрокомпьютер в качестве основного ПК. Вычислительная мощность Pi4 стала уже весьма неплохой, да и полноценный Linux на борту звучит многообещающе. Меня давно интересовала возможность использования портативного и бесшумного ПК для несложных задач вроде набора этого текста, где настоящий десктоп избыточен, а планшет неудобен. Я купил топовую модель Raspberry Pi 4 c 8 Гб памяти настала пора проверить, как это работает.

Часть 1, Raspbian

Часть 2, Ubuntu

Фонд EFF возмущен решением HP удалённо блокировать принтеры неплательщикам сервиса Бесплатные чернила на всю жизнь



Категория: Новости/Разное



Слабо относится к миру FOSS, скорее новость с того света. Linux.org.ru пишет: Правозащитная организация Фонд Электронных Рубежей (Electronic Frontier Foundation, EFF) выпустила обличительную статью о деятельности компании Hewlett-Packard. В ноябре 2020 года стало известно, что HP изменило линейку тарифных планов, и убрало бесплатную возможность печати 15 страниц в месяц по программе Instant Ink. Теперь, если пользователь не заплатит $0.99 в месяц, то его механически исправный и заправленный принтер будет отключен дистанционно. Наблюдается ситуация схожая со стриминговыми сервисами, только если там купленные вами данные вам по сути не принадлежат, то тут всё ещё хуже ваше железо уже вам не принадлежит.

Подробности

Короткой строкой



Новости



Мероприятия



  1. Ссылки по прошедшей конференции OS DAY 2020 []
  2. Митап Apache Kafka в вопросах и ответах 17 ноября в 19:00 []


Новости FOSS организаций



  1. Компания Mozilla представила движок распознавания речи DeepSpeech 0.9 []
  2. Google обязал применять инклюзивную терминологию в своих открытых проектах []
  3. По требованию Google заблокированы 135 репозиториев на GitHub []
  4. Android переходит на сборочную систему Bazel []


Специальное



WSL --install: добавлена нативная установка дистрибутивов в Windows 10 Insiders Preview build 20246 []

Безопасность



  1. В репозитории NPM выявлен вредоносный пакет discord.dll []
  2. Уязвимость в GDM, позволяющая получить привилегии root в Ubuntu []
  3. Новая атака Platypus на процессоры Intel и AMD []


DevOps



Linux Foundation и CNCF выпустили бесплатный курс о работе с Linkerd [ (en)]

Web



В Chrome намерены удалить поддержку технологии Server Push []

Для разработчиков



Си и Python сместили Java в рейтинге языков программирования Tiobe []

Железо



  1. В обновлении микрокода Intel выявлена проблема, приводящая к зависанию на системах Tiger Lake []
  2. System76 анонсировала обновленный Linux-ноутбук Galago Pro на новом Intel 11-го поколения []


Пользовательское



DigitalOcean теперь позволяет задеплоить Open Source приложение одной кнопкой []

Разное



  1. АПКИТ попросила вице-премьера перенести вступление в силу закона об обязательной предустановке отечественного софта []
  2. RIP Bill Morrow []
  3. Гвидо ван Россум вышел на работу в Microsoft [ 1, 2]


Статьи



DIY



  1. Станция для подкастинга на Raspberry Pi []
  2. Мониторинг качества воздуха с использованием Raspberry Pi 4, датчика Sensirion SPS30 и Microsoft Azure []


Ядро и дистрибутивы



  1. Подготовка к заморозке пакетной базы Debian 11. Объявлено кодовое имя Debian 13 []
  2. MuditaOS: красивая и минималистичная ОС для минималистичных телефонов [ (en)]
  3. Дистрибутив GNOME OS как платформа для тестирования GNOME приложений [ (en)]


Специальное



  1. Как дебажить запросы, используя только Spark UI []
  2. Обновления в смотрелке логов []
  3. Linux Switchdev по-мелланоксовски []
  4. Да, вам может понадобиться блокчейн []
  5. WireGuard без NAT, внутренняя сеть и клиенты с обратной связью []
  6. Танцуем с cl-build- []
  7. Виртуальная АТС. Часть 3: Переводим Asterisk на PjSIP без лишних телодвижений []
  8. Кунг-фу стиля Linux: мониторинг дисковой подсистемы []
  9. Балансировка трафика с HAProxy [ (en)]
  10. Об использовании Cockpit для управления серверами [ (en)]
  11. Об использовании Home Assistant для домашней автоматизации [ (en)]


Безопасность



  1. Атака NAT slipstreaming для отправки запросов на внутренний IP []
  2. Долой рутину расшифровки дисков, или использование сетевой разблокировки с помощью tang/clevis []


DevOps



  1. Создание шаблона VDS с Zabbix 5 на CentOS 8 []
  2. PostgreSQL на K8s в Zalando: два года в бою. Александр Кукушкин (Zalando) []
  3. Видеокурс Kubernetes База: что нового в версии 2.0? []
  4. Запускаем тесты на GitLab Runner с werf на примере SonarQube []
  5. Одна строка, которая ускорила клонирование в 100 раз []
  6. Как уменьшить количество обращений к DockerHub из инфраструктуры CI/CD при помощи кэширования образов Docker? []
  7. Пример развертывания Spring Boot-приложения в Kubernetes []
  8. Тестирование Ansible с использованием Molecule с Ansible в качестве верификатора []
  9. Все об OpenShift Egress. Часть 1 []
  10. Red Hat Advanced Cluster Management и управление приложениями, часть 1. Развертывание в нескольких средах []
  11. Пять рекомендаций по экспортёрам Prometheus для повышения производительности []
  12. Обзор операторов PostgreSQL для Kubernetes. Часть 2: дополнения и итоговое сравнение []
  13. Управление алертами с помощью Alerta.io []
  14. Современное состояние микросервисов [ (en)]
  15. Настройка Minishift и запуск Jenkins в Linux [ (en)]
  16. О различиях между оркестрацией и автоматизацией [ (en)]
  17. Как создать своё первое Knative приложение [ (en)]


AI & Data Science



  1. Краткий обзор системы Apache NlpCraft []
  2. Как подружить инженеров и дата-сайентистов с помощью одной библиотеки []
  3. Актуальные инструменты контроля версий данных в 2020 году []
  4. Как Open Source позволяет больше доверять ИИ [ (en)]


Для разработчиков



  1. Реализация epoll, часть 3 []
  2. Реализация epoll, часть 4 []
  3. Дополнительные компоненты для кроссплатформеннной библиотеки материального дизайна KivyMD []
  4. Linux-контейнеры в паре строчек кода []
  5. Типы, где их не ждали []
  6. О программировании микроконтроллера с помощью MicroBlocks [ (en)]


Менеджмент



  1. Как Open Source улучшает работу менеджера [ (en)]
  2. Об улучшении устойчивости Open Source сообщества с помощью двух метрик [ (en)]
  3. 3 способа как построить командную культуру вокруг Open Source [ (en)]
  4. Как увлечение Star Trek помогает в работе [ (en)]


Пользовательское



  1. Лучшие менеджеры паролей для Linux []
  2. 5 причин использовать Linux в 2020 году []
  3. Лёгкие приложения Linux для старого железа []
  4. ТОП 5 причин использовать Linux в 2020 []
  5. Сбор информации о системе Ubuntu []
  6. Установка Clear Linux []
  7. Как установить Fedora в VirtualBox (с USB, буфером обмена и разделяемыми папками) [ (en)]
  8. Как установить и использовать Etcher на Linux для созданияLive Linux USB [ (en)]
  9. Как установить Google Chrome на Fedora (руководство новичка) [ (en)]
  10. Quick Lookup: простое приложение-словарь, использующее Викисловарь [ (en)]
  11. Об использовании любимых Open Source приложений на macOS с помощью MacPorts [ (en)]
  12. Что хорошего есть в новом GNOME [ (en)]


Разное



  1. Для чего нужен Linux []
  2. Сборка Colobot Gold []
  3. Как появилась на свет программа youtube-dl []
  4. ISH Linux или возможно ли установить и использовать Linux на iOS []


Релизы



Ядро и дистрибутивы



  1. Выпуск атомарно обновляемого дистрибутива Endless OS 3.9 [ 1, 2]
  2. SparkyLinux 5.13. Релиз дистрибутива []
  3. Релиз дистрибутива MX Linux 19.3. Что нового []
  4. Представлен дистрибутив Proxmox Backup Server 1.0 []
  5. Образы Fedora 33 опубликованы в AWS Marketplace []
  6. Выпуск дистрибутива CentOS 7.9 []
  7. Компания Oracle выпустила ядро Unbreakable Enterprise Kernel R6U1 []
  8. Выпуск дистрибутива Clonezilla Live 2.7.0 []
  9. Доступен дистрибутив Oracle Linux 8.3 []


Системное



Доступен выпуск KDE Frameworks 5.76 []

Специальное



  1. Релизы Wine 5.19/20/21. Что нового []
  2. FontForge 20th Anniversary Edition []
  3. Релиз QVGE 0.6.1 (интеграция с GraphViz) []
  4. Новая версия Open CASCADE Technology (OCCT) 7.5.0 [ 1, 2]
  5. Frrouting 7.5 []
  6. Релиз Apache Ignite 2.9.0 что нового? []
  7. Опубликован стандарт параллельного программирования OpenMP 5.1 []
  8. Обновление PostgreSQL с устранением уязвимостей []


Мультимедиа



Доступен предварительный выпуск графического редактора GIMP 3.0 [ 1, 2]

Безопасность



Обновление Tor 0.3.5.12, 0.4.3.7 и 0.4.4.6 с устранением уязвимости []

Web



  1. Выпуск почтового клиента Mutt 2.0 [ 1, 2]
  2. Обновление Firefox 82.0.3 и Thunderbird 78.4.2 с устранением уязвимости []


Для разработчиков



  1. Вышел релиз GitLab 13.5 с обновлениями для безопасности мобильных приложений и вики-страницами групп []
  2. Релиз фреймворка для создания установщиков Calamares 3.2.33 []
  3. Релиз унифицированной платформы .NET 5 с поддержкой Linux и WebAssembly [ 1, 2]
  4. Новая функциональность в RESTinio и опять с помощью C++ных шаблонов []
  5. Выпуск cSvn 0.0.9, web-интерфейса для репозиториев Subversion []


Пользовательское



  1. Релиз среды рабочего стола LXQt 0.16.0. Что нового []
  2. Релиз KDE Plasma 5.20 и KDE Applications 20.08.3 [ 1, 2]
  3. Выпуск офисного пакета Apache OpenOffice 4.1.8 []
  4. Обновление Plasma Mobile: октябрь 2020 []


Игры



  1. Релиз авиасимулятора FlightGear 2020.3. Два года работы. Стабильный релиз []
  2. Компания Valve выпустила Proton 5.13-2, пакет для запуска Windows-игр в Linux []


Разное



  1. Новый выпуск Androwish, окружения для запуска приложений Tcl/Tk на системах с Android []
  2. Вышел релиз androwish The Flux Capacitor. []


Что ещё посмотреть



Видео от Пингвинус: Новости #28. Смартфон Pro1 X, что нового в LXQt, FlightGear []




На этом всё, до следующего воскресенья!

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

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

Подписывайтесь на наш Telegram канал, группу ВКонтакте или RSS чтобы не пропустить новые выпуски FOSS News.

Предыдущий выпуск
Подробнее..

FOSS News 43 дайджест новостей и других материалов о свободном и открытом ПО за 16-22 ноября 2020 года

22.11.2020 18:15:46 | Автор: admin


Всем привет!

Продолжаем дайджесты новостей и других материалов о свободном и открытом ПО и немного о железе. Всё самое главное про пингвинов и не только, в России и мире. В этом выпуске получилось особенно много важных материалов про мобильные устройства. PinePhone с KDE Plasma Mobile с возможностью использования в качестве десктопа; смартфон Librem 5 перешёл на стадию массового производства; началась кампания по сбору средств для производства смартфона с выдвижной клавиатурой Pro1 X; GitHub разблокировал youtube-dl и принял меры для исключения необоснованных блокировок; Ubuntu Web Remix (альтернатива Chrome OS с браузером Firefox вместо Google Chrome); как монетизируется Open-Source; переведут ли госсофт на open source технологии (возможности для развития этого тренда в США) и многое другое.

Оглавление


  1. Главное
  2. Короткой строкой
    1. Новости
      1. Мероприятия
      2. Новости FOSS организаций
      3. Мультимедиа
      4. Безопасность
      5. Web
      6. Пользовательское
      7. Железо
    2. Статьи
      1. DIY
      2. Ядро и дистрибутивы
      3. Системное
      4. Специальное
      5. Мультимедиа
      6. Безопасность
      7. DevOps
      8. Web
      9. Для разработчиков
      10. Менеджмент
      11. Пользовательское
      12. Железо
      13. Разное
    3. Релизы
      1. Ядро и дистрибутивы
      2. Системное
      3. Специальное
      4. Мультимедиа
      5. Безопасность
      6. Web
      7. Для разработчиков
      8. Пользовательское
      9. Разное
  3. Что ещё посмотреть


Главное



Представлен cмартфон PinePhone с KDE Plasma Mobile, который можно использовать как десктоп



Категория: Новости/Мобильные



OpenNET пишет: Сообщество Pine64 и проект KDE анонсировали скорое поступление в продажу редакции смартфона PinePhone KDE Community Edition, укомплектованной прошивкой с пользовательским окружением KDE Plasma Mobile. Редакция с KDE дополнит ранее выпускаемые варианты смарфтона, поставляемые с postmarketOS, UBports/Ubuntu Touch и Manjaro. Редакция смартфона PinePhone с KDE поступит в продажу 1 декабря и будет поставляться в вариантах с 2GB ОЗУ + 16GB eMMC и 3GB ОЗУ + 32GB eMMC + переходник USB Type-C для подключения к монитору (HDMI), сети (10/100 Ethernet), клавиатуре и мыши (два порта USB 2.0). Стоимость устройств составит 149 и 199 долларов.

Подробности (1, 2, 3, 4, 5)

Смартфон Librem 5 перешёл на стадию массового производства



Категория: Новости/Мобильные



OpenNET пишет: Компании Purism объявила о начале массового производства смартфона Librem 5, примечательного наличием программных и аппаратных средств для блокирования попыток отслеживания и сбора информации о пользователе. Смартфон предоставляет пользователю полный контроль над устройством и оснащён почти только свободным ПО, включая драйверы и прошивки. Как и в предыдущей новости, смартфон можно использовать как базу для своего рода настольного компьютера подключив смартфон к монитору получить типовой рабочий стол GNOME на базе единого набора приложений.

Основные характеристики, по данным издания:

  1. SoC i.MX8M c четырехъядерным CPU ARM64 Cortex A53 (1.5GHz), вспомогательным чипом Cortex M4 и GPU Vivante GC7000Lite с поддержкой OpenGL/ES 3.1, Vulkan и OpenCL 1.2.
  2. 5.7-дюймовый экран (IPS TFT) с разрешением 7201440.
  3. ОЗУ 3GB.
  4. встроенный Flash 32GB плюс слот microSD.
  5. Аккумулятор ёмкостью 4500mAh.


Подробности (1, 2, 3)

Кампания по сбору средств для производства Pro1 X, смартфона с выдвижной клавиатурой, совместимого с Ubuntu Touch и Android



Категория: Новости/Мобильные



OpenNET пишет: Английская компания F(x)tec в сотрудничестве с интернет-сообществом XDA проводит кампанию по привлечению средств в поддержку новой версии смартфона Pro1 с физической клавиатурой. Главной особенностью данного устройства заявлена поддержка ОС на выбор Android 9, Lineage OS 17, либо Ubuntu Touch. Для последней заявлена поддержка конвергенции возможности использования в качестве настольного ПК при подключении монитора, клавиатуры и мыши.

Основные характеристики, по данным издания:

  1. 5.99-дюймовый AMOLED дисплей разрешением 2160x1080.
  2. Процессор Qualcomm Snapdragon 835 MSM8998.
  3. Оперативная память 6 или 8 ГБ LPDDR4.
  4. Хранилище 128 или 256 ГБ, расширяемое до 2 ТБ картой microSD
  5. Аккумулятор 3200 mAh с возможностью быстрой зарядки.


Подробности

GitHub разблокировал youtube-dl и принял меры для исключения необоснованных блокировок



Категория: Новости/Новости FOSS организаций



OpenNET пишет: GitHub восстановил доступ к репозиторию проекта youtube-dl, который был заблокирован в прошлом месяце на основании жалобы от Ассоциации звукозаписывающих компаний Америки (RIAA), обвинившей разработчиков проекта в нарушении действующего в США Закона об авторском праве в цифровую эпоху (DMCA). Разработка youtube-dl возвращена на GitHub. Блокировка была снята после внесения разработчиками изменения, удаляющего упомянутые в жалобе RIAA тестовые загрузки. Напомним, что основной причиной блокировки стало наличие в youtube-dl кода для проверки корректности работы, использующего в тестовых загрузках материалы, авторские права на которые принадлежат участникам RIAA.

Подробности (1, 2)

Ubuntu Web Remix альтернатива Chrome OS с браузером Firefox вместо Google Chrome



Категория: Новости/Ядро и дистрибутивы



Компания Selectel в своём блоге на Хабре пишет: Хромбуки популярные устройства, продажи которых постепенно растут. Причин тому несколько они недорогие, относительно универсальные и отлично подходят для учебы или работы, включая дистанционный режим. В итоге в третьем квартале этого года продажи Хромбуков выросли сразу на 122%. Единственная проблема хромбуков то, что в качестве ОС используется Chrome OS с браузером Chrome или Chromium. Это ПО нравится хотя и многим, но не всем. Большое количество пользователей принимает Chrome OS вынужденно, не имея альтернативы. Но теперь, кажется, она появилась. Речь идет о дистрибутиве Linux, который получил название Ubuntu Web Remix. Его начали разрабатывать в начале лета, а сейчас он доступен для загрузки.

Подробности

Как монетизируется Open Source



Категория: Статьи/Разное



Компания Jitsu в своём блоге на Хабре пишет: Когда мы слышим слово open-source, на ум приходит сразу что-то связанное с благотворительностью и альтруизмом: талантливые программисты по ночам после работы пишут код, чтобы сделать мир лучше. Однако, жизнь устроена сложнее. Несмотря на то, что open-source действительно делает мир лучше, большая часть открытого кода пишется с исключительно коммерческими целями. Некоторые компании используют продукты с открытым исходным кодом как часть маркетинговой стратегии, или стратегии найма. Другие же компании основывают весь бизнес целиком на open-source ядре. Мы в Jitsu тоже выбрали open-source стратегию. Мы строим наш бизнес на открытом ядре EventNative (о нем мы писали в предыдущем тексте). Прежде чем остановиться на такой модели мы исследовали рынок и много поняли про его устройство.

Подробности

Переведут ли госсофт на open source технологии возможности для развития этого тренда в США



Категория: Статьи/Разное



Компания VAS Experts пишет в своём блоге на Хабре: Ранее мы подробно останавливались на том, как власти США планируют развивать IT-инфраструктуру и линии связи по всей стране обсуждали, почему этому процессу мешают действующие стандарты, методы сбора отчетности с интернет-провайдеров и низкая точность так называемых карт широкополосного доступа, построенных на ее основе. Несмотря на эти сложности, регуляторы и телеком-компании все активнее двигаются от слов к делу.

Подробности

Короткой строкой



Новости



Мероприятия



Kubernetes для разработчиков: трехдневный интенсив []

Новости FOSS организаций



  1. Компания Mozilla передала движок Servo организации Linux Foundation [ 1, 2 (en), 3]
  2. IBM, Linux Foundation, Cisco, Akamai и VMware начали продвижение инклюзивной терминологии []
  3. Инициатива по развитию средств управления цветом и HDR для Wayland []
  4. Facebook стал корпоративным спонсором Blender Foundation []
  5. В Fedora 34 планируют задействовать PipeWire для звука вместо PulseAudio []
  6. Консолидация AI и MLпроектов в Linux Foundation [ (en)]


Мультимедиа



Проект GIMP празднует двадцатипятилетие []

Безопасность



Критическая уязвимость в системе управления контентом Drupal []

Web



Поддержка Flash в Mozilla Firefox прекращается 26 января 2021 []

Пользовательское



Улучшения поддержки Wayland в программах KDE []

Железо



Организация Purism представила Linux-компьютер Librem Mini v2 []

Статьи



DIY



Облачное управление или локальное. Что выбрать для домашней автоматизации? [ (en)]

Ядро и дистрибутивы



Сравнение KDE Neon vs Kubuntu []

Системное



Как забыть ZFS и начать использовать Btrfs [ (en)]

Специальное



LazySSH, SSH-сервер для запуска временных виртуальных машин []

Мультимедиа



LazPaint: открытая альтернатива Paint.NET [ (en)]

Безопасность



  1. CrowdSec современная альтернатива Fail2Ban и коллективный иммунитет для Интернета []
  2. bdshemu: эмулятор шелл-кода в Bitdefender []
  3. О повышении безопасности контейнеров с SELinux [ (en)]


DevOps



  1. Автоматизация миграций баз данных с помощью контейнеров и Git []
  2. Учимся читать логи []
  3. Как в Smarkets улучшили мониторинг для своих Kubernetes-кластеров []
  4. Как обновиться до Terraform 0.12 [ (en)]
  5. Об управлении несколькими версиями Terraform с использованием tfenv [ (en)]
  6. Об автоматизации задач с помощью короткой справки по Ansible [ (en)]


Web



  1. Мониторинг пропускной способности интернет-канала []
  2. Установка Ace Stream в Ubuntu []


Для разработчиков



  1. Установка и настройка cSvn []
  2. Материальный дизайн. Создание анимаций в Kivy []
  3. Фреймворки и библиотеки для кроссплатформенной разработки десктопных программ []
  4. Эволюция Material Design для AvaloniaUI []
  5. Разработка приложения с использованием Python и OpenCV на Android устройстве []
  6. Как использовать сериализаторы в Python веб фреймворке Django [ (en)]
  7. Топ 7 Rust команд для использования Cargo [ (en)]
  8. [Для начинающих] Как написать, собрать и запустить C программу в Ubuntu и других дистрибутивах [ (en)]


Менеджмент



  1. О применеии научной методологии при agile разработке [ (en)]
  2. Чем занимаются Open Source продуктовые менеджеры? [ (en)]


Пользовательское



  1. Кунг-фу стиля Linux: глобальный поиск и замена строк с помощью ripgrep []
  2. Как установить Google Chrome в Linux Mint []
  3. 6 причин, почему Ubuntu лучше Windows []
  4. Кунг-фу стиля Linux: упрощение работы с awk []
  5. Что такое man []
  6. Лучшие календари для Linux []
  7. Кунг-фу стиля Linux: наблюдение за файловой системой []
  8. [Для начинающих] Как сохранить вывод команды в файл в терминале [ (en)]
  9. Как увеличить размер диска для существующей виртуальной машины в VirtualBox [ (en)]
  10. Автоматическая разблокировка шифрованных дисков в Linux [ (en)]
  11. Линукспросвет: что такое Grub в Linux и для чего он используется? [ (en)]


Железо



Psion 5mx и аппаратные развлечения с linux []

Разное



  1. Протоколы, а не Платформы: технологический подход к свободе слова Часть 1 []
  2. Как посчитать метрики успешности проведения Open Source мероприятий [ (en)]
  3. Open Source объединяет музыкантов в виртуальном пространстве [ (en)]
  4. Трудовые отношения и Open Source [ (en)]


Релизы



Ядро и дистрибутивы



  1. Релиз Ubuntu Touch 14. Ubuntu для смартфонов. Что нового []
  2. Выпуск операционной системы MidnightBSD 2.0 []
  3. Доступен Solaris 11.4 SRU27 []
  4. Релиз дистрибутива для исследования безопасности Kali Linux 2020.4 []


Системное



  1. Представляем PowerShell 7.1 []
  2. Доступен оконный менеджер i3wm 4.19 []
  3. Выпуск системы инициализации sysvinit 2.98 []
  4. Выпуск Coreboot 4.13 []


Специальное



  1. Coq 8.12 []
  2. Выпуск Wine 5.22 и Wine staging 5.22 []


Мультимедиа



  1. gmusicbrowser 1.1.16 и 1.1.99.1 beta []
  2. Релиз пакета для создания 2D-анимации Synfig 1.4 []


Безопасность



  1. Сканер для выявления слабых паролей в СУБД []
  2. Релиз системы обнаружения атак Snort 2.9.17.0 []


Web



  1. Выпуск интегрированного набора интернет-приложений SeaMonkey 2.53.5 []
  2. Выпуск P2P-платформы GNUnet 0.14 []
  3. Первый выпуск gping, утилиты для мониторинга сетевых задержек []
  4. Релиз Firefox 83 [ 1, 2, 3]
  5. Выпуск Tor Browser 10.0.5 и дистрибутив Tails 4.13 []
  6. Релиз Chrome 87 [ 1, 2]
  7. Обновление почтового клиента Thunderbird 78.5.0 []


Для разработчиков



  1. Обновление dotenv-linter, линтера для env-файлов []
  2. Выпуск языка программирования Rust 1.48 [ 1, 2]
  3. Выпуск Electron 11.0.0, платформы создания приложений на базе движка Chromium []
  4. Вышла Scala 2.13.4 []


Пользовательское



  1. topalias утилита для генерации коротких алиасов по истории bash/zsh [ 1, 2]
  2. Второй предварительный выпуск Xfce 4.16 []


Разное



Выпуск GCompris 1.0, обучающего набора для детей от 2 до 10 лет []

Что ещё посмотреть



4 книги по цифровой трансформации для тимлидов, шпаргалка по Quarkus & Observability дайджест от RedHat []




На этом всё, до следующего воскресенья!

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

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

Подписывайтесь на наш Telegram канал, группу ВКонтакте или RSS чтобы не пропустить новые выпуски FOSS News.

Предыдущий выпуск
Подробнее..

Перевод Протоколы, а не Платформы технологический подход к свободе слова Часть 1

18.11.2020 10:21:27 | Автор: admin

Продвижение свободы слова за счет изменения экономической и цифровой инфраструктуры интернета

Будущее свободы слова

Серия статей, для переосмысления Первой поправки в эпоху цифровых технологий

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

Ситуация создала нечто вроде кризиса, как внутри, так и за пределами этих компаний. Платформы постоянно пытаются выполнять новые обязанности в качестве арбитров правды и доброты в интернете, несмотря на то, что исторически позиционируют себя защитниками свободы слова. Между тем, в США, политики из двух основных партий критикуют их, пусть даже и по совершенно разным причинам. Одни жалуются на то, что платформы потенциально допускают иностранное вмешательство в их выборы.3 Другие жалуются на то, что их использовали для распространения дезинформации и пропаганды.4 Третьи обвиняют платформы в том, что они просто слишком влиятельны.5 Следующие обращают внимание на неуместные аккаунты и удаление контента,6 в то время как другие рассуждают о попытках смягчения дискриминации по отношению к определенным политическим точкам зрения.7

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

Одни выступают за более строгое регулирование контента в интернете, в то время как такие компании, как Facebook, YouTube и Twitter, подумывают о найме тысяч сотрудников для своих команд модераторов.8 Одновременно продолжая инвестировать в искусственный интеллект для выявления спорного контента на ранней стадии процесса.9 Другие утверждают, что нужно изменить раздел 230 CDA, который дает платформам свободу действий в модерировании (или не модерировании) контента.10 Третьи предлагают вообще не допускать модерирования по крайней мере, для платформ определенного размера,чтобы они считались частью всеобщего доступа.11

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

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

Этот подход: строить протоколы, а не платформы.

Это подход, который вернет нас к интернету, каким он был раньше. Он включал в себя множество различных протоколовинструкций и стандартов, которые каждый мог использовать для создания совместимых интерфейсов. Электронная почта использует SMTP (Simple Mail Transfer Protocol). Чат был сделан через IRC (Internet Relay Chat). Пользовательская сеть осуществляла функции распределенной дискуссионной системы, использующей NNTP (Network News Transfer Protocol). Сама Всемирная паутина имела свой собственный протокол: протокол передачи гипертекста, или HTTP.

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

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

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

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

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

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

Однако это принесло свои трудности. С установлением контроля, появилась и ответственность, которая повлекла более строгий контроль контента, размещенного на этих платформах. Фильтрование и предвзятость начали перерастать в обеспокоенность пользователей.13 И вдобавок, это закончилось доминированием нескольких интернет-компаний, что (вполне обоснованно) вызывает дискомфорт у многих.14

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

Ранние проблемы протоколов и качественные платформы

На раннем этапе развития интернета доминировало несколько протоколов, но их ограниченность позволила платформам заполучить влияние. Существует множество различных платформ которые были успешны в течение некоторого времени и провалились (или нет), и, чтобы продемонстрировать это, мы возьмем Usenet и Reddit для сравнения.

Чисто теоретически, и Usenet, и Reddit очень похожи. В обоих случаях речь идет о форумах, организованных по определенной теме. В Usenet они назывались группами новостей. На Reddit - сабреддитами.15 Каждая новостная группа или сабреддит, как правило, имеют модераторов, уполномоченных устанавливать различные правила. Пользователи могут размещать новые сообщения в рамках каждой группы, что ведет к threads с другими участниками группы и развитию дискуссии.

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

Для получения доступа к Usenet, первоначально нужно было специальное клиентское приложение для чтения новостей (их было несколько), а затем нужно было получить доступ к серверу Usenet. Многие интернет-провайдеры сначала предлагали свои собственные услуги (когда я впервые попал в интернет в 1993 году, я использовал Usenet через сервер новостей в моем университете, а также Usenet reader, предоставленный университетом). С популяризацией интернета, все больше организаций пытались создать веб-интерфейс для Usenet. Изначально доминировала служба Deja News Research Service, предоставившая один из первых веб-интерфейсов для Usenet; позже они добавили ряд дополнительных функций, включая (наиболее полезную) всеобъемлющую поисковую систему.

Пока DejaNews экспериментировали с различными бизнес-моделями, их поисковик закрылся. Google купил их в 200116 году, вместе с архивами Usenet, которые стали ключевой частью Google Groups.

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

А период после сентября 1993 года запомнился поклонниками старой школы Usenet как Сентябрь, который никогда не закончился или Вечный сентябрь. Это был момент когда проприетарная платформа America Online (AOL) запустила Usenet у себя, и пришло огромное количество пользователей которых было не так легко приручить.17

Контент размещался не централизованно, а между различными серверами, поскольку серверов Usenet было очень много. У этого есть свои преимущества и недостатки, в том числе то, что разные серверы могут обрабатывать разный контент по-разному. Не каждый сервер Usenet должен хостить каждую группу, что означает, что нет централизованной власти, которая бы могла заниматься модерированием деструктивного поведения или троллинга. Однако некоторые серверы могут блокировать определенные группы новостей, и пользователи могут использовать такие инструменты, как kill files, для фильтрации нежелательного контента на основе критериев, выбранных ими самими.18

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

Возможно, самой большой проблемой старой системы было отсутствие очевидной бизнес-модели. Как показало падение Deja News, запуск сервера Usenet никогда не был особенно выгодным. Со временем наблюдался рост профессиональных серверов Usenet, которые требовали оплаты за доступ, но они появились гораздо позже, и были не настолько велики как, например, Reddit, и обычно фокусировались на торговле пиратским контентом.20

Нынешние проблемы больших платформ

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

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

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

Вторая проблема, с которой сегодня сталкиваются крупнейшие платформы, заключается в том, что их операторы все больше обеспокоены содержанием разрешенного контента, а также ответственностью, которую они несут за контроль или блокировку данного контента.22 Они столкнулись с растущим давлением со стороны пользователей и политиков, требующих от них более активной работы.23 Были приняты законы, которые более четко требуют от платформ удалять определенный контент, постепенно снижают прежнюю неприкосновенность (например, Акт о соблюдении приличий в СМИ, раздел 230, в США, или Директива об электронной торговле в ЕС), которой многие платформы наслаждались ранее при выборе уровня модерирования.

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

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

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

Эта установка расстраивает всех участников, и вряд ли в ближайшее время изменится к лучшему.

Вместо заключения

Мнения, выраженные в этой статье, являются мнениями Mike Masnick, цитируемого выше, и не обязательно соответствуют мнениям NEAR.

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

Код NEAR открыт, наша реализация написана на Rust, её можно найтитут.

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

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

Подробнее..

Есть ли параллелизм в произвольном алгоритме и как его использовать лучшим образом

26.11.2020 16:14:32 | Автор: admin

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

Ниже приведена иллюстрация процесса выявления параллелизма для простейшего случая вычисления выражения axb+a/c (a, b, c входные данные).

а) облако операторов (последовательность выполнения не определена), б) полностью последовательное выполнение, не определена), б) полностью последовательное выполнение, в) параллельное исполнение

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

Параллельная вычислительная система включает несколько вычислителей (арифметико-логических устройств), объединённых общей или локальной оперативной памятями и кэшами. Современные параллельные системы часто имеют не только гомогенное, но и гетерогенное вычислительное поле. Задача распределения вычислений между отдельными вычислителями приводит к разработке расписания (плана) вычислений. Проблемой является многозначность расписаний параллельного выполнения алгоритма в общем случае это NP-полная задача [2], точное решение (при заданных оптимизационных требованиях) которой можно получить только методом полного перебора (что нереально при числе операторов уже более сотен-тысяч). Выходом является использование эвристических методов, исходя из сложности данную область знания можно обоснованно отнести к наиболее сложным случаям Науки о данных (Data Science).

Параметрам выполнения распространенных алгоритмов в параллельном варианте посвящен известный ресурс AlgoWiki [3].

Особенно интересен, с точки зрения автора, вариант параллелизации для языков программирования высокого уровня без явного указания распараллеливания и в системах c концепцией ILP (Instruction-Level Parallelism, параллелизм на уровне команд, с реализацией посредством вычислительной архитектуры EPIC (Explicitly Parallel Instruction Computing, явный параллелизм выполнения команд). При этом аппаратное обеспечение вычислительных систем сильно упрощается и все проблемы выявления параллелизма и построение собственно расписания выполнения программы для заданной конфигурации параллельной вычислительной системы ложатся на компилятор, что ведет к его усложнению и снижению скорости компиляции.

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

Одной из важных процедур выявления параллелизма по заданному ИГА является получения его исходной (обладающей свойством каноничности) Ярусно-Параллельной Формы (ЯПФ), [4]. При этом условием расположением операторов на едином ярусе является независимость их друг от друга по информационным связям (необходимое условие их параллельного выполнения).

Получение такой (без условия ограниченности количества операторов на ярусах) ЯПФ требует O(N2) действий, где N число операторов (вершин графа), ее высота (общее число ярусов) равна увеличенной на единицу длине критического пути в ИГА. Напрямую использовать такую ЯПФ в качестве основы для построения расписания выполнения параллельной программы обычно затруднительно (ширина некоторых ярусов часто сильно превышает число имеющихся параллельных вычислителей). Но т.к. вычисление такой ЯПФ вычислительно малозатратно, во многих случаях целесообразно начинать анализ именно с ее получения и в дальнейшем проводить модификацию этой ЯПФ с учетом конкретных задач. При этом при каждой модификации ЯПФ получаем новую форму, полностью соответствующую исходному ИГА.

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

На рис. ниже приведен несложный случай алгоритма вычисления вещественных корней полного квадратного уравнения ax2+bx+c=0.

На рисунке -ярусно-параллельная форма алгоритма решения полного квадратного уравнения в вещественных числах в канонической форме (номера ярусов ЯПФ расположены справа)На рисунке -ярусно-параллельная форма алгоритма решения полного квадратного уравнения в вещественных числах в канонической форме (номера ярусов ЯПФ расположены справа)

Показанная ЯПФ уже является расписание выполнения параллельной программы (выполнение начинается сверху вниз, требует 6 относительных единиц времени и 4-х параллельных вычислителей). При этом число задействованных вычислителей по ярусам крайне неравномерно (важно при однозадачном режиме работы вычислительной системы) на 1-м ярусе задействованы все 4, на 2,3,4 - только один и по два на 5- и 6 ярусах. Однако легко видеть, что простейшее преобразование (показанные красным пунктиром допустимые перестановки операторов с яруса на ярус) позволяют выполнить тот же алгоритм за то же (минимальное из возможных) время всего на двух вычислителях! Не для любого алгоритма получается столь идеально часто для снижения требуемого числа параллельных вычислителей единственным путем является увеличение времени выполнения алгоритма (возрастание числа ярусов ЯПФ).

Для решения задач определения рационального (на основе заданных критериев) расписания выполнения произвольных алгоритмов создан инструментальный программный комплекс, включающая два модуля - D-F и SPF@home. Свободная выгрузка инсталляционных файлов доступна с ресурсов http://vbakanov.ru/dataflow/content/installdf.exe и http://vbakanov.ru/spf@home/content/installspf.exe соответственно (дополнительная информация по теме - http://vbakanov.ru/dataflow/dataflow.htm и http://vbakanov.ru/spf@home/spf@home.htm).

 На рисунке - схема инструментального комплекса (*.set и *.gv программный файл и файл информационного графа анализируемой программы соответственно, *.mvr, *.med файлы метрик вершин и дуг графа алгоритма соответственно, *.cls, *.ops файлы параметров вычислителей и операторов программы соответственно, *.lua текстовый файл на языке Lua, содержащий методы реорганизации На рисунке - схема инструментального комплекса (*.set и *.gv программный файл и файл информационного графа анализируемой программы соответственно, *.mvr, *.med файлы метрик вершин и дуг графа алгоритма соответственно, *.cls, *.ops файлы параметров вычислителей и операторов программы соответственно, *.lua текстовый файл на языке Lua, содержащий методы реорганизации

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

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

Для управления созданием расписания используется встроенный скриптовый язык Lua (Lua написан на ANSIC, обеспечивает неявную динамическую типизацию, поддерживает прототипную модель объектно-ориентированного программирования и был выбран на основе свойств его компактности, полной открытости исходных кодов и близости синтаксиса к распространенному С).

Родительское приложение создано с использованием языка программирования С++, является GUI Win32-программой и доступно для свободной выгрузки и использования (как и исходные тексты) через GIT-репозиторий. Вывод данных осуществляется на экран в текстовом и графическом форматах и в файлы (также в структурированной текстовой форме).

Сочетание компилируемой родительской программы и встроенного интерпретатора скриптового языка позволило обеспечить высокую производительность и гибкость (Lua-вызовы фактически являются обертками для API-функций модуля SPF@home).

Копии экранов обсуждаемого комплекса приведены на изображениях ниже (программные модули D-F и SPF@home соответственно).

Модуль D-F (Data-Flow) является фактически универсальным вычислителем, выполняющим программу на ассемблероподобном языке на заданном числе параллельных вычислителей. При их числе большем 1 вычисления ведутся по принципу Data-Flow (реализуется статическая потоковая архитектура), операторы выполняются по условию готовности их к выполнению (ГКВ), что является следствием присвоенности значений все операндам данного оператора; при единичном вычислителе реализуется обычное последовательное выполнение. В случае превышения числа ГКВ-операторов числа свободных вычислители используется задаваемая система приоритетов их выполнения, условное выполнение реализуется предикатным выполнением, для реализации циклов используется система макросов, разворачивающая циклические структуры. Модуль D-F имеет встроенную систему проверку корректности ИГА, для контроля выполнения используется динамическая цветовая индикация выполненности операторов.

Программы для D-F составляются в императивном стиле, каждый оператор по уровню сложности сопоставим с уровнем ассемблера, порядок расположения операторов в программе несущественен. Нижеприведен пример записи программы вычисления вещественных корней полного квадратного уравнения (входной set-файл для модуля D-F, механизм предикатов в приведенном варианте не используется):

Такая программа может рассматриваться как результат компиляции с языков программирования высокого уровня, не содержащих явных указаний на параллелизацию вычислений. В модуле D-F программа отлаживается, результат выдается в файл ИГА-формата для обработки в модуле SPF@home. В модуле SPF@home для получения ЯПФ из gv-файла (стандартный формат текстовых файлов описаний графов), запоминания его во внутреннем представлении системы, создание ЯПФ и запоминание его в Lua-массиве для дальнейшей обработки может быть выполнен следующий код (наклоном выделены API-вызовы системы, двойной дефис означает начало комментария до конца строки):

CreateTiersByEdges("EdgesData.gv")  -- создать ЯПФ по файлу EdgesData.gv -- с подтянутостью операторов вверх-- CreateTiersByEdges_Bottom("EdgesData.gv")  -- создать ЯПФ по файлу EdgesData.gv -- с подтянутостью операторов вниз--OpsOnTiers={} -- создаём пустой 1D-массив OpsOnTiers for iTier=1,GetCountTiers() do -- по ярусам ЯПФ   OpsOnTiers[iTier]={} -- создаём iTier-тую строку 2D-массива OpsOnTiers   for nOp=1,GetCountOpsOnTier(iTier) do -- по порядковым номерам операторов на ярусе iTier        OpsOnTiers[iTier][nOp]=GetOpByNumbOnTier(nOp,iTier) -- взять номер оператора nOpend end -- конец циклов for по iTier и for по nOp

Для удобства данные метрик операторов и дуг графа выведены из gv-файлов и расположены в текстовых mvr и med-файлах, для моделирования выполнения программ на гетерогенном поле параллельных вычислителей служат cls и ops-файлы сопоставления возможностей выполнения определенных операторов на конкретных вычислителях. Преимуществом такого подхода является возможность задания нужных параметров целой группе объектов (списком типа от-до, причем список может быть и вырожденным) одной строкой файла. Задавать параметры можно по практически неограниченному количеству тегов, определяемых разработчиком.

Модуль SPF@home также позволяет определять время жизни данных между ярусами ЯПФ, что необходимо для определения/оптимизации параметров устройств временного хранения данных (обычно регистров процессора). Собственно размер данных при этом берется из med-файлов.

Система нацелена в основном на анализ программ, созданных с использованием языков программирования высокого уровня без явного указания распараллеливания и в системах c концепцией ILP (Instruction-LevelParallelism, параллелизм на уровне команд), хотя возможности модуля SPF@home позволяют использовать в качестве неделимых блоков последовательности команд любого размера.

Т.о. процедура составления расписания параллельного выполнения программы заключается в составлении Lua-программы, реализующей процедуры реорганизации ЯПФ в соответствие с заданными требованиями. Тремя типовыми встречающимися подзадачами (в реальном случае обычно требуется выполнение нескольких из этих подзадач одновременно) являются:

I. Балансировка числа операторов по всем ярусам заданной ЯПФ без увеличения ее высоты (минимизируется требуемое для решения задачи число параллельных вычислителей).

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

III. Получение расписания выполнения программы на гетерогенном поле параллельных вычислителей.

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

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

Собственно последовательность получения рационального расписания выполнения параллельной задачи будут следующей:

1) Получение исходной (не имеющей ограничений по ширине ярусов) ЯПФ.

2) Модификация этой ЯПФ в нужном направлении путем целенаправленной перестановки операторов с яруса на ярус при сохранении исходных связей в информационном графе алгоритма.

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

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

Методы достижения цели могут быть собственно разработанными эристиками (обычно ограниченной сложности для возможности использования в режиме реального времени) или стандартными - метод ветвей и границ, генетические, муравьиные и др. (чаще используются при исследовательской работе). Возможности системы включают использование оберток многофункциональных системных Windows-вызовов WinExec, ShellExecute и CreateProcess, так что исследователь имеет возможность вызова и управления любыми внешними программами (например, использовать тот же METIS в качестве процесса-потомка), файловое обслуживание при этом осуществляется средствами Lua.

В качестве примера на рис.6 приведены (в форме линейчатых диаграмм распределения ширин ярусов ЯПФ) результаты вычислительных экспериментов с общим символическим названием Bulldozer, возникшим по аналогии с отвалом бульдозера, перемещающим грунт с возвышенностей во впадины.

На рис. показаны линейчатые диаграммы ширин ярусов реальных ЯПФ из копий экранов при работе системы SPF@home (средне-арифметическое значение ширин показано пунктиром, a) и символическая схема действия метода Bulldozer - б)На рис. показаны линейчатые диаграммы ширин ярусов реальных ЯПФ из копий экранов при работе системы SPF@home (средне-арифметическое значение ширин показано пунктиром, a) и символическая схема действия метода Bulldozer - б)

Многочисленные вычислительные эксперименты показывают, что во многих случаях удается значительно (до 1,5-2 раз) снизить ширину ЯПФ без увеличения высоты, но почти никогда до минимальной величины (средне-арифметическое значение ширин ярусов).

Т.о. истинной ценностью данного исследования являются именно эвристические методы (реализованные на языке Lua) создания расписаний выполнения параллельных программ при определённых ограничениях (напр., c учетом заданного поля параллельных вычислителей, максимума скорости выполнения, минимизации или ограничения размеров временного хранения данных и др.).

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

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

Список литературы

1. Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. СПб.: БХВ-етербург, 2002. 608 c.

2. Гери М., Джонсон Д. Вычислительные машины и труднорешаемые задачи. : Мир, Книга по Требованию, 2012. 420 c.

3. AlgoWiki. Открытая энциклопедия свойств алгоритмов. URL: http://algowiki-project.org (дата обращения 31.07.2020).

4. ФедотовИ.Е.Параллельное программирование. Модели и приёмы. М.: СОЛОН-Пресс, 2018. 390 с.

5. Roberto Ierusalimschy. Programming in Lua. Third Edition. PUC-Rio, Brasil, Rio de Janeiro, 2013. 348 p.

Подробнее..

4 книги по цифровой трансформации для тимлидов, шпаргалка по Quarkus amp Observability

19.11.2020 12:06:35 | Автор: admin


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

Начни новое:



Качай:


  • Debezium на OpenShift
    Debezium это распределенная опенсорсная платформа для отслеживания изменений в данных. Благодаря ее надежности и скорости ваши приложения смогут реагировать быстрее и никогда не пропустят события, даже если что-то пойдет на так. Наша шпаргалка поможет с развертыванием, созданием, запуском и обновление DebeziumConnector на OpenShift.
    Загрузить шпаргалку
  • Шпаргалка Quarkus & Observability (придется зарегистрироваться в девелоперской программе и стать частью community, мухахаха)



Почитать на досуге:


  • Объясняем простым языком, что такое гибридное облачное хранилище
    Что это вообще и какие задачи оно решает в условиях постоянного роста объемы данных и эволюции приложений.
    Вкратце: гибридные облачные хранилища сейчас в тренде, и не зря. Майк Пих (Mike Piech), вице-президент и генеральный менеджер Red Hat по облачным хранилищам и дата-сервисам, а также другие эксперты рассказывают о преимуществах, сценариях использования и ограничениях этой технологии.
  • 4 книги по цифровой трансформации, которые должен прочесть каждый руководитель
    Технологии это далеко не всё, на чем фокусируются руководители, успешно осуществляющие цифровую трансформацию. Представленные книги расширят ваше понимание путей развития корпоративные заказчиков, глобальных рынков и других важных тем.
    Вкратце: эти 4 книги помогут освежить понимание перспектив цифровой трансформации.


  • 7 способов применения микрокомпьютеров Raspberry Pi на предприятии
    От тимбилдинга до сверхдешевых средств безопасности и экспериментов с Kubernetes рассказываем, как задействовать Raspberry Pi на предприятиях.
    Вкратце: крохотный Raspberry Pi способен придать большой импульс развитию корпоративной ИТ-системы.

Смотри в записи:


  • jconf.dev (30 сентября)
    Бесплатная виртуальная Java-конференция прямо у вас на экране: четыре техно-трека с нашими комьюнити-экспертами по Java и облаку, 28 углубленных сессий и два потрясающих основных доклада.
  • AnsibleFest (13-14 октября)
    Два дня интереснейших докладов, демонстраций и практических занятий. Отличная возможность узнать, как разработчики, администраторы и ЛПР в сфере ИТ отвечают на вызовы перемен с помощью гибких технологий автоматизации с открытым кодом, которые позволяют перейти от того, что есть, к тому, что нужно.
  • J4K Conference (13-14 октября)
    Новая виртуальная конференция по Kubernetes, Java и облаку: 17 сессий с сотрудниками Red Hat, включая доклад Марка Литтла (Mark Little), главного человека в Red Hat по связующему ПО.
  • График предстоящих мероприятия DevNation
    Ознакомьтесь с планом мероприятия DevNation на портале Red Hat Developer, включая все вебинары Tech Talks и мастер-курсы, чтобы заранее спланировать свое расписание и зарегистрироваться на заинтересовавшие вас мероприятия.

По-русски:


Подробнее..

Обзор инструментов для chaos engineering в Kubernetes. Часть 1 kube-monkey, chaoskube, Chaos Mesh

23.11.2020 12:04:01 | Автор: admin


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

Благо, уже сегодня можно найти не одно Open Source-решение, помогающее в подобных экспериментах. Представляем вашему вниманию их обзор. Он получился весьма объёмным, поэтому был разбит на две части: в этой мы рассмотрим три популярных проекта.

Предыстория


История chaos engineering начинается в 2011, когда в компании Netflix решили, что только избыточная и распределенная инфраструктура может дать действительно высокую отказоустойчивость. Для того, чтоб непрерывно убеждаться в том, что это действительно так, они и создали Chaos Monkey.

Суть этой обезьяны сводилась к тому, чтобы регулярно убивать один из экземпляров какого-то сервиса, будь то виртуальная машина или контейнер. Увеличение размера инфраструктуры и эволюция привели к появлению Chaos Kong сервиса, который отрубает один из трёх регионов AWS. Вот это по-настоящему масштабная проверка отказоустойчивости!

В целом же, список доступных действий для хаос-инжиниринга значительно шире, чем простое убийство сервисов. Главная цель этой новой науки обнаружение вероятных проблем, которые либо не устраняются должным образом, либо не обнаруживаются / не воспроизводятся постоянно. Поэтому убийством не ограничиваются: нужно ещё умело вставлять палки в колёса и дисковую подсистему, рвать сетевые соединения и поджаривать CPU с памятью особо продвинутые могут даже фрагментировать страницы памяти в ядре запущенного pod'а (как это вообще, cgroups?).

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

Возвращаясь же к классическому Chaos Monkey: эта утилита была создана и используется в Netflix. В настоящий момент она интегрирована с платформой непрерывной доставки Spinnaker, поэтому работает с любым поддерживаемым там бэкендом: AWS, Google Compute Engine, Azure, Kubernetes, Cloud Foundry.

Однако такое, казалось бы, удобство таит в себе обратную сторону. Установка/настройка Chaos Monkey для Kubernetes (в связке со Spinnaker) по своей простоте очень далека от привычного Helm-чарта Далее будут рассмотрены инструменты для chaos engineering, созданные специально для K8s.

1. kube-monkey



Один из самых старых проектов среди изначально ориентированных на Kubernetes: первые публичные коммиты в его репозитории состоялись в декабре 2016 года. Попробуем его сразу в деле на развёрнутом deployment'е nginx из пяти реплик, попутно рассказывая о возможностях.

Итак, вот манифест для испытаний:

---apiVersion: v1kind: Namespacemetadata:  name: test-monkeysspec:  finalizers:  - kubernetes---apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx  namespace: test-monkeysspec:  selector:    matchLabels:      app: nginx  replicas: 5  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx:1.16        ports:        - containerPort: 80---

Готовый чарт с kube-monkey самый простой вариант установки и запуска утилиты:

$ git clone https://github.com/asobti/kube-monkey$ cd kube-monkey/helm

Немного модифицируем команду из README.md, чтобы обезьянка жила в своём namespace и начинала работу в двенадцать ночи по Москве, заканчивая за час до полуночи (такое расписание подходило нам на момент написания статьи):

$ helm install -n kubemonkey --namespace kubemonkey --set config.dryRun=false --set config.runHour=0 --set config.startHour=1 --set config.endHour=23 --set config.timeZone=Europe/Moscow --set config.debug.schedule_immediate_kill=true --set config.debug.enabled=true kubemonkey

Теперь можно натравить обезьянку на nginx с помощью лейблов. Kube-monkey работает по принципу opt-in, т.е. взаимодействует только с теми ресурсами, которые разрешено убивать:

$ kubectl -n test-monkeys label deployment nginx kube-monkey/enabled=enabled$ kubectl -n test-monkeys label deployment nginx kube-monkey/kill-mode=random-max-percent$ kubectl -n test-monkeys label deployment nginx kube-monkey/kill-value=100$ kubectl -n test-monkeys label deployment nginx kube-monkey/identifier=nginx

Пояснения по лейблам:

  • Второй и третий (kill-mode, kill-value) говорят kube-monkey убивать случайное количество pod'ов из StatefulSets/Deployments/DaemonSets, вплоть до 100%.
  • Четвёртый (identifier) определяет уникальный лейбл, по которому kube-monkey найдёт жертв.
  • Пятый (mtbf mean time between failure) определяет, сколько дней должно пройти между убийствами (по умолчанию равен единице).

Сразу появляется ощущение, что пять лейблов это многовато, чтобы просто взять и кого-то поубивать Кроме того, есть pull request о том, чтобы mtbf указывать не только в днях (но и в часах, например, чтобы чаще совершать злодеяния). Однако он висит с 5 февраля без движения, что печально.

Ок, посмотрим на логи обезьянки и увидим в конце:

I0831 18:14:53.772484       1 kubemonkey.go:20] Status Update: Generating next schedule in 30 secI0831 18:15:23.773017       1 schedule.go:64] Status Update: Generating schedule for terminationsI0831 18:15:23.811425       1 schedule.go:57] Status Update: 1 terminations scheduled todayI0831 18:15:23.811462       1 schedule.go:59] v1.Deployment nginx scheduled for termination at 08/31/2020 21:16:11 +0300 MSKI0831 18:15:23.811491       1 kubemonkey.go:62] Status Update: Waiting to run scheduled terminations.********** Today's schedule **********k8 Api Kind    Kind Name        Termination Time-----------    ---------        ----------------v1.Deployment    nginx        08/31/2020 21:16:11 +0300 MSK********** End of schedule **********

Ура! Chaos-monkey нашла deployment и запланировала убийство одной или более из его реплик. Но что же это и почему?

E0831 18:16:11.869463       1 kubemonkey.go:68] Failed to execute termination for v1.Deployment nginx. Error: v1.Deployment nginx has no running pods at the moment

Посмотрим внимательно в мануал ещё раз и увидим (с устаревшим apiVersion, к сожалению):

For newer versions of kubernetes you may need to add the labels to the k8s app metadata as well.

---apiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: monkey-victim  namespace: app-namespace  labels:    kube-monkey/enabled: enabled    kube-monkey/identifier: monkey-victim    kube-monkey/mtbf: '2'    kube-monkey/kill-mode: "fixed"    kube-monkey/kill-value: '1'spec:  template:    metadata:      labels:        kube-monkey/enabled: enabled        kube-monkey/identifier: monkey-victim[... omitted ...]

Ок, изменяем наш шаблон с удалением deployment'а на:

---apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx  namespace: test-monkeys  labels:    kube-monkey/enabled: enabled    kube-monkey/identifier: nginx    kube-monkey/kill-mode: random-max-percent    kube-monkey/kill-value: "100"    kube-monkey/mtbf: "1"spec:  selector:    matchLabels:      app: nginx  replicas: 5  template:    metadata:      labels:        app: nginx        kube-monkey/enabled: enabled        kube-monkey/identifier: nginx    spec:      containers:      - name: nginx        image: nginx:1.16        ports:        - containerPort: 80---

Теперь все получилось:

I0831 18:24:20.434516       1 kubemonkey.go:20] Status Update: Generating next schedule in 30 secI0831 18:24:50.434838       1 schedule.go:64] Status Update: Generating schedule for terminations    ********** Today's schedule **********    k8 Api Kind    Kind Name        Termination Time    -----------    ---------        ----------------    v1.Deployment    nginx        08/31/2020 21:25:03 +0300 MSK    ********** End of schedule **********I0831 18:24:50.481865       1 schedule.go:57] Status Update: 1 terminations scheduled todayI0831 18:24:50.481917       1 schedule.go:59] v1.Deployment nginx scheduled for termination at 08/31/2020 21:25:03 +0300 MSKI0831 18:24:50.481971       1 kubemonkey.go:62] Status Update: Waiting to run scheduled terminations.I0831 18:25:03.540282       1 kubemonkey.go:70] Termination successfully executed for v1.Deployment nginxI0831 18:25:03.540324       1 kubemonkey.go:73] Status Update: 0 scheduled terminations left.I0831 18:25:03.540338       1 kubemonkey.go:76] Status Update: All terminations done.I0831 18:25:03.540499       1 kubemonkey.go:19] Debug mode detected!I0831 18:25:03.540522       1 kubemonkey.go:20] Status Update: Generating next schedule in 30 sec

Ок, работает хорошо и весьма конкретно. Хотя настраивается сложнее, чем могло быть, не очень гибко, да и функций совсем мало. Бывают и странности в работе:

I0831 18:30:33.163500       1 kubemonkey.go:19] Debug mode detected!I0831 18:30:33.163513       1 kubemonkey.go:20] Status Update: Generating next schedule in 30 secI0831 18:31:03.163706       1 schedule.go:64] Status Update: Generating schedule for terminationsI0831 18:31:03.204975       1 schedule.go:57] Status Update: 1 terminations scheduled today    ********** Today's schedule **********    k8 Api Kind    Kind Name        Termination Time    -----------    ---------        ----------------    v1.Deployment    nginx        08/31/2020 21:31:45 +0300 MSK    ********** End of schedule **********I0831 18:31:03.205027       1 schedule.go:59] v1.Deployment nginx scheduled for termination at 08/31/2020 21:31:45 +0300 MSKI0831 18:31:03.205080       1 kubemonkey.go:62] Status Update: Waiting to run scheduled terminations.E0831 18:31:45.250587       1 kubemonkey.go:68] Failed to execute termination for v1.Deployment nginx. Error: no terminations requested for v1.Deployment nginxI0831 18:31:45.250634       1 kubemonkey.go:73] Status Update: 0 scheduled terminations left.I0831 18:31:45.250649       1 kubemonkey.go:76] Status Update: All terminations done.I0831 18:31:45.250828       1 kubemonkey.go:19] Debug mode detected!

2. chaoskube



Эта утилита тоже может похвастать длинной историей: первый её релиз состоялся в ноябре 2016 года. У chaoskube есть готовый чарт и хороший мануал по нему. По умолчанию запускается в режиме dry-run, поэтому никто не пострадает.

Запустим на простом deployment'е с nginx, живущем в пространстве имен test-monkey, и укажем опцию про создание RBAC (потому что у роли default нет нужных прав):

$ helm install --name chaoskube --set dryRun=false --set namespaces="test-monkeys" --set rbac.create=true --set rbac.serviceAccountName=chaoskube stable/chaoskube

дело сразу пошло!

$ kubectl -n default logs chaoskube-85f8bf9979-j75qmtime="2020-09-01T08:33:11Z" level=info msg="starting up" dryRun=false interval=10m0s version=v0.14.0time="2020-09-01T08:33:11Z" level=info msg="connected to cluster" master="http://personeltest.ru/aways/10.222.0.1:443" serverVersion=v1.16.10time="2020-09-01T08:33:11Z" level=info msg="setting pod filter" annotations= excludedPodNames="<nil>" includedPodNames="<nil>" labels= minimumAge=0s namespaces=test-monkeystime="2020-09-01T08:33:11Z" level=info msg="setting quiet times" daysOfYear="[]" timesOfDay="[]" weekdays="[]"time="2020-09-01T08:33:11Z" level=info msg="setting timezone" location=UTC name=UTC offset=0time="2020-09-01T08:33:11Z" level=info msg="terminating pod" name=nginx-594cc45b78-8kf64 namespace=test-monkeystime="2020-09-01T08:43:11Z" level=info msg="terminating pod" name=nginx-594cc45b78-t7wx7 namespace=test-monkeystime="2020-09-01T08:53:11Z" level=info msg="terminating pod" name=nginx-594cc45b78-8fg9q namespace=test-monkeystime="2020-09-01T09:03:11Z" level=info msg="terminating pod" name=nginx-594cc45b78-wf5vg namespace=test-monkeys

Конфигурировать можно всё, что может потребоваться: часовой пояс, временные исключения, лейблы, по которым ищутся pod'ы-жертвы, и исключения.

Подводя быстрый итог: хороший, удобный и простой инструмент, но, как и kube-monkey, умеет только убивать pod'ы.

3. Chaos Mesh



Chaos Mesh состоит из двух компонентов:

  1. Chaos Operator оператор хаоса, основной компонент, который в свою очередь состоит из:
    1. controller-manager (управляет Custom Resources),
    2. chaos-daemon (привилегированный daemonset с возможностями управления сетью, cgroups и т.д.),
    3. sidecar-контейнера, динамически вставляемогов целевой pod, чтобы вмешиваться в I/O целевого приложения.
  2. Chaos Dashboard веб-интерфейс для управления и мониторинга хаос-оператора

Проект входит в CNCF и разработан китайской компанией PingCAP, которая известна своей распределённой, Open Source, cloud-native SQL-базой данных для аналитики в реальном времени TiDB (мы писали про её собрата TiKV, тоже входящего в число проектов CNCF).

Итак, хаос-оператор использует CRD для определения объектов хаоса. Всего их шесть типов: PodChaos, NetworkChaos, IOChaos, TimeChaos, StressChaos и KernelChaos. А вот какие доступны действия (эксперименты):

  • pod-kill убийство pod'а;
  • pod-failure недоступность pod'а некоторое (определённое) время;
  • container-kill убийство одного из контейнеров pod'а;
  • netem chaos сетевые проблемы, задержки, повторы пакетов;
  • network-partition эмуляция распада сети на сегменты;
  • IO chaos проблемы с диском и чтением/записью;
  • time chaos искажение показателя текущего времени в pod'е;
  • cpu-burn стресс CPU;
  • memory-burn стресс памяти;
  • kernel chaos жертва получит ошибки ядра, фрагментацию страниц памяти, проблемы с блочным I/O.

Объявляя любой из нужных нам Custom Resource, мы можем указать в нём типы действий, лейблы и селекторы для определения целевых namespace или конкретных pod'ов, а также длительность и расписание проведения экспериментов в общем, всё необходимое для планирования веселья.
Звучит очень интересно, да? Давайте попробуем! Документация по установке снова с Helm.

Не забудем указать --set dashboard.create=true, чтобы получить панели с красивыми графиками! Через пару минут мы получаем целое пространство имён из повелителей хаоса пока ещё бездействующих, но уже готовых к работе:

$ kubectl -n chaos-testing get poNAME                                       READY   STATUS    RESTARTS   AGEchaos-controller-manager-bb67cb68f-qpmvf   1/1     Running   0          68schaos-daemon-krqsh                         1/1     Running   0          68schaos-daemon-sk7qf                         1/1     Running   0          68schaos-daemon-wn9sd                         1/1     Running   0          68schaos-dashboard-7bd8896c7d-t94pt           1/1     Running   0          68s

Для изучения и демонстрации работы chaos-mesh подготовлен подробный мануал, в котором можно увидеть многочисленные возможности оператора. С технической точки зрения, внутри репозитория (https://github.com/chaos-mesh/web-show) находится Deployment тестового приложения на React с сервисом, которому скриптом передаётся IP-адрес pod'а kube-controller-manager (первый из списка, если у нас мультимастер, или просто единственный). После запуска этот pod начинает непрерывно пинговать pod controller-manager'а и визуализировать на графике этот ping.

В нашем случае удобнее выпустить этот график наружу через Ingress, а не команду из deploy.sh (nohup kubectl port-forward svc/web-show --address 0.0.0.0 8081:8081). Поэтому мы просто применяем Deployment и Service из репозитория и объявляем любой Ingress просто для того, чтобы можно было попасть в приложение снаружи.



Приятный график. Судя по сегменту ST, у пациента острый инфаркт! Стоп, это же не кардиограмма А теперь можно применить заклинание хаоса, слегка подкорректировав его для пущей красоты:

apiVersion: chaos-mesh.org/v1alpha1kind: NetworkChaosmetadata:  name: web-show-network-delayspec:  action: delay # the specific chaos action to inject  mode: one # the mode to run chaos action; supported modes are one/all/fixed/fixed-percent/random-max-percent  selector: # pods where to inject chaos actions    namespaces:      - test-monkeys    labelSelectors:      "app": "web-show"  # the label of the pod for chaos injection  delay:    latency: "50ms"  duration: "10s" # duration for the injected chaos experiment  scheduler: # scheduler rules for the running time of the chaos experiments about pods.    cron: "@every 60s"

Результат ожидаемая нами красивая пила, сигнализирующая о том, что netem chaos уже работает. И вот тут уже точно инфаркт.



А вот как выглядит chaos-dashboard:



Визуализация событий:



Подробности о конкретном эксперименте:



Есть даже веб-редактор Custom Resources, но встроенной авторизации к нему нет (обязательно надо закрывать авторизацией!):



В завершении обзора этого проекта стоит упомянуть, что недавно (25 сентября 2020 г.) у Chaos Mesh произошло знаменательное событие релиз версии 1.0.

Продолжение следует


Во второй части статьи будут рассмотрены Litmus Chaos, Chaos Toolkit, игровые варианты хаос-инжиниринга в Kubernetes и некоторые другие проекты, а также подведён общий итог.

P.S.


Читайте также в нашем блоге:

Подробнее..

Конвертируем doc в docx и xml на C

23.11.2020 10:05:21 | Автор: admin

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


С момента моей последней публикации Конвертация xls в xlsx и xml на C# прошло более полугода, за которые я успел сменить как работодателя, так и пересмотреть свои взгляды на некоторые аспекты коммерческой разработки. Сейчас, работая в международной компании с совершенно иным подходом к разработке ПО (ревью кода, юнит-тестирование, команда автотестеров, строгое соблюдение СМК, заботливый менеджер, очаровательная HR и прочие корпоративные плюшки), я начинаю понимать, почему некоторые из комментаторов интересовались целесообразностью предлагаемых мной велокостылей, когда на рынке есть очень достойные готовые решения, например, от e-iceblue. Но давайте не забывать, что ситуации бывают разные, компании тем более, и если потребность в решении какой-то задачи с использованием определенного инструментария возникла у одного человека, то со значительной долей вероятности она возникнет и у другого.



Итак, дано:


  1. Неопределенное множество файлов в формате .doc, которые нужно конвертировать в xml (например, для парсинга и организации автоматизированной навигации внутри текста), желательно с сохранением форматирования.
  2. На сервере памяти чуть больше, чем у рыбки, а на процессоре уже можно жарить яичницу, да и у компании нет лишней лицензии на Word, поэтому конвертация должна происходить без запуска каких-либо офисных приложений.
  3. Сервис должен быть написан на языке C# и в последующем интегрирован в код другого продукта.
  4. На решение задачи два дня и две ночи, которые истекли вчера.

Поехали!


  • Во-первых, нужно сразу уяснить, что старые офисные форматы файлов, такие как .doc и .xls, являются бинарными, и достать что-нибудь человекочитаемое из них без использования текстовых редакторов/процессоров не получится. Прочитать об этом можно в официальной документации. Если есть желание поковыряться поглубже, посчитать нолики с единичками и узнать, что они означают, то лучше сразу перейти сюда.
  • Во-вторых, несмотря на наличие бесплатных решений для работы с .doc, большинство из них написаны на Python, Ruby и чем угодно еще, но не C#.
  • В-третьих, найденное мной решение, а именно библиотека b2xtranslator, является единственным доступным бесплатным инструментом такого рода, еще и написана при поддержке Microsoft, если верить вот этому источнику. Если вдруг вы встречали какие-нибудь аналоги данной библиотеки, пожалуйста, напишите об этом в комментариях. Даже это душеспасительное решение не превратит .doc в .xml, однако поможет нам превратить его в .docx, с которым мы уже умеем работать.

Довольно слов давайте к делу


Установка b2xtranslator


Для работы нам понадобиться библиотека b2xtranslator. Ее можно подключить через менеджера пакетов NuGet.

Однако я настоятельно рекомендую скачать ее из официального git-репозитория по следующим причинам:


  • a) Библиотека представляет собой комбайн, работающий с различными бинарными офисными документами (.doc, .xls, .ppt), что может быть избыточным
  • b) Проект достаточно долго не обновляется и вам, возможно, придется доработать его напильником
  • c) Задача, с которой я столкнулся, как раз потребовала внесения некоторых изменений в работу библиотеки, а также изучения ее алгоритмов и используемых структур для успешной интеграции в свое решение
    Для дальнейшей работы нам понадобиться подключить в свое решение два проекта из библиотеки: b2xtranslator\Common\b2xtranslator.csproj и b2xtranslator\Doc\b2xtranslator.doc.csproj

Конвертация .doc в .docx


Конвертация документов строится по следующему алгоритму:


  1. Инициализация дескриптора для конвертируемого файла.
    Для этого необходимо создать экземпляр класса StructuredStorageReader, конструктор которого в качестве аргумента может принимать или путь до файла, или последовательность байтов (Stream), что делает его крайне удобным при работе с файлами, загружаемыми по сети. Также обращаю внимание, что так как библиотека b2xtranslator является комбайном для конвертации бинарных офисных форматов в современный OpenXML, то независимо от того, какой формат мы хотим конвертировать (.ppt, .xls или .doc) инициализация дескриптора всегда будет происходить с помощью указанного класса (StructuredStorageReader).
    StructuredStorageReader reader = new StructuredStorageReader(docPath);
    
  2. Парсинг бинарного .doc файла с помощью объекта класса WordDocument, конструктор которого в качестве аргумента принимает объект типа StructuredStorageReader.
    WordDocument doc = new WordDocument(reader);
    
  3. Создание объекта, который будет хранить данные для файла в формате .docx.
    Для этого используется статический метод cs public static WordprocessingDocument Create(string fileName, OpenXmlPackage.DocumentType type) класса WordprocessingDocument. В первом аргументе указываем имя нового файла (вместе с путем), а вот во втором мы должны выбрать тип файла, который должен получиться на выходе:
    a. Document (обычный документ с расширением .docx);
    b. MacroEnabledDocument (файл, содержащий макросы, с расширением .docm);
    c. Template (файл шаблонов word с расширением .dotx);
    d. MacroEnabledTemplate (файл с шаблоном word, содержащий макросы. Имеет расширение .dotm).
    WordprocessingDocument docx = WordprocessingDocument.Create(docxPath, DocumentType.Document);
    
  4. Конвертация данных из бинарного формата в формат OpenXML и их запись в объект типа WordprocessingDocument.
    За выполнение указанной процедуры отвечает статический метод
    public static void Convert(WordDocument doc, WordprocessingDocument docx)
    

    класса Converter, который заодно и записывает получившийся результат в файл.

    Converter.Convert(doc, docx);
    

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

    using b2xtranslator.StructuredStorage.Reader;using b2xtranslator.DocFileFormat;using b2xtranslator.OpenXmlLib.WordprocessingML;using b2xtranslator.WordprocessingMLMapping;using static b2xtranslator.OpenXmlLib.OpenXmlPackage;namespace ConverterToXml.Converters{    public class DocToDocx    {        public void ConvertToDocx(string docPath, string docxPath)        {            StructuredStorageReader reader = new StructuredStorageReader(docPath);            WordDocument doc = new WordDocument(reader);            WordprocessingDocument docx = WordprocessingDocument.Create(docxPath, DocumentType.Document);            Converter.Convert(doc, docx);        }    }}
    

    Внимание!
    Если вы используете платформу .Net Core 3 и выше в своем решении, обратите внимание на целевые среды для подключенных проектов b2xtranslator. Так как библиотека была написана довольно давно и не обновляется с 2018 года, по умолчанию она собирается под .Net Core 2.
    Чтобы сменить целевую среду, щелкните правой кнопкой мыши по проекту, выберите пункт Свойства и поменяйте целевую рабочую среду. В противном случае вы можете столкнуться с проблемой невозможности конвертации файлов .doc, содержащих в себе таблицы.
    Я не стал разбираться, почему так происходит, но энтузиастам могу подсказать, что причину стоит искать в 40 строчке файла ~\b2xtranslator\Doc\WordprocessingMLMapping\MainDocumentMapping.cs в момент обработки таблицы.
    Кроме того, рекомендую собирать все проекты и само решение под 64-битную платформу во избежание всяких непонятных ошибок.



    Сохранение результата в поток байтов


    Так как моей целью при использовании данного решения была конвертация .doc в .xml, а не в .docx, предлагаю вовсе не сохранять промежуточный OpenXML файл, а записать его в виде потока байтов. К сожалению, b2xtranslator не предоставляет нам подходящих методов, но это довольно легко исправить:
    В абстрактном классе OpenXmlPackage (см. ~\b2xtranslator\Common\OpenXmlLib\OpenXmlPackage.cs) давайте создадим виртуальный метод:


    public virtual byte[] CloseWithoutSavingFile(){    var writer = new OpenXmlWriter();    MemoryStream stream = new MemoryStream();    writer.Open(stream);    this.WritePackage(writer);    writer.Close();    byte[] docxStreamArray = stream.ToArray();    return docxStreamArray;}
    

    По большому счету, данный метод будет заменять собой метод Close(). Вот его исходный код:


    public virtual void Close(){     // serialize the package on closing    var writer = new OpenXmlWriter();    writer.Open(this.FileName);    this.WritePackage(writer);    writer.Close();}
    

    Скажем спасибо разработчикам библиотеки за то, что не забыли перегрузить метод Open(), который может принимать или имя файла, или поток байтов. Однако, библиотечный метод Close(), который как раз и отвечает за запись результата в файл, вызывается в методе Dispose() в классе OpenXmlPackage. Чтобы ничего лишнего не поломать и не заморачиваться с архитектурой фабрик (тем более в чужом проекте), я предлагаю просто закомментировать код внутри метода Dispose() и вызвать метод CloseWithoutSavingFile(), но уже внутри нашего метода после вызова Converter.Convert(doc, docx).
    Для сохранения результата конвертации вызываем вместо docx.Close() метод docx.CloseWithoutSavingFile():


    public MemoryStream ConvertToDocxMemoryStream(Stream stream){    StructuredStorageReader reader = new StructuredStorageReader(stream);    WordDocument doc = new WordDocument(reader);    var docx = WordprocessingDocument.Create("docx", DocumentType.Document);    Converter.Convert(doc, docx);    return new MemoryStream(docx.CloseWithoutSavingFile());}
    

    Теперь библиотека b2xtranslator будет возвращать сконвертированный из формата .doc в .docx файл в виде потока байтов. Даже если у вас нет цели получить на выходе .xml, такой метод может оказаться более подходящим для дальнейшей работы с файлами, тем более что стрим всегда можно сохранить в виде файла там, где вам надо.
    Для тех, кому все-таки очень хочется получить на выходе .xml документ, еще и с сохраненной структурой, предлагаю дойти до кухни, сварить кофе покрепче, добавить в него рюмку коньяка и приготовиться к приключению на 20 минут.


    Конвертация .doc в .xml



    Теперь, когда, казалось бы, можно воспользоваться классом-конвертором DocxToXml, работа которого была описана вот в этой статье, нас поджидает сюрприз, связанный с особенностями работы b2xtranslator.
    Давайте посмотрим на результат работы библиотеки повнимательнее и сравним с оригинальным .docx файлом, из которого был экспортирован .doc файл для конвертации. Для этого достаточно изменить расширение сравниваемых файлов с .docx на .zip. Вот отличия, которые мы увидим, заглянув внутрь архивов:


    1. В результате конвертации в новом .docx файле (справа) отсутствуют папки customXml и docProps.
    2. Внутри папки word, мы также найдем определенные отличия, перечислять которые я, конечно же, не буду:
    3. Естественно, что и метаданные, по которым осуществляется навигация внутри документа, также отличаются. Например, на представленном скрине и далее оригинальный .docx слева, сгенерированный b2xtranslator cправа.

      Налицо явное отличие в атрибутах тега w:document, но этим отличия не заканчиваются. Всю "мощь" библиотеки мы ощутим, когда захотим обработать списки и при этом:
      a. Сохранить их нумерацию
      b. Не потерять структуру вложенности
      c. Отделить один список от другого

    Давайте сравним файлы document.xml для вот этого списка:


    1.1 Первый.Первый1.2 Первый.Второй1.2.1   Первый.Второй.Первый1.2.2   Первый.Второй.ВторойКакая-то строчка 1.2.3   Первый.Второй.Третий2.  Второй2.1 Второй.Первый
    

    Вот так будет выглядеть .xml для первого элемента списка.


    -Во-первых, мы видим, что сама структура документов несколько отличается (например, точка внутри строк рассматривается как отдельный элемент, что, как оказалось, совсем не страшно).
    -Во-вторых, у тегов остался только один атрибут (w:rsidR), а вот w:rsidR, w14:textId, w:rsidRDefault, w:paraId и w:rsidP пропали. Все эти особенности приводят к тому, что наш класс-конвертер DocxToXml(про него подробно можно почитать здесь) подавится и поднимет лапки вверх с ошибкой NullReferenceException, что указывает на отсутствие индексирования параграфов внутри документа.

    Вместе с тем, если мы попытаемся такой файл отрыть в Word, то увидим, что все хорошо отображается, а таблицы и списки покоятся на своих местах! Магия!
    В общем, когда в поисках решения я потратил N часов на чтение документации, мои красные от дебагера глаза омылись горькими слезами, а один лишь запах кофе стремился показать коллегам мой дневной рацион, решение было найдено!
    Исходя из документации к формату doc и алгоритмов работы b2xtranslator, можно сделать вывод, что исторически в бинарных офисных текстовых документах отсутствовала индексация по параграфам*. Возникает задача расставить необходимые теги в нужных местах.
    За индекс параграфа отвечает атрибут тега paraId, о чем прямо написано здесь. Данный атрибут относится к пространству имен w14, о чем можно догадаться при изучении document.xml из архива .docx. В принципе, на скринах выше вы это тоже видите. Объявление пространства имен в .xml выглядит так:


    xmlns:wp14="http://personeltest.ru/away/schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
    

    Теперь давайте заставим b2xtranslator добавлять это пространство имен и идентификатор каждому параграфу. Для этого в файле ~\b2xtranslator\Common\OpenXmlLib\ContentTypes.cs после 113 строки добавим вот эту строчку:


    public const string WordprocessingML2010 = "http://schemas.microsoft.com/office/word/2010/wordml";
    

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

    Далее наша задача заставить библиотеку вставлять в начало файла ссылку на данное пространство имен. Для этого в файле ~\b2xtranslator\Doc\WordprocessingMLMapping\MainDocumentMapping.cs в 24 строке вставим код:


    this._writer.WriteAttributeString("xmlns", "w14", null, OpenXmlNamespaces.WordprocessingML2010);
    

    Разработчики библиотеки также позаботились о документации:


    Теперь дело за малым заставить b2xtranslator индексировать параграфы. В качестве индексов предлагаю использовать рандомно сгенерированные GUID может быть, это несколько тяжеловато, но зато надежно!

    Переходим в файл ~\b2xtranslator\Doc\WordprocessingMLMapping\DocumentMapping.cs и в 504 и 505 строки вставляем вот этот код:


    this._writer.WriteAttributeString("w14", "paraId", OpenXmlNamespaces.WordprocessingML2010, Guid.NewGuid().ToString());            this._writer.WriteAttributeString("w14", "textId", OpenXmlNamespaces.WordprocessingML2010, "77777777");
    

    Что касается второй строчки, в которой мы добавляем каждому тегу параграфа атрибут w14:textId = "77777777", то тут можно лишь сказать, что без этого атрибута ничего работать не будет. Для пытливых умов вот ссылка на документацию.
    Если серьезно, то, как я понимаю, атрибут используется, когда текст разделен на разные блоки, внутри которых происходит индексация тегов, которые могут иметь одинаковый Id внутри одного документа. Видимо, для этих случаев используется дополнительная индексация текстовых блоков. Однако, так как мы используем GUID, который в несколько раз больше индексов, используемых в вордовских документах по умолчанию, то генерацией отдельных индексов для текстовых блоков можно и пренебречь.


    Вот теперь мы получили .docx-файл, пригодный для дальнейшего преобразования в .xml. Подробнее о том, как работать с ним дальше, вы можете прочитать в этой статье или воспользоваться уже выложенным на github решением.


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


    Наконец, бонус для тех, кто хочет разобраться, что значат все эти бесконечные теги и их атрибуты в документах .docx и как они мапаются на бинарный .doc: советую заглянуть в файл ~\b2xtranslator\Doc\DocFileFormat\CharacterProperties.cs, а также посмотреть спецификацию для docx и doc.

Подробнее..

Recovery mode Типы, где их не ждали

12.11.2020 08:22:24 | Автор: admin

Давайте представим себе реализацию модуля Scaffold, который генерирует структуру с предопределенными пользовательскими полями и инжектит ее в вызываемый модуль при помощи use Scaffold. При вызове use Scaffold, fields: foo: [custom_type()], ... мы хотим реализовать правильный тип в Consumer модуле (common_field в примере ниже определен в Scaffold или еще где-нибудь извне).


@type t :: %Consumer{  common_field: [atom()],  foo: [custom_type()],  ...}

Было бы круто, если бы мы могли точно сгенерировать тип Consumer.t() для дальнейшего использования и создать соответствующую документацию для пользователей нашего нового модуля.


Lighthouse in French Catalonia


Пример посложнее будет выглядеть так:


defmodule Scaffold do  defmacro __using__(opts) do    quote do      @fields unquote(opts[:fields])      @type t :: %__MODULE__{        version: atom()        # magic      }      defstruct @fields    end  endenddefmodule Consumer do  use Scaffold, fields: [foo: integer(), bar: binary()]end

и, после компиляции:


defmodule Consumer do  @type t :: %Consumer{    version: atom(),    foo: integer(),    bar: binary()  }  defstruct ~w|version foo bar|aend

Выглядит несложно, да?


Наивный подход


Давайте начнем с анализа того, что за AST мы получим в Scaffold.__using__/1.


  defmacro __using__(opts) do    IO.inspect(opts)  end# [fields: [foo: {:integer, [line: 2], []},#            bar: {:binary, [line: 2], []}]]

Отлично. Выглядит так, как будто мы в шаге от успеха.


  quote do    custom_types = unquote(opts[:fields])    ...  end# == Compilation error in file lib/consumer.ex ==#  ** (CompileError) lib/consumer.ex:2: undefined function integer/0

Бамс! Типыэто чего-то особенного, как говорят в районе Привоза; мы не можем просто взять и достать их из AST где попало. Может быть, unquote по месту сработает?


      @type t :: %__MODULE__{              unquote_splicing([{:version, atom()} | opts[:fields]])            }# == Compilation error in file lib/scaffold.ex ==#  ** (CompileError) lib/scaffold.ex:11: undefined function atom/0

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


Ладно, кажется, нам нужно собрать все это богатство в AST и инжектнуть его целиком, а не по частям, чтобы компилятор увидел сразу правильное объявление.


Построение типа в AST


Я опущу тут пересказ нескольких часов моих метаний, мучений, и тычков пальцем в небо. Все знают, что я пишу код в основном наугад, ожидая, что вдруг какая-нибудь комбинация этих строк скомпилируется и заработает. В общем, сложности тут с контекстом. Мы должны пропихнуть полученные определения полей в неизменном виде напрямую в макрос, объявляющий тип, ни разу не попытавшись это AST анквотнуть (потому что в момент unquote типы наподобие binary() будут немедленно приняты за обыкновенную функцию и убиты из базуки вызваны компилятором напрямую, приводя к CompileError.


Кроме того, мы не можем использовать обычные функции внутри quote do, потому что все содержимое блока, переданного в quote, уже само по себеAST.


quote do  Enum.map([:foo, :bar], & &1)end# {#   {:., [], [{:__aliases__, [alias: false], [:Enum]}, :map]}, [],#     [[:foo, :bar], {:&, [], [{:&, [], [1]}]}]}

Видите? Вместо вызова функции, мы получили ее препарированное AST, все эти Enum, :map, и прочий маловнятный мусор. Иными словами, нам придется создать AST определения типа вне блока quote и потом просто анквотнуть внутри него. Давайте попробуем.


Чуть менее наивная попытка


Итак, нам надо инжектнуть AST как AST, не пытаясь его анквотнуть. Звучит устрашающе? Вовсе нет, отнюдь.


defmacro __using__(opts) do  fields = opts[:fields]  keys = Keyword.keys(fields)  type = ???  quote location: :keep do    @type t :: unquote(type)    defstruct unquote(keys)  endend

Все, что нам нужно сделать сейчас, это произвести надлежащий AST, все остальное в порядке. Ну, пусть ruby сделает это за нас!


iex|1  quote do...|1    %Foo{version: atom(), foo: binary()}...|1  end#{:%, [],#   [#     {:__aliases__, [alias: false], [:Foo]},#     {:%{}, [], [version: {:atom, [], []}, foo: {:binary, [], []}]}#   ]}

А нельзя ли попроще?


iex|2  quote do...|2    %{__struct__: Foo, version: atom(), foo: binary()}...|2  end# {:%{}, [],#   [#     __struct__: {:__aliases__, [alias: false], [:Foo]},#     version: {:atom, [], []},#     foo: {:binary, [], []}#   ]}

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


Почти работающее решение


defmacro __using__(opts) do  fields = opts[:fields]  keys = Keyword.keys(fields)  type =    {:%{}, [],      [        {:__struct__, {:__MODULE__, [], ruby}},        {:version, {:atom, [], []}}        | fields      ]}  quote location: :keep do    @type t :: unquote(type)    defstruct unquote(keys)  endend

или, если нет цели пробросить типы из собственно Scaffold, даже проще (как мне вот тут подсказали: Qqwy here). Осторожно, оно не будет работать с проброшенными типами, version: atom() за пределами блока quote выбросит исключение.


defmacro __using__(opts) do  fields = opts[:fields]  keys = Keyword.keys(fields)  fields_with_struct_name = [__struct__: __CALLER__.module] ++ fields  quote location: :keep do    @type t :: %{unquote_splicing(fields_with_struct)}    defstruct unquote(keys)  endend

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


Screenshot of type definition


Примечание: трюк с фрагментом AST


Но что, если у нас уже есть сложный блок AST внутри нашего __using__/1 макроса, который использует значения в кавычках? Переписать тонну кода, чтобы в результате запутаться в бесконечной череде вызовов unquote изнутри quote? Это просто даже не всегда возможно, если мы хотим иметь доступ ко всему, что объявлено внутри целевого модуля. На наше счастье, существует способ попроще.


NB для краткости я покажу простое решение для объявления всех пользовательских полей, имеющих тип atom(), которое тривиально расширяеься до принятия любых типов из входных параметров, включая внешние, такие как GenServer.on_start() и ему подобные. Эту часть я оставлю для энтузиастов в виде домашнего задания.

Итак, нам надо сгенерировать тип внутри блока quote do, потому что мы не можем передавать туда-сюда atom() (оно взовется с CompileError, как я показал выше). Хначит, что-нибудь типа такого:


keys = Keyword.keys(fields)type =  {:%{}, [],    [      {:__struct__, {:__MODULE__, [], ruby}},      {:version, {:atom, [], []}}      | Enum.zip(keys, Stream.cycle([{:atom, [], []}]))    ]}

Это все хорошо, но как теперь добавить этот АСТ в декларацию @type? На помощь приходит очень удобная функция эликсира под названием Quoted Fragment, специально добавленный в язык ради генерации кода во время компиляциию Например:


defmodule Squares do  Enum.each(1..42, fn i ->    def unquote(:"squared_#{i}")(),      do: unquote(i) * unquote(i)  end)endSquares.squared_5# 25

Quoted Fragments автоматически распознаются компилятором внутри блоков quote, с напрямую переданным контекстом (bind_quoted:). Проще простого.


defmacro __using__(opts) do  keys = Keyword.keys(opts[:fields])  quote location: :keep, bind_quoted: [keys: keys] do    type =      {:%{}, [],        [          {:__struct__, {:__MODULE__, [], ruby}},          {:version, {:atom, [], []}}          | Enum.zip(keys, Stream.cycle([{:atom, [], []}]))        ]}    #              @type t :: unquote(type)    defstruct keys  endend

Одинокий вызов unquote/1 тут разрешен, потому что bind_quoted: был напрямую указан как первый аргумент в вызове quote/2.




Удачного внедрения!

Подробнее..
Категории: Open source , Elixir/phoenix , Erlang/otp , Injection , Macros , Macro

Релиз Apache Ignite 2.9.0 что нового?

13.11.2020 14:18:57 | Автор: admin
Apache Ignite это высокопроизводительная распределенная база данных с открытым исходным кодом, предназначенная для хранения и распределенной обработки больших объемов данных в кластере узлов. Мы в Сбере активно его используем, и у нас есть команда, занимающаяся разработкой этого продукта. 23 октября 2020 года вышла новая версия Apache Ignite 2.9.0. Как менеджер данного релиза от лица всей команды разработчиков Apache Ignite хочу поделиться информацией об основных нововведениях.

  • Snapshots (Резервное копирование)
  • Трэйсинг
  • Новые возможности тонких клиентов
  • Режим работы кластера Только чтение
  • Запуск пользовательского кода в песочнице
  • Прозрачное шифрование данных: ротация мастер ключа
  • Инструменты для прерывания пользовательских задач и запросов
  • Кэширование на стороне платформы (.NET)
  • Подключение клиентских узлов к серверным через NAT


Snapshots (Резервное копирование)


В Ignite 2.9.0 появилась возможность создания резервной копии всех сохраняемых на диске кэшей (то есть кэшей, работающих в режиме Ignite Native Persistence) со всего кластера. Снапшоты могут создаваться онлайн, на активном кластере с пользовательской нагрузкой. При этом создается полностью консистентная копия всех данных кластера.

Запустить создание резервной копии можно одним из следующих способов:

  • с помощью command-line утилиты control.sh: control.sh --snapshot create <snapshot name>;
  • JMX операцией: MBean group="Snapshot", name=SnapshotMXBeanImpl, операция createSnapshot(<snapshot name>);
  • через Java API: Ignite.snapshot().createSnapshot("<snapshot name>").

Где <snapshot name> это уникальное имя снапшота.

После окончания формирования снапшота в директории work/snapshots/<snapshot name> (с настройками по умолчанию) каждого узла будет воссоздана структура файлового хранилища этого узла на момент старта снапшота. Сформированную файловую структуру можно использовать в дальнейшем для восстановления из резервной копии путем замены файлов с данными узла на файлы из директории снапшота.

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

Трэйсинг


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

В Ignite 2.9.0 трэйсинг охватывает следующие внутренние компоненты:

  • сообщения Discovery;
  • сообщения Communication;
  • процесс Exchange;
  • транзакции.

Чтобы посмотреть трэйсы, их необходимо экспортировать во внешнюю систему. Для этих целей Ignite использует библиотеку OpenCensus, которая из коробки предоставляет несколько экспортеров в различные системы (например, в Zipkin).

Ограничить объем экспортируемой информации можно, задав один или несколько перечисленных выше компонентов в качестве области интересов (scope) и установив частоту сэмплирования (настройки доступны для изменения в runtime).

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

Новые возможности тонких клиентов


В тонких клиентах java и .NET появился функционал Ignite, который до этого был доступен только в толстом клиенте.

Была добавлена возможность использовать:

  • cluster API & cluster group API (в .NET и java):
    • изменение режимов работы кластера;
    • получение информации о кластере;
    • фильтрация, группировка и получение информации об узлах кластера;
    • выполнение различных операций над группами узлов;
  • compute API (в .NET и java):
    • выполнение распределенных вычислений в кластере. В отличии от подобного функционала в толстом клиенте, который может использовать p2p class loader и сам автоматически загружать необходимые классы с клиента на серверные узлы, для запуска задачи тонким клиентом требуется чтобы весь исполняемый код уже был доступен в class-path серверных узлов (автоматическая загрузка классов с тонких клиентов не происходит);
  • Service Grid (пока только в java):
    • вызов сервисов Ignite. Как и в случае с compute API, тонким клиентом не предоставляется функционал по загрузке классов и развертыванию сервисов, возможен только вызов уже развернутых в кластере сервисов.

Кроме этого тонкий клиент .NET получил функцию автоматического обнаружения узлов кластера (Automatic Server Node Discovery), которая включается совместно с функционалом осведомленность о партициях (partition awareness). При использовании осведомленности о партициях клиент устанавливает соединение не с одним серверным узлом, а сразу с несколькими, для того чтобы по возможности отправить запрос на узел, который является основным для данных в этом запросе. Автоматическое обнаружение узлов кластера при этом позволяет не перечислять в конфигурации клиента все адреса узлов кластера. Достаточно чтобы клиент мог подключиться хотя бы к одному живому узлу, используя перечисленные в конфигурации адреса. Адреса остальных узлов клиент получит уже из кластера.

Подробнее об использовании новых возможностей можно узнать в соответствующих подразделах документации тонкого клиента java и тонкого клиента .NET.

Режим работы кластера Только чтение


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

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

Запуск пользовательского кода в песочнице


Ignite может запускать пользовательский код (такой как compute-задачи, слушатели событий, различные фильтры) на серверных узлах. Такой код выполнялся с теми же правами что и системный код Ignite и ему был доступен весь java API без ограничений. Потенциально опасный код мог нарушить работоспособность кластера (например, удалить файлы данных Ignite, завершить работу JVM и т.д.).

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

Для функционирования Ignite Sandbox необходимо наличие двух установленных и включенных компонентов:

  • Java security manager. Отвечает за авторизацию субъектов при выполнении вызовов системных java-библиотек. По умолчанию отключен;
  • Ignite security processor. Отвечает за аутентификацию субъектов доступа. Из коробки с Ignite не поставляется, требуется самостоятельная реализация и подключение с помощью плагина.

С более подробной информацией об Ignite Sandbox вы можете ознакомиться в официальной документации.

Прозрачное шифрование данных: ротация мастер ключа


Прозрачное шифрование данных (TDE Transparent data encryption) функционал, позволяющий не хранить данные на диске в открытом виде. Шифрование данных на диске средствами СУБД требуется, например, для сертификации по стандарту безопасности данных PCI DSS. В Apache Ignite базовый функционал TDE (первая фаза) был реализован в версии 2.7. В текущей версии была реализована вторая фаза TDE ротация мастер-ключа (мастер-ключом зашифрованы хранящиеся на диске кэш-ключи). Третья фаза TDE (ротация кэш-ключей) будет реализована в следующем релизе.

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

Инструменты для прерывания пользовательских задач и запросов


В предыдущих версиях Ignite не было целостного механизма прерывания пользовательских задач и запросов администратором. У пользователей была возможность отмены своих задач и запросов. Для администраторов были доступны отдельные, никак друг с другом не коррелирующие, инструменты (например, можно было прервать транзакции списком, по фильтру, через JMX или утилиту control.sh, и убить SQL-запрос с помощью SQL-команды KILL QUERY). В текущем релизе у администратора появилась возможность прерывать

  • различные виды запросов (SQL, scan, continous),
  • транзакции,
  • сompute-задачи,
  • Ignite-сервисы,

используя унифицированный интерфейс.

Все эти виды задач и запросов могут быть прерваны любым из следующих способов:

  • утилитой control.sh;
  • через JMX;
  • SQL-командой.

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

Кэширование на стороне платформы (.NET)


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

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

Подключение клиентских узлов к серверным через NAT


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

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

Заключение


Выше перечислены наиболее значимые изменения в релизе Apache Ignite 2.9.0. Но список изменений не ограничивается только ими. Как обычно, мы исправили множество ошибок и внесли множество других полезных улучшений. Полный список изменений можно посмотреть в release notes.
Подробнее..

Единороги на страже вашей безопасности исследуем код Bouncy Castle

13.11.2020 16:21:32 | Автор: admin
image1.png

Хотите увидеть новую порцию ошибок, найденных статическим анализатором PVS-Studio для Java? Тогда присоединяйтесь к прочтению статьи! В этот раз объектом проверки стал проект Bouncy Castle. Самые интересные фрагменты кода, как обычно, ждут вас ниже.

Немного о PVS-Studio


PVS-Studio инструмент для выявления ошибок и потенциальных уязвимостей в исходном коде программ. На момент написания статьи статический анализ реализован для программ, написанных на языках программирования C, C++, C# и Java.

Анализатор для Java самое молодое направление PVS-Studio. Несмотря на это, в поиске дефектов в коде он не уступает своим старшим братьям. Это связано с тем, что Java анализатор использует всю мощь механизмов из C++ анализатора. Об этом уникальном союзе Java и С++ можно почитать здесь.

На данный момент для более удобного использования существуют плагины для Gradle, Maven и IntelliJ IDEA. Если вы знакомы с платформой непрерывного контроля качества SonarQube, то, возможно, вам будет интересна идея поиграться с интеграцией результата анализа.

Немного о Bouncy Castle


Bouncy Castle это пакет с реализацией криптографических алгоритмов, написанный на языке программирования Java (также существует реализация на C#, но в данной статье речь пойдет не об этом). Данная библиотека дополняет стандартное криптографическое расширение (JCE) и содержит API, подходящий для использования в любой среде (включая J2ME).

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

Приступаем к проверке


Bouncy Castle довольно серьезный проект, ведь любая ошибка в такой библиотеке может снизить надежность системы шифрования. Поэтому сначала мы даже сомневались, сможем ли мы найти в данной библиотеке хоть что-то интересное, или же все ошибки уже были найдены и исправлены до нас. Скажем сразу, что наш Java анализатор нас не подвел :)

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

А мы приступим к рассмотрению самых интересных фрагментов кода, которые были обнаружены.

Недостижимый код


V6019 Unreachable code detected. It is possible that an error is present. XMSSTest.java(170)

public void testSignSHA256CompleteEvenHeight2() {    ....    int height = 10;    ....    for (int i = 0; i < (1 << height); i++) {        byte[] signature = xmss.sign(new byte[1024]);        switch (i) {            case 0x005b:                assertEquals(signatures[0], Hex.toHexString(signature));                break;            case 0x0822:                assertEquals(signatures[1], Hex.toHexString(signature));                break;            ....        }    }}

Значение переменной height в методе не меняется, поэтому счетчик i в цикле for не может быть больше, чем 1024 (1 << 10). Однако, в операторе switch второй case проверяет i на соответствие значению 0x0822 (2082). Естественно, проверка байта signatures[1] никогда не будет выполнена.

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

Идентичные подвыражения


V6001 There are identical sub-expressions 'tag == PacketTags.SECRET_KEY' to the left and to the right of the '||' operator. PGPUtil.java(212), PGPUtil.java(212)

public static boolean isKeyRing(byte[] blob) throws IOException {    BCPGInputStream bIn = new BCPGInputStream(new ByteArrayInputStream(blob));    int tag = bIn.nextPacketTag();    return tag == PacketTags.PUBLIC_KEY || tag == PacketTags.PUBLIC_SUBKEY        || tag == PacketTags.SECRET_KEY || tag == PacketTags.SECRET_KEY;}

В данном фрагменте кода в операторе return дважды производится проверка tag == PacketTags.SEKRET_KEY. По аналогии с проверкой публичного ключа, последняя проверка должна быть на равенство tag и PacketTags.SECRET_SUBKEY.

Идентичный код в if / else


V6004 The 'then' statement is equivalent to the 'else' statement. BcAsymmetricKeyUnwrapper.java(36), BcAsymmetricKeyUnwrapper.java(40)

public GenericKey generateUnwrappedKey(....) throws OperatorException {    ....    byte[] key = keyCipher.processBlock(....);    if (encryptedKeyAlgorithm.getAlgorithm().equals(....)) {        return new GenericKey(encryptedKeyAlgorithm, key);    } else {        return new GenericKey(encryptedKeyAlgorithm, key);    }}

В данном примере метод возвращает одинаковые экземпляры класса GenericKey вне зависимости от того, выполнено условие в if или нет. Понятно, что код в ветвях if / else должен отличаться, иначе проверка в if вообще не имеет смысла. Здесь программиста явно подвел копипаст.

Выражение всегда ложно


V6007 Expression '!(nGroups < 8)' is always false. CBZip2OutputStream.java(753)

private void sendMTFValues() throws IOException {    ....    int nGroups;    ....    if (nMTF < 200) {        nGroups = 2;    } else if (nMTF < 600) {        nGroups = 3;    } else if (nMTF < 1200) {        nGroups = 4;    } else if (nMTF < 2400) {        nGroups = 5;    } else {        nGroups = 6;    }    ....    if (!(nGroups < 8)) {        panic();    }}

Здесь переменной nGroups в блоках кода if / else присваивается значение, которое используется, но нигде не меняется. Выражение в операторе if всегда будет ложным, т.к. все возможные значения для nGroups: 2, 3, 4, 5 и 6 меньше 8.

Анализатор понимает, что метод panic() никогда не будет выполнен, и поэтому бьет тревогу. Но здесь, скорее всего, было использовано "защитное программирование", и беспокоиться не о чем.

Добавление одинаковых элементов


V6033 An item with the same key 'PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC' has already been added. PKCS12PBEUtils.java(50), PKCS12PBEUtils.java(49)

class PKCS12PBEUtils {    static {        ....        keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC,                     Integers.valueOf(192));        keySizes.put(PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC,                     Integers.valueOf(128));        ....        desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC);        desAlgs.add(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC);    }}

Эта ошибка снова из-за копипаста. В контейнер desAlgs добавляются два одинаковых элемента. Разработчик скопировал последнюю строчку кода, но исправить цифру 3 на 2 в имени поля забыл.

Индекс за пределами диапазона


V6025 Possibly index 'i' is out of bounds. HSSTests.java(384)

public void testVectorsFromReference() throws Exception {    List<LMSigParameters> lmsParameters = new ArrayList<LMSigParameters>();    List<LMOtsParameters> lmOtsParameters = new ArrayList<LMOtsParameters>();    ....    for (String line : lines) {                ....        if (line.startsWith("Depth:")) {            ....        } else if (line.startsWith("LMType:")) {            ....            lmsParameters.add(LMSigParameters.getParametersForType(typ));        } else if (line.startsWith("LMOtsType:")) {            ....            lmOtsParameters.add(LMOtsParameters.getParametersForType(typ));        }    }    ....    for (int i = 0; i != lmsParameters.size(); i++) {        lmsParams.add(new LMSParameters(lmsParameters.get(i),                                        lmOtsParameters.get(i)));    }}

Добавление элементов в коллекции lmsParameters и lmOtsParameters производится в первом цикле for, в разных ветках оператора if / else. Затем, во втором цикле for, осуществляется доступ к элементам коллекций по индексу i. При этом проверяется только то, что индекс i меньше, чем размер первой коллекции, а размер второй коллекции в цикле for не проверяется. Если размеры коллекций окажутся разными, то, вполне вероятно, можно получить IndexOutOfBoundsException. Правда, стоит отметить, что это код тестового метода, и особой опасности данное предупреждение не представляет, т.к. коллекции заполняются тестовыми данными из заранее созданного файла и, естественно, по окончанию добавления элементов, коллекции имеют одинаковый размер.

Использование до проверки на null


V6060 The 'params' reference was utilized before it was verified against null. BCDSAPublicKey.java(54), BCDSAPublicKey.java(53)

BCDSAPublicKey(DSAPublicKeyParameters params) {    this.y = params.getY();    if (params != null) {        this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(),                                            params.getParameters().getQ(),                                            params.getParameters().getG());    } else {        this.dsaSpec = null;    }    this.lwKeyParams = params;}

В первой строке метода переменной y присваивается значение params.getY(). Сразу же после присваивания переменная params проверяется на null. Если допускается, что в данном методе params может быть null, следовало сделать данную проверку перед тем, как использовать переменную.

Избыточная проверка в if / else


V6003 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. EnrollExample.java(108), EnrollExample.java(113)

public EnrollExample(String[] args) throws Exception {    ....    for (int t = 0; t < args.length; t++) {        String arg = args[t];        if (arg.equals("-r")) {            reEnroll = true;        } ....        else if (arg.equals("--keyStoreType")) {            keyStoreType = ExampleUtils.nextArgAsString                           ("Keystore type", args, t);            t += 1;        } else if (arg.equals("--keyStoreType")) {            keyStoreType = ExampleUtils.nextArgAsString                           ("Keystore type", args, t);            t += 1;        } ....    }}

В операторе if / else значение строки args дважды проверяется на равенство со строкой "--keyStoreType". Естественно, вторая проверка избыточна, и никакого смысла в ней нет. Однако, на ошибку это не похоже, т.к. в тексте справки по аргументам командной строки нет других параметров, которые бы не были обработаны в блоке if / else. Скорее всего, это избыточный код, который стоит удалить.

Метод возвращает одно и то же значение


V6014 It's odd that this method always returns one and the same value. XMSSSigner.java(129)

public AsymmetricKeyParameter getUpdatedPrivateKey() {    // if we've generated a signature return the last private key generated    // if we've only initialised leave it in place    // and return the next one instead.    synchronized (privateKey) {        if (hasGenerated) {            XMSSPrivateKeyParameters privKey = privateKey;            privateKey = null;            return privKey;        } else {            XMSSPrivateKeyParameters privKey = privateKey;            if (privKey != null) {                privateKey = privateKey.getNextKey();            }            return privKey;        }    }}

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

Подведем итоги


Как вы видите, ошибки в проекте Bouncy Castle нам все же удалось обнаружить, и это только лишний раз подтверждает, что никто из нас не пишет идеальный код. Разные факторы могут сработать: разработчик устал, невнимателен, его кто-то отвлек Пока код пишет человек ошибки будут встречаться всегда.

По мере роста проектов находить проблемы в коде становится все сложнее и сложнее. Поэтому в современном мире статический анализ кода это не просто очередная методология, а реальная необходимость. Даже если вы используете code review, TDD или динамический анализ это не значит, что можно отказаться от статического анализа. Это совершенно разные методологии, которые прекрасно дополняют друг друга.

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

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


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Irina Polynkina. Unicorns on Guard for Your Safety: Exploring the Bouncy Castle Code.
Подробнее..

Установка и настройка cSvn

14.11.2020 22:12:09 | Автор: admin

cSvn это web-интерфейс к Subversion репозиториям. Основу cSvn представляет CGI-скрипт написанный на языке С.


В данной статье рассматривается установка и настройка cSvn для работы с использованием Nginx + uWsgi. Настройка серверных компонентов достаточно проста и практически не отличается от настройки cGit.


На стороне клиента работает элементарный JavaScript составляющий не более 350 строк и таблица стилей размером 24K в распакованном виде. Markdown-тексты обрабатываются на стороне сервера с помощью библиотеки md4c, которая успешно зарекомендовала себя в проекте KDE Plasma.


Стоит заметить, что с помощью cSvn можно просматривать не только собственные репозитории, но и настроить просмотр сторонних ресурсов по протоколам HTTPS и SVN.



Требования к системе


cSvn использует библиотеки libpcre2, md4c, libmagic, входящую в состав пакета File и libxml2. На сервере должны быть установлены: HTTP сервер Nginx, сервер uWsgi и, разумеется Apache Subversion.


Инсталляция продуктов


cSvn пакет состоит из двух частей. Первая представляет собой обычный Linux демон, который отвечает за разбор конфигурационного файла /etc/csvnrc. Вторая непосредственно является CGI-скриптом, отвечающим на HTTP запросы клиента. Обе части устанавливаются одновременно.


Исходные тексты


Получить исходный пакет cSvn можно двумя способами: загрузить с FTP-сервера или с помощью Subversion:


svn checkout svn://radix.pro/csvn/trunk csvn

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


cd csvn./bootstarp

который установит Autotools средства, соберет коллекцию aclocal.m4 и создаст configure скрипт.


Сборка пакета


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


./configure --prefix=/usr \            --sysconfdir=/etc \            --with-config=/etc/csvnrc \            --with-controldir=/etc/rc.d \            --with-logrotatedir=/etc/logrotate.d \            --with-scriptdir=/var/www/htdocs/csvn \            --with-homedir=/var/lib/csvn \            --with-logdir=/var/log \            --with-piddir=/var/runmakemake install

Здесь, параметр --with-scriptdir определяет место установки CGI-скрипта и связанных с ним файлов, необходимых для работы сервера cSvn. Далее, в описании настроек сервера Nginx, мы будем использовать именно этот каталог. Разумеется, пользователи могут настроить работу cSvn и виртуального HTTP сервера относительно любого другоро каталога.


Права доступа


После инсталляции пакета cSvn необходимо отдать права на каталог /var/www/htdocs/csvn пользователю, от имени которого работает Nginx:


  chown -R nginx:nginx /var/www/htdocs/csvn


Subversion репозитории


Перед первым запуском сервера cSvn необходимо создать конфигурационный файл /etc/csvnrc, в котором должны быть определены все обязательные переменные и описан хотя бы один репозиторий.


На странице руководства csvnrc(5) приведен рабочий файл конфигурации сервера:


/etc/csvnrc:
svn-utc-offset = +0300;checkout-prefix-readonly = 'svn://radix.pro';checkout-prefix          = 'svn+ssh://svn@radix.pro';branches = 'branches';trunk    = 'trunk';tags     = 'tags';snapshots = 'tar.xz';css = '/.csvn/css/csvn.css';logo = '/.csvn/pixmaps/csvn-banner-280x280.png';logo-alt = "Radix.pro";logo-link = "https://radix.pro";main-menu-logo = '/.csvn/pixmaps/logo/SVN-logo-white-744x744.svg';favicon-path = '/.csvn/pixmaps/favicon';syntax-highlight-css = '_csvn.css';header = '/.csvn/html/header.html';footer = '/.csvn/html/footer.html';page-size = 200;owner = "Andrey V.Kosteltsev";author = "Andrey V.Kosteltsev";title = "Radix.pro SVN Repositories";description = "Subversion repositories hosted at radix.pro (St.-Petersburg)";keywords = "cSvn repositories";copyright = " Andrey V. Kosteltsev, 2019  2020.";copyright-notice = "Where any material of this site is being reproduced, published or issued to others the reference to the source is obligatory.";home-page = "https://radix.pro/";section "Tools" {  repo 'csvn' {    owner = "Andrey V.Kosteltsev";    title = "cSvn CGI Script";    description = "cSvn CGI Script  is a web frontend for Subversion Repositories";    home-page = "https://radix.pro/";  }}

Его можно использовать как начальный шаблон.


После создания конфигурационного файла /etc/csvnrc можно проверить работу csvnd(8) демона.


В случае работы на системе с BSD-like инициализацией, для запуска csvnd(8) демона достаточно выполнить команду


/etc/rc.d/rc.csvnd start

Для систем использующих systemd, необходимо воспользоваться утилитой systemctl:


systemctl enable csvnd.servicesystemctl start csvnd.service

Здесь необходимо упомянуть следующее...

При сборке и установке исходного пакета cSvn, устанавливается start/stop скрипт /etc/rc.d/rc.csvnd. Если же речь идет о системах использующих systemd, то для установки cSvn лучше использовать бинарный RPM или pacman пакет, поскольку в таких пакетах файл /etc/rc.d/rc.csvnd заменяется на Systemd Unit,


/usr/lib/systemd/system/csvnd.service:
[Unit]Description=The cSvn daemonAfter=network.target[Service]PIDFile=/var/run/csvnd.pidExecStart=/usr/sbin/csvnd --daemonize --inotify --config=/etc/csvnrcExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s TERM $MAINPID[Install]WantedBy=multi-user.target

устанавливаемый в каталог /usr/lib/systemd/system.


Если для используемой вами системы еще не создан пакет cSvn, то вы его можете приготовить самостоятельно, по инструкциям, приведенным к каталоге doc/build-packages.


Если же вы не хотите создавать пакет для вашей системы, то вы можете просто поместить файл csvnd.service в каталог /usr/lib/systemd/system/ и выполнить запуск демона самостоятельно.



После запуска csvnd(8) демона надо убедиться в существовании файла /dev/shm/csvn.bcf и, в случае его отсутствия посмотреть на ошибки приведенные в /var/log/csvnd.log файле.


Настройка uWsgi


Поскольку на этапе конфигурирования мы выбрали для инсталляции cSvn CGI-скрипта каталог /var/www/htdocs/csvn/, файл /etc/uwsgi/csvn.ini должен ваглядеть следующим образом:


/etc/uwsgi/csvn.ini:
[uwsgi]master          = trueplugins         = cgisocket          = /run/uwsgi/%n.sockuid             = nginxgid             = nginxprocname-master = uwsgi csvnprocesses       = 1threads         = 2cgi             = /var/www/htdocs/csvn/csvn.cgi

Здесь переменная cgi устанавливает полное имя CGI-скрипта cSvn.


Для запуска uWsgi демона на системах с BSD-like инициализацией, такой как Slackware, необходимо создать start/stop скрипт следующего вида:


/ets/rc.d/rc.csvn-uwsgi:
#!/bin/sh## uWSGI daemon control script.#CONF=csvnBIN=/usr/bin/uwsgiCONFDIR=/etc/uwsgiPID=/var/run/$CONF-uwsgi.piduwsgi_start() {  # Sanity checks.  if [ ! -r $CONFDIR/csvn.ini ]; then # no config files, exit:    echo "There are config files in $CONFDIR directory. Abort."    exit 1  fi  if [ -s $PID ]; then    echo "uWSGI for cSvn appears to already be running?"    exit 1  fi  echo "Starting uWSGI for cSvn server daemon..."  if [ -x $BIN ]; then    /bin/mkdir -p /run/uwsgi    /bin/chown nginx:nginx /run/uwsgi    /bin/chmod 0755 /run/uwsgi    $BIN --thunder-lock --pidfile $PID --daemonize /var/log/csvn-uwsgi.log --ini $CONFDIR/$CONF.ini  fi}uwsgi_stop() {  echo "Shutdown uWSGI for cSvn gracefully..."  /bin/kill -INT $(cat $PID)  /bin/rm -f $PID}uwsgi_reload() {  echo "Reloading uWSGI for cSvn configuration..."  kill -HUP $(cat $PID)}uwsgi_restart() {  uwsgi_stop  sleep 3  uwsgi_start}case "$1" in  start)    uwsgi_start    ;;  stop)    uwsgi_stop    ;;  reload)    uwsgi_reload    ;;  restart)    uwsgi_restart    ;;  *)  echo "usage: `basename $0` {start|stop|reload|restart}"esac

Дать ему права на выполнение


  chmod a+x /ets/rc.d/rc.csvn-uwsgi

и добавить следующие строчки в файлы /etc/rc.d/rc.M, /etc/rc.d/rc.6, соответственно:


/etc/rc.d/rc.M:
# Start uWSGI for cSvn server:if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then  /etc/rc.d/rc.csvn-uwsgi startfi

/etc/rc.d/rc.6:
# Stop uWSGI for cSvn server:if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then  /etc/rc.d/rc.csvn-uwsgi stopfi


Настройка Nginx


Конфигурационный файл, для выбранного нами каталога установки и домена csvn.example.org должен выглядеть следующим образом:


/etc/nginx/vhosts/csvn.example.org.conf:
## cSvn server:#    server {        listen 80;        server_name csvn.example.org;        return 301 https://csvn.example.org$request_uri;    }    server {        listen 443 ssl;        server_name csvn.example.org;        root /var/www/htdocs/csvn;        charset UTF-8;        #        # see:        #   https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security ,        #   https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html        #        # see also: http://classically.me/blogs/how-clear-hsts-settings-major-browsers        # and do not include includeSubdomains; parameter into line:        #        add_header Strict-Transport-Security "max-age=63072000; preload";        error_log /var/log/nginx/csvn.example.org-error.log;        access_log /var/log/nginx/csvn.example.org-access.log;        keepalive_timeout        60;        ssl_certificate          /etc/letsencrypt/live/csvn.example.org/fullchain.pem;        ssl_certificate_key      /etc/letsencrypt/live/csvn.example.org/privkey.pem;        ssl_trusted_certificate  /etc/letsencrypt/live/csvn.example.org/chain.pem;        ssl_protocols            SSLv3 TLSv1 TLSv1.1 TLSv1.2;        ssl_ciphers              "RC4:HIGH:!aNULL:!MD5:!kEDH";        gzip on;        gzip_disable "msie6";        gzip_comp_level 6;        gzip_min_length 1100;        gzip_buffers 16 8k;        gzip_proxied any;        gzip_types text/plain text/css text/js text/xml text/javascript                   image/svg+xml image/gif image/jpeg image/png                   application/json application/x-javascript application/xml application/xml+rss application/javascript                   font/truetype font/opentype application/font-woff application/font-woff2                   application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject application/font-sfnt;        #        # Serve static content with nginx        #        #        # Rewrite rules for versioning CSS + JS thtouh filemtime directive        #        location ~* ^.+.(css|js)$ {            rewrite ^(.+).(d+).(css|js)$ $1.$3 last;            expires 31536000s;            access_log off;            log_not_found off;            add_header Pragma public;            add_header Cache-Control "max-age=31536000, public";        }        #        # Caching of static files        #        location ~* .(eot|gif|gz|gzip|ico|jpg|jpeg|otf|pdf|png|svg|svgz|swf|tar|t?gz|woff|zip)$ {            expires 31536000s;            access_log off;            log_not_found off;            add_header Pragma public;            add_header Cache-Control "max-age=31536000, public";        }        location ~ ^/favicon.ico$ {            root /u3/nginx/vhosts/csvn;            access_log off;            log_not_found off;            expires 30d;        }        location = /robots.txt {            allow all;            log_not_found off;            access_log off;        }        location / {            try_files $uri @csvn;        }        location @csvn {            gzip off;            include uwsgi_params;            uwsgi_modifier1 9;            uwsgi_pass unix:/run/uwsgi/csvn.sock;        }    }

После создания файла /etc/nginx/vhosts/csvn.example.org.conf его необходимо включить в основной конфигурационный файл Nginx:


/etc/nginx/nginx.conf:
    include /etc/nginx/vhosts/csvn.example.org.conf;

После запуска uWsgi и Nginx можно заняться настройкой репозториев используя руководство csvnrc(5).



Заключительная настройка


Все необходимые файлы для работы на стороне web-клиента находятся в каталоге /var/www/htdocs/csvn/.csvn/. Редактируя файл /.csvn/html/header.html и меняя значения переменных в файле /etc/csvnrc, пользователь может сменить favicon.ico, поменять тему подсветки синтаксиса, выбрать изображения для собственных репозиториев, задать ключевые слова для поисковых систем, а также выполнить множество других настроек своего сервера.


Внешний вид интерфейса определяется единственным CSS-файлом и поэтому, пользователь может поменять тему web-интерфейса так, как ему будет необходимо.


Посмотреть на рабочую копию cSvn сервера можно здесь.

Подробнее..

Современный Web-UI для SVN в 2020 году

15.11.2020 00:20:52 | Автор: admin

cSvn это web-интерфейс к Subversion репозиториям. Основу cSvn представляет CGI-скрипт написанный на языке С.


В мае 2020 года был опубликован релиз очередной версии Apache Subversion 1.14.0. В свете этого события, был создан новый, современный web-интерфейс для просмотра Subversion репозиториев на любых устройствах. Это весьма позитивная новость для тех, кто использует централизованные системы версионного контроля по тому, что до вчерашнего дня существовал лишь один достойный web-UI (WebSVN), написанный на PHP и, к сожалению, отстающий от современных требований.


В данной статье рассматривается установка и настройка cSvn для работы с использованием Nginx + uWsgi. Настройка серверных компонентов достаточно проста и практически не отличается от настройки cGit.


На стороне клиента работает элементарный JavaScript составляющий не более 350 строк и таблица стилей размером 24K в распакованном виде. Markdown-тексты обрабатываются на стороне сервера с помощью библиотеки md4c, которая успешно зарекомендовала себя в проекте KDE Plasma.


Стоит заметить, что с помощью cSvn можно просматривать не только собственные репозитории, но и настроить просмотр сторонних ресурсов по протоколам HTTPS и SVN.



Требования к системе


cSvn использует библиотеки libpcre2, md4c, libmagic, входящую в состав пакета File и libxml2. На сервере должны быть установлены: HTTP сервер Nginx, сервер uWsgi и, разумеется Apache Subversion.


Инсталляция продуктов


cSvn пакет состоит из двух частей. Первая представляет собой обычный Linux демон, который отвечает за разбор конфигурационного файла /etc/csvnrc. Вторая непосредственно является CGI-скриптом, отвечающим на HTTP запросы клиента. Обе части устанавливаются одновременно.


Исходные тексты


Получить исходный пакет cSvn можно двумя способами: загрузить с FTP-сервера или с помощью Subversion:


svn checkout svn://radix.pro/csvn/trunk csvn

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


cd csvn./bootstarp

который установит Autotools средства, соберет коллекцию aclocal.m4 и создаст configure скрипт.


Сборка пакета


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


./configure --prefix=/usr \            --sysconfdir=/etc \            --with-config=/etc/csvnrc \            --with-controldir=/etc/rc.d \            --with-logrotatedir=/etc/logrotate.d \            --with-scriptdir=/var/www/htdocs/csvn \            --with-homedir=/var/lib/csvn \            --with-logdir=/var/log \            --with-piddir=/var/runmakemake install

Здесь, параметр --with-scriptdir определяет место установки CGI-скрипта и связанных с ним файлов, необходимых для работы сервера cSvn. Далее, в описании настроек сервера Nginx, мы будем использовать именно этот каталог. Разумеется, пользователи могут настроить работу cSvn и виртуального HTTP сервера относительно любого другоро каталога.


Права доступа


После инсталляции пакета cSvn необходимо отдать права на каталог /var/www/htdocs/csvn пользователю, от имени которого работает Nginx:


  chown -R nginx:nginx /var/www/htdocs/csvn


Subversion репозитории


Перед первым запуском сервера cSvn необходимо создать конфигурационный файл /etc/csvnrc, в котором должны быть определены все обязательные переменные и описан хотя бы один репозиторий.


На странице руководства csvnrc(5) приведен рабочий файл конфигурации сервера:


/etc/csvnrc:
svn-utc-offset = +0300;checkout-prefix-readonly = 'svn://radix.pro';checkout-prefix          = 'svn+ssh://svn@radix.pro';branches = 'branches';trunk    = 'trunk';tags     = 'tags';snapshots = 'tar.xz';css = '/.csvn/css/csvn.css';logo = '/.csvn/pixmaps/csvn-banner-280x280.png';logo-alt = "Radix.pro";logo-link = "https://radix.pro";main-menu-logo = '/.csvn/pixmaps/logo/SVN-logo-white-744x744.svg';favicon-path = '/.csvn/pixmaps/favicon';syntax-highlight-css = '_csvn.css';header = '/.csvn/html/header.html';footer = '/.csvn/html/footer.html';page-size = 200;owner = "Andrey V.Kosteltsev";author = "Andrey V.Kosteltsev";title = "Radix.pro SVN Repositories";description = "Subversion repositories hosted at radix.pro (St.-Petersburg)";keywords = "cSvn repositories";copyright = " Andrey V. Kosteltsev, 2019  2020.";copyright-notice = "Where any material of this site is being reproduced, published or issued to others the reference to the source is obligatory.";home-page = "https://radix.pro/";section "Tools" {  repo 'csvn' {    owner = "Andrey V.Kosteltsev";    title = "cSvn CGI Script";    description = "cSvn CGI Script  is a web frontend for Subversion Repositories";    home-page = "https://radix.pro/";  }}

Его можно использовать как начальный шаблон.


После создания конфигурационного файла /etc/csvnrc можно проверить работу csvnd(8) демона.


В случае работы на системе с BSD-like инициализацией, для запуска csvnd(8) демона достаточно выполнить команду


/etc/rc.d/rc.csvnd start

Для систем использующих systemd, необходимо воспользоваться утилитой systemctl:


systemctl enable csvnd.servicesystemctl start csvnd.service

Здесь необходимо упомянуть следующее...

При сборке и установке исходного пакета cSvn, устанавливается start/stop скрипт /etc/rc.d/rc.csvnd. Если же речь идет о системах использующих systemd, то для установки cSvn лучше использовать бинарный RPM или pacman пакет, поскольку в таких пакетах файл /etc/rc.d/rc.csvnd заменяется на Systemd Unit,


/usr/lib/systemd/system/csvnd.service:
[Unit]Description=The cSvn daemonAfter=network.target[Service]PIDFile=/var/run/csvnd.pidExecStart=/usr/sbin/csvnd --daemonize --inotify --config=/etc/csvnrcExecReload=/bin/kill -s HUP $MAINPIDExecStop=/bin/kill -s TERM $MAINPID[Install]WantedBy=multi-user.target

устанавливаемый в каталог /usr/lib/systemd/system.


Если для используемой вами системы еще не создан пакет cSvn, то вы его можете приготовить самостоятельно, по инструкциям, приведенным к каталоге doc/build-packages.


Если же вы не хотите создавать пакет для вашей системы, то вы можете просто поместить файл csvnd.service в каталог /usr/lib/systemd/system/ и выполнить запуск демона самостоятельно.



После запуска csvnd(8) демона надо убедиться в существовании файла /dev/shm/csvn.bcf и, в случае его отсутствия посмотреть на ошибки приведенные в /var/log/csvnd.log файле.


Настройка uWsgi


Поскольку на этапе конфигурирования мы выбрали для инсталляции cSvn CGI-скрипта каталог /var/www/htdocs/csvn/, файл /etc/uwsgi/csvn.ini должен ваглядеть следующим образом:


/etc/uwsgi/csvn.ini:
[uwsgi]master          = trueplugins         = cgisocket          = /run/uwsgi/%n.sockuid             = nginxgid             = nginxprocname-master = uwsgi csvnprocesses       = 1threads         = 2cgi             = /var/www/htdocs/csvn/csvn.cgi

Здесь переменная cgi устанавливает полное имя CGI-скрипта cSvn.


Для запуска uWsgi демона на системах с BSD-like инициализацией, такой как Slackware, необходимо создать start/stop скрипт следующего вида:


/ets/rc.d/rc.csvn-uwsgi:
#!/bin/sh## uWSGI daemon control script.#CONF=csvnBIN=/usr/bin/uwsgiCONFDIR=/etc/uwsgiPID=/var/run/$CONF-uwsgi.piduwsgi_start() {  # Sanity checks.  if [ ! -r $CONFDIR/csvn.ini ]; then # no config files, exit:    echo "There are config files in $CONFDIR directory. Abort."    exit 1  fi  if [ -s $PID ]; then    echo "uWSGI for cSvn appears to already be running?"    exit 1  fi  echo "Starting uWSGI for cSvn server daemon..."  if [ -x $BIN ]; then    /bin/mkdir -p /run/uwsgi    /bin/chown nginx:nginx /run/uwsgi    /bin/chmod 0755 /run/uwsgi    $BIN --thunder-lock --pidfile $PID --daemonize /var/log/csvn-uwsgi.log --ini $CONFDIR/$CONF.ini  fi}uwsgi_stop() {  echo "Shutdown uWSGI for cSvn gracefully..."  /bin/kill -INT $(cat $PID)  /bin/rm -f $PID}uwsgi_reload() {  echo "Reloading uWSGI for cSvn configuration..."  kill -HUP $(cat $PID)}uwsgi_restart() {  uwsgi_stop  sleep 3  uwsgi_start}case "$1" in  start)    uwsgi_start    ;;  stop)    uwsgi_stop    ;;  reload)    uwsgi_reload    ;;  restart)    uwsgi_restart    ;;  *)  echo "usage: `basename $0` {start|stop|reload|restart}"esac

Дать ему права на выполнение


  chmod a+x /ets/rc.d/rc.csvn-uwsgi

и добавить следующие строчки в файлы /etc/rc.d/rc.M, /etc/rc.d/rc.6, соответственно:


/etc/rc.d/rc.M:
# Start uWSGI for cSvn server:if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then  /etc/rc.d/rc.csvn-uwsgi startfi

/etc/rc.d/rc.6:
# Stop uWSGI for cSvn server:if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then  /etc/rc.d/rc.csvn-uwsgi stopfi


Настройка Nginx


Конфигурационный файл, для выбранного нами каталога установки и домена csvn.example.org должен выглядеть следующим образом:


/etc/nginx/vhosts/csvn.example.org.conf:
## cSvn server:#    server {        listen 80;        server_name csvn.example.org;        return 301 https://csvn.example.org$request_uri;    }    server {        listen 443 ssl;        server_name csvn.example.org;        root /var/www/htdocs/csvn;        charset UTF-8;        #        # see:        #   https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security ,        #   https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html        #        # see also: http://classically.me/blogs/how-clear-hsts-settings-major-browsers        # and do not include includeSubdomains; parameter into line:        #        add_header Strict-Transport-Security "max-age=63072000; preload";        error_log /var/log/nginx/csvn.example.org-error.log;        access_log /var/log/nginx/csvn.example.org-access.log;        keepalive_timeout        60;        ssl_certificate          /etc/letsencrypt/live/csvn.example.org/fullchain.pem;        ssl_certificate_key      /etc/letsencrypt/live/csvn.example.org/privkey.pem;        ssl_trusted_certificate  /etc/letsencrypt/live/csvn.example.org/chain.pem;        ssl_protocols            SSLv3 TLSv1 TLSv1.1 TLSv1.2;        ssl_ciphers              "RC4:HIGH:!aNULL:!MD5:!kEDH";        gzip on;        gzip_disable "msie6";        gzip_comp_level 6;        gzip_min_length 1100;        gzip_buffers 16 8k;        gzip_proxied any;        gzip_types text/plain text/css text/js text/xml text/javascript                   image/svg+xml image/gif image/jpeg image/png                   application/json application/x-javascript application/xml application/xml+rss application/javascript                   font/truetype font/opentype application/font-woff application/font-woff2                   application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject application/font-sfnt;        #        # Serve static content with nginx        #        #        # Rewrite rules for versioning CSS + JS thtouh filemtime directive        #        location ~* ^.+.(css|js)$ {            rewrite ^(.+).(d+).(css|js)$ $1.$3 last;            expires 31536000s;            access_log off;            log_not_found off;            add_header Pragma public;            add_header Cache-Control "max-age=31536000, public";        }        #        # Caching of static files        #        location ~* .(eot|gif|gz|gzip|ico|jpg|jpeg|otf|pdf|png|svg|svgz|swf|tar|t?gz|woff|zip)$ {            expires 31536000s;            access_log off;            log_not_found off;            add_header Pragma public;            add_header Cache-Control "max-age=31536000, public";        }        location ~ ^/favicon.ico$ {            root /u3/nginx/vhosts/csvn;            access_log off;            log_not_found off;            expires 30d;        }        location = /robots.txt {            allow all;            log_not_found off;            access_log off;        }        location / {            try_files $uri @csvn;        }        location @csvn {            gzip off;            include uwsgi_params;            uwsgi_modifier1 9;            uwsgi_pass unix:/run/uwsgi/csvn.sock;        }    }

После создания файла /etc/nginx/vhosts/csvn.example.org.conf его необходимо включить в основной конфигурационный файл Nginx:


/etc/nginx/nginx.conf:
    include /etc/nginx/vhosts/csvn.example.org.conf;

После запуска uWsgi и Nginx можно заняться настройкой репозториев используя руководство csvnrc(5).



Заключительная настройка


Все необходимые файлы для работы на стороне web-клиента находятся в каталоге /var/www/htdocs/csvn/.csvn/. Редактируя файл /.csvn/html/header.html и меняя значения переменных в файле /etc/csvnrc, пользователь может сменить favicon.ico, поменять тему подсветки синтаксиса, выбрать изображения для собственных репозиториев, задать ключевые слова для поисковых систем, а также выполнить множество других настроек своего сервера.


Внешний вид интерфейса определяется единственным CSS-файлом и поэтому, пользователь может поменять тему web-интерфейса так, как ему будет необходимо.


Посмотреть на рабочую копию cSvn сервера можно здесь.

Подробнее..

Recovery mode Типы в рантайме глубже в крольчью нору

19.11.2020 10:11:44 | Автор: admin

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


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


# @fields [foo: 42]# defstruct @fields@definition var: atom()use Foo, @definition

Lighthouse in French Catalonia


Код выше не то, что не обработает тип так, как нам хочетсяон не соберется вовсе, потому что @definition var: atom() выбросит исключение ** (CompileError) undefined function atom/0.


Наивный подход


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


Итак, я начал с того, что сделал две разных реализации __using__/1: одну, которая принимает список (и ожидает увидеть в нем пары field type()), и другую принимающую все, что угодно, ожидая встретить в аргументах либо квотированные типы, либо триплы {Module, :type, [params]}. Я использовал сигил ~q||, который был услужливо имплементирован мной же, в одном из стародавних игрушечных проектов, во времена, когда я учился работать с макросами и AST. Он позволяет вместо quote/1 писать лаконичнее: foo: ~q|atom()|. Там внутри я руками строил список, который потом передавался в первую функцию, принимающую списки. Весь этот код был настоящим кошмаром. Я сомневаюсь, что видел что-то более невнятное за всю свою карьеру, несмотря на то, что я чувствую себя абсолютно комфортно с регулярными выражениями, они мне нравятся, и я их часто использую. Однажды я выиграл спор на воспроизведение регулярного выражения для электронной почты максимально близко к оригиналу, но этот код, всего-то передававший туда-сюда старый добрый простой эрланговский тип оказался в пять раз запутаннее и как-то неаккуратнее, что ли.


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


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


Tyyppi


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


В ядре эликсира присутствует незадокументированный модуль Code.Typespec, который существенно облегчил мне жизнь. Я начал с очень простого подхода: с проверки всех возможных термов по всем возможным типам. Я просто загрузил все типы, доступные в моей текущей сессии, и дописывал новые обработчики по мере того, как рекурсивный анализ типов падал глубже по рекурсии. Честно говоря, это было скорее скучно, чем весело. Зато оно привело меня к первой полезной части этой библиотекифункции Tyyppi.of?/2, которая принимает тип и терм, а возвращает логическое значение да/нет в зависимости от того, принадлежит ли терм указанному типу.


iex|tyyppi|1  Tyyppi.of? GenServer.on_start(), {:ok, self()}# trueiex|tyyppi|2  Tyyppi.of? GenServer.on_start(), :ok# false

Мне нужно было какое-то внутреннее представление для типов, поэтому я решил хранить все в виде структуры с именем Tyyppi.T. Так у Tyyppi.of?/2 появился брат-близнец Tyyppi.of_type?/2.


iex|tyyppi|3  type = Tyyppi.parse(GenServer.on_start)iex|tyyppi|4  Tyyppi.of_type? type, {:ok, self()}# true

Единственный нюанс, связанный с этим подходом, заключается в том, что мне нужно загрузить и сохранить все типы, доступные в системе, и эта информация не будет доступна в релизах. На данный момент я прекрасно справляюсь с хранением всего этого в обычном файле при помощи :erlang.term_to_binary/1, который связывается с релизом и загружается через обычный специализированный Config.Provider.


Структуры


Теперь я был полностью вооружен, чтобы вернуться к своей первоначальной задаче: создать удобный способ объявления типизированной структуры. Со всем этим багажом на борту, это было легко. Я решил ограничить само объявление структуры явным встроенным литералом, содержащим пары key: type(). Также я реализовал для него Access, с проверкой типов при upserts. Имея все это под рукой, я решил позаимствовать еще пару идей у Ecto.Changeset и добавил перегружаемые функции cast_field/1 и validate/1.


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


defmodule MyStruct do  import Kernel, except: [defstruct: 1]  import Tyyppi.Struct, only: [defstruct: 1]  @typedoc "The user type defined before `defstruct/1` declaration"  @type my_type :: :ok | {:error, term()}  @defaults foo: :default,            bar: :erlang.list_to_pid('<0.0.0>'),            baz: {:error, :reason}  defstruct foo: atom(), bar: GenServer.on_start(), baz: my_type()  def cast_foo(atom) when is_atom(atom), do: atom  def cast_foo(binary) when is_binary(binary),    do: String.to_atom(binary)  def validate(%{foo: :default} = my_struct), do: {:ok, my_struct}  def validate(%{foo: foo} = my_struct), do: {:error, {:foo, foo}end

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


Весь код библиотеки доступен, как всегда, на гитхабе.




Удачного рантаймтайпинга!

Подробнее..
Категории: Open source , Elixir/phoenix , Erlang/otp , Injection , Macros , Macro

Ubuntu Web Remix альтернатива Chrome OS c браузером Firefox вместо Google Chrome

20.11.2020 04:16:11 | Автор: admin

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

Единственная проблема хромбуков то, что в качестве ОС используется Chrome OS с браузером Chrome или Chromium. Это ПО нравится хотя и многим, но не всем. Большое количество пользователей принимает Chrome OS вынужденно, не имея альтернативы. Но теперь, кажется, она появилась. Речь идет о дистрибутиве Linux, который получил название Ubuntu Web Remix. Его начали разрабатывать в начале лета, а сейчас он доступен для загрузки.

Основа дистрибутива Ubuntu. Но разработчик постарался следовать минимализму Chrome OS, упростив интерфейс оригинальной операционной системы. Вместо Google Chrome здесь используется браузер Firefox, несколько веб-приложений из /e/, плюс Anbox, инструмент, который дает возможность запускать Android-приложения на Linux.

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


Дистрибутив дает возможность установить практически любое приложение для Ubuntu при помощи apt-get, но вот Ubuntu Software Center в этой ОС нет. Вместо этого используется линк на Open Web Store, размещенный в таскабре. При клике по ярлыку пользователь попадает на сат, где можно найти набор приложений на все случаи жизни. После загрузки и установки они отображаются в списке приложений ОС.

Для работы каждого из эти веб-приложений используется браузер Firefox. Каждое новое запущенное приложение открывается в новой вкладке.

Сейчас в базе Open Web Store есть SoundCloud, YouTube, Facebook, Twitter и Mastadon. Но сторонние разработчики могут создавать собственные веб-приложения, предлагая их автору проекта для размещения. При желании можно разрабатывать веб-приложения для самого себя автор предоставил необходимый инструмент.


Может ли Ubuntu Web Remix на текущем этапе заменить собой Chrome OS? Пока что нет, проекту нужно еще поразвиваться некоторое время. Тем не менее, базовые функции эта ОС выполняет, так что использовать дистрибутив для решения ряда обычных задач вполне можно.

Сложно сказать, когда Ubuntu Web Remix станет хотя бы приблизительно такой же функциональной операционной системой, как Chrome OS ведь у разработчика нет тех же ресурсов, что есть у корпорации Google. Да и приобрести убунтубук с предустановленной Ubuntu Web Remix тоже нельзя по крайней мере, пока.


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

Стоит отметить, что разработчик, создавший этот дистрибутив, развивает и проекты Ubuntu Unity Remix с Ubuntu Education. Что касается первого упомянутого проекта, то это модифицированный дистрибутив Ubuntu 20.04, он базируется на оболочке Unity версии 7 и оконным менеджером Compiz. Второй проект дистрибутив, предназначенный для использования в школах, вузах и других учебных заведениях.

Подробнее..

Изучение иностранных языков с помощью программ для чтения

22.11.2020 00:21:34 | Автор: admin

Всем здравствуйте!


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


Должен сразу оговориться, что больше рассказ коснётся KnownReader (он же KR), который мы разрабатываем, а также близкого семейства, построенного на одном движке (CoolReader, он же CR; KOReader). Но кое-какие ссылки и на другие приложения будут даны, если потребуется. Хотелось не столько поделиться собственными ноу-хау, сколько рассказать, как оно работает изнутри, с какими проблемами пришлось столкнуться и как они были решены, а заодно и познакомить читателя с интерфейсом и возможностями приложения. Потому что читалка это целая философия, без понимания которой можно не заметить целый океан возможностей, скрытых от взгляда обывателя.


Выделяем, переводим


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


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


Для некоторых словарей (в том числе онлайн) есть возможность уточнить направление перевода.


Направление перевода
Направление перевода Перевод (Lingvo)

Про элементы управления


Должен сделать небольшое отступление о том, как устроены элементы управления в программах для чтения. Читалка вещь уникальная тем, что она должна быть похожа на книгу. Поэтому на всём своём пространстве она рисует текст. А если везде текст, как же ей управлять? И вот что обычно предлагают читалки:
Тап-зоны это зоны экрана (в KR их 9 3х3), на нажатие которых можно назначить действия. Очевидно, должны быть как минимум следующая/предыдущая страницы, но не только. Разнообразие действий очень велико, а потому тут каждый развлекается как может. Буквально. В настройках KR можно настроить тап-зоны под себя;


Тап зоны


Жесты. Всякие смахивания, проведения слева направо, сверху вниз и т.п.;
Панель с кнопками. Её не все любят, считая её визуальным мусором, но не все и не любят.


Про ноу-хау


И эти самые базовые возможности в KR заиграли по-своему, т.е. даже в таких в некотором смысле стандартных аспектах взаимодействия с читалкой KR отметился своим подходом. Вот что здесь было доработано:


  1. В качестве словаря в KR можно указать любую программу, которая может принимать в себя текст (хоть СМС отправляйте). Это удобно, если у вас есть какой-то словарь, про который KR не знает. Отмечу также, что и переключение словарей также можно вынести на тап-зону;
  2. Сделали несколько настроек словарей, между которыми можно быстро переключаться (режимы переключить на 2 словарь, переключить на 2 словарь на один следующий перевод, потом вернуться обратно);

Словари и режимы выделения
Настройки словарей Настройки различных видов выделения в разных режимах: режим чтения, выделения, инспектора

  1. Добавили уникальное действие длинный двойной тап. Это когда вы делаете двойной тап, но не отпускаете палец после второго тапа. На это уникальное действие можно настроить что душе угодно. Например, вызов другого словаря. Если вы знаете другую читалку, которая умеет длинный двойной тап, напишите об этом в комментариях или в личку. Мне правда интересно;
  2. К жестам (это не про словари, но все равно напишу) добавили возможность менять размер шрифта диагональным щипком и размеры полей горизонтальным и вертикальными щипками. Тут следует отметить, что аудитория читалки отреагировала хорошо. Но не вся аудитория. А потому без правок не обошлось. В следующем же релизе пришлось вынести в настройки возможность отключения управления жестами;
  3. Разнообразили панель с кнопками её теперь можно очень гибко настраивать: изменять список и функции кнопок, регулировать её размер (больше, меньше, средний) и цвет. Вообще, гибкость настраивания это про KR. Возможно, кого-то это может запутать поначалу, но было замечено, что к такой свободе люди быстро привыкают и неохотно от неё отказываются.

Несколько словарей


Одна из моих любимых тем.


Минутка заботы от автора материала

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


  1. Элемент управления или пункт меню в читалке;
  2. Приложение для отображения словарей (Abbyy, GoldenDict и т.д.);
  3. Конкретный словарь (например Толковый словарь Ушакова), отображаемый в пункте выше.
    Как правило, из контекста понятно о чём идет речь. Если непонятно, спрашивайте, отвечу.

Как правило, хватает двух словарей. Но в KR их больше. И вот что это даёт:


  1. Разнообразие. В одной программе могут быть одни словарные статьи, в другой другие. Где-то есть транскрипция, где-то нет. Какие-то умеют переводить фразы (Яндекс, Гугл, Промт), какие-то могут оперировать только словами.
  2. Словари языковые и толковые. Может быть интересно посмотреть как перевод слова, так и его толкование (википедия, энциклопедии и т.д.).

Стоит сказать пару слов о приложениях-словарях, достойных внимания:


  • Lingvo. Очень достойное приложение от уважаемой фирмы ABBYY. Всё на уровне, даже с проговаривателем. Умеем показывать его в карточке (т.е. на часть экрана). Есть хороший такой минус это платно. Как сама программа, так и словари. Я покупал английский словарь за 20 долларов (а для России ещё и с НДС). Другой значимый минус в том, что нельзя повлиять на развитие. Например, я просил поддержку добавить кнопку скопировать словарную статью уж столько воды утекло, а её до сих пор не добавили.
  • GoldenDict. Очень хорошая вещь, практически не имеющая аналогов, у которой есть куча словарей. Их очень много. Также GoldenDict умеет найти словари из Lingvo и использовать их. Есть форк на форуме 4pda, который привносит некоторую функциональность и осовременивает интерфейс. От минусов совсем грустно становится развитие остановилось, исходников программы нет. Да и платный он, этот GoldenDict.
  • Aard 2. Совершенно уникальная вещь. Программа создана для обработки больших (даже не больших, а огромных) словарей. На сайте Aardа выкладываются дампы википедий. Представляете, оффлайновая википедия в телефоне? Ух...

Любопытный вариант использования Aard

Аард один раз лично мне очень помог в работе (в настоящей, за которую деньги платят). У него есть утилита Slob (на питоне), которая позволяет выполнять поиск словарных статей и выгружать их в html формат. Нам (моей команде на работе) нужно было обогатить информацию о населённых пунктах РФ данными из википедии (численность населения по годам и т.д.). Мы разработали свою утилиту, которая запускала Slob и давала ей на вход название населенного пункта (например Пермь). Далее находились все статьи (с околопермской тематикой), после чего мы пакетно обрабатывали файлы и легко вычисляли нужный (через jsoup) по наличию определённых атрибутов коды ОКАТО, ОКТМО и т.д., затем забирали из него нужные данные (страницы википедии хорошо шаблонизированы и структурированы). Так задача была решена в автоматическом режиме по всем населённым пунктам РФ.


  • Яндекс Переводчик / Гугл Переводчик. Это уже новое веяние, они в представлении не нуждаются. Работают, развиваются, очень хороши. Недавно, правда, Яндекс немного расстроили, переведя свой API переводчика на платные рельсы. Мы об этом писали на форуме и даже инструкцию оформили о том, как его теперь готовить для использования в KR. Поэтому здесь повторяться не буду. Если кому интересно станет, заходите, в нашей ветке на форуме уютно.
  • Если знаете другие хорошие словари добавляйте в комментарии, обсудим.

Пользовательский словарь


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


Онлайн-словарь
Перевод в онлайн-словаре Перевод в онлайн-словаре

Пользовательский словарь
Сохранённые слова в пользовательском словаре Быстрый просмотр слова из пользовательского словаря

Цитаты, история поиска
Диалог пользовательский словарь / цитаты / история поиска в словаре Диалог пользовательский словарь / цитаты / история поиска в словаре

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


  1. При выделении слова оно запоминается внутри KR как последнее выделенное слово.
  2. Дальше оно уходит во внешнюю программу-словарь.
  3. Мы в свою очередь прочитали, посмотрели, дальше ВДЕЛИЛИ словарную статью и СКОПИРОВАЛИ её в буфер обмена, затем вернулись в KR и нажали действие (мы же помним, что его можно назначить на тап-зону) создать элемент пользовательского словаря по последнему выделению и содержимому буфера обмена (знаем, что надо поработать над формулировкой, но как есть), после чего осталось только нажать OK. Можно даже без буфера есть возможность отправить текст в KR через всплывающее меню андроида функциональность PROCESS_TEXT.
    Что здесь сложно? Копирование словарной статьи. Это снова подержать, подвигать ползунки (не у нас, а в программе-словаре). Хорошо, мы упорные. Поговорили с коллегами из GoldenDict mod, сделали для них доработку добавили кнопку в GoldenDict, чтобы можно было хотя бы выделить словарную статью. Коллеги обещали нашу доработку включить в свой билд и выпустить. Ждём-с.

Онлайн словари


Пользовательский словарь это не только нижняя панелька. Это полноценное окно пользовательский словарь / цитаты / история поиска в словаре. С поиском и т.д. Вызывается также по действию, либо можно нажать на ссылку слов: Х.
Вроде бы и звучит хорошо, но мало. Мы живем в современном мире. Современный мир живет в онлайне. Поэтому тут мы добавили онлайновые словари Яндекс, Lingvo, Wikipedia (пока еще в ранней реализации).:


  1. Яндекс хорош тем, что переводит несколько слов (добавили действие перевести всю страницу). Лингво расширенными словарными статьями и транскрипциями. Википедия хороша сама по себе.
  2. Технически онлайновый словарь вызывается не выходя из KR, т.е. вызывается в собственном интерфейсе KR. Таким образом мы получили главную ценность у нас нет необходимости копировать перевод, вставлять в пользовательский словарь и т.д. Перевод в онлайновом словаре автоматически заносит слово в историю с переводом. И мы сразу видим его на следующих страницах. Профит.
  3. Минусы онлайновых словарей тоже очевидны зависимость от внешних сервисов с их ограничениями (которые могут меняться), а также необходимость быть онлайн.
    Ну, это, в целом, более чем приемлемо.

Режимы


Ещё не уснули? Тогда пойдём дальше, в глубь. Про выделение слов и текста я уже сказал, но тут есть ещё возможности:


  1. Режим выделения.
    Включается режим выделения (страница текста обводится сплошной рамочкой), в котором слово можно выделить в один тап, а несколько слов тапнули и провели. Что мы поменяли. В режиме выделения можно настроить другие словари на действия. Действий три: выделение слова, выделение нескольких слов, выделение слова по длинному двойному тапу. Это расширяет возможности использования выделения. Допустим в обычном режиме перевод в англо-русском словаре, в режиме выделения в википедии.
  2. Режим инспектора.
    Страница текста выделяется штрихпунктирной рамочкой. Режим выделения после перевода отключается. Режим инспектора это такой залипающий режим выделения, который включен, пока не выключен. Удобно, например, если хочется протыкать много слов на странице друг за другом и получить быстрый перевод по каждому. Также в режиме инспектора тоже можно настроить свои словари (на три варианта выделения).

Режимы
Режим выделения Режим инспектора

Википедия
Поиск в Википедии список статей Википедия выбранная статья

Что дальше?


Много всего сказано, но хочется большего:


  • У нас есть возможность отображения в горизонтальном расположении устройства текста в виде двух страниц (выглядит совсем как раскрытая книга). И это можно как-то обыграть. Есть мысль сделать возможность на одной странице показывать исходный текст, а на второй перевод этого текста.

Отображение двух страниц


  • Пользовательский словарь. Сейчас найденные слова на странице отрисовываются на нижней панельке. Есть желание просто подсвечивать их в тексте в виде примерно как гиперссылка.
  • Лингво-онлайн умеет отдать wav-файл с озвучкой. У нас пока не реализовано, но можно сделать проговариватель.
  • Википедия-онлайн у нас выводится без форматирования. Можно развиваться в эту сторону.
    К чему это я? Да к тому, что приложение живёт, пока оно кому-нибудь нужно. Желательно, чтобы оно было нужно не только его автору и паре-тройке его друзей. Нет, это, конечно, тоже уже кое-что, но всегда хочется большего. Если вы посетите нашу ветку на 4pda, то, возможно, заметите, что у нас ведётся достаточно активное обсуждение новых фич и старых багов. У нас есть своя аудитория, мы ценим её мнение и дорожим ей. Но взгляд со стороны довольно часто бывает полезным. А потому приглашаю вас, хабровчане, к обсуждению.
Подробнее..

Категории

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

© 2006-2020, personeltest.ru