Dev
:Как же хорошо, что у всех интервалы времени измеряются в одинаковых единицах и фразу "через 15 минут" понимают одинаково во всем цивилизованном мире.
Нет такого, что у одного минута длится дольше, чем у другого. Или что в США вместо секунды используют какой-нибудь "тик", который равен 1.672 секунды, и день состоит не из 24 часов, а из 4 "квартосуток".
Если бы еще и такое было, программисты бы вообще свихнулись. Им и так хватает високосных секунд и часовых поясов.
Go: Отложенная обработка событий файловой системы
Допустим, вам нужно что-то сделать при возникновении какого-то события файловой системы. Например, перезапустить веб-сервер при изменении файлов. Довольно частая практика при разработке: повесить "слушателя" файловой системы, запустить приложение, сразу же после редактирования файлов "на лету" перекомпилировать проект и заново запустить его.
Этот сайт написан на Go, и недавно я решил добавить в него подобный hot-reload для markdown-файлов с постами: кладешь новый файл в папку, веб-сервер это замечает и переналивает внутренний in-memory-storage с публикациями без перезапуска самого себя. При этом мне хотелось именно "слушать" файловую систему, а не сканировать ее раз в несколько секунд.
Читать далееАбстракции и наследование в Си - стреляем по ногам красиво
Иногда нет-нет да и хочется что-нибудь абстрагировать и обобщить в коде на Си. К примеру, хочешь ты принтануть содержимое структуры несколько раз, пишешь везде, как дурак, printf("%s %d %f\n", foo->bar, foo->baz, foo->boom)
, и интуитивно кажется, что есть способ сделать foo->print(foo)
, и так вообще со всеми структурами, не только с foo
.
Возьмем пример: есть некий чувак с именем и фамилией, и есть птица, у которой есть имя и владелец.
typedef struct Person Person;
struct Person {
char *first_name;
char *last_name;
};
typedef struct Bird Bird;
struct Bird {
char *name;
Person *owner;
};
Чтобы вывести информацию про этих животных, кондовый сишник напишет просто две функции:
void Person_Print(Person *p) {
printf("%s %s\n", p->first_name, p->last_name);
}
void Bird_Print(Bird *b) {
printf("%s of %s %s\n", b->name, b->owner->first_name, b->owner->last_name);
}
И будет таки прав! Но что если подобных структур у нас много, а наш мозг испорчен веяниями ООП?
Читать далееDocker Buildkit: Правильное использование --mount=type=cache
TL;DR Содержимое каталогов, смонтированных через
--mount=type=cache
, не сохраняется в docker-образе, поэтому кэшировать надо не целевые каталоги, а промежуточные.
В dockerfile:1.3
появилась возможность монтировать файловые системы во время построения образа, в том числе и в целях кэширования: можно кэшировать скачанные пакеты или промежуточные артефакты компиляции.
Например, пакет uwsgi
каждый раз компилируется при установке, и это время хочется сократить, закэшировав весь каталог с пакетами:
# syntax=docker/dockerfile:1.3
FROM python:3.10
RUN mkdir /pip-packages
RUN --mount=type=cache,target=/pip-packages \
pip install --target=/pip-packages uwsgi
> docker build -t pip-cache -f Dockerfile.pip .
# ...
[+] Building 14.6s (7/7) FINISHED
Выглядит, что все прошло успешно, но целевой каталог пуст:
> docker run -it --rm pip-cache ls -l /pip-packages
total 0
Что-то явно пошло не так.
Читать далееБыстрый коммит и пуш
Хочу поделиться shell-функцией gacp
(Git Add, Commit and Push), которую я придумал несколько месяцев назад и с тех пор использую ее примерно каждый час:
# fish
function gacp
git add .
git commit -m "$argv"
git push origin HEAD
end
# bash/zsh
function gacp() {
git add .
git commit -m "$*"
git push origin HEAD
}
Пример использования:
> gacp add some new crazy stuff
[master fb8dcc9] add some new crazy stuff
<...>
Enumerating objects: 12, done.
<...>
To github.com:foo/bar.git
912c95d..fb9dcc9 master -> master
Наконец-то больше не придется городить цепочки с &&
и вставлять кавычки, когда надо написать в сообщении больше одного слова!
Ж К П
В любом текстовом процессоре (Microsoft Word, Google Docs, LibreOffice) кнопки "полужирный", "курсив" и "подчеркнутый" находятся рядом:
Десятилетиями в голове устаканивался паттерн о том, что это свойства одного порядка. Хочешь сделать полужирный курсив, нажимаешь две кнопки рядом:
Хочешь жирный и подчеркнутый:
Про подчеркнутый курсив не буду - это для особенных людей.
В HTML-тегах с этим тоже просто. Есть три тега: b
, i
и u
. Можно вкладывать их друг в друга и получать желаемую комбинацию:
<b><i>полужирный курсив</i></b> <b><u>полужирный подчеркнутый</u></b> <i><u>пожалуйста, не надо</u></i>
А в CSS это совершенно разные свойства:
{
/* полужирный */
font-weight: bold;
/* курсив */
font-style: italic;
/* подчеркнутый */
text-decoration: underline;
}
Про font-weight
еще более-менее понятно, но правила применения двух остальных свойств я уже 13 лет не могу запомнить. Если нужно сделать подчеркнутый текст, а подсказок взять негде, я могу просто перебрать все варианты, пока не заработает:
text-style: underline;
font-style: underline;
font-decoration: underline;
text-underline: true;
Очень бесит. Хочется либо так:
font-style: bold;
font-style: bold, italic;
font-style: italic, underline;
Либо так:
font-bold: true;
font-underline: true;
font-italic: true;
Большего мне и не надо.