Дам пирожка
Больше недели назад кардинально изменил причёску — побрился налысо. Что делать — лысею, у меня только две дороги — зачёсывать волосы с шеи или побриться налысо. Хотя нет, можно ещё делать вид, что ничего не замечаешь. Мне показалось, что увидеть как выглядит мой лысый череп — хороший вариант.
Переживал, что мне не пойдёт — когда трогаешь руками, череп кажется удивительно неровным, но нет, оказалось всё в порядке. Было неожиданно тяжело на это решиться, не могу сказать почему, не разобрался.
Из неожиданных ощущений — кожа головы оказалась непривычной к зиме. В шапке сначала казалось холоднее, чем обычно, а в помещении при лёгком сквозняке приходилось прикрываться капюшоном худи. Прошла неделя и вроде привык. Или волосы немного выросли.
Переезд на «Эгею»
Как вы наверное заметили, в блоге внезапно сменился дизайн. Не пугайтесь, так и должно быть.
Покопавшись в себе, удалось поднять со дна несколько причин и часть из них — технические. Мне уже давно надоел тот движок блога, который у меня стоит — я им не занимаюсь и он явно обветшал, как внутренне — архитектурно, так и внешне, с точки зрения дизайна. Я с большой надеждой смотрел на «Эгею» Бирмана и в этой году нашёл в себе силы наконец переехать на неё.
Эта работа отняла оба выходных и два вечера рабочей недели. Требовалось сконвертировать мою внутреннюю разметку в актуальную разметку «Эгеи», а так же внести несколько исправления в код (надеюсь скоро они попадут в основную ветку), чтобы сохранить
Наверное пока не всё идеально, временно пропали страницы «Обо мне», «Прочтённое» и «99», но я надеюсь в скором времени справиться со всеми трудностями.
Кроме того, я сменил хостинг. Уважаемые «Докеры» хостили меня бесплатно восемь лет, спасибо им за это огромное, при случае всем его рекомендовал и рекомендую. Однако пора и честь знать, в связи с переходом на другой движок мне нужны большие аппаратные ресурсы и мне кажется неправильным просить их у «Докера», не платя за это ни копейки. Сейчас я подселился на площадку внутри «Мастерхоста» к своим знакомым, надеюсь ресурсов всем хватит.
В конце хотел бы сказать спасибо Илье Бирману за консультации по движку!
Вастрик-бокс
Было интересно поучаствовать в этой относительно свежей движухе — заказать и получить себе бокс. Суть вкратце такова — вы платите денежку, а получатель на другом конце кидает в коробку всякий мусор
Затея массовая, анонсируется заранее, её смысл для анонсирующего — финансовая выгода и пиар, для поддавшегося — получить положительные эмоции. То есть если вы покупаете бокс для того, чтобы получить
Я бокс заказал у Вастрика — это такой новый модный блогер, спешите видеть! Ожидал получить
Причём П — персонализация, Вастрик даже зашёл ко мне в бложик и, увидев, что мне интересны монеты, насыпал несколько в бокс. Что, кстати, сподвигло меня наконец сделать перепись всех современных моей тушке монет, которые у меня есть. Надо бы
Моно-но аварэ
Вчера нашёл в себе силы оторваться от вечернего сериальчика и сесть за ассемблер, в итоге моя неповторимая поделочка уже может почти всё, что и жалкий оригинал.
Пока писал, обнаружилась несколько занятных вещей. Ниже серьёзный тон и если вам не нравится программирование, можете смело пропустить этот пост, да и картиночек не будет, совсем печально.
В прошлой версии своей утилиты я сначала пытался файл открыть, если не получалось, то создать. Вообще, есть такой флаг O_CREAT, который можно указать в качестве режима открытия и если файл не существует, он создаётся. У меня не создавался. Я не понимал почему и понял лишь когда запустил strace. Оказалось, что константы, которые я взял
Вторая вещь — я очень давно не программирую на ассемблере и растерял большинство лучших практик. Вот например я не помню как лучше — когда подпрограмма сохраняет регистры, которая она портит или наоборот. Вроде первый вариант выглядит
Ну и последнее, самое интересное. Утилита работает с файлами, а файловые хендлеры надо
Получаются всего несколько вызовов — мне нужен sys_mmap или sys_brk, первый работает с памятью от четырёх килобайт, второй и с менее значительными кусками. Хотя первый вызов мне интереснее, но выглядит он как попытка выстрелить из пушки по воробьям, попробую использовать второй.
Вообще всё это конечно очень непрактично, зато очень увлекательно —
🍎 + 🍍 + 🍌 = 🥗 ★
По интернету ходят сотни картинок, где надо «решить фрукты» — в уравнение в качестве имён переменных подставлены
Когда я увидел картинку выше, ради развлечения сунул её в «Вольфрам» — хотелось посмотреть как ему указать, что числа должны быть целые. Заинтересовало, что решения не нашлось. Я задумался и внимательно посмотрел на фрукты, в них подвоха тоже не увидел.
Оказалось, что картинка выше — пранк по мотивам статьи на «Кьюоре». Решить уравнение, которое на ней, сможет лишь небольшое количество людей со специальными знаниями, а прямой перебор значений займёт совершенно нереальное время.
Минимальные подходящие числа для уравнения такие (ответ проверял на ЯП «Эр»):
`🍎` <- 154476802108746166441951315019919837485664325669565431700026634898253202035277999
`🍌` <- 36875131794129999827197811565225474825492979968971970996283137471637224634055579
`🍍` <- 4373612677928697257861252602371390152816537558161613618621437993378423467772036
print(`🍎` / (`🍌` + `🍍`) + `🍌` / (`🍎` + `🍍`) + `🍍`/(`🍎` + `🍌`)) # [1] 4Это числа от 79 знаков и больше! Где уж такое решить!
Ассемблер под Линукс ★
Заметка про полноту по Тьюрингу команды присваивания в ассемблере натолкнула меня на мысль, что я
Тогда не довелось, решил вчера попробовать. Теорию в очень общих чертах я знал — есть системные вызовы (сисколы), которые можно дёргать
MOV RAX, 3 ; sys_read
MOV RBX, 0 ; stdin
MOV RCX, string ; адрес строки, которую выведем на экран
MOV RDX, len ; длина строки
INT 0x80Но я
MOV RAX, 0 ; sys_read
MOV RDI, 0 ; stdin
MOV RSI, string ; адрес строки, которую выведем на экран
MOV RDX, len ; длина строки
SYSCALLК тому времени меня посетила мысль сделать простенький аналог линуксовой утилитки tee, но для этого нужно было
Так как системный вызов для открытия файла (sys_open) как раз требует на вход сишную строку, я передал указатель, который взял со стека, в сискол, ожидая, что всё заработает. Это было моей ошибкой. Я потратил не меньше часа, разбираясь, что я сделал не так, перебирал способы передачи параметров, ползал по стеку при помощи отладчика gdb, ничего не помогало, пока не забрезжила догадка, что сами параметры командной строки тоже лежат на стеке и системному вызову это может не нравится.
Попробовал скопировать строку оттуда в данные и всё заработало. Не знаю что это было, пока не гуглил, возможно сделано из соображений безопасности. Времени потерял изрядно.
Пока получилась очень простая утилитка, но хочу её дописать как выпадет свободный вечер — сделать поддержку указания нескольких файлов и флага для режима присоединения. Размер радует, кстати, — всего 752 байта.
Дизассемблируй это ★
В моей жизни последовательно сменяли друг друга три ассемблера. Первый, для компьютера
В те времена я думал, что всю жизнь буду программировать на ассемблере, на деле же последнюю программу на нём написал в начале
В ассемблере есть такая команда — MOV (в некоторых ассемблерах — LD), записывает содержимое одного аргумента в другой. Сейчас набор комманд разросся, аргументом может быть почти что угодно — регистр, ячейка в памяти, сумма некоторого числа, одного регистра и другого, умноженного на число, но по сути это всегда присваивание.
И вот оказалось, что эта команда — полная по Тьюрингу. Звучит невероятно, но это так. Некие ребята заморочились и сделали компилятор, который компилирует любую программу на Си в последовательность команд MOV. Причём им даже ДУМ удалось скомпилировать, правда один кадр рисуется семь часов. Кстати, такая программа неуязвима для горюшка века — Мелтдауна и Спектра.
Есть небольшая (на 156 страниц и 90% воды) презентация, достаточно популярно объясняющая как этого удалось достичь, но для её чтения надо знать ассемблер, поэтому я позволю себе раскрыть детали трансляции двух инструкций, чтобы пояснить принцип для тех, кто ассемблера не знает или ленится причитать.
Например, сравнение двух чисел делается при помощи следующего псеводокода:
mov [X], 0
mov [Y], 1
mov R, [X]У нас есть два числа в аргументах «X» и «Y», результат сравнения которых попадает в «R» — там будет ноль, если числа не равны и единица в противном случае. Как же это работает?
Первой командой ноль записывается в ячейку по адресу «X». Это ассемблер, у нас тут всё — число, остальное — человеческие интерператации, поэтому записанное в «X» мы используем как адрес. Второй командой единица записывается в ячейку по адресу «Y». Третьей командой мы читаем значение по адресу «X» и если значения в «X» и «Y» совпадают, то ноль перетрётся единицей (и она попадёт в R), если нет, то в ячейке по адресу «X» ноль останется (который попадёт в R).
Несложно. Но из кода выше непонятно как получаются другие необходимые инструкции. Увы,
Возьмём, например, логическое «ИЛИ» («OR»), тут чуточку сложнее:
OR_ADDRS: dd OR_0, OR_1
OR_0: dd 0, 1
OR_1: dd 1, 1
; …
mov eax, X
mov edx, [OR_ADDRS + eax]
mov eax, Y
mov eax, [eax + edx]
mov R, eaxВо всех логических операциях ребята используют записанные заранее неизменяемые массивы значений.
Что тут происходит? В регистр (переменную, с которыми работает процессор) «eax» записывается значение «X» (возможные входные значения у нас тут — ноль или единица, численное представление булевых значений).
Далее в регистр «edx» записывается число из адреса, который является суммой адреса массива OR_ADDRS и содержимого регистра eax. Таким образом в eax попадёт OR_0 или OR_1, в зависимости от того былы записаны в eax ноль или единица. Эти значения — тоже числа и являются адресами двух других массивов из двух элементов.
Далее в eax мы записываем аргумент Y, его значение складывается с адресом полученным на предыдущем шаге и из получившегося адреса мы читаем записанное там значение. В переводе на ПХП получается следующее:
function mov_or(int $X, int $Y): int
{
define('OR_0', [0, 1]);
define('OR_1', [1, 1]);
define('OR_ADDRS', [OR_0, OR_1]);
$R = OR_ADDRS[$X][$Y];
return $R;
}Кстати, интересно, что у знаменитого дисассемблера «ИДА» от полученной таким образом программы крепко уносит крышу — при попытке отладки диссасемблер не видит никаких ветвлений и падает на анализе кода. Получился бы неплохой метод защиты от анализа, если бы не производительность.
Что есть истина?
У нашего бывшего сотрудника в фейсбуке увидел ссылку на любопытную задачку — может ли (a == 1 && a == 2 && a == 3) быть «истиной» в ДжаваСкрипте?
Не заглядывая в статью, я предложил два варианта, вполне очевидный первый:
a = ((counter) => ({valueOf:() => ++counter}))(0)
// {valueOf: ƒ}
a == 1 && a == 2 && a == 3
// trueИ второй — на суррогатных парах. Но по ссылке есть ряд других занимательных способов — через геттеры, похожие символы Юникода (мне приходил в голову такой вариант, но я не смог подобрать три символа, одинаковых на вид), другие специальные методы и прочее. Больше всех мне понравился такой способ:
a = [1,2,3];
a.join = a.shift;
a == 1 && a == 2 && a == 3
// trueОчень просто и элегантно — массив при преобразовании в скаляр в ДжаваСкрипте, всегда сначала преобразуется в строку значених, объединённых через запятую. В коде выше метод для объединения заменяется методом, который забирает из массива первый элемент. И всё работает как требуется — при каждом сравнении массива с числом, забирается первый элемент массива.
Сказки от прабабушки
Есть такая штука, немного пафосно называемая «связью поколений». Я довольно далеко продвинулся в исследовании дерева своего рода и могу сказать, что она ощущается только в том случае, если с предком связны хоть
Хотелось бы оставить дочке хоть
Перерыл все «дневники», сказок не нашёл. Видимо записал
Зато много интересного про себя вычитал. Например,
Тухандредкоины
Я их в руках не держал, сфотографировать не могу,
Так вот, за купюрами в 200 и 2000 рублей сейчас охотятся коллекционеры, но так как их становится всё больше, то котируется не каждая купюра, а только серия «АА», причём чем больше нулей после серии, тем лучше — то есть ценятся купюры первых партий. На «Авито» народ надеется выручить от 100 до 4000 рублей за такие купюры, но считается, что их стоимость будет ещё расти.
Эта охота за нулями очень мне напомнила другие популярные денежки — биткоины. Дело в том, что там закрывающие блоки имеют определённую сложность, чтобы считать их было трудно, поэтому подбирается специальное значение (хеш), так, чтобы в начале было определённое количество нулей. Мне показалось смешным, что майнеры и коллекционеры охотятся за нулями, одни за виртуальными, другие — за нарисованными.
Кстати, всех, кто всё ещё хочет понять, что такое биткоины, отсылаю к гениальной статье Вастрика «Блокчейн изнутри: как устроен биткоин» — его сайт, кстати, для меня стал открытием года. Получаю громадное удовольствия от чтения всех его статей.
Мой цвет волос в детстве
На новогодние праздники приехали в гости родители и по моей просьбе захватили два пакетика с моим детскими локонами —
Дочка у меня относительно светлая и мне стало любопытно сравнить её цвет с тем, что у меня был в детстве.
Увы, не смог сфотографировать как видно глазами, видимо
Чёрная перфолента
Дмитрий Радищев, околокомпьютерные обзоры которого я с удовольствием читал на его застывшем в янтаре сайте, прислал для нашего музея компьютерной техники перфокарт и бобину неиспользованной чёрной перфоленты с двумя пробитыми обрывками.
Если бы не обрывки, вряд ли можно было бы быстро догадаться для чего эта лента предназначалась — чёрную перфоленту я никогда в жизни не видел и даже не задумывался о наличии других цветов, кроме белого.
Кстати, одно время перфолента широко использовалась в советских журналах, как элемент оформления различных компьютерный статей, некий символ тогдашнего айти. Уже ушедший символ, вслед за которым почти уже ушла дискета, которую с большим трудом теперь заменяют на облако со стрелочкой. И вот ещё думаю, современным детям уже трудно будет объяснить, почему трубку телефона «кладут» или «бросают», сам телефон «звонит» даже на вибрации, а «берут» трубку, сдвигая непонятный символ, похожий на перевёрнутую кратку над буквой «Й».
Дима, большое спасибо за подарок музею на Новый год!
Запойный сладкоежка
Около пятнадцати лет назад я бросил пить алкоголь. Точнее не помню, но припоминаю, что в том же году моя тогдашняя кошка родила котят, о чём осталась запись, датированная
Много воды утекло и я уже
Я больше года занимаюсь с тренером, которая так же составляет для меня диету. Ничего фантастического, но от потребления сахара пришлось отказаться. Я всю жизнь считал себя заядлым сладкоежкой (несколько лет назад я ел по шоколадке в день), но оказалось, что для меня это не такой уж и трудный шаг.
Так вот, оказалось, что отказаться о сахара, это примерно как отказаться от алкоголя — многим кажется, что меня заставили, что я бедный и несчастный, что меня надо освободить от этой кабалы. Многие предлагают съесть,
Сижу и думаю — не лишусь ли в этот раз ещё части друзей. Вдруг меня с ними объединяет только сахар?
Тридцать девятый выезд
Давненько закрыл сезон в этом году — примерно с первым снегом, не помню числа, но всё никак руки не доходили сфотографировать. Сейчас, когда предновогодняя лихорадка закрытия контрактов спала, могу послепенно обработать накопленное. На фото — результаты последнего в этом году выезда.
На снимке: стёртая в ноль монета, предположительно «масон»
Memcached и persistent connections
В работе с модулем «Мемкешд» есть целая куча подводных камней, которые иногда всплывают
Упомянутый модуль имеет малозаметную возможность, которая помогает экономии ресурсов в проектах с большой нагрузкой — если в конструктор передать строку, то она станет идентификатором для так называемого «персистент коннекта» — соединения, которое открывается процессом интерпретатора ПХП и живёт между запуском обрабатываемым этим процессом программ.
Оказалось у этого функционала есть особенность:
socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_TCP) = 4
connect(4, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("127.0.0.1")}, 16) = -1
poll([{fd=4, events=POLLOUT}], 1, 4000) = 1 ([{fd=4, revents=POLLOUT}])
getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
sendto(4, "version\r\n", 9, MSG_NOSIGNAL, NULL, 0) = 9
recvfrom(4, "VERSION 1.5.1\r\n", 8196, MSG_NOSIGNAL, NULL, NULL) = 15
sendto(4, "quit\r\n", 6, MSG_NOSIGNAL, NULL, 0) = 6
shutdown(4, SHUT_WR) = 0
shutdown(4, SHUT_RD) = -1 ENOTCONN (Transport endpoint is not connected)
close(4) = 0
socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_TCP) = 4
setsockopt(4, SOL_SOCKET, SO_LINGER, {onoff=1, linger=0}, 8) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(11211), sin_addr=inet_addr("127.0.0.1")}, 16) = -1
poll([{fd=4, events=POLLIN|POLLOUT}], 1, 4000) = 1 ([{fd=4, revents=POLLOUT}])
getsockopt(4, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
sendto(4, "version\r\n", 9, MSG_NOSIGNAL, NULL, 0) = 9
recvfrom(4, "VERSION 1.5.1\r\n", 8196, MSG_NOSIGNAL, NULL, NULL) = 15В логе выше видно, что процесс постоянно устанавливает новые соединения с сервером мемкешда, несмотря на то, что в коде (поверьте) используется один и тот же постоянный идентификатор.
Мы долго были в недоумении, но в конечно счёте выяснилось, что такое поведение воспроизводится, если после создания объекта выставлять любые опции, влияющие на сокет. В этом случае модуль переоткрывает соединение с сервером, причём неважно открывался сокет с теми же настройками или нет.
Решение — любым доступным способ проверять получили ли мы «свежий» объект или имеем дело с уже открытым соединением и выставлять опции только в первом случае:
$mc = new Memcached('persistent');
if (!$mc->getServerList()) {
$mc->setOptions([
Memcached::OPT_NO_BLOCK => true,
]);
$mc->addServer('127.0.0.1', 11211);
}Тогда соединение благополучно переиспользуется.
Митохондриальная Ева
Прочистил голову от заблуждения о «митохондриальной Еве» — так СМИ называют женщину от которой мы все получили свою митохондриальную ДНК прекрасным роликом.
Я подозревал, что с публикациями «у человечества единая мать»
Читая СМИ можно сделать вывод, что исследователи
Но в то же время жило ещё множество предков, в том числе и женского пола, от которых им достались другие гены! Просто других прямых женских линий не осталось —
На картинке выше видно в чём тут дело. Митохондриальную ДНК я получил только от своей прабабушки Евдокии Никоноровны, тогда как от других предков я тоже получал гены.
Наблюдение
Давно заметил, что многие девушки, носящие сумку на одном плече, со временем перестают шевелить той рукой при ходьбе, со стороны которой носят сумку. Даже если сумки на плече нет.
И вот смотрю я на весь из себя такой футуристичный сериал «Звёздный путь: Дискавери», где все ходят в мундирах, живут на своих короблях и никаких сумок через плечо и в помине нет. А посреди этого милитаристского будущего через весь кадр идёт девушка, почти не двигая правой рукой, при энергичном участии левой. Малозаметный анахронизм.
Поскреби русского…
Несколько лет назад я сдал свою ДНК на анализ. Как следствие — примерно раз в месяц мне падает в почту письмо о совпадении по ДНК с различными незнакомыми людьми, а так же некоторое количество инфографики.
Как видно на картинке выше, в основном мои предки — выходцы из Европы.
Я без понятия кто у меня из предков был эскимос, а часть южноазиатских генов — это определённо влияние Кандауровых, тюркской фамилии. Правда Кандауровы давно обрусели — по меньшей мере
Оказывается 1,9 процента — это довольно много. Например, если не исключать адюльтер
Интернет-археология: браузер ViolaWWW
★
Пока читал про «
Эта вещь достойна внимания
Автор написал несколько программ на своём языке, например — шахматы. Я пока не нашёл документацию, зато обнаружил несколько примеров. Например, скрипт выводящий синусоиду:
\class {field}
\name {wave}
\parent {}
\children {wave.sb}
\script {
switch (arg[0]) {
case "graph":
f = float(arg[1]);
xx = width();
r = height() / 2.0;
theta = 0;
for (x = 20; x < xx; x += 2) {
theta = theta + 0.1;
y = sin(theta * f) * r + r;
drawLine(x, y, x, y + 1);
}
return;
break;
}
usual();
}
\width {300}
\height {200}
\
\class {slider}
\name {wave.sb}
\parent {wave}
\script {
switch (arg[0]) {
case "_shownPositionV":
usual();
send(parent(), "graph", arg[1]);
return;
break;
}
usual();
}
\x {2}
\y {2}
\width {15}
\height {200}
\shownSizeV {10}К сожалению, позапускать программы пока нечем. Исходный код я нашёл, но под Линуксом он компилироваться не захотел, собственно, судя по коду, он никогда под ним и не собирался. Я сделал минимально необходимые правки, код собрался, но попытка запуска завершилась крахом. Подумаю стоит ли тратить силы дальше.
Даже интересно какой бы веб мы увидели сейчас, если бы этот браузер тогда получил дальнейшее распространение! Получается
Насколько я могу видеть, поддерживалось более десятка форматов графики, в том числе всем знакомый GIF, правда без анимации и в формате 1987 года, а так же сейчас уже экзотический XBM (до относительно недавнего времени поддерживался «Эксплорером», «Сафари» и «Оперой»).
99 бутылок: Cmm, интернет-археология
61. Cmm. Язык «Cmm» был разработан в 1992 году компанией «Nombas». Основной идеей языка было упрощение языка «Си», отсюда и название — C minus minus. Официальное руководство говорит, что это «Си, минус объявление типов, минус указатели». Позже язык был переименован в ScriptEase, так как упоминание «Си» отпугивало людей. Язык существовал для ДОСа, Виндоуз, ОС/2 и операционной системы компании «Новелл».
В конце 1995 года компания создала версию скриптового языка
Язык действительно простой — типы выводятся из использования, массивы без указания размера, нет явного выделения и освобождения памяти, указателей не видно.
Массивы и строки, хоть и являются указателями (есть даже арифметика с ними), но этого не замечаешь — выглядят, как обычные переменные. Все lvalue передаются по указателю, для передачи по значению есть специальный синтаксис. Забавно, кстати, что точка с запятой не обязательна, прямо как в ДжаваСкрипте.
Остальные отличия от «Си» не столь заметны. Языки почти что близнецы, есть даже ограниченный предпроцессор, да и встроенные функции, в основном, сишные. Язык, видимо, претендовал сразу на несколько ниш, на нишу коммандных оболочек в том числе — в составе предпроцессора есть команда, позволяющая импортировать куски программ, указывая с какой по какую строку производить импорт. Насколько я смог заметить, это широко используется, чтобы внедрять «СиЭмЭм» внутрь
// Written by Evgeny Stepanischev, 2017
BottlesPlural(Beer)
{
switch ( Beer )
{
case 0:
return `no bottles`
case 1:
return `1 bottle`
default:
sprintf(Bottles, `%d bottles`, Beer)
return Bottles
}
}
i = 99
Bottles = BottlesPlural(i)
while ( i > 0 ) {
printf("%s of beer on the wall, %s of beer.\n", Bottles, Bottles)
Bottles = BottlesPlural(--i)
printf("Take one down and pass it around, %s of beer on the wall.\n\n", Bottles)
}
printf("No more bottles of beer on the wall, no more bottles of beer.\n")
printf("Go to the store and buy some more, 99 bottles of beer on the wall.\n")Если