Заметки

Лог и баг

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

Эти измерения записывались в судовом журнале, который тоже назывался логом. Со временем так стали называть вообще любой журнал или запись о каком-то событии, а в айти слово вообще обрело вторую жизнь :)

Или, скажем, «баг» — ну, про это, наверное, все слышали? Мотылек, который семьдесят с гаком лет назад помешал работе компьютера, был отмечен в журнале как «first actual case of bug being found», и пошло-поехало. Насекомое получило своего рода цифровое бессмертие: теперь так называют любую ошибку, особенно в программе.

(Жаль только, что это было не какое-нибудь насекомое посимпатичнее — ну, не знаю, бабочка? Это прибавило бы нашей работе нотку романтики)

(Впрочем, если подумать... Может, «bug» и не такой плохой вариант. «Butterfly» — как-то длинновато. Кроме того, кто-нибудь быстро сократил бы это до «butt», и чинили бы мы сейчас не баги, а жопы)

12 октября 2024 английский

Мимикрия ChatGPT

Коллеги вовсю экспериментируют с o1-preview от OpenAI: модель получилась по-настоящему интересной. Жаль, задачи для неё попадаются не так уж часто: с большинством повседневных прекрасно справляется и обычная 4o. Поиск ошибок в коде, анализ медицинских тестов на незнакомом языке, попытки вспомнить название книги, которую читал в детстве и едва помнишь завязку — я сходу и не вспомню, что ей не по зубам.

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

Морковка Кулаки Угараешь?

А вот ответ ниже прямо порадовал. Даже если оставить за скобками философию — Скайнет, похоже, отменяется! :) Впрочем, будущее из финала SOMA — пока, боюсь, нет.

Любовь

29 сентября 2024 ИИ видеоигры

Во!

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

Грузинский язык красивый, но на слух я его совсем не понимаю. Вздохнул, предложил перейти на английский или русский.

Девушки насупились. Потом одна выудила из сумки раздатку, показала на неё, потом показала мне большой палец — типа, во! — и сунула её мне в руки.

Рассмеялись и убежали.

Так тебе, языковой барьер, получай!

21 сентября 2024 тем временем Грузия

Про PDF

Получаю жалобу: клиент не может войти на наш портал. Смотрю в базе — учетная запись в порядке. Что не так-то? Проверяю логин и вижу чудную картину:

PDF

Выше то, что вводит пользователь, а ниже — то, что в базе. Первая мысль: откуда, черт подери, в строке взялся документ? :D

Опущу дальнейший разбор. Главное тут — задавать правильные вопросы (иначе и гугл, и ИИ будут рассуждать о популярном формате, а не о символе). Короче, PDF в контексте Юникода означает Pop Directional Formatting! Это символ, который управляет направлением текста; он нужен, например, чтобы корректно рендерить арабский язык (где может встречаться как текст слева направо, так и справа налево). Пользователь, очевидно, вводит логин в режиме RTL (или копирует откуда-то), а портал этого нюанса не понимает.

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

6 сентября 2024 работа

Восторг

Помню, в каком восторге я был, когда впервые поработал с оконными функциями в PostgreSQL. Можно построчно регулировать окошко вычислений для каждой строки! И на сегменты предварительно нарезать! И всё это — нативно, внутри самого обычного запроса, никаких пристроек справа и слева. Стандартная агрегация с группировкой и подзапросами, к которой я привык в 1С, резко превратилась в тыкву, совсем как карета Золушки в полночь.

Последнее время осваиваю Blender и внезапно ощутил то же чувство по той же самой причине. То, что объект можно произвольно таскать по 3D Viewport через команду Move, было понятно ещё на берегу, ладно. Но когда до меня дошло, что каждый объект — это набор полигонов, и каждый из таких полигонов тоже можно произвольно таскать, и это приводит к естественному изменению геометрии объекта — вот тут-то меня и накрыло.

Технологии удивительны. Учиться — клёво. Ради таких озарений хочется делать это ещё и ещё :)

31 августа 2024 PostgreSQL 3D

Некуда бежать

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

Ой, привет!

Отвлекся, блин. Платформа следит за тобой, %username%!

P.S. Зато теперь у меня есть кастомный значок с символикой любимой компании!

31 августа 2024 спорт

Анализ систем

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

Сертификат

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

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

Однако 1С-инстансы, кажется, можно воспринимать как монолиты с определенным набором характеристик (в зависимости от решаемых внутри задач), а в остальном коммуникации с ними мало чем отличаются от традиционных решений: те же события (например, кролик), те же входящие/исходящие HTTP-вызовы, тот же показатель instability и так далее.

На этом этапе я точно потащу (или уже потащил) к себе:

  1. Распил ТЗ на нумерованные пункты (US-XXX) и хранение их в одном месте с пометками «updated at», «canceled at» и так далее. Кажется, удачный формат.
  2. Ведение ADR. Собственно, это уже внедрил. Несколько смущает, правда, что в них периодически оседает что-то, что архитектурой в прямом смысле не является (например, принципы логирования событий на каком-то участке). Однако такие штуки тоже кажутся важными для принятия решений.
  3. Event Storming как способ визуализации бизнес-процессов. Не могу сказать, что он сильно выигрывает по сравнению с той сборной солянкой, которая до этого обычно оседала у нас, но результат выглядит симпатично и вообще: какой-то стандарт лучше, чем никакого.
  4. Диаграммы сервисов приложения с наклеенными стикерами, указывающими характеристики. Достаточно функционально, если надо взглянуть на проект с высоты птичьего полета и опять же не так сухо, как гигантские таблицы. То есть, если сработает bus factor — выше шанс, что следующий (или следующая) я заметит эти детали.
  5. Хочу делать BPMN-ки и Activity Diagrams. Формат мне нравится, но пока мои попытки оставляют желать лучшего. Буду пробовать ещё.
  6. Неожиданно зашел концепт разделения функционала для снижения зависимостей. Раньше казалось, что всегда проще склеить похожий функционал для снижения объёма кода, но это увеличивает и сложность, и внутреннюю связность — а значит, может сильно больше вредить, чем помогать.

В целом курсом очень доволен. Лучшее вложение сил за последний год. Если думаете идти туда, но сомневаетесь — идите :)

25 августа 2024 готово тем временем

Мой первый подход к генеративкам

Понадобилось по-быстрому наделать картинок для одного пет-проекта. Развернул первое, что под руку попалось — WaifuDiffusion (это такой клон StableDiffusion, но обученный на аниме и манге).

Запрос:

A dimly lit, empty classroom with faintly visible music notes on the chalkboard. A young woman with long blue hair and blue eyes, is standing behind the teacher's desk, packing her things into a small handbag. She looks tired and worried.

Результат:

Молодая женщина

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

Думаю, WaifuDiffusion просто решила поднять мне настроение. Смех, говорят, продлевает жизнь. В любом случае, первую генерацию считаю успешной! Но над калибровкой явно придется поработать еще :)

25 августа 2024 ИИ

Переключалка дней для Obsidian

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

Каждый раз набирать нужную дату мне лень, поэтому я написал под это скрипт. Берет дату заметки из её названия (ожидает, что она в формате ISO 8601) и рисует выноску со ссылками на вчера и завтра для неё. В заголовке выводит день недели для дополнительного удобства:

Пример

Скрипт написан для плагина Dataview, потому что я его и так использую для других задач. Можно легко переделать его для Templater, CustomJS или отдельный плагин накидать (мне, опять-таки, было лень возиться).

Если будете использовать:

  1. В функции noteLink() пропишите путь к вашей папке с ежедневными заметками (сейчас в ней папка Days для примера; путь, если забыли, указан в настройке Daily notes/New file location);
  2. Закиньте скрипт в шаблон ежедневной заметки (настройка Daily notes/Template file location).

17 августа 2024 Obsidian JavaScript

Клементина запомнит это

Когда ChatGPT запоминает какую-то деталь диалога на будущее, он рисует над своим ответом плашку "Memory updated". Типа, я понял:

Memory updated

Каждый раз смешно: сразу вспоминается The Walking Dead и мем «Клементина запомнит это» :) В этой игре персонажи, окружающие протагониста, запоминали его решения и это оказывало влияние на их поведение. В том числе и Клементина — девочка, которую главный герой спасает в начале игры.

Клементина запомнит это

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

9 августа 2024 ИИ видеоигры

Сделать окно дверью

Вчера во время прогулки слушал Be Somebody от Thousand Foot Krutch и неожиданно зацепился за фразу «you made my window a door». Мне эта идиома всегда казалась забавной: блин, врезать дверь вместо окна — это как-то небезопасно звучит. Можно выпасть с десятого этажа, например.

Но песня-то чудесная и совсем не про то! Стало любопытно; пошел копаться, какой смысл вкладывают носители языка.

Оказалось, это про две разные позиции: пассивный наблюдатель и активный участник. То есть, если перед тобой окно — ты лишь смотришь сквозь него на что-то или кого-то. А вот дверь можно открыть и что-то сделать. Так что «when I could only see the floor you made my window a door» — это по смыслу что-то вроде «когда мои руки опустились, ты помогла мне встать».

Кстати, есть ещё одна похожая идиома — «to be a better window than a door». Абстракция здесь та же: если какой-то человек похож на окно, а не на дверь — он никогда не подпускает окружающих близко к себе, делая пассивных наблюдателей даже из очень близких ему людей.

4 августа 2024 английский

Яга

Случайно вспомнил, что полгода назад кто-то из коллег закинул в рабочий чат ссылку на Ягу — будущего (наверное) конкурента JIRA в России. Разработкой, судя по URL, занимаются ребята из Ростелекома. Проснулось любопытство — как оно там, взлетело?

Увы, но похоже, что нет. По крайней мере, на лендинге висит стандартное «оставьте заявку и ждите ответного гудка». Доступна урезанная версия для команд поменбше, но я сейчас не в России, и клик по кнопке «Начать пользоваться» приводит к бану. Ладно, как-нибудь в следующий раз.

Нейминг, конечно, у ребят кликбейтный. Но не уверен, что прям удачный. Например, название «1С», может, и провоцирует натужные шутки (один эс! задница Одина! хахаха!), но если ты гуглишь его — то, скорее, находишь инфу про платформу или хотя бы вендора. А не кучу статей, фанфиков, фанарта и видеоигр, как в случае с Ягой.

И вообще, ассоциации какие-то не те лезут. Избушка на курьих ножках? Выглядит как изначально плохо спроектированное приложение, которое кое-как переделали прямо на проде. Ступа? Костыль? Блин, если смотреть с точки зрения программистов — тут не красные флаги, а алые знамена :)

Ну и я еще, наверное, испорченный, но при слове «Яга» у меня в голове первым делом всплывает не могущественная ведьма из славянского фольклора, а отвратительное пойло из двухтысячных.

И вот баба с ягой уже не быдло, а патриотичная программистка!

― коллега

29 июля 2024 тем временем

Ибрагим

Закатился в курс по анализу систем, который проводят ребята из "Школы сильных программистов". Цели у меня две:

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

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

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

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

А переходишь к дополнительным ссылкам — вообще хоть святых выноси. Нужно полгода, не меньше. Я старался читать их хотя бы по диагонали, но это оказалось чертовски плохой идеей: кончилось тем, что главный герой курса начал мне мерещиться в уличной рекламе :)

Ибрагим

7 июля 2024 тем временем

Сингапурская кукла

Можно ли любить валюту своей страны сильнее, чем жители Саудовской Аравии? Вопрос риторический: уверен, что нет.

Разглядываю сайт их центрального банка. Валюта страны — саудовский риал, и курсы других валют ЦБ устанавливает по отношению к ней. То есть, нет смысла спрашивать с банка курс самого риала. Однако сайт невозмутимо предлагает выбрать его дважды:

Форма выбора

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

Другая забавная деталь: коллеги, кажется, хранят названия валют как строки длиной в 14 символов. Иначе сложно объяснить, почему по их данным в Канаде используется не канадский доллар, а CANADIAN DOLLA, а в Румынии — загадочный NEW ROMANIAN L вместо леи. Впрочем, этим двоим ещё повезло: Сингапур, например, ведёт расчёты в SINGAPORE DOLL.

22 июня 2024 работа

Не уникальные метаданные

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

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

При этом платформа не предлагает никакого понятного способа найти такие записи — иди туда, не знаю куда, сделай то, не знаю что.

Таблица метаданных истории данных cодержит не уникальные записи, которые должны быть удалены

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

Как это работает? Ну, когда меняется состав реквизитов объекта (например, реквизит в справочнике добавили), платформа запоминает его метаданные: конкретно, добавляет в _DataHistoryMetadata новую запись и сохраняет в ней актуальный список реквизитов объекта, а также номер версии этого списка (например, в при включении истории для объекта сохраняется первая версия метаданных, при добавлении какого-нибудь реквизита — вторая и так далее).

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

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

Как помочь больной скотине?

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

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

  1. get-issues.sql проверяет, что проблема есть: ищет версии метаданных, которые одновременно помечены как актуальные.
  2. fix-issues.sql снимает признак актуальности с тех версий, которые на самом деле устарели.

Оба запроса написаны для Microsoft SQL Server. Если вы используете PostgreSQL, то вот они же для этой СУБД.

Запросы потребуют небольшой адаптации под конкретную базу: в них используется поле _fld626, в котором хранится разделитель данных. В вашей таблице _DataHistoryMetadata это поле может называться иначе, поэтому нужно обновить его имя на актуальное. Ошибиться будет трудно — у таблицы только одно поле с префиксом _fld.

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

8 июня 2024 PostgreSQL MS SQL

Главная проблема UUID

Наткнулся на хороший текст об основной проблеме, которую таскает с собой UUID. Для 1С она тоже актуальна: все ссылочные объекты платформы (элементы справочников, документы и так далее) имеют собственные UUID. Они хранятся в БД, активно используются при поиске и, понятно, обильно индексируются (со всеми вытекающими последствиями).

1С старается компенсировать проблему, создавая последовательные UUID. Пусть не идеально, но в целом эта штука работает и индексы получаются более-менее ровными. Да и вообще в сообществе об этом говорят довольно давно: вот, например, бородатый топик на Мисте (правда, тут диалог быстро перерос в курятник и из шести десятков комментариев от силы полтора — по делу).

P.S. Рассмешила ремарка про вероятность создать в одной базе два одинаковых UUID:

As an aside, for those worried about collisions: you should take up the lottery, since winning the jackpot twice in a row is a much more likely outcome than your system ever generating two identical random 128 bit numbers.

2 июня 2024 PostgreSQL

Скриншот со звуком

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

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

Cut My Life Into Pieces

Заголовок вышел со звуком. Ладно, думаю, смешно, но как тогда назвать? Во, пусть будет Distributed Internal ERP. Сокращенно... DIE?

Оставил первый вариант. Long live Papa Roach :)

20 мая 2024 работа тем временем

Таймшит для Обсидиана

Написал ещё один плагин к Obsidian, на этот раз — для ежедневных заметок. Рисует симпатичный отчет: над какими задачами работал, что сделал, сколько времени потратил. Я постарался описать в репозитории, как это работает; буду рад, если кому-то ещё пригодится!

Забавный момент: для примеров в README я использовал номера задач FBI-1, FBI-2 и так далее. Это не отсылка к X-Files или Twin Peaks — просто первое, что пришло мне в голову. Дело в том, что наш внутренний проект по разработке FirstBit ERP называется First Bit Internal, сокращенно — FBI. Основной пул задач, над которыми мы работаем, живёт именно в нём.

Мы-то уже привыкли, но коллег вне компании наши скриншоты из JIRA или SonarQube неизменно веселят. Представили, что вы — агент Купер? А мне и представлять не надо :)

12 мая 2024 готово TypeScript Obsidian работа

Запросом больше, запросом меньше

Регулярно слышу тейк: запросом больше, запросом меньше — без разницы. Мол, главное, чтобы запрос был дешевым: не читал лишнего, попадал в индекс и так далее.

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

Пример из недавней практики. Есть ERP, в которой лежит таблица с этапами оплаты по заказам клиентов. Один из таких этапов — предоплата; пока она не внесена, создать заказ поставщику нельзя.

Технически в заказе поставщику просто хранится ID заказа клиента; если последний заполнен (то есть, заказ поставщику создан под заказ клиента), ERP нужно прочитать этапы оплаты по заказу клиента и понять, можно ли делать закупку.

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

825701 записей

То есть вместо того, чтобы выдернуть два-три этапа оплаты по заказу, ERP читает без малого миллион! Как так?

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

Оказалось, большое. В таблице этапов оплаты оказались данные не только для заказов клиентов, но и для других видов документов. Поле с ID заказа клиента у них было пустым. В итоге ERP при попытке найти этапы оплаты по пустому ID заказа клиента находила такие записи — и, как видите, немало.

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

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

5 мая 2024 оптимизация

Фудиари для Обсидиана

Вслед за первым плагином для Obsidian пару недель назад выкатил второй. Считает КБЖУ (калории, белки, жиры и углеводы) в пище. Помогает не переедать на пустом месте — всё-таки на глаз трудно оценить, сколько слопал за день, и можно ли позволить себе вон тот пончик.

Короче, полезная штука, если вы:

  1. Толстяк (как я)
  2. Хотите перестать им быть (как я)
  3. Ведете заметки в Obsidian (как я) 🙂

На самом деле, программ для этой задачи полным-полно (я перепробовал штук десять). Остался недоволен: либо страшная, либо глючит, либо постоянно пытается всучить ежемесячную подписку. Короче, больше раздражает, чем помогает. Хочется чего-то нативного, встроенного в обычную рутину — и если она оседает в Obsidian, то решение напрашивается само собой.

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

В репозитории по ссылке выше есть примеры.

14 апреля 2024 готово TypeScript Obsidian

Ранее Ctrl + ↓