Небольшая предыстория и мотив написания

Когда я только знакомился с OSDev, я очень долго искал соответствующие материалы. Находил и на YouTube, и на Habr, и просто какие‑то англоязычные сайты (тогда я не сильно знал английский). Но почти все что я находил было либо незаконченным, либо недостаточно понятным и полным.

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

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

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

Переходим к мясу. И все‑таки, как это делают?

Сразу хочу сказать, что в этой статье я буду использовать не UEFI, а BIOS. Не потому что так лучше, просто потому что с UEFI я не знаком.

В этой статье мы напишем мини загрузчик, который сможет просто вывести «Hello, world».

Наверняка это не первая статья, которую вы читали, задаваясь довольно сложной, нишевой и довольно уважаемой целью — написание своей ОС, поэтому вы натыкались на что‑то по типу int 0x10, но не понимали, что вообще на здесь происходит. Именно поэтому мы сейчас разберем, что именно делает BIOS, и что из этого мы можем использовать.

BIOS поможет, BIOS услышит..

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

Немного про диск. Диск делится на огромное количество секторов, которые в себе сохраняют 512 байт. Именно поэтому ограничение на размер загрузчика составляет лишь 512 байт (либо 4096 байт на новых дисках), ибо BIOS загружает лишь один первый сектор по адресу в оперативной памяти 0x7C00.

Про векторы прерываний

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

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

Важно, что IVT работает только в реальном режиме (как на 8086), а как только процессор переключается в защищенный или 64-битный режим, используется исключительно IDT.

Перед тем, как BIOS любезно загрузит весь первый сектор в память по адресу 0x7C00 и передать прямо туда управление (как раз нашему загрузчику), он всегда заполняет таблицу прерываний своими функциями (ту самую IVT). К ним мы и обращаемся инструкцией int. Она никак не связана с типом данных int из C/C++ и многих других языков, она расшифровывается как Interrupt. Прерывания делятся на исключения, программные и аппаратные — исключения вызывает сам процессор, когда не может выполнить какую-либо инструкцию, если мы пытаемся поделить на 0, или просто плохо действуем на кремниевые нервы процессора. программные прерывания вызывает сама программа по собственному желанию с помощью инструкции int, а вот аппаратные прерывания позволяют нашему ядру обработать события от внешних устройств, таких как нажатие клавиши или готовность данных.

BIOS ставит в качестве своих обработчиков функции, которые как раз и выполняют всю грязную работу на ранних этапах загрузки ОС. Один из таких обработчиков находится по номеру 0x10 в нашей таблице (кстати, в ассемблере, который используем мы (FASM), 10h и 0x10 — это просто два способа записи числа в 16-ричной системе, и они абсолютно эквивалентны друг другу), и выполняет он основную работу с экраном. Он умеет переключать видеорежимы (об этом позже), печатать символ на экран, ждать ввод от пользователя и еще очень многие вещи. Все это — подфункции. Номер нужной нам подфункции мы можем указать в ax регистре.

В целом мы готовы приступать к первому коду, написанному уже, очень надеюсь, с полным пониманием всего происходящего. Давайте напишем простой Hello, world, который работает уже без помощи ни Windows, ни Linux, ни MacOS, ни любой другой ОС. Приступим!

Hello, world по-мужски

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

Привык к CLion, и вам советую, ибо в этой серии статей мы долго циклиться на ассемблере не станем:)
Привык к CLion, и вам советую, ибо в этой серии статей мы долго циклиться на ассемблере не станем:)

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

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

fasm os/boot.asm build/boot.bin
qemu-system-i386 build/boot.bin

Здесь мы просто компилируем наш бутлоадер (тот самый загрузчик) и сразу скармливаем его QEMU.

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

QEMU запустился. Но BIOS решил, что это не загрузочный диск и пошел дальше искать, откуда можно загрузиться. Почему? Он просто смотрит байты со смещением 510 и 511 (в секторе на 512 байт это два последних байта) первого сектора диска, на котором и хранится наш загрузчик. Эти два байта должны быть равны 0x55 и 0xAA. Исправим это одним хитрым, но единственным способом.

times 510-($-$$) db 0 ; заполнение нулями до 510 байт 
db 0x55 ; первая часть сигнатуры
db 0xAA ; вторая часть сигнатуры

Лично мне раньше не была понятна строка times 510-($-$$) db 0. В times N мы говорим ассемблеру повторить инструкцию N раз, которую мы сразу после него пишем, в нашем случае это db 0. 510-($-$$) — это мы взяли общий размер загрузчика, из которого вычли эти два байта на сигнатуру (510), потом из этих 510 мы вычитаем размер уже написанного нами кода с помощью $-$$, где $ является текущей точкой, а $$ — точкой начала всей программы.

Допустим, мы написали 100 байт кода, и расположили эту заветную times 510-($-$$) db 0. Получается 510 - (100 - 0) = 410. В реальности числа могут быть другими, но всегда в $‑$$ получится размер кода, который мы уже написали, в байтах. Получается общий размер программы (без учета 2-байтовой сигнатуры) 510 байт. Потом добавляем те самые 0x55 и 0xAA и получаем ровно 512 байт. Проверим? Запускаем наш скрипт компиляции (у меня он comp.bat).

Qemu успешно загрузил наш загрузчик. BIOS увидел сигнатуру 0x55 0xAA и передал управление нашему коду. Правда, код пока ничего не делает — просто висит. Исправим это в следующем шаге.
Qemu успешно загрузил наш загрузчик. BIOS увидел сигнатуру 0x55 0xAA и передал управление нашему коду. Правда, код пока ничего не делает — просто висит. Исправим это в следующем шаге.

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

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

org 0x7C00

; именно с этой точки и начинается вся работа загрузчика

times 510-($-$$) db 0
db 0x55
db 0xAA

И начинаем писать наш долгожданный «Hello, world». Для начала инициализируем сегментные регистры, значения которых BIOS мог оставить любыми.

org 0x7C00

start:
    xor ax, ax        ; обнуляем AX
    mov ds, ax        ; обнуляем DS
    mov es, ax        ; обнуляем ES

times 510-($-$$) db 0
db 0x55
db 0xAA

Теперь можем приступать к выводу нашей строки на экран. В ассемблере нет никаких циклов, поэтому мы используем создание меток и переход по ним. Алгоритм вывода строки прост: так как строки должны заканчиваться нулем (не '0', а '\0', код которого равен тоже 0), мы просто идем по байтам (символам) нашей строки и поочередно говорим BIOS вывести наш символ на экран с помощью int 0x10 и его подфункции AH=0xE. Для начала, выведем просто H.

org 0x7C00

start:
    xor ax, ax        ; обнуляем AX
    mov ds, ax        ; обнуляем DS
    mov es, ax        ; обнуляем ES

    mov ah, 0xE       ; ставим номер подфункции (напечатать символ и сдвинуть курсор)
    mov al, 'H'       ; ставим сам символ
    int 0x10          ; вызываем видео-сервис

stop:                 ; останавливаем код, чтобы процессор не исполнял мусор
    hlt
    jmp stop

times 510-($-$$) db 0
db 0x55
db 0xAA

Итак, наш загрузчик вывел свой первый символ. Можем приступать к циклу.

org 0x7C00

start:
    xor ax, ax        ; обнуляем AX
    mov ds, ax        ; обнуляем DS
    mov es, ax        ; обнуляем ES

    mov si, msg       ; ставим в si адрес первого символа msg
print_cycle:
    mov al, byte[si]  ; загружаем в al символ, который находится по адресу si
    cmp al, 0         ; сравниваем al с нулем
    je print_end      ; если al был равен нулю, то прыгаем
    mov ah, 0xE       ; ставим номер подфункции (напечатать символ и сдвинуть курсор)
    int 0x10          ; вызываем видео-сервис
    inc si            ; инкрементируем si (сдвигаем указатель на 1)
    jmp print_cycle   ; прыгаем обратно в начало цикла

print_end:
    ; здесь мы уже вывели наше сообщение
    jmp stop          ; на всякий случай прыгаем на метку stop

stop:                 ; останавливаем код, чтобы процессор не исполнял мусор
    hlt
    jmp stop

msg db "Hello, world", 0

times 510-($-$$) db 0
db 0x55
db 0xAA

Запускаем код и видим, что наш загрузчик успешно напечатал долгожданный Hello, world.

Заключение

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

Жду ваших мнений, исправлений, критики и в целом обратной связи.

Комментарии (33)


  1. KarmaCraft
    14.08.2026 18:22

    Интересная статья, интересно что будет дальше


  1. olku
    14.08.2026 18:22

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


    1. sashz
      14.08.2026 18:22

      я бы сказал - хватит! таких статей тут завались, а толку с них - ноль.


  1. Alex_Builder
    14.08.2026 18:22

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

    Успехов в начинании!
    Даже если большого толку не будет, то знания архитектуры работы ОС на уровне железа всегда пригодятся.


    1. risc32 Автор
      14.08.2026 18:22

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


      1. olku
        14.08.2026 18:22

        Может есть ниша. Слышал, что Андроид не полностью открытая ОС, а iOS и подавно


        1. risc32 Автор
          14.08.2026 18:22

          андроид вообще на линуксе:) странная штука, этот андроид


        1. Moog_Prodigy
          14.08.2026 18:22

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

          1.Разрабатываем железо и пишем к нему проприетарные дрова.

          2.Берем чистый андроид, пихаем туда проприетарные дрова, допиливаем под себя, лочим, ставим макс.

          3.Выпускаем смартфон.

          3.1 Profit!

          4.Забываем про него, goto 1


      1. SpLab
        14.08.2026 18:22

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

        Пока плюсую авансом. Жду продолжения.


        1. risc32 Автор
          14.08.2026 18:22

          хорошо, учту, спасибо


  1. checkpoint
    14.08.2026 18:22

    Писать свою ОС для платформы PC - дело неблагодарное. Платформа PC за десятилетия своего существования обросла слишком большим количеством мха (BIOS, APM, EUFI, ACPI, Protected Mode, Long Mode, PCI, USB). Охватить всё это в одиночку за конечное время просто невозможно. Поэтому я синтезировал в ПЛИС свою несложную платформу на базе RV32IMFAC и потихоньку пилю для неё софт. Из законченного есть пока только Monitor (он же - загрузчик и отладчик).


    1. Alex_Builder
      14.08.2026 18:22

      Да, интЭресно, конечно. Но только как хобби.
      И как всегда возникает вопрос - на кой это надо с прагматичной точки зрения?
      А именно - кто это купит да или даже просто кто это возьмется поддерживать?
      Одно дело - прикладная программа от одного разработчика под всем известную ОСь, НО совсем другое дело принципиально новая ОСь, от одного разработчика, которая к тому же ни WinAPI, ни Posix. Во всяком случае, я не увидел там упоминания про posix.
      Т.е. кому это надо кроме вас, ну и может быть маленького кружка заинтересовавшихся по приколу?

      Линус Торвальдс ведь не просто очередное колесо когда-то изобрёл, он ещё и подогнал его под всем уже известный к тому времени posix.

      А так постоянно подобные хобби-эксперименты проскакивают. Я знаю некоторые оригинальные решения даже на чистом Free Pascal (т.е. даже не на Си). Например, Ultibo:
      https://ultibo.org/
      С другой стороны прикольно, конечно и интересно, наверное, если свободного времени много.


      1. risc32 Автор
        14.08.2026 18:22

        разрабатывать свое ядро это просто прикольно. это такой проект, который никогда нельзя «закончить», ибо там работы на десятилетия. здесь человек учится самому думать, как поведет себя код, и в целом лично я заметно поднял свои знания, занимаясь OSDev’ом. но работа реально неблагодарная — никому не нужна чья-то хобби ОС, которая способна максимум Doom2 запустить, или что-то по типу этого) просто интересно, и все


        1. Alex_Builder
          14.08.2026 18:22

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

          При том, что почти все конкуренты тогда были платными и даже порой очень дорогими (если на сервере) HP-UX, SunOS и т.п.
          А зато сейчас бесплатных Линуксов хоть "попой ешь" :D На любой вкус.
          И если уж мечтать, что ваше "новое колесо" покатит ещё кто-то кроме вас, то нужно понимать, почему бы это ему понадобилось...

          Но в любом случае успехов!


          1. risc32 Автор
            14.08.2026 18:22

            спасибо, вам тоже успехов)


          1. checkpoint
            14.08.2026 18:22

            А зато сейчас бесплатных Линуксов хоть "попой ешь" :D На любой вкус.

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


      1. checkpoint
        14.08.2026 18:22

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

        Я поясню зачем это нужно. Да, коммерческого приложения в такой разработке не много, но оно всё же есть - мы разрабатываем свои электронные изделия на базе МК и ПЛИС, иметь свою миниатюрную ОС заточенную под наши задачи это благо!

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


        1. Alex_Builder
          14.08.2026 18:22

          Кто-то же должен знать как устроены операционные систем, чтобы нести это знание в массы

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

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

          Но раз вам надо, как вы говорите, то значит надо.
          А десятилетиями отлаженных QNX, VxWorks, LinxOS и т.п. для вашего железа разве нет?


  1. vybo
    14.08.2026 18:22

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


  1. SIISII
    14.08.2026 18:22

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

    Ну и отдельно отмечу, что, в отличие от 90% авторов Хабра, здесь всё достаточно хорошо в плане русского языка: оркографией и лапописанием автор таки владеет.


  1. redfox0
    14.08.2026 18:22

    Опять 16-ти битный режим процессора x86… Всё жду, когда кто-нибудь напишет статью про запуск самодельного ядра ОС прямо из /EFI/BOOT/BOOTX64.EFI

    Хотя нет, вот одна статья есть: https://habr.com/ru/articles/798587/


    1. strvv
      14.08.2026 18:22

      Были ещё циклы статей про GOP и другие части приложения на uefi


  1. Wi11k4
    14.08.2026 18:22

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


  1. DrMefistO
    14.08.2026 18:22

    Я так и не увидел в коде метки stop, на которую Вы прыгаете. Или она встроенная?

    Так же, из замечаний: странно в оборот вводить какие-то сокращения (IVT и IDT), и говорить о них так, будто это что-то известное, не поясняя до этого что это и как расшифровывается.


    1. risc32 Автор
      14.08.2026 18:22

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


      1. DrMefistO
        14.08.2026 18:22

        А, прошу прощения, увидел метку stop, там цикл stop: hlt, jmp stop.


  1. ShaltaiBoltai
    14.08.2026 18:22

    Странно, что автора начали спрашивать сразу: "А кто у вас эту вашу ОС купит?", как будто автор ее продавать собирается. Как будто у автора вообще есть, что продавать. Хорошо, хоть карму в минус 20 не загнали. Неужели не видно, что автор просто делает это из чистого любопытства: "А получится ли?" Что никакой серьезный, да что там серьезный, никакой вообще хоть как-то работающий продукт даже не обсуждается? Автор просто ради собственного удовольствия посмотрел: "А можно ли в течении пары часов сделать голый загрузчик для компа?" Молодец, попробовал, поделился. А с него уже начали спрашивать, как с будущего Билла Гейтса.

    Что же касается разработок реальных ОС энтузиастами, коли об этом речь зашла. Знаете такой проект ReactOS? Он ровесник Linux Линуса Торвальдса . Знаете, чего проект добился за сопоставимый срок жизни 30 лет? Да примерно того же, чего добился автор этой статьи: оно загружаеццо! Вот что бывает, когда во главу угла ставится вопрос "А кому мы это продадим?" вместо "А как сделать рабочую ОС?"


  1. SkalolazOther
    14.08.2026 18:22

    Ну, насколько я слышал, то под ReactOS даже (вроде бы) запускали банковский терминал. Как там было дело дальше, не знаю. По моему мнению, автор статьи делает никому не нужную работу, даже ему эта "перспективная" ось не нужна. Я еще понимаю, если бы он написал хоть какую то утилиту, которая закрывала бы его потребности (может еще нескольких человек), но тут все упираться даже не в то запуститься ОС или нет, а в необходимость написания к этой ОС еще утилит аналоги CP, MKDIR и т.д. История помнит уже не одну "любительскую" ОС, которые были не чета этой, и где они все .... вопрос риторический если чё ... Такое мое непрофессиональное ИМХО...


    1. Seraphimt
      14.08.2026 18:22

      По моему мнению, автор статьи делает никому не нужную работу

      А знаете, кто ещё делает ненужную работу? Студенты на практиках - то компилятор напишут, то 2д движок, то вообще хеллоуворды какие, как будто не знают, что их уже тысячи существуют.


  1. OlegZH
    14.08.2026 18:22

    Понятное дело, что всякая ОС реализуется снизу. Но проектировать её надо сверху. Нужно что-то предложить пользователю, некую модель приложений.


  1. brumbrum
    14.08.2026 18:22

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

    Таненбаум Э. - Современные операционные системы


    1. alexs963
      14.08.2026 18:22

      • Вильям Столлингс. Операционные системы. Внутренняя структура и принципы проектирования.


    1. lkik
      14.08.2026 18:22

      книга Операционные системы. Три простых элемента (Арпачи-Дюрсо)

      перевод https://habr.com/ru/articles/446340/