Замечания и предложения по нему, а также их обсуждение.Перекат ото >>1000686. Трудящиеся могут перекатывать треды сами. BTW, думаю, имеет смысл увеличить bump limit в /d/. Как считаете?
Неплохо бы сделать, чтобы в catalog.html br'ы превращались в пробелы.
>>1001067Мне лично не нравится ибо нечитаемая каша.
>>1001068Не нравится, как на >>1001067-картинке? На той картинке br'ы убраны полностью: это то, как дела обстоят сейчас, из-за чего ссылка сливается с идущим за ней словом.
>>1001069А, и правда.
В /b/ нет этих странных <a name="s0" id="s0"></a>, надо перегенерировать страницы. Зачем они вообще? Почему не a[name][id]:first?
<a name="s0" id="s0"></a>
a[name][id]:first
> SMTP error from remote mail server after end of data: 550 spam message rejected. Please visit https://help.mail.ru/notspam-support/id?c=Рассмотрите делание чего-нибудь с этим. gmail ему теперь тоже не нравится.
>>1001072С этим ничего делать не надо, потому что почта сервера никак к мылу не относится.>>1001071Претензии к >>1001045 или тому кто дизайнил быстрый ответ. Так-то id вообще в thread уже запихнуто
>>1001073> С этим ничего делать не надо, потому что почта сервера никак к мылу не относится.?У вас не работает канал связи. Не работает он, скорее всего, потому, что> Multi-hop forwarding is close to a worst-case setup for modern spam filtering, because each forward typically breaks SPF and can break DKIM alignment. [...] The final hop has nothing left to authenticate the message against, so it falls back to content-based spam heuristics.Первое моё письмо (на @yakuji.moe) прошло. Вы мне прислали ответ с @yandex.ru. Ответ на ваш ответ (он отправлялся на @yandex.ru) — тоже прошёл. А вот второе моё письмо на @yakuji.moe — не прошло, потому что промежуточный @list.ru не знает, что вы мне ответили с @yandex.ru и думает, что я вам спамлю.Вы второе письмо-то получили?
>>1001073> Претензии к >>1001045 или тому кто дизайнил быстрый ответFixed in PR #23. Страницы перегенерировать после этого, да.
>>1001076Тем не менее, SRS поставлен.
>>1001067Done in PR #24.
Behold now!https://codeberg.org/ozoi/fbe-410/commit/cb6297145ab9c8a081888fd9138cc29abb0b7e10https://codeberg.org/ozoi/fbe_round_phashПока не открываю PR, запрашиваю фидбэк.
>>1001079Пока такие вопросы-замечания.> $candidates = $similar_class->findSimilar($_FILES['imagefile']['tmp_name'], KU_SIMILAR_MAXDISTANCE);В будущем от отправки скриптом просто хэша, а не всей какртинки, мы не отказываемся, и это пока MVP? Неплохо бы было тогда в сигнатуре функции хэш, а не путь к файлу, наверное.> findSimilar(2)> SELECT ..., LPAD(HEX(`hash{$i}`), 16, '0') AS `hash{$i}_hex`, ...Но зачем? В SimilarImageCandidate же нету самого хэша.> self::hammingDistanceBetweenHex($hashLimbs[$i], $line["hash{$i}_hex"])А.Предлагаю:1. В doCalculateHash(2) (просто calculateHash?) добавить опциональный параметр, if set возвращать limbs как массив PHP int'ов;2. Отказаться от UNSIGNED в базе для limbs. Или не отказываться, XOR инвариантен знаковости, одинаковая знаковость типов XOR'ируемых элементов в MariaDB не нужна;3. Гнать в базу limbs не строками, а int'ами SELECT board, postid, bit_count($limbs[0] ^ `phash_limb_0`) + bit_count($limbs[1] ^ `phash_limb_1`) + ... AS hamming_distance WHERE ..., bit_count($limbs[0] ^ `phash_limb_0`) + bit_count($limbs[1] ^ `phash_limb_1`) + ... < $max_distance ORDER BY postid DESC` ;3.1. (Можно переделать выражение выше на CTE, если хочется подстановки значений взамен '?'.)Теперь по поводу totalPopcountOfAllBytes. Если поручить базе считать расстояние, оно, it would seem, вместе с hammingDistanceBetweenHex оказывается не нужно. Если для чего-то окажется нужно, то такие соображения. Вызов ord, как ни странно, штука наудивление тяжёлая, если память моя верна, да и строить lookup table придётся, считай, при каждом запуске, пока кэширование не настроено. Сirca стандартный (увы, в PHP ни logical shift, ни настоящего integer multiplication) SWAR approach точно не куда элегантнее и быстрее?private static function totalPopcountOfAllBytes(string $s) : int { $limbs = unpack("q*", $s); $result = 0; foreach($limbs as $limb) { $popcnt = ($limb & 0x5555555555555555) + (($limb >> 1) & 0x1555555555555555); $popcnt = ($popcnt & 0x3333333333333333) + (($popcnt >> 2) & 0x3333333333333333); $popcnt = ($popcnt + ($popcnt >> 4)) & 0x0F0F0F0F0F0F0F0F; $popcnt = $popcnt + ($popcnt >> 32); $popcnt = $popcnt + ($popcnt >> 16); $popcnt = $popcnt + ($popcnt >> 8); $popcnt &= 0xFF; $popcnt -= $limb >> 63; $result += $popcnt; } return $result;} как-то так, хотя вроде можно ещё снизить количество операций, развернув цикл или увеличив шаг.Таким образом, возможно, удобнее окажется в коде хранить хэш в PHP int'ах, а не в строках.Возможно, есть смысл добавить опцию, что fbe_round_phash выводил в stdout бинарь, а не хекс.Наверное, word ближе к общеупотребимому, чем limb для мультибайтового регистрооперируемого. Но у word нету смысла, что часть чего-то.
$candidates = $similar_class->findSimilar($_FILES['imagefile']['tmp_name'], KU_SIMILAR_MAXDISTANCE);
findSimilar(2)
SELECT ..., LPAD(HEX(`hash{$i}`), 16, '0') AS `hash{$i}_hex`, ...
self::hammingDistanceBetweenHex($hashLimbs[$i], $line["hash{$i}_hex"])
SELECT board, postid, bit_count($limbs[0] ^ `phash_limb_0`) + bit_count($limbs[1] ^ `phash_limb_1`) + ... AS hamming_distance WHERE ..., bit_count($limbs[0] ^ `phash_limb_0`) + bit_count($limbs[1] ^ `phash_limb_1`) + ... < $max_distance ORDER BY postid DESC`
private static function totalPopcountOfAllBytes(string $s) : int { $limbs = unpack("q*", $s); $result = 0; foreach($limbs as $limb) { $popcnt = ($limb & 0x5555555555555555) + (($limb >> 1) & 0x1555555555555555); $popcnt = ($popcnt & 0x3333333333333333) + (($popcnt >> 2) & 0x3333333333333333); $popcnt = ($popcnt + ($popcnt >> 4)) & 0x0F0F0F0F0F0F0F0F; $popcnt = $popcnt + ($popcnt >> 32); $popcnt = $popcnt + ($popcnt >> 16); $popcnt = $popcnt + ($popcnt >> 8); $popcnt &= 0xFF; $popcnt -= $limb >> 63; $result += $popcnt; } return $result;}
>>1001080> В будущем от отправки скриптом просто хэша, а не всей какртинки, мы не отказываемся, и это пока MVP?Да.> Неплохо бы было тогда в сигнатуре функции хэш, а не путь к файлу, наверное.Новый метод findSimilarByHash() создаётся тривиально (а findSimilar() переписывается в его вызов). Зачем это делать сейчас?> Предлагаю:> 1. В doCalculateHash(2) (просто calculateHash?) добавить опциональный параметр, if set возвращать limbs как массив PHP int'ов;> 2. Отказаться от UNSIGNED в базе для limbs. Или не отказываться, XOR инвариантен знаковости, одинаковая знаковость типов XOR'ируемых элементов в MariaDB не нужна;> 3. Гнать в базу limbs не строками, а int'амиWhat for? Сейчас мы не зависим от bitness’а PHP, и не нужно дублировать ...$hashLimbs. Слотов для кандидатов всего 30, это какие-то микрооптимизации уже же.> Вызов ord, как ни странно, штука наудивление тяжёлая, если память моя верна, да и строить lookup table придётся, считай, при каждом запуске, пока кэширование не настроено.Ufufu. Спавн трёх процессов (можно просимулировать как exec('whoami | wc -l')), что у нас и происходит, в ≈4000 раз тяжелее этого вычисления (и вашей, и моей версии). Подозреваю, что взаимодействие с БД ещё медленнее.> Возможно, есть смысл добавить опцию, что fbe_round_phash выводил в stdout бинарь, а не хекс.Хи-хи~, got you!$ php -r '$b64 = base64_encode("abcd\r\n\r\nfoo\n"); var_dump(exec("echo " . $b64 . " | base64 -d"));'string(3) "foo"$> SWAR approach точно не куда элегантнее и быстрее?Элегантнее было бы так:private static function totalPopcountOfAllBytes(string $s) : int { return gmp_popcount(gmp_import($s));}Только php-gmp нужен.Ну или как сейчас, только без $lookupTable. Это всё равно копейки.> Наверное, word ближе к общеупотребимому, чем limb для мультибайтового регистрооперируемого. Но у word нету смысла, что часть чего-то.Это терминология из gmp. A limb contains a number of digits.
...$hashLimbs
exec('whoami | wc -l')
$ php -r '$b64 = base64_encode("abcd\r\n\r\nfoo\n"); var_dump(exec("echo " . $b64 . " | base64 -d"));'string(3) "foo"$
private static function totalPopcountOfAllBytes(string $s) : int { return gmp_popcount(gmp_import($s));}
> $ php -rНет, плохой пример, но там всё ещё веселее — оно убирает trailing whitespace у последней строки:$ php -r '$b64 = base64_encode("test "); var_dump(exec("echo " . $b64 . " | base64 -d"));'string(4) "test"$Workaround’ить в PHP можно, но в целом это очень плохая идея. "$(command)" в bash/POSIX sh, например, не ограничивает вывод последней строкой, но зато удаляет все trailing newlines. И подобные проблемы почти в любом ЯП будут.
$ php -r
$ php -r '$b64 = base64_encode("test "); var_dump(exec("echo " . $b64 . " | base64 -d"));'string(4) "test"$
"$(command)"
>>1001083> Сейчас мы не зависим от bitness’а PHPАн-нет. У нас уже есть parser.class.php, так что зависим. Да и в чём проблема ограничить среду выполнения FBE 64-битными системами? ИМХО, проблем никаких, а удобства есть.> What for?Позволяет укоротить similar_images.class код на два метода, а построение SQL-запроса в findSimilar укоротить на LPAD'ы, HEX'ы, CONV'ы и CAST'ы и позволяет для того запроса использовать одно и то же $bit_count_expr выражение для WHERE и для SELECT кляуз. А ещё оптимизация.> Ufufu. Спавн трёх процессов (можно просимулировать как exec('whoami | wc -l')), что у нас и происходит, в ≈4000 раз тяжелее этого вычисления (и вашей, и моей версии).Perhaps, но мне реализация totalPopcountOfAllBytes пока кажется слишком громоздкой for what it's worth. Потом, если когда-нибудь будет поиск картинок только по хэшу, то будет без сповнов.> Только php-gmp нужен.Оно же не сильно тяжёлое? Если не переносить в БД и оставлять расчёты веса/расстояния Хэмминга в PHP, то почему бы и не подключить. С одной стороны, тянуть либу ради мелкофункции так себе, а с другой, ну что поделать, раз в PHP нету даже полноценной компьютерной арифметики, не говоря уж о BMI.
>>1001086Нет. Я думаю, должно быть одно каноническое представление хэша в виде строки. Все действия на них хэшах быть на строках. Иначе сложнее будет отлаживать (в том числе endianness issues — у нас строковое представление хэша в big endian, а машины-то little endian).Хэшер на клиенте-то что будет слать на сервер? Сырые байты? Запросы будет смотреть сложно.В целом, всё должно быть максимально просто и дубово.> А ещё оптимизация.Оптимизация чего? Heap с результатами в MariaDB на 30 элементов? Там же LIMIT 30.> Perhaps, но мне реализация totalPopcountOfAllBytes пока кажется слишком громоздкой for what it's worth.Если вы про размер кода, то с этим можно согласиться (but see the latest commit). Если вы про вычисления, то это копейки по сравнению со всем остальным, включая генерацию вывода, взаимодействие с БД и спавнинг процессов. И тем, что отдельный процесс интерпретатора пхп поднимается на каждый запрос.Счёт хэша от 1x1 PNG (90 байт) тяжелее этих вычислений в ≈91000 раз.> Потом, если когда-нибудь будет поиск картинок только по хэшу, то будет без сповнов.Это как? Клиентов без WASM не будем поддерживать и вообще на сервере не будем уметь считать хэши?Сейчас оно даже без JS работает. Только девочку нужно с первой попытки угадывать, но оно так и было до этого.> Оно же не сильно тяжёлое?Это официальный модуль PHP, но нужно ставить отдельным пакетом везде (пакет php-gmp в Debian, ни сам пхп, ни апач его не требуют).Нет, не нужно плодить зависимости для такого.И так процесс установки слишком неочевидный.
>>1001087> в том числе endianness issues — у нас строковое представление хэша в big endian, а машины-то little endianПокуда limbs PHP кодом всюду читаются, как little endian, никаких issues быть не должно. popcnt(a ^ b) = popcnt(bswap(a) ^ bswap(b)). А больше как для popcnt(a ^ b) хэши те и не нужны совсем.$limbs = array_values(unpack("q*", hex2bin($client_hash_str)));При получении строки от клиента. Или, скажем, от fbe_round_phash.$to_str = bin2hex(pack("q*", ...$limbs))И обратно. Можно оформить как class PHash, или как функции limbsToString(), limbsFromString().Вроде всё просто же, и всилу упрощения взаимодействий с БД ещё проще становится. Dunno.Жаль, в PHP 8.5 не завезли "q>*".> Это как?Я плохо выразился. "Только по хэшу" as in "без картинки".
$limbs = array_values(unpack("q*", hex2bin($client_hash_str)));
$to_str = bin2hex(pack("q*", ...$limbs))
Потом будет graceful-extend капчи, чтобы та же капча/фапча работала ещё один раз для постинга (но не для ещё одного поиска похожих).>>1001088А админу потом думать, почему в БД значения как бы перевёрнуты, но перевёрнуты только внутри троек из 16 символов, а порядок самих троек не перевёрнут, и внутри троек перевёрнуты только сами соседние пары из двух символов, а внутри этих пар символы символы не перевёрнуты.
>>1001089Я очень сомневаюсь, что Соус или Кот знают функцию CONV(), чтобы вдруг озадачиться этим вопросом.Да и в целом мне кажется крайне маловероятной необходмость лезть в базу ручками и пытаться восстановить хэшевую строку из внутреннего формата или загонять ту строку туда. Хотя с big endian это дейстительно проще.
>>1001091Впрочем, я согласен, что вычисление distance можно переложить на БД без дубликации кода и ещё каких-то проблем. Что я и сделал.А ещё, вместо каких-то сомнительных костылей на стороне сервера для graceful-extend капчи, лучше просто JS-ом сказать пользователю, что ему нужно ввести капчу ещё раз после поиска похожих.Открыл PR.
preview_clicked() не обрабатывает сетевые ошибки. Таким образом кнопка не возвращается из disabled состояния, то есть UI ломается, требуя рефреша всей страницы.
preview_clicked()
>>1001096Fixed in PR #27.
>>1001097That was fast! Thx.