#инструмент дня
Мозаики (паттерны) это всегда прекрасно. Но соблюсти симметрию, чтобы заполнить поле, может быть не совсем тривиально.
Симметрия, отражение и поворот станут вашими лучшими друзьями. Хотелось бы какой-нибудь простой инструмент для их настройки.
И такой есть!
https://patternico.com/
Можно заполнить встроенными иконками (Font Awesome или Line), а можно загрузить свои. Есть даже ссылка на вариант конструктора с эмодзи :) Правда, там убогонькие Emojione, но вдруг кому ок.
В общем, имеет право на жизнь. Только на мобиле работает не очень :(
#pattern #background #generator #бородач
Мозаики (паттерны) это всегда прекрасно. Но соблюсти симметрию, чтобы заполнить поле, может быть не совсем тривиально.
Симметрия, отражение и поворот станут вашими лучшими друзьями. Хотелось бы какой-нибудь простой инструмент для их настройки.
И такой есть!
https://patternico.com/
Можно заполнить встроенными иконками (Font Awesome или Line), а можно загрузить свои. Есть даже ссылка на вариант конструктора с эмодзи :) Правда, там убогонькие Emojione, но вдруг кому ок.
В общем, имеет право на жизнь. Только на мобиле работает не очень :(
#pattern #background #generator #бородач
❤9👍4
#заметка дня
Рубрика "Вы не спрашивали, но я всё равно отвечу!"
На самом деле, разговор произошёл в Твиттере, и я посчитал разумным, вынести его сюда.
Итак, вопрос:
Что бы убедиться: использование testid в end-2-end тестах для выборки элементов это анти-паттерн, верно? Следует тестировать с точки зрения пользователя: искать кнопку с неким текстом, например.
Знаете ли вы статьи или доклады, которые подкрепляют эту точку зрения?
Отвечаю:
Это не то чтобы антипаттерн, это просто бестолковое использование ресурсов, потому и продвигается как антипаттерн.
1. Надо тестировать то, что видит юзер
2. Если что-то не видит, значит, всё плохо
3. Если там иконка или нужен результат — искать надо по a11y атрибутам.
Сразу поясню за "бестолковость".
Когда ты что-то тестируешь, тесты становятся твоей документацией. Значит, в тестах закрепляется текущее поведение проекта. Даже строки не стоит импортировать (если ты только не тестируешь систему перевода).
А это значит, если кто-то случайно сломает систему перевода или неправильно переведёт строку без информирования остальных — тесты упадут и это правильно.
Дальше, решая проблему через ARIA-атрибуты, ты заодно решаешь вопрос доступности. Бесплатно. Поэтому data-testid и названы бестолковым использованием ресурсов.
Это же, кстати, касается систем трекинга вроде Datadog RUM.
Смысл фронтенда в том, чтобы пользователь мог с продуктом взаимодействовать. Для этого необходима визуальная и когнитивная поддержка. Кнопка может быть и видна, но на кнопке — упс — может не быть текста. Или она будет цвета фона (потому скриншот-тесты ещё не вымерли).
Подобный подход к тестировани применяется как в E2E, так и в юнит- и интеграционном тестировании. Вот, например, поясняющая статья от Testing Library, которая нынче стандарт де-факто для тестирования в вебе.
Тестируйте, котаны!
#web #testing #e2e #бородач
Рубрика "Вы не спрашивали, но я всё равно отвечу!"
На самом деле, разговор произошёл в Твиттере, и я посчитал разумным, вынести его сюда.
Итак, вопрос:
Что бы убедиться: использование testid в end-2-end тестах для выборки элементов это анти-паттерн, верно? Следует тестировать с точки зрения пользователя: искать кнопку с неким текстом, например.
Знаете ли вы статьи или доклады, которые подкрепляют эту точку зрения?
Отвечаю:
Это не то чтобы антипаттерн, это просто бестолковое использование ресурсов, потому и продвигается как антипаттерн.
1. Надо тестировать то, что видит юзер
2. Если что-то не видит, значит, всё плохо
3. Если там иконка или нужен результат — искать надо по a11y атрибутам.
Сразу поясню за "бестолковость".
Когда ты что-то тестируешь, тесты становятся твоей документацией. Значит, в тестах закрепляется текущее поведение проекта. Даже строки не стоит импортировать (если ты только не тестируешь систему перевода).
А это значит, если кто-то случайно сломает систему перевода или неправильно переведёт строку без информирования остальных — тесты упадут и это правильно.
Дальше, решая проблему через ARIA-атрибуты, ты заодно решаешь вопрос доступности. Бесплатно. Поэтому data-testid и названы бестолковым использованием ресурсов.
Это же, кстати, касается систем трекинга вроде Datadog RUM.
Смысл фронтенда в том, чтобы пользователь мог с продуктом взаимодействовать. Для этого необходима визуальная и когнитивная поддержка. Кнопка может быть и видна, но на кнопке — упс — может не быть текста. Или она будет цвета фона (потому скриншот-тесты ещё не вымерли).
Подобный подход к тестировани применяется как в E2E, так и в юнит- и интеграционном тестировании. Вот, например, поясняющая статья от Testing Library, которая нынче стандарт де-факто для тестирования в вебе.
Тестируйте, котаны!
#web #testing #e2e #бородач
Testing-Library
React Testing Library | Testing Library
React Testing Library builds on top of DOM Testing Library by adding
3👍8❤5
#статья дня
JSON.stringify в V8 теперь в два раза быстрее!
Пруф: https://v8.dev/blog/json-stringify
Ну и мы все с вами так любим применять
А еще клонирование! JSON.stringify => JSON.parse и вуаля!
Кто сказал
В V8 провели серьёзную работу и сделали функцию более чем в два раза быстрее!
Основные улучшения такие:
Срезание углов
Обычно при сериализации движок обязан быть очень осторожным: вдруг у объекта есть геттеры, собственный метод
Все эти проверки занимают время.
Теперь V8 научился определять случаи, когда объект «чистый», то есть просто содержит данные и не может неожиданно запустить код. В таких ситуациях сериализация идёт по короткому маршруту — без лишних проверок, что даёт значительный прирост скорости.
Убираем рекурсию
Прежняя реализация работала рекурсивно, из-за чего сериализация глубоко вложенных структур была и медленнее, и потенциально опасна переполнением стека. Теперь используется итеративный алгоритм: он быстрее и надёжнее, вне зависимости от глубины объекта.
Для разработчиков это значит, что операции с данными становятся заметно быстрее.
А как же structuredClone?
Конечно, для клонирования объектов нас есть современный инструмент —
Для обмена данными снаружи всё равно будет нужен
Теперь же, благодаря оптимизациям,
Вообще, там в статье еще много чего! Очень рекомендую.
#v8 #json #stringify #structuredClone
JSON.stringify в V8 теперь в два раза быстрее!
Пруф: https://v8.dev/blog/json-stringify
JSON.stringify
— одна из самых используемых функций в стандартной библиотеке JavaScript. Её используют для превращения объектов в JSON-строку. Надо ли объяснять, зачем? :)Ну и мы все с вами так любим применять
JSON.stringify
для сравнения объектов... ведь достаточно сериализовать оба и сравнить строки. До недавнего времени способа лучше просто не существовало.А еще клонирование! JSON.stringify => JSON.parse и вуаля!
Кто сказал
structuredClone
?В V8 провели серьёзную работу и сделали функцию более чем в два раза быстрее!
Основные улучшения такие:
Срезание углов
Обычно при сериализации движок обязан быть очень осторожным: вдруг у объекта есть геттеры, собственный метод
toJSON
, прокси или ещё какой-то механизм, который может вмешаться в процесс.Все эти проверки занимают время.
Теперь V8 научился определять случаи, когда объект «чистый», то есть просто содержит данные и не может неожиданно запустить код. В таких ситуациях сериализация идёт по короткому маршруту — без лишних проверок, что даёт значительный прирост скорости.
Убираем рекурсию
Прежняя реализация работала рекурсивно, из-за чего сериализация глубоко вложенных структур была и медленнее, и потенциально опасна переполнением стека. Теперь используется итеративный алгоритм: он быстрее и надёжнее, вне зависимости от глубины объекта.
Для разработчиков это значит, что операции с данными становятся заметно быстрее.
А как же structuredClone?
Конечно, для клонирования объектов нас есть современный инструмент —
structuredClone
. Его главное отличие в том, что он не превращает данные в строку, а создаёт точную копию структуры. Он умеет работать с типами, которые JSON.stringify
просто «теряет»: Map
, Set
, Date
, RegExp
, бинарные буферы и даже циклические ссылки.Для обмена данными снаружи всё равно будет нужен
JSON.stringify
, для внутренних операций удобнее и надёжнее использовать structuredClone
.Теперь же, благодаря оптимизациям,
JSON.stringify
остаётся такой же универсальной «рабочей лошадкой», но работает заметно быстрее.Вообще, там в статье еще много чего! Очень рекомендую.
#v8 #json #stringify #structuredClone
❤18👍3
#инструмент дня
Volta? nvm? asdf? fnm? n?
Вы же поняли? Да, это всё менеджеры версий node.js.
Ладно-ладно, asdf чуть шире штука.
И хорошо, если нестабильные версии ноды ставишь только ради проверки фишек...
Так вот, к чему это я?
А к тому, что наш любимый pnpm с версии 10.14 тоже стал таким менеджером!
Подробнее: https://pnpm.io/blog/releases/10.14
Поддерживаются Node.js, Deno, и Bun.
За что мы так любим pnpm? За воркспейсы в том числе. Так вот, теперь в разных воркспейсах могут быть и разные версии ноды!
Круто? Не то слово :)
#pnpm #nvm #volta #node #bun
Volta? nvm? asdf? fnm? n?
Вы же поняли? Да, это всё менеджеры версий node.js.
Ладно-ладно, asdf чуть шире штука.
И хорошо, если нестабильные версии ноды ставишь только ради проверки фишек...
Так вот, к чему это я?
А к тому, что наш любимый pnpm с версии 10.14 тоже стал таким менеджером!
Подробнее: https://pnpm.io/blog/releases/10.14
{
"devEngines": {
"runtime": {
"name": "node",
"version": "^24.4.0",
"onFail": "download" // we only support the "download" value for now
}
}
}
Поддерживаются Node.js, Deno, и Bun.
За что мы так любим pnpm? За воркспейсы в том числе. Так вот, теперь в разных воркспейсах могут быть и разные версии ноды!
Круто? Не то слово :)
#pnpm #nvm #volta #node #bun
1👍15❤4
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня
Как решить главную проблему бесконечной бегущей строки?
При создании бегущей строки (marquee, да) в CSS всегда встаёт вопрос: в какой момент элементу нужно «перепрыгнуть» в начало, чтобы анимация выглядела непрерывной? Если рассчитать неправильно — появляются рывки или пустые промежутки.
Как правило, это решается или через JavaScript, или дублированием элементов до какого-то неразумного предела. Или и так и так.
В статье на Frontend Masters уже так хорошо знакомым нам Темани Афифом (он автор CSS Shape) предложен современный способ, где эта проблема решается автоматически.
Используются новые функции sibling-index() и sibling-count(). Они позволяют CSS «понимать», какой по счёту элемент в наборе и сколько всего элементов.
На основе этих данных каждому элементу назначается своя задержка старта анимации. Это делается через формулу: задержка = индекс * (общая_длительность / количество_элементов).
Путь движения задаётся через offset: shape(...), а сама анимация повторяется бесконечно (infinite linear).
В результате элементы выстраиваются один за другим и «зацикливаются» без единого рывка — всё считается динамически, без ручных правок.
И самое приятное: HTML остаётся простым <div> с изображениями, а вся магия — в десятке строк CSS!
Почитайте, очень круто вышло.
#css #marquee
Как решить главную проблему бесконечной бегущей строки?
При создании бегущей строки (marquee, да) в CSS всегда встаёт вопрос: в какой момент элементу нужно «перепрыгнуть» в начало, чтобы анимация выглядела непрерывной? Если рассчитать неправильно — появляются рывки или пустые промежутки.
Как правило, это решается или через JavaScript, или дублированием элементов до какого-то неразумного предела. Или и так и так.
В статье на Frontend Masters уже так хорошо знакомым нам Темани Афифом (он автор CSS Shape) предложен современный способ, где эта проблема решается автоматически.
Используются новые функции sibling-index() и sibling-count(). Они позволяют CSS «понимать», какой по счёту элемент в наборе и сколько всего элементов.
На основе этих данных каждому элементу назначается своя задержка старта анимации. Это делается через формулу: задержка = индекс * (общая_длительность / количество_элементов).
Путь движения задаётся через offset: shape(...), а сама анимация повторяется бесконечно (infinite linear).
В результате элементы выстраиваются один за другим и «зацикливаются» без единого рывка — всё считается динамически, без ручных правок.
И самое приятное: HTML остаётся простым <div> с изображениями, а вся магия — в десятке строк CSS!
Почитайте, очень круто вышло.
#css #marquee
1👍19❤5
This media is not supported in your browser
VIEW IN TELEGRAM
#инструмент дня
React Compiler, говорите...
А что если я скажу вам, что есть инструмент, конвертирующий ваши JSX-компоненты во... во все остальные?
Буквально: JSX/Svelte в: React, Svelte, Vue, Angular, Qwik, Lit, Solid, Preact...
Давайте просто сразу дам ссылку на песочницу: https://mitosis.builder.io/playground/
Если уж и не для практического применения, но если вдруг надо срочно пересесть на другой фреймворк — то понять принципы можно с лёгкостью.
Знаешь JSX или Svelte — пишешь на всех :)
#framework #tool #бородач
React Compiler, говорите...
А что если я скажу вам, что есть инструмент, конвертирующий ваши JSX-компоненты во... во все остальные?
Буквально: JSX/Svelte в: React, Svelte, Vue, Angular, Qwik, Lit, Solid, Preact...
Давайте просто сразу дам ссылку на песочницу: https://mitosis.builder.io/playground/
Если уж и не для практического применения, но если вдруг надо срочно пересесть на другой фреймворк — то понять принципы можно с лёгкостью.
Знаешь JSX или Svelte — пишешь на всех :)
#framework #tool #бородач
👍10❤1🤩1🤡1
#статья дня
Можно ли заменить стейт-менеджеры — простым localStorage?
Вопрос не настолько абсурдный, как может показаться, хотя понятное дело, что многие из вас уже знают ответ.
Давайте подумаем:
> Не всё должно быть постоянным. Допустим, у тебя открыто модальное окно. Перезагрузил страницу — и оно снова открыто, потому что значение сохранилось в localStorage. Абсурдный UX.
> Нет реактивности. Если просто читать из localStorage, React не узнает, что данные изменились, и не перерендерит компонент. Придётся вручную дёргать setState.
> Событие storage работает не так. Оно срабатывает только в других вкладках, а не в той, где ты вызвал localStorage.setItem(). То есть синхронизацию внутри приложения оно не решает.
> Ограничения. Только строки, лимит около 5 МБ, возможные ошибки при парсинге JSON, коллизии ключей. Всё это требует дополнительных костылей.
> SSR недоступен. На сервере localStorage просто не существует, и код падает с ошибкой.
localStorage и, частично, sessionStorage отлично подходят для мелочей:
> выбор темы,
> сохранение введённых данных формы,
> открытая вкладка меню,
Но как только речь заходит о данных, которые должны синхронно обновляться в разных компонентах и вызывать ререндер — нужен Context или полноценный state-менеджер.
Итак: localStorage — это удобное дополнение к Context/Redux/Zustand, но не замена. Он решает задачу «сохранить между сессиями», а не «синхронизировать состояние внутри React».
А если хотите подробностей — собственно, статья от Нади Макаревич: https://www.developerway.com/posts/local-storage-instead-of-context
Не думаю, что олды что-то найдут новое (разве что лишний раз поржать над событием storage), но у новичков вопросы такого плана возникают постоянно.
#react #localstorage
Можно ли заменить стейт-менеджеры — простым localStorage?
Вопрос не настолько абсурдный, как может показаться, хотя понятное дело, что многие из вас уже знают ответ.
Давайте подумаем:
> Не всё должно быть постоянным. Допустим, у тебя открыто модальное окно. Перезагрузил страницу — и оно снова открыто, потому что значение сохранилось в localStorage. Абсурдный UX.
> Нет реактивности. Если просто читать из localStorage, React не узнает, что данные изменились, и не перерендерит компонент. Придётся вручную дёргать setState.
> Событие storage работает не так. Оно срабатывает только в других вкладках, а не в той, где ты вызвал localStorage.setItem(). То есть синхронизацию внутри приложения оно не решает.
> Ограничения. Только строки, лимит около 5 МБ, возможные ошибки при парсинге JSON, коллизии ключей. Всё это требует дополнительных костылей.
> SSR недоступен. На сервере localStorage просто не существует, и код падает с ошибкой.
localStorage и, частично, sessionStorage отлично подходят для мелочей:
> выбор темы,
> сохранение введённых данных формы,
> открытая вкладка меню,
Но как только речь заходит о данных, которые должны синхронно обновляться в разных компонентах и вызывать ререндер — нужен Context или полноценный state-менеджер.
Итак: localStorage — это удобное дополнение к Context/Redux/Zustand, но не замена. Он решает задачу «сохранить между сессиями», а не «синхронизировать состояние внутри React».
А если хотите подробностей — собственно, статья от Нади Макаревич: https://www.developerway.com/posts/local-storage-instead-of-context
Не думаю, что олды что-то найдут новое (разве что лишний раз поржать над событием storage), но у новичков вопросы такого плана возникают постоянно.
#react #localstorage
❤10🫡1
This media is not supported in your browser
VIEW IN TELEGRAM
#фишка дня
И #тред дня, и #статья дня... Сегодня всё и сразу от Джоша Комо.
И речь пойдёт о недооценённом хуке в React: useDeferredValue.
Итак, некоторое время назад Джош выпустил свой инструмент для создания красиво выглядящих теней (да-да, drop-shadow просто уже недостаточно). И одной из проблем инструмента стала... дёрганая реакция на движение ползунков. Как будто мало FPS.
Начав разбирать проблему, Джош понял, что событие onChange происходит очень часто, за это время надо успеть сгенерировать тень, потом отрисовать её, потом вставить код в редактор для копирования. А редактор, естественно, ещё пытается этот самый код подсветить.
Но что нам нужно? Нам ведь сначала нужен результат, а уже потом — код. Так почему бы не заполнить код чуть позже, не нагружая систему?
И именно для этого и нужен хук useDeferredValue. Данные молучим только когда основной процесс рендеринга завершится. Буквально ленивое выполнение.
Собственно, тред и статья если кто предпочитает подробности. Там, как всегда, шикарно.
Будьте разумно ленивыми, котаны!
#react #hook #бородач
И #тред дня, и #статья дня... Сегодня всё и сразу от Джоша Комо.
И речь пойдёт о недооценённом хуке в React: useDeferredValue.
Итак, некоторое время назад Джош выпустил свой инструмент для создания красиво выглядящих теней (да-да, drop-shadow просто уже недостаточно). И одной из проблем инструмента стала... дёрганая реакция на движение ползунков. Как будто мало FPS.
Начав разбирать проблему, Джош понял, что событие onChange происходит очень часто, за это время надо успеть сгенерировать тень, потом отрисовать её, потом вставить код в редактор для копирования. А редактор, естественно, ещё пытается этот самый код подсветить.
Но что нам нужно? Нам ведь сначала нужен результат, а уже потом — код. Так почему бы не заполнить код чуть позже, не нагружая систему?
И именно для этого и нужен хук useDeferredValue. Данные молучим только когда основной процесс рендеринга завершится. Буквально ленивое выполнение.
Собственно, тред и статья если кто предпочитает подробности. Там, как всегда, шикарно.
Будьте разумно ленивыми, котаны!
#react #hook #бородач
❤21
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня
Вот мало было нам хороших статей по SVG, нужно больше!
Джош Комо продолжает свою серию про SVG. Начав со статьи про базовые принципы, пришло время объяснить, как работает механизм формирования кривых, контуров, aka path: https://www.joshwcomeau.com/svg/interactive-guide-to-paths/
Вы можете заметить, что у нас так-то уже огромное количество интерактивных обучающих ресурсов, начиная от чего-то похожего на ЛогоМиры, до более сложных инструментов.
Но Джош это Джош! Как всегда потрясающая любовь к деталям, интерактивные примеры и понятные объяснения по ходу.
Фишка его подхода в этот раз — пошаговый разбор алгоритма отрисовки кривых. Проигрывает его по кадрам, как будто вы очень медленный компьютер :)
Залипательно!
P. S. розыгрыш билета на конференцию от подлодки открыт до утра, если что.
#svg #path #tool
Вот мало было нам хороших статей по SVG, нужно больше!
Джош Комо продолжает свою серию про SVG. Начав со статьи про базовые принципы, пришло время объяснить, как работает механизм формирования кривых, контуров, aka path: https://www.joshwcomeau.com/svg/interactive-guide-to-paths/
Вы можете заметить, что у нас так-то уже огромное количество интерактивных обучающих ресурсов, начиная от чего-то похожего на ЛогоМиры, до более сложных инструментов.
Но Джош это Джош! Как всегда потрясающая любовь к деталям, интерактивные примеры и понятные объяснения по ходу.
Фишка его подхода в этот раз — пошаговый разбор алгоритма отрисовки кривых. Проигрывает его по кадрам, как будто вы очень медленный компьютер :)
Залипательно!
P. S. розыгрыш билета на конференцию от подлодки открыт до утра, если что.
#svg #path #tool
❤13👍3
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня
Ну чо, котаны, есть занятная история с GitHub.
Исследователь Шерон Бризинов решил проверить, что вообще происходит с коммитами, которые мы с вами удаляем через git reset и force push: https://trufflesecurity.com/blog/guest-post-how-i-scanned-all-of-github-s-oops-commits-for-leaked-secrets
Спойлер — никуда они не исчезают.
GitHub продолжает хранить все те ваши коммиты с ключами и секретами бесплатных и не очень API, даже если нам кажется, что мы всё подчистили.
Собственно, идея исследования простая: если коммиты не пропадают, значит, в них вполне могут оставаться секреты — ключи, токены и прочие радости.
Шерон пошёл и просканировал архив GitHub за несколько лет. Нашёл он там немало интересного, включая утечки, которые потом оценили на баг-баунти в 25 тысяч долларов.
Чтобы процесс не был ручным, он вместе с Truffle Security сделал инструмент Force Push Scanner.
Этот сканер вытаскивает пуши, достаёт зависшие коммиты и прогоняет их через TruffleHog, чтобы поймать секреты. Получился вполне практичный open source, которым можно пользоваться прямо сейчас.
Вывод в итоге грустный, но очевидный: удалить коммит — не значит избавиться от проблемы. GitHub всё хранит, и если секрет уже засветился, его надо менять, а не надеяться на «забывчивость» платформы.
Лучше, конечно, не допускать таких ошибок вовсе, но если уж случилось — придётся действовать радикально.
P. S. у этой статьи есть не менее занятная предыстория, которая дополняет общую картину: https://medium.com/@sharon.brizinov/how-i-made-64k-from-deleted-files-a-bug-bounty-story-c5bd3a6f5f9b
#github
Ну чо, котаны, есть занятная история с GitHub.
Исследователь Шерон Бризинов решил проверить, что вообще происходит с коммитами, которые мы с вами удаляем через git reset и force push: https://trufflesecurity.com/blog/guest-post-how-i-scanned-all-of-github-s-oops-commits-for-leaked-secrets
Спойлер — никуда они не исчезают.
GitHub продолжает хранить все те ваши коммиты с ключами и секретами бесплатных и не очень API, даже если нам кажется, что мы всё подчистили.
Собственно, идея исследования простая: если коммиты не пропадают, значит, в них вполне могут оставаться секреты — ключи, токены и прочие радости.
Шерон пошёл и просканировал архив GitHub за несколько лет. Нашёл он там немало интересного, включая утечки, которые потом оценили на баг-баунти в 25 тысяч долларов.
Чтобы процесс не был ручным, он вместе с Truffle Security сделал инструмент Force Push Scanner.
Этот сканер вытаскивает пуши, достаёт зависшие коммиты и прогоняет их через TruffleHog, чтобы поймать секреты. Получился вполне практичный open source, которым можно пользоваться прямо сейчас.
Вывод в итоге грустный, но очевидный: удалить коммит — не значит избавиться от проблемы. GitHub всё хранит, и если секрет уже засветился, его надо менять, а не надеяться на «забывчивость» платформы.
Лучше, конечно, не допускать таких ошибок вовсе, но если уж случилось — придётся действовать радикально.
P. S. у этой статьи есть не менее занятная предыстория, которая дополняет общую картину: https://medium.com/@sharon.brizinov/how-i-made-64k-from-deleted-files-a-bug-bounty-story-c5bd3a6f5f9b
#github
1👍23🤩1
#фишка дня
Иногда встаёт задача не просто проиллюстрировать статью, но обрезать (кропнуть) исходное изображение. И желательно так, чтобы результат был адаптивен и адекватно реагировал на масштабирование.
Джейк Арчибальд предлагает решение на SVG и foreignObject: https://codepen.io/alinaki/pen/KKLXvwz
Вообще, весьма красиво. Да, можно генерировать кропы на сервере, но это, как минимум, лишние телодвижения. А тут – одна картинка, чистый и понятный код.
#svg #img #foreignObject #crop #бородач
Иногда встаёт задача не просто проиллюстрировать статью, но обрезать (кропнуть) исходное изображение. И желательно так, чтобы результат был адаптивен и адекватно реагировал на масштабирование.
Джейк Арчибальд предлагает решение на SVG и foreignObject: https://codepen.io/alinaki/pen/KKLXvwz
Вообще, весьма красиво. Да, можно генерировать кропы на сервере, но это, как минимум, лишние телодвижения. А тут – одна картинка, чистый и понятный код.
#svg #img #foreignObject #crop #бородач
❤15
#новость дня
Ой, а вчера-то Linux исполнилось 34 года. Хотите вы этого или нет, но плодами этих трудов вы все пользуетесь прямо или косвенно.
Лично я на Linux как на основной ОС сидел с 2006 года по 2018. Фотошоп и игры через WINE, а потом и Фотошоп стал не нужен с приходом Figma.
Ну почему перестал использовать, пожалуй, понятно 🍏
Ну что, ещё, как минимум, 34 года впереди?
Что на ваших машинах, котаны? В комментарии я скину пару скриншотов старых со своих.
#linux #birthday
Ой, а вчера-то Linux исполнилось 34 года. Хотите вы этого или нет, но плодами этих трудов вы все пользуетесь прямо или косвенно.
Лично я на Linux как на основной ОС сидел с 2006 года по 2018. Фотошоп и игры через WINE, а потом и Фотошоп стал не нужен с приходом Figma.
Ну почему перестал использовать, пожалуй, понятно 🍏
Ну что, ещё, как минимум, 34 года впереди?
Что на ваших машинах, котаны? В комментарии я скину пару скриншотов старых со своих.
#linux #birthday
👍15
#фишка дня
Сидишь такой и не вдупляешь, что происходит в пулл или мёрдж-реквесте?
GitHub и GitLab соответственно
Или, возможно, пытаешься вспомнить, а как ты вообще задачу решил? Надо же описание внести какое-то, а в голове туман...
Современный ответ: так проведи ревью от Copilot!
Но а) не везде он включён б) не везде разрешён к применению в PR/MR в) в GitLab вообще ничего нет.
Ничего страшного, на это есть решение!
Кто-то из олдов наверняка помнит, что вот этот раздельный вид в веб-интерфейсе с удалёнными и добавленными строками — штука сравнительно новая. Ещё во времена царя-гороха царило понятие diff- или patch-файлов. Вот ссылка на вики: https://en.wikipedia.org/wiki/Patch_(Unix)
Формат простой до безумия:
Я думаю, людям, прошивающим всякие там андроиды и ардуинки процесс хорошо известен: скачиваешь исходники библиотеки или конфига, скачиваешь patch-файл от анона с форума и накладываешь его командой, буквально,
Ладно, к чему этот экскурс вообще?
А к тому, что изменения из PR/MR легко можно получить в таком же виде! Все добавления и изменения в одном файле.
Просто берите ссылку на ваш реквест и добавьте к нему
А что делать потом? Cкормить это ChatGPT или Gemini или что там в вашей компании разрешено конечно же!
LLM-ки отлично справляются с разбором таких вещей! И на понятном языке и объяснят, что происходит, и найдут косяки, и напишут описание.
Вкусно? Не то слово! Пользуемся.
#git #patch #ai
Сидишь такой и не вдупляешь, что происходит в пулл или мёрдж-реквесте?
GitHub и GitLab соответственно
Или, возможно, пытаешься вспомнить, а как ты вообще задачу решил? Надо же описание внести какое-то, а в голове туман...
Современный ответ: так проведи ревью от Copilot!
Но а) не везде он включён б) не везде разрешён к применению в PR/MR в) в GitLab вообще ничего нет.
Ничего страшного, на это есть решение!
Кто-то из олдов наверняка помнит, что вот этот раздельный вид в веб-интерфейсе с удалёнными и добавленными строками — штука сравнительно новая. Ещё во времена царя-гороха царило понятие diff- или patch-файлов. Вот ссылка на вики: https://en.wikipedia.org/wiki/Patch_(Unix)
Формат простой до безумия:
++++ добавлено
---- удалено
Я думаю, людям, прошивающим всякие там андроиды и ардуинки процесс хорошо известен: скачиваешь исходники библиотеки или конфига, скачиваешь patch-файл от анона с форума и накладываешь его командой, буквально,
patch
. Я так делал с Rockbox для iPod недавно, например.Ладно, к чему этот экскурс вообще?
А к тому, что изменения из PR/MR легко можно получить в таком же виде! Все добавления и изменения в одном файле.
Просто берите ссылку на ваш реквест и добавьте к нему
.patch
. Вот так: https://patch-diff.githubusercontent.com/raw/edvardchen/eslint-plugin-i18next/pull/145.patchА что делать потом? Cкормить это ChatGPT или Gemini или что там в вашей компании разрешено конечно же!
LLM-ки отлично справляются с разбором таких вещей! И на понятном языке и объяснят, что происходит, и найдут косяки, и напишут описание.
Вкусно? Не то слово! Пользуемся.
#git #patch #ai
👍27❤3🤩2
#статья дня
Все, наверное, знают о том, что существует поведенческий таргетинг — который определяет, какая реклама вам больше интересна.
И под капотом такой системы — полноценная big data-инфраструктура: события пишутся в логи, проходят обработку и попадают в key-value хранилище, откуда их читает рантайм показа рекламы.
Причем система должна работать так надежно, чтобы каждое событие обработалось ровно один раз (exactly-once), и так быстро, чтобы уложиться в миллисекунды на весь цикл.
Как этого добиться — рассказал в статье Руслан Савченко, разработчик динамических таблиц YTsaurus: https://habr.com/ru/companies/yandex/articles/939078/
Из интересного:
— События шардируются по хешу идентификатора. Это гарантирует, что все события одного пользователя обрабатываются одним воркером в рамках локальной транзакции.
— Дошли до низкоуровневой оптимизации аллокатора памяти и работы с ядром Linux, чтобы убрать провалы на высоких перцентилях.
— Вместо перезаписи всего protobuf-профиля система пишет бинарные дельты (через xdelta). Агрегатные колонки накладывают все накопившиеся дельты на оригинальный protobuf — получаем актуальную версию объекта
Все решения, на самом деле, можно применять не только к профилям. Прикольно, что в статье куча графиков — помогают разобраться. Советую почитать на досуге
#highload #db #database
Все, наверное, знают о том, что существует поведенческий таргетинг — который определяет, какая реклама вам больше интересна.
И под капотом такой системы — полноценная big data-инфраструктура: события пишутся в логи, проходят обработку и попадают в key-value хранилище, откуда их читает рантайм показа рекламы.
Причем система должна работать так надежно, чтобы каждое событие обработалось ровно один раз (exactly-once), и так быстро, чтобы уложиться в миллисекунды на весь цикл.
Как этого добиться — рассказал в статье Руслан Савченко, разработчик динамических таблиц YTsaurus: https://habr.com/ru/companies/yandex/articles/939078/
Из интересного:
— События шардируются по хешу идентификатора. Это гарантирует, что все события одного пользователя обрабатываются одним воркером в рамках локальной транзакции.
— Дошли до низкоуровневой оптимизации аллокатора памяти и работы с ядром Linux, чтобы убрать провалы на высоких перцентилях.
— Вместо перезаписи всего protobuf-профиля система пишет бинарные дельты (через xdelta). Агрегатные колонки накладывают все накопившиеся дельты на оригинальный protobuf — получаем актуальную версию объекта
Все решения, на самом деле, можно применять не только к профилям. Прикольно, что в статье куча графиков — помогают разобраться. Советую почитать на досуге
#highload #db #database
👍5❤4🫡3
This media is not supported in your browser
VIEW IN TELEGRAM
#статья дня
А нет такого, что новые технологии фронтенда нет смысла изучать, пока их не разжуют Шадид, Комо или Вес Бос? :)
Не, ну серьёзно. Вот читаешь ты блоги разработчиков Хрома или, простите, Вебкита. Что получаешь?
Получаешь нечто слишком рано, слишком мало, слишком сухо и сложно. Ну, буквально, посмотрите на статью про якорное позиционирование в блоге WebKit aka Safari: https://webkit.org/blog/17240/a-gentle-introduction-to-anchor-positioning/
A gentle introduction... куда уж более gentle: ни одного интерактивного примера, код минимален.
И тут давайте Шадида возьмём, буквально утром сегодня выпустил: https://ishadeed.com/article/anchor-positioning/
Уже начиная с шапки становится понятно о чём речь!
Каждый пример как всегда снабжён интерактивом, а если браузер не поддерживает пока якоря — всегда есть переключатель на видео.
Как всегда, глубокое почтение Шадиду за работу и рекомендация к прочтению! Якоря — уже не за горами, как минимум, можно заполифиллить.
#css #anchor
А нет такого, что новые технологии фронтенда нет смысла изучать, пока их не разжуют Шадид, Комо или Вес Бос? :)
Не, ну серьёзно. Вот читаешь ты блоги разработчиков Хрома или, простите, Вебкита. Что получаешь?
Получаешь нечто слишком рано, слишком мало, слишком сухо и сложно. Ну, буквально, посмотрите на статью про якорное позиционирование в блоге WebKit aka Safari: https://webkit.org/blog/17240/a-gentle-introduction-to-anchor-positioning/
A gentle introduction... куда уж более gentle: ни одного интерактивного примера, код минимален.
И тут давайте Шадида возьмём, буквально утром сегодня выпустил: https://ishadeed.com/article/anchor-positioning/
Уже начиная с шапки становится понятно о чём речь!
Каждый пример как всегда снабжён интерактивом, а если браузер не поддерживает пока якоря — всегда есть переключатель на видео.
Как всегда, глубокое почтение Шадиду за работу и рекомендация к прочтению! Якоря — уже не за горами, как минимум, можно заполифиллить.
#css #anchor
👍14❤4🤩2👎1
Будни разработчика
#фишка дня Сидишь такой и не вдупляешь, что происходит в пулл или мёрдж-реквесте? GitHub и GitLab соответственно Или, возможно, пытаешься вспомнить, а как ты вообще задачу решил? Надо же описание внести какое-то, а в голове туман... Современный ответ:…
С полей сообщают, что добавление
А чем меньше символов — тем дешевле и быстрее обработка.
Вот бы всё можно было представить в таком виде...
P. S. На BitBucket тоже работает!
.diff
к адресу пулл-реквеста делает то же самое, но в формате .diff
, который чуть менее многословный, чем .patch
!А чем меньше символов — тем дешевле и быстрее обработка.
Вот бы всё можно было представить в таком виде...
P. S. На BitBucket тоже работает!
Wikipedia
diff
В вычислительной технике diff — утилита сравнения файлов, выводящая разницу между содержанием двух файлов. Эта программа выводит построчно изменения, сделанные в файле (для текстовых файлов). Современные реализации поддерживают также двоичные файлы. Вывод…
❤7
Media is too big
VIEW IN TELEGRAM
#заметка дня
Эпопея с пультом на Flutter продолжается! И в этот раз мне захотелось реализовать трансляцию фото (ну и видео) на телевизор.
Да, в 2025 году есть Chromecast, MirrorLink и AirPlay. Но хоть MirrorLink моим телевизором 2018 года выпуска и поддерживается, основной мой телефон — iPhone, а в AirPlay телевизор не умеет.
Да и задачи у этих троих чуть-чуть иные, нежели просто галерею фотографий посмотреть. Трансляция экрана это совсем не то же самое, что показать картинку или видео.
Потому на помощь нам приходит технология двадцатилетней давности, которая до сих пор поддерживается везде — DLNA!
В 2003 году тогдашние гиганты индустрии объединились и создали Digital Living Network Alliance, описав соответствующие стандарты и протоколы. В духе индустрии, использовались основанные на XML протоколы обмена данными и уже расмотренный когда-то мной SSDP.
Как это всё работает?
Когда мы сканируем сеть по SSDP, устройства сообщают в ответ поддерживаемые протоколы, схемы работы порты. И одна из таких схем работы —
Ну и мы отправляем телевизору запрос:
В этот же момент роли меняются. Ваш компьютер или телефон становятся сервером, а телевизор — клиентом. Телевизор (или другой плеер) скачивает переданный в CurrentURI файл. Естественно, надо этот самый сервер у себя на телефоне или компьютере запустить!
А уже второй командой посылаем Play:
И всё, всё работает. Главное, чтобы телевизор понимал, что ему передали. Заодно ещё метадату можно накинуть.
Да, в 2017 году альянс распустили, но DLNA работает буквально везде, где нужно. Просто называть стали по разному: Samsung AllShare, LG SmartShare, Sony Video/Music/Photo. А так, телевизоры, NAS-ы, куча приложений для всех платформ... Это очень простой, хоть и избыточный, протокол.
Да и реализовать это было весьма просто и интересно.
Кстати, можете сами попробовать побаловаться, есть минимальная имплементация DLNA с названием nano-dlna: https://github.com/gabrielmagno/nano-dlna
А большего и не надо.
#flutter #dart #dlna
Эпопея с пультом на Flutter продолжается! И в этот раз мне захотелось реализовать трансляцию фото (ну и видео) на телевизор.
Да, в 2025 году есть Chromecast, MirrorLink и AirPlay. Но хоть MirrorLink моим телевизором 2018 года выпуска и поддерживается, основной мой телефон — iPhone, а в AirPlay телевизор не умеет.
Да и задачи у этих троих чуть-чуть иные, нежели просто галерею фотографий посмотреть. Трансляция экрана это совсем не то же самое, что показать картинку или видео.
Потому на помощь нам приходит технология двадцатилетней давности, которая до сих пор поддерживается везде — DLNA!
В 2003 году тогдашние гиганты индустрии объединились и создали Digital Living Network Alliance, описав соответствующие стандарты и протоколы. В духе индустрии, использовались основанные на XML протоколы обмена данными и уже расмотренный когда-то мной SSDP.
Как это всё работает?
Когда мы сканируем сеть по SSDP, устройства сообщают в ответ поддерживаемые протоколы, схемы работы порты. И одна из таких схем работы —
/MediaRenderer/AVTransport/Control
. Ну и мы отправляем телевизору запрос:
POST /MediaRenderer/AVTransport/Control HTTP/1.1
HOST: 192.168.1.42:1400
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<CurrentURI>http://192.168.1.10:8000/picture.jpg</CurrentURI>
<CurrentURIMetaData></CurrentURIMetaData>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
В этот же момент роли меняются. Ваш компьютер или телефон становятся сервером, а телевизор — клиентом. Телевизор (или другой плеер) скачивает переданный в CurrentURI файл. Естественно, надо этот самый сервер у себя на телефоне или компьютере запустить!
А уже второй командой посылаем Play:
POST /MediaRenderer/AVTransport/Control HTTP/1.1
HOST: 192.168.1.42:1400
CONTENT-TYPE: text/xml; charset="utf-8"
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<Speed>1</Speed>
</u:Play>
</s:Body>
</s:Envelope>
И всё, всё работает. Главное, чтобы телевизор понимал, что ему передали. Заодно ещё метадату можно накинуть.
Да, в 2017 году альянс распустили, но DLNA работает буквально везде, где нужно. Просто называть стали по разному: Samsung AllShare, LG SmartShare, Sony Video/Music/Photo. А так, телевизоры, NAS-ы, куча приложений для всех платформ... Это очень простой, хоть и избыточный, протокол.
Да и реализовать это было весьма просто и интересно.
Кстати, можете сами попробовать побаловаться, есть минимальная имплементация DLNA с названием nano-dlna: https://github.com/gabrielmagno/nano-dlna
А большего и не надо.
#flutter #dart #dlna
1❤20👍10🫡1
This media is not supported in your browser
VIEW IN TELEGRAM
#такое дня
Когда вам в очередной раз станет стыдно, что вы сделали какой-то костыль, вспомните, что бегущую строку в CSS ещё совсем недавно нельзя было сделать без дублирования элементов: https://www.tgoop.com/htmlshit/3721
А если и это не помогает, вспомните, что где-то там есть компания Apple, которая не осилила сделать «бесконечный» (или хотя бы автовозвратный) список часов и минут в будильнике, поэтому продублировала 0-23 на часах (0-12 в AM/PM) и 0-59 на минутах много-много раз. Очень. Много. Раз.
Кого-то, впрочем, это только больше расстроит. Ведь и платят им больше.
#apple #ios #бред
Когда вам в очередной раз станет стыдно, что вы сделали какой-то костыль, вспомните, что бегущую строку в CSS ещё совсем недавно нельзя было сделать без дублирования элементов: https://www.tgoop.com/htmlshit/3721
А если и это не помогает, вспомните, что где-то там есть компания Apple, которая не осилила сделать «бесконечный» (или хотя бы автовозвратный) список часов и минут в будильнике, поэтому продублировала 0-23 на часах (0-12 в AM/PM) и 0-59 на минутах много-много раз. Очень. Много. Раз.
Кого-то, впрочем, это только больше расстроит. Ведь и платят им больше.
#apple #ios #бред
🤩14❤7🫡4
#заметка дня
На связи glebcha, который иногда с большим удовольствием предлагает идеи новых статей автору канала (старому другу) и, с недавнего времени, пишет сам в канал.
Недавно появилась интересная задача - отображать список вкладок редактора вне области скролла как в любом редакторе кода, например в IDEA.
Сразу же составил список технологий себе в помощь и в их списке оказалось событие scrollend для более эффективного формирования списка вкладок вне области прокрутки.
И вроде бы все отлично, но как обычно "есть один нюанс"....и это Safari. Ссылка на активный баг.
Но не стоит расстраиваться, решение нашлось в виде полифилла (не идеального, но отличного).
Проверяйте доступности браузерного api перед использованием и помните - "нет нереализуемых задач, всё лишь вопрос мотивации и времени".
#safari #scroll #scrollend
На связи glebcha, который иногда с большим удовольствием предлагает идеи новых статей автору канала (старому другу) и, с недавнего времени, пишет сам в канал.
Недавно появилась интересная задача - отображать список вкладок редактора вне области скролла как в любом редакторе кода, например в IDEA.
Сразу же составил список технологий себе в помощь и в их списке оказалось событие scrollend для более эффективного формирования списка вкладок вне области прокрутки.
И вроде бы все отлично, но как обычно "есть один нюанс"....и это Safari. Ссылка на активный баг.
Но не стоит расстраиваться, решение нашлось в виде полифилла (не идеального, но отличного).
Проверяйте доступности браузерного api перед использованием и помните - "нет нереализуемых задач, всё лишь вопрос мотивации и времени".
#safari #scroll #scrollend
👍12
Синдром самозванца, разрастающийся state и эволюция фронтенда в продукте
20 сентября Яндекс Вертикали собирают фронтендеров на ежегодном митапе Vertis JS, чтобы обсудить главные страхи и современные инструменты разработчиков.
Помимо докладов, в программе активности-ритуалы:
▫️Beer manifestation — для тех, кто готов поделиться своей историей
▫️Whispercoding, где каждый участник добавляет свою строчку к письму, пока зрители нашёптывают новые условия
Всё это — вместе с ребятами из Вертикальных сервисов: Авто.ру, Яндекс Путешествий и Яндекс Аренды.
📍 Санкт-Петербурге, БЦ Феррум
📌 Полная программа и регистрация
20 сентября Яндекс Вертикали собирают фронтендеров на ежегодном митапе Vertis JS, чтобы обсудить главные страхи и современные инструменты разработчиков.
Помимо докладов, в программе активности-ритуалы:
▫️Beer manifestation — для тех, кто готов поделиться своей историей
▫️Whispercoding, где каждый участник добавляет свою строчку к письму, пока зрители нашёптывают новые условия
Всё это — вместе с ребятами из Вертикальных сервисов: Авто.ру, Яндекс Путешествий и Яндекс Аренды.
📌 Полная программа и регистрация
Please open Telegram to view this post
VIEW IN TELEGRAM
👎6❤1🤡1