программирование
Отсутствие cp1251 в iconv
На днях встретил дистрибутив Линукса, в котором не оказалось
Многим, конечно, покажется, что однобайтовые кодировки не нужны,
В общем, как бы то ни было, запишу себе, чтобы не забыть. Если iconv ругается на CP1251:
iconv -f cp1251 -t utf-8 /dev/null
iconv: failed to start conversion processingто надо поставить пакет glibc-gconv-extra и ошибка пропадёт.
Адвент-календарь
В этом году внезапно узнал, что существует
В начале задания совсем пустяковые, но постепенно сложность нарастает. Пока всё ещё несложно, в последнем задании, которое я выполнил — перебор с возвратом, но времени на решение у меня уходит всё больше и больше.
Меня затея впечатлила, я даже сел его прорешивать (правда опоздал на несколько дней, узнал поздновато, но нагнал сразу же), а чтобы жизнь мёдом не казалась, каждое задание стал писать на отдельном языке.
На сегодня у меня выполнено восемнадцать заданий (любопытствующие могут заглянуть ко мне в репозиторий) на следующих языках: GNU dc, PHP, Regina Rexx, Perl, Tcl, PowerShell, Crystal, V, D, AppleScript,
Честно говоря, подбор языка занимает больше времени, чем написание на нём решения, тем более, часть хорошо знакомых языков я оставил на конец, — по совету товарищей, которые прорешивали такие календари в прошлые коды.
Единственный язык, где я гораздо дольше мучился с самим языком, чем с его подбором — это Рефал. Это язык программирования на сопоставлениях с образцом и я
У меня тяжело заболела дочка, плюс всплыл ряд и других проблем, так что я сильно отстаю от графика — это шесть заданий на сегодня. Буду заниматься своими проблемами, если силы останутся, то нагоню, если нет, то брошу или буду дорешивать в новогодние выходные.
«99 бутылок» на баше без цикла
Когда я только начал программировать, все интерпретаторы, которые мне попадались в то далёкое время, интерпретировали программу построчно. Недавно разговаривали на эту тему с одним из приятелей, который буквально был в шоке, когда случайно обнаружил, что популярная оболочка bash работает именно таким образом.
Мне кажется совершенно естественным, что такой способ интерпретации должен дожить и до наших дней, он же очень простой в реализации и для многих вещей его вполне достаточно.
#!/bin/bash
len=$(wc -c<"$0"); : https://bolknote.ru 2021
echo -e "99 bottles of beer on the wall, 99 bottles of beer.
Take one down and pass it around, 98 bottles of beer on the wall.\n"
: ${i:=99}; ((--i)) && (grep -B5 -m1 ^G "$0" |
sed "s/9[8]/$(($i-1))/g;s/9[9]/$i/g;s/ [0] / no /;s/\([1] b[^s]*\)s/\\1/g" >> "$0") ||
(echo 'No more bottles of beer on the wall, no more bottles of beer.
Go to the store and buy some more, 99 bottles of beer on the wall.';truncate -s "$len" "$0")
:;Пока разговаривали, у меня возникла смешная идея — попробовать написать считалочку «99 бутылок пива…» без циклов, на принципе дописывания кода, чтобы строки добавлялись в файл программы по мере интерпретации.
Результат чуть выше. Так как bash местами довольно сложен для понимания, попробую позже (если не заленюсь) сделать разбор странно выглядящих мест этой программы отдельным постом.
PHPFuck для PHP8
Немного про программирование.
Один из читателей написал, что программа PHPFuck (это способ писать программы
В самом деле, восьмая версия стала куда строже к программисту,
<?=[[$_=@([].[]),$___=-!![],$$_=![]+![],$$_=$$_*$$_,$__=$$_+![],$$__=$$_+$__,
$____=$_[-![]-![]],$$___="{$$__}"^$____,$$___=($$___^"$___"). ($$___^"{$$__}"^"$___"^"{$$_}").
($$$_=$$___^"{$$_}"). $$$_.($_____="{$$__}"^"{$$_}"^++$____).("$___"&$____).
([$$___=$_[+![]],"{$$_}"|++$$___][+![]]).$_____.$_[+![]].$$$_. ("$__"^$_[-![]-![]]^"$___")
],$$___][+![]];Выше новая версия.
Кстати, она компактнее, но при этом выводит больше текста — «hello world», вместо «Hello!» предыдущего варианта. Ниже я немного расскажу откуда взялась экономия и с чем ещё пришлось столкнуться.
Принцип формирования текста остался, в общих чертах, прежним — корнем всего является комбинация @([].[]), которая даёт слово ArrayArray
Из этой строки потом рождаются все остальные символы. Дело в том, что в ПХП над символами можно производить некоторые бинарные и математические операции, что иногда позволяет получить другие символы. Например, первая буква — h в слове hello получается из сочетания '9' ^ 'a' ^ '0' (где ^ — бинарная операция «исключающего или»).
При этом цифры я получаю довольно простым способом — 0 как +!![] (преобразованием false в число), «девятку», — набирая нужные цифры по единицам (из +![]), а a — как предпоследнюю букву из полученной ранее строки ArrayArray, то есть @([].[])[-2] (аналогично, -2 получается тут из двух замаскированных единиц со знаком «минус»).
По сравнению с предыдущим вариантом в новом коде сделаны следующие изменения.
В этой связи весь код теперь — большое выражение, все переменные в нём лежат внутри массива. Если давать им нормальные имена, то основной принцип выглядит
Кроме того, мне надоело подбирать буквы вручную, вместо этого я написал небольшую программу, которая делает это за меня. Я не стал придумывать алгоритм, который бы анализировал какие биты нужно изменить, а решил задачу полным перебором.
Ниже приведен листинг этой программы, вдруг
<?php
declare(strict_types=1);
// Доступный алфавит
$abc = str_split(count_chars("Array0123456789", 3));
// буквы, которые надо получить
$need = str_split(count_chars("hello world", 3));
function gen(array $chrs): Generator
{
// чем операции длиннее, тем ближе к концу
// это нужно, чтобы более короткие конструкции выигрывали
foreach ($chrs as $ch) {
yield $ch => [$ch, $ch];
}
// возврат: из чего делаем, [как выглядит, значение]
foreach ($chrs as $ch) {
yield $ch => ["~$ch", ~$ch];
}
// для символа инкремент работает, а декремент — нет (особенность ПХП)
foreach ($chrs as $ch) {
$value = $ch;
yield $ch => ["++$ch", (string)++$value];
}
}
function eval_op(string $op, string $a, string $b): string
{
return ([
'|' => fn($a, $b) => $a | $b,
'&' => fn($a, $b) => $a & $b,
'^' => fn($a, $b) => $a ^ $b,
][$op])($a, $b);
}
function generate(array $set): Generator
{
foreach (gen($set) as $src1 => [$p1, $ch1]) {
foreach (gen($set) as $src2 => [$p2, $ch2]) {
foreach (['|', '&', '^'] as $op) {
$result = eval_op($op, $ch1, $ch2);
if ($result !== $ch1 && $result !== $ch2) {
yield [
$src1,
$src2,
"$p1 $op $p2",
$result,
];
}
}
}
}
}
function out(string $str): string
{
return preg_replace_callback(
'/[\x00-\x1F\x80-]/s',
fn($m) => sprintf("\\x%02X", ord($m[0])),
$str
);
}
$set = $abc;
do {
foreach (generate($set) as [$src1, $src2, $str, $res]) {
$idx = array_search($res, $need, true);
if (!isset($rules[$res])) {
$rules[$res] = $str;
}
if ($idx !== false) {
if (!in_array($src1, $abc, true)) {
echo out("{$rules[$src1]} = '$src1'"), "\n";
}
if (!in_array($src2, $abc, true)) {
echo out("{$rules[$src2]} = '$src2'"), "\n";
}
echo out("$str = '$res'"), "\n\n";
unset($need[$idx]);
}
$set[] = $res;
}
$set = array_unique($set);
} while ($need);Это ни в коем случае не инструмент для оптимизации программ в такой технике, а набросок, позволяющий ускорить подбор букв.
Для более глубоких оптимизаций нужно научить эту программу дробить выражения, которые уже вычислялись, на куски и эффективно использовать их, а так же подбирать частоиспользуемым кускам имена переменных меньшей длины.
У меня дробления нет, я использую предыдущие выражения целиком, а имена переменным моя программа вообще не подбирает.
Как скачать видео с URL «blob:»
Нередко в последнее время нередко встречается ситуация, когда хочется сохранить себе видео
Бывает, что в теге проигрывания видео (который легко найти при помощи «Инструментов разработчика» браузера) указан файл, который можно скачать, но иногда там применяется протокол blob: и с ним не настолько всё просто.
К счастью, есть способ скачать и такое видео, но он требует
Нужно открыть «Инструмент разработчика» на вкладке «Сеть» («Network»), запустить проигрывание видео и поискать в перехваченных урлах первый, который заканчивается на m3u8.
Этот урл надо скормить известной утилите для работе с видео ffmpeg:
ffmpeg -i 'https://example.org/master.m3u8' -c copy -bsf:a aac_adtstoasc ~/Downloads/output.mp4Где https://example.org/master.m3u8 — перехваченный урл, а ~/Downloads/output.mp4 — файл, куда нужно будет сохранить искомое видео.
После этого остаётся только ждать, утилита ffmpeg сделает всё сама.
Среднее специальное в «айти»
Наблюдаю интересную тенденцию, — если раньше в айтишники шли, как правило, люди с высшим образованием (исключения мне встречались, но редко), то сейчас всё больше появляется людей со средним специальным, причём без планов пойти учиться в вуз.
Наверное это закономерно —
Правда не знаю, это общероссийское явление или особенность местного рынка. В Казани в айти идёт много ребят из техникума связи, можно предположить, что там просто уникально хороший уровень образования, а по всей остальной России ситуация в отрасли совершенно не изменилась.
Мои «99 бутылок» на клоне Эпла-I
Два года назад я написал на ассемблере первого компьютера компании Эпл (сейчас он условно называется «Эпл I») считалочку «99 бутылок пива на стене». Писал под эмулятор, но не оставлял надежду увидеть
Ради этого я даже повторно посетил музей Эпл в Москве, но к сожалению, искомый компьютер в момент моего посещения не работал. К счастью, подкупом удалось договориться с владельцем музея, чтобы тот позже запустил мою программу и прислал видео.
Увы, позже ни на одно из моих писем владелец не ответил, зато один из энтузиастов
Зелёная плата с чёрными микросхемами — это и есть сам компьютер. Программа, как можно заметить, вводится в виде аудиофайла через звуковой вход (через разъём справа к компьютеру подключен смартфон), это гораздо быстрее, чем набирать её на клавиатуре.
Посмотрите немного, оцените быстродействие, при такой низкой скорости работы тогдашних компьютеров, софт, конечно, разнообразием не блистал. Даже интересно — существовали ли под этот компьютер
99 бутылок: Psql (переработанная версия)
Я уже публиковал сегодня одну попытку написать «песню про пиво» на языке утилиты psql, но, к сожалению, результат получился не совсем честный — для математики и сравнения мне пришлось использовать вставку на эскуэеле.
Чисто интуитивно чувствовалось, что
Реализовать задуманное получилось через таблицу замен (об этом ниже) и кодогенерацию — psql позволяет писать в файлы произвольное содержимое, а потом эти же файлы подключать. К сожалению, после этого остаётся немного мусора во временной папке, но тут уж ничего не попишешь.
Таблицу замен я реализовал через девять переменных с числовыми именами, значением которых является число на единицу меньше имени. Например: \set 9 8 — тут переменная с именем 9 получает значение 8.
Чтобы реализовать вычитание единицы, пришлось разделить счётчик цикла на две переменные — beer_h (старший разряд) и beer_l (младший разряд), вычитание производится для каждой цифры отдельно. На диск записывается код, в который помещается имя переменной и её новое значение, используя текущее значение, как имя переменной, из которой надо взять следующее. Понимаю, что запутанно, надеюсь на примере понять будет проще.
Вот этот кусок: \qecho '\\set beer_h :':beer_h. Если текущее значение переменной beer_h равно 9, то на диск будет помещен скрипт с содержимым \set beer_h :9, после его подключения код выполнится, а так как значение переменной 9 — 8, то beer_h получит значение 8.
Одновременно я таким же способом создаю логические переменные beer_разряд_value_значение со значением 1, которые я использую потом как флаги, чтобы остановить цикл или отключить использование множественного числа, когда число «бутылок» доходит до единицы.
С кодогенерацией, кстати, работать веселее — сгенерированный код потом можно использовать как некий аналог подпрограмм, экономя размер кода.
В общем, в результате получилось реализовать «песню про пиво» на чистом языке утилиты psql, не привлекая другие языки программирования.
\if 0
99.psql
Psql beer song v.2
Written by Evgeny Stepanischev https://bolknote.ru
\endif
\if :{?beer_l} \else
\set 9 8 \set 8 7 \set 7 6 \set 6 5 \set 5 4 \set 4 3 \set 3 2 \set 2 1 \set 1 0
\set print /tmp/beer_print.sql
\set minus /tmp/beer_minus.psql
\out :print
\qecho '\\if :{?beer_h_value_0} \\echo -n :beer_l'
\qecho '\\else \\echo -n :beer_h:beer_l \\endif'
\set beer_h 9
\set beer_l 9
\set s s
\endif
\include :print
\echo -n ' bottle':s' of beer on the wall, '
\include :print
\echo ' bottle':s' of beer.'
\if :{?beer_l_value_0}
\unset beer_l_value_0
\set beer_l 9
\out :minus
\qecho '\\set beer_h :':beer_h '\\set beer_h_value_:':beer_h 1
\include :minus
\else
\out :minus
\qecho '\\set beer_l :':beer_l '\\set beer_l_value_:':beer_l 1
\include :minus
\endif
\if :{?beer_h_value_0}
\if :{?beer_l_value_1}
\set s
\endif
\if :{?beer_l_value_0}
\echo Take one down and pass it around, no bottles of beer.'\n'
\echo No more bottles of beer on the wall, no more bottles of beer.
\echo Go to the store and buy some more, 99 bottles of beer on the wall.
\q
\endif
\else
\unset beer_l_value_1
\endif
\echo -n 'Take one down and pass it around, '
\include :print
\echo ' bottle':s' of beer.\n'
\include_relative 99.psql99 бутылок: Psql
Давно чесались руки написать очередную «песню о пиве»
75. Psql — не совсем язык программирования, это название клиентской программы, распространяемая вместе с СУБД «Постгрес». У неё есть довольно скромный встроенный язык, в который относительно недавно добавили условный блок.
Тем не менее на этом языке можно требуемое, если привлечь для математики и сравнения эскуэль — сам psql такого не умеет. В качестве цикла пришлось применить включение файла в самого себя, повезло, что цикл относительно короткий, а то бы я упёрся в лимит на количество открытых файлов в системе.
Добавлено позднее: мне всё же удалось реализовать «песню о пиве» без использования эскуэля.
\if 0
99.psql
Psql beer song
Written by Evgeny Stepanischev https://bolknote.ru
\endif
\if :{?beer} \else \set beer 99 \endif
\echo :beer bottles of beer on the wall, :beer bottles of beer.
select :beer-1 beer, :beer > 2 notend \g /dev/null
\gset
\if :notend \set s s \else \set s \endif
\echo Take one down and pass it around, :beer bottle:s of beer.'\n'
\if :notend
\include_relative 99.psql
\else
\echo 1 bottle of beer on the wall, 1 bottle of beer.
\echo Take one down and pass it around, no bottle:s of beer.'\n'
\echo No more bottles of beer on the wall, no more bottles of beer.
\echo Go to the store and buy some more, 99 bottles of beer on the wall.
\endifВроде код понятен почти без объяснений, но несколько моментов без знакомства с утилитой вряд ли возможно расшифровать самостоятельно, поэтому я их вкратце хочу объяснить.
:{?beer} — синтаксис проверки существования переменной, это нужно чтобы понять запускаем ли мы программу в первый раз или включили её в себя же, чтобы имитировать цикл.
select :beer-1 beer, :beer > 2 notend —
\g /dev/null — запуск запроса в выводом результата в /dev/null (то есть в никуда), поскольку его результат на экране нам не нужен.
\gset — записываем результат запроса в переменные, имена которых равны именам столбцов запроса.
У меня есть одна идея, как сделать вычитание, не привлекая эскуэль, надо будет попробовать. А вот с остановом хуже — там никаких идей.
«ВАМПИР»
Я
Одному из моих гештальтов в этом определении почти 30 лет — в начале
Игру удалось починить и возможно поэтому она мне так запомнилась, что через много лет мне захотелось её найти и сыграть. Тем более, что эмуляторов
Шли годы, я без особой надежды регулярно гуглил эту игрушку, но она никак не находилась.
Но тут недавно, когда я подбирал чего бы мне такого портировать на «Фортран», в списке старых игр на «Бейсике» увидел игру «Hunt the Wumpus» 1972 года и по листингу понял, что передо мной — исходный вариант игры «Вампир», следы которой я до сих пор никак не мог разыскать!
Хоть
Все программы для этого компьютера в те времена набирались вручную из печатных источников — из журналов, возможно
Игра «Ровно в полдень»
Как я писал вчера, по не совсем ясной причине мне захотелось посмотреть что из себя представляет «Фортран» — язык программирования, придуманный ещё
Крупное писать не хотелось, из мелочи ничего в голову не пришло, поэтому пошёл по лёгкому пути — портировал небольшую текстовую игру «HIGH NOON» («High noon» — очень известный в своё время
Игра написана неким Крисом Гейло, учеником средней школы Сайассет
Игре уже около полувека и сейчас она, разумеется, кажется крайне незамысловатой. Дело происходит на Диком Западе, вы стоите на ста шагах от Чёрного Барта, который вызвал вас на перестрелку. На каждом шаге игрок может продвинуться вперёд, отступить, прыгнуть в укрытие, сдаться или выстретить. Чем ближе удасться подобраться к оппоненту, тем выше точность выстрела, причём и игрока, и его виртуального противника.
На портирование ушло около часа (на результат можно полюбоваться в моём репозитории), больше всего времени пришлось потратить на написание функции, которая переводит числа в строки (если ею не пользоваться, а просто выводить числа как есть, «Фортран» очень неуместно форматирует их пробелами).
Ещё никак не мог понять в чём смысл части оригинального листинга с 460 по 520 строки, сначала мне показалось, что он просто не дописан:
460 PRINT "WHAT IS YOUR LUCKY NUMBER FOR TODAY";
470 INPUT A
480 A = 1E4 * ABS(SIN(A))
490 A = (A - INT(A)) * 1000
500 FOR I = 1 TO A
510 B = RND(0)
520 NEXT IУ игрока спрашивается какое сегодня его счастливое число, потом делается некое вычисление и по результату прокручивается цикл с RND(0) внутри. В дальнейшем полученные в этом куске кода значения ни на что как будто бы не влияют.
Это место из своей портированной версии я просто выкинул, но позже мне пришло в голову объяснение. По всей видимости, это попытка инициализировать генератор псевдослучайных чисел. Видимо в «Бейсике», на котором писал автор, не было другого хорошего способа это сделать.
Счётчик цикла и Фортран
Пока
У языка много особенностей, но больше всего интересна следующая. Фортран — язык со статической типизацией, то есть для каждой переменной требуется указать тип, но в некоторых случаях компилятор может вывести тип самостоятельно. Правда, думаю, правило вывода этого типа сильно вас удивит.
В этой простой программе тип переменной I не указан, но компилятор знает, что её тип — integer.
DO I = 99, 1, -1
PRINT *, I
END DO
ENDДело в том, что
Есть мнение, что отсюда и пошла привычка называть переменные цикла буквами из «целого» ряда.
Говорящие часы
По причинам, далёким от рациональных, захотелось мне вчера сколхозить для себя говорилку времени. Простой вариант проговаривания цифр показался очень скучным, сразу вспомнились лебедевские часы «Вербариус», где одно и то же время каждый раз пишется
На сайте «Студии Лебедева», в разделе часов «Вербариус» есть языковые файлы, три из которых — для русского, английского и французского выгружены в виде обычных экселевских таблиц. Их легко преобразовать в формат CSV при помощи приложения «Намберс» или всем знакомого «Экселя».
В получившемся файле много пустых полей и лишних пробельных символов, которые будут мешать, их легко удалить утилитой командной строки sed:
sed -i '' -E "s/; +| +;/;/g; s/;+/;/g; s/;[ "$'\r'"]*$//;" ~/Downloads/russian.csvУ получившегося файла очень простой формат — сначала идёт время без ведущего нуля, потом — варианты для произношения, разделённые точкой с запятой. На мой взгляд, для поиска нужной строки и выбора случайного вариант для произношения лучше всего подойдёт утилита awk.
Если направить её вывод маковской утилите say, то говорящие часы готовы:
awk -F\; "BEGIN{srand}/^$(date +%k:%M|xargs)/{print \$(int(2+rand*(NF-1))); exit;}" \
~/Downloads/russian.csv | xargs sayЯ их пока вызываю из командной строки коротким алиасом t, но если понравится, настрою как службу, с вызовом через горячую клавишу.
Особенности использования индексов в PostgreSQL
Вчера под ночь боролся с «Постгресом» (это такая СУБД), в итоге поборол, но не так, как хотелось бы.
SELECT id, CASE WHEN RANDOM()>.5 THEN value END AS value
INTO test
FROM generate_series(1, 1000000) WITH ORDINALITY AS test(id, value)В тестовой таблице два поля — идентификатор (id) и значение (value), примерно половина значений в поле value — NULL. И теперь нам надо создать индекс для запросов, которые выглядит примерно так:
SELECT id FROM test WHERE value IS NULL ORDER BY id;
SELECT id FROM test WHERE value IS NOT NULL ORDER BY id;План для них выглядит одинаково печально, что логично — на таблице ни одного индекса:
Sort (cost=61739.93..62977.68 rows=495100 width=4) (actual time=47289.775..47761.235 rows=498778 loops=1)
Sort Key: id
Sort Method: external merge Disk: 6848kB
-> Seq Scan on test (cost=0.00..14910.00 rows=495100 width=4) (actual time=12.039..40854.731 rows=498778 loops=1)
Filter: (value IS NULL)
Rows Removed by Filter: 501222
Planning Time: 0.174 ms
Execution Time: 48134.553 msЧтобы сэкономить место, мне очень хотелось сделать индекс функциональным:
CREATE UNIQUE INDEX ON test((value IS NULL), id);Таким образом вместо целого поля будет использован логический тип всего с двумя значениями.
Конечно
Первый запрос ожидаемо улучшился:
Index Scan using test_expr_id_idx on test (cost=0.42..33882.43 rows=495100 width=4) (actual time=0.056..519.584 rows=498778 loops=1)
Index Cond: ((value IS NULL) = true)
Planning Time: 0.182 ms
Execution Time: 894.551 msА второй — нет:
Sort (cost=62738.26..64000.51 rows=504900 width=4) (actual time=1046.582..1471.180 rows=501222 loops=1)
Sort Key: id
Sort Method: external merge Disk: 6880kB
-> Seq Scan on test (cost=0.00..14910.00 rows=504900 width=4) (actual time=0.033..522.071 rows=501222 loops=1)
Filter: (value IS NOT NULL)
Rows Removed by Filter: 498778
Planning Time: 0.136 ms
Execution Time: 1841.282 msНесмотря на то, что в индексе содержится информация, достаточная для выполнения этого запроса, в данном случае «Постгрес» не понимает, что VALUE IS NOT NULL эквивалентно (VALUE IS NULL) = false.
Причём, если попробовать переписать запрос, чтобы условие выборки выглядело как (VALUE IS NULL) = false, то тут оптимизатор не оплошает — перепишет за нас условие в виде VALUE IS NOT NULL и опять не будет узнавать его в индексе.
Я вижу несколько путей решения этой проблемы, все с недостатками.
CREATE UNIQUE INDEX ON test((CASE WHEN value IS NULL THEN TRUE ELSE FALSE END), id);Недостатки очевидны: громоздкость конструкции, кроме того, легко забыть, что условия для этой таблицы надо писать именно так. Можно поместить эту конструкцию внутрь функции, но это устранит только первый недостаток.
CREATE UNIQUE INDEX ON test((value IS NULL), id);
CREATE UNIQUE INDEX ON test((value IS NOT NULL), id);Недостаток: у нас два индекса — при вставке или обновлении будем писать в два места, раздуваться (bloat) у нас будут тоже два индекса вместо одного.
CREATE UNIQUE INDEX ON test(value, id);Фатальный недостаток: индекс, по сути, бесполезен — он содержит всю таблицу целиком, «Постгрес» скорее всего выберет последовательное сканирование таблицы, а индекс использовать не будет.
И, наконец, вариант, который мне нравится в этой ситуации больше всего — частичные индексы:
CREATE UNIQUE INDEX ON test(id) WHERE value IS NULL;
CREATE UNIQUE INDEX ON test(id) WHERE value IS NOT NULL;Да, у нас опять два индекса, но они довольно компактны по размеру: в каждом примерно половина данных, кроме того, в нём вообще только одно поле — второго нет вовсе, его заменяет условие индекса.
Добавлено позднее: мне тут подсказывают, что нужно ещё учитывать селективность. Это верно, но мне совершенно не хотелось затрагивать ещё и эту тему. В реально задаче в индексе больше полей.
Длинные имена и PHP
На днях наткнулись на немаловажную особенность, — на системе примонтированной по CIFS (эта система — наследница небезызвестной «Самбы»), программа ПХП не видела некоторые файлы. В принципе, мы довольно быстро разобрались, что дело в длине имени — все функции для обхода директориев в языке такие файлы игнорировали.
Оказалось, что наша версия ПХП использует устаревший вызов readdir_r. У него много недостатков, но среди прочих — на некоторых системах он не может читать длинные имена. Проблему исправили в версии 7.4, но у нас всё ещё есть проекты на 7.3.
До конца перехода будем использовать системную утилиту /bin/ls, у неё таких трудностей не возникает.
Архив программ
Честно сказать, я считаю проект «Архив Интернета» более важным проектом, чем «Википедия», жаль что ему достаётся незаслуженно мало внимания. За 20 лет существования моего сайта, в старых заметках поумирало 100% ссылок и только «Архив Интернета» позволяет понять что
В нём же я нередко ищу старые книги, подшивки газет и прочие бумажные материалы — некоторые издания можно найти в интернете только там. Но кроме этого, как оказалось, там бывают старые компьютерные программы, причём запускаемые прямо в окне браузера!
Я тут заинтересовался препроцессором «Ратфор», который был разработан
Пока гуглил информацию по «Ратфору» (литературы не так уж и много), в «Архиве Интернета» нашёл реализацию, запускаемую в окне браузера под портированным ДОСБоксом. Очень здорово придумано — можно сразу бегло посмотреть требуемое.
«Я тебя по IP вычислю»
Сегодня утром, читая
Я сам это делал несколько раз. Добытые магическим образом персональные данные остужали любого зарвавшегося оппонента. Правда никакой магии там не было — немного технической грамотности и личных знакомств.
Помню, в одном из местных
Посмотрел его
ФОКАЛ
Один из читателей (за что ему большое спасибо) прислал очередной экспонат в музей вычислительной техники им. Самитова, соучредителем которого я являюсь — книгу по языку программирования «ФОКАЛ». У меня на нём есть написанная считалочка «Песня о пиве».
На скане книга открыта на загадочной функции FSBR, описание которой мне в своё время найти не удалось, прислал
Вообще дома накопилось довольно большое количество экспонатов для музея, у которого сейчас непонятная ситуация со статусом, поэтому ничего нового там пока не появляется. Всё очень сложно, не исключено, что проще организовать второй музей
В короновирусный год шансов на это мало, у всех есть более насущные проблемы, но чем чёрт не шутит, может всё ещё сложится.
Починил PogodaStatusBar
Обратил внимание, что мой
Пришлось исправить две вещи —
Остался ещё один баг — если «Яндекс» не отдаёт информацию о пробках (в некоторых небольших городах такой информации нет), то плагин работать не будет. Не знаю, стоит ли это править,
Какие ещё графические форматы поддерживает ваш браузер?
Переложил на хостинг «Гитхаба» свой проект семилетней давности — «Какие графические форматы поддерживает ваш браузер?». Я его иногда обновляю и мне было бы проще это делать через репозиторий.
Из всего, что я там проверяю, сразу не сработала только проверка на AVIF — это новейший формат, у меня на компьютере его поддерживает пока только «Файерфокс», ему важно указание типа содержимого, а «Гитхаб» передаёт неправильное значение.
Я подумал, что наверняка есть
Пришлось идти другим путём — вместо того, чтобы загружать файл картинки, внедрил его внутрь при помощи протокола data:, это позволило обойти проблему. Можете протестировать на своём браузере.
Ссылка на проект: https://bolknote.github.io/detect-browser-graphics-formats/
Ссылка не репозиторий проекта: https://github.com/bolknote/detect-browser-graphics-formats