программирование
Картинка в терминале
Несколько лет назад программа «айТерм2» (iTerm2, терминал для «Мака») обзавелась поддержкой графики в командной строке. Сильной необходимости в ней нет, но иногда это удобно — можно посмотреть картинку на удалённом сервере, не выкачивая её себе.
Вообще уже очень давно существует формат «Сиксел», рождённый в незапамятные времена компанией «ДЭК» (DEC), его даже поддерживают некоторые терминалы, но он значительно сложнее придуманного авторами «айТерма2».
Я это знаю, так как
В общем виде тот и другой форматы представляют собой управляющие последовательности, после которых передаётся закодированная картинка.
Мне тут подумалось, что было бы интересно попробовать вставить внутрь настоящей картинки её закодированную копию, чтобы при попытке вывода её в консоль в виде текста, в терминал попадали управляющие коды и на экран выводился не бинарный мусор, а картинка.
Для этого я нарисовал небольшой ГИФ и вставил закодированную картинку после изображения следующей командой:
cat test.gif \
<(echo -ne "\033[3F\033[J\033]1337;File=inline=1:") \
<(base64 test.gif) \
<(printf "\a")\
> test2.gifЕстественно, так как бинарный код изображения идёт первым, при выводе на экран его так же будет видно, поэтому я добавил другие управляющие конструкции (большинство терминалов их поддерживают), возвращающие курсор на место и вычищающие бинарщину.
В данном случае я сначала двигаю курсор на три строки вверх (столько занимает бинарный мусор на экране), потом произвожу очистку от курсора до конца экрана.
Теперь буду пугать наших системных администраторов картинкой, которую видно сразу и в терминале, при выводе командой cat, и в графическом интерфейсе.
99 бутылок: dc
68. DC — программа для арифметических вычислений с произвольной точностью
Поддерживаются 256 стековых регистров и основной стек программы. На стеках могут размещаться числа и строки, последние могут исполняться, как подпрограммы. Команды однобуквенные, некоторые имеют операнд; числа записываются как есть, строки — между квадратными скобками.
Компактно «песню о пиве» можно записать таким кодом:
[n10P]su[[s]P]ss[[No bottles]Plon2+Q]sn
[d0=ndn[ bottle]n1!=slon]sb[ of beer]so
[ddlbx[ on the wall, ]nlbx[.]lux
[Take one down and pass it around,]lux
1-dlbx[ on the wall.]lux[]luxd0!=B]sB
99lBx
[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.
] nА вот вариант с комментариями (которые, правда, не делают программу уж сильно понятнее):
# beer.dc
# Степанищев Е. В. bolknote.ru
# Печать с переводом строки, мне не нравится помещать
# его в строку символом — ломаются отступы
[
n 10 P
] su
# Печатаем «s»
[
[s] P
] ss
# Печатаем «No bottles of beer», убираем (сложением) ноль со стека,
# прерываем выполнение родителя (выходим из двух уровней)
[
[No bottles] P lon
2+Q
] sn
# Вывод кол-ва бутылок с «bottle(s) of beer»
[
d 0 =n
d n [ bottle] n 1 !=s lon
] sb
# « of beer» — в регистр «о», будем использовать
# для вывода части фразы
[ of beer] so
# основной цикл программы (вызывается рекурсивно)
[
d
d lbx [ on the wall, ] n lbx [.] lux
[Take one down and pass it around,] lux
1-
d lbx [ on the wall.] lux [] lux
d 0 !=B
] sB
99 lBx
[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.
] nСтрелочные функции в PHP 7.4
Версия 7.4 интерпретатора ПХП, которая должна появиться осенью, смотрится очень привлекательно. Одни только стрелочные функции чего стоят — код будет выглядеть куда компактнее.
Как только прочитал про это нововведение, очень заинтересовался, даже скомпилировал интерпретатор и попробовал предлагаемый синтаксис в деле. Действительно удобно, смутило только, что в описании ничего не нашлось про рекурсивный вызов. Попробовал на практике:
$f = 'magic';
($f = fn() => var_dump($f))();Я ожидал, что в данном случае функция выведет своё представление, но на самом деле выводится слово «magic». Определённая логика тут есть конечно, — сначала создаётся тело функции, вместе с замыканием всех используемых переменных в локальной зоне видимости, и только потом получившееся присваивается переменной.
Впрочем, после непродолжительных экспериментов обнаружилось, что функцию внутри себя можно получить, если передать её как параметр. Не очень изящно, но работает:
$f = 'magic';
($f = fn($f) => var_dump($f))($f);Вот практическое использование рекурсии со стрелочными функциями на примере программы, генерирующей SBox для ГОСТовых алгоритмов:
$k=fn($i)=>ord('@`rFTDVbpPBvdtfR@¬p?â>4¦é{zãq5§è'[$i]);$p=fn($x)=>($f=fn($x,$f,$l=256)=>
--$l*$x^$l?$f($x+$x^($x>>7)*285,$f,$l):($l%17?$k($l%17)^$k(17+$l/17)^17:$k($l/17)^188))($x,$f);Кстати, неделю назад началось соревнование по написанию самой короткой версии такой программы, рекорд на настоящий момент — 58 символов. У меня получилось 183, но за размером я не гнался, ПХП чересчур многословен для такого, было интересно сам синтаксис погонять.
99 бутылок: Юᓂ곧⎔
67. Юᓂ곧⎔ — эзотерический язык программирования, кратко описанный в пятничном посте в блоге кандидата математических наук Дэвида Мадора. Основная идея — придумать язык, обфусцированный ресурсами Юникода.
Недавно появился транслятор из «Юᓂ곧⎔» в Си, благодаря чему можно писать и запускать программы на этом необычном языке.
Согласно спецификации языка, все имена функций должны записываться кириллицей, десятичные цифры — быть монгольскими, в именах аргументов должна использоваться хирагана и тому подобное.
Несмотря на это, писать не особо сложно — можно быстренько накидать требуемое в Си, а потом перевести программу в «Юᓂ곧⎔», подсмотрев правила в трансляторе.
Интересно как смотрится программа под разными операционными системами. «МакОС», насколько я могу судить, отображает всё корректно.
❝99.⎔❞
ℤбутылок «ℤぶ»
☹
¿«ぶ ⇔ ☰» писать «“⁌☱☵☶⁍⁌☱☵☷⁍⁌☴☰⁍”»।
¬писать «“﹪ℤ⁌☴☰⁍” ¦ ぶ»।
писать «“⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍”»।
¿«ぶ ⇔ ☱»।¬писать «“⁌☱☶☳⁍”»।
☺
⌂ «»
☹
∀«ቁምፊ 工 ← ᠙᠙। 工 ≩ ☰। ∇工»
☹
бутылок «工»।
писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍\
⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☴⁍⁌☴☰⁍”»।
бутылок «工»।
писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☵☶⁍␊”»।
писать «“⁌☱☲☴⁍⁌☱☴☱⁍⁌☱☵☳⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☱☴☵⁍⁌☴☰⁍\
⁌☱☴☴⁍⁌☱☵☷⁍⁌☱☶☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☴☰⁍⁌☱☶☰⁍⁌☱☴☱⁍⁌☱☶☳⁍\
⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☱⁍⁌☱☶☴⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☶☲⁍⁌☱☵☷⁍⁌☱☶☵⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☵☴⁍⁌☴☰⁍”»।
бутылок «工−᠑»।
писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍\
⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☶⁍␊␊”»।
☺
писать «“⁌☱☱☶⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☵☷⁍\
⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍\
⁌☱☶☲⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍\
⁌☵☴⁍⁌☴☰⁍⁌☱☵☶⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍\
⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☵☶⁍␊”»।
писать «“⁌☱☰☷⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☳⁍\
⁌☱☶☴⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☶☵⁍⁌☱☷☱⁍⁌☴☰⁍\
⁌☱☶☳⁍⁌☱☵☷⁍⁌☱☵☵⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☵☴⁍⁌☴☰⁍⁌☷☱⁍⁌☷☱⁍⁌☴☰⁍\
⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍\
⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☶⁍”»।
☺sudo по отпечатку пальца ★
На «Маке» я нередко использую командную строку — некоторые мои задачи через неё выполнять проще, чем через графический интерфейс. Как правило для этого используется непривилегированный пользователь, но иногда приходится
Обычно она запрашивает специальный пароль, чтобы убедиться, что тот, кто её запускает, действительно имеет право повысить полномочия.
И вот сегодня один из сотрудников спросил — работает ли у меня на «Маке» sudo по отпечатку пальца.
/etc/pam.d/sudo
первой строкой добавить
auth sufficient pam_tid.so
И всё, при следующем запуске sudo можно просто приложить палец к сканеру. Экономит уйму времени, спасает от опечаток, никто не сможет подсмотреть пароль.
Сборка пакетов под POWER8
По случаю получил доступ к оборудованию на процессорах POWER8 и, в качестве домашнего проекта, попробовал развернуть там один из наших продуктов. Оказалось, для этого требуется немалое количество стороннего софта, до этого момента я даже не представлял себе насколько немалое. В стандартных репозиториях
Хорошо, что для бо́льшей части существуют SRPM, но несколько десятков пакетов всё же пришлось собрать полностью вручную — разбираться что они должны содержать, компилировать необходимое, писать спецификацию.
В последнем случае меня несколько раз выручил придуманный по ходу дела трюк.
Если пакет существует для другой архитектуры, то черновую спецификацию для него можно получить через утилитку rpmrebuild. Она предназначена для создания RPM из уже установленного пакета и умеет создавать спецификации автоматически.
Требуемый пакет нужно сначала установить на машину с той архитектурой, для которой он существует, а потом вытянуть из rpmrebuild сгенерированную спецификацию. Пример для пакета
echo|EDITOR=cat rpmrebuild -e php-pecl-imagick 2>&- > /tmp/php-pecl-imagick.specДля того, чтобы достать спецификацию, приходится вызвать её на редактирование с заменой редактора на команду cat. Более простого способа я не обнаружил.
Потом остаётся только скомпилировать нужный софт на POWER8, поменять внутри спецификации платформу, выкинуть мусор и подсунуть её утилите rpmbuild; по сообщениям об ошибках можно понять куда и что из скомпилированного требуется положить.
При желании это можно было бы даже автоматизировать, но я на это силы тратить не стал, не терпелось увидеть результат. В итоге, функциональное тестирование показало, что всё работает без ошибок.
Reduce
Мы с коллегами сейчас проходим курс по машинному обучению, организованный для нас университетом Иннополиса. Курс рассчитан на два месяца, к настоящему моменту мы бегло пробежались по высшей математике и начали изучать Пайтон — один из языков, популярных в машинном обучении.
По Пайтону соскучился — он мне нравится, а я всерьёз не программировал на нём несколько лет. С удовольствием смотрю что наворотили в третьей версии, которую я почти не трогал. Бо́льшая часть языка легко и почти сразу вспоминается, но долгое отсутствие практики всё же сказывается.
Решали сегодня задачки из «Проекта Эйлер», в частности
from functools import reduce
def read():
with open('p067_triangle.txt') as f:
for line in f.readlines()[::-1]:
yield tuple(int(x) for x in line.strip().split(' '))
reduce(lambda cur, prv: [max(cur[pos:pos+2])+v for pos, v in enumerate(prv)], read())Пока решали, преподаватель упомянул, что задачу можно решить через фолдинг. Я загорелся идеей — настолько не умею обращаться с фолдингом, что ни разу не сумел его
Результат мозговых усилий выше. Код сократился до одной строки (функция над ней — просто чтение данных).
Наверное хорошо бы порешать подобные задачи — которые гарантированно изящно решаются через фолдинг, чтобы плотнее уложить концепцию на извилины, но не знаю где такие задачки можно было бы взять. Впрочем есть и другой путь — начать
На закуску вот вам фолдинг на «Баше», взятый из комментария со «Стека Оверфлоу»:
foldl() {
echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)
# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)Тут суммируются двадцать псевдослучайных чисел из диапазона 0—999.
«Apple I» в музее техники Эпл
Пока был в Москве, сходил в «Музей техники Эпл», благо три дня в неделю он работает до 9 вечера, так что была возможность заскочить после работы.
Я уже был в нём несколько лет назад, но за это время впечатления стёрлись напрочь, радовался каждому гаджету, как в первый раз.
Правда на этот раз я шёл в музей не просто посмотреть на винтажную технику, но и с мыслью запустить свою программу для «Эпла I» вживую, благо в музее можно поработать за любой машиной. Я, например, в этот раз не упустил возможность поближе познакомиться с компьютером NeXT, ну где сейчас ещё такое увидишь в работоспособном состоянии?
Оригинального «Эпла I» в музее нет — в мире их осталось меньше сотни, зато есть реплика, но не повезло — в этот день, как нарочно, у неё не работала клавиатура. Моя программа небольшая, много времени набор на клавиатуре не занял бы.
Договорились с сотрудником музея — я ему пришлю свою поделку, а он, когда компьютер отремонтируют, её запустит и снимет для меня видео как она работает. Правда для этого придётся
Думаю, такой конвертор в звук должен существовать, но пока найти его мне не удалось.
ZMODEM
Для проекта, которым мы тут в Москве, в командировке занимаемся, заказчик предоставил компьютер на Винде, который по РДП соединяется с виндовой же виртуалкой и вот откуда по ssh имеется доступ на целевые сервера.
Конечно мы с собой привезли образы виртуалок с проектом, но всё равно приходится
Непростое занятие, которое надо делать параллельно с другими делами. Очень раздражает. Ситуация немного улучшилась, когда я
ZMODEM — довольно древняя штука, сейчас уже малоизвестная, использовалась ещё на бибиэсках, там подобных протоколов было, как грязи. Я узнал о ней из ssh-клиента SecureCRT, пользовался им когда ещё сидел под Виндоуз. SecureCRT на команду передачи файла на сервер, запускает на удалённой стороне утилиту rz, открывает диалог выбора файлов и очень бодро перекачивает выбранное. Удобно.
Реинкарнация утилиты rz нашлась в виде пакета lrzsz, а запуск установленной команды открыл окно выбора файлов — XShell прекрасно понял чего я от него ожидаю. Жизнь немного улучшилась.
Физическое воплощение TCP-пакета
★
В чате бывших сотрудников «Яндекса» сегодня всплыла безвестная картинка с пакетом (на самом деле — сумкой) с принтом в виде TCP-пакета. Каламбур зашёл, местные гики изошли слюной.
Я тоже заинтересовался — где такую взять и ценой вопроса. С заметным трудом разыскал источник — китайский мономагазин, сумка стоит
Видимо не удастся такую получить, разве что найти
Apple I ★
Заметил позитивную тенденцию — меня снова стали интересовать статьи на «Хабре», вплоть до зуда
Не знаю, что ребята сделали, но направление верное, молодцы!
В общем, прочитал недавно там статью про самодельный «Эпл I» и сегодня не спал до двух ночи.
Нет, свой компьютер я не собрал, да и начиналось всё невинно — сначала скачал несколько эмуляторов, попробовал
Для этой цели мне очень подошёл «ОупенЭмулятор»
Первая моя программа умела совсем мало — только бесконечно выводить на экран таблицу символов. Она такая короткая (всего восемь байт), так как для самого сложного — печати на экран, используется вызов ECHO, встроенной в «Эпл I» программы «Woz Monitor», — по всей видимости её писал Возняк, поэтому она так называется.
В ассемблере 6502 особо не развернёшься — три восьмибитных регистра (A, X, Y), 56 команд (не считая нескольких недокументированных), только целые числа, нет деления и умножения. Я совсем не помню свой первый ассемблер
Тем интереснее было написать
Кстати,
Там всего несколько страничек, вникнуть просто и сейчас (о ужас!) мне даже удобно.
Самый долгий merge в моей жизни ★
Заметка будет интересна только программистам.
Фотография ниже лежит у меня на ноуте с августа 2013 года. Очень не люблю такое — всё нужное я привык закачивать в интернет, всё ненужное — удалять. Не мог определиться куда деть это фото, решил положить в блог, снабдив небольшим рассказом.
Наверное все программисты знают что такое «мерж» (merge) — слияние двух веток и согласование изменений, сделанных в файлах в рамках этих веток. Если системе контроля версий удаётся справить самостоятельно, то «мержи» происходят автоматически, это, в моей практике, наиболее частая ситуация. В противном случае возникает «конфликт» — «мерж» останавливается до разрешения конфликта человеком. Только человек может решить как будет выглядеть сводный код, учитывающий изменения, сделанные в двух слияемых ветках.
Я однажды попал в неприятнейшую ситуацию, когда две команды в нашей компании, в силу многих причин, независимо работали над одним и тем же продуктом около года.
Одна из команд работала над функциями, которые нужны в продукте заказчику, вторая, которой руководил я, — делала несколько довольно серьёзных изменений с заделом на будущее, в частности — внедряла шаблонизацию.
Через год попытались слить две ветки воедино и получили конфликты почти во всех основных файлах проекта. Ничего совсем уж неожиданного, конечно, особенно с учётом того, что часть кода была переписана с ПХП на «Твиг», но никогда в ещё в жизни я не видел столько конфликтов. Затронуты были, если мне не изменяет память, несколько сотен файлов.
С одной стороны, других вариантов, кроме как собрать это всё воедино, не рассматривалось, с другой стороны, объём предстоящей работы удручал.
В общем, погрустил я, погрустил, повесил табличку «Не беспокоить» и заперся в кабинете на неделю. Каждый файл с конфликтом распечатывал дважды — из каждой ветки. Потом раскладывал распечатанное на полу, выделял маркером одинаковые места, рисовал стрелками что куда переместилось, шёл к ноутбуку и так или иначе разрешал конфликт.
На фотографии — процесс разрешения конфликтов одного из файлов. Через неделю я был полностью разбит монотонностью работы, но ветки слил.
Как открыть файл в формате HLP
Потребовалось открыть файл в древнем формате HLP. Оказавается сейчас его ничего не открывает, даже операционная система Виндоуз, под которую он
Возможно существует
diff --ignore-blank-lines --minimal -urd a/winhelpcgi/dib2png.c b/winhelpcgi/dib2png.c
--- winhelpcgi-1.0/winhelpcgi/dib2png.c 2004-06-15 11:38:40.000000000 +0400
+++ winhelpcgi-1.0-patched/winhelpcgi/dib2png.c 2018-11-03 13:59:03.405031382 +0300
@@ -85,7 +85,7 @@
/* Set error handling. REQUIRED if you aren't supplying your own
* error hadnling functions in the png_create_write_struct() call.
*/
- if (setjmp(png_ptr->jmpbuf))
+ if (setjmp(png_jmpbuf(png_ptr)))
{
/* If we get here, we had a problem writing the file */
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
@@ -93,7 +93,7 @@
}
/* Set the I/O callback function to transfer directly to memory */
- png_set_write_fn(png_ptr, (voidp) sbout, user_write_data, NULL);
+ png_set_write_fn(png_ptr, (png_voidp) sbout, user_write_data, NULL);
/* Get access to the windows DIB data */
lpbmi = (LPBITMAPINFOHEADER) GlobalLock(hDIB);Утилита с грехом пополам преобразовала файл в нечитаемый ХТМЛ, который пришлось перекодировать:
/usr/local/bin/winhelpcgi.cgi --tar HELP.HLP |
php -r 'echo mb_convert_encoding(strtr(stream_get_contents(STDIN), ["\0"=>""]),
"CP1252", "HTML-ENTITIES");' > help.htmlПосле этого читать можно, но если
Числа от «n» до нуля без сравнений
На «Хабре» интересную задачу увидел, требуется написать на Си программу, выводящую числа от «n» до нуля, не используя (скрыто или явно) операторы сравнения.
Мой вариант:
#include <stdlib.h>
#include <stdio.h>
void print(const int n) {
printf("%d\n", n - 1);
}
int main(int argc, char* argv[])
{
const int N = atoi(argv[argc - 1]);
void (*f[])(int) = {print, exit};
for (int n = -1;;n++) {
f[~n/~N](N - n);
}
}Слоны
Есть такая система репликации на триггерах для СУБД «Постгрес» — Slony, не знаю кто как читает это слово по всему миру, я всегда произносил его как «Сло́ни» — вслед за нашими системными администраторами.
Оказывается читать это слово следует немного иначе.
Примерно в конце девяностых на логотипе «Постгреса» появился слон, к этому логотипу, да и видимо вёрстке сайта, приложили руку россияне. Так картинка со слоном называлась «slonik.gif» и прислал её, как достоверно известно, петербуржец Дмитрий Самерсов, рисунок сделала
Ян Вик, активный участник сообщества, в то время искал название для своей системы репликации и поинтересовался что значит «slonik», а потом спросил как будет много слонов, так и родилось название «Slony» — «Слоны́».
mozjpeg 3.3.1
Заворачивал в пакет для седьмой ЦентОСи относительно свежий mozjpeg. В теории всё просто, на практике просто так пакет не собрался, пришлось корректировать руками. Запишу себе сюда, чтобы не забыть что делал.
Нужно отредактировать в двух местах файл mozjpeg.spec.in (ниже готовый патч под утилиту patch):
diff -urd --ignore-blank-lines --minimal a/release/mozjpeg.spec.in b/release/mozjpeg.spec.in
--- a/release/mozjpeg.spec.in 2017-07-10 13:58:14.000000000 +0300
+++ b/release/mozjpeg.spec.in 2018-10-12 12:30:04.172828265 +0300
@@ -8,7 +8,7 @@
%define _datadir %{__datadir}
# Path under which docs should be installed
-%define _docdir /usr/share/doc/%{name}-%{version}
+%define _docdir /opt/mozjpeg/doc/%{name}-%{version}
# Path under which headers should be installed
%define _includedir %{__includedir}
@@ -35,7 +35,7 @@
Release: @BUILD@
License: BSD-style
BuildRoot: %{_blddir}/%{name}-buildroot-%{version}-%{release}
-Prereq: /sbin/ldconfig
+Requires(pre,preun): /sbin/ldconfig
%ifarch x86_64
Provides: %{name} = %{version}-%{release}, @PACKAGE_NAME@ = %{version}-%{release}, libturbojpeg.so()(64bit)
%elseДальше запустить:
autoreconf -fiv
./configure
make rpmИ получится пакет.
Предложил авторам утилиты правку на «Гитхабе», посмотрим примут ли.
Дополнение: ура, патч приняли в репозиторий, теперь можно не патчить самостоятельно.
Мелочь в синтаксисе SELECT
В синтаксисе запроса SELECT «Постгреса» есть приятная мелочь, которая хоть и нестандартна, но греет мне душу, — согласно описанию, выбираемые поля (часть между SELECT и FROM) можно опускать.
Вот как это работает в консоли:
SELECT FROM usr;
--
(588910 строк)Кстати, можно ещё поставить там ключевое слово ALL, будет результат будет точно такой же.
Для чего это может пригодиться? Для подзапросов с EXISTS. Мне не нравится, как выглядит всем привычный вариант:
SELECT COUNT(*)
FROM document
WHERE EXISTS (
SELECT NULL
FROM document_n
WHERE id = document.id
)В подзапросе после SELECT по стандарту надо
SELECT COUNT(*)
FROM document
WHERE EXISTS (
SELECT
FROM document_n
WHERE id = document.id
)Смотрится как будто чуть почище. Знаю, многие ребята осуждают использование особенностей реализации эскуэля в конкретной СУБД,
Если
Примерная оценка в Постгресе
Читая документацию по «Постгресу», набрёл на интересную конструкцию — TABLESAMPLE. Она позволяет обработать запросом не всю таблицу, а только указанный процент, причём строки выбираются случайным образом.
Например, встречается такая задача — показать
SELECT id FROM (
SELECT id FROM very_big_table TABLESAMPLE SYSTEM (.0001) LIMIT 100
) _ ORDER BY RANDOM() LIMIT 1Тут выбирается одна десятитысячная процента таблицы (0,0001%), а потом из этой выборки берётся первая строка. На настоящей таблице с почти миллиардом строк, такой запрос у меня занял около ста миллисекунд.
SYSTEM тут — метод выборки. Их всего два, второй (BERNOULLI) даёт более случайные и аккуратные результаты, но работает
А вообще TABLESAMPLE хорошая штука, когда нужно быстро прикинуть результат. Например, у вас
Типа, сколько в среднем примерно сотрудники некой гипотетической компании тратят на обед в зависимости от пола (оценка по одному проценту данных):
SELECT sex, AVG(spent)
FROM meal TABLESAMPLE SYSTEM (1)
WHERE mtime BETWEEN SYMMETRIC '12:00:00' AND '14:00:00'
GROUP BY 1Или сколько примерно раз я ездил такси «Везёт» за последние семь лет (оценка по пяти процентам и экстраполяция):
SELECT COUNT(*)*20
FROM taxi_call TABLESAMPLE BERNOULLI (5)
WHERE carrier='vezet' AND cdate >= '2011-08-03'Шило на мыло
Несколько лет назад, один из программистов написал в нашем продукте интересный код, который я сильно упростил, чтобы показать суть:
<?php
$array = '';
$array[PHP_INT_MAX] = 1;Главное тут в том, что массив
Несмотря на эту странность, всё работало — ПХП на втором присваивании преобразовывал строку в массив.
Оказалось, что в ПХП 7.1 и выше (мы недавно перешли с 7.0 на 7.2), преобразование в массив тут больше не происходит.
Статический анализ в Go
С интересом попробовал в действии gocritic — статический анализатор для Гоу, статья о котором в прошлом месяце появилась на «Хабре». Он в самом начале пути,
Для теста взял один из внутренних проектов нашей компании — узкоспециализированный поисковый сервис, который размещает данные в памяти. Проекту четыре года, можно было ожидать, что в нём скопилось
Просто так gocritic не запустился, упал
После успешного запуска получилось примерно два экрана замечаний, большей частью относящихся к устаревшим за время существования проекта практикам, но парочка замечаний была действительно полезна. Жаль, что пока нет интеграции
Как бы то ни было, большинство замечаний были однотипными и много времени правка не заняла — помогли регулярные выражения. Теперь, даже со включенными экспериментальными и опциональными проверками, анализатор ругается только на одно место — он ошибочно считает, что раз у функций одинаковая сигнатура, то и сами функции одинаковые, рекомендует дать им имя и вызывать по имени.
Как я уже говорил,
rangeExprCopy: copy of utf (256 bytes) can be avoided with &utfstdExpr: can replace "POST" with net/http.MethodPostПо моему мнению очень полезный проект, желаю ему дальнейшего развития!