Распределение времени в разработке

Только половина программирования это кодинг. Остальные 90% это отладка(поиск багов).
Сохраняй посты, комментируй и ставь оценки

Только половина программирования это кодинг. Остальные 90% это отладка(поиск багов).

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

Для максимальной скорости и эффективности выгрузки изображений из любой точки Земли мы внедрили на сайт CDN - Content Delivery Network. Эта система позволяет оптимизировать загрузку, распределяя ваши картинки по серверам, что минимизирует задержки и ускоряет отображение.
Также была реализована функция проверки размера изображений и их сжатие. Это гарантирует, что слишком большая фотография не заставит сайт лагать или работать медленнее. Мы понимаем, что такое решение может расстроить фотографов и тех капибаринов, которым важно разглядеть все мельчайшие детали в первозданном виде. Однако покуда наш сайт молод и мал, к сожалению, это наиболее оптимальное решение для обеспечения его работоспособности.
На наш сайт помимо обычных картинок вы можете загружать и гифки (.apng, .gif, .webp) размером до 5 Мб. Каждое загруженное изображение конвертируется на стороне бэкенда в webp для оптимального отображения и снижения нагрузки на инфраструктуру.
Для не прогружающихся картинок - из-за плохого интернета, проблем на сайте или в браузере - мы добавили плейсхолдер - специальную рамку, которая рисуется вместо проблемного изображения.
Ограничение количества медиа в комментариях. Введено ограничение на количество медиафайлов в комментариях до двух изображений, чтоб не перегружать интерфейс и не удлинять сверх меры комментарий. При попытке добавить третью картинку сайт предложит создать отдельный пост.
🤖 Бот для Верификации через Telegram.

Для упрощения процесса верификации профилей через Telegram был создан специальный бот. Он позволяет пользователям верифицировать свои аккаунты всего в три клика.
Для бота верификации добавлена поддержка создания Docker-образов в среде GitLab-CI.
Это означает, что процесс развертывания и обновления бота теперь может быть полностью автоматизирован с использованием Docker-контейнеров. Внедрение GitLab-CI обеспечивает непрерывную интеграцию и доставку (CI/CD).
💭 Комментарии

Почти одновременно с началом альфа-теста была завершена разработка дерева комментариев. Мы реализовали сами комментарии а так же систему управления их вложенностью - это значит, что когда ветка уходит вправо на 4 (для телефонов) или 9 уровней (для компьютеров), новые комментарии оказываются снова слева , однако теперь с гиперссылкой на родительский комментарий. Это улучшает визуальное восприятие длинных веток и предотвращает излишнее дробление обсуждения.
Заложен первый камень в защиту сайта от ботов. Была реализована верификация пользователей через телеграм и ограничение на комментирование, голосование и создание постов для тех, кто её не прошёл. Такая система позволит усложнить жизнь ботоводам, ведь завести 100500 почт намного легче чем 100500 телеграм-аккаунтов. От того, что они у нас массово зарегистрируются, особого вреда не будет, а вот от того, что они будут клепать «нужные» посты, бурстить / топить «нужные» комментарии / посты — вред очевиден
(Если этого не сделать, будет как на Пикабу сейчас)
Для живых, пока еще неверифицированных пользователей, мы реализовали интуитивно понятные всплывающие сообщения о необходимости подтверждения аккаунта при попытках комментирования, голосования или создания постов. Это улучшает пользовательский опыт, предоставляя чёткие инструкции о необходимости верификации для полного доступа к функционалу платформы.
Индикация новых и непрочитанных комментариев. Сейчас ведётся активная работа над системой визуальной индикации, которая будет выделять новые и непрочитанные комментарии в ленте ответов. Это значительно упростит отслеживание активности в дискуссиях и поможет пользователям не упустить важные моменты обсуждения.
🏷️ Теги
Фильтрация по тегам. Разработали ленту постов с поиском по одному или нескольким тегам. В нее можно перейти как с бокового меню(вкладка «Теги»), так и напрямую из поста кликнув по тегу. В открывшейся вкладке вы можете добавить дополнительные теги по которым будет осуществляться поиск постов.

Пока только на бэкенде, но уже сделали API отдающее список популярных тегов для быстрого выбора тегов на странице поиска по тегам.
Установили лимит в 10 тегов на пост, исключая специальные теги, такие как «Своё», «Авторское» и «Телеграм». Это предотвращает перегрузку постов избыточным количеством тегов и способствует более точной категоризации контента.
Специализированные Теги «Своё» и «Авторское». Ведётся разработка нового блока в интерфейсе создания поста для выбора этих специальных тегов, включая подсказки, которые объясняют их значение. Тег «Своё» предназначен для контента, созданного пользователем лично или имеющего к нему прямое отношение. Тег «Авторское» применяется к контенту, в который пользователь вложил своё время, старания и творческие усилия
👁️ Лента «Просмотренное»

На бэкенде реализован API для управления и вывода просмотренных постов. Это означает, что теперь у нас есть бэкенд-структура, которая способна обрабатывать и передавать данные о просмотренных пользователями постах. Однако, эта функциональность пока что не интегрирована в пользовательский интерфейс и доступна только на уровне сервера.
Также на бэкенде начата работа над механизмом скрытия просмотренных постов из ленты. Эта функция также пока не реализована, но находится в активной разработке
🔥 Лента «Тренды»
За последнее время мы также сделали ленту «Тренды», в которую попадают положительно оцененные пользователями посты.

В данный момент алгоритм выходы в Тренды следующий: рейтинг поста больше 25 и более 80% плюсов. Сортировка в ленте осуществляется на основе двух ключевых параметров: процента положительных оценок и времени публикации поста.
Хотя лента «Тренды»(как и «Новое» и «Топ») визуально кажется бесконечной, посты на самом деле подгружаются постранично (пагинация). Это означает, что контент из бэкенда на фронтенд отдаётся не одновременно, а порциями. Введено ограничение в 20 постов на страницу для лент. Это решение позволяет ускорить загрузку контента и снизить нагрузку на базу данных.
Существующий алгоритм сортировки в ленте «Тренды» не является финальным, и мы планируем продолжить экспериментировать для определения наиболее оптимальных критериев сортировки. Как минимум, следующим шагом добавим влияние наличия тегов «Своё» и «Авторское» на упрощение выхода поста в Тренды. После добавления функционала скрытия постов продолжим искать наилучший алгоритм.
🖋️ Редактор постов

Добавлено ограничение по количеству символов в заголовках постов на Капибаре. Это необходимо для более красивых URL-адресов и менее загруженного внешнего вида сайта.
Ещё теперь можно загружать видео, правда пока что только с YouTube и Coub. В ближайшем будущем возможно расширение функционала возможностью добавления видео с других платформ, например из ВКонтакта. К сожалению, прямая загрузка видео на сайт пока невозможна ввиду ограниченного бюджета проекта. т. к. стоимость хранения и обработки зависит в том числе от количества просмотров.
👤 Профиль пользователя
Наконец-то можно поставить свою аватарку! Также близится к своему завершению доработка функции «О себе» - вы сможете написать какую-то фразу в своём профиле, которая будет видна остальным пользователям… Вернее, написать вы можете уже сейчас, просто пока что информация не сохранится. Но это скоро починим

Помимо этого, была исправлена ошибка 404, которая возникала при попытке доступа к страницам профилей пользователей.
И, наконец, важное изменение в создании профиля - нами была введена проверка на уникальность имени пользователя, игнорирующая регистр букв. Это означает, что имена типа "kapibar" и "KaPiBaR" теперь считаются идентичными с точки зрения системы.
🔨 Прочие Улучшения

Устранено более 150 мелких и значительных ошибок, обнаруженных отважными авторам - альфа-тестировщиками и сообщенных через систему репортов.
🪲 Баги.

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

Мы не можем упустить возможность выразить нашу глубокую благодарность всем альфа-тестировщикам, которые помогли и помогают нам обнаружить и устранить баги на нашей платформе. Ваша обратная связь была неоценимой, и мы благодарны за каждый отправленный вами баг-репорт! Ребята, вы - лучшие :)
🌟 А также Особая благодарность десяти самым активным тестировщикам:
kapi.bar/profile/NoAdO – 66 баг-репортов
kapi.bar/profile/Wtagn25 – 38 баг-репортов
kapi.bar/profile/DrMegabyte – 29 баг-репортов
kapi.bar/profile/vita – 28 баг-репортов
kapi.bar/profile/vervolph – 24 баг-репортов
kapi.bar/profile/Sergej_Serov – 22 баг-репортов
kapi.bar/profile/mik_s1d – 19 баг-репортов
kapi.bar/profile/Archi – 18 баг-репортов
kapi.bar/profile/jewellerpotato – 17 баг-репортов
kapi.bar/profile/Eisenporn – 16 баг-репортов
🌍 Благодарим всех остальных альфа-тестировщиков отправивших нам репорты об обнаруженных багах:
Blood, Yarilo23, Rofs, UglyElf, gambitushka, userfortest, ZenitTTLMir1B, Xrenotik, LinDess, Marta, Lazolvo, olvik, Innokenti4, uk_kate24, Dnocompany, Unionsquare, L0z4, Kvasnik, Xena, rammdarkfunny, Tiamin,
Jugabut, Dr.Hannibal, BulkaSmaslow, Kyrillbeisel, KonstantyPL, findeler, aice4, gulyashbezpiva, appossumoid, FreeDaSw, Wesker, alexvektor, Dildiy, Cloud, oriaraniar, BabudaiAga, VODKA5665, WandWanderer, PaulHirsch, Hokum62,
Nojnichki, Bespiril, indie_dev_01, Beer3erk, BeerFather, dones, stormspeller, prmn, ITMan96, Custom_KseniEv, loonyloon, Darti163, nameless.second, Shady311, Pilirom, veterinar, lenanexman, socialware, zzaec, kritbis,
kusokcheloveka, statusspb, Bowjob, ctulhu31, SergeyRY, R.Melvin, Kitsu-NeshKaa, Rilwing, Ahremkin, ibraman, Marb.Ivanna, SexFox, camelos, HugReed, Hippopocat, Chaika312, hunterpo, Exfaded, SIGILLITE,
chief, tanur_orican, gelevaya, ally_me, Natt, Hegny, shaehl, EpicMorg, Vojdelenec, margent, timur_bv, CircusBirdEli, Aragorn, Phyros, HARDiNA, Kisati, SarcasticImp, Akyndro, V27S, ivanisenko, LeSpectateur,
Мы постоянно работаем над улучшением Капибары и ценим вашу обратную связь. Записывайтесь на альфа-тест, в данный момент набираем не только авторов но и активных комментаторов.
Ваша, команда Капибары 🧡💙
Мы предпочитаем работать в чуть более комфортных местах, нежели подвал :)

В наличии есть окно(!!), стол, стул и кондиционер, и даже кровать!

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

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

За шакалов извините(.
Я бы советовал переименовывать изображения для удобства.
Итак, запоминаем новый тег, который послужит для добавления фото на сайт.

Разберем этот тег:
src="" - атрибут, который дает ссылку на фото, которое нужно добавить на сайт, внутри кавычек нужно добавить название файла с расширением, например, kapibara.jpg.
alt="" - атрибут, который работает в случае, если браузер не может найти или обработать фото. Вместо него он говорил нам, что это за фото. Так он работает///

Weight и height обозначают высоту и ширину, все просто.
Перед созданием навигации расфасуем все пункты по id и дадим им свои классы. Запоминаем новый атрибут - id.
Подобным образом создаем id. (вместо class - id)

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

Вроде все, ах да..!
Помните те линии в Википедии после заголовков? Чем наша Капипедия хуже? Тег создает линию. Прописываем ее после заголовков.

Спасибо за внимание к посту! Надеюсь вам понравилось, ну а я пойду капибарить новый пост, всем пока.
Я сегодня испытал на себе шахидский крафт.
Создаю на верстаке меч волшебный. Когда крафт заканчивается, стол взрывается вместе со мной.
Начинаю разбираться.
Когда крафт заканчивается, предметы-ингредиенты для него исчезают(до этого хранятся чтобы можно было сделать отмену крафта и обратно получить компоненты)
Но! Я вызывал метод дестрой у компонентов, который я переопределил ранее под пользовательские нюансы.
И камни с энергией ( взял за основу powerstone из gurps4e) взрываются при уничтожении обычно. А должны просто исчезнуть в этом конкретном случае.
Короткий познавательный пост, основанный на моей больной фантазии. Все совпадения случайны.
Обратился как-то один человек на профильном форуме с вопросом, как запустить (не сказать чтобы старую) игру на Windows 10. Игра (хотя я бы назвал это технодемо) была разработана на легендарном XNA 4.0 (земля пухом) и планировалась к выпуску через Steam Greenlight (и ему земля пухом) еще в далеком 2012, после чего заброшена и убрана со всех магазинов.
Игра была куплена тем человеком еще в тот момент, когда она легально продавалась. А спустя годы она просто перестала подавать признаки жизни. $5 за полную версию уплочены, а поиграть нельзя. Обидно.

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

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

Ошибка. Открываем стек вызовов и ищем место, где произошел провальный запрос в сеть.

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

Если почитать документацию на XNA, то этот метод предназначен для загрузки контента и вызывается автоматически при запуске игры. Первым делом выполняется инициализация некоторых вещей, после чего открывается файл настроек (options.xml) и начинает последовательно считываться. Как только считываются параметры аккаунта для таблицы рекордов, то происходит отправка логина+пароля на официальный сайт и попытка получить ID. Если сервер возвращает Failure, то открывается диалог входа, который можно пропустить. Если сервер возвращает число, то игра запускается. А вот если сервер недоступен, то вылетает исключение, которое никак не обрабатывается и приводит к молчаливому вылету.

На этом этапе есть 2 варианта действий:
Нормальные герои всегда идут в обход, так что переходим к написанию небольшого патча. (На самом деле, о первом варианте я додумался не сразу. Более того, полная версия зависает при убирании этого пункта из настроек).
Выделяем строчку с запросом и нажимает "Изменить инструкции IL". Открывается окно с заголовком "Изменение тела метода".

Это - язык MSIL. Он очень прост и сильно напоминает Forth, на самом деле, но новичка может отпугнуть.
Ключевым элементом является стек. Что такое стек я уже когда-то рассказывал. Это некоторое место, на вершину которого можно последовательно добавлять значения (числа, строки и прочие объекты), а так же снимать их в обратном порядке.

Тут мы добавляем на стек:
Потом мы вызываем String::Concat(), принимающий в себя 4 строки и соединяющий их вместе. При вызове метода будут сняты 4 верхние строки со стека и добавлена новая строка.
Вызов следующего метода (WebClient::DownloadString()) снимает строку, полученную от String::Concat(), и веб-клиент. В результате должна остаться только 1 строка, возвращенная WebClient::DownloadString().
Следующим этапом мы должны снять эту строку со стека и сохранить её в локальную переменную 1, но этого не произойдет, так как WebClient::DownloadString() всегда будет проваливаться и выбрасывать исключение. Исключение, если его не обработать сразу, будет раз за разом проваливаться глубже по стеку вызовов, пока не достигнет обработчика или дна. Так как никаких обработчиков по пути нет, то исключение достигает дна и приводит к вылету.
Чтобы избежать получения исключения, мы можем убрать всё, что предназначено для запроса в сеть. Примерно вот так:

8 инструкций превратились в 2: загрузка строки с числом (которое может быть любым) и сохранение в локальную переменную под номером 1.
Сохраняем и проверяем результат.


Из декомпилированного кода полностью исчез кусок с запросом. Осталась лишь загрузка константной строки и сравнение с "Failure", которое всегда будет успешным.
Сохраняем модуль и пытаемся запускать опять.



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

Но не всё так просто. Если попытаться пройти любой уровень, то вылетит то же самое исключение.
Для исправления точно так же выделяем строку и опять редактируем инструкции в теле метода. Но так как отправка статистики нонче ни на что не влияет, то просто удаляем выделенные инструкции без остатка.
А для надежности выделяем WebClient, нажимаем "Анализировать" и смотрим, где еще может ждать нас подлянка.

В Finish.Update() мы ошибку только что исправили, в Game1.LoadContent() исправили в самом начале, а Login.button1_Click(), Program.Main() и Title.Update() нас не интересуют, так как достаточно просто не делать того, что приведет к обращению в сеть (а конкретно: не открывать диалог входа, не указывать никакие аргументы при запуске и не пытаться авторизоваться через главное меню (вроде бы не реализовано)).
Вуаля. Игра работает как прежде.
Привет, с вами чихнул! (не глагол, а я) Как я говорил в прошлом посте, я - начинающий веб-разработчик. Базовые знания я уже имею и хочу поделиться с вами.

С чего начнется наш путь? Для начала нам нужно освоить базу, на чем строятся сайты. Вообще, для более менее полноценного сайта требуются три языка - html, CSS и JavaScript. Самый первый язык (хотя не совсем язык, но давайте не обижать его) - HTML. Кто-то вместо него использует PHP, кто-то другие языки. Это - основа основ. Без него вам не собрать ни один сайт. Ни-че-го.

Что из себя представляет html? По-сути, это буквально текстовый редактор. Вы не сможете сделать с ним красивые фоны, анимации, пушки и бомбы. Но и без него вы этого не сделаете.
Как строится код html? На деле - очень просто. 90% кодов идут по следующей схеме: Открывающий тэг - содержимое - закрывающий тэг (в большинстве случаев со слешем). Рассмотрим самый простой код с тэгом
, что выводит текст на экран.
Код слева, что видит посетитель сайта - справа.
Помимо этого для написания текста есть тэги заголовков, где - самый большой, а равняется стандартному
.

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

А как Вы думаете?

Гейб Ньюэлл – редкий пример руководителя в игровой индустрии, добившегося огромных успехов и в творческой, и в бизнес-сфере. Но у подобного статуса оказалась неожиданная обратная сторона – после Portal 2 глава Valve фактически отошёл от активного участия в создании игр.
Причину раскрыл Джош Вайер, ведущий дизайнер Portal 2, в интервью каналу Kiwi Talkz. По словам Вайера, Ньюэлл осознал, что окружён людьми, которые просто не решаются ему возражать.
Он всегда хотел быть частью команды, но будучи Гейбом и занимая своё положение, это никогда по-настоящему не работало. Люди просто говорили: "Как скажешь", а он отвечал: "Нет-нет-нет, я хочу быть частью команды и предлагать идеи". Это было действительно сложно для окружающих, так что, думаю, наступил период, когда он отступил и сказал: "Ладно, видимо, я просто не смогу так взаимодействовать со всеми".

Речь идёт о конце 2000-х – периоде, когда Valve была на пике после Half-Life 2, а Steam превратился в доминирующую платформу цифровой дистрибуции на ПК. Даже если Ньюэлл искренне настаивал на равноправном сотрудничестве, нетрудно понять нежелание спорить с человеком, стоящим за несколькими играми, изменившими индустрию.
Подобная ситуация несёт вполне конкретную опасность. Классический пример – Джордж Лукас на съёмках приквелов "Звёздных войн", где отсутствие возражений привело к неоднозначному результату. Когда окружающие начинают идеализировать руководителя или придавать особый вес каждому слову, творческий процесс перестаёт работать так, как задумано.
В титрах Portal 2 Ньюэлл указан как продюсер. В последующих релизах Valve его участие сводится к благодарностям или общим упоминаниям в составе студии. Судя по словам Вайера, глава Valve теперь в основном наблюдает за процессами со стороны и изредка делится соображениями, но редко погружается в разработку напрямую.
Привет капибаряне! Возможно, уже увидев название поста вы были удивлены, но я покажу вам, как создать свою псевдовикипедию, хотя, быть честным, только страницу из нее. Итак, начнем.
Для написания кода вы можете использовать разные среды разработки, например, я использую VSCode, однако, для постов я использую онлайн компилятор repl.it , т.к. это банально быстрее и легче.
В прошлом посте мы с вами узнали, как добавлять на свой сайт текст и заголовки. Но начнем немного раньше.
Первый наш код должен иметь следующее содержание, но не пугайтесь - я все вам объясню.

Сейчас вы все испугались, но успокойтесь. Давайте по порядку.
рассказывает браузеру, на какой версии html построен сайт, дабы избежать ошибок.
Говорит браузеру, что наш сайт русскоязычный. Это нужно, например, для встроенного переводчика. Так он может понять, с какого языка переводить сайт для иностранного посетителя.
В контейнере (Да, запомните это слово, чуть позже оно нам пригодится) head хранятся данные сайта как сайта. Логично.
говорит браузеру, в какой кодировке написан сайт.
А вот в хранится название вкладки. Да-да, вкладки. По-этому эта часть особенно важна.
Итак, перейдем к основе, все, что внутри сайта, пишется в контейнере . Нашу страницу на википедии мы будем писать о... КАПИБАРАХ!!!!! кхм-кхм, извините

Начнем с тех моментов, которые мы изучили ранее. Создадим заголовки. Из предыдущего поста вы узнали, как их создавать.
Создайте заголовки следующего типа: Капибары (h1), Внешний вид (h3), Отличительные признаки (h3), Обитание (h2), Места с наибольшей популяцией (h3) и Места с наименьшей популяцией (h3), Медиа (h2).
Ваш код и сайт будут выглядеть так:

Уже напоминает?
Но чего-то не хватает. А, точно, описания капибары! В интернете находим описание капибары и вставляем. Какой тег мы будем использовать для обычного текста? Правильно - тег параграфа
.
Добавляем информацию из интернета для пунктов
А чтобы текст не выглядел скучно, выделите основные моменты (ВРЕМЯ ЗАПОМИНАНИЯ НОВЫХ ТЕГОВ!) жирным шрифтом - или или курсивом - . Для этого прямо в тексте выделите нужные слова этими тегами.

Ну, почти все. Но, почему мы пропустили пункт "Места с наибольшей популяцией"? Тут нам нужно сделать так называемый "топ стран", иначе говоря - список. Есть два типа списков:

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

Глава и основатель Larian Studios Свен Винке поделился новостями о ходе разработки новой Divinity, отметив, что игра достигла той стадии, когда разработчики "чувствуют, что она начинает оживать". Пост Винке в целом довольно абстрактный и адресован скорее коллегам по индустрии, но для поклонников студии, ожидающих новостей, это важный сигнал.
По словам Винке, ключевой момент осознания пришёл во время разговора с директором по нарративу Larian Адамом Смитом.
Он провёл целую неделю, прорабатывая различные вариации одной конкретной ситуации, подбирая слова, и у него было полно идей. То, что он говорил, имело смысл, но поразило меня не это. У него часто бывают хорошие идеи. Меня поразил уровень энергии, на котором он находился.
Винке сравнил свои ощущения с возвращением в знакомое и любимое место:
Это сделало меня счастливым, потому что я почувствовал, будто вернулся в хорошее место после долгого отсутствия и увидел, что все мои любимые люди и места всё ещё здесь, вместе с кучей новых, ожидающих, пока я их исследую.
На данный момент о новой Divinity известно не так много помимо того, что можно было почерпнуть из мрачного анонсирующего трейлера. Игра станет полностью самостоятельным тайтлом, масштабнее Baldur's Gate 3, с расширенным взаимодействием между спутниками. Также Larian заверила, что в игре не будет сгенерированного ИИ контента. Всё это пока достаточно общие штрихи, и именно поэтому слова Винке представляют особый интерес. По его утверждению, игра всё ещё "очень податлива", но он уже уверен в том, что в итоге получится хорошая RPG.
Я говорю о том этапе разработки, когда многое ещё сырое или отсутствует, но ты чувствуешь, что игра начинает оживать. Что-то было создано из ничего, и теперь ты можешь ощутить, каково это, зная, что всё ещё очень податливо и что отсюда дальше может стать только лучше. Это хороший момент в жизни любой игры. И я уверен, что многие разработчики его узнают.
Винке также описал конкретный момент, окончательно укрепивший его в уверенности:
Когда наша беседа перешла к аркам одного из наших антагонистов и мы начали обсуждать микродетали, я сказал себе – да, это хорошо.

Марк Дарра, исполнительный продюсер серии Dragon Age и печально известной Anthem, опубликовал видео под названием "Have an Idiot at the Table", в котором рассказал о неочевидной, но, по его словам, ценной практике в разработке игр: включении в рабочие обсуждения "идиота" – то есть человека без профильной экспертизы.
По словам Дарры, более половины своей карьеры он сам выступал именно в такой роли. Будучи программистом по образованию, он участвовал в дискуссиях об игровом дизайне, художественном направлении и звуке, не имея глубокой подготовки ни в одной из этих областей. Именно это, как он считает, и делало его присутствие полезным.

Суть аргумента Дарры сводится к тому, что узкие специалисты склонны замыкаться в рамках собственной дисциплины. По его словам, разговор между экспертами способен "начать пожирать собственный хвост", когда те чрезмерно увлекаются тонкостями ремесла. Дизайнеры могут выстраивать системы нарастающей эзотерической сложности, сценаристы и создатели вымышленных миров способны часами обсуждать проработанность придуманных хронологий, а художники рискуют погружаться в "обсуждения незначительных деталей с пустым пространством, которые очевидны им, но могут не восприниматься рядовым игроком".
Очень тонкие вещи могут просто не считываться. И это может быть нормально. Но если [игра] пытается донести свою мысль исключительно через тонкие вещи, эта мысль может потеряться.
Присутствие человека без экспертизы, способного поднять руку и честно сказать, что он не улавливает нюансов, помогает команде понять: вещи, очевидные специалистам, могут оставаться незамеченными для широкой аудитории. Важно, что это не призыв отказываться от глубины и деталей, а скорее индикатор того, что какие-то элементы стоит сделать более доступными.
Однако Дарра делает важную оговорку: чтобы подобный "внешний голос" приносил пользу, а не становился источником раздражения, такой человек должен владеть одним ключевым навыком – умением молчать тогда, когда ему нечего сказать.
Если вы этот внешний голос, от чего действительно нужно себя уберечь – это не попасть в ловушку ощущения, что вы должны давать столько же обратной связи, сколько остальные за столом. Вы не подготовлены к этому.
Если "идиот за столом" начинает злоупотреблять своей ролью и активно высказываться по каждому поводу, команда, по словам Дарры, "начинает бояться его участия": обсуждения превращаются в попытку справиться с потоком мнений, не подкреплённых практическим пониманием.
Хорошо иметь этот внешний голос, но этот внешний голос должен понимать, что ему не стоит говорить большую часть времени в комнате.

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

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

В интервью Eurogamer Тодд Говард из Bethesda осторожно прошёл по минному полю дискуссий об ИИ в игровой индустрии, пояснив, что технология может быть полезным "инструментом", но не для создания контента.
Я рассматриваю это как инструмент. Творческое намерение исходит от людей-художников, это главное. Но мы смотрим на ИИ как на инструмент – есть ли способ использовать его, чтобы быстрее проходить некоторые итерации, которые мы делаем сами. Не для генерации вещей, но мы постоянно работаем над нашим инструментарием для построения миров или проверки элементов.
Говард далеко не первый известный разработчик с подобной позицией. Хидео Кодзима недавно назвал ИИ "другом", которого хотел бы привлекать только для "рутинных задач", снижающих затраты и экономящих время.
Думаю, если вернуться на 10 лет назад, к той версии Photoshop – вы бы не захотели работать с ней снова. Таков наш взгляд на это. Но мы хотим защитить художественность. Человеческое намерение – вот что делает наши работы особенными.
Говард и Кодзима находятся в умеренном разделе спектра принятия ИИ. Другие руководители вроде основателя Valve Гейба Ньюэлла и главы Ubisoft Ива Гиймо занимают куда более оптимистичную позицию, не говоря уже о гигантах вроде EA, инвестирующих огромные суммы в полное внедрение технологии. В то же время, есть разработчики, выступающие категорически против использования ИИ-инструментов в создании игр.

Несмотря на триумф Clair Obscur: Expedition 33, особенно после недавних побед на The Golden Joystick Awards 2025, креативный директор Гийом Брош не считает, что это серьезно повлияет на работу студии Sandfall Interactive. В интервью GamesRadar Брош рассказал, что успех не должен менять команду как людей.
Директор отметил, что студия продолжит работать в привычном русле, создавая игры с "историями, которые трогают людей".
Я чувствую, что драматические изменения не обязательно означают, что мы должны измениться как люди. Мы хотим делать именно то, что планировали с самого начала. Просто создавать честные и искренние игры, писать истории, которые трогают людей и устанавливают с ними эмоциональную связь.
Что касается возможного расширения штата, который сейчас насчитывает чуть более 30 сотрудников, Брош заявил, что таких планов нет. По его словам, студия отлично работает небольшой командой, поэтому менять что-то не имеет смысла.
Мы не хотим сильно разрастаться как компания. Нам хорошо работается в нынешнем составе, небольшой командой, и мы хотим оставаться такими. Мы счастливы, зачем что-то менять?
При этом Брош добавил, что Sandfall Interactive возьмет опыт разработки Clair Obscur: Expedition 33 с собой в будущие тайтлы. Это касается и ошибок, которых студия постарается избежать в дальнейшем. Он также затронул тему эмоционального отклика игроков на игру и способности трогать аудиторию – именно это направление команда намерена развивать.
Но самое поразительное для нас, настоящая награда в наших сердцах – это эмоциональная реакция на персонажей, на историю, то, как люди полюбили героев и как игра помогла им пережить трудные моменты в жизни. Я думаю, искусство в целом существует именно для этого – чтобы вызывать эмоциональный отклик и трогать людей.Этим мы и хотим заниматься дальше.
Ранее Брош говорил, что студия не ожидала такого масштабного отклика на Clair Obscur: Expedition 33. Команда думала о том, что игра "будет крутой", а не о том, что она "станет большой".
Думаю, люди не понимают, что сейчас игра стала большой, но до запуска она не должна была стать такой. Мы все чувствовали одно и то же – что она будет крутой, а не большой. И то, что происходит сейчас...Как мы говорим, никто не понимает, что на самом деле происходит.
В честь выхода фильма «Чужой: Земля» на Hulu мы спросили зоолога, встречаются ли в природе какие-либо из печально известных характеристик Ксеноморфа.

Ксеноморфы , пожалуй, самые великие монстры из фильмов всех времен: пугающее скопление инвазивных паразитов, вооруженные челюсти и опасная кислотная кровь.
Когда режиссер Ридли Скотт объединился с художником Х. Р. Гигером для создания оригинального «Чужого», они с помощью биоинженерии создали существо, которое должно было вселять максимальный ужас, и Ксеноморф XX121 (таково его официальное обозначение от Weyland-Yutani ) с тех пор оказался на удивление живучим.
Итак, в преддверии выпуска этого так называемого «идеального организма» в совершенно новую среду обитания в долгожданном сериале « Чужой: Земля » мы решили разобраться в его ужасающей биологии. Мы обратились к зоологу Паоло Вискарди , хранителю отдела естественной истории Национального музея Ирландии, чтобы выяснить, могут ли какие-либо из печально известных характеристик этого существа быть правдоподобными в реальной жизни, не говоря уже о магической чёрной слизи «Прометея» , которая совершенно лишена логики.
Паразит потерян

Они могут быть высшими хищниками, способными выживать в самых агрессивных условиях, но ксеноморфам все равно необходимо использовать ничего не подозревающих хозяев — людей или кого-то еще — для продолжения рода.
Паоло Вискарди говорит: «Паразиты, как правило, не убивают своего хозяина. Они могут вызывать у него заболевания, но, в общем и целом, их функция — работать бок о бок с хозяином, чтобы получать всё необходимое, не вызывая у него стресса, способного привести к смерти. Такие существа, как Чужой [и некоторые виды ос], являются паразитоидами, потому что они фактически убивают своего хозяина. [Синтетический Энди на самом деле использует этот термин для описания лицехватов в фильме «Чужой: Ромул».]
Число паразитов огромно, и, честно говоря, это невероятные создания, которые творят всякие странные вещи. Один из моих любимых — языковая вошь, которая обычно проникает через жабры рыбы-хозяина (вроде красного люциана), съедает язык, а затем занимает его место. Она прикрепляется к кончику языка и питается тем, чем питается рыба, так что она буквально заменяет то, что уничтожила.
Круг жизни

Вы уже знакомы с невероятно сложным жизненным циклом Ксеноморфа ... Королева откладывает яйца, лицехваты вылупляются и оплодотворяют хозяина, из них появляются грудоломы (убивая хозяина в процессе) и быстро вырастают, превращаясь в дронов.
Паоло говорит: «Существуют гораздо более сложные жизненные циклы! Ланцетовидная двуустка — отличный пример. Когда муравей заражается на стадии личинки, ланцетовидная двуустка что-то переключает в мозге муравья, так что вместо того, чтобы возвращаться в своё гнездо ночью, он забирается на верхушку травинки и держится за неё жвалами. А утром он снова спускается вниз и продолжает выполнять свои обычные муравьиные обязанности».
«Причина этого в том, что коровы чаще пасутся в сумерках и ночью, а значит, не видят ничего странного в своей пище и поедают печеночных сосальщиков. Затем коровы выделяют цисты, которые поедают улитки, а их фекалии — муравьи. Всё это способствует непрерывному движению цепочки, и каждый из этих новых хозяев даёт печеночным сосальщикам ещё одну возможность для распространения».
Bigmouth снова наносит удар

Потому что, когда вы охотитесь на космических дальнобойщиков, колониальных морских пехотинцев, закоренелых преступников и даже наивных детей, дополнительная пара челюстей может оказаться очень полезным оружием.
Паоло говорит: «Существует довольно много видов, использующих челюсти с несколькими компонентами, позволяющими им выдвигаться гораздо дальше. Есть множество костистых рыб с сильно выдвижными челюстями, и они работают очень интересно, потому что, по сути, всасывают воду, быстро вытягивая рот. У нимф стрекоз нижняя часть мандибул как бы откидывается, выбрасывается вперёд, хватает что-то и возвращается обратно, очень похоже на Чужого!»
Хрустящие снаружи

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

Инопланетяне ловко обходят эту неловкую подростковую фазу, за считанные часы вырастая из Грудила размером с кошку в Дрона, который превосходит человека.
Паоло говорит: «Вы удивитесь, насколько быстро может расти что-то, сбрасывая старый экзоскелет, так что это вполне возможно. Новый экзоскелет часто складывается, образует складки и сминается внутри старого, занимая гораздо меньший объём. Затем, когда старый экзоскелет сбрасывается, новый, мягкий, наполняется гемолимфой [аналог крови у членистоногих] или чем-то ещё. Этот процесс может происходить довольно быстро».
«Внутри нового экзоскелета может быть довольно много пустого пространства, и это полезно, поскольку даёт больше места для роста до следующей фазы линьки. Но животное на этом этапе будет довольно слабым — если бы это произошло за очень короткий промежуток времени, рост мышц не смог бы поспеть за расширением экзоскелета».
«Ромул» также представил новую стадию развития Ксеноморфа, показав, что скачок роста Грудолома-Дрона происходит внутри очень неприятного кокона.
Паоло говорит: «Коконы — это то, что нужно для метаморфоза, который представляет собой практически полную ликвидацию всего тела для формирования новой формы, которая часто может полностью отличаться от старой. Стадия кокона имеет смысл, когда происходит значительное изменение морфологии, но этот процесс займёт некоторое время».
Тепловое зрение

Ксеноморф всегда показывал удивительную способность преследовать свою добычу без видимых глаз, и «Ромул» подтвердил, что лицехваты захватывают потенциальных хозяев с помощью мощной комбинации звуковых и тепловых сигнатур.
Паоло говорит: «Есть множество устройств, которые эффективно используют тепловидение, чтобы находить добычу или определять её местоположение. Комары могут эффективно обнаруживать инфракрасное излучение — это всё ещё форма зрения, но они используют инфракрасное излучение, чтобы обнаруживать теплокровных».
В вакуумной упаковке

Ксеноморфы уже доказали свою стойкость, выйдя из посредственности фильмов «Чужой против Хищника» без единой царапины. Затем «Ромул» доказал, что они также способны десятилетиями выживать в холодном вакууме космоса.
Паоло говорит: «Конечно, есть тихоходки , которые попали в вакуум и чувствуют себя прекрасно. Я бы сказал, что чем вы больше, тем сложнее это сделать, но это не невозможно — и если это произошло с одним животным, то, вероятно, это может произойти и с чем-то другим».
Думаю, это будет немного зависеть от того, являются ли ксеноморфы хладнокровными или теплокровными. [Это не совсем ясно из фильмов, хотя в «Чужих» они, похоже, «вообще не видны в инфракрасном диапазоне».] Если охладить окружающую среду, холоднокровный вид замедлится и остановится, но это не значит, что он не возобновит свою деятельность, как только нагреется. На самом деле, это может быть очень полезно, поскольку метаболические процессы протекают гораздо медленнее, и они фактически переходят в стазис. Теплокровным видам, как правило, необходимо поддерживать определённые метаболические процессы, чтобы выжить, поэтому в некотором смысле хладнокровность была бы гораздо более уместна для Чужого.
Ожог, детка, ожог

У вида XX121 есть ещё один, последний, но важный элемент защиты – адаптация настолько гениальная, что стрельба по ним из импульсных винтовок может быть крайне вредна для здоровья. Да, кровеносная система ксеноморфа заполнена смертоносным, чрезвычайно липким коктейлем из серной и плавиковой кислот.
Паоло говорит: «Вполне логично, что пищеварительные соки состоят из кислоты, это справедливо, но я не думаю, что это было бы особенно эффективно для транспортировки кислорода, а питательные вещества просто полностью растворились бы. Поэтому высокая кислотность крови Чужого немного странна, но есть примеры очень сильных кислот, например, желудочного сока, которые вырабатываются в природе».
В поисках совершенства

«Братья-андроиды» Эш и Рук выражают обескураживающее восхищение ксеноморфом, описывая существо как «совершенный организм». Гипербола?
Паоло говорит: «Я бы сказал, что всё — совершенный организм, думаю, так будет правильнее. Всё приспособилось к окружающей среде и выживает в ней наилучшим образом в любой момент времени — иначе бы его здесь не было. Это тот случай, когда что-то идеально подходит для определённого случая, и в этом, собственно, и заключается суть эволюции: всё идеально, и ничто не идеально».
Источник. Перевод от deepl

Все началось с рабочей задачи по реализации весьма специфичной web-панели мониторинга и управления различным оборудованием, в которой нужно было получать данные и отправлять команды по разнообразным сценариям (периодический опрос, подписка на websocket-события, https-запросы и т.д.), а также выводить состояние и графики в реальном времени, динамически комбинируя различные источники данных в разных виджетах.
Кроме того, у панели было предусмотрено несколько настраиваемых режимов работы, которые переключались по запросу пользователя, что требовало массового управления маршрутами потоков данных внутри системы.
В первой итерации с использованием RxJS получилось много неструктурированного и сложно поддерживаемого кода, так как архитектура на RxJS вынуждала императивно описывать перестроение топологии при изменении правил маршрутизации «на лету». В нашем специфичном кейсе с динамическими виджетами это приводило к сайд-эффектам и сложностям в отладке. Кроме того, местами размывалась строгая типизация и мы лишались compile-time гарантий. Так появилась идея разработать собственное решение на основе альтернативной концепции — модели графа потоков данных.
В результате получившаяся модель продемонстрировала предсказуемое поведение и низкую связность компонентов, а кодовая база сократилась на ~30% и приобрела более декларативный вид. Убедившись в эффективности решения, мы решили оформить его в виде отдельной библиотеки с открытым исходным кодом — Transferum.
Не совсем. Классические FRP-библиотеки (RxJS, Bacon, Most) построены вокруг единственного примитива (Observable). Transferum же основан на композиции различных типов узлов с явно определенным поведением.
Каждый узел в графе потоков распространения данных явно декларирует свои способности: может ли он принимать данные через push, отдавать через pull, распространять полученный сигнал подписчикам, опрашивать источник, фильтровать, блокировать поток и т.д.
Объявленные узлом возможности являются одновременно флагами для использования в runtime и compile-time гарантиями наличия соответствующих методов, определяющих его поведение.
Ключевая идея: поведение системы описывается как композиция независимых возможностей, которые одновременно определяют тип, реализацию и правила взаимодействия.
Концептуальная и архитектурная основа — capability flags system. Каждый трансфер реализует CommunicationContractInterface — набор булевых флагов, определяющих его возможности.
Флаги isPushable, isPullable, isSubscribable, isGate и другие — это не просто свойства объекта. Это метаданные, которые:
Один набор флагов — три потребителя. Это единый источник истины для всей системы.
Когда флаг равен true, соответствующий метод входит в TypeScript-интерфейс трансфера. Это позволяет предоставлять трансфер пользователю вот так:
Transfer
// гомогенный трансфер: T -> [ Transfer ] -> TИли вот так:
Transfer
// гетерогенный трансфер: TInput -> [ Transfer ] -> TOutputИменно в таком формате типов фабрики в библиотеке возвращают трансферы. Например:
const pushChannel: Transfer;
const converter: Transfer;
// содержат методы push(), subscribe()
const manualBuffer: Transfer;
// содержит методы push(), pull(), trigger()
// trigger() в данном случае нужен, чтобы сделать запушенное значение
// доступным для чтения через pull()
const pollingProxy: Transfer
// содержит методы pull(), subscribe(), trigger(), activate(), deactivate(), toggle()
// может быть связан с pullable-источником благодаря поддержке поллингаЭта «магия» работает в compile-time благодаря несколько замысловатой системе вычислимых типов:
type FeatureMap =
F extends { readonly isPushable: true } ? Pushable & { readonly isInput: true } :
F extends { readonly isPollingProxy: true } ? PollingProxy & { readonly isInput: true, readonly isOutput: true } :
F extends { readonly isPullable: true } ? Pullable & { readonly isOutput: true } :
F extends { readonly isSubscribable: true } ? Subscribable & { readonly isOutput: true } :
F extends { readonly isTriggerable: true } ? Triggerable :
F extends { readonly isGate: true } ? Gate :
F extends { readonly isAsyncPushable: true } ? AsyncPushable & { readonly isInput: true } :
F extends { readonly isAsyncPollingProxy: true } ? AsyncPollingProxy & { readonly isInput: true, readonly isOutput: true } :
F extends { readonly isAsyncPullable: true } ? AsyncPullable & { readonly isOutput: true } :
F extends { readonly isAsyncTriggerable: true } ? AsyncTriggerable :
unknown;
type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type ResolveFeatures = UnionToIntersection;
type IsDuplexFeatures =
ResolveFeatures extends { readonly isInput: true, readonly isOutput: true }
? { readonly isDuplex: true }
: unknown;
type ExplicitTransfer = BaseTransferInterface
& ResolveFeatures
& IsDuplexFeatures;
export type Transfer<
TInOrAll,
TOutOrFeatures extends any[] | any,
TFeaturesOrUndefined extends any[] | undefined = undefined,
> = TFeaturesOrUndefined extends any[]
? ExplicitTransfer
: TOutOrFeatures extends any[]
? ExplicitTransfer
: never;Трансфер определяет своё поведение (push, pull, subscribe и др.), но никогда не ссылается и не проверяет класс другого трансфера. Он не знает, что является upstream или downstream — лишь выполняет свой контракт. Пользователь может создать свой трансфер, объявить и реализовать его возможности — и он органично и бесшовно впишется в экосистему.
Мост инспектирует capability flags, а не имена классов. Нет цепочки instanceof, нет переключения по имени класса. Любой output-трансфер может быть соединен с любым input-трансфером — при условии совместимости их флагов, о чем мы поговорим чуть ниже. Это применимо и к тем узлам, которые еще не существуют и будут созданы пользователем.
В Transferum undefined означает «нет данных», а не «пустое значение». Оно подавляется на уровне внутренней реализации менеджера подписок — подписчики никогда не уведомляются с undefined. При этом для явных маркеров пустых значений можно использовать null. Мы сознательно пошли на этот компромисс, чтобы избежать runtime-оверхеда и сохранить нативную скорость работы на плотных потоках данных.
Функция linkTransfers(lhs, rhs) соединяет output-трансфер (lhs) с input-трансфером (rhs) с автоматическим выбором стратегии связывания на основе возможностей этих трансферов:
Protocol-oriented design: механизм не спрашивает «какой это класс?» — он выясняет, какие у него есть возможности. Любая пара трансферов с совместимыми возможностями является linkable. Добавление нового класса трансфера требует только объявления его флагов и реализации соответствующих методов — как связать его с другим трансфером, связующий алгоритм разберется сам.
import { createPushChannelTransfer, createSinkTransfer, linkTransfers } from 'transferum';
const source = createPushChannelTransfer();
const target = createSinkTransfer({ callback: (x) => console.log(x) });
const link = linkTransfers(source, target);
source.push(22);
link.unsubscribe(); // разорвать связьСинхронные и асинхронные трансферы сосуществуют и могут быть связаны между собой. linkTransfers() предпочитает sync-связывание, когда это возможно, а async-стратегии применяет только когда sync неприменим. Нет отдельного «асинхронного мира».
Ряд асинхронных трансферов (AsyncSinkTransfer, AsyncWriteTransfer, AsyncConvertTransfer, AsyncConditionTransfer) поддерживают необязательные поля в конфигурации: maxConcurrency, bufferSize и onBufferOverflow — для ограничения параллельных async-операций, очереди избыточных данных и graceful-обработки переполнения. По умолчанию — неограниченная обработка, без буферизации.
Transferum использует единую модель обработки ошибок для всех трансферов. Каждый трансфер, который может столкнуться с runtime-ошибкой, принимает опциональный onError-хэндлер в своей конфигурации.
Вот так можно просто и декларативно описать опрос и агрегирование данных из нескольких источников:
import {
createMergeTransfer,
createConditionTransfer,
createThrottleTransfer,
createAsyncSinkTransfer,
createAsyncPollingSourceTransfer,
CompositeTransferBuilder,
} from 'transferum';
const sensor1 = createAsyncPollingSourceTransfer({
fetcher: () => Promise.resolve({ sensorId: 1, temperature: 25, humidity: 50 }),
interval: 50,
activated: true,
});
const sensor2 = createAsyncPollingSourceTransfer({
fetcher: () => Promise.resolve({ sensorId: 2, temperature: 26, humidity: 55 }),
interval: 50,
activated: true,
});
const sensorsAggregator = createMergeTransfer({
sources: [sensor1, sensor2],
});
const alertPipeline = CompositeTransferBuilder
.start(sensorsAggregator)
.to(createConditionTransfer({
shouldAccept: (d) => d.temperature > 95,
}))
.to(createThrottleTransfer({ interval: 5000 }))
.finish(createAsyncSinkTransfer({
callback: (sensorData) => {
console.warn(Alert! Sensor ${sensorData.sensorId}: temperature is ${sensorData.temperature});
}
}));
sensorsAggregator.subscribe((sensorData) => console.log('Debugging', sensorData));А вот как можно организовать динамический роутинг:
import {
createPushStoredChannelTransfer,
createBridgeMultiSelector,
createBridgeSelector,
createPassBridge,
} from 'transferum';
// Вариант 1. Выбор одного реципиента
const commandRouter = createBridgeSelector({
bridges: {
light: createPassBridge({ source: commandChannel, target: lightController, activated: false }),
thermostat: createPassBridge({ source: commandChannel, target: thermostatController, activated: false }),
lock: createPassBridge({ source: commandChannel, target: lockController, activated: false }),
},
initialKey: 'thermostat', // выбор по умолчанию
activated: true,
owned: true,
});
commandRouter.select('lock'); // выберем другой вариант
// Вариант 2. Выбор нескольких реципиентов
const loggersRouter = createBridgeMultiSelector({
bridges: {
prometheus: createPassBridge({ source: metricsChannel, target: prometheusWriter, activated: false }),
elk: createPassBridge({ source: metricsChannel, target: elkWriter, activated: false }),
sentry: createPassBridge({ source: metricsChannel, target: sentryWriter, activated: false }),
},
initialKeys: ['prometheus', 'elk'], // будут активированы по умолчанию
activated: true,
owned: true,
});
loggersRouter.check('elk'); // теперь выбраны все три
loggersRouter.uncheck('prometheus'); // выбраны elk, sentry
loggersRouter.select(['prometheus', 'sentry']); // выбраны prometheus, sentryА вот пример c организацией игровой механики:
import {
createDebounceTransfer,
createConvertTransfer,
createMapOperator,
createBridgeSelector,
createPassBridge,
linkTransfers,
} from 'transferum';
// Источник: debounce нажатий клавиш (16ms ~ 1 кадр при 60 FPS)
const rawInputSource = createDebounceTransfer({ delay: 16 });
// Конвертер: KeyboardEvent -> код клавиши
const inputConverter = createConvertTransfer({
operator: createMapOperator((event) => event.code),
});
// Целевые системы-потребители пользовательских событий
const carSystem = { push: (cmd: string) => console.log(🚗 Car executing: ${cmd}) };
const planeSystem = { push: (cmd: string) => console.log(✈️ Plane executing: ${cmd}) };
const menuSystem = { push: (cmd: string) => console.log(📋 Menu processing: ${cmd}) };
// Роутер: динамическое переключение между игровыми контекстами
const gameplayRouter = createBridgeSelector({
bridges: {
driving: createPassBridge({ source: inputConverter, target: carSystem }),
flying: createPassBridge({ source: inputConverter, target: planeSystem }),
ui: createPassBridge({ source: inputConverter, target: menuSystem }),
},
initialKey: 'driving', // игрок начинает в машине
activated: true,
});
// Связывание источника с конвертером с автовыбором стратегии
linkTransfers(rawInputSource, inputConverter);
// Демонстрация:
// Игрок в машине нажимает "W"
rawInputSource.push(new KeyboardEvent('keydown', { code: 'KeyW' }));
// Через 16ms: 🚗 Car: KeyW
// ==================
// Переключаемся на самолёт
gameplayRouter.select('flying');
// Та же клавиша теперь управляет самолётом
rawInputSource.push(new KeyboardEvent('keydown', { code: 'KeyW' }));
// Через 16ms: ✈️ Plane: KeyWБиблиотека подойдет для:
Буду рад, если вы заглянете в репозиторий, попробуете библиотеку в деле и поделитесь замечаниями — обратная связь поможет сделать Transferum лучше.
P. S. Если вы сталкивались с похожими задачами и решили их как-то иначе — буду рад прочитать о вашем опыте в комментариях.
Комментарии