программирование

Картинка в терминале

Несколько лет назад программа «айТерм2» (iTerm2, терминал для «Мака») обзавелась поддержкой графики в командной строке. Сильной необходимости в ней нет, но иногда это удобно — можно посмотреть картинку на удалённом сервере, не выкачивая её себе.

Вообще уже очень давно существует формат «Сиксел», рождённый в незапамятные времена компанией «ДЭК» (DEC), его даже поддерживают некоторые терминалы, но он значительно сложнее придуманного авторами «айТерма2».

Я это знаю, так как когда-то разобрался в обоих форматах и даже побаловался с тем, что придумали в «айТерме2» — написал программу на «баше», где нарисованный глаз следил за курсором мыши в терминале.

Скриншот: два файла test.gif и test2.gif (24x96) с вертикальным текстом HELP рядом с терминалом bash, где выполнена команда cat ~/Downloads/test2.gif, выводящая тот же текст HELP.
Картинку с надписью «HELLO» видно сразу и в графической среде, и в терминале

В общем виде тот и другой форматы представляют собой управляющие последовательности, после которых передаётся закодированная картинка.

Мне тут подумалось, что было бы интересно попробовать вставить внутрь настоящей картинки её закодированную копию, чтобы при попытке вывода её в консоль в виде текста, в терминал попадали управляющие коды и на экран выводился не бинарный мусор, а картинка.

Для этого я нарисовал небольшой ГИФ и вставил закодированную картинку после изображения следующей командой:

cat test.gif \
    <(echo -ne "\033[3F\033[J\033]1337;File=inline=1:") \
    <(base64 test.gif) \
    <(printf "\a")\
> test2.gif

Естественно, так как бинарный код изображения идёт первым, при выводе на экран его так же будет видно, поэтому я добавил другие управляющие конструкции (большинство терминалов их поддерживают), возвращающие курсор на место и вычищающие бинарщину.

В данном случае я сначала двигаю курсор на три строки вверх (столько занимает бинарный мусор на экране), потом произвожу очистку от курсора до конца экрана.

Теперь буду пугать наших системных администраторов картинкой, которую видно сразу и в терминале, при выводе командой cat, и в графическом интерфейсе.

4 комментария

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, но за размером я не гнался, ПХП чересчур многословен для такого, было интересно сам синтаксис погонять.

2 комментария

99 бутылок: Юᓂ곧⎔

67. Юᓂ곧⎔ — эзотерический язык программирования, кратко описанный в пятничном посте в блоге кандидата математических наук Дэвида Мадора. Основная идея — придумать язык, обфусцированный ресурсами Юникода.

Недавно появился транслятор из «Юᓂ곧⎔» в Си, благодаря чему можно писать и запускать программы на этом необычном языке.

Согласно спецификации языка, все имена функций должны записываться кириллицей, десятичные цифры — быть монгольскими, в именах аргументов должна использоваться хирагана и тому подобное.

Несмотря на это, писать не особо сложно — можно быстренько накидать требуемое в Си, а потом перевести программу в «Юᓂ곧⎔», подсмотрев правила в трансляторе. Из-за этого можно мухлевать, например я разбил длинные строки слешами, потому что так позволяется делать в Си, в который в конечном счёте превратится программа.

Интересно как смотрится программа под разными операционными системами. «МакОС», насколько я могу судить, отображает всё корректно.

❝99.⎔❞
ℤбутылок «ℤぶ»
☹
	¿«ぶ ⇔ ☰» писать «“⁌☱☵☶⁍⁌☱☵☷⁍⁌☴☰⁍”»।
	¬писать «“﹪ℤ⁌☴☰⁍” ¦ ぶ»।

	писать «“⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍”»।

	¿«ぶ ⇔ ☱»।¬писать «“⁌☱☶☳⁍”»।
☺

⌂ «»
☹
	∀«ቁምፊ 工 ← ᠙᠙। 工 ≩ ☰। ∇工»
	☹
		бутылок «工»।
		писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍\
⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☴⁍⁌☴☰⁍”»।
		бутылок «工»।
		писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☵☶⁍␊”»।
		писать «“⁌☱☲☴⁍⁌☱☴☱⁍⁌☱☵☳⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☱☴☵⁍⁌☴☰⁍\
⁌☱☴☴⁍⁌☱☵☷⁍⁌☱☶☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☴☰⁍⁌☱☶☰⁍⁌☱☴☱⁍⁌☱☶☳⁍\
⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☱⁍⁌☱☶☴⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☶☲⁍⁌☱☵☷⁍⁌☱☶☵⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☵☴⁍⁌☴☰⁍”»।
		бутылок «工−᠑»।
		писать «“⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍\
⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☶⁍␊␊”»।
	☺

	писать «“⁌☱☱☶⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☵☷⁍\
⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍\
⁌☱☶☲⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍\
⁌☵☴⁍⁌☴☰⁍⁌☱☵☶⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍\
⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍⁌☱☴☵⁍⁌☱☶☲⁍⁌☵☶⁍␊”»।
	писать «“⁌☱☰☷⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☷⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☳⁍\
⁌☱☶☴⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☴☱⁍⁌☱☵☶⁍⁌☱☴☴⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☶☵⁍⁌☱☷☱⁍⁌☴☰⁍\
⁌☱☶☳⁍⁌☱☵☷⁍⁌☱☵☵⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☵☵⁍⁌☱☵☷⁍⁌☱☶☲⁍⁌☱☴☵⁍⁌☵☴⁍⁌☴☰⁍⁌☷☱⁍⁌☷☱⁍⁌☴☰⁍\
⁌☱☴☲⁍⁌☱☵☷⁍⁌☱☶☴⁍⁌☱☶☴⁍⁌☱☵☴⁍⁌☱☴☵⁍⁌☱☶☳⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☴☶⁍⁌☴☰⁍⁌☱☴☲⁍⁌☱☴☵⁍\
⁌☱☴☵⁍⁌☱☶☲⁍⁌☴☰⁍⁌☱☵☷⁍⁌☱☵☶⁍⁌☴☰⁍⁌☱☶☴⁍⁌☱☵☰⁍⁌☱☴☵⁍⁌☴☰⁍⁌☱☶☷⁍⁌☱☴☱⁍⁌☱☵☴⁍⁌☱☵☴⁍⁌☵☶⁍”»।
☺

2 комментария

sudo по отпечатку пальца ★

Окно macOS: sudo запрашивает пароль или Touch ID для администратора. Кнопки «Использовать пароль...» и «Отменить».
Запрос отпечатка пальца для команды sudo

На «Маке» я нередко использую командную строку — некоторые мои задачи через неё выполнять проще, чем через графический интерфейс. Как правило для этого используется непривилегированный пользователь, но иногда приходится что-то запускать с правами администратора. С этой целью в системе существует специальная команда sudo.

Обычно она запрашивает специальный пароль, чтобы убедиться, что тот, кто её запускает, действительно имеет право повысить полномочия.

И вот сегодня один из сотрудников спросил — работает ли у меня на «Маке» sudo по отпечатку пальца.

Что-то я даже не задумывался о такой возможности, погуглил, оказывается это элементарно включается: нужно в файл

/etc/pam.d/sudo

первой строкой добавить

auth sufficient pam_tid.so

И всё, при следующем запуске sudo можно просто приложить палец к сканеру. Экономит уйму времени, спасает от опечаток, никто не сможет подсмотреть пароль.

7 комментариев

Сборка пакетов под POWER8

По случаю получил доступ к оборудованию на процессорах POWER8 и, в качестве домашнего проекта, попробовал развернуть там один из наших продуктов. Оказалось, для этого требуется немалое количество стороннего софта, до этого момента я даже не представлял себе насколько немалое. В стандартных репозиториях кое-что нашлось, но всё равно пришлось собирать собственные пакеты, более сотни штук.

Хорошо, что для бо́льшей части существуют SRPM, но несколько десятков пакетов всё же пришлось собрать полностью вручную — разбираться что они должны содержать, компилировать необходимое, писать спецификацию.

В последнем случае меня несколько раз выручил придуманный по ходу дела трюк.

Если пакет существует для другой архитектуры, то черновую спецификацию для него можно получить через утилитку rpmrebuild. Она предназначена для создания RPM из уже установленного пакета и умеет создавать спецификации автоматически.

Требуемый пакет нужно сначала установить на машину с той архитектурой, для которой он существует, а потом вытянуть из rpmrebuild сгенерированную спецификацию. Пример для пакета php-pecl-imagick:

echo|EDITOR=cat rpmrebuild -e php-pecl-imagick 2>&- > /tmp/php-pecl-imagick.spec

Для того, чтобы достать спецификацию, приходится вызвать её на редактирование с заменой редактора на команду cat. Более простого способа я не обнаружил.

Потом остаётся только скомпилировать нужный софт на POWER8, поменять внутри спецификации платформу, выкинуть мусор и подсунуть её утилите rpmbuild; по сообщениям об ошибках можно понять куда и что из скомпилированного требуется положить.

При желании это можно было бы даже автоматизировать, но я на это силы тратить не стал, не терпелось увидеть результат. В итоге, функциональное тестирование показало, что всё работает без ошибок.

Оставить комментарий

Reduce

Мы с коллегами сейчас проходим курс по машинному обучению, организованный для нас университетом Иннополиса. Курс рассчитан на два месяца, к настоящему моменту мы бегло пробежались по высшей математике и начали изучать Пайтон — один из языков, популярных в машинном обучении.

По Пайтону соскучился — он мне нравится, а я всерьёз не программировал на нём несколько лет. С удовольствием смотрю что наворотили в третьей версии, которую я почти не трогал. Бо́льшая часть языка легко и почти сразу вспоминается, но долгое отсутствие практики всё же сказывается.

Решали сегодня задачки из «Проекта Эйлер», в частности 67-ю задачу. Суть её такова, вкратце. Дан треугольник чисел, нужно найти в нём максимальную сумму, из всех, что получаются, если двигаться сверху по соседям ниже. Посмотрите задачу, там картинка есть, всё понятно.

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.

5 комментариев

«Apple I» в музее техники Эпл

Экспонат Apple II: материнская плата, клавиатура, кассетный магнитофон, монитор Sony и информационная карточка с характеристиками компьютера на столе.
Реплика компьютера «Эпл I» в музее техники Эпл, к сожалению в момент посещения музея этот компьютер не работал

Пока был в Москве, сходил в «Музей техники Эпл», благо три дня в неделю он работает до 9 вечера, так что была возможность заскочить после работы.

Я уже был в нём несколько лет назад, но за это время впечатления стёрлись напрочь, радовался каждому гаджету, как в первый раз.

Правда на этот раз я шёл в музей не просто посмотреть на винтажную технику, но и с мыслью запустить свою программу для «Эпла I» вживую, благо в музее можно поработать за любой машиной. Я, например, в этот раз не упустил возможность поближе познакомиться с компьютером NeXT, ну где сейчас ещё такое увидишь в работоспособном состоянии?

Оригинального «Эпла I» в музее нет — в мире их осталось меньше сотни, зато есть реплика, но не повезло — в этот день, как нарочно, у неё не работала клавиатура. Моя программа небольшая, много времени набор на клавиатуре не занял бы.

Договорились с сотрудником музея — я ему пришлю свою поделку, а он, когда компьютер отремонтируют, её запустит и снимет для меня видео как она работает. Правда для этого придётся как-то перевести программу в звук — компьютеры той поры загружали программы с обычного бытового магнитофона через специальный вход.

Думаю, такой конвертор в звук должен существовать, но пока найти его мне не удалось.

4 комментария

ZMODEM

Скриншот рабочего стола Windows с открытым окном «Открыть» в программе MobaXterm, где выбраны SQL-файлы из папки resolutions; внизу — уведомление «Activate Windows».
Виндовый XShell понимает что такое ZMODEM, при запуске утилиты на сервере готов передавать файлы

Для проекта, которым мы тут в Москве, в командировке занимаемся, заказчик предоставил компьютер на Винде, который по РДП соединяется с виндовой же виртуалкой и вот откуда по ssh имеется доступ на целевые сервера.

Конечно мы с собой привезли образы виртуалок с проектом, но всё равно приходится что-то донастраивать и заливка файла на удалённый сервер каждый раз то ещё мучение — с ноутбука на флешку, с флешки на физическую машину, потом по РДП на виртуалку, уже оттуда — через WinSCP дальше.

Непростое занятие, которое надо делать параллельно с другими делами. Очень раздражает. Ситуация немного улучшилась, когда я в какой-то паузе решил посмотреть не поддерживает ли XShell (ssh-клиент, который нам поставили) протокол передачи файлов ZMODEM.

ZMODEM — довольно древняя штука, сейчас уже малоизвестная, использовалась ещё на бибиэсках, там подобных протоколов было, как грязи. Я узнал о ней из ssh-клиента SecureCRT, пользовался им когда ещё сидел под Виндоуз. SecureCRT на команду передачи файла на сервер, запускает на удалённой стороне утилиту rz, открывает диалог выбора файлов и очень бодро перекачивает выбранное. Удобно.

Реинкарнация утилиты rz нашлась в виде пакета lrzsz, а запуск установленной команды открыл окно выбора файлов — XShell прекрасно понял чего я от него ожидаю. Жизнь немного улучшилась.

Оставить комментарий

Физическое воплощение TCP-пакета ★

Синяя сумка-шоппер с белой схемой заголовка протокола TCP и надписью «TCP», рядом — распечатанный фрагмент документа RFC 793 с описанием формата заголовка.
Физическое воплощение TCP-пакета, обеспечивается гарантированная доставка, надо полагать

В чате бывших сотрудников «Яндекса» сегодня всплыла безвестная картинка с пакетом (на самом деле — сумкой) с принтом в виде TCP-пакета. Каламбур зашёл, местные гики изошли слюной.

Я тоже заинтересовался — где такую взять и ценой вопроса. С заметным трудом разыскал источник — китайский мономагазин, сумка стоит по-божески — 48¥ ($7), но, судя по всему, на доставку по всему миру автор не рассчитывал.

Видимо не удастся такую получить, разве что найти кого-то в Китае, но я не припомню, чтобы у меня там жили знакомые. Жаль, принт вызывает слюноотделение, да и вещь не бесполезная — молния, внутренний карман, рассчитана на «Макбук Эйр» 13″. Я как раз собирался переходить со своей «прошки» на «Эйр» модели этого года.

8 комментариев

Apple I ★

Скриншот окна эмулятора Apple Monitor III с зелёным текстом на чёрном фоне: шестнадцатеричные адреса и данные, символы ASCII, кнопки управления (Power Down, Sleep, Wake Up, Reset).
Моя первая программа в машинных кодах «Эпл I» бесконечно выводит таблицу символов

Заметил позитивную тенденцию — меня снова стали интересовать статьи на «Хабре», вплоть до зуда что-нибудь попробовать самому. В одно время «Хабр» чрезвычайно испортился — в ленте стало столько маркетинговой чуши, что иногда я неделями туда не заходил, всё равно читать нечего.

Не знаю, что ребята сделали, но направление верное, молодцы!

В общем, прочитал недавно там статью про самодельный «Эпл I» и сегодня не спал до двух ночи.

Нет, свой компьютер я не собрал, да и начиналось всё невинно — сначала скачал несколько эмуляторов, попробовал что-то позапускать готовое. Потом почитал про тамошний ассемблер (на борту там процессор 6502) и решил написать что-нибудь простое на нём.

Для этой цели мне очень подошёл «ОупенЭмулятор» и онлайн-компилятор с возможностью отладки «Асм80». Неожиданно удобная штука, кстати, не знаю сколько я бы без неё проваландался.

Скриншот кода на ассемблере с метками ECHO и LOOP, инструкциями TXA, JSR, INX, JMP и сообщениями о определении и использовании меток в строках 3, 4, 6, 8.
Программа, выводящая таблицу символов в компиляторе и отладчике «Асм 80»

Первая моя программа умела совсем мало — только бесконечно выводить на экран таблицу символов. Она такая короткая (всего восемь байт), так как для самого сложного — печати на экран, используется вызов ECHO, встроенной в «Эпл I» программы «Woz Monitor», — по всей видимости её писал Возняк, поэтому она так называется.

В ассемблере 6502 особо не развернёшься — три восьмибитных регистра (A, X, Y), 56 команд (не считая нескольких недокументированных), только целые числа, нет деления и умножения. Я совсем не помню свой первый ассемблер (для «Радио-86РК»), но кажется даже он был богаче.

Тем интереснее было написать что-нибудь чуть более серьёзное. Я написал, разумеется, «песню о пиве», в ближайшее время выложу. Машинные коды вбивал сначала руками прямо в «монитор», всё как в детстве, в начале 90-х, но ближе к ночи устал и написал на «Пайтоне» программу, которая hex-файл «Асма80» перебивает в эмулятор, имитируя нажатия на клавиши через «ЭплСкрипт».

Кстати, какое-то время пришлось ещё потратить на то, чтобы понять как работать с «монитором» Возняка — это предельно аскетичная командная строка, в которой без руководства не разобраться, что, учитывая скромные размеры программы, объяснимо. К счастью, в сети есть копия « Apple-I Operation Manual», которую я наскоро проштудировал.

Там всего несколько страничек, вникнуть просто и сейчас (о ужас!) мне даже удобно.

Оставить комментарий

Самый долгий merge в моей жизни ★

Заметка будет интересна только программистам.

Фотография ниже лежит у меня на ноуте с августа 2013 года. Очень не люблю такое — всё нужное я привык закачивать в интернет, всё ненужное — удалять. Не мог определиться куда деть это фото, решил положить в блог, снабдив небольшим рассказом.

На стене вывешены десятки листов с текстом, справа висит записка с надписью «НЕ ТРОГАТЬ!
Каждый файл для слияния приходилось печатать на куче бумаги, раскладывать на полу и сравнивать вручную

Наверное все программисты знают что такое «мерж» (merge) — слияние двух веток и согласование изменений, сделанных в файлах в рамках этих веток. Если системе контроля версий удаётся справить самостоятельно, то «мержи» происходят автоматически, это, в моей практике, наиболее частая ситуация. В противном случае возникает «конфликт» — «мерж» останавливается до разрешения конфликта человеком. Только человек может решить как будет выглядеть сводный код, учитывающий изменения, сделанные в двух слияемых ветках.

Я однажды попал в неприятнейшую ситуацию, когда две команды в нашей компании, в силу многих причин, независимо работали над одним и тем же продуктом около года.

Одна из команд работала над функциями, которые нужны в продукте заказчику, вторая, которой руководил я, — делала несколько довольно серьёзных изменений с заделом на будущее, в частности — внедряла шаблонизацию.

Через год попытались слить две ветки воедино и получили конфликты почти во всех основных файлах проекта. Ничего совсем уж неожиданного, конечно, особенно с учётом того, что часть кода была переписана с ПХП на «Твиг», но никогда в ещё в жизни я не видел столько конфликтов. Затронуты были, если мне не изменяет память, несколько сотен файлов.

С одной стороны, других вариантов, кроме как собрать это всё воедино, не рассматривалось, с другой стороны, объём предстоящей работы удручал.

В общем, погрустил я, погрустил, повесил табличку «Не беспокоить» и заперся в кабинете на неделю. Каждый файл с конфликтом распечатывал дважды — из каждой ветки. Потом раскладывал распечатанное на полу, выделял маркером одинаковые места, рисовал стрелками что куда переместилось, шёл к ноутбуку и так или иначе разрешал конфликт.

На фотографии — процесс разрешения конфликтов одного из файлов. Через неделю я был полностью разбит монотонностью работы, но ветки слил.

14 комментариев

Как открыть файл в формате HLP

Потребовалось открыть файл в древнем формате HLP. Оказавается сейчас его ничего не открывает, даже операционная система Виндоуз, под которую он когда-то и был создан.

Возможно существует какой-то быстрый и приятный путь читать такие файлы, но мне на него выйти не удалось. Гуглёжка принесла не первой свежести утилиту winhelpcgi, которая просто так не скомпилировалась, пришлось разбираться и патчить:

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

После этого читать можно, но если кто-нибудь подскажет более удобоваримый способ преобразования, буду благодарен.

7 комментариев

Числа от «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» — «Слоны́».

3 комментария

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
)

Смотрится как будто чуть почище. Знаю, многие ребята осуждают использование особенностей реализации эскуэля в конкретной СУБД, из-за возможных проблем с портированием на другие СУБД, но для нас это вряд ли проблема — в нашем продукте используется множество куда более сложных специфичных для «Постгреса» вещей.

Если когда-либо встанет вопрос о переезде на другую СУБД, то вышеописанное — самая малая из проблем и решить её просто — заменой через регулярное выражение.

2 комментария

Примерная оценка в Постгресе

Читая документацию по «Постгресу», набрёл на интересную конструкцию — TABLESAMPLE. Она позволяет обработать запросом не всю таблицу, а только указанный процент, причём строки выбираются случайным образом.

Например, встречается такая задача — показать какую-нибудь внутреннюю рекламу, для этого надо быстро выбрать какой-нибудь случайный идентификатор из таблицы, вот так это можно сделать при помощи указанной конструкции:

SELECT id FROM (
    SELECT id FROM very_big_table TABLESAMPLE SYSTEM (.0001) LIMIT 100
) _ ORDER BY RANDOM() LIMIT 1

Тут выбирается одна десятитысячная процента таблицы (0,0001%), а потом из этой выборки берётся первая строка. На настоящей таблице с почти миллиардом строк, такой запрос у меня занял около ста миллисекунд.

SYSTEM тут — метод выборки. Их всего два, второй (BERNOULLI) даёт более случайные и аккуратные результаты, но работает как-то уж очень медленно. SYSTEM работает на уровне блоков, выдавая случайные блоки целиком, и из-за этого я дополнительно сортирую результат — чтобы перемешать строки внутри блока.

А вообще 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), преобразование в массив тут больше не происходит. Зачем-то одно странное поведение заменили другим — теперь в этом коде создаётся гигантская строка, состоящая из пробелов и в позицию PHP_INT_MAX записывается символ «единица». Вот память и кончается. ?

9 комментариев

Статический анализ в Go

С интересом попробовал в действии gocritic — статический анализатор для Гоу, статья о котором в прошлом месяце появилась на «Хабре». Он в самом начале пути, но кое-что уже умеет.

Для теста взял один из внутренних проектов нашей компании — узкоспециализированный поисковый сервис, который размещает данные в памяти. Проекту четыре года, можно было ожидать, что в нём скопилось какое-то количество мусора, на который анализатор среагирует.

Просто так gocritic не запустился, упал с какой-то невнятной ошибкой. Хорошо, что я знаю одного из авторов — с его помощью удалось разобраться. Во-первых, пришлось переложить файлы так как сейчас это принято в Гоу, во-вторых, избавиться от относительных путей в импорте.

После успешного запуска получилось примерно два экрана замечаний, большей частью относящихся к устаревшим за время существования проекта практикам, но парочка замечаний была действительно полезна. Жаль, что пока нет интеграции с каким-либо редактором кода, как у прекрасного РеШарпера — он сам предлагает правку, остаётся только её принять.

Как бы то ни было, большинство замечаний были однотипными и много времени правка не заняла — помогли регулярные выражения. Теперь, даже со включенными экспериментальными и опциональными проверками, анализатор ругается только на одно место — он ошибочно считает, что раз у функций одинаковая сигнатура, то и сами функции одинаковые, рекомендует дать им имя и вызывать по имени.

Терминал с командой gofmt и предупреждением о повторном использовании переменной interface{} в файле main.go

Как я уже говорил, по-настоящему полезных замечаний было два.

Во-первых, в одном из циклов происходила итерация с копированием значения, цикл вызывается нередко, поэтому это заметное исправление.

rangeExprCopy: copy of utf (256 bytes) can be avoided with &utf

Во-вторых, в трёх местах анализатор посоветовал заменить «магические значения» на константы, которые оказывается (я не знал), есть в соответствующих модулях. Это полезно для читаемости кода и для самообучения — как результат я узнал что-то новое.

stdExpr: can replace "POST" with net/http.MethodPost

По моему мнению очень полезный проект, желаю ему дальнейшего развития!

Оставить комментарий

← 1 19 20 21 22 23 67 →