#opensource
Обзор исходников Telegram Desktop💬
Для меня Telegram - основное средство связи со всеми коллегами и знакомыми. Поэтому я решил посмотреть в исходники десктопного Telegram и возможно что-нибудь переделать под себя.
Эти исходники находятся тут - https://github.com/telegramdesktop/tdesktop, там же внизу ссылки на инструкции по билду Telegram.
Я попробовал сбилдить Telegram для Linux на двух ноутбуках и на виртуалке, и у меня не получилось, вплоть до того что навернулось окружение рабочего стола на одном ноутбуке😶 Сначала чинил кривые скрипты сборки, потом пытался обновить старую версию Glib, и так далее.
Зато получилось с полпинка сбилдить его для Windows😁 Вспомнил как выглядит Visual Studio: скриншот.
Исходники самого Telegram сравнительно небольшие, но вместе с ним качается и билдится из исходников куча хрени (~25 либ включая ffmpeg и Qt, в размере несколько гигабайтов).
Десктоп написан на движке Qt, с довольно хорошим кодом, он сравнительно небольшой. После исследования известны такие факты:
1️⃣ Что-нибудь "сломать" в самом Телеграме не выйдет, так как десктоп сделан правильно - это всего лишь красивая оболочка над Telegram API, которая получает и посылает все данные из сервера.
Например, когда мы видим статус
2️⃣ Можно написать свой десктоп или даже консольный Телеграм, но на это сомнительное в своей полезности занятие уйдет слишком много времени.
3️⃣ Если собрать "свой" Телеграм и зайти туда хоть раз, то твой аккаунт ставят на счётчик ставят под колпак. За действиями с аккаунта будут следить, в случае разных приколов (спам, накрутка, другой абьюз) будет вечный бан. Об этом честно предупреждают. 🔫
Поменять работу сервера Telegram не выйдет, но можно кастомизировать клиент под свои приколы или под приколы компании, если это рабочий инструмент (вместо такого сизифова труда, как создание своего мессенджера с нуля).
Я сделал такую мелкую фичу: в написанном сообщении обнаруживаются все http-ссылки и заменяются на укороченный вариант из clck.ru. Это может быть нужно для безопасности, если в компании есть свой сервис url shortener для внутренних ссылок, но не хочется тратить по 5-10 секунд для вбивания каждой ссылки.
К счастью, Qt это одна из лучших библиотек C++ на свете, поэтому там есть почти всё свое. Контейнеры (как
Единственный минус - Qt очень заточен под асинхронность, поэтому пришлось сделать какой-то фокус (с 3-го раза), чтобы поставить барьер для ожидания ответов на http-запрос.
✨ Примерный коммит, который включает короткие урлы (с параллельными походами!), выглядит так. (И еще такой кусок кода во "внешней" либе). Там работа со строками.
🔍 😐 Гифка с результатом
Урлы из гифки:
исходник1, исходник2, исходник3
https://clck.ru/34A7Hv, https://clck.ru/3vyXS, https://clck.ru/8f7h6
При желании можно достаточно сильно кастомизировать Telegram, чтобы в нем показывалось больше информации (например, соответствие профиля юзера и его аккаунта во внутренней сети компании, его должность, и т.д.)
Обзор исходников Telegram Desktop
Для меня Telegram - основное средство связи со всеми коллегами и знакомыми. Поэтому я решил посмотреть в исходники десктопного Telegram и возможно что-нибудь переделать под себя.
Эти исходники находятся тут - https://github.com/telegramdesktop/tdesktop, там же внизу ссылки на инструкции по билду Telegram.
Я попробовал сбилдить Telegram для Linux на двух ноутбуках и на виртуалке, и у меня не получилось, вплоть до того что навернулось окружение рабочего стола на одном ноутбуке
Зато получилось с полпинка сбилдить его для Windows
Исходники самого Telegram сравнительно небольшие, но вместе с ним качается и билдится из исходников куча хрени (~25 либ включая ffmpeg и Qt, в размере несколько гигабайтов).
Десктоп написан на движке Qt, с довольно хорошим кодом, он сравнительно небольшой. После исследования известны такие факты:
Например, когда мы видим статус
last seen recently
вместо точного времени (есть такая настройка), то десктоп действительно не знает точного времени - сервер отдает ему именно такой статус.Поменять работу сервера Telegram не выйдет, но можно кастомизировать клиент под свои приколы или под приколы компании, если это рабочий инструмент (вместо такого сизифова труда, как создание своего мессенджера с нуля).
Я сделал такую мелкую фичу: в написанном сообщении обнаруживаются все http-ссылки и заменяются на укороченный вариант из clck.ru. Это может быть нужно для безопасности, если в компании есть свой сервис url shortener для внутренних ссылок, но не хочется тратить по 5-10 секунд для вбивания каждой ссылки.
К счастью, Qt это одна из лучших библиотек C++ на свете, поэтому там есть почти всё свое. Контейнеры (как
QVector
, QList
, QString
), регексы, сеть, и очень многое другое. Поэтому такие задачи делаются сравнительно без проблем.Единственный минус - Qt очень заточен под асинхронность, поэтому пришлось сделать какой-то фокус (с 3-го раза), чтобы поставить барьер для ожидания ответов на http-запрос.
Урлы из гифки:
исходник1, исходник2, исходник3
https://clck.ru/34A7Hv, https://clck.ru/3vyXS, https://clck.ru/8f7h6
При желании можно достаточно сильно кастомизировать Telegram, чтобы в нем показывалось больше информации (например, соответствие профиля юзера и его аккаунта во внутренней сети компании, его должность, и т.д.)
Please open Telegram to view this post
VIEW IN TELEGRAM
#creepy
Как выбить из C++ настоящий адрес объекта🌃
Недавно коллега искал причины какого-то бага. У нас система многопоточная с большим количеством объектов, поэтому было решено вместе с логами выводить адрес объекта в памяти, к которому относится лог. Это выглядело примерно так:
😁 То есть фильтр логов по адресу показывал явно не все логи, которые должны были быть. После исследования нашли, что такие куски кода:
😒
Класс
Но есть тот факт, что виртуальные классы нормально работают со смещенными указателями. Если указатель когда-то начнет указывать не на тот адрес, то он все равно разрушится по правильному адресу при вызове виртуального деструктора.
😐 Для информации я прочитал две крутые статьи:
C++ vtables - Part 1 - Basics
C++ vtables - Part 2 - Multiple Inheritance
Оттуда узнаем такие факты (верные для 64-битного Linux с включенным rtti):
1️⃣ vtable pointer указывает не на начало vtable, а смещен на 16 байт от начала. Первые 8 байт это число 2️⃣ Компилятор генерирует особые методы под названием thunk, которые фиксят смещение указателя
Продолжение в комментарии - нахождение реального адреса!
Как выбить из C++ настоящий адрес объекта
Недавно коллега искал причины какого-то бага. У нас система многопоточная с большим количеством объектов, поэтому было решено вместе с логами выводить адрес объекта в памяти, к которому относится лог. Это выглядело примерно так:
std::shared_ptr<CallService> callService = ...;Спустя некоторое время оказалось, что созданные объекты пропадают с концами
LOG_INFO("blah blah blah " << callService); // выведет адрес `callService` в конце
void Foo::Bar(std::weak_ptr<IListener> listener) {где
LOG_INFO("add listener " << listener.lock().get());
}
listener
это указатель на callService
(а класс IListener
- предок класса CallService
), выводит этот же адрес со смещением, в данном случае было на +4 байта вперед Класс
CallService
имел множественное наследование, а из-за этого указатели на базовые типы могли указывать со смещением. На простом примере:struct Foo { int i; };Это логично, потому что указатель должен давать доступ к под-объектам без всяких приколов, то есть вызов
struct Bar { short s; };
struct Baz { char c; };
struct All : Foo, Bar, Baz {};
// ...
All all; // &all == 0x7ffdfa3ce770
Foo* foo = &all; // foo == 0x7ffdfa3ce770
Bar* bar = &all; // bar == 0x7ffdfa3ce774
Baz* baz = &all; // baz == 0x7ffdfa3ce776
bar->s
должен работать одинаково, без разницы куда указывает bar
. Таким образом, затея коллеги полностью провалилась, полностью.Но есть тот факт, что виртуальные классы нормально работают со смещенными указателями. Если указатель когда-то начнет указывать не на тот адрес, то он все равно разрушится по правильному адресу при вызове виртуального деструктора.
// IEdible - виртуальный класс, (с `virtual ~IEdible()`)То же самое верно для других виртуальных методов. Если взять указатель на предок, и он будет смещенным, то вызов метода все равно отработает корректно, а точнее - неявный параметр
// struct Mango : IFruit, IEdible
std::unique_ptr<IEdible> edible;
{
std::unique_ptr<Mango> mango = std::make_unique<Mango>();
std::cout << mango << std::endl; // вывод "0x56366c90beb0"
edible = std::move(mango);
}
std::cout << edible << std::endl; // вывод "0x56366c90beb8"
// удаляется объект именно по правильному адресу "0x56366c90beb0"!
// с вызовом ~Mango()
this
будет пофикшен.struct IEdible {Таким образом можно попробовать найти "настоящий" адрес объекта виртуального класса
virtual ~IEdible() = default;
virtual void Eat() = 0;
};
struct Mango : IFruit, IEdible {
void Eat() override { Eaten = true; }; // используется неявный `this`
bool Eaten = false;
};
// ...
IEdible& e = ...; // смещенный указатель
e.Eat(); // работает корректно!
C++ vtables - Part 1 - Basics
C++ vtables - Part 2 - Multiple Inheritance
Оттуда узнаем такие факты (верные для 64-битного Linux с включенным rtti):
top_offset
(смещение относительно реального объекта), вторые 8 байт это указатель на объект typeinfo
this
на реальный и потом вызывают нужный метод. В примере выше e.Eat()
на самом деле вызовет thunk, который сместит this
на -8
(это top_offset
) и потом вызовет Mango::Eat()
.Продолжение в комментарии - нахождение реального адреса!
Please open Telegram to view this post
VIEW IN TELEGRAM
#compiler
Простые тесты для C++ кода на Python🍄 🍄 🍄 🍄 🍄
Часто хочется покрыть тестами код на C++ в проекте - не логику, которую описывает код, а сам исходный код. Сейчас для этого есть приличное количество чекеров в clang-tidy. Можно написать свой чекер, который все равно будут ревьюить много месяцев и КПД всего этого занятия близок к нулю. Для специфических проверок надо что-то колхозить самому.
Примерных проверок может быть много:
1️⃣ Запрет на использование
2️⃣ Запрет на использование старого API в новом коде во время масштабного рефакторинга.
3️⃣ Проверка, что в начале каждого файла находится копипаста лицензии проекта.
Можно придумать проверку на примере лямбд😊 Пусть у нас есть такой код:
Если переменная используется только внутри лямбды, то ее можно вкостылить прямо в capture list. Тогда вместо двух верхних строк примера будет такая строка, дающая аналогичный результат:
Попробуем сделать тест на такие кейсы😁 Если мы для этого используем библиотеки clang, то логика такая:
1️⃣ Получаем AST (Abstract Syntax Tree) из исходного кода.
2️⃣ Лямбды в AST это вершины
3️⃣ "Объявление переменной" в AST это вершина
4️⃣ "Использование переменной" (в каком-то месте) это вершина
5️⃣ Если все "использования переменной" находятся внутри какого-то одного и того же
6️⃣ Делаем рекурсивный обход AST с корня и держанием указателя на "текущую лямбду", и делаем проверку на пункт 5.
Этот тест можно сделать на👩💻 C++: вкостылить новый чекер в локальной сборке clang-tidy или просто сделать программу на libclang. Но можно сделать то же самое на 👩💻 Python и кода будет меньше в несколько раз, и это делается быстрее - менее муторно. Python хорошо подходит для быстрого написания разных тестов.
Поддерживается libclang в Python, и после просмотра примеров можно поставить его себе:
Также не хватает некоторых очевидных фичей, например получения родительской ноды: в курсорах есть пара ссылок на другие курсоры (типа родительские, двух видов), но они работают неправильно.
Кроме тестов можно писать другие тулзы, например "кодогенераторы" - которые сгенерируют какой-нибудь исходник на основе существующего кода. Про кодогенераторы можно почитать лонгрид.
Еще можно делать "исправляторы" исходников - которые берут AST, что-то туда дописывают и сохраняют в другой файл, а компилятор имеет дело с уже поправленным AST (то есть с этим другим файлом).
Простые тесты для C++ кода на Python
Часто хочется покрыть тестами код на C++ в проекте - не логику, которую описывает код, а сам исходный код. Сейчас для этого есть приличное количество чекеров в clang-tidy. Можно написать свой чекер, который все равно будут ревьюить много месяцев и КПД всего этого занятия близок к нулю. Для специфических проверок надо что-то колхозить самому.
Примерных проверок может быть много:
typeid(x).name()
, потому что он дает mangled имя, с советом использовать костыль, который отдаст demangled имя.Можно придумать проверку на примере лямбд
int counter = 15;В этом примере лямбда использует внешнюю переменную, которая влияет на логику.
const auto addEvent = [&counter](int number) {
if (counter > 0) {
// do something...
--counter;
}
};
// ... call the lambda
addEvent(1337);
Если переменная используется только внутри лямбды, то ее можно вкостылить прямо в capture list. Тогда вместо двух верхних строк примера будет такая строка, дающая аналогичный результат:
auto addEvent = [counter = 15](int number) mutable {Такой же подход работает для переменных любых типов. Если интересно, что происходит внутри лямбд, то можно почитать целую книгу про них.
Попробуем сделать тест на такие кейсы
LambdaExpr
.VarDecl
.DeclRefExpr
.LambdaExpr
, а "объявление переменной" находится вне этого LambdaExpr
, то тест должен упасть, потому что данную переменную можно всунуть в capture list лямбды.Этот тест можно сделать на
Поддерживается libclang в Python, и после просмотра примеров можно поставить его себе:
pip install pytestи сделать такой простой тест, где реализуется описанная проверка для лямбд. Можно в директории рядом сохранить тестовый файл source.cpp и проверить, что тест падает:
pip install clang
pip install libclang
python3 -m pytest test.pyВывод:
E Failed: These variables can be declared in lambda capture:libclang на Python выглядит нормально, но неприятно то, что для понятия "нода AST" не к месту придумали новый термин "курсор".
E "counter" (at source.cpp:3:44), to lambda at source.cpp:4:88
Также не хватает некоторых очевидных фичей, например получения родительской ноды: в курсорах есть пара ссылок на другие курсоры (типа родительские, двух видов), но они работают неправильно.
Кроме тестов можно писать другие тулзы, например "кодогенераторы" - которые сгенерируют какой-нибудь исходник на основе существующего кода. Про кодогенераторы можно почитать лонгрид.
Еще можно делать "исправляторы" исходников - которые берут AST, что-то туда дописывают и сохраняют в другой файл, а компилятор имеет дело с уже поправленным AST (то есть с этим другим файлом).
Please open Telegram to view this post
VIEW IN TELEGRAM
#youtube
Поваренная книга пирата: создание своего торрент-клиента 🏴☠️
https://youtu.be/usVMq7LDW1Y
Когда есть желание написать о чем-то прикольном, обычно я делаю это в двух форматах:
1️⃣ Статья на Хабр - кондовые лонгриды, которые можно читать, помолясь и перекрестясь.
2️⃣ Этот канал - небольшие приколы, которые быстро читаются.
Сейчас я решил попробовать новый формат - а именно формат видео на ютубе.
Первое видео получилось длиной в полчаса, оно в основном про создание своего торрент-клиента на Python и побочные вещи. Могу сказать, пока я готовил его, я посмотрел с десяток других видео про торренты на ютубе (в том числе типа дофига технические), там близко нет того уровня проникновения, как у меня.
Возможно, такой формат будет более удачным. Так можно накидать неограниченный объем информации (как на Хабре) и оставаться неформальным (как в Телеге)😁
Заранее прошу прощения за мое чувство юмора, и дисклеймер: старайтесь не пиратить, не бухать, не накуриваться; а если очень хочется, то делайте так, чтобы никто не узнал😡
Поваренная книга пирата: создание своего торрент-клиента 🏴☠️
https://youtu.be/usVMq7LDW1Y
Когда есть желание написать о чем-то прикольном, обычно я делаю это в двух форматах:
Сейчас я решил попробовать новый формат - а именно формат видео на ютубе.
Первое видео получилось длиной в полчаса, оно в основном про создание своего торрент-клиента на Python и побочные вещи. Могу сказать, пока я готовил его, я посмотрел с десяток других видео про торренты на ютубе (в том числе типа дофига технические), там близко нет того уровня проникновения, как у меня.
Возможно, такой формат будет более удачным. Так можно накидать неограниченный объем информации (как на Хабре) и оставаться неформальным (как в Телеге)
Заранее прошу прощения за мое чувство юмора, и дисклеймер: старайтесь не пиратить, не бухать, не накуриваться; а если очень хочется, то делайте так, чтобы никто не узнал
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
ПОВАРЕННАЯ КНИГА ПИРАТА: СОЗДАНИЕ СВОЕГО ТОРРЕНТ-КЛИЕНТА
Исследуем протокол BitTorrent и делаем свой торрент-клиент на Python с asyncio.
Ссылки:
Канал в Телеграме - www.tgoop.com/cxx95
Исходный код - github.com/Izaron/pidorrent
Сайт протокола BitTorrent - www.bittorrent.org
Сбор статистики в DHT - andv.medium.com/веселимся…
Ссылки:
Канал в Телеграме - www.tgoop.com/cxx95
Исходный код - github.com/Izaron/pidorrent
Сайт протокола BitTorrent - www.bittorrent.org
Сбор статистики в DHT - andv.medium.com/веселимся…
#madskillz
Как правильно выполнить любой код до и после main()🏃
Функция
Почти всегда этот код - инициализация статических объектов, которая выполняется до
В этом коде можно делать что угодно (читать файлы, записывать в поток и т.д.), окружение там полностью готово. Я часто использую лямбды:
Пример на godbolt 1, godbolt 2.
😀 Есть крутой лонгрид (со схемами) про то, что происходит до и после
Но все описание там "примерное", потому что поведение зависит от компилятора и его версии🖥
В моем случае некоторые действия находятся в другом положении схемы (увидел по
⌨️ Для того, чтобы "вызвать функцию до
А именно
Здесь слова "constructor" и "destructor" не относятся к классам в C++, это исторические названия еще до C++.
Пример на godbolt с ctor-ами и dtor-ами
Однако здесь есть типичный прикол с😁
👍 Пример по ссылке выше, скомпилированный на
❌ Более старый релиз
😠 Это связано с тем, что
А компилятор данной версии так скомпилировал, что кторы выполняются ДО НЕГО и пытаются обратиться к неинициализированному объекту.
Функция
Мораль думайте сами👍
❔ Для чего может быть полезна такая штука? Лучше описать как "вопрос-ответ"
1️⃣
Вопрос: В чем принципиальное отличие этого кода:
2️⃣
Вопрос: Зачем это все надо, почему нельзя этот кусок кода поместить в
Ответ: Иногда нужно выполнить кусок кода, только если мы линкуем какую-то библиотеку или подключаем хедер. Например, если в библиотеке хэширования есть расчет хитрых данных для хэшей на старте программы в
Да точно это же и происходит для
3️⃣
Вопрос: Какие жесткие проблемы решает эта запись?
Ответ: В кторах и дторах можно указывать приоритет😐 Чем он выше, тем позже выполнится ктор (и соответственно раньше дтор).
Пример на godbolt.
Это решает артиллерийский выстрел в ногу под названием Static Initialization Order Fiasco. Очередность выполнения инициализаций обычно зависит от порядка линковки, а с приоритетом стало можно это нормально разруливать!😎
В остальном проблемы линковки все еще остаются легендарными - можно почитать пример особо опасной проблемы, о которой писал раньше: https://www.tgoop.com/cxx95/76
Как правильно выполнить любой код до и после main()
Функция
int main()
не является настоящей "точкой входа" в программе. До того, как зайти туда (и после него), программа выполняет много другого кода, в том числе юзерского.Почти всегда этот код - инициализация статических объектов, которая выполняется до
main()
. Программа:std::vector<int> MakeVector() {Выведет такое:
std::cout << "do MakeVector" << std::endl;
return {1, 2, 3};
}
std::vector<int> VECTOR = MakeVector();
int main() {
std::cout << "do main" << std::endl;
}
do MakeVectorПример на godbolt
do main
В этом коде можно делать что угодно (читать файлы, записывать в поток и т.д.), окружение там полностью готово. Я часто использую лямбды:
Пример на godbolt 1, godbolt 2.
main()
: Linux x86 Program Start Up.Но все описание там "примерное", потому что поведение зависит от компилятора и его версии
В моем случае некоторые действия находятся в другом положении схемы (увидел по
gdb
), и еще есть дополнительная вложенность - есть функции для отдельных .cpp-файлов, а там внутри уже вызовы для инициализации переменных.main()
", можно пометить ее специальным атрибутом.А именно
__attribute__((constructor))
или менее вырвиглазно [[gnu::constructor]]
.Здесь слова "constructor" и "destructor" не относятся к классам в C++, это исторические названия еще до C++.
Пример на godbolt с ctor-ами и dtor-ами
Однако здесь есть типичный прикол с
std::cout
x86-64 clang trunk
по состоянию на 13.06.2023
работает нормально.x86-64 clang 16.0.0
дает сегфолт в кторах и будет работать только если поменять там на printf
- ссылка на godbolt.std::cout
и подобные объекты инициализируются в конструкторе статического объекта std::ios_base::Init (объявление этого объекта находится в хедере <iostream>
).А компилятор данной версии так скомпилировал, что кторы выполняются ДО НЕГО и пытаются обратиться к неинициализированному объекту.
Функция
printf
таких спецэффектов не имеет, там просто перенаправление в нужный системный вызов (syscall) без регистрации и СМС.Мораль думайте сами
Вопрос: В чем принципиальное отличие этого кода:
[[gnu::constructor]] void foo() {от этого:
// приколы
}
struct Dummy {или более укуренного этого:
Dummy() { /* приколы */ }
};
Dummy dummy;
const auto dummy = []{Ответ: Никакого, кроме более удобной записи.
// приколы
return nullptr;
}();
Вопрос: Зачем это все надо, почему нельзя этот кусок кода поместить в
int main()
???Ответ: Иногда нужно выполнить кусок кода, только если мы линкуем какую-то библиотеку или подключаем хедер. Например, если в библиотеке хэширования есть расчет хитрых данных для хэшей на старте программы в
[[gnu::constructor]]
, то не надо париться с тем, как и что вызвать в main()
, можно просто линковать библиотеку и заработает.Да точно это же и происходит для
std::cout
, как мы только что увидели выше!Вопрос: Какие жесткие проблемы решает эта запись?
Ответ: В кторах и дторах можно указывать приоритет
Пример на godbolt.
Это решает артиллерийский выстрел в ногу под названием Static Initialization Order Fiasco. Очередность выполнения инициализаций обычно зависит от порядка линковки, а с приоритетом стало можно это нормально разруливать!
В остальном проблемы линковки все еще остаются легендарными - можно почитать пример особо опасной проблемы, о которой писал раньше: https://www.tgoop.com/cxx95/76
Please open Telegram to view this post
VIEW IN TELEGRAM
#theory
Замороженные корутины🧊
Am Ende bleib ich doch alleine
Но в конце я остаюсь один
Die Zeit steht still und mir ist kalt
Время остановилось, и мне холодно
Этот пост больше теоретический, чем практический - просто эта тема сложная, чтобы даже иметь какой-то minimal viable product😱
Я много работал с двумя фреймворками, которые со всеми плюсами имели в некоторых местах очень неудобный процесс разработки:
1️⃣ Разработка "тасок" по триггеру
"Таска" это такая микро-программа на Python, которая должна запускаться по какому-то триггеру и делать что-то обычно небольшое: отправка email, создание тикетов, http-запрос в сервис, и прочее👦 Сервис выполняет эти программы на каком-нибудь свободном сервере.
Иногда таска может быть посложнее - например, создать и запустить другие таски и ждать их выполнения. В таких случаях исходная таска "замораживается" (переходит в состояние "Wait") и прекращает свою работу, а после финиширования дочерней таски возобновляет работу, снова на каком-нибудь свободном сервере🖥
Есть проблема - система не может как бы "продолжить" код таски с той точки, где было ожидание таски. Был придуман нереальный костыль, который выглядит примерно так:
В "контексте" можно ставить флажки, чтобы имитировать разные стадии таски, еще туда можно сохранять списки/строки/числа✍️
Наконец, оповещение сервису о том, что текущей таске надо дождаться другую таску, делается через бросание исключения (🤔
При таком подходе надо очень аккуратно писать код и много думать, если таске нужно делать что-то немного нетривиальное: например запуск дочерних тасок в цикле, пока одна из них не завершится успешно🙁 Попробуйте сами наколхозить такое, будет треш.
2️⃣ Микросервисы в Apphost
По ссылке открыто описано что такое Apphost - фреймворк для микросервисов (на Python или C++).
Он решает многие старые проблемы, но появляется новая проблема - теперь программа не может просто так сделать HTTP-запрос.
Нужно разбивать всю программу на микроскопические куски кода, которые принимают некие "входящие" объекты и формируют "исходящие", но не более того. Все походы во внешние сервисы делает Apphost. Эти куски кода выполняются на разных серверах.
Та часть, которая раньше делалась мгновенно, сейчас делается в 10 раз медленнее из-за настройки конфигов, жесткого обдумывания "графа" выполнения, и так далее.
❓ Использование корутин
Неприятности в сервисах, указанных выше, теоретически можно решить через корутины. Я когда-то писал о них в канале. Это функции, которые могут приостанавливать свое выполнение, а затем продолжать с той же точки.
На самом деле, проще всего изучать корутины в простых языках - здесь статья про корутины в Lua. Общий подход не меняется.
Потом здесь можно почитать, как корутины реализованы в C++ (начиная с C++20) - это очень сложные статьи, их можно читать несколько недель, зато появляется максимальное понимание, как компилятор преобразовывает код.
Суть идеи, которая решит проблемы, которые я описал - замороженные корутины: программа выполняется на одном сервере, потом останавливается, ожидает возобновления, и выполняется на каком-нибудь другом сервере с той точки, где была остановлена😎
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Замороженные корутины
Am Ende bleib ich doch alleine
Но в конце я остаюсь один
Die Zeit steht still und mir ist kalt
Время остановилось, и мне холодно
Этот пост больше теоретический, чем практический - просто эта тема сложная, чтобы даже иметь какой-то minimal viable product
Я много работал с двумя фреймворками, которые со всеми плюсами имели в некоторых местах очень неудобный процесс разработки:
"Таска" это такая микро-программа на Python, которая должна запускаться по какому-то триггеру и делать что-то обычно небольшое: отправка email, создание тикетов, http-запрос в сервис, и прочее
Иногда таска может быть посложнее - например, создать и запустить другие таски и ждать их выполнения. В таких случаях исходная таска "замораживается" (переходит в состояние "Wait") и прекращает свою работу, а после финиширования дочерней таски возобновляет работу, снова на каком-нибудь свободном сервере
Есть проблема - система не может как бы "продолжить" код таски с той точки, где было ожидание таски. Был придуман нереальный костыль, который выглядит примерно так:
def on_execute(self):Сервис сохраняет "контекст" между разными запусками таски, а метод
if not self.Context.config_stage:
self.Context.config_stage = True
param1 = ...
param2 = ...
task = sdk.CreateTask(param1, param2, ...) # создаем дочернюю таску №1
raise sdk.WaitTask(task)
if not self.Context.run_stage:
self.Context.run_stage = True
param = ...
task = sdk.CreateTask(param, ...) # создаем дочернюю таску №2
raise sdk.WaitTask(task)
on_execute
каждый раз запускается сначала ♻️В "контексте" можно ставить флажки, чтобы имитировать разные стадии таски, еще туда можно сохранять списки/строки/числа
Наконец, оповещение сервису о том, что текущей таске надо дождаться другую таску, делается через бросание исключения (
raise
), чтобы это "прорвалось" за пределы def on_execute
(удобнее, чем просто return
, если вызываются всякие вложенные методы) При таком подходе надо очень аккуратно писать код и много думать, если таске нужно делать что-то немного нетривиальное: например запуск дочерних тасок в цикле, пока одна из них не завершится успешно
По ссылке открыто описано что такое Apphost - фреймворк для микросервисов (на Python или C++).
Он решает многие старые проблемы, но появляется новая проблема - теперь программа не может просто так сделать HTTP-запрос.
Нужно разбивать всю программу на микроскопические куски кода, которые принимают некие "входящие" объекты и формируют "исходящие", но не более того. Все походы во внешние сервисы делает Apphost. Эти куски кода выполняются на разных серверах.
Та часть, которая раньше делалась мгновенно, сейчас делается в 10 раз медленнее из-за настройки конфигов, жесткого обдумывания "графа" выполнения, и так далее.
Неприятности в сервисах, указанных выше, теоретически можно решить через корутины. Я когда-то писал о них в канале. Это функции, которые могут приостанавливать свое выполнение, а затем продолжать с той же точки.
На самом деле, проще всего изучать корутины в простых языках - здесь статья про корутины в Lua. Общий подход не меняется.
Потом здесь можно почитать, как корутины реализованы в C++ (начиная с C++20) - это очень сложные статьи, их можно читать несколько недель, зато появляется максимальное понимание, как компилятор преобразовывает код.
Суть идеи, которая решит проблемы, которые я описал - замороженные корутины: программа выполняется на одном сервере, потом останавливается, ожидает возобновления, и выполняется на каком-нибудь другом сервере с той точки, где была остановлена
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Please open Telegram to view this post
VIEW IN TELEGRAM
#cringe
Про SJW в C++ комьюнити🤡
Настало время обратить внимание на такую суперважную для Барнаула (Алтайский край) проблему, как борьбу за социальную справедливость в комьюнити по C++.
В начале 2022 года я отправил патч в Clang
После чего забил на него на месяц, а когда вернулся чтобы исправить его, то обнаружил что ревьюер забанен, хотя он профессионал - у него много статей, выступлений и тд.
Я написал ему на почту - что произошло и кто может отревьюить патч. Оказалось, что сообщество его "отменило" aka "закэнселило"🤡
В 2011 году он, видимо, последовал совету Трампа ("grab them by the pussy" ), после чего получил две уголовки и попал в почетный список Форбс "U.S.'s sex offender registry".
Зачем об этом знать и какое отношение это имеет к C++?
Оказывается (как он мне написал), в 2021 году группировка с includecpp.org об этом факте узнала и начала попытки "отменить" еб*ря-террориста со всего интернета, и оффлайн тоже.🔫
По этой причине он, например, не выступал на CppCon 2021 - для этого борцуны в твиттере угрожали Гербу Саттеру, а также выгнать Microsoft из комитета по C++.
И соответственно из LLVM его также выгнали - якобы по причине нарушение "Code of Conduct".
Далее произошел небольшой прикол (это было начало 2022 года)😁
- Я в ответ написал ему, что понимаю его - меня также "отменяют", ограничивая в правах пожрать в макдаке и оплатить онлифанс, хотя я даже не трогал маленьких девочек.
- На что он бомбанул и ответил в общих чертах, что тут как раз все правильно, SJW ни при чем, наши страны находятся в состоянии войны, тебя разъ*бут как Ирак, зато ты после этого получишь аналог Плана Маршалла😱
От такой щедрости я почувствовал мем с пингвином. Особо не ответил ему, но надеюсь что он больше не показывает своего Маршалла местным Лолитам😁
Однако вернемся к нашим маленьким фанатам экстремизма. Сайт includecpp.org выглядит максимально клоунским.
Достаточно посмотреть на "code of conduct" и пооткрывать твиттеры в ссылках под "the moderation and administration team includes", чтобы начать подозревать, что в западных странах есть проблемы с доступностью психотерапии для населения.
На мой взгляд, корнем проблемы является то, что комьюнити по C++ не объединено никаким бизнес-интересом - развитие языка и компиляторов не идет слишком быстро.
Из-за этого, когда толпе нечего делать, они находят всякие причины поссориться с кем-либо, и особенно крикливые объединяются в организованные группировки. В целом это оставляет плохое впечатление и желание дистанцироваться от любого рода "тусовок".
Похожие драмы происходят в Rust и прочих языках, и мне все-таки кажется что нормальный человек не будет таким заниматься.
Я пофантазировал и представил себе "Моральный кодекс C++-программиста в 2030 году", через несколько лет посмотрим насколько я попал🚬
1️⃣ Запрет паттерна проектирования "фабрика" и слов в коде как
2️⃣ Одобрямс легализации насвая в стране, истинная вера в то что это "менее вредно чем алкоголь", прослушивание учёных которые доказывают это "научными фактами"
3️⃣ Подписывание бумажки "я признаю Rust Foundation террористической организацией за вторжение в Linux Kernel и оккупацию 20% Stackoverflow"
4️⃣ Переменные наподобии номера гендера хранить в int16, потому что int8 не будет хватать
5️⃣ Не менее 28.2% C++-программистов должны составлять иностранные специалисты из беднейших регионов мира, с такой же зарплатой как у всех
6️⃣ Мультиязычность - одна часть проекта должна быть на C++, другая на Python, третья на Delphi, четвертая на JavaScript и т.д. Реклама, что такой подход делает проект более технологично богатым. Всякие утверждения, что некоторые языки не совместимы друг с другом и что моноязычный C++-проект проще разрабатывать - языковой шовинизм.
7️⃣ Из-за того, что комитет по C++ когда-то попытался поглотить комитет по C, каждый C++-программист теперь должен платить репарации C-программистам. За утверждения, что C и C++ родственные языки, имеющие общую историю и происхождение, которые совместимы в одном проекте, следует немедленный кэнселинг.
Про SJW в C++ комьюнити
Настало время обратить внимание на такую суперважную для Барнаула (Алтайский край) проблему, как борьбу за социальную справедливость в комьюнити по C++.
В начале 2022 года я отправил патч в Clang
После чего забил на него на месяц, а когда вернулся чтобы исправить его, то обнаружил что ревьюер забанен, хотя он профессионал - у него много статей, выступлений и тд.
Я написал ему на почту - что произошло и кто может отревьюить патч. Оказалось, что сообщество его "отменило" aka "закэнселило"
В 2011 году он, видимо, последовал совету Трампа (
Зачем об этом знать и какое отношение это имеет к C++?
Оказывается (как он мне написал), в 2021 году группировка с includecpp.org об этом факте узнала и начала попытки "отменить" еб*ря-террориста со всего интернета, и оффлайн тоже.
По этой причине он, например, не выступал на CppCon 2021 - для этого борцуны в твиттере угрожали Гербу Саттеру, а также выгнать Microsoft из комитета по C++.
И соответственно из LLVM его также выгнали - якобы по причине нарушение "Code of Conduct".
Далее произошел небольшой прикол (это было начало 2022 года)
- Я в ответ написал ему, что понимаю его - меня также "отменяют", ограничивая в правах пожрать в макдаке и оплатить онлифанс
- На что он бомбанул и ответил в общих чертах, что тут как раз все правильно, SJW ни при чем, наши страны находятся в состоянии войны, тебя разъ*бут как Ирак, зато ты после этого получишь аналог Плана Маршалла
От такой щедрости я почувствовал мем с пингвином. Особо не ответил ему, но надеюсь что он больше не показывает своего Маршалла местным Лолитам
Однако вернемся к нашим маленьким фанатам экстремизма. Сайт includecpp.org выглядит максимально клоунским.
Достаточно посмотреть на "code of conduct" и пооткрывать твиттеры в ссылках под "the moderation and administration team includes", чтобы начать подозревать, что в западных странах есть проблемы с доступностью психотерапии для населения.
На мой взгляд, корнем проблемы является то, что комьюнити по C++ не объединено никаким бизнес-интересом - развитие языка и компиляторов не идет слишком быстро.
Из-за этого, когда толпе нечего делать, они находят всякие причины поссориться с кем-либо, и особенно крикливые объединяются в организованные группировки. В целом это оставляет плохое впечатление и желание дистанцироваться от любого рода "тусовок".
Похожие драмы происходят в Rust и прочих языках, и мне все-таки кажется что нормальный человек не будет таким заниматься.
Я пофантазировал и представил себе "Моральный кодекс C++-программиста в 2030 году", через несколько лет посмотрим насколько я попал
work
, job
и прочее, так как это угнетает права безработныхPlease open Telegram to view this post
VIEW IN TELEGRAM
C++95
billy.png
#books
Обзор книги "Practical Binary Analysis" (2019 г.) 📚
(можно скачать PDF тут)
На фотографии внештатный корреспондент паблика "C++95" Билли, прочитавший данную книгу.
Его отзыв: "Oh yeah, это точно стоит three hundred bucks! ASM WE CAN!"📞
Я давно ничего не писал из-за занятости, но сейчас смог🫡
Эта книга посвящена разнообразному анализу бинарников, то есть исполняемых программ без соответствующего исходного кода. В ней очень много информации, больше чем в любой другой книге из #books - ее реально читать неделями.
Там есть знания, которые могут пригодиться разве что reverse engineers и vulnerable researchers, но и другим тоже может быть интересно🤔
В1️⃣ главе дается анатомия бинарника и как он вообще появляется на свет - как в книге про компиляцию.
Во2️⃣ и в 3️⃣ главах описываются форматы исполняемых файлов ELF (на Linux) и PE (на Windows)
В4️⃣ главе строится своя тулза для загрузки бинарника с помощью libbfd. В книге вообще есть упор на создание собственных анализаторов бинарников.
В крутой5️⃣ главе решается задача из CTF по поиску "флага" в бинарнике, на примере которой применяются десятки подходов и тулз, чтобы шарить еще лучше.
В6️⃣ главе, которая на мой взгляд является центральной, показывается фундамент анализа и дизассемблирования 🖥
Там народу являют жестокую правду - в общем случае нет какого-то единого алгоритма дизассемблирования.
Более тупые дизассемблеры (как objdump) имеют линейный алгоритм - тупо расшифровывают ассемблерные команды от начала до конца.
Так как компиляторы могут встраивать вспомогательные данные прямо в код (особенно Visual Studio), то можно например напороться на jump table. По факту это список адресов, но дизассемблер об этом не знает и нарасшифрует в этом месте ассемблерные команды👍
Ничего не упадет, потому что в x86 "плотный" набор команд и практически любая последовательность байтов представляет собой валидный ассемблер👍
Более умные дизассемблеры (как IDA Pro) имеют рекурсивный алгоритм - они расшифровывают как бы настоящий код и только те места, куда управление доказанно может перейти, например через jmp. Там свои сложности с неявным control flow, когда в коде есть jump table или vtable, которые неявно указывают куда передавать управление, но это решаемо.
Дизассемблеры восстанавливают функции довольно условно (в ассемблере "функции" это вообще слишком большая абстракция) - оптимизирующий компилятор может так навертеть, что код принадлежащий функции может оказаться размазанным по всему бинарнику, и разные "функции" могут переиспользовать какой-то один кусок ассемблера👍
Чтобы определить, где находится условная "функция", дизасм ищет "сигнатуры", то есть паттерны ассемблерных инструкций, которые часто используются в начале/конце функции.
Пример сигнатуры в неоптимизированном x86 это "пролог"
Очень сложно восстанавливать структуры данных (C/C++), дизасмы часто не пытаются этого делать☔️
Для более простого анализа часто используется промежуточное представление (IR, Intermediate Representation) ассемблера - например, вместо исходника где могут быть сотни разновидностей инструкций x86/ARM, можно получить IR где единицы разновидностей. IR бывает несколько, например REIL.
Дизасм восстанавливает код, который делает примерно то же, что ассемблер. Обычно выглядит он все равно довольно ужасно, но дизасмы стараются🥺 Например, по эвристикам (то есть через три костыля) определяются простые циклы (for/while), математические формулы, и прочее.
ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
Обзор книги "Practical Binary Analysis" (2019 г.) 📚
(можно скачать PDF тут)
На фотографии внештатный корреспондент паблика "C++95" Билли, прочитавший данную книгу.
Его отзыв: "Oh yeah, это точно стоит three hundred bucks! ASM WE CAN!"
Я давно ничего не писал из-за занятости, но сейчас смог
Эта книга посвящена разнообразному анализу бинарников, то есть исполняемых программ без соответствующего исходного кода. В ней очень много информации, больше чем в любой другой книге из #books - ее реально читать неделями.
Там есть знания, которые могут пригодиться разве что reverse engineers и vulnerable researchers, но и другим тоже может быть интересно
В
Во
В
В крутой
В
Там народу являют жестокую правду - в общем случае нет какого-то единого алгоритма дизассемблирования.
Более тупые дизассемблеры (как objdump) имеют линейный алгоритм - тупо расшифровывают ассемблерные команды от начала до конца.
Так как компиляторы могут встраивать вспомогательные данные прямо в код (особенно Visual Studio), то можно например напороться на jump table. По факту это список адресов, но дизассемблер об этом не знает и нарасшифрует в этом месте ассемблерные команды
Ничего не упадет, потому что в x86 "плотный" набор команд и практически любая последовательность байтов представляет собой валидный ассемблер
Более умные дизассемблеры (как IDA Pro) имеют рекурсивный алгоритм - они расшифровывают как бы настоящий код и только те места, куда управление доказанно может перейти, например через jmp. Там свои сложности с неявным control flow, когда в коде есть jump table или vtable, которые неявно указывают куда передавать управление, но это решаемо.
Дизассемблеры восстанавливают функции довольно условно (в ассемблере "функции" это вообще слишком большая абстракция) - оптимизирующий компилятор может так навертеть, что код принадлежащий функции может оказаться размазанным по всему бинарнику, и разные "функции" могут переиспользовать какой-то один кусок ассемблера
Чтобы определить, где находится условная "функция", дизасм ищет "сигнатуры", то есть паттерны ассемблерных инструкций, которые часто используются в начале/конце функции.
Пример сигнатуры в неоптимизированном x86 это "пролог"
push ebp; mov ebp,esp
и "эпилог" leave; ret
Есть и более сложные кейсы, когда делается "tail call", а оптимизированные функции могут не иметь пролога и/или эпилога, поэтому ошибок может быть от 20% и больше.Очень сложно восстанавливать структуры данных (C/C++), дизасмы часто не пытаются этого делать
Для более простого анализа часто используется промежуточное представление (IR, Intermediate Representation) ассемблера - например, вместо исходника где могут быть сотни разновидностей инструкций x86/ARM, можно получить IR где единицы разновидностей. IR бывает несколько, например REIL.
Дизасм восстанавливает код, который делает примерно то же, что ассемблер. Обычно выглядит он все равно довольно ужасно, но дизасмы стараются
ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
Please open Telegram to view this post
VIEW IN TELEGRAM
C++95
ban.png
#cringe #books
На данном скриншоте - последствие того, как автор поста на два дня положил систему для практикума форк-бомбой.
Но не стоит за него волноваться - он только получил отстранение от занятий на три недели, потом успешно выпустился из учебного заведения с дипломомбаландёра бакалавра и забыл его как страшный сон.
Обзор книги "Введение в язык Си++" (2012/2020 г.) 📚🤪
Jeder lacht, jeder lacht — ja
Все смеются, все смеются, да
Jeder lacht über dich
Все смеются над тобой
В #books есть обзоры на хорошие книги, но не хватает обзоров на примеры, каких книг не стоит писать. Я решил, что надо обзирать какой-нибудь университетский учебник, потому что его эффект более разлагающий.
Под руку попалось творчество уже знакомого нам Столярика. Уважаемый телезритель может засомневаться - нет ли у меня предвзятого отношения к нему? Нет - просто других методичек почти нет, и они слишком плохи, чтобы быть интересными.
Третья редакция опуса от 2012 года находится тут, мы будем кринжевать с нее. Ради справедливости, уже есть пятая редакция 2020 года (тут), но она слабо отличается от третьей - убрана часть фактических ошибок и добавленыновые ошибки рандомные факты, а про rvalue и фичи стандартов не рассказали (потому что Столяров не признает стандарты).
Книжка намеренно небольшая, потому что рассчитана на 6-8 лекций. За 4 года бакалавриата на C++ больше времени не находится, ведь так в учебный план не поместятся философия, урматы и основы экономики.
А ведь плюсы это такая глыба, что полный справочник позволяет Столярову обороняться от своих многочисленных врагов...🔫 👀 🔫
😈
Языки упорно называются "Си" и "Си++", одобряем патриотический перевод👍
В главе
На примере показывается полезность инкапсуляции в C++. К сожалению, не описана типичная Сишная идиома для инкапсуляции opaque data type, что было бы к месту для тех, кто переучивается с С на C++.
В главе про
Там же рекомендуется передача переменной через константную ссылку:
ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
На данном скриншоте - последствие того, как автор поста на два дня положил систему для практикума форк-бомбой.
Но не стоит за него волноваться - он только получил отстранение от занятий на три недели, потом успешно выпустился из учебного заведения с дипломом
Обзор книги "Введение в язык Си++" (2012/2020 г.) 📚
Jeder lacht, jeder lacht — ja
Все смеются, все смеются, да
Jeder lacht über dich
Все смеются над тобой
В #books есть обзоры на хорошие книги, но не хватает обзоров на примеры, каких книг не стоит писать. Я решил, что надо обзирать какой-нибудь университетский учебник, потому что его эффект более разлагающий.
Под руку попалось творчество уже знакомого нам Столярика. Уважаемый телезритель может засомневаться - нет ли у меня предвзятого отношения к нему? Нет - просто других методичек почти нет, и они слишком плохи, чтобы быть интересными.
Третья редакция опуса от 2012 года находится тут, мы будем кринжевать с нее. Ради справедливости, уже есть пятая редакция 2020 года (тут), но она слабо отличается от третьей - убрана часть фактических ошибок и добавлены
Книжка намеренно небольшая, потому что рассчитана на 6-8 лекций. За 4 года бакалавриата на C++ больше времени не находится, ведь так в учебный план не поместятся философия, урматы и основы экономики.
А ведь плюсы это такая глыба, что полный справочник позволяет Столярову обороняться от своих многочисленных врагов...
Полное описание всех возможностей языка и его стандартной библиотеки представляет собой книгу такого объёма, что ею вполне можно при желании воспользоваться в качестве оружия против врагов (в смысле чисто физическом).Предполагается, что читатель уже знает язык C и с него переучивается на C++, там описывается разница между языками
Для изучения базовых средств языка Си++ вам потребуется уверенное владение языком СиЗвучит аналогично тому, чтобы изучить французский язык, надо сначала выучить латынь (откуда le français произошел), а потом выучить дифф между латынью и французским
Языки упорно называются "Си" и "Си++", одобряем патриотический перевод
В главе
Язык Си++ и его совместимость с Си
нет ни слова про действительную совместимость языков через extern "C"
.В языке Си++ введен механизм **защиты**, который позволяет запретить доступ к некоторым частям структурыИнтересно, как "инкапсуляцию" перевели как "защиту"... Еще можно переводить "полиморфизм" как "превентивный удар", а "наследование" как "хлопо́к". Там много такого надмозгового перевода.
Мы могли бы написать и так:Фразу "unnamed object" из Стандарта лучше перевести как "безымянный объект". Но лучше бы были рассмотрены категории выражений (
double mod = str_complex(2.7, 3.8).modulo();
В последнем случае мы создали временную **анонимную переменную** типа `str_complex`
lvalue/rvalue
и их подвиды) и их поведение, вместо этого всё объясняется "на пальцах" и размыто, а про move-семантику нет ни слова.На примере показывается полезность инкапсуляции в C++. К сожалению, не описана типичная Сишная идиома для инкапсуляции opaque data type, что было бы к месту для тех, кто переучивается с С на C++.
В главе про
const
ничего не сказано про ключевые слова constexpr
и (!) mutable
, что плохо, потому что не складывается понимание что это слово про логическую константность, а не физическую.Там же рекомендуется передача переменной через константную ссылку:
Так, если в описанном ранее классе `Complex` вместоПо крайней мере для 16-байтовых типов это неверно - их на x86-64 выгоднее передавать через копию. В проектах можно использовать чекер clang-tidy: пример проверки на godbolt.
Complex operator+(Complex op2) { ... }
написать
Complex operator+(const Complex &op2) { ... }
семантика кода не изменится, но физически вместо копирования двух полей `double` будет происходить передача адреса ...
ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
Please open Telegram to view this post
VIEW IN TELEGRAM
#opensource
Обзор на TeX📖
Ist doch so gut gewürzt und so schön flambiert
Так хорошо приправлено и красиво обжарено
Und so liebevoll auf Porzellan serviert
И с любовью подано на фарфоре
Dazu ein guter Wein und zarter Kerzenschein
Под хорошее вино и нежный свет свечей
Ja, da lass ich mir Zeit, etwas Kultur muss sein
Да, я не тороплюсь, капля культуры должна быть!
В опенсорсе самым 𝓪𝓮𝓼𝓽𝓱𝓮𝓽𝓲𝓬𝓪𝓵 проектом является скорее всего TeX от Дональда Кнута. Это система для создания красивых документов, особенно для научных работ и технических книг📖 Многие хотя бы раз его использовали, например для описания математических формул.
Про него есть много информации, но почти вся поверхностная. Стало интересно, что там внутри.
Можно смотреть "снизу вверх":
1️⃣ Шрифты - набор изображений символов (обычно векторных), сейчас популярен формат TrueType.
Векторные изображения переводятся в пиксельные на мониторе с приколами наподобии хинтинга и ClearType.
Многие стандартные шрифты имеют разное начертание для разных размеров, чтобы выглядело красивее. То есть буквы в 10м кегле (10pt) это не то же самое, что увеличенные в два раза буквы из 5pt🤵
Есть шрифты, где записаны математические значки или другие символы в векторном виде, например знак ⚠️, это удобнее чем вставлять картинки.
Это обширная тема, в линуксе даже есть мемчик "шрифты говно"💩
2️⃣ Формат файлов DVI - выходной файл TeX. Чтобы "прочитать" этот файл, надо хранить состояние из нескольких переменных и выполнять "команды" из файла побайтово. Например, команда
Этот файл не содержит в себе шрифтов, а только "ссылается" на них, и знает из шрифта высоту/длину/глубину символов. На картинки он тоже только ссылается, и дефолтные DVI-просмотрщики не показывают их.
Смысл этого формата - получать один и тот же документ на любом компьютере🖥
3️⃣ TeX - сам набор программ и язык разметки.
Самая подробная информация есть в книге от автора The TeXbook в 400+ страниц, можно пропускать слишком подробные куски🔍
В других книгах как обычно выкинут 80% информации и еще неправильно переведут (например, "инкапсуляцию" как "защиту").
У ванильного TeX примерно 900 команд, но только ~300 команд являются базовыми. Например, команда
📄
В The TeXbook описано, как текст из .tex-файла переводится в токены, какие есть категории токенов (глава 8)
В отличие от WYSIWYG-редакторов, TeX работает на уровне абзаца, а не строки, и распределяет слова по отдельным строкам так, чтобы минимизировать метрику badness.
В TeX есть понятие "клей" (glue) - это объект-отступ между разными сущностями TeX🔺 "Клей" после запятой растягивается в 1.25 раз больше, чем "клей" между соседними словами, а "клей" после точки/знака
"Клей" может быть бесконечно растяжимым/сжимаемым, например команда
Есть огромная куча костылей, чтобы менять любое правило.
Например, чтобы написать в документе
Чтобы было нельзя перенести
Можно поставить одинаковый glue stretching (после слов, запятых и точек) командой
Можно сформировать длины строк в форме полукруга (в The TeXbook есть примеры) командой
ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
Обзор на TeX
Ist doch so gut gewürzt und so schön flambiert
Так хорошо приправлено и красиво обжарено
Und so liebevoll auf Porzellan serviert
И с любовью подано на фарфоре
Dazu ein guter Wein und zarter Kerzenschein
Под хорошее вино и нежный свет свечей
Ja, da lass ich mir Zeit, etwas Kultur muss sein
Да, я не тороплюсь, капля культуры должна быть!
В опенсорсе самым 𝓪𝓮𝓼𝓽𝓱𝓮𝓽𝓲𝓬𝓪𝓵 проектом является скорее всего TeX от Дональда Кнута. Это система для создания красивых документов, особенно для научных работ и технических книг
Про него есть много информации, но почти вся поверхностная. Стало интересно, что там внутри.
Можно смотреть "снизу вверх":
Векторные изображения переводятся в пиксельные на мониторе с приколами наподобии хинтинга и ClearType.
Многие стандартные шрифты имеют разное начертание для разных размеров, чтобы выглядело красивее. То есть буквы в 10м кегле (10pt) это не то же самое, что увеличенные в два раза буквы из 5pt
Есть шрифты, где записаны математические значки или другие символы в векторном виде, например знак ⚠️, это удобнее чем вставлять картинки.
Это обширная тема, в линуксе даже есть мемчик "шрифты говно"
set_char_a
как бы "печатает" в текущем месте один символ a
и сдвигает курсор вправо на ширину символа a
.Этот файл не содержит в себе шрифтов, а только "ссылается" на них, и знает из шрифта высоту/длину/глубину символов. На картинки он тоже только ссылается, и дефолтные DVI-просмотрщики не показывают их.
Смысл этого формата - получать один и тот же документ на любом компьютере
Самая подробная информация есть в книге от автора The TeXbook в 400+ страниц, можно пропускать слишком подробные куски
В других книгах как обычно выкинут 80% информации и еще неправильно переведут (например, "инкапсуляцию" как "защиту").
У ванильного TeX примерно 900 команд, но только ~300 команд являются базовыми. Например, команда
\TeX
для вывода лого TeX является макросом для такой последовательности:T\kern -.1667em\lower .5ex\hbox {E}\kern -.125emXТо есть печатается символ
T
, потом печатается E
со сдвигом от изначального места немного вниз и влево, потом печатается X
со сдвигом влево В The TeXbook описано, как текст из .tex-файла переводится в токены, какие есть категории токенов (глава 8)
В отличие от WYSIWYG-редакторов, TeX работает на уровне абзаца, а не строки, и распределяет слова по отдельным строкам так, чтобы минимизировать метрику badness.
В TeX есть понятие "клей" (glue) - это объект-отступ между разными сущностями TeX
!
/знака ?
соответственно в 3 раза больше."Клей" может быть бесконечно растяжимым/сжимаемым, например команда
\centerline
это макрос\line {\hss #1\hss }Команда hss ставит бесконечный "клей", и TeX располагает параметр макроса (то есть
#1
) ровно в центр строки.Есть огромная куча костылей, чтобы менять любое правило.
Например, чтобы написать в документе
Mr. Evil
с отступом как между соседними словами (а не с х3 отступом как для нового предложения) надо писать Mr.\ Evil
.Чтобы было нельзя перенести
Evil
на следующую строку без Mr.
, надо писать Mr.~Evil
(~
это тот же пробел).Можно поставить одинаковый glue stretching (после слов, запятых и точек) командой
\frenchspacing
.Можно сформировать длины строк в форме полукруга (в The TeXbook есть примеры) командой
\parshape
, и так далее...ПРОДОЛЖЕНИЕ В КОММЕНТАРИИ
Please open Telegram to view this post
VIEW IN TELEGRAM
#story
Как проходит отбор к межнару по информатике🚬
Я подумал, о чем бы написать в канал, чтобы он не пустовал, и решил, что эта тема сойдет😁 Про C++ тоже будет.
🅰️ 🅰️ 🅰️ 🅰️ 🅰️ 🫥 1️⃣
КалибровкаDota MMR рейтинга Codeforces
Однажды я как обычно отсиживал время в своей школе, и кто-то сказал что бывают некие "олимпиады", с помощью которых можно поступить в любой вуз без экзаменов, но это не точно👦
Я был не уверен, что мне особо нужен "топовый" (будто бы) вуз, что я вывезу если там сложно учиться и так далее🚬 Но идти в рандомный ПТУ из-за слитых экзаменов тоже не хотелось.
Отнесся скептически, слово "олимпиады" ассоциировались со скучным занятием для ботанов🤓 Стало просто интересно, за что дают ход в любой вуз.
Узнал, что в этом олимпиаде есть несколько этапов (школа/город/область/финал). Открыл Codeforces, который в интернете советовали для подготовки. Порешал там что-то (🔍 первый день).
Спустя какое-то время пару раз поучаствовал на Codeforces в "раундах" (их правила), по их результатам перерасчитывается твой рейтинг.
После этого я стал поехавшим на теме Codeforces🤪
Cледующие два года я постоянно решал на нем задачи, на уроках с телефона читал разборы раундов и алгоритмов, прорешивал старые задачи, и не мог дождаться нового раунда.
Прикол в том, что Codeforces превращает решение обычных алгоритмических задач в рейтинговую игру🎮
В стандартном раунде дается 5 задач на 2 часа.
В самом начале задачи стоят 500-1000-1500-2000-2500 баллов, они отсортированы по сложности: первую решают почти все, последнюю единицы (из многих тысяч участников)⌨️ Чем позже решишь задачу, тем меньше баллов она будет стоить, за неудачную попытку от задачи отнимается 50 баллов.
Во время раунда отосланное решение задачи проверяется на "претестах", то есть каком-то наборе из ~10-15 тестов, и только после раунда на всех ~100-150 тестах. Это значит, что статус "претесты пройдены" не означает полного решения и задача может упасть во время полного тестирования🚬 Если кажется, что решение было неправильным, то можно в течение раунда перепослать решение, тогда от задачи также отнимается 50 баллов.
Если 100% кажется, что твое решение правильное, можно "заблокировать" задачу - тогда больше нельзя перепосылать решение, зато можно смотреть решения этой же задачи у других участников в твоей "комнате" (рандомные ~50 участников раунда) и попытаться "взломать" их решения⌨️ То есть подбирать такой тестовый кейс, на котором чужое решение работает неправильно. Успешный взлом +100 баллов, неуспешный -50 баллов.
Это всё и еще ряд правил делают каждый раунд непохожим друг на друга. Есть несколько стратегий по разгрому раунда, самые необычные/сложные такие:
1️⃣ "Стальные Яйца" - первым делом решать 3-ю или 4-ю задачу. Так как более "весомые" задачи теряют больше баллов со временем, то выгоднее решать их быстрее всего (в разумных пределах) и потом уже 1-ю и 2-ю.
Это самый рискованный путь, и если задачу решить не удастся, то урон рейтингу будет мощным.
2️⃣ "Крутой Какер" - после решения первых задач (сколько можешь - 2 или 3) не пытаться решать оставшиеся, а "заблокировать" решения и бросить все силы на "взлом" чужих решений. Для этого усиленно ищутся крайние случаи и прокачивается навык скорочтения говнокода.
Можно пойти на такую хитрость - так как многие другие участники изредка мониторят "комнату" и сразу же блокируют свои решения после первых взломов (далеко не все задачи "взломабельные") и тоже пытаются ломать кого-то, лучше не ломать никого сразу, а накопить список лохов и потом грохнуть сразу пятерых и получить +500 баллов👊
(Самые жесткие вариации стратегии дополнительно предполагают засылку хренового решения по сложной задаче, лишь бы пройти претесты, а потом прочитать чье-то нормальное решение в комнате и также ломать)
Codeforces давал жесткую дозу адреналина, на которую подсаживаешься и побочно прокачиваешь навык решения алгоритмических задач. Это работает, есть такой вайб заходит (далеко не всем).
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Как проходит отбор к межнару по информатике
Я подумал, о чем бы написать в канал, чтобы он не пустовал, и решил, что эта тема сойдет
Калибровка
Однажды я как обычно отсиживал время в своей школе, и кто-то сказал что бывают некие "олимпиады", с помощью которых можно поступить в любой вуз без экзаменов, но это не точно
Я был не уверен, что мне особо нужен "топовый" (будто бы) вуз, что я вывезу если там сложно учиться и так далее
Отнесся скептически, слово "олимпиады" ассоциировались со скучным занятием для ботанов
Узнал, что в этом олимпиаде есть несколько этапов (школа/город/область/финал). Открыл Codeforces, который в интернете советовали для подготовки. Порешал там что-то (
Спустя какое-то время пару раз поучаствовал на Codeforces в "раундах" (их правила), по их результатам перерасчитывается твой рейтинг.
После этого я стал поехавшим на теме Codeforces
Cледующие два года я постоянно решал на нем задачи, на уроках с телефона читал разборы раундов и алгоритмов, прорешивал старые задачи, и не мог дождаться нового раунда.
Прикол в том, что Codeforces превращает решение обычных алгоритмических задач в рейтинговую игру
В стандартном раунде дается 5 задач на 2 часа.
В самом начале задачи стоят 500-1000-1500-2000-2500 баллов, они отсортированы по сложности: первую решают почти все, последнюю единицы (из многих тысяч участников)
Во время раунда отосланное решение задачи проверяется на "претестах", то есть каком-то наборе из ~10-15 тестов, и только после раунда на всех ~100-150 тестах. Это значит, что статус "претесты пройдены" не означает полного решения и задача может упасть во время полного тестирования
Если 100% кажется, что твое решение правильное, можно "заблокировать" задачу - тогда больше нельзя перепосылать решение, зато можно смотреть решения этой же задачи у других участников в твоей "комнате" (рандомные ~50 участников раунда) и попытаться "взломать" их решения
Это всё и еще ряд правил делают каждый раунд непохожим друг на друга. Есть несколько стратегий по разгрому раунда, самые необычные/сложные такие:
Это самый рискованный путь, и если задачу решить не удастся, то урон рейтингу будет мощным.
Можно пойти на такую хитрость - так как многие другие участники изредка мониторят "комнату" и сразу же блокируют свои решения после первых взломов (далеко не все задачи "взломабельные") и тоже пытаются ломать кого-то, лучше не ломать никого сразу, а накопить список лохов и потом грохнуть сразу пятерых и получить +500 баллов
(Самые жесткие вариации стратегии дополнительно предполагают засылку хренового решения по сложной задаче, лишь бы пройти претесты, а потом прочитать чье-то нормальное решение в комнате и также ломать)
Codeforces давал жесткую дозу адреналина, на которую подсаживаешься и побочно прокачиваешь навык решения алгоритмических задач. Это работает, есть такой вайб заходит (далеко не всем).
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Please open Telegram to view this post
VIEW IN TELEGRAM
C++95
GIF
#retro #story
Обзор Sega Mega Drive🏃
16-битная приставка Sega Mega Drive появилась у меня в середине 00-х. Я переиграл во многие игры, потому что на городском рынке можно было брать напрокат картриджи на неделю за 15 рублей🏃♂️
Хотя тогда было уже поздно для таких приставок, в провинции время идет с отставанием (обыграно в "Жмурках", снятом в то время), я помню даже оранжевые картриджи для совсем отсталой 8-битной Dendy на том же рынке🎮
Mega Drive породил новый культурный пласт и сподвиг людей на такие увлечения:
1️⃣ Sonic 😈 - вырос из игры 1991 года, которая выжала максимум из тогдашнего железа (обзор только физики значителен).
После успеха оригинальной игры вышло овер 9000 других игр про Соника, мультфильмов, комиксов и прочего хлама для школьников.
Известный деятель sndk также вырос на нем - даже пробовал сделать свою игру, и в параллельной вселенной он стал бы обычным программистом, но куда лучше у него получалась треш-озвучка, что стало его карьерой.
Даже профессиональные издатели игр выпускали закосы под Соника🦔
2️⃣ PixelArt 😊 - старые игры были вынуждены иметь пиксельную графику, но с эволюцией железа это почти сразу стало андеграундом. До сих пор живы ценители такого стиля.
В этой сфере популярно рисовать со всякими ограничениями, например "не больше 8 цветов на картинку".
3️⃣ RetroGaming 🎮 - любовь к старому железу и играм, анализ их архитектур и так далее. Играть можно на эмуляторах, хотя есть ценители которые приобретают старые оригинальные девайсы.
У некоторых приставок (у той же Mega Drive) есть новодельные реплики, можно их купить на алиэкспресс😁
Еще, например, есть дистрибутив Raspberry Pi специально под ретро, и у всех версий RaspPi есть композитный видеовыход, способный работать со старыми телевизорами, что нужно для аутентичности.
4️⃣ Reversing ⚙️ - реверс и изменение старых игр.
Изменение старых игр называется "ромхакинг", про это тоже есть куча ресурсов.
Есть деятели, которые проводят лютые стримы по ромхакингу.
Есть даже ежегодный конкурс на лучший ромхак Соника.
5️⃣ Sega - отдельные ценители следят именно за компанией Sega, например выкладывают на форумах всякие найденные сомнительной ценности материалы, наподобии "финансовый отчет Sega за 1986 год" 😁 Это показывает, насколько приставка повлияла на культуру, что даже такие увлечения есть.
Архитектура Mega Drive выглядит так🔍 , то есть состоит из нескольких главных кусков:
1️⃣ Motorola 68000 - главный процессор, о нем писал тут. Игры программировались на его ассемблере.
Любое обращение к памяти в ассемблере выполнялось шиной (на картинке 68000 bus), которая преобразовывала адреса в разные места: ROM картриджа (объем 4Mb), RAM процессора (объем 64Kb), контрольные порты и так далее, подробнее описано тут.
В общем, больше сказать нечего😁 Это обычный процессор для игровой логики, достаточно дешевый и популярный на момент создания Mega Drive.
2️⃣ VDP (Video Display Processor) - асик разработки самой Sega, чип видеоконтроллера. Полностью про его работу описано на этом крутейшем сайте (это лучшее, что я читал технического за год), ниже будет пересказ 😉
Этот процессор работает так - у него 24 регистра, которые отвечают за всякую хреновню, а также 64Kb собственного RAM (называется VRAM - Video RAM), куда нужно совать информацию о графике.
Данные во VRAM засовывает процессор 68000 (он же может менять регистры), и VDP просто отрисовывает на телевизор картинку согласно присланным данным и всё, больше ничего не делает.
В VDP достаточно навороченная система со цветами.
В любой момент времени активно 4 палитры, в каждой палитре находится 16 цветов, каждый цвет занимает 9 бит (то есть по 3 бита на R/G/B, суммарно доступно 512 уникальных цветов).
Первый цвет палитры всегда прозрачный, то есть по факту в палитре доступно 15 цветов плюс "прозрачность".
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Обзор Sega Mega Drive
16-битная приставка Sega Mega Drive появилась у меня в середине 00-х. Я переиграл во многие игры, потому что на городском рынке можно было брать напрокат картриджи на неделю за 15 рублей
Хотя тогда было уже поздно для таких приставок, в провинции время идет с отставанием (обыграно в "Жмурках", снятом в то время), я помню даже оранжевые картриджи для совсем отсталой 8-битной Dendy на том же рынке
Mega Drive породил новый культурный пласт и сподвиг людей на такие увлечения:
После успеха оригинальной игры вышло овер 9000 других игр про Соника, мультфильмов, комиксов и прочего хлама для школьников.
Известный деятель sndk также вырос на нем - даже пробовал сделать свою игру, и в параллельной вселенной он стал бы обычным программистом, но куда лучше у него получалась треш-озвучка, что стало его карьерой.
Даже профессиональные издатели игр выпускали закосы под Соника
В этой сфере популярно рисовать со всякими ограничениями, например "не больше 8 цветов на картинку".
У некоторых приставок (у той же Mega Drive) есть новодельные реплики, можно их купить на алиэкспресс
Еще, например, есть дистрибутив Raspberry Pi специально под ретро, и у всех версий RaspPi есть композитный видеовыход, способный работать со старыми телевизорами, что нужно для аутентичности.
Изменение старых игр называется "ромхакинг", про это тоже есть куча ресурсов.
Есть деятели, которые проводят лютые стримы по ромхакингу.
Есть даже ежегодный конкурс на лучший ромхак Соника.
Архитектура Mega Drive выглядит так
Любое обращение к памяти в ассемблере выполнялось шиной (на картинке 68000 bus), которая преобразовывала адреса в разные места: ROM картриджа (объем 4Mb), RAM процессора (объем 64Kb), контрольные порты и так далее, подробнее описано тут.
В общем, больше сказать нечего
Этот процессор работает так - у него 24 регистра, которые отвечают за всякую хреновню, а также 64Kb собственного RAM (называется VRAM - Video RAM), куда нужно совать информацию о графике.
Данные во VRAM засовывает процессор 68000 (он же может менять регистры), и VDP просто отрисовывает на телевизор картинку согласно присланным данным и всё, больше ничего не делает.
В VDP достаточно навороченная система со цветами.
В любой момент времени активно 4 палитры, в каждой палитре находится 16 цветов, каждый цвет занимает 9 бит (то есть по 3 бита на R/G/B, суммарно доступно 512 уникальных цветов).
Первый цвет палитры всегда прозрачный, то есть по факту в палитре доступно 15 цветов плюс "прозрачность".
ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Please open Telegram to view this post
VIEW IN TELEGRAM