Іграшка 1-ша: CLI кліент для DW. Користуюсь десь з місяць, ніби працює.
( Read more... )Іграшка 2-га: транслітератор з російської в українську
( Read more... )Іграшка 1-ша: CLI кліент для DW. Користуюсь десь з місяць, ніби працює.
( Read more... )Іграшка 2-га: транслітератор з російської в українську
( Read more... )https://sigwait.gitlab.io/les_podervyansky--plays/
Коли 2 роки тому, мені закортіло перечитати п'єси ЛП, я не спромігся їх знайти у нормальному epub. Тоді я зробив свою компіляцію і розповів про це десь у LJ. Не знаю чому, але the resulting epub/pdf найбільше скачували з Росії. Навіщо їм там Подерв'янський?
На останній сторінці epub'у я попрохав надсилати мені erratum. За 2 роки це наважилася зробити аж 1 людина з Чехії. Сьогодні я, нарешті, знайшов сили epub обновити.
( Read more... )Колись був такий чималенький хфайла jarg447.txt, який містив дефініції слів micros~1 чи ken та загальний опис емайтішних хакерів, їх поведінку, розваги і погляди на життя.
З тих часів, коли я його листав (> 20 тому), змінилося майже все, а меінтейнер хфайлу--Ерік Реймонд (який, до речі, хоча є і маґа, але не любить Московію)--не оновлював його з 2003 року.
Я згадав про хфайла жаргонів, коли намагався пригадати як називають software тіпів, яким є байдуже на hardware:
$ ./jargon softy
softy: n.
[IBM] Hardware hackers' term for a software expert who is largely
ignorant of the mysteries of hardware.
(Це ж я! Ну, за вийнятком 'іксперт'.)
jarg447.txt чомусь залишається ув iso-8859-1, напевно тому шо ув 2003 ще не вийнашли UTF8, а уйоб-версія видає
$ curl -Is http://www.catb.org/~esr/jargon/html/S/support.html | grep type
content-type: text/html; charset=utf-8
хоча сторінки також залишаються ув iso-8859-1. Сучасні бовзери вибирати кастомне кодування сторінки не дозволяють і все виглядає поламаним та занедбаним.
Після iconv залишається питання як шукати терміни, тому що вгадати довжену конь тексту для grep там є неможливо:
:term: pronunciation\n\n def
(довжина def є довільна)
awk дозволяє змінювати роздільники, наприклад, замість '\n':
BEGIN { RS = "\n\n:" }
де залишається тоді тільки домовитися на чому робити match:
$ cat jargon
#!/usr/bin/awk -f
function eh(s) { print s > "/dev/stderr"; exit 1 }
BEGIN {
if (ARGC < 2) eh("Usage: jargon pattern [indices_mode]")
if ( !("JARGON" in ENVIRON))
eh("JARGON env must contain path to jarg447.txt")
pattern = ARGV[1]
indices_mode = ARGV[2]
ARGV[1] = ENVIRON["JARGON"]
ARGV[2] = ""
RS = "\n\n:"
ORS = indices_mode ? "\n" : "\n\n"
}
function entry() {
if ($0 ~ /^#/) return ""
return substr($0, 0, index($0, ":")-1)
}
tolower(entry()) ~ tolower(pattern) {
print indices_mode ? entry() : $0
}
Що є трохи забагато зусиль для іграшкового словника, але дозволяє дізнатися купу трівіа:
$ export JARGON=/mnt/scrap/lib3/doc/jargon-4.4.7.txt
$ ./jargon . 1 | wc -l
2310
$ ./jargon slop 1
slop
slopsucker
Ось, ви напевно думали що slop це якесь нове слово останніх років.
$ ./jargon micro 1
killer micro
micro-
MicroDroid
microfortnight
microLenat
microReid
microserf
Microsloth Windows
Microsoft
micros~1
$ ./jargon \~
micros~1:
An abbreviation of the full name {Microsoft} resembling the rather
{bogus} way Windows 9x's VFAT filesystem truncates long file names to
fit in the MS-DOS 8+3 scheme (the real filename is stored elsewhere).
If other files start with the same prefix, they'll be called micros~2
and so on, causing lots of problems with backups and other routine
system-administration problems. During the US Antitrust trial against
Microsoft the names Micros~1 and Micros~2 were suggested for the two
companies that would exist after a break-up.
(Дуже програв з останнього речення.)
Виявляється, Кен Томпсон був відповідальним за релізи:
$ ./jargon ^ken | head
ken: /ken/, n.
1. [Unix] Ken Thompson, principal inventor of Unix. In the early days
he used to hand-cut distribution tapes, often with a note that read
"Love, ken". Old-timers still use his first name (sometimes
uncapitalized, because it's a login name and mail address) in
third-person reference; it is widely understood (on Usenet, in
particular) that without a last name `Ken' refers only to Ken
Thompson. Similarly, `Dennis' without last name means Dennis Ritchie
(and he is often known as dmr). See also {demigod}, {Unix}.
awk-скрипта має бага зі словом zorkmid, т.я. воно є останнім і після нього ув хфайлі йдуть поза-словникові додатки. Фікса залишається ув якості домашнього завдання.
Для спеціялізованого кастомного дістро мені знадобився механізма збільшення fat32 партішона (під час початкового буту). Коли вимовляють слово resize мають на увазі 2 речі: збільшення партішона та збільшення хфайлової системи. Можна просто зробити 1ше, але зиску для користувача-дурбели від того буде небагато.
Кастомний дістро використовує (не треба непритомніти) systemd, який вміє це робити, але, на жаль, не для fat32:
"systemd-growfs knows very little about specific file systems ... and will instruct the kernel to grow the mounted filesystem to full size of the underlying block device ... Currently: ext4, btrfs, xfs"
Якщо би мова йшла про ext4 та безтурботне життя без systemd, алгоритма був би нескладний: за допомогою parted(8) збільшується розмір партішона, потім за допомогою resize2fs(8) збільшується хфайлова система. Робити це можна, наприклад, ув initramfs, до того як монтуються блокові дівайси і запускається фінальний switch_root(8).
Ріпо з parted насправді має С бібліотеку libparted, якою користується ютіліта parted. Навколо libparted побудована вся інфраструктура магічних аплікації, які можуть зменшувати/збільшувати розміри будь-яких партішонів.
libparted не містить коду для збільшення файлових систем, за винятком vfat. Не дивлячись на це, рісайзування fat залишається прихованим від користувача і відсутнім ув parted (страшенно популярна gtk'шна аплікація gparted той маловідомий куток libparted радісно використовує).
Далі починається божевілля. Будь-який дістро, від деривативів убунти, федори та прибацаного арча до контейнерів з олпайном, містить нєчто під назвою fatresize. Будь-яка LLM мументально виплюне цю назву і напише приклад її використання, що, могло би бути вкрай корисно, коли би та fatresize працювала.
Якщо поглянути на її нутрощі після розглядання libparted/parted, стає
нескладно помітити, що той, хто її писав, копіював звідти шматки
хфункцій чи цілі хфункції verbatim, що одначе не допомогло: "ютіліта"
є неспроможною навіть розпарсити рядок /dev/sda3 коректно і вилітає
після спроби замість того обробляти /dev/sda, тому що libparted
відмовляється робити ідіотизм.
На ґітгабі плачуть, але автор не відповідає. Є 1 (один) форк працюючий (у сенсі, з намаганням полагодити елементарні речі), але також занедбаний.
Варіянти вирішення прублеми: (а) натравити на те улюбленого огента, (б) сказати огенту написати з нуля, (с) написати самому. Я вибрав останнє,
$ _out/fat32-resize _out/junk/1G info 2
transport file
sectors 2097152
partition_table msdos
partitions 2
sector_size 512
partition_start 411648
partition_end 2097151
partition_length 1685504
fs_type fat32
fs_start 411648
fs_end 1460219
fs_length 1048572
partition_used_percent 62
lolbar loooooooooooooooooooo...........l
але перед тим поцікавився, хто є автор fatresize.
Ви не повірите!
"то, что ми сєйчас наблюдаєм по всєму міру -- єто вскритий давно зрєющій фурункул русофобії і злоби. Шовінізм по отношєнію Запада ко всєм русскім. Маскі сняти."
Це з його linkedin, де він пише що нібито працює ув швейцарському охфісі гоогла, але одночасно ув твіторі чомусь косить під румунського маґа-патріота.
Нумеро тре драматичного епосу про майкрософтські айсо хфайли. (Нумеро уно, а також менш цікавий нумеро дуе.)
Невеличкий скрипта, який тулив інсталяційні хфайли з охфіційного .iso до .img (для подальшої dd'ізації його на блокового носія знімного), раптом перестав працювати з .iso від 25h2!
Щось ув механізмі з двома GPT партішонами перестало подобатися свіжій інсталяції. Т.я. останній раз я дивився на те майже рік тому, жодного бажання пригадувати деталі у мене не з'явилося. Простіше за все було подивитися як то робить Media Creation Tool майкрософтський та скопіювати його поведінку.
Замість GPT він форматує дівайса з MBR і створює самотнього fat32
партішона, куди переносить всі хфайли з .iso. Останній містить
efi/boot/bootx64.efi аплікацію, тому байоса навіть ув режимі
суворого UEFI її запускає. Я думав GPT є необхідний завжди, але це
виявилося неправдою.
Щоправда fat32 не підтримує файли > 4 GB, а .iso має install.wim
розміром > 6 GB, тому останнього треба ділити на шматки за допомогою
ютіліти wimlib-imagex, яка є навіть ув стандартних федориних ріпо.
Хоча фінальний .img виглядає як MBR-леґесі,
$ parted w11.img print | grep '^[PN ]'
WARNING: You are not superuser. Watch out for permissions.
Partition Table: msdos
Number Start End Size Type File system Flags
1 1049kB 8591MB 8590MB primary fat32 boot, lba
він не зможе завантажитися ув режимі байосного леґесі режиму через відсутність бут лоадеру:
$ head -c512 < w11.img | xxd -a
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
*
000001b0: 0000 0000 0000 0000 3eeb 5b2d 0000 8020 ........>.[-...
000001c0: 2100 0cfe ffff 0008 0000 0000 0001 0000 !...............
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 55aa ..............U.
Оновлений ланаксний скрипта на ґітгабі.
Хотів звільнити usb драйва від лайнаксних gpt партішонів, щоб заформатувати потім його ув віндюку, і отримав ось це:
$ sudo fdisk -l /dev/sdi
Disk /dev/sdi: 112.64 GiB, 120945901568 bytes, 236222464 sectors
Disk model: Transcend 128GB
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Device Boot Start End Sectors Size Id Type
/dev/sdi1 4294967295 8589934589 4294967295 2T ff BBT
/dev/sdi2 4294967295 8589934589 4294967295 2T ff BBT
/dev/sdi3 4294967295 8589934589 4294967295 2T ff BBT
/dev/sdi4 4294967295 6854241533 2559274239 1.2T ff BBT
Виявляється, як видаляти все через копіювання /dev/zero на перший та останній МБ, віндюка побачить відсутність партішонів і, ув якості помсти, зробить superfloppy. Супер-шо?
'Removable media without either GPT or MBR formatting is considered a "superfloppy". The entire media is treated as a single partition.'
(З майкрософтських питань-відповідей про gpt.)
Щоб цього не сталосі (і ув fdisk не їхав дах) треба заздалегідь мати
$ lsblk /dev/sdi
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdi 8:128 1 120.3M 0 disk
└─sdi1 8:129 1 119.3M 0 part
Я спитав себе чому за стільки років не маю скрипта який би робив очищення та 'правільно' заформатовував дівайса, а замість того кожного разу гооглю офсети для dd. Цікавого там є 0, кожний читач може написати те коректно самотужки, але що мені не подобається ув таких скриптах і чого я боюся, це те, що слухаючи сирену, я можу випадково передати їм ім'я не usb драйву, а внутрішнього ssd, і тоді Smokey, my friend, you're entering a world of pain.
Перевірити ув лайнаксі чи є блоковий носій знімним, можна подивившись
ув файла /sys/block/XXX/removable. Тоді, проітерувавши все з
/sys/block/, стає легко відфільтрувати непотрібне. Якщо такий
шелóвий скрипта намалює список зі usb-драйвів користувачу, останній
зможе безпечно вибрати потрібний, а перший надрукує результат вибору
для наступної аплікації:
$ ./blockdevrem-select | xargs sudo ./blockdevrem-wipe
Тобто, скрипта, який небезпечно маніпулює байтами на дівайсі, нічого не знає про нутрощі скрипта який дозволяє дівайса вибрати. Запускати другий без першого зазвичай немає потреби.
Віджет меню ув dialog(1) очікує парного числа параметрів, але у нас вони можуть містити пробіли, тому як не використовувати баша з його масивами, доведеться змінювати IFS.
$ cat blockdevrem-select
#!/bin/sh
eh() { echo "blockdevrem-select error: $*" 1>&2; exit 1; }
test -d /sys/block || eh /sys/block is not a directory
command -v dialog >/dev/null || eh 'no dialog(1)'
# shellcheck disable=2012
removables() {
ls -1 /sys/block | while read -r name; do
[ "`cat /sys/block/"$name"/removable`" = 1 ] &&
[ "`cat /sys/block/"$name"/size`" != 0 ] &&
desc "$name"
done
}
US=`printf '\037'`
desc() {
cat "/sys/block/$1/device/vendor" "/sys/block/$1/device/model" | xargs |
xargs -0 printf "%s$US%s$US" "/dev/$1"
}
dev=`removables`; [ "$dev" = "" ] && eh no USB drives
reply=`mktemp`
trap 'rm -f $reply' 0 1 2 15
exec 3> "$reply"
IFS=$US
dialog --output-fd 3 --title -- "${1:-Select a removable drive}" --keep-tite \
--menu "${2:-}" 0 0 0 $dev 1>&2 &&
cat "$reply"
Дуже сміявсь:
Anonymous @OpDeathEaters
The Epstein files on the DOJ website allow you to highlight the redacted text, copy it, and paste it into another document, which reveals what was hidden. You can also press Ctrl+F and search for "Trump " (with a space) to see his name appear more than 600 times. #OpDeathEaters
4:02 PM . Dec 23, 2025
Може то є звичайна твіторська маячня, перевіряти я не буду, але це нагадало мені старий квеста (2017), коли тато спитав мене за редагування pdf:
https://henry-flower.dreamwidth.org/397452.html
Гадаю, з тих часів змінилося небагато.
Ґай Кавасакі ув своєму Шлях Мокінтошу (1989) має пасажа про совок:
'Denise Caruso, columnist extraordinaire for the San Francisco Examiner, wrote about the first issue of PC World USSR. Thirty pages of ad space were sold to American advertisers, but only four pages appeared.
'The Soviet editors had pulled the other ads because they did not contain enough technical information or the information was already mentioned in the editorial. The Soviets have something there—advertising with content.'
Як то є типово для раціоналізації на відсутності фактів, висновок виглядає ахінеєю (до речі, а громші вони повернули?), але з того цінного Кавасаківського едвайсу я дізнався шо ув совдепії друкували локалізований PC World. (Я пам'ятаю PC World Ukraine, де ув ~2002 я прочитав як інсталювати fbsd.)
Якийсь петрушка відсканував 1й випуск 1988 року. Дебіл не спромігся накласти текстового шару на зображення і pdf виглядає як OCR газети.
Однак "only four pages appeared" виявилось неправдою. Сторінки іностранной реклами:
| Країна | Кількість |
|---|---|
| Bundesrepublik Deutschland | 2 |
| U.S.A. | 17 |
Але найбільше там мене розсмішив текст Гаррі Каспарова, де він бідкається за відсутність ґласності в інформатікє:
'Можно понять, почему у нас трудно наладить производство и пустить в массовую продажу 24-игольчатые, струйные и лазерные принтеры, цветные мониторы с высоким разрешением, дисководы 1,44 Мбайт, винчестеры, модемы, телефаксы, видеодиджитайзеры, детские конструкторы "Собери сам IBM-совместимый ПК", сканеры (устройства ввода текста и изображений), копировальные машины и многие другие необходимые в жизни товары. Но кто может объяснить, почему программисты должны стоять в очереди на чтение книги Б. Карнигана и Д. Ричи "Язык программирования Си" или ксерокопировать ее по 10 коп. за страницу? За нелегальное ксерокопирование могут очень строго наказать. А кто наказал тех, кто виноват в том, что тираж "Англо-русского словаря по программированию и информатике" А. Борковского всего 60 000 экземпляров? Даже если не говорить о миллионах школьников и студентов, которым он очень нужен, в СССР 300 000 программистов.'
300К погромістів?
Я побачив це недавно, але коїтися воно почалосі біля року тому. На деяких уйоб-сайтах звичайний теґ img став раптом виглядати як божевільне майкрософтське ікстеншона Інторнет Іксплореру 1998 року:
<img src="blob:https://example.com/b501e863-fe43-4b63-ae5d-dac14cac097e">
Уйоб-сторінка, яка його містить, наочно рендерить зображення без
жодних прублем, але коли наївний користувач збросіт лінк в чят, з
того вийде нічого--блоб, на який посилається <img>, існує лише ув
пам'ті конкретного інстансу бовзера, а на https://example.com/UUID
сервер відповість 404.
Навіщо це роблять? Деякі люди кожні n років починають боятися хотлінкінґу (сволочі воруют наш трафік), борці з ЕйАй намагаються зіпсувати бізнес злим корпораціям, а поціновувачі іграшкових DRM тішаться від нової скіми.
Якщо подивиться на fetch-ріквести такої сторінки, там будуть ресурси які схожі на зображення, але насправді не є ними:
$ url='https://ia800206.us.archive.org/🙈.jpg' $ curl -sI "$url" | grep -e type -e length -e obfuscate content-type: image/jpeg content-length: 267470 x-obfuscate: 1|uoEV6/PZOWtGhOZdVM898w== $ curl -s "$url" | head -c25 | file - /dev/stdin: data
Такий .jpg є зашифрований. Частковий ключа є ув X-Obfuscate хедері,
але про це не знає ані скрейпера рендомної ЕйАй контори, ані
будь-яка соцсіточка. Шифр також не афішується, і кожний уйоб-сайт може
мати який завгодно, дотримання рекомендацій тут зводить нанівець мету
обфускації.
Алгоритм малювання зображень тоді стає таким:
URL.createObjectURL;img, у якого атрібута src дорівнює
новому посиланню.Для збільшення ентропії можна написати кастомного елемента:
<img-blob alt="a fluffy cat" src="cat.bin"></img-blob>
який буде робити все перелічене самотужки.
Ув якості економії, аркайв.орґ AES-CTR-шифрує лише перші 1024 байт зображення. Бовзери знають про AES, але суворо вимагають secure context, що може дратувати під час тестування, тому для мікімаусного DRM можна взяти xor-шифра.
Обфускатувати X-Obfuscate хедера можна ще більше. Наприклад
x-obfuscate: rlW2MKWmnJ9hVwbtZFjtVzgyrFV6VPVkZwZ0AFW9Pt==
виглядає як рядок ув base64, але
$ echo rlW2MKWmnJ9hVwbtZFjtVzgyrFV6VPVkZwZ0AFW9Pt== | base64 -d | xxd
base64: invalid input
00000000: ae55 b630 a5a6 9c9f 6157 06ed 6458 ed57 .U.0....aW..dX.W
00000010: 3832 ac55 7a54 f564 6706 7400 55bd 3e 82.UzT.dg.t.U.>
Я спитав вініпухівський ДіпСік розібратися: він витратив 9 хвилин і залишив без води 2 села ув провінції Чжецзян, був кілька разів дуже близько від мети, але зрештою зазнав невдачі.
Рядок був оброблений напилком rot13:
$ alias rot13="tr 'A-Za-z' 'N-ZA-Mn-za-m'"
$ echo rlW2MKWmnJ9hVwbtZFjtVzgyrFV6VPVkZwZ0AFW9Pt== | rot13 | base64 -d
{"version": 1, "key": "12345"}
Ув якості домашнього завдання, до кастомного елементу можна додати
еквівалента loading="lazy" за допомогою Інтерсекційного
Спостерігача.
Що відбувається з Еплом останні 25 років ув Кетаї:
До них звертається тайванська (або кетайська) контора, яка обіцяє за 3-5% від BOM збирати дівайси (або навіть, як з еірподами, за 0%). Виробництво прототипів є завжди безплатно.
У такої контори є зв'язки з КПК, тому землю під фабрику Кетай материковий їм "дарує".
Контора будує фабрику (та житло для робочих) за гроші, які дає конкретна кетайська провінція. Зазвичай то є території Спеціяльних Економічних Зон, де перші N років роботи фабрики податків фактично немає.
Епл купляє обладнання, яке буває гамериканським, дойчландським, японським, чи кетайським. Фабрика, таким чином, орендує обладнання у Еплу. Якщо останні є чимось незадоволені, вони його забирають і відвозять до іншої кетайської контори.
Кетайська провінція завозить автобусами селян з навколишніх сіл. Вони оселяються ув збудованих для них бараках.
Епл привозить тисячі інженерів з гамерики, які вчать маленьких вініпухів збирати дівайса.
(Процеса є описаний ув книжці Apple in China, яка хоча і написана неприємним сучасним стилем бізнес-макулатури, містить багато анекдотів.)
Не знаю, чи є випадки, коли контора сама платить Еплу за привілеї працювати з, але я не здивуюсь.
Навіщо це кетайцям? Фабрика працює ув 2 зміні. На 3й, робиться такий самий дівайса, але для місцевого бренду Liu Hai Zhong чи Zhong Gongsu Hai. Іноді ця таємниця розкривається і Епла влаштовує скандал. Через рік, Епл з подивом дізнається як Хуавей чи Шаомі починають виробляти майже такий самий дівайса, не дивлячись на те, що вони з ними контактували ніколи.
Коли Епл потребує компонента, який неможливо знайти ув Кетаї, вони купляють його ув гамериканського виробника щоб згодом навчити вініпухів робити копію.
Гамериканські інженери, яких відправляють до Кетаю, отримують офери від Хуавею x2 від їх поточних зарплат. Ув якості бонусу можуть підіслати кошкожінку. I want to express my sincere gratitude for the opportunities, support, and experience I've gained at Apple. It's been a pleasure working with the team.
Найсумніше ув цьому не Епл per se, а те що так само роблять всі (?) тайванські та японські бренди (добровольно і с пєстнєй). Як злізти з цієї голки не знає ніхто.
Зазвичай пісеньки тематичні не вартують уваги, але I Love My Mac (2004) від канадійської тітоньки мене розвеселила:
Що сталося з авторкою--невідомо. Всі її інтервебні маєтності не працюють, видно лише їх шматки на аркайв.орґ.
Окрім ойтюнзу, знайти оригінальні хфайли пісеньки можна лише всередині .dmg диску (грудень 2005) з журналу MacAddict, який збанкрутував 18 років тому.

Всі інтерпрайзні лайнакси зроблені для постійного нагадування що життя це є виживання найпристосованіших.
ОйБіЕмівські дістро мають агента-посередника поміж кернельним файрволом та істотою з клавіятурою. Без таких прокладок інтерпрайзний лайнакс немає сенсу: раціоналізація необхідності преміяльного саппорту тоді звужується до швидкості копіпасти. Додана вартість ув якості біспоукного софтware, яке повинно генерувати додаткове технічне обслуговування, необхідна як запас води ув пустелі.
Агента-посередник називається firewalld. Це є повільна як черепаха пáйфонівська аплікація, яка виконує команди "нумо відкрити порт нумеро 1488 на інтерхфесі enp13s77". З кернелом firewalld розмовляє за допомогою С бібліотеки libnftables, а з юзерлендом по протоколу dbus.
Якщо наївний користувач, чуждий духу інтєрпрайза, додасть свою chain чи rule командою nft, то firewalld на це відреагує ніяк--ув кернелі з'явиться гуляш з інструкцій від firewalld та користувача.
Що мене завжди неймовірно дратувало ув клайнтах до firewalld це їх відраза до показу номерів портів. Наприклад, активний "сервіс" (термінологія firewalld, нічого спільного з "сервісами" від systemd) з назвою samba контролює їх 2 штуки, але ані GUI клаент, ані жахлива, повільна як черепаха (се є пáйфон) ютіліта firewall-cmd, вам їх не покажуть. Where ignorance is bliss, 'tis folly to be wise.
Свій стейт firewalld зберігає ув /etc/firewalld/ (яка є чомусь 0750
root:root, що там такого секретного?), де мапінґа сервіс-порт є
відсутній.
З деяким дратування гортаючи man-сторінку firewall-cmd, можна знайти
опцію --info-service:
$ sudo firewall-cmd --info-service samba | grep /
ports: 139/tcp 445/tcp
Для групи сервісів окремої зони це треба робити руками:
$ sudo firewall-cmd --zone=home --list-services |
xargs -n1 sudo firewall-cmd --info-service |
grep -ie ^[a-z] -e /
dhcp
ports: 67/udp
dhcpv6-client
ports: 546/udp
destination: ipv6:fe80::/64
http
ports: 80/tcp
…
Це займає секунди 3 якщо "сервісів" > 20 (можна прискорити через
xargs -P). Запити по dbus не є такими повільними per se навіть через
огидний пáйфон, повільна є ютіліта firewall-cmd.
Є також варіянт з dbus. Ви часто бачите скрипти які розмовляють з ґноумівською шиною? Я--ніколи. Можливо, нарід не знає що поттерінґівське busctl може друкувати результат ув json (додали недавно, 7 років тому), або просто цим гидують.
$ cat firewall-zone-ports
#!/usr/bin/env bash
set -e -o pipefail
zone="${1:?Usage: firewall-zone-ports zone}"
call_firewall='busctl -j call org.fedoraproject.FirewallD1'
$call_firewall \
/org/fedoraproject/FirewallD1 \
org.fedoraproject.FirewallD1.zone \
getServices s "$zone" |
jq -r .data[].[] |
while read -r service; do
interface=`$call_firewall \
/org/fedoraproject/FirewallD1/config \
org.fedoraproject.FirewallD1.config \
getServiceByName s "$service" | jq -r '.data[]'`
echo "$service"
$call_firewall \
"$interface" \
org.fedoraproject.FirewallD1.config.service \
getPorts | jq -r '[.data[][] | join("/")] | join(",")'
done | xargs -r -n2 printf "%-30s %s\n"
Мілий ґлазу інтерпрайз org.fedoraproject.FirewallD1.config.service
справляється за 0.1 сек, але витрачати час на таку оптимізацію я не
раджу.
Нижче є статистика висіння ~15 годин ув топі хакір н'юз неділю тому. Ув порівнянні з минулорічним показниками, змінилося мало: Польща тоді була на 9 позиції, ми на 32.
Дуже сумно, тому що до '22 цифри були зворотні: ми мали 10-15 місця завжди, а Польща бовталася ув 3-тьому десятку.
Як повернути все назад, я не знаю. Гадаю, це є неможливо і далі буде лише гірше: залишаться військові (мілтек за $500/місяць), тітки за 40 та пенсіонери. Пітун переміг.
Вибачте за відсутність оптимізму.
Команда dirname(1) з беллабсівської рісьóрч Unix v8 (1985):
$ cat usr/bin/dirname
# @(#)dirname.sh 1.2
expr \
${1-.}'/' : '\(/\)[^/]*/$' \
\| ${1-.}'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \
\| .
На жаль, Торвальдсу тоді було лише 16 років і ґіта він AT&T подарувати не міг, тому хто був автором іммортальних рядків, залишається невідомим.
Загалом, v8 продвжувала традицію 'все що може бути скриптом шелóвим має їм бути', наприклад /bin/true сяяв 0755 з розміром 0 байт.
Багато хто зі світу віндюка досі не розуміє чому навіть сучасні лайнакси мало використовують імена хфайлів з пробілами. Річ у тому, що останні вийнашли тільки ув 2000х роках, а до того люди ніколи не умивалися і їли сало:
$ sh usr/bin/dirname 'foo bar'
expr: syntax error: unexpected argument ‘bar/’
Ви часто використовуєте ютіліту expr(1)? Я чомусь думав вона є
builtin, але ніхто з шелів її не чіпає. Гадаю, про неї забули всі
хто про неї знав, як тільки з'явилася підтримка орифметичного
ікспаншону ув $(( … )).
Оператор : став для мене новиною. STRING : REGEX робить пошук за
взірцем, а якщо regex має субікспрешона \( … \), то ютіліта друкує
його ув стилі 'grep -o'.
Це видається корисним, але насправді товку від того є небагато.
Можна написати аналога basename(1), але навіщо?
$ expr /$SHELL : '.*/\([^/]*\)$'
bash
Порахувати довжину рядка:
$ expr foobar : '.*'
6
Надрукувати ув лайнаксі регіона таймзони:
$ expr `realpath /etc/localtime` : '.*/\(.*\)/.*$'
Europe
Таке. Перевірити рядок на суфікса:
$ q=foo.txt
$ expr $q : '.*\.txt$'
7
але ідіома
$ [ "${q##*.}" = 'txt' ]
є більш відомою і викличе меньше питань.
Сучасні dirname(1), звичайно, шелóвими скриптами не бувають. Вони або використовують позіксну dirname(3), або пишуть криву (але свою, як coreutils) хфункцію пошуку '/'.
Розважаючи себе переписуванням SOHO конфіґурації Exim, якщо це можна назвати розвагою, я поцікавився навіщо гаю час на Exim, коли допевне мають бути ольтернативи.
Років 20 тому ця галузь консалтинґу вирувала разом зі великою всесвітньою боротьбою проти спаму, але з того часу вояцький запал помітно вщух, а SOHO сервери поштові залишилися лише ув гротескних параноїків чи контрольних фріків.
Як вірити вікіпідіа (я не вірю), бійка поміж postfix та exim триває досі, де обидва разом мають маркетову частку ув ~92%. Обидва знаходяться ув непевному стані на межі занедбаності: 1й відрізняється відсутністю публічного ріпо; зміст вікі 2го нагадує покинуті військові бази або таймкапсулу з 2002 року. Обидва мають по 1му регулярному комітеру.
92%?
Перевірити який саме сервер поштовий використовує нарід можна просто відкривши tcp сокета і прочитавши (зазвичай) 1 рядок, який сервер надішле. RFC 5321 не вимагає друкувати ім'я, лише код відповіді зі своїм доменом, тому цей тест не завжди є корисний.
(Навіщо залишають ім'я та версію ув рядку вітання, я не зовсім розумію, напевно щоб русскім та північним корейцям було легше підбирати вразливості.)
$ dig mx apple.com +short | head -1
20 mx-in-vib.apple.com.
$ timeout 2 ncat mx-in-vib.apple.com 25
220 vib-mx02.apple.com -- Server ESMTP (Oracle Communications Messaging Server 8.1.0.27.20250130 64bit (built Jan 30 2025))
Я спитав ув Ґрока за популярні уйоб-сайти, але добрий шмат зі того списку використовує гооглівську хмару. Наприклад, 40 штук для України:
$ xargs ./smtp-banner.sh < top_websites_ukraine.txt | tee ua.txt
112.ua 220-mx2.myservices.email ESMTP Postfix (Debian/GNU)
nv.ua 220 mx.nv.ua ESMTP MailCleaner (Community Edition 0-da47da2) Wed, 30 Jul 2025 15:40:51 +0300
tsn.ua 220 ironport2.1plus1.net ESMTP
suspilne.media 220 DU6PEPF0000A7E2.mail.protection.outlook.com Microsoft ESMTP MAIL Service ready at Wed, 30 Jul 2025 12:45:23 +0000 [08DDCC7178A4D2A2]
ukr.net 220 2.0.0 UKR.NET ESMTP Wed, 30 Jul 2025 15:38:14 +0300 [un.20250730.wFQEzbLiXz8plF0C]
prom.ua 220-mail.uaprom.net ESMTP
youtube.com 220 mx.google.com ESMTP 38308e7fff4ca-331f409b92csi28321721fa.89 - gsmtp
google.com 220 mx.google.com ESMTP 38308e7fff4ca-331f4302005si28576861fa.422 - gsmtp
rozetka.com.ua 220 eva.rozetka.com.ua ESMTP Exim 4.98.2 Wed, 30 Jul 2025 15:38:14 +0300
sinoptik.ua 220 UKR.NET ESMTP Wed, 30 Jul 2025 15:38:14 +0300
wikipedia.org 220 mx-in1001.wikimedia.org ESMTP Postfix (Debian/GNU)
censor.net 220 mx.cloudflare.net Cloudflare Email ESMTP Service ready
uakino.best 220 uakino.me ESMTP Postfix (Debian/GNU)
gismeteo.ua 220 mx.google.com ESMTP 2adb3069b0e04-55b633bfa57si3094256e87.626 - gsmtp
x.com 220 mx.google.com ESMTP 2adb3069b0e04-55b63161bdasi3091803e87.68 - gsmtp
telegram.org 220 mx110.telegram.org ESMTP Postfix (Debian/GNU)
instagram.com 220 mx0b-00082601.pphosted.com ESMTP mfa-m0109332
obozrevatel.com 220 mail.obozrevatel.com ESMTP Exim 4.97.1 Wed, 30 Jul 2025 15:38:15 +0300
privatbank.ua 220 mx.google.com ESMTP d9443c01a7336-24022a2c33fsi83113735ad.210 - gsmtp
korrespondent.net 220 fr1.umh.ua ESMTP Exim 4.90_1 Wed, 30 Jul 2025 15:38:15 +0300
facebook.com 421 4.1.8 DNS-T2 Domain lookup failed https://www.facebook.com/postmaster/response_codes?ip=109.95.54.222#DNS-T2
segodnya.ua oopsie
pravda.com.ua 220 mx.google.com ESMTP d9443c01a7336-240837b0f6dsi29521265ad.390 - gsmtp
olx.ua 220 mx.google.com ESMTP d9443c01a7336-24076196724si35342125ad.184 - gsmtp
alerts.in.ua 220 mx.cloudflare.net Cloudflare Email ESMTP Service ready
epravda.com.ua 220 mx.google.com ESMTP 2adb3069b0e04-55b63374c7bsi3209840e87.411 - gsmtp
shafa.ua 220-mail.uaprom.net ESMTP
rbc.ua 220 mx.zohomail.com SMTP Server ready July 30, 2025 5:38:15 AM PDT
zoom.us 220 mx0b-00569201.pphosted.com ESMTP mfa-m0288579
netflix.com 220 mx.google.com ESMTP 38308e7fff4ca-331f42d90afsi28847841fa.324 - gsmtp
unian.ua 220 fiat.1plus1.net ESMTP
booking.com 220 mx07-0032a201.pphosted.com ESMTP mfa-m0176169
dou.ua 220 mx.google.com ESMTP 41be03b00d2f7-b42100b07ebsi3220280a12.1117 - gsmtp
zakupki.prom.ua 220-mail.uaprom.net ESMTP
znaj.ua 220 mx.cloudflare.net Cloudflare Email ESMTP Service ready
kyivpost.com 220 mx.google.com ESMTP 41be03b00d2f7-b3f7f73b516si9642287a12.729 - gsmtp
sport.ua 220 mx.google.com ESMTP 41be03b00d2f7-b421518e194si2403306a12.701 - gsmtp
lun.ua 220 mx.google.com ESMTP 98e67ed59e1d1-31f63dc06e0si1846146a91.45 - gsmtp
work.ua 220 mail.work.ua ESMTP Exim 4.96 Wed, 30 Jul 2025 15:38:18 +0300
aliexpress.com 220 mx1.aliyun-inc.com MX AliMail Server
Сортування є випадкове, т.я. скрипта робить конкурентні ріквести. Фасебоок огризається, тому що домашній ойпі у мене не має PTR рекорду.
Без поняття, наскільки ці данні є релевантні.
$ grep -ic exim ua.txt
4
$ grep -ic postfix ua.txt
4
$ grep -ic gsmtp ua.txt # гоогл
13
Лайнаксний скрипта замість ncat'у використовує башівські віртуальні /dev/tcp файли:
#!/usr/bin/env bash
# shellcheck disable=SC3040
set -o pipefail
banner() {
dig MX "${1:?no domain}" +short | awk '{print $NF}' | sort -R | head -1 |
grep . | {
server=`cat`; [ "$server" ] || exit 1
MODE=connect timeout 5 "$0" "$server"
}
}
read_1_line() {
{ exec 3<> "/dev/tcp/$1/25"; } 2>/dev/null || return 1
read -r line <&3
exec 3<&-
echo "$line"
}
fmt() { tr -d \\r | tr \\n \\0 | xargs -0 printf '%-25s %s\n' "$1"; }
type dig nproc timeout > /dev/null || exit 1
[ "$1" ] || { echo Usage "$0" example.com ... 1>&2; exit 1; }
case "$MODE" in
connect) read_1_line "$1" ;;
banner) { banner "$1" || echo oopsie; } | fmt "$1" ;;
*)
export MODE=banner
echo "$@" | xargs -P"`nproc`" -n1 "$0"
esac
"Компактні" Мокінтоши перестали мати чорно-білі екрани лише 1993 року, що є вкрай смішно, тому що їх лінійка "професійних" Мокінтошів ІІ отримала кольори ув 1987. NeXT ув 1988 вийшов з 2-бітним монітором (ч/б + 2 варіянти сірого), про що ув одному зі старих інтерв'ю Джобса останній розповідав як газети тоді писали що він таємно ненавидить кольори і, коли має для того владу, робить лише монохромні комп'ютери.
(До речі, оригінальний посібник по Мокінтошу ІІ виглядав гарною coffee table книжкою (конь цепта маловідомий у Центрально-Східній Європі), випадкове досягнення яке Епл спромоглася повторити ніколи, навіть після повернення Джобса.)
Мокінтош ув 1984 комплектувавсь безоплатним MacPaint'ом, який трохи пізніше Майкрософта злизала собі для віндюка. Для 1-бітних екранів симулювати відтінки сірого ув MacPaint'і можна було тільки за допомогою дізерінґу. Найвідоміший алгоритм--Floyd-Steinberg (FS)--був винайдений ув 1974, але Аткінсон, якого автор книжки Revolution in the valley називає єдиним дорослим ув команді Мокінтошу, вважав FS малоконтрастним.
Коли стало відомо що Аткінсон помер, на HN з'явився лінка на бовзерний емулятора його алгоритму від якогось угорця, який ховається від Орбана ув Ландані.
Якість мене вразила:
Напевно це можна робити ув лайнаксі з командного рядка? На жаль,
ні. Опція -⁠dither ув ImageMagick про Аткінсона
не знає (слушайтє пєсню Валєнкі). pamditherbw (з netpbm) знає, але
результат засмучує:
Угорська демо працює так:
Всі пункти, окрім 4, підтримуються власно бовзером та вимагають жодних зусиль.
Хоча угорська демо написана ув темні часи кофіскрипта, траспайлер останнього друкує читабельного джаваскрипта. Скомбінувавши зміст до 1ї хфункції
export default function(imagedata) {
let threshold = i => (i <= 128) ? 0 : 255
let luminance = function(imagedata) {
var i, j, pixels, ref;
pixels = imagedata.data;
for (i = j = 0, ref = pixels.length; j <= ref; i = j += 4) {
// luminance: red x 0.3 + green x 0.59 + blue x 0.11
pixels[i] = pixels[i + 1] = pixels[i + 2] = parseInt(pixels[i] * 0.3 + pixels[i + 1] * 0.59 + pixels[i + 2] * 0.11, 10);
}
return imagedata;
}
let dither = function(imagedata) {
var err, i, j, mono, neighbours, one, pixels, ref, w;
pixels = imagedata.data;
w = imagedata.width;
for (i = j = 0, ref = pixels.length; j <= ref; i = j += 4) {
neighbours = [i + 4, i + 8, i + (4 * w) - 4, i + (4 * w), i + (4 * w) + 4, i + (8 * w)];
mono = threshold(pixels[i]);
err = parseInt((pixels[i] - mono) / 8, 10);
pixels[i] = mono;
for (one in neighbours) {
pixels[neighbours[one]] += err;
}
pixels[i + 1] = pixels[i + 2] = pixels[i];
}
return imagedata;
}
return dither(luminance(imagedata))
}
залишається лише прикрутити її до Canvas. (Уважний читач помітить зайві змінні ув циклах, courtesy of транспайлера.)
Спочатку я чомусь вирішив що то є робота для Puppeteer. Це була велика помилка. Кожного разу коли я намагаюся притулити його до чогось, закінчується це невгамовним бажанням міцно потримати авторів Puppeteer ойпіай за горло. Кривий скрипта врешті запрацював, але користуватися їм я не раджу.
Потім я згадав про шматки DOM, які нарід багато років (марно) намагаються портувати до ноуда. Певно, Canvas має бути там давно? Виявляється, так, контора яка пише Вордпреса, роздає свою реалізацію всім охочим. (Її дуже складно знайти--1й хіт на npmjs.com на кейворда "кенвес".)
З вордпресівською бібліотекою, безглуздий мотлох Puppeteer зменшується до
function dither(img, algo) {
let cnvas = canvas.createCanvas(img.width, img.height)
let ctx = cnvas.getContext('2d')
ctx.drawImage(img, 0, 0)
let imagedata = ctx.getImageData(0, 0, img.width, img.height)
ctx.putImageData(algo(imagedata), 0, 0)
return cnvas.createPNGStream()
}
IRL, щоб показувати прогреса ув %, там є трохи більше рядків, але мінімалізм мене тішить. Щоб подивитися на життя ув 1984, для ноуда 22:
$ npm -g i atkinson
$ atkinson file.jpg > 1.png
https://stas.dreamwidth.org/1475958.html
Достеменно залишається невідомим, чи переможуть цього року на змаганнях ув жалюгідності сндовські маґа навальністів з дойчландії.
(Продовження саги про віндюка та його інсталяцію.)
Я помітив що аплікація gnome-disks вміє монтувати image files не
питаючи ув polkit дозволу. Виявляється, монтувати loop дівайси можна
через udisksctl без руту, тобто замість
$ sudo mount -t udf Win11_24H2_English_x64.iso /media
друкується
$ udisksctl loop-setup -f Win11_24H2_English_x64.iso
Mapped file Win11_24H2_English_x64.iso as /dev/loop0.
$ udisksctl mount -t udf -b /dev/loop0
Mounted /dev/loop0 at /run/media/alex/CCCOMA_X64FRE_EN-US_DV9
Таким чином, створювати окремі партішони, форматувати їх та копіювати результата до raw image можна також робити зовсім без руту. Наприклад, 2й партішон для ntfs:
$ truncate -s 6G lol.img
$ mkfs.ntfs -fF -s 512 -S 63 -H 255 -p $((boot_size + 2048)) lol.img
де boot_size розмір (ув секторах) 1го партішону.
Raw image генерується sfdisk'ом як
$ boot_size=$(( 1024*1024*1023 / 512))
$ setup_size=$(( 6*1024*1024*1024 / 512))
$ sfdisk w11.img << EOF
label: gpt
1 : start=2048, size=$boot_size, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, name="BOOT"
2 : start=$((boot_size + 2048)), size=$setup_size, type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, name="INSTALL"
EOF
Потім, щоб втулити отой lol.img з ntfs до w11.img, треба вказати
правильний офсета для dd і не забути про conv=notrunc:
$ dd if=lol.img of=w11.img conv=notrunc bs=512 seek=$((boot_size + 2048))
Майкрософт вперше додали механізма autounattend.xml за часів
захоплюючих краєвидів Вісти. Користувач завантажував те що зараз
називається ADK віндюковий, який містив графічну ютіліту WSIM, яка
випльовувала xml-файла. Останній клавсь до кореня usb-драйву і віндюка
(ув ідеалі) інсталювався без втручання хомо сапієнса.
Нічого революційно нового ув тому не було--лайнакси схожі механізми мали багато років, наприклад kickstart ув Федорі.
Прублема ADK є ув тому, що він потребує інстальованої ОС, а способу
генерації autounattend.xml з-під ОС конкурентів Майкрософт не надає,
окрім цінних порад писати його ув текстовому редакторі вручну (дуже
дякую).
Не слідкуючи за їх цирком на дроті, деякий час назад я почув, що з винахідливим змістом того .xml можна отримати інсталяцію віндюка без сучасних та корисних аплікації типу коупайлота або ноутпеда (модерн) чи аутлука (н'ю), та без необхідності ув танцюванні гопака для створювання 'офлайнового' користувацького акавнту.
Різноманітні онлайнові генератóри autounattend.xml змінюються як
пори року. Поточним, працюючим, популярним (ППП) залишається
дойчландський unbeaufsichtigter (вимовляйте це самі)
generator.
На цьому пригоди лише починаються:
Якщо потрібен .iso з доданим autounattend.xml для створення
мошини віртуальної, то як модифікувати оригінальний .iso? Всередені
там є хфайлова система udf, яку змаунтувати можна тільки read-only.
Якщо треба інсталювати віндюка на справжнього комп'ютера (ви не повірите, але такі випадки трапляються непоодиноко), то як створити з оригінального .iso завантажувальний usb?
Нагадаю: ми ув лайнаксі, де жодні rufus'и працюють не тут. Різноманітні ютіліти різної ступені занедбаності або підтримують лише .iso лайнаксних дістро, або написані ув найкращому випадку школярами, ув найгіршому--вініпухами чи руснею (маґа-патріот-джон с тексастской області лєнінґрадскоґо района). Ув 2х останніх різновидах є гарний шанс отримати гарного .iso с безоплатним подарунком всередині.
З найсмішніших варіянтів що я бачив, кількість залежностей є така, що аплікацію, разом з залежностями, завертають ув appimage як ковбасу.
Rufus'и та друзі для режиму UEFI роблять нічого складного: на usb-дівайсі створюється дві GPT партішони:
До 1ї переписують бутлоадера (зазвичай 'універсального', який може вантажити декілька різних ОС). До ntfs копіюють вміст .iso.
Ув нашому варіянті майкрософтський .iso має свого бутлоадера, тому скопіювати можна його. Головний трюка є ув правільному створені партішонів: (1) fat32 не повинен бути з позначками esp та boot, інакше віндюковий інсталятора вирішить що саме на usb-драйві буде EFI розділ для ОС, хоча останню він ставить до геть іншого драйва; (2) без позначки msftdata на ntfs партішоні віндюка кидає "Install driver to show hardware" даялога, а її diskpart малює його як "Unknown". Вкрай неввічливо.
$ parted test.img print | grep -v ^Disk
WARNING: You are not superuser. Watch out for permissions.
Model: (file)
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Number Start End Size File system Name Flags
1 1049kB 1074MB 1073MB fat32 BOOT msftdata
2 1074MB 7516MB 6442MB ntfs INSTALL msftdata
Наївний скрипта, який це втомлююче робить, на жаль, вимагає рута через створення loop devices, але не чіпає хадварних драйвів:
$ sudo ./winiso2img Win11_24H2_English_x64.iso test.img
test.img потім можна перенести на usb-драйв будь-яким улюбленим
способом, наприклад:
$ sudo dd if=test.img of=/dev/XXX status=progress bs=1M oflag=direct,sync
Ув принципі, щоб згенерувати хфайла з потрібною таблицею партішонів
можна обійтися без losetup+parted, а взяти sfdisk та udisksctl, але
mkfs.ntfs -fF file.img у мене не бажало форматувати хфайла так, щоб
його визнавала інсталяція.
Майкрософтські .iso зроблені з хфайлової системи udf, а крихітний шар iso9660 там містить лише хфайла README.TXT з повідомленям про skill issue читача.
Лайнакс знає про udf, але маунтить оті .iso лише ув read-only.
Спочатку я хотів взяти 7-zip. Розаркування великого аркайву (> 5GB)
займає час навіть на сучасних мошинах, тому бажано повідомляти
користувачу що коїться. 7-zip друкує лінію стану розаркування, але
робить це ув найворожіший спосіб. По-1ше, автор 7-zip'у вважає що \r
(carriage return) то є буржуазноє ізлішєство. Ось фрагмент
збереженого аутпуту:
00000000: 2020 304d 2053 6361 6e20 2f68 6f6d 652f 0M Scan /home/
00000010: 616c 6578 2f44 6f77 6e6c 6f61 6473 2f77 alex/Downloads/w
00000020: 696e 2f69 736f 2f77 3131 2f08 0808 0808 in/iso/w11/.....
00000030: 0808 0808 0808 0808 0808 0808 0808 0808 ................
00000040: 0808 0808 0808 0808 0808 0808 0808 0808 ................
00000050: 0808 0808 0808 2020 2020 2020 2020 2020 ......
00000060: 2020 2020 2020 2020 2020 2020 2020 2020
00000070: 2020 2020 2020 2020 2020 2020 2020 2020
00000080: 2008 0808 0808 0808 0808 0808 0808 0808 ...............
00000090: 0808 0808 0808 0808 0808 0808 0808 0808 ................
000000a0: 0808 0808 0808 0808 0808 0808 2020 3025 ............ 0%
000000b0: 2031 3030 204f 7065 6e08 0808 0808 0808 100 Open.......
000000c0: 0808 0808 0808 2020 ......
Воно видаляє рядок за допомогою циклу з \b (backspace), потім друкує
пробіли щоб видалити їх знову.
По-2ге, воно відмовляється малювати лінію стану коли stdout не є терміналом. Зі script(1) це можна побороти і, з деяким зусиллям, я змусив аутпут від 7z бути зумісним з dialog(1) gauge, але після проглядання 7-zip src, огида до нього у мене переросла бажання його торкатися. Це 1 з найгірших src, які я бачив. То є диво що воно працює взагалі, а кількість CVE починаючи з 2022 наводить на конспірологічні думки які я тут писати не буду.
Якщо ігнорувати 7-zip, як тоді модифікувати змонтований read-only .iso? Можна скопіювати все ув іншу директорію, але існує більш шляхетний спосіб: overlayfs.
З ним гагібайти хфайлів не копіються, але метод вимагає рута. FreeBSD ніби мала раніше щось схоже (unionfs), але коли я користувався fbsd, воно часто працювало з помилками.
Після отримання директорії з autounattend.xml хфайлом, її завертають
ув .iso знову.
Скрипта,
який це робить, є на 24 рядки більший за попередній winiso2img:
$ wc -l *
67 mkwiniso
91 winiso2img
158 total
$ sudo ./mkwiniso add lol.xml Win11_24H2_English_x64.iso test.iso
Якщо просто треба з розаркованого Майкрософтського .iso створити новий, рута є непотрібний:
$ ./mkwiniso generate dir 1.iso
712 безглуздих слів про "renewing the Brand".
Дякуючи Зевсу, Гері та іншим богам, ЕйАй, який нищить Stack Exchange, вміє перетворювати воду на сенс:
"Stack Exchange is launching a rebrand because they think their identity is a mess, and it’s hurting their business. Instead of fixing real problems, they’re wasting time and money on consultants and vague “brand strategy” to make everything look more polished while AI eats their lunch. They say they want community input, but this is corporate theater."
З безтурботних часів кінця сивочолого криголама (що мені не подобалось?), для знаходження діректових лінків на .iso, Майкрософт кілька разів змінювали внутрішній ойпіай, загалом, потреба ув якому як була так і залишається незрозумілою, якщо не рахувати необхідність свіжих булітів кожного end-of-year рів'ю.
Щоб завантажити 24h2, треба отримати ойді сесії та список мов, за якими Майкрософт подарує згенерований url ув джейсоні. Як робити найостанніший ріквеста забагато разів на годину (наприклад, нахабно 5 разів), Майкрософт зобанить. Покласти всі .iso на статичного сервера не можна--це буде глузування над здоровий глуздом, потрібна Процедура.
$ grep -Ev '^#|^$' windows-iso-url | wc -l
28
Скрипта вимагає nokogiri.
Спостерігаючи за бійкою між Поттерінґом та термінальними пуристами, я дізнався про таке собі XTGETTCAP. Це є механізма (відносно новий, ~2019?) для отримання можливостей терміналу без консалтінґу terminfo. Це означає, що брехати про тип терміналу з XTGETTCAP не вийде.
Наприклад, якщо хочеться намалювати користувачу саме монохроматичного інфобокса, зараз можна підсунути назву терміналу, для якого ув terminfo зазначено безбарвне життя:
$ TERM=vt100 dialog --infobox 'ну шо ти малá' 0 0
Це працює тому що даялоґа використовує ncurses, який дивиться ув
terminfo. Якби даялоґа стріляв ув термінала XTGETTCAP'апом, замість
читання змінної середовища TERM, такий хфокус би не спрацював:
$ echo $TERM
xterm-256color
$ TERM=vt100 ./XTGETTCAP TN
xterm-256colorЯкщо ув теорії XTGETTCAP--майбутнє вже сьогодні, то на практиці цей
механізма мені не подобається. Можливо in-band signalling було
надією людства ув 1970ті, але зараз щоб імплементувати XTGETTCAP запита
та прочитати результата, треба перемикати термінала ув raw режим,
конвертувати ім'я capability ув hex строку і писати до tty обгорнувши
її з \e (ascii 033 ув октал) з обох боків, поряд з іншим мотлохом:
printf '\033P+q%s\033'\\ "$capablity" > "`tty`"Що для "TN" виглядає як
00000000: 1b50 2b71 3534 3465 1b5c .P+q544e.\Потім треба обережно прочитати результата все ще знаходячись ув raw режимі. Якщо робити це з акуратністю, з якою нарід пише скрипти шелóві, вірогідність того, шо термінал буде заблоковано перманентно, наближається до 1.
Для wayland'у є емулятор терміналу foot, який має окрему C ютіліту для читання XTGETTCAP, але вона наглухо висне, якщо термінала не розуміє запиту. Як можна сподіватися на здібності гіпадріла звичайного, якщо це не можуть порядно зробити навіть люди, які пишуть термінального емулятора.
Окрім xterm (який вимагає увімкненого allowTcapOps, який вирублений
по замовчуванню на всіх ОйБіЄм'івських дістро через цирка на
дроті),
найбільше просунулося у цьому напрямку індійське диво kitty (на яке я
маю алергію після стількох років страждань з calibre (автор той
самий)), та усілякі ghostly та ін. штукенції, якими користуються 12
людей на планеті земля. iterm2 та діфолтне еплівське одоробло також ніби має
підтримку, але мені є лінь перевіряти.
Найсумніше є те, що XTGETTCAP наразі не працює через gnu screen чи tmux, що хоча є вина останніх, популярності XTGETTCAP не додає.
Скрипта, яким можна тестувати:
#!/bin/sh
set -e
eh() { echo "Error: $*" 1>&2; trap - 0; exit 1; }
text2hex() { od -A n -t x1 | tr -d ' \n'; }
hex2text() { sed 's/../0x& /g' | xargs printf '\\\\%03o\n' | xargs printf %b; }
stty_orig=`stty -g`
stty_restore() { stty "$stty_orig"; }
[ -n "$1" ] || eh Usage: XTGETTCAP capability
capablity=`printf '%s' "$1" | text2hex`
trap stty_restore 0
stty -echo raw time 1 min 0
printf '\033P+q%s\033'\\ "$capablity" > /dev/tty
buf=`dd status=none count=1`
stty_restore
[ -n "$buf" ] || eh unsupported terminal
[ "$V" ] && printf %s "$buf" | xxd
buf=`printf %s "$buf" | sed 's/[^a-zA-Z0-9+=]//g'`
[ P1 = "${buf%+*}" ] || eh unknown capabilitah
printf %s "${buf#*=}" | hex2text | xargs
Повинно працювати з пацаватими dash, busybox sh та ін.
hex2text() тут не фонтан, звичайно, але нопешіть як то можна інакше,
щоб (а) було сумісно з fbsd, (б) не вимагало чогось ікстернального, як
xxd.
$ ./XTGETTCAP TN
xterm-kitty
$ V=1 ./XTGETTCAP colors
00000000: 1b50 312b 7236 3336 6636 6336 6637 3237 .P1+r636f6c6f727
00000010: 333d 3332 3335 3336 1b5c 3=323536.\
256
$ ./XTGETTCAP шо?
Error: unknown capabilitahУв вікіпідіа написано шо хадварні термінали VT100 (продавалися з 1978 року) та VT220 (1983) були монохромні (кольорові варіянти, напевно, лише для заможних верств гіпадрілів). Terminfo ув лайнаксі про ці термінали містить ту саму інформацію:
$ for i in dumb vt100 vt220 screen xterm $TERM; do printf "%-20s" $i; TERM=$i tput colors; done
dumb -1
vt100 -1
vt220 -1
screen 8
xterm 8
xterm-256color 256
Кілька днів тому, нєкто Поттерінґ, мастодонів про діфолтне значення
TERM, яке обирає systemd:
'The default fallback $TERM we so far picked has been "vt220" … This deemed us to be a good choice, since (unlike the better known vt100) these kind of terminals support PageUp/PageDown keys'
Загалом, ув terminfo дивляться зазвичай тільки ютіліти які для користувацького інтерхфейсу використовують ncurses; решта вгадує можливості терміналу шляхом слідкування за візерунками руху небесних тіл, e.g.:
COLORTERM (нещодавно обраний шлях systemd);NO_COLOR (я би віддав перевагу, навпаки, щось на
кшталт COLOR=1, бо діфолтне плювання кольорами ув консолі є
страшенний несмак);TERM і шукати збіг ув своїй вкомпайлений (не жарт)
табличці, як то робить ls з coreutils;Лайнаксний ls, звичайно, перемагає ув конкурсі найдебільнішого рішення.
Воно друкує барвами для vt100, тому що протягом компіляції coreutils хапається текстовий хфайла з налаштунками для dircolors(1), який має ось такі рядки:
TERM vt100
TERM xterm*
Цей хфайл (його копія зазвичай є ув /etc/DIR_COLORS) скрипта
перловий конвертує ув символьного масива
$ head -c7 src/dircolors.hin # ув ріпо coreutils
# Confi
$ (head -c61 && printf 🤡 && tail -c39) < <(src/dcgen src/dircolors.hin)
static char const G_line[] =
{
'#',' ','C','o','n','f','i',🤡,'r','i','a','b','l','e','s','.',0,
};
який потім інклудиться як dircolors.h ув ls.c, де є хфункція
/* Check if the content of TERM is a valid name in dircolors. */
static bool known_term_type(void) {
char const *term = getenv("TERM");
if (!term || !*term)
return false;
char const *line = G_line;
while (line - G_line < sizeof(G_line)) {
if (STRNCMP_LIT(line, "TERM ") == 0) {
if (fnmatch(line + 5, term, 0) == 0)
return true;
}
line += strlen(line) + 1;
}
return false;
}
dircolors(1) також парсить нещасну G_line та друкує 0 інструкцій для
ls, коли TERM є відсутня чи несе невідоме значення:
$ env -i SHELL=/bin/sh dircolors
LS_COLORS='';
export LS_COLORS
У чому сенс тоді, навіть за відсутності LS_COLORS, розмальовуювати
множинні character devices з директоріями (довгий масив
color_indicator[] ув ls.c, якщо комусь цікаво), але полишати файли
звичайні (кольори для яких G_line має), залишається невідомим.
Найвизначнішою рисою істот з СНД, навіть якщо останнє вони покинули фізично, залишається гарантована compassion towards victims.
Приклад типовий: https://stas.dreamwidth.org/1468036.html разом з коментарями.
Бовзер Кроум має інтернáльну сторінку chrome://gpu/, яка малює,
поміж інших речей, статуса хадварних відеокодувальників. Якщо драйвер
gpu не опиняється ув блеклисті (це слово можна знову
використовувати?), ближче до кінця там з'являється таблиця з рядками
Decode hevc main 64x64 to 8192x4352 pixels
З інтернáльною сторінкою пов'язано багато смішного. Наприклад, одного разу на безмежні узбережжя скелястих форумів гоогла викинуло монголку:
"Добрий дєнь! вопрос про страніцу chrome://gpu - у мєня поддєржка ЯндєксКарти запросіла пріслать содєржімоє єтой страніци. Єто что, вообщє? Єто бєзопасно? Я вставіла єє в адрєсную строку і получіла коллапс какой-то - цвєтниє полоси, клінья, сєґмєнти і прочую бєлібєрду, послє чєґо всє откритиє страніци інтєрнєта пошлі "плясать" - содєржімоє пєрєкорєжіло. Вірус, что лі?"
Раніше, якщо треба було дивитися на окремі відеофрейми, брався src відеокодеку на C та відчайдушно компілювався ув вебасемблі. Зараз це ліпше робити ні, т.я. бовзер розуміє вдосталь відеокодеків самотужки і має новітнього ойпіай (йому 5 років) для маніпулювання фреймами--WebCodecs.
Ув лайнаксі, Кроум використовує хадварні відеокодувальникі через завдяки за допомогою VAAPI. Якщо дістро має застарілі (або занадто нові) версії Mesa з їх DRI-драйверами, відеокодувальники ув Кроумі будуть софтварними, навіть якщо GPU підтримує їх хадварну акселерацію. З ідіотськими порадами "не викидайте старі комп'ютери, а інсталюйте на них лайнакса", наївний користувач отримує гул кулерів, який був відсутній ув віндюку, де Кроум дружив з драйверами GPU.
WebCodecs має метода статичного VideoDecoder.isConfigSupported(),
яким можна перевірити чи використовує Кроум могутню акселерацію для
конкретного кодека. З VideoEncoder це можна
перевірити для конкретної роздільної здатності.
Наприклад, якщо пастнути текста нижче ув дівтулзову консоль, воно
надрукує трохи більш зручну табличку, аніж простирадла з
chrome://gpu/:
Promise.all([
['AV1', 'av01.0.08M.10'],
['H.264', 'avc1.640033'],
['H.265', 'hev1.1.6.L120.90'],
['VP8', 'vp8'],
['VP9', 'vp09.00.40.08']
].map( async v => ({
name: v[0],
codec: v[1],
support: (await VideoDecoder.isConfigSupported({
codec: v[1], hardwareAcceleration: "prefer-hardware",
})).supported
}))).then(console.table)
(Звичайно шо isConfigSupported() є червона хфункція, т.я. потрібно
нагадувати гіпадрілам постійно шо життя це є боротьба.)
На жаль, console.table() не вертає html, тому щоб написати
уйоб-сторінку, яку зручно відкривати на SBC з ондроїдом або кетайських
тівібоксах, треба малювати все самому.
Мінімальний приклад (працює лише ув Кроумі; Файрфокс видає галімат'ю):
$ wc -l *html
47 index.html
є отут (вибачте що не Реакт). Ув якості домашнього завдання,
додайте вибір варіянтів baseline/main/high кодеків з <select>.
Я уявляю це собі так: ув старі добрі часи для швидкого анкетування
можна було пнути хропучого сисадміна, який би написав html форму та
елементарний сервер (на його улюбленій мові), що з'їдав би post
ріквеста і складав результат ув якійсь директорії. Після
чого сисадмін вертався до своєї комірки сопти далі, а ікзéк'ютів
починав спамити колег адресою
172.20.1.15/surveys/job-satisfaction.html.
Тобто, як то воно була насправді, я гадки не маю. 10+ років тому, коли потрібні були анкети, я робив їх ув гоогл хформах і читав результати ув гоогл шітс. Зараз, звичайно, варіянти коливаються від $0/mo (вся дейта вільно продається кому завгодно) чи $199/mo за "1 active project" з "10K сабмітів" (вся дейта дістається русскім з рансомware угрупувань) до селф-хостинґу з хропучим дівопсом фултайм ув комплекті (вся дейта губиться, коли дівопс звільняється).
Чомусь останній варіянт з селф-хостинґом завжди виглядає як конкурс мошин Руба Голдберґа, хоча такий "проєкта" має бути на рівні можливостей будь-якого школяра. 2 файли ув найпростішому вигляді: form.html та server.js. Ні?
server.js містить статичного http сервера. На GET /simplest шукає
public_html/simplest/index.html та виставляє сесію ув cookie. Автор
анкети пише simplest/index.html руками ув текстовому
редакторі. Найпростіша анкета:
<form method="post">
Name? <input name="name" type="text" required>
<input type="submit">
</form>
Це є класичний postback, тобто POST ріквест форма відсилає на той
самий pathname за яким було GET сторінки. Ув даному випадку це
дозволяє з URL викопирсати ім'я анкети. Ув директорії
public_html/simplest/ можуть бути будь-які файли, які треба для
рендеренгу екстравагантної форми: світлини, відео, джаваскрипт і т.ін.
Число анкет обмежується лише лімітами файлової системи. Додавати анкети можна ув ріалтайм, перезапускати сервера є непотрібно.
Якщо POST був без помилок, application/x-www-form-urlencoded конвертується ув json і ✍️ ув окремій директорії.
Бовзерна валідація хформ працює всюди > 10 років (окрім ондроїдного файрфоксу, тому що кожного року треба усім світом збирати мульйони долярів на зарплату CEO і часу на все не вистачає). Перевірку пейлоаду з post ріквеста можна робити загальнопролетарським json schema, який можна генерувати зі статичного form.html на льоту.
Є купа мотлоху який генерує html з json schema, але не навпаки: я
знайшов нічого, що оналізує якийсь <input type="text" minlength="2" maxlength="50"> і випльовує скіму, але з ноудівським cheerio можна
написати свій генератор за кілька годин. Форми не можуть бути
вкладеними одна в одну, тому складність генератора буде рости лише з
кількістю віджетів.
Наприклад, з
<input type="radio" name="os" value="linux" required> Linux
<input type="radio" name="os" value="macos"> macOS
генерується
{
"type": "object",
"properties": {
"os": { "enum": [ "linux", "macos" ] }
...
},
"required": [ "os", ... ]
}
Ванільний фронтенд не був ви фронтендом, якщо би всі стандартні
віджети працювали однаково. Якщо для множини radio кнопок
підтримується валідація "required", то для множини чекбоксів немає ані
"required", ані перевірки мінімальної кількості увімкнених прапорців
(навіщо bother, як то кажуть ув Калґарі). Я виставляв
data-required="true" та data-min="N" на парентному div.
Коли анкетування є номінально анонімним, auth можна пропустити і просто встановлювати cookie щоб користувач, який згадає шо він цейво, як його, забувсь, шо він хотів написати, міг якийсь час свою анкету редагувати. З
Set-Cookie: sid=2025/01/26/a8b92708-f1dc-4870-abee-907a50a10800; Max-Age=31536000; Path=/js101/
Set-Cookie: signature=3c564fa3f3b534b85fdab82deb575c2ab2af48b7; Max-Age=31536000; Path=/js101/
результати записуються ув db/js101/2025/01/26/XXXX/results.json, які
~легко трансформуються ув csv. Без couchbase, mongo чи mariadb. Жах.
(Здогадайтеся для чого потрібна "signature".)
Анкета стає автоматично 403, якщо хфайл з формою має mtime < зараз. Тобто, валідна анкета має обов'язково мати дату модифікації
ув майбутньому, що є трохи незвично, але звільняє від необхідності
тримати якогось конфігураційного хфайла.
Якщо над директорією з results.json запустити іншого статичного http сервера, то анкета, сімлінка якої пишеться поряд з results.json, може читати results.json і заповнювати ту саму форму результатами тяжкої роботи користувача.
Стандартних має вистачити, але як тільки закортить мінімального дайґрешона, треба готуватися до ведмежих кутів бовзерних ойпіай.
Наприклад, я хотів вертикального слайдера з підписом рисок:
Кастомний уйоб-компонента якого виглядає ось так:
<spartaforms-slider name="knowledge" min="0" max="4" value="0" required>
<span data-value="4">I'm Douglas Crockford 🧙♂️</span>
<span data-value="3"><i>Très bien</i></span>
<span data-value="2">Can code with an LLM</span>
<span data-value="1">Syntax only</span>
<span data-value="0">Nil</span>
</spartaforms-slider>
Всередині то є звичайний <input type=range>, розвернутий на -90°; зі
<span> генерується datalist, з якими слайдер стає схожим на
словацького термометра. Можна було би писати datalist самотужки, та
його відмовляється рендерити ie6 еплівський вебкіт.
Але <input type=range> сидить ув shadow dom уйоб-компонента, тому
форма на сторінці його не бачить! Будь-які зміні ув атрибутах
<spartaforms-slider> треба переносити до <input> (і навпаки)
самому. Щоб дружити з формами існує спеціяльний ойпіай, який став з
~2023 таким популярним, що про нього користоґо є ~0, окрім скупих
речень на whatwg.org.
Якоїсь підтримки ув збереженні інпуту, набраного користувачем ув елементах форми, від бовзера чекати є марно. Доводиться перехоплювати submit івента щоб зберігати їх десь (хоча би ув localStorage) і самотужки відновлювати, коли користувач вирішує ту форму відредагувати. Все це вміють робити різноманітні фреймвоки багато років, а ванільний джаваскрипта полишає нічого, окрім дратування через витрачання часу на цю ґілімат'ю.
Загалом, екперимента визнано невдалим. Що здавалося елементарним 1+N файловим рішенням (де N--кількість анкет), ув реальності з 3ма анкетами виросло на
$ tree --gitignore -I test --dirsfirst
.
├── public_html
│ ├── eng210
│ │ ├── form.css -> ../form.css
│ │ ├── form.js -> ../form.js
│ │ ├── index.html
│ │ └── widgets.js -> ../widgets.js
│ ├── js101
│ │ ├── form.css -> ../form.css
│ │ ├── form.js -> ../form.js
│ │ ├── index.html
│ │ └── widgets.js -> ../widgets.js
│ ├── simplest
│ │ └── index.html
│ ├── 60438.svg
│ ├── favicon.ico
│ ├── form.css
│ ├── form.js
│ ├── index.html
│ ├── posted.html
│ └── widgets.js
├── Makefile
├── mkschema.js
├── package.json
└── server.js
з малонадихаючим розміром джаваскрипта:
$ wc -lc *js public_html/*js
196 5260 mkschema.js
249 8322 server.js
136 4193 public_html/form.js
101 2906 public_html/widgets.js
682 20681 total
Приклад анкети є ось тут. Чи має сенс цей ковгосп викладати на ґітгаб, я не знаю.
Such is human stupidity that whatever is difficult
to obtain is always thought to be better.
-- Peter Martyr d'Anghiera, 1524.
Колись давно, років 8 тому, ув часи сивочолого гетьмана і кволих реформ мусоріату, на HN з'явився лінка на http-сервера розміром 1KB. Не src того сервера був 1KB, а його статично зкомпільований байнарник. Все що той сервер вмів робити це відповідати на будь-який ріквест 1 файлом. Я проявив 0 інтересу, тому що написано воно було на asm/C ув пропорції 60/40.
Ідея такого розміру програм сподобалася французькому автору haproxy і він вмовив нарід ув LKML погодитися закомітити окрему бібліотеку для написання "nolibc" аплікацій. Прикладом такої аплікації є rcutorture--тестування кернела--де генерується невеличкий initrd, написаний на C без використання будь-якої libc.
Іронія ув необхідності спеціяльної бібліотеки щоб не використовувати стандартну бібліотеку нагадує спробу обійти коло, рухаючись по його контуру.
На тему < 1KB байнарників є класичний текста Really Teensy ELF Executables, але у ньому йде мова про асемблера, на який я не бажав звертати уваги ув минулому і на який не бажаю звертати уваги зараз.
Чи можна створювати крихітні (байнарі-вайз) аплікації без асемблеру на
C без стандартної бібліотеки? Майже пусту main() лінкер--лінкує, але:
$ cat 42.v1.c
int main() { return 42; }
$ clang -Os 42.v1.c -o 42.v1.o -c
$ ld.lld -e main -o 42.v1 42.v1.o
$ ./42.v1
Segmentation fault (core dumped)Виявляється, осемблер потрібен щоб кликати сисколи лайнакса:
$ cat 42.v2.c
static inline long syscall(long NR, long arg1) {
long r;
__asm__ volatile("syscall" : "=a" (r) : "a" (NR),
"D" (arg1) : "rcx", "r11", "memory");
return r;
}
int main() { return 42; }
void _start() { syscall(60, main()); }
$ clang -Os 42.v2.c -o 42.v2.o -c
$ ld.lld -e _start -o 42.v2 42.v2.o
$ strip -s 42.v2
$ strace ./42.v2
execve("./42.v2", ["./42.v2"], 0x7ffc7190b9a0 /* 105 vars */) = 0
exit(42) = ?
+++ exited with 42 +++Ага! Такий статичний байнарник має розмір 800 байт і залежить від 0
бібліотек. Номер сисколу (60) для exit можна подивитися ув файлі
arch/x86/entry/syscalls/syscall_64.tbl кернельного src. На відміну
від віндюка, де ABI змінюється з щорічними "feature updates", такий
800-байтовий ікзек'ютабл буде працювати доки є жива орхітектура
x86_64.
Чи складно тоді, маючи обгортки для лайнаксних сисколів, написати елементарного TCP сервера для x86_64? Я вирішив спробувати:
$ _out/uptime-tcp-nolibc &
[1] 53161
$ nc --recv-only 127.0.0.1 1377
07:16:29 up 1 day(s) 22:14, load average: 0.19, 0.31, 0.30Воно вертає шось схоже на команду uptime на ремоутній мошині, але не використовує ніяких екстернальних команд чи бібліотек. Якого розміру uptime-tcp-nolibc та скільки він їсть пам'яті написано ув кінці посту.
Якщо без libc немає жодного способу робити I/O чи відкривати сокета, тоді С стає фанкшонал мовою, про яку мріяли вчоні з 80х років, але, на їх невдачу, кернела набув IP стек та аналоги open(2) з write(2).
42.v2.c не вміє читати argv чи environ, а варіятивні хфункції у ньому роблять кордамп. Останне лікується
__attribute__((force_align_arg_pointer))
void _start() { ... }З argv все є набагато гірше: якщо мета є саме отримувати поінтера на
argv, потрібен знову осемблер (~14 рядків), який я тут постити не
буду, щоб не лякати людей. Технічно, прочитати argv можна просто
відкривши /proc/self/cmdline, ув якому \0 є роздільником аргументів:
$ tr \\0 \\n < /proc/self/cmdline
tr
\0
\nале вас засміють ув інтервебах.
Перша каменюка на шляху до сокетів лежить ув man-сторінках відповідних
libc враперів. Наприклад, bind(2) чекає на аргумента struct sockaddr *,
опис якого ув man-сторінці ip(7) був скопійований з документації
якоїсь 4.3BSD-Tahoe 1987 року і відповідає реальності нутрощів
лайнуксного сьогодення з висоти дзвіниці Києво-Печерської
лаври. (Потрібний додатковий паддінґ' unsigned char __pad[8].)
Якщо libc-врапери вертають -1 на помилку та виставляють errno, то сисколи вертають errno × -1. Ув справжніх libc errno є локальна для поточного треду. Для мікімаусного nolibc серверу писати свою версію позікс тредів це як збирати гелікоптер AK1-3 на подвір'ї поміж 2ма хрущовками, тому тут errno--глобальна змінна. Як зберігати інтерхфейса, до якого звикли всі, хто коли-небудь писав мережеві майкросервіси на C, то найпростіший враппер виглядає як
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
int r = my_syscall(43, sockfd, (long)addr, (long)addrlen, 0, 0, 0);
if (r < 0) {
errno = -r;
r = -1;
}
return r;
}Ув класичних Unix-серверах, якщо вони писалися не для inetd, конкурентна модель є форкова модель, яка вимагає прислуховуватися до SIGCHLD і чекати доки child завершить роботу, інакше після кожного ріквесту буде залишатися зомбі.
Форкова модель була популярна, тому що дозволяла серверу не лякатися сіґфолта, якщо сервер мав бага на який натрапив клайент: зупинявся лише child-невдаха, всі інші продовжували працювати.
Для встановлення колбеку на окремий сигнал лайнакс має свій rt_sigaction сискола.
Ув аргументах той має
поінтера на struct sigaction з дуже підступним філдом
void (*sa_restorer)(void);Ув man-сторінках про нього написано ось таке:
'This flag is used by C libraries [тобто, нами] to indicate that the
sa_restorerfield contains the address of a "signal trampoline".'… the C library's sigaction(2) wrapper function informs the kernel of the location of the trampoline code by placing its address in the
sa_restorerfield of the sigaction structure.'
Шматок з мікімаусного врапера:
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
// ...
struct kernel_sigaction kact, koact;
kact.k_sa_handler = act->sa_handler;
memcpy(&kact.sa_mask, &act->sa_mask, sizeof(sigset_t));
// ...
kact.sa_restorer = &restore_rt; // THE MOST IMPORTANT STEP
int r = my_syscall(13, sig,
(long)(act?&kact:NULL), (long)(oact?&koact:NULL),
_NSIG/8, 0, 0);
// ...
}Звідкіля береться адреса хфункції для kact.sa_restorer? Це є та сама
"signal trampoline", про необхідність якої попереджає лайнаксна
документація. Звичайно, можна її не виставляти, але тоді жоден з
сигналів не буде пійманий і жоден з колбеків не буде виконаний.
Спочатку я наївно написав
void restore_rt() {
my_syscall(15, 0, 0, 0, 0, 0, 0); // 15 це rt_sigreturn
__builtin_trap();
}сигнали перехоплювалися, колбеки виконувалися,
СЄЧЄНОВ Цей гіпноз корисний дуже, У хазяйстві вєрно служить, Злакі мощно прорастають І надої возрастають!
але після завершення останніх сервер гепався через сіґфолта. На жаль, тут був потрібен осемблер знову:
__asm__(
".globl restore_rt\n"
"restore_rt:\n"
" movq $15, %rax\n"
" syscall\n"
" hlt\n"
);Чому не працює С-версія я не знаю. Клод ЕйАй вважає вона "may modify registers or the stack layout."
Життя без snprintf--життя варварів.
-- Невідомий філософ.
Ув src кернелу є приклад мінімалістичної vfprintf на 101 рядок, але
вона не підтримує floats, які має друкувати uptime. Замість додавання
їх підтримки, ліпше пошукати справжню snprintf, яка не використовує
malloc. Така є ув pkg Федори (із усіх можливих місць саме тут) і
називається stb_sprintf-devel. Це самотній .h файла, який
зкомпільовується ув 18168 байт. Жахливе марнування ресурсів, але
нічого не вдіяти. Тій хфункції потрібні va_start з друзями, але gcc та
clang мають __builtin_va_* ув комплекті:
#define va_start(v,l) __builtin_va_start(v,l)Після інкорпорації stb_sprintf життя заграло новими барвами.
Дізнатися час ув секундах з початку буту можна зі сисколом sysinfo, поточний час--зі gettimeofday. Останній провайдить навіть кількість хвилин на захід від Ґрінвічу! Така розкіш.
Розмір нестріпованого статичного байнарника: 21736 байт. (Я до сих пір не можу повірити як це можливо.)
$ make info
wc -lc *.[ch] | while read -r lines bytes file; do \
elf=-;\
echo $file | grep -q '\.c$' && elf=`stat -c%s _out/${file%.*}.o`;\
echo $file $lines $bytes $elf;\
done | column -t -N\ ,LINES,BYTES,ELF
LINES BYTES ELF
main.c 134 3657 5896
signal.c 76 1699 1704
signal.h 113 2649 -
snprintf.c 6 120 18168
snprintf.h 12 274 -
sockets.c 37 896 1728
sockets.h 45 1119 -
u.c 98 2152 4496
u.h 46 1353 -
uptime.c 67 2148 2128
uptime.h 6 79 -
total 640 16146 -Якби не stb_sprintf, розмір був би < 10KB.
Але це є не найбільша цікавинка. Ось кількість пам'яті, яку їсть такий конкурентний tcp-сервер після відповіді на 100 одночасних ріквестів:
$ sudo ps_mem -p `pgrep -f uptime-tcp-nolibc`
Private + Shared = RAM used Program
36.0 KiB + 4.5 KiB = 40.5 KiB uptime-tcp-nolibc
---------------------------------
40.5 KiBДуже сміюся. Ув сучасному світі, якщо споживання серверу, який робить 0 складного, < 80 _мегабайт_, то це є видатний вчинок і безстрашний прояв волі, за який треба сертифікат хоноровий, медаль та грошовий бонус для походу ув підпільне казино з повіями.
Пан @vak нещодавно знайшов дотепну заміну fortune(1), де парсячи реддітовського джейсона окремого ком'юніті, можна собі ув терміналі друкувати ~свіжі жарти.
У коментарях там мументально переписали пáйфона на шелл, тому мінімальний скрипта, з доданими очікуваннями на деякі помилки, виглядає ось так:
Якщо реддіт вертає не зовсім того джейсона, який ми очікували, ми
друкуємо нічого. w3m потрібен щоб перетворювати & і друзів на
відповідні символи.
Скрипта має 2 недоліки:
Завантажування можна закешити і перевіряти застарілість кешу на кожному запуску. jq вміє самотужки парсити окремо кожний файловий аргумента. Переписати скрипта ліпше за все як мейкфайла, тому шо лише дурень пише на баші те, шо може зробити Мейка (ніхто так не каже):
#!/usr/bin/make -sf
r := showerthoughts CrazyIdeas oneliners
update := 600
wits := /tmp/reddit-wisdom/all.txt
age := $(shell expr `date +%s` - `date -r $(wits) +%s 2>/dev/null || echo 0`)
$(shell [ $(age) -gt $(update) ] && rm -f /tmp/reddit-wisdom/*)
all: $(wits)
sort -R < $< | head -1 | w3m -dump -T text/html
$(wits): $(patsubst %, /tmp/reddit-wisdom/%.json, $(r))
jq -r '.data?.children[]?.data | "\"\(.title)\" -- \(.author)" | gsub("\\n"; " ")' $^ > $@
/tmp/reddit-wisdom/%.json:
mkdir -p $(dir $@)
echo Fetching r/$*
curl -sf 'https://www.reddit.com/r/$*/top.json?sort=top&t=week&limit=100' > $@
.DELETE_ON_ERROR:(Ув fbsd потрібно встановити gmake та відредагувати shebang.) cowsay з lolcat'ом я прибрав. Завантажений джейсона застаріває кожні 600 секунд, але IRL краще виставити 48 годин.
$ ./reddit-wisdom
Fetching r/showerthoughts
Fetching r/CrazyIdeas
Fetching r/oneliners
"We’re constantly playing a tug of war against companies by paying YouTube to
not show ads while they pay YT to show them. " -- SillySlothySlug
$ ./reddit-wisdom
"make a law where everybody gives money to me" -- Due_Intention_2473
$ wc -l < /tmp/reddit-wisdom/all.txt
186Найскладніше тут знайти слушні ком'юніті, які мають цікаві тайтлс постів. showerthoughts інколи буває NSFW.
FreeBSD is very compatible with standards such as POSIX.
-- FreeBSD Developer Handbook
На будь-якому лайнаксі з будь-яким sh-похідним шелом, скрипта нижче друкує hello world:
$ cat -n 1.sh
1 set -e
2
3 hello() {
4 false
5 echo hello
6 }
7
8 true | hello && echo world
$ sh 1.sh
hello
world
fbsd зі своїм /bin/sh робить потужний кєк на рядку 4:
$ sh 1.sh
$ echo $?
1
$ sh -x 1.sh
+ set -e
+ true
+ hello
+ false
$ uname -rs
FreeBSD 14.1-RELEASE-p5
Їхній sh(1) має ось таке речення ув роздлі про set -e:
"If a shell function is executed and its exit status is explicitly tested, all commands of the function are considered to be tested as well."
Я, звичайно, не є перший хто це випадково помітив: схожі 4 скарги ув їхній баґзилі date back to 1999-2005, всі обнадійливо позначені як FIXED.
Хто і навіщо fbsd використовує для роботи, окрім контори Соні та ображених на Торвальдса русскіх, залишається незрозумілим.
Іграшка нова: маючи колекцію з NN тисяч хфото, локально описувати на лайнаксі що коїться на кожній світлині без допомоги Епла, Гоогла або распазнай-с-єйай.лох:
$ alias omglol='find -name \*txt | xargs -n50 grep -li'
$ omglol selfie
./10/IMG_20241019_204444.txt
./09/IMG_20240930_082108.txt
./09/IMG_20240930_082118.txt
./07/IMG_20240712_154559.txt
./07/IMG_20240712_154554.txt
кожний .txt файл лежить поряд з .jpg, який було відправлено до ollama.
Або для слайдшоу:
$ omglol selfie | sed s/txt/jpg/ | xargs feh
Опис можна пхати до exif UserComment, звичайно, але я не хотів модифікувати оригінали.
На жаль, з поточним ollama'овським cli прикріпляти світлини немає куди. Замість cli пропонують робити json пост-ріквести до ollama'овського ендпоінту, перед чим кожне зображення треба спочатку base64-конвертувати.
Другий недолік діфолтного cli--неможливість читати stdin. Я не розумію чому стандартний паттерна будь-якого текстового редактора 'селекнутий текста передати до stdin зовнішній ютіліти', є наразі бонусна фіча вчорашніх крипто-бро, сабскріпшона на яку вони залюбки продадуть простодушному користувачу.
Третій недолік--ігнорування ліміту вихідного тексту для деякого інпуту, для якого ніякі поради конструювання підказок не працюють, а num_predict ув api просто обрізає генерацію, що можна зробити без їх допомоги і так. Зі своїм враппером стає можливим підсумувати підсумки, на чому я і зупинився:
$ ./llm llama3.2 'summarize the following:' < VI.txt | ./llm llama3.2 'summarize the following in 40 words using the present tense:' | fmt -w50
Hernán Cortés and his men arrive on Cozumel
after rough seas delay them; they're rejoiced to
see Geronimo de Aguilar, a Christian prisoner
who's fluent in Yucatecan. Cortés sees great
potential for Aguilar as an interpreter and
prepares to proceed with his expedition.
Нещасний llm врапер--58-рядковий шелóвий скрипта (осьо є його svg), куди ув якості домашнього завдання можна додати async спінера.
Зі скриптом та невеликим мейкфайлом, процеса аналізу світлин виглядає як:
$ find . -iname \*.jpg | sed 's/\.[^.]*$/.txt/' | xargs -r -d\\n -n50 llm-image
де llm-image це:
#!/usr/bin/make -f
model := llama3.2-vision
define desc
@printf "%s\n\n" $(model) > $@
echo 'describe the image' | llm -i $< $(model) | tee -a $@
endef
%.txt: %.jpg; $(desc)
%.txt: %.JPG; $(desc)
Фасебооківська llama3.2-vision не є єдина модель, знатна описувати зображення (llava:13b, наприклад, вміє це також і працює ув 5 разів швидше), але вона здалася мені найбільш корисною ув виробництві keywords для пошуку.
Як нарід робить векторні скріншоти терміналу? Ось такі:
Я гадав є конвертори аутпуту зі script(1) ув SVG, але нічого такого не знайшов. Результат з asciinema нормально конвертується лише ув бітмапові зображення. Мотлох ansi-ту-шото на пáйфоні та расті або видає скуйовджені світлини або не розуміє ті ansi сіквенсес, що відповідають за рух курсору. Покинутим termtosvg можна генерувати купу svg, але він покладається на пáйфонівський in memory емулятора терміналу, який має купу багів.
Сучасний xterm вміє робити "SVG Screen Dump", але з наївним
позіціонуванням літер. Наприклад, рядок '$ uname' він серіялізує як:
<g fill='rgb(60.00%, 60.00%, 60.00%)'>
<text x='2' y='17'>$</text>
<text x='22' y='17'>u</text>
<text x='32' y='17'>n</text>
<text x='42' y='17'>a</text>
<text x='52' y='17'>m</text>
<text x='62' y='17'>e</text>
</g>Це означає, що кернінґа шрифта до уваги не береться і результат виглядає чудернацько.
Сучасний xterm також вміє робити "XHTML Screen Dump" (ув меню Ctrl + Миша-1), який гендериться ув бовзері майже ідеально (з замалим line-height). Додати необхідного стилю до .xhtml файлу ж нескладно, але як конвертнути той xhtml ув svg?
Бовзери вміють друкувати ув pdf. Кроум має headless режима, а гооглова
бібліотека puppeteer (з дебільним інтерфейсом), має Page#pdf()
метода. Нам лише потрібно вибрати розмір в'юпорту та опцію 'друкувати
background graphics'.
$ cat html2pdf
#!/usr/bin/env node
import util from 'util'
import fs from 'fs'
import puppeteer from 'puppeteer'
async function pdf(url, output, opt) {
let bowser = await puppeteer.launch()
let page = await bowser.newPage()
let print_settings = Object.assign({
path: output,
printBackground: true,
width: 1920,
height: 1080,
}, opt)
await page.emulateMediaType('screen')
await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36')
try {
await page.goto(urlise(url), { waitUntil: 'networkidle0' })
await page.pdf(print_settings)
} catch (e) {
err('Error:', e.message)
}
await bowser.close()
}
function urlise(s) {
return (/^https?:/.test(s)) ? s : 'file://' + fs.realpathSync(s)
}
function err(...msg) { console.error(...msg); process.exit(1) }
let args = util.parseArgs({
options: {
width: { type: 'string', short: 'w' },
height: { type: 'string', short: 'h' },
},
allowPositionals: true
})
if ( !(args.positionals[0] && args.positionals[1]))
err('Usage: html2pdf URL output.pdf')
pdf(args.positionals[0], args.positionals[1], args.values)Скрипта підтримує -w та -h опції і конвертує будь-яку
уйоб-сторінку, а не тільки локальні файли. Якщо не виставити
user-agent, по-замовчуванню буде HeadlessChrome, на що деякі сайти
неприємно реагують.
PDF, на жаль, не буде мати розмір конь тенту, а буде містити borders (як це українською? межа?) Прибрати їх простіше всього Inkscape'ом:
$ inkscape --actions "select-all;fit-canvas-to-selection" 1.pdf -o 2.pdf$ pdf2svg 2.pdf 1.svgВоно автоматом перетворює текст ув path. Зменшити розмір .svg можна svgcleaner'ом.
На кроці нумеро дуе можна було би зразу конвертнути рельтат ув svg, але він тоді виходить гаргантюажного розміру.
Енівей, фінальний мейкфайла:
$ cat xterm-xhtml-to-svg
#!/usr/bin/make -f
font := monospace
$(if $(and $(i),$(o)),,$(error Usage: xterm-xhtml-to-svg i=1.xhtml o=1.svg))
__dir__ := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
$(o): $(i).dirty.svg; svgcleaner --quiet $< $@
%.nokogiri.xhtml: $(i)
ruby -rnokogiri -e 'd = Nokogiri.XML(STDIN.read); d.css("#vt100 > pre").first["style"] = "font-family: '$(call se,$(font))'; line-height: 1.2"; puts d.to_xml' < $< > $@
%.uncropped.pdf: %.nokogiri.xhtml; $(__dir__)/html2pdf $< $@
%.pdf: %.uncropped.pdf
inkscape --actions "select-all;fit-canvas-to-selection" $< -o $@
%.dirty.svg: %.pdf; pdf2svg $< $@
se = '$(subst ','\'',$1)'
.INTERMEDIATE: $(i).dirty.svgКоли рік тому до імаксу додали інтерактивну хфункцію emoji-insert, я
подумав що hell froze over. Окремий emoji інпут, звичайно, мають всі
ОС багато років. Ув лайнаксі це залежить від середовища стільниці, і
якщо ними (середовищами стільниці) не користуватися, то невблаганну
залізну хватку прогресу можна не помітити.
Нещодавно на хакір н'юз хтось презентував свого менхетнського проекту:
emoji-клавіятуру написану на голому XCB. На що хтось ув
коментарях зазначив
що то є вражаюче досягнення, але маючи список пар
emoji1 опис1
emoji2 опис2
…то emoji вставляються за допомогою будь-якого динамічного меню без спеціяльної клавіятури.
Раніше таким меню була аплікація dmenu (яку я колись ламав для інкрементного аналога alt-tab для FVWM), але зараз гіпадріли користуються rofi, який є ув пекеджах будь-якого дістро:
$ ls /etc | rofi -dmenu -iОдного rofi буде замало, треба механізма вставки тексту, який друкує rofi на stdout, до активного вікна. Ув xorg це вміє робити xdotool:
$ ls /etc | rofi -dmenu -i | xdotool type --file -Де взяти список пар? Федора має unicode-emoji пекеджа (unicode-data ув
Деб'яні) з файлом emoji-test.txt:
Зліва від середника там список codepoints. Наприклад, щоб отримати чорного кота 🐈⬛, треба взяти звичайного кота (0x1F408, 🐈), додати ZERO WIDTH JOINER (0x200D) та чорного квадрату (0x2B1B, ⬛).
На жаль, %b та \Uxxxx ув printf є непортабельні:
$ e="printf '%b\n' '\U1F408\U200D\U2B1B'"
$ bash -c "$e"
🐈⬛
$ bash -c /bin/"$e"
/bin/printf: missing hexadecimal number in escape
$ dash -c "$e"
\U1F408\U200D\U2B1B
$ busybox sh -c "$e"
\U1F408\U200D\U2B1B
$ zsh -c "$e"
🐈⬛
$ ksh -c "$e"
\U1F408\U200D\U2B1BАле якщо перевести всі hex до int та роздрукувати кожен байт з int ув octal, це буде працювати навіть ув busybox:
$ echo $'\360\237\220\210\342\200\215\342\254\233'
🐈⬛
Файл emoji-test.txt містить 3773 придатних для використання
emojis. Щоб не генерувати статичні пари ув якомусь my-dull-list.txt,
які будуть задавнюватися при кожному оновленні пекеджу, краще написати
швидкого шелóвого фільтра.
Look, ma--no execve() after fork()s:
$ cat codepoint.sh
codepoint_to_oct() {
local dec="`printf %d 0x${1:-0}`"
local b1 b2 b3 b4
if [ "$dec" -lt $((0x80)) ]; then # 1-byte
b1=$dec
elif [ "$dec" -lt $((0x800)) ]; then # 2-byte
b1=$((0xC0 | (dec >> 6)))
b2=$((0x80 | (dec & 0x3F)))
elif [ "$dec" -lt $((0x10000)) ]; then
b1=$((0xE0 | (dec >> 12)))
b2=$((0x80 | ((dec >> 6) & 0x3F)))
b3=$((0x80 | (dec & 0x3F)))
elif [ "$dec" -lt $((0x200000)) ]; then
b1=$((0xF0 | (dec >> 18)))
b2=$((0x80 | ((dec >> 12) & 0x3F)))
b3=$((0x80 | ((dec >> 6) & 0x3F)))
b4=$((0x80 | (dec & 0x3F)))
else
return 1 # out of range
fi
printf \\%03o "$b1" $b2 $b3 $b4
}
emoji_print() { printf %b "`for i; do codepoint_to_oct "$i"; done`"; }Кросиві var assignments ув codepoint_to_oct() написав chatgpt, після
чого Гостре Око помітив що генерувати взагалі потрібно нічого, тому що
emoji-test.txt має для кожного codepint готовий emoji.
$ cat emoji-list.sh
: "${DB:=/usr/share/unicode/emoji/emoji-test.txt}"
grep '; fully-qualified ' "$DB" \
| grep -v 'skin tone' \
| sed -E 's/.+# ([^ ]+) E[^ ]+ (.+)/\1\t\2/'Як відфільтровувати безцінні варіянти з кольором шкіри, список виходить дещо коротший:
$ ./emoji-list.sh | wc -l
1898
$ ./emoji-list.sh | tail -3
🏴 flag: England
🏴 flag: Scotland
🏴 flag: WalesЩоб не викидати codepoint.sh, над яким тяжко пітнів чатбот, можна
зробити додаткового хфінта: друкувати список не лише emojis, а велику
частку utf8:
$ ./unidata-list.sh | grep TELEPHONE
℡ TELEPHONE SIGN
⌕ TELEPHONE RECORDER
☎ BLACK TELEPHONE
☏ WHITE TELEPHONE
✆ TELEPHONE LOCATION SIGN
📞 TELEPHONE RECEIVER
🕻 LEFT HAND TELEPHONE RECEIVER
🕼 TELEPHONE RECEIVER WITH PAGE
🕽 RIGHT HAND TELEPHONE RECEIVER
🕾 WHITE TOUCHTONE TELEPHONE
🕿 BLACK TOUCHTONE TELEPHONE
🖀 TELEPHONE ON TOP OF MODEMДовжина списку таких пар є 34,856. Джерело є текстовий хфайл
UnicodeData.txt з unicode-ucd пекеджу ув Федорі (unicode-data ув
Деб'яні):
$ grep TELEPHONE /usr/share/unicode/ucd/UnicodeData.txt | head -3
2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;
2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;
260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;Якщо генерувати списка лінійно, це буде займати кількадесят секунд. Хоча rofi вміє не чекати, а показувати рядки як вони з'являються на його stdin, процес ліпше пришвидшити:
$ cat unidata-list.sh
__dir__=$(dirname "$(readlink -f "$0")")
: "${DB:=/usr/share/unicode/ucd/UnicodeData.txt}"
sed 1,33d "$DB" | while IFS=\; read -r codepoint desc _ _ _ _ _ _ _ _ alt _; do
[ -n "$alt" ] && [ '<' = "`printf %c "$desc"`" ] && desc=$alt
printf '%s %s\n' "$codepoint" "$desc"
done | grep -Eav '^.+\s<' \
| xargs -r -d \\n -n1 -P "`nproc`" "$__dir__/codepoint.sh"до чатботівского codepoint.sh додати:
…
set -e
codepoint=${1%% *}; [ "$codepoint" ]
char=`emoji_print "$codepoint"`; [ "$char" ]
printf '%s\t%s\n' "$char" "${1#[0-9A-F]* }"Якщо навіть з такою кенкаренсі все одно доводиться чекати, споглядаючи цифри прогресу ув rofi, рекомендую користуватися нормальними комп'ютерами, а не raspberry pi.

Намагаючись приготуватися до неминучого колапсу Кроума, згадав шо є бовзер Файрфокс, фундацьоне якого минулого року збирало усім світом на зарплату своєї CEO.
Чому колапсу? Кроум переходить на "новий" API для ікстеншонів (моніфест 3.0), депрікуючи "старий". За винятком Ublock Origin, всі ікстеншони у мене є самописні (99% того що має гооглівський могозин є malware; я не перебільшую). Ublock Origin працювати з "новим" API не збирається, а я маю 0 стимулу та зиску ув портуванні самописного. 1 з ікстеншонів використовує той самий API що і Ublock Origin, але для додавання/редагування http headers.
З цим ікстеншоном були 2 смішні гішторії. Його статистика плаває від 30 користувачів до раптом 900, 1200, 1900 і знову вниз до 30, а т.я. ніякої телеметрії там немає, чому їм починають користуватися на короткий час ув Азії, я не знаю. Якось після такого бурсту активності мені прийшов листа від якогось кетайця, який чемно запропонував продати йому ікстеншона за €600 (я не відповів).
Іншого разу до мене приколупася гамериканська коб'єта, у якої не працювало замовлення з якогось локального склепу, тому що її бовзер видаляв referer і вона якимось незбагненним чином знайшла того ікстеншона та вкрай наполегливо у мене розпитувала як її referer повернути взад. Я чесно намагався їй допомогти, але ув кінці здався і порекомендував встановити Файрфокса, на що вона відповіла "Foxfire [sic] works, thank you!", а я перехрестився.
Чому колапсу Кроума? Я, звичайно, трохи перебільшую, але маю сумніви, що після стількох років з інтервебом без реклами, ореал ойті та їх сімей добровільно погодиться на, та буде сумлінно спостерігати, наприклад, рекламу ув ютубі. Скільки це додасть мульйонів користувачів ФФ це є цікаве питання, але я очікую невеличкого ренесансу.
Як справи ув ФФ на лайнаксі?
Для свого кроуму він використовує gtk3, який фундацьйоне Ґноума та контора Червоний Капелюх вважає депрікейтед. (Для тих хто живе під скелею та є не ув уйоб-дівелопмент дискурсі: кроум--специфічний крос-бовзерський термін, який означає будь-які елементи gui, які не стосуються DOM'у уйоб-сторінки. Наприклад, меню з букмарками або url-бар. Відповідно, кроумлес є вікно лише з уйоб-сторінкою. Фулскрін режим F11 є прикладом кроумлес.)
Gtk3 означає 0 покращень для кроуму, т.я. дівелопмент тулкіту багато років переїхав на gtk4 та майбутнього gtk5. Старий gtk3 бажають викинути геть, але наразі через аплікації типу ФФ це зробити не вдається, хоча люди намагаються.
Наприклад, одного дня ФФ перестав показувати pointer курсор
(використовується при наведенні на лінка). Раніше мені було все
одно--я пускав ФФ лише для перевірки рендеренґу. Виявляється це
сталосі тому, що ув діфолтний gtk3 темі загубили той курсор для
xorg. Хтось накричав на Ґноум, але їм було по-барабану, тому ФФ
спеціяльно додав widget.gtk.legacy-cursors.enabled конфіґураційного
параметра, який по-замовчуванню є false--доля лайнаксоїдів не ув
wayland є страждати.
Але найгірша ситуація є зі шрифтами. Gtk3 підтримує fontconfig і
ФФ'шний кроум рендерить заміни згідно користувацьких
~/.config/fontconfig/fonts.conf та налаштувань ув
~/.config/gtk-3.0/, як того юзер очікує. Механізма рендеренґу
шрифтів ув бовзерному двигуні ФФ технічно питає fontconfig також,
але за своїми правилами, тому на практиці результати відрізняються
від Гоогл Кроуму та Майкрософтського Edge.
За часів w2k/winxp на fbsd/лайнакс копіювали віндюкові шрифти Arial, Times New Roman, Courier New, &c (така колекція називалася core fonts), і МС деякий проміжок часу дозволяла їх завантажувати легально. Копіювали всі: вільними лайнаксними шрифтами можна було катувати.
Деб'ян має core fonts ув своїх пекеджах (Федора--ні), але ті шрифти застигли ув версіях чи то w98 чи то w2k і відповідних версіях юнікоду. За цей час з'явилося вдосталь metric-compatible families і технічно навіть оновлена колекція core fonts стала непотрібна.
З /usr/share/fontconfig/conf.avail/30-metric-aliases.conf:
| Microsoft | Liberation | Google CrOS core | StarOffice |
|---|---|---|---|
| Arial | Liberation Sans | Arimo | Albany |
| Arial Narrow | Liberation Sans Narrow | ||
| Times New Roman | Liberation Serif | Tinos | Thorndale |
| Courier New | Liberation Mono | Cousine | Cumberland |
| Cambria | Caladea | ||
| Calibri | Carlito | ||
| Symbol | SymbolNeu |
Але я звик до core fonts. Не оригінальних, а свіжих, які я регулярно оновлював коли оновлювався віндюк. Ув fonts.conf достатньо було мати на кшталт
<alias>
<family>sans-serif</family>
<prefer><family>Arial</family></prefer>
</alias>і гоогловський Кроум рендерував sans-serif Arial'ом замість лайнаксового Liberation Sans, Nimbus Sans чи DejaVu Sans.
Звісно з ФФ це не працює (навіщо). Той наполегливо ставить 1й ліпший
sans-serif шрифта, який fontconfig знаходить ув
/etc/fonts/conf.d/. Якщо того шрифта дісейблнути ув fonts.conf, ФФ
бере наступного. На їхній баґзилі відкритий баґ висить 10й рік.
Подолати це можна тільки створивши ув /etc/fonts/conf.d/ хфайла з
ім'ям, яке буде сортуватися (in numeric order) до хфайлів з "family
substitution", наприклад, 12-msfonts.conf:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fontconfig SYSTEM "../fonts.dtd">
<fontconfig>
<alias>
<family>sans-serif</family>
<prefer><family>Arial</family></prefer>
</alias>
<alias>
<family>Arial</family>
<default><family>sans-serif</family></default>
</alias>
…
</fontconfig>Це було 1не з 1ших речей, що було, з 1го погляду, безнадійно зломано на ФФ у порівнянні зі Кроумом. Як то буде далі, прогнозувати не хочу, можливо є крихітний шанс що гоогл передумає з моніфестом 3.0 і переїжджати на ФФ не доведеться (шансів немає).
Сміявсь
ОйБіЕм:
'In 1964, for example, one of our branch managers staged a burlesque show at a sales conference in the Midwest.
The skit was too vulgar to believe--about an Indian village, starring the manager himself as the chief and some scantily clad models as squaws. They even had live chickens running around on the stage. At the end of the skit the manager disappeared with one of these models into a tepee, and as he turned to go into the tent, the audience saw a sign on his back that said something like "Branch Manager: I do all things for all people." Then he and the girl pulled the tepee flap closed behind them.
There were families present, and somebody who witnessed the show wrote me a letter saying, "Is this what you call IBM dignity?" So I started a big inquiry.'
(З Father, Son & Co.: My Life at IBM and Beyond Томаса Ватсона молодшого.)
Якщо набрати link checker ув гооглі, то виявиться що перевірка посилань є серйозний бізнес. Запускання скрипта, який пишуть на 1му курсі, коштує від $13 до $159 на місяць. За $13 дозволяється це робити кожні 2 тижні, а за $159 с барскоґо плєча до 1 разу на день.
Для тих хто готовий нарешті "стати професіоналом", контора зовсім іншого гатунку пропонує вдосконалені та ентерпрайзні рішення за $449 та $1249 на місяць відповідно. Тоді відкриваються потужні можливості відправляння csv-звіту до "колеги чи фрілансера".
Є статичний уйоб-сайта з 375ма сторінками, який має 241 ікстернальний лінка. Зазвичай подібні сайти перевіряють локально на рівні .md хфайлів, з яких він генерується, і ютіліти, які це роблять, працюють доволі швидко, т.я. їм не треба повзати по http зі сторінки до сторінки, створюючи графа. Про них ми говорити не будемо.
Щоб перевірити задіплойеного сайта, а не директорію з .md-хфайлами, додається прублема рекурсивного знаходження посилань та питання коли зупинятися. Спочатку, я вирішив пошукати щось готове ув пекеджах Федори: якийсь пáйфонівський скрипта linkchecker, який за майже 4 хв на локалхості і рівнем рекурсії 20, знайшов 60 лінків загалом, замість 241.
Потім я подивився на W3C'шний link-checker (категорія програм, що є сповнена різноманітністю імен). Окрім уйоб інтерхфейсу він має CLI компонента--перл-скрипта, який витратив 13 хв для народження лоґу з 27859 рядками, де посеред машино-нечитабельного мотлоху пропонується шукати зламані посилання. Можливо, як за таке чарджити клаентів по $1249, то це має сенс; найняти когось буде нескладно.
Ґітхаб є повний "fast" та "async" чекерів, найпопулярнійший з яких (1.9K зірочок) не підтримує рекурсії, але друкує затишні 🔍, ✅, 🚫, 💤 емоджі ув консолі та рожеву progress bar. Рисою професіоналізму посеред сучасних лікн-чекерів є порада використовувати їх з докер-контейнеру, тому що для відправляння http ріквестів наш час вимагає >= 216 бібліотек на будь-якій мові пограмування.
Чи складно написати свій, наприклад, на bash? Хоча він буде мати міцний вайб нульових, коли завантажена сторінка якимось wget майже відповідала сторінці яку рендерив бовзер, для перевірки сторінок, наприклад, документації, такий чекер все одно буде залишатися корисним. Назвемо його badlinks:
$ wc -l lib.bash url* badlinks
21 lib.bash
28 urlcheck
14 urlextract.rb
54 urlextract-recursive
24 badlinks
141 totalНа чистому bash це зробити майже неможливо: переписування nokogiri на шелі я залишаю комусь іншому, а ліпшого парсера кострубатого html, аніж nokogiri, не існує ув природі.
badlinks складається з 3 компонентів:
text/html, та занурюється до них; на кожному етапі він друкує
знайдені leafs;$ curl -sL google.com | ./urlextract.rb q:
https://www.google.com/imghp?hl=uk&tab=wi
http://maps.google.com.ua/maps?hl=uk&tab=wl
…
q:/intl/uk/about.htmlq: тут означає будь-яку base, відносно якої друкуються релатівні
посилання.
$ cat urlextract.rb
#!/usr/bin/env -S ruby -rnokogiri -raddressable/uri
include Addressable
def eh = abort "Usage: #{$0} base_url < html"
base = URI.parse $*[0] rescue eh
eh unless base&.scheme
Nokogiri::HTML(STDIN.read).css('links,a,img,iframe,script,video,audio').each {|n|
u = URI.parse(n['src'] || n['href']) rescue next
next if !u || (!u.scheme && u.path.strip == '')
u.fragment = nil
puts u.scheme ? u : base.join(u)
}Щоб воно працювало, треба сказати gem install nokogiri
addressable. Вбудований ув stdlib парсер url є не такий гнучкий як
addressable.
Фрагмент (частина рядка після #) видаляється для простоти, хоча, звичайно, можна було би намагатися шукати його (фрагмент) потім ув html.
Філософське питання, яке може виникнути: чи має ютіліта друкувати унікальні лінки лише (тому що уйоб-сторінка може містити кілька геть однакових), чи залишати процес фільтрування downstream, так би мовити, процесам.
… є найбільш неприємним компонентом. Шелóві мовні конструкції допомагають погано, і найпримітивніший пошук ув глибину з пародією на детектора циклів, це є все що вдалося втиснути ув 54 рядка коду.
./urlextract-recursive http://127.0.0.1/
0 Scanning http://127.0.0.1/ .
1 Scanning http://127.0.0.1/foo.html http://127.0.0.1/
2 Scanning http://127.0.0.1/bar.png http://127.0.0.1/foo.html
2 External http://example.com http://127.0.0.1/foo.html
1 Leaf http://127.0.0.1/baz.jpg http://127.0.0.1/
…Алгоритма є вкрай простий:
Для кожного лінка зі стартового url робимо HTTP HEAD ріквест. Якщо
останній є text/html, занурюємося в, якщо ні--друкуємо його як
leaf.
Формат друку:
level type url parentЩоб не сканувати лінка декілька разів, записуємо його ув хфайл history (1 лінк на рядок для макс швидкості grep'у). Рівень занурення регулюється користувачем і по замовчуванню == 20.
parent потрібен лише для ютіліти ув наступному розділі.
$ cat urlextract-recursive
#!/usr/bin/env bash
set -e -o pipefail
__dir__=$(dirname "$(readlink -f "$0")")
. "$__dir__/lib.bash"
jn() { jobs -l | wc -l; }
scan() {
local url="$1" level="$2" parent="$3"
[ "$level" -ge "$LEVEL" ] && return 0
echo "$level Scanning $url $parent"
level=$((level+1))
for u in `fetch "$url" | "$__dir__/urlextract.rb" "$url" | sort -u`; do
search "$u" "$history" && continue
echo "$u" >> "$history"
if echo "$u" | grep -F -- "${URL[host]}" >/dev/null 2>&1; then
if is_html "$u"; then
local async=
[ 1 == $level ] && [ "$JOBS" -gt 1 ] \
&& [ `jn` -lt "$JOBS" ] && async=1
if [ $async ] ; then
scan "$u" $level "$url" &
else
scan "$u" $level "$url"
fi
else
echo "$level Leaf $u $url"
fi
else
echo "$level External $u" "$url"
fi
done
}
type curl > /dev/null
: "${LEVEL:=20}"
: "${JOBS:=`nproc`}"
url=${1:?Usage [LEVEL=$LEVEL] $0 url}
url_parse "$url"
history=${HISTORY:-`mktemp /tmp/urlextract-recursive.XXXXXX`}
trap 'rm -f $history; exit 130' 1 2 15
trap 'rm -f $history' 0
if is_html "$url"; then
scan "$url" 0 .
wait
else
echo "0 Leaf $url ."
fi
(Вибачте за простирадло.)
Скрипта намагається робити конкурентні ріквести. Найнеприємніше тут є
неможливість знати заздалегідь скільки посилань буде далі і складність
створення фіксованої кількості worker'ів, перевірка яких була би
можлива ув child процесах. Тому "паралелізм" використовується лише на
рівні 1. Це означає якщо стартовий url мав рівно 1 text/html
посилання, поралелізму не буде.
Якщо не робити ліміта на конкурентні ріквести, вбити мошину можна дуже легко. Я так тестував безлімітний варіянт з 6K gnu libstdc++ doxygen сторінками на локалхості: стався еквівалента форк бімби, лайнакс грохнув ікси та почав люто плюватися сторінками вбитих процесів.
Енівей, отримані рядки від urlextract-recursive легко фільтруються. Наприклад, щоб дізнатися який був макс рівень рекурсії і чи не треба його збільшити:
$ ./urllextract-recursive http://127.0.0.1/ | tee 1
$ awk '{print $1}' 1 | sort -un | tail -1
11або показати лише ікстернальні посилання:
$ awk '$2 == "External"' 1Нецікаві шматки з lib.bash:
fetch() { curl -sfL --connect-timeout 3 -m 3 -A 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36' -H 'accept-language: en-US,en;q=0.9' -H 'upgrade-insecure-requests: 1' "$@"; }
is_html() { fetch -I "$1" | grep -Ei '^content-type:\s+text/html' > /dev/null; }
search() { grep -Fx -- "$1" "$2" > /dev/null; }На відміну від попередньої ютіліти, ця чудово і елементарно паралелізується. Сам скрипта про це гадки не має, тому що оперує лише з 1 url, але конкурентна перевірка робиться ув фінальному врапері наступного розділу через xargs.
$ cat urlcheck
#!/usr/bin/env bash
set -e -o pipefail
__dir__=$(dirname "$(readlink -f "$0")")
. "$__dir__/lib.bash"
check_link() {
local ec=0
fetch "$1" | head -c1 > /dev/null || {
ec=$?
[ $ec == 23 ] && return 0 # pipe was closed by 'head'
[ $ec -lt 100 ] && echo "Bad $1 in $2"
return 101
}
}
type curl > /dev/null
url=${1:?Usage: IGNORE=domains.txt $0 url parent}
parent=${2:-.}
url_parse "$url" || { echo "Invalid $url in $parent"; exit 100; }
if [ "$IGNORE" ] && search "${URL[host]}" "$IGNORE" ; then
echo "Ignoring $url in $parent"
else
[ 2 == $? ] && exit 100
check_link "$url" "$parent"
fiЄдина оптимізація гідна уваги це є check_link(), який читає лише 1
байт успішного ріспонзу і перевіряє статусного кода curl.
Деякі уйоб-сайти ітервебу (наприклад wsj, або припизджена квора) вважають curl ботом, ув незалежності від user agent, тому якщо вказати ув IGNORE env var шлях до хфайлу зі списком доменів, посилання з ними перевірятися не будуть.
Фінальна обгортка:
$ cat badlinks
#!/usr/bin/env bash
set -e -o pipefail
__dir__=$(dirname "$(readlink -f "$0")")
usage="Usage: $0 [-l max level] [-j max jobs] [-e] [-i domains.txt] url"
link_type=Leaf
while getopts i:l:j:e opt; do
case $opt in
i) opt_i=$OPTARG ;;
l) opt_l=$OPTARG ;;
j) opt_j=$OPTARG ;;
e) link_type="$link_type|External" ;;
*) echo "$usage" 1>&2; exit 1
esac
done
shift $((OPTIND-1))
: "${1:?$usage}"
export LEVEL=${opt_l:-20} JOBS=${opt_j:-`nproc`} IGNORE=${opt_i}
"$__dir__/urlextract-recursive" "$1" | \
awk '$2 ~ /'"$link_type"'/ {print $3, $4}' | \
xargs -r -n2 -P "$JOBS" "$__dir__/urlcheck"Зі статичним уйоб-сайтом, на який попередньо знайдені готові пекеджи витрачали від 4 до 13 хв, набір скриптів шелóвих впорався за 16 секунд, відсканувавши 769 лінка.
Ґноум втратив директора:
"Holly Million was named the GNOME Foundation Executive Director in late October. Part of her focus was going to be on helping the GNOME Foundation attain more funding. But coming today as a surprise, she will be departing her role with GNOME effective the end of July. She is stepping down on the basis of pursuing a PhD in psychology and dedicating herself to her own private practice."
Намагання знайти фінансування для Ґімпу викликає такий рівень психоемоційного стресу, який лікується лише отриманням PhD ув психології.
До погодження стати директоркою Ґноума, вона працювала "професійним шаманом, артистом, виробником трав'яних ліків та займалася мікро-гомстедингом". Останнє є не сексуальне збочення, а тип сільського господарства ув Гамериці.
"I do energy healing work on behalf of individuals, land, houses, and businesses.", розказувала про себе пані Мілліон, "I can do this work remotely because everything is connected. We live in a quantum universe."
Гомстединг був дуже ув нагоді: вирощування лікарських трав допомагало "with my shamanic work". Якщо у вас врожай з'їдали комахи, пані Мілліон проводила цілющі церемонії та ритуали по телефону: $250 за годину енергетичної роботи 1:1 з вирівнюванням чакри, або $500 за повне очищення енергії у вашому домі чи охфісі.
Наразі рада директорів Фундацьйоне Ґноума, запаливши пахощі та свічки, шукає нового директора.
Як хутко довести дівопсу або хмарному провайдеру що завантаження з серверу є повільне? Можна заміряти час загальний, чи копіювати все що curl написав на stderr, або вислати кєно зроблене на телефоні (вертикальне, тремтячою рукою, під кутом > 10°, на відстані > 1м від монітора).
Не пам'ятаю ув якій версії віндюка його іксплорер почав малювати графіка під час копіювання хфайлів (Vista?), але він (віндюк) так і не почав цього робити ані ув класичних своїх бовзерах минулого, ані ув своєму поточному безглуздому різновиді кроума для блінка.
Найнахабнішим повідомленням дівопсу був би svg:
та/чи рядки
00:00:01 1000k
00:00:02 2000k
00:00:03 2500kув якості доказу.
2й варяінт є найпростіший; curl, наприклад, друкує
fprintf(tool_stderr,
"\r"
"%-3s " /* percent downloaded */
"%-3s " /* percent uploaded */
"%s " /* Dled */
"%s " /* Uled */
"%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */
"%5" CURL_FORMAT_CURL_OFF_T " " /* Live */
" %s " /* Total time */
"%s " /* Current time */
"%s " /* Time left */
"%s " /* Speed */
"%5s" /* final newline */,
…кожну секунду, тому лише замінивши \r на \n можна відправляти повного логу:
$ curl http://example.com/1.zip -o 1.zip 2>&1 | tr \\r \\nта вимагати сатисфакції.
Щоб намалювати графіка з gnuplot, нам потрібні Current time та
Speed. Останнє доведеться конвертувати з 1234k чи 4567M ув
байти. Спочатку я думав малоелегантно замінювати суфікси:
awk 'function expr(s) {
h["k"]=2**10; h["M"]=2**20; h["G"]=2**30; h["T"]=2**40; h["P"]=2**50
for (k in h) sub(k, "*"h[k], s); return s
}
/[0-9.][kMGTP]?$/ { print expr($NF) | "bc"; close("bc") }'але, виявляється, саме для цього coreutils має ютіліту numfmt(1), про яку я ніколи не чув (додали недавно, лише 12 років тому, не встигаєш слідкувати за всіма ціма новими штуками):
$ echo lol 10M | numfmt --from iec --field 2
lol 10485760Так, звичайно, зараз не роблять, а кожного разу ретельно пишуть нудні, багатослівні простирадла на пáйфоні. Те що має фітнутися ув 5 рядків шелових макс + 6 рядків скрипта gnuplot'у, потрібно ретельно розмазувати на 70+, ніби працюєш на ойбіем ув році 1984 і тобі платять за кількість рядків коду.
Повна версія іграшкового візуалайзатора пускається як
$ ./curlbench http://example.com/1.zip | gnuplot --persistде gnuplot дозволяє зберегти графіка ув потрібному форматі.
$ cat curlbench
#!/usr/bin/env -S stdbuf -o0 bash
set -e -o pipefail
numfmt=`type -p gnumfmt numfmt;:`; test "${numfmt:?}"
cat <<E
set xdata time
set timefmt "%H:%M:%S"
set xlabel "Time"
set format y "%.0s%cB"
set grid
plot "-" using 1:2 with lines title ""
E
curl "$@" -fL -o /dev/null 2>&1 | tr \\r \\n | awk '
/[0-9.][kMGTP]?$/ {
time = index($10, ":") == 0 ? $11 : $10
if (time != "--:--:--") print time, $NF
}' | tr k K | $numfmt --from iec --field 2Має працювати також на fbsd та маку (як були встановлені coreutils), але мені є лінь перевіряти.
Побачив ув твіторі:
Robert @RobertZeltinsh · Jun 6
Діди самодєлкіни, викликаю вас. Є задача, зібрати якусь шляпу щоб коли вмикається і пропадає світло, вона відправляла про це смс.
Знайшов якісь вумні розетки з gsm, але воно криве і косе. Все що з розумним будинком не підходе, бо інтернет відсутній.
З будь-яким непотрібним ондроїдом з встановленим Termux можна написати нескладного скрипта, який буде використовувати 2 ютіліти:
(apt-get install termux-api, який вимагає також окрему ондроїдну
аплікацію termux-api.)
1ша вертає json:
{
"health": "GOOD",
"percentage": 42,
"plugged": "PLUGGED_AC",
"status": "CHARGING",
"temperature": 31.0,
"current": -564452
}2га відправляє рядок на телехфонний номер. Ув якості тесту я надіслав sms собі, після чого Київстар життєрадісно відповів що це коштувало мені 3 гривені (~7 євроцентів). Останній раз я таке робив, напевно, ув 2010 році, тому з подивом дізнався, що sms не тільки не є безплатні, а продаються пакетами по 300 штук.
Це означає, що якщо ув гаражі станеться перевантаження ланцюга і світло почне мерехтіти, за годину можна зайняти 1ше місце у Європі за кількістю відправлених sms та сертифікат від Київстару 'ідіот року'.
Отже скрипта має пам'ятати про sms ліміт на день.
Найпростіша скіма з опитуванням батареї може виглядати так: телехфон вмикається до розетки, на телехфоні запускається termux, ув якому запускається:
#!/usr/bin/env bash
set -e
poll_time=3
battery=${battery:-termux-battery-status}
sms=${sms:-termux-sms-send}
...
type jq $battery $sms > /dev/null
number=${1:?no phone number}
last=
while true; do
status=`$battery | jq -r .plugged`; [ "$status" ]
[ "$status" = "$last" ] && continue
[ "$last" = "" ] || case $status in
UNPLUGGED) send No electricity ;;
PLUGGED_AC) send A keen and shared excitement ;;
*) log "Unknown status: $status"
esac
last=$status
sleep $poll_time
doneде poll_time ліпше виставляти не 3 секунди, а ув залежності від
ліміту sms, наприклад для 100 штук на день--864 секунди (опитування
кожні 14.4 хв).
Найнудніша частина є ув відстеженні кількості відісланих sms. Ви знали що bash вміє порівнювати рядки лексикоґрафічно? Я не знав!
$ [ 2024-06-11 \> 2024-06-10 ] ; echo $?
0
$ [ 2024-06-11 \> 2024-06-12 ] ; echo $?
1Тоді перевіряючи mtime хфайла, де записується кількість sms, можна скидати ліміта:
sms_limit_file="${XDG_CACHE_HOME:-$HOME/.cache}/elektrokharchuvannia"
sms_limit=10
sms_limit_get() {
local r=$sms_limit
[ -r "$sms_limit_file" ] && {
r=`head -c4 "$sms_limit_file" | awk '{print $0+0 == $0 ? $0 : 0}'`
local today="`date +%Y-%m-%d`"
local mtime="$(date -d "@$(stat -c %Y "$sms_limit_file")" +%Y-%m-%d)"
[ "$today" \> "$mtime" ] && r=$sms_limit
}
echo "$r"
}
sms_limit_decr() {
mkdir -p "`dirname "$sms_limit_file"`"
echo $((`sms_limit_get` - 1)) > "$sms_limit_file"
}
log() { printf '%s: %s\n' "`date`" "$*"; }
send() {
[ "`sms_limit_get`" -lt 1 ] && { log SMS dayly limit reached; return; }
local msg="$* (SMS left: $((`sms_limit_get` - 1)))"
log "$msg"; log "$msg" | xargs -d\\n $sms -n "$number";
sms_limit_decr
}Тестування цього ковгоспу без відсилання повідомлень:
$ sms=true ./elektrokharchuvannia +380148800000Тут воно повинно показувати нічого. Далі, висмикування дроту з телехфону та вставляння його знову, друкує:
Wed 12 Jun 01:25:15 EEST 2024: No electricity (SMS left: 2)
Wed 12 Jun 01:25:20 EEST 2024: A keen and shared excitement (SMS left: 1)
Wed 12 Jun 01:25:25 EEST 2024: No electricity (SMS left: 0)
Wed 12 Jun 01:25:28 EEST 2024: SMS dayly limit reachedКоли фасебоок іноді попереджує про непозбувану бентегу, якщо клікнути на ікстернальний лінка (як вам не соромно, you're going to a link outside facebook), то минулого літа ув багатьох газетах від цього відбувався розрив дупи (Facebook is now treating content links like malware).
jwz колись розповідав, що оригінальний Mosaic був піонером цього епроачу, маючи налаштування, з яким бовзер малював попереджувального даялога, коли нещасний користувач клікав на будь-якому лінку.
Виявляється, Mosaic 2.7 можна зібрати на сучасному лайнаксі, що я зробив щоб даялога побачити. Це motif аплікація! Вікна зі налаштуванням там немає, тому що вся конфіґурація очікується ув X resources, якщо хтось пам'ятає цей навіки забутий механізма користувацьких параметрів:
$ grep Mosaic ~/.Xdefaults
Mosaic*protectMeFromMyself: true
Mosaic*XmDialogShell*fontList: -*-helvetica-medium-r-*-*-24-*-*-*-*-*-*-*
Були часи. Щоб змінити розмір шрифта, інакше розгледіти діфолтний на сучасних екранах можна лише за допомогою лупи, довелося передивлятися дерево мотіфних віджетів за допомогою editres.
Salacious materials, так.
Кожного разу як я перевіряю чи буде працювати лайнаксна аплікація на відюку, то жалкую що спробував.
Наприклад, є ноудний майкро-сервіс foo, який від ОС вимагає лише підтримку TCP/IP, робить жодних змін ув файловій системі, вимагає 0 суто лайнаксних API, пише logs до stdout, вважає що його будуть байнднути до умовного 12345 порту, що привілей спеціяльних не вимагає.
На лайнаксі для такого майкро-сервісу пишуть елементарного юніт-хфайлу
ув ~/.config/systemd/user/foo.ini і Боб є ваш дядько--користувач
лайнаксу (регулярний) контролює foo за допомогою звичних команд
systemctl.
Ув віндюку, починаючи з 10 (чи 8?), з'явилися "per-user" сервіси,
наприклад cbdhsvc (це так, у якості конспірації, зашифровується
словосполучення сервіс кліпбоарду), які, незважаючи на назву,
вимагають привілеї адміністраторські для свого створення і затишні
поради "інсталюйте нові ваші аплікації до $env:APPDATA"
зіштовхуються зі суворою реальністю майкрософтського ідіотизму.
Чи складно тоді сгенерувати інсталятора, що
$env:PROGRAMFILES/foo;http://127.0.0.1:12345?Нескладно, але я би поставив оцінку 3/10: не рекомендую.
До появи UWP аплікації, які у нас час роблять для майкрософтського магазину істоти що народилися лузерами, генерувався .msi хфайл. Більше 10 років тому для цього був wix toolset--декілька феноменально огидних CLI-утіліт, написаних людьми, для яких поняття смак є так само близьке, як відстань сузір'я Андромеди до планети Земля.
З того часу змінилося нічого. Є інші способи створювати інсталятори, наприклад Inno Setup (якщо вас не дратує даялекта паскалю (так), на якому доводиться писати шматки скриптів для будь-якої нетривіяльної дії), або InstallShield, якщо ви міцно поїхали головою та бажаєте сабскріпшона $2474/рік годувати якихось індусів.
Питати про wix будь-яку LLM--гаяти час. Гоогл забитий порадами для версії 3.x, яка малює даялоги для моніторів 2006 року з 96 dpi. Нова версія 5 має неймовірне поліпшення: вміє створювати список файлів сама, без допомоги ікстернального препроцесора або (я вибачаюсь) xslt! Для цього грандіозного leap forward їм знадобилося 20 років. А також:
"інторнет" шортката, який генерує wix, потім неможливо відредагувати (до permissions це стосунку не має), url є вшитий намертво;
якщо воно не може стартувати сервіса ув процесі інсталяції--настає павза та rollback, жодні твікі з vital=no, wait=no і т.і. не допомагають, хоча згідно пародії на документацію повинні;
інтерхфейсьні лейбли можуть стискатися ув залежності від різолюшену
монітору та dpi--дуже зручно якщо ти повідомляєш користувачу "дивись
logs ув $env:SystemRoot/Temp/foo*, а згенерований даялог малює
.../foo*.
Куди правильно писати logs для користувача NT Authority\Local Service я так і не зрозумів. Від блискучих за точністю порад що він
має limited write access to the file system у мене бажання
перекваліфікуватися на ілектришона та до кінця своїх днів лагодити
розетки ув субурбії Калґарі.