«Яндекс»
Удивительно, но спустя столько лет мне, оказывается, всё ещё снится «Яндекс». Сегодня просыпался ночью попить водички, поэтому сон запомнился,
В этот раз снилось, что я сижу на своей текущей работе, в офисе и вижу рекламный видеостенд, который сломался. В последовательности слайдов, которую он показывает, с последним кадром
Интересно, что во сне был определённый коллега, с которым я почти и не общался в реальной жизни. Кстати, он совершенно не постарел за прошедшие десять с лишним лет.
Во сне оказывается, что у меня есть доступ к интранету «Яндекса», которым я иногда пользуюсь. Поэтому я без труда нахожу этого коллегу
Анатомия Котопса
Начали смотреть с дочкой детский
А именно — как эта животинка
Дочкина теория довольно неаппетитная, поэтому проводить не буду, хотя в интернете у неё тоже есть сторонники.
Но на мой взгляд, фантазировать не о чем, всё раскрывается уже в первом сезоне — в шестой серии есть эпизод, где Котопёс спит в пижамке, на которой виден «бомболюк», как я его называю, — закрытое отверстие, чтобы было проще ходить в туалет, не снимая пижаму.
По его расположению сразу видно как у этой химеры функционирует пищеварение. Странно, что этот кадр в найденных мною обсуждениях анатомии Котопса не всплыл ни разу.
Интересный балкон
Очень люблю находить приметы времени в городской среде и с тех пор как узнал, что на рельсах тоже бывают надписи, всегда обращаю внимание на металлические конструкции — вдруг
В один выходные гулял по центру города
Глазами разобрать не удалось, сфотографировал с максимальным увеличением. К сожалению, свой текущий смартфон я выбирал не за камеру, так что много вытянуть не удалось, но основная надпись читается — «Дружковка», есть такой город в Краматорском районе Донецкой области.
Согласно «Википедии», в Дружковке до революции действовали два завода, которые могли бы выпустить удерживающую балкон двутавровую балку, но самый подходящий из них — чугуноплавильный и сталелитейный, основной продукцией которого были рельсы. Строить его начинали в 1893 году, а в 1896 году о нём написал в своей классической повести «Молох» Александр Куприн:
Прямо под его ногами открылась огромная панорама завода, раскинувшегося на пятьдесят квадратных верст. Это был настоящий город из красного кирпича, с лесом высоко торчащих в воздухе закопченных труб, — город, весь пропитанный запахом серы и железного угара, оглушаемый вечным несмолкаемым грохотом. Четыре доменные печи господствовали над заводом своими чудовищными трубами. Рядом с ними возвышалось восемь кауперов, предназначенных для циркуляции нагретого воздуха, — восемь огромных железных башен, увенчанных круглыми куполами. Вокруг доменных печей разбросались другие здания: ремонтные мастерские, литейный двор, промывная, паровозная, рельсопрокатная, мартеновские и пудлинговые печи и так далее.
Завод спускался вниз тремя громадными природными площадями. Во всех направлениях сновали маленькие паровозы. Показываясь на самой нижней ступени, они с пронзительным свистом летели наверх, исчезали на несколько секунд в туннелях, откуда вырывались, окутанные белым паром, гремели по мостам и, наконец, точно по воздуху, неслись по каменным эстакадам, чтобы сбросить руду и кокс в самую трубу доменной печи.
Завод был разрушен в Гражданскую войну и вновь был возрождён
Полезный сценарий
Как я уже
Думаю, я не один такой, поэтому время от времени делюсь сценариями, которые оказались полезными для меня.
У нас квартира так устроена, что легко не услышать как открывается дверь и, чтобы не вздрагивать от неожиданности, когда заходишь в коридор, а там
Лук эт зис
Ездили на прошлые выходные на дачу к А. Х., нашему другу, — поболтать, провести время. Заодно, помятуя, что он всерьёз увлёкся луком, решили тоже попробовать пострелять. Мне было интересно, но не более того, не сказать, что зацепило. Я люблю пострелять из огнестрела или пневматики, но лук стойкого интереса не вызывал.
Пока я стрелял, жена меня фотографировала, и уже позже, когда я отсматривал снятое, оказалось, что некоторые фотографии вызывают у меня ощущение, что их сгенерировала нейросеть. Я даже могу сказать какая — Stable Diffusion.
Не знаю откуда у меня такая определённость в выборе нейросети, но почему снимки мне кажутся сгененированными, могу сказать.
Интересно, конечно, сколько ещё мы будем в состоянии хоть
Пацаны и суверенитет
На фоне интереса к текстовому квесту нулевых
Сначала я отнекивался, но позже решил последовать совету. Уже почти дочитал, правда
Пожалел, что начал читать, но это не вина книги, конечно, просто криминальная тема мне никогда не нравилась.
Только один отрывок зацепил, хочу поделиться:
Когда начался парад суверенитетов, они выступили с неоднозначными лозунгами, написанными Байрамовой, мол, «русских надо гнать». Все шло к резне. Авторитеты многих группировок встретились с «кашапами» и дали понять, что при таком раскладе все улицы в городе будут воевать против них. Насколько я знаю, в Казани группировки заявили то же самое.
Многие считают, что резни у нас не случилось во многом благодаря позиции группировок, хотя это расходится с официальной точкой зрения.
Помню это время, очень неспокойное, некоторые близкие друзья ударились в национализм, что выглядело просто дико. Фамилию Байрамовой я тогда запомнил на всю жизнь — она знатно шатала лодку. Что бы тогда ни удержало республику от сепарации, ощущение было, что беда прошла стороной буквально
Whatcha gonna do when they come for you?
То, на что мне открыла глаза книга «Слово Пацана» Роберта Гараева, о которой я упоминал вчера, — что группировки с улиц Казани никуда не исчезли. По мнению одного из героев книги, в группировках состоят примерно 30% молодых пацанов нашего города. Это очень и очень много.
Причём пацана «с улицы» до сих пор можно отличить по неким внешним признакам:
Дела обсуждаются в WhatsApp и вконтакте, где мы создавали беседы — типа чатики. Основное правило: ни в коем случае не болтать лишнего. Появилась такая мода, что пацаны с улицы не ставят настоящие имена и фамилии во вконтакте. И фотографии нет. […]
В наше время особых отличий нет, но пацанам нельзя стричь челку на бок. Нельзя носить определенную одежду, которую носят чушпаны. […]
Сейчас у пацанов одна отличительная черта — носят барсетки через плечо. И, конечно, все коротко стриженные — ни в коем случае не зачесанные набок волосы. За проборы даже спрашивают: при мне лично наваляли одному мальчишке. И джинсы должны быть широкими, не зауженными.
У меня, кстати, во время чтения книги разблокировалось воспоминание: я, ещё школьник, стою на балконе, а через наш очень широкий двор «Грязь» в Лениногорске бежит толпа пацанов.
«Жизнь в коробке из-под Сяоми»
На заре интернета (для меня заря — это вторая половина
Это были персональные сайты, выглядящие
Нередко такие сайты имели
Это я к чему вспомнил, — недавно
Так и жизнь проходит в собственной картонной коробке от Сяоми.
Я всё больше прихожу к мнению, что это просто гениальное название для моего дневника. В духе «хомяков»
А может и нет.
Краткие инструкции к лекарствам
Очень не хватает кратких инструкций к лекарствам, чтобы самое главное было написано
Почему прямо на блистере нельзя написать: «невротоникс, 1 таблетка 3 раза в сутки, рассосать, улучшает сон, снимает тревожность»? «Аспиринус,
Модуль scalar_objects
Очень мне нравится идея навести порядок в функциях ПХП при помощи присобачивания к примитивным типам
К именованию встроенных функций есть много претензий:
- различный стиль наименований: html_entity_decode, но htmlentities;
- неинтуитивность некоторых названий: strcspn, strpbrk;
- разный порядок параметров: strpos($haystack, $needle), array_search($needle, $haystack);
Считается, что это один из серьёзных недостатков ПХП. Напрашивается очевидное решение — сделать всем проблемным функциям алиасы, но так язык замусорится ещё сильнее.
А вот добавив псевдометоды у примитивных типов, можно сразу сразу сделать хорошо. Один из контрибьютеров даже сделал модуль, который показывает как это могло бы выглядеть:
declare(strict_types=1);
class IntHandler {
public static function abs(int $self): int {
return abs($self);
}
public static function div(int $self, int $other): int {
return intdiv($self, $other);
}
public static function sqrt(int $self): float {
return sqrt($self);
}
}
register_primitive_type_handler('int', 'IntHandler');
$i = -5;
var_dump($i->abs()->div(2)->sqrt()); // 1.4142135623730951Разумеется, если это решение поместить в язык, никаких классов регистрировать не надо будет, так что можно смотреть только на последнюю строку.
Кроме того, повышается читаемость. Сравните два подхода
$result = substr(strtr(rtrim($className, '_'), '\\', '_'), 15);
$result = $className->trimRight('_')->replace('\\', '_')->slice(15);Как по мне, очень хорошее решение, совершенно непонятно почему оно ещё не в языке.
Северокорейские причёски
Зашёл с одним дружищем разговор про Северную Корею, и в рамках этого разговора он мне кинул ссылку на статью о разрешённых в этой стране женских и мужских причёсках.
Меня, как человека, который бреется налысо, заинтересовало — лысых корейцев не существует или все парики носят?
Прогресс у дочки в чтении
Как я писал ранее, в школе, в которую мы стремились отдать дочку, уже в первом классе от ребёнка требуется беглое чтение.
Мы наняли репетитора, которая занимается с Евой по часу два раза в неделю, но мне кажется этого мало. Поэтому я решил каждый день тоже понемногу помогать этому процессу. Методика сложилась стихийно: подобрал несколько захватывающих книг, из которых я каждый вечер начал читать по несколько страниц, и предложил дочке читать по одному слову на страницу. Слово выбирал сам.
Сначала я держал пальцем то слово, которое надо прочитать, потом перестал, так же постепенно увеличивал количество слов, которые надо прочитать на странице. Сейчас мы дошли до шести и иногда я предлагаю прочитать целые предложения, но не усердствую — подряд читать много слов пока трудно.
Прерываемся, как только дочка устаёт, — начинает путать порядок букв или сами буквы. Дальше я несколько страниц читаю без неё, думаю, если бы я останавливался сразу после этого, это было бы похоже на наказание.
Такая методика оказалась хороша тем, что позволяет поддержать интерес — дочке самой хочется продолжать, старается, читает.
Побочным эффектом подхода стало то, что почти исчезла боязнь больших текстов. Я даже не знал или забыл, что у детей существует такое явление.
Стало понятным почему дочка читала раньше исключительно вывески и короткие фразы в комиксах. Несмотря на то, что целая страница книги ей
Apple Vision Pro
Сейчас все обсуждают шлем дополненной реальности, который представила «Эпл» несколько дней назад. Выглядит очень круто, но меня больше заинтересовало что за пять тысяч патентов они там подали. На что? Твит Стерлинга Криспина, исследователя нейротехнологических прототипов в «Эпле» немного проливает свет на эту загадку:
Для того чтобы сделать возможными конкретные предсказания, было использовано множество хитростей, о которых подробно говорится в нескольких патентах, автором которых я являюсь. Один из самых крутых результатов — предсказание того, что пользователь собирается нажать
на что-то до того, как он это сделает.Это была огромная работа, которой я горжусь. Ваш зрачок реагирует до того, как вы нажмете на кнопку, отчасти потому, что вы ожидаете, что
что-то произойдет после нажатия. Поэтому вы можете создать биологическую обратную связь с мозгом пользователя, отслеживая поведение его глаз и изменяя дизайн пользовательского интерфейса в реальном времени.
Ещё интересное место:
В другом патенте подробно описывается использование машинного обучения и сигналов тела и мозга для предсказания того, насколько вы сосредоточены или расслаблены, или насколько хорошо вы учитесь. А затем обновлять виртуальную среду, чтобы улучшить эти состояния. Представьте себе адаптивную среду погружения, которая помогает вам учиться, работать или расслабляться, изменяя то, что вы видите и слышите на заднем плане.
Конечно, шлем «Вижн Про» — технологический бриллиант, даже если его рассматривать просто как замену монитору. Я предвкушаю возможность поработать с ним
ИИ и «Эльбрус»
Прочитал свежую новость о том как ребята из «Гугла» при помощи алгоритмов искуственного интеллекта ускорили сортировку. На коротких последовательностях ускорение там достигает 70%:
AlphaDev’s newly discovered algorithm achieves a 70% increase in efficiency for sorting short sequences of elements and approximately 1.7% for sequences surpassing 250 000 elements, as compared to the algorithms in the C++ library.
Казалось бы слово «коротких» портит всю малину (на больших там не такие выдающиеся цифры), но это тоже полезно —
Отметим так же, что задачи сортировки очень широко распространены в программировании и естественный интеллект много сделал для того, чтобы их оптимизировать — эта область алгоритмов пользуется повышенным вниманием, но ИИ всё равно нашёл что тут улучшить.
В этой связи мне вспомнился многострадальный процессор «Эльбрус» со своей неоднозначной архитектурой VLIW, которую ещё недавно с удовольствием многие пинали.
Особенность такой архитектуры в том, что мы упрощаем процессор — убираем оттуда блоки динамического управления распараллеливанием кода. Предполагается, что для таких процессоров эта работа должна производится на этапе компиляции — код параллелится статически, раз и навсегда указывается как объединятся инструкции в каком порядке и где они будут выполняться.
Такой упрощённый процессор дешевле разрабатывать и производить, ну и компилятор дорабатывать проще процессора — новая версия не требует запуска новой производственной линии.
Проблема в том, что такой умный компилятор пока написать не удаётся и вряд ли удастся, если использовать традиционные методы, применяемые в разработке компиляторов. Слабое звено тут человек — с каждой итерацией всё сложнее придумывать и добавлять новые оптимизации, да ещё и так, чтобы не сломать всё остальное.
Но если привлечь к этому ИИ, наверняка станет веселее. Не вполне понятно пока когда, но однажды точно станет. Пока реализации алгоритмов искусственного интеллекта недостаточно проворны для этого, но может быть через несколько лет кожаные совместно с коваными достаточно всё оптимизируют, чтобы компилятор под такой процессор работал с достаточной скоростью.
Совсем не факт, конечно, что такая стратегия выгоднее традиционной,
Ссылки через веб-архив
Поймал себя на том, что всё чаще у себя на сайте даю ссылки через «
Сон про фраки
Сегодня встал в половине четвёртого ночи, чтобы поехать с ребятами на рыбалку на острова — ехать несколько часов, потом ещё плыть. А так как сон прервался в неурочное время, я запомнил что мне снилось, редко могу таким похвастаться.
Снилось мне, что ещё в недавнем прошлом,
Сама поездочка вышла чуть экстремальной и немного менее интересной, чем сон — погода испортилась, плюс наползались по пересечёнке, ноги отваливаются. В этом месте много битых кирпичей, там
Подозреваю, что это мушкетные пули, но могут быть чем угодно, конечно же. Взял в подарок дочке — ей нравится, когда я привожу
99 бутылок: SectorC
Мне тут попеняли в комментариях, что я совсем забросил раздел, в котором я пишу на разных языках программирования американскую считалочку про пиво на стене. Я
Пора возобновить.
76. SectorC — очень маленький компилятор подмножества языка Си. Помещается в один сектор — 512 байт, отсюда и название. Язык очень сильно урезанный, но всё равно меня поражает как автор запихнул имеющееся в такой малый объём.
В языке нет строк и операторов
Самые распространённые в выходном тексте буквы я кодирую полубайтом от 0x1 до 0xE, а более редкие — байтом от 0xF1 до 0xFC. Завтра попробую описать это чуть подробнее.
Немного так же печалит, что нет локальных переменных, параметров и возвращаемых значений — всё передаётся через глобальные переменные, как в ранних Бейсиках. Кроме того, немного
// Written by Evgeny Stepanischev https://bolknote.ru
// SectorC
int c; // input
int shift; int x;
void x() { if( c == ( x >> 8 ) ){ print_ch = x & 255; } }
void p() { print_ch = c; print_char(); }
void c2c() {
c = c + shift;
x = 288; x(); x = 613; x(); x = 879; x(); x = 1140; x(); x = 1388; x();
x = 1634; x(); x = 1902; x(); x = 2145; x(); x = 2419; x(); x = 2674; x();
x = 2918; x(); x = 3191; x(); x = 3338; x(); x = 3684; x(); x = 4200; x();
x = 4396; x(); x = 4654; x(); x = 4981; x(); x = 5204; x(); x = 5481; x();
x = 5739; x(); x = 6000; x(); x = 6253; x(); x = 6471; x(); x = 6734; x();
x = 7033; x();
if( c != 15 ){ print_char(); }
shift = 0; if( c == 15 ){ shift = 15; }
}
int s; // input
void ps() {
while( s ){
c = s & 15;
c2c();
s = s >> 4;
if( s == ( 0 - 1 ) ){ s = 0; } // signed workaround
}
}
void bottle() { s = 17249; ps(); s = 596; ps(); }
void of_beer() { s = 6961; ps(); s = 41510; ps(); }
void on_wall() { of_beer(); s = 5937; ps(); s = 8692; ps(); s = 22721; ps(); print_char(); }
void o_more() { s = 40723; ps(); s = 675; ps(); }
int b; // input
void bottle_b() {
if( b == 0 ){ s = 55; ps(); }
if( b > 0 ){ print_num = b; print_u16(); }
bottle();
if( b != 1 ){ c = 115; p(); } // s
}
void main() {
shift = 0; b = 99;
while( b > 0 ){
bottle_b(); on_wall();
s = 303; ps(); /* ', ' */ bottle_b(); of_beer();
c = 46; p(); // '.'
print_newline();
b = b - 1;
s = 2143; ps(); s = 4735; ps(); s = 4723; ps(); s = 31806; ps();
s = 59265; ps(); s = 35057; ps(); s = 409; ps(); s = 5231; ps();
s = 936; ps(); s = 59215; ps(); s = 303; ps();
bottle_b(); on_wall(); c = 46; p(); // '.'
print_newline(); print_newline();
}
c = 78; p(); /* 'N' */ o_more(); bottle(); c = 115; p(); // 's'
on_wall();
s = 28975; ps(); /* ', n' */ o_more(); bottle(); c = 115; p(); // 's'
on_wall();
c = 46; p(); // '.'
print_newline();
s = 5039; ps(); s = 16692; ps(); s = 4639; ps(); s = 41801; ps();
s = 30738; ps(); s = 1566; ps(); s = 53071; ps(); s = 913; ps();
s = 4767; ps(); s = 41887; ps(); s = 4850; ps();
b = 99; bottle_b(); on_wall(); c = 46; p(); // '.'
}Свёртка строк на SectorC (лонгрид)
Вчера я обещал рассказать что я придумал, чтобы компактнее выводить строки в языке SectorC. Напомню, это компактный компилятор подмножества Си, который занимает один сектор (512 байт).
Для начала посмотрим что доступно в компиляторе для вывода текста. В самом языке для этого ничего нет, но если заглянуть в стандартную библиотеку языка, которая подключается автоматически, то можно увидеть там функции print_char(), print_u16() и print_i16(), предназначенные, соответственно, для вывода символа, заданного его кодом, целого числа без знака и целого числа со знаком.
Соответственно вывод «Hello» выглядит так:
print_ch = 72; print_char(); // H
print_ch = 101; print_char(); // e
print_ch = 108; print_char(); // l
print_ch = 108; print_char(); // l
print_ch = 111; print_char(); // oОчень многословно. Когда я вчера написал «песню о пиве» в таком формате, программа получилась чересчур длинной. Мне захотелось
Код задаётся целым типом int, который имеет в этом языке 65536 значений. Поскольку мне нужны не все буквы, выглядит так как будто в одно число можно запихнуть несколько знаков. Но сколько?
Для начала посмотрим сколько символов вообще используется. Цифры меня не интересуют (числа выводятся отдельной функцией), поэтому выкинем их:
import sys
from collections import Counter
data = Counter(x for x in ''.join(sys.stdin.readlines()) if x > '9' or x < '0')
print(data)Вот что получилось:
Counter({' ': 2306, 'e': 1305, 'o': 1108, 't': 903, 'l': 702, 'b': 601, 'n': 600, 'a': 598, 's': 497, 'r': 403, 'f': 300, 'w': 300, '\n': 298, 'd': 298, 'h': 202, ',': 200, '.': 200, 'u': 100, 'T': 99, 'i': 99, 'k': 99, 'p': 99, 'm': 4, 'G': 1, 'N': 1, 'y': 1})Двадцать шесть символов. Жаль не шестнадцать, было бы удобно хранить — как я говорил выше, значений в целом типе помещается 65536 штук. Какая связь? Чтобы это понять, разберёмся откуда взялось число 65536.
Оно вытекает из особенностей машинного хранения. Минимальная единица хранения — бит, хранит всего два состояния, — биты, в свою очередь, собраны по восемь штук в байты. Тип int в данном случае — это два байта.
Отсюда получается, байт — восемь бит по два значения или 2⁸ = 256 значений, два байта — 256² = 65536. В десятичной системе выглядит довольно бессмысленно, но если перейти на шестнадцатеричную, где цифры записываются от 0…9, A…F, с префиксом 0x (он ставится чтобы различить две формы записи числа), то становится понятнее.
Тогда число 65536 будет выглядеть как 0xFFFF — визуально распадается на два байта по 256 (0xFF) значений или на четыре полубайта по 16 (0xF).
Я решил хранить символы в полубайтах. Поскольку символов у меня 26, а в полубайте помещается 16 значений, то одно значение пришлось занять префиксом — если он встречается, то мы используем вторую таблицу символов. Под префикс я выделил 0xF. Таким образом, в одном int можно закодировать от двух до четырёх символов.
Например, число 0x2F40 или 0x2 0xF 0x4 0x0 означает, что мы смотрим второй символ в первой таблице, потом переключаемся на вторую (так как встретили 0xF) и смотрим там четвёртый символ, а символ 0x0 имеет специальное значение, — он не выводится и нужен для того, чтобы у нас была возможность закодировать строку, которая короче, чем могла бы поместиться.
В первую таблицу я поместил самые часто встречающиеся символы, во вторую — те, что встречаются реже. Получилось намного компактнее. Например, строка «hello» в моём алфавите выводится вот так:
s = 21023; ps(); s = 53; ps(); // 0x521F, 0x35Поскольку по техническим причинам число проще обрабатывать с конца, то я разворачиваю ту часть строки, которая кодируется. Это легко заметить по тому, что префиксное значение 0xF у меня находится в конце числа 0x521F.
Код для преобразования строк в такую форму выглядит следующим образом:
input = 'hello'
from itertools import *
# основная таблица
t0 = [' ', 'e', 'o', 't', 'l', 'b', 'n', 'a', 's', 'r', 'f', 'w', '\n', 'd']
# и дополнительная
t1 = ['h', ',', '.', 'u', 'T', 'i', 'k', 'p', 'm', 'G', 'N', 'y']
# поиск символов в таблицах
def conv(ch):
try:
yield t0.index(ch) + 1
except ValueError:
yield 0xF
yield t1.index(ch) + 1
# подготовка к разбиению по группам, которые будут кодироваться вместе
def make_shifter():
pos = 0
gr = 0
def shifter(v):
nonlocal pos
nonlocal gr
if pos == 4:
pos = 0
gr += 1
# префикс переключения таблиц не может остаться в одиночестве,
# поэтому мы не можем оставить его в хвосте
if pos == 3 and v == 0xF:
pos = 1
gr += 1
else:
pos += 1
return (v, gr, )
return shifter
shifter = make_shifter()
# нумеруем группы символов
gen = (shifter(x) for x in chain(*(conv(ch) for ch in input)))
# собираем группы символов вместе
gen = groupby(gen, key = lambda x: x[1])
# двигаемся по собранным группам, собираем их в число
for x in gen:
sum = 0
for y in list(x[1])[::-1]:
sum *= 16
sum += y[0]
print("s = {}; ps(); ".format(sum))Теперь только осталось запрограммировать декодирующую часть в SectorC. У нас будет две функции — одна достаёт из числа по одном полубайту за раз, вторая преобразовывает полубайт в соответствующий символ. Как всё работает в деталях объяснять не буду, покажу с минимальными комментариями.
Первая выглядит совсем просто:
int s; // input
void ps() {
while( s ){
c = s & 15;
c2c();
s = s >> 4;
if( s == ( 0 - 1 ) ){ s = 0; } // signed workaround
}
}Напоминаю, что вы языке у функции нет аргументов и возможности вернуть значение — всё делается через глобальные переменные, поэтому код выглядит странновато.
Строка с комментарием нужна, так как число у нас знаковое (то есть возможные 65536 значений делятся пополам, часть значений считается отрицательным, другая часть — положительными). У отрицательных чисел есть особенность — битовый сдвиг (>>) хоть и считается эквивалентом деления на два, но из минус единицы ноль не делает.
c2c тут — как раз функция, которая должна преобразовывать код в символ (
Сначала я так и сделал, но выглядело, опять же, громоздко. В итоге, переделал чуть попроще: код сравнения выделил в короткую функцию x(), а пару что во что превращается закодировал в один int:
int c; // input
int x;
void x() { if( c == ( x >> 8 ) ){ print_ch = x & 255; } }После такого кодирования функция
void c2c() {
c = c + shift;
x = 288; x(); x = 613; x(); x = 879; x(); x = 1140; x(); x = 1388; x();
x = 1634; x(); x = 1902; x(); x = 2145; x(); x = 2419; x(); x = 2674; x();
x = 2918; x(); x = 3191; x(); x = 3338; x(); x = 3684; x(); x = 4200; x();
x = 4396; x(); x = 4654; x(); x = 4981; x(); x = 5204; x(); x = 5481; x();
x = 5739; x(); x = 6000; x(); x = 6253; x(); x = 6471; x(); x = 6734; x();
x = 7033; x();
if( c != 15 ){ print_char(); }
shift = 0; if( c == 15 ){ shift = 15; }
}Как видите, код 0xF (15) устанавливает флаг сдвига значений shift, который в следующий раз складывается с кодом (c + shift) и сдвигает значение на следующем декодировании. Заметно, что нигде нет else, потому что этого оператора в языке тоже нет!
Как будто бы рассказал всё.
Вместо вывода — интересный своей компактностью компилятор, автору моё уважение, — я даже и не подозревал, что в таком малом объёме можно уложить полноценный язык! Очень и очень круто!
Моя тема для «Эгеи»
Вчера выложил свою тему оформления для движка «Эгеи». Меня давно просили, а вчера был очередной комментарий на эту тему, ну я и сделал это наконец. Тему надо положить в папку user/themes/bolk, выбрать её в настройках блога и сбросить кеши.
SectorCFuck
Очень интересно устроен разбор файла программы в компиляторе SectorC, который я ковыряю вечерами из любви к ненормальному программированию. Для тех, кто успел позабыть, напомню — этот компилятор занимает один сектор (512 байт) и способен выполнять программу на подмножестве Си.
Когда смотришь на код такого маленького объёма, сразу возникает вопрос — каким чудом удалось туда запихнуть грамматику языка Си, даже если
Автор использует реализацию функции atoi, которая превращает любые строки в шестнадцатибитное числа:
unsigned short sectorc_atoi(const char *s)
{
unsigned short n = 0;
for (;;) {
char c = *s++;
if (!c) break;
n = 10 * n + (c - '0');
}
return n;
}Все токены, которые встречаются в программе, обязательно разделяются пробелами (за исключением ;, для него есть специальная обработка). Это позволяет довольно просто парсить программу — любой токен скармливаем atoi, получаем число и по таблице смотрим с чем имеем дело.
Если в таблице число не находится, значит это переменная, её численное значение, умноженное на два, даёт двухбайтовую область памяти, где надо взять значение. Для чисел, видимо, есть
Перед запуском программа проходит через линтер, который не является частью компилятора. Он нужен для поиска ошибок в коде и коллизий в получившихся хешированных значениях. В последнем случае линтер останавливается с ошибкой, показывая хеши каких токенов совпали между собой.
Если линтер выключить, можно достигнуть интересного эффекта. Для каждого токена можно вычислить коллизию позаковыристей и написать всю программу без букв и цифр. SectorC как будто бы «из коробки» предназначен для запуска обфусцированного кода.
Ниже программа, выводящая «Hello» (её надо запускать без линтера):
<**^ ')'|] /=]
-_.@" -[ )~( /@< $^+>\() /<'
-_.@" -[ /<'' /@< $^+>\() /<'
-_.@" -[ ,[~ /@< $^+>\() /<'
-_.@" -[ +^^` /@< $^+>\() /<'
-_.@" -[ /<(' /@< $^+>\() /<'
,[_Я поленился и не стал рассчитывать разные значения для одинаковых токенов, которые упоминаются несколько раз, но можно сделать и это, тогда восстановление исходного текста будет безумно затратной задачей.
Обфусцированный таким образом листинг, запускающий файл и программу для поиска коллизий выложил на «Гитхаб», можно посмотреть подробности там.
Кстати, такое развлечение, когда мы не используем в программе
Женя Владимирович
У многих имён есть «официальная» форма и «дежурная». Для моего имени это «Евгений» и «Женя», соответственно. У «дежурной» формы есть особенность — она никогда не ставится вместе с отчеством, «Женя Владимирович» звучит нелепо.
Так вот, меня не покидает ощущение, что у части имён как будто бы нет «официального» варианта. Например, у «Ляли» и «Олеси». Для меня всю жизнь немного необычно звучат «Ляля Узбековна» или «Олеся Александровна», словно тут должна стоять
Деление в SectorC
Очень неудобно, что в языке SectorC нет деления. Я сначала думал, что это
Но сегодня для интереса я попытался добавить в код новый токен для деления и оказалось, что места хватает. Закинул автору
Впрочем, SectorC устроен так, что в программе можно использовать машинные коды. Можно написать деление прямо в них, если воспользоваться ассемблером.
При этом надо знать две вещи: присваивание значения переменной происходит через регистр AX, так что присвоив переменную саму себе, можно записать в AX её значение, и второе — если посчитать atoi (см. мою вчерашнюю заметку) для имени переменной и умножить получившееся число на два, можно получить ячейку, где хранится значение этой переменной.
Так вычисленный результат можно будет положить куда вздумается.
Объединив всё вышесказанное, получим такой результат:
int div_a; int div_b; // input
int div_result;
void div()
{
div_b = div_b; // mov ax, [&div_b]
asm 145; // xchg cx, ax
asm 49; asm 210; // xor dx, dx
div_a = div_a; // mov ax, [&div_a]
asm 247; asm 241; // div cx
asm 163; asm 48; asm 193; // mov [&div_result], ax
}
void main()
{
div_a = 35500; div_b = 113; div();
print_num = div_result; print_u16(); // «314»
}Писательская мозоль
Смотрел сегодня утром интервью лингвиста Игоря Исаева, там в один момент там всплыла тема писательской мозоли — бугорка, который образуется сбоку среднего пальца от постоянного письма ручкой или карандашом.
Я помню какая монструозная она была в школе, мы ведь много писали,
Последние лет двадцать я пишу рукой редко и она почти исчезла, сейчас она даже не во всех положениях заметна. На снимке я нарочито её подчеркнул, а то, мало ли, может молодое поколение вообще не знает что это такое и как она выглядит.
Я плохо представляю пока что происходят в современных школах — у меня дочь в этом году только пойдёт в первый класс.
В этой связи вопрос — у современных детей эта мозоль образовывается? Я
Make QR-code great again!
Продолжаем рубрику «все побежали и я побежал».
Сейчас все ударились в генерацию
Мы, конечно, давно набаловались со смешиванием нейросетями двух и более изображений, — весь интернет этим завален до сих пор, — но возможность смешать
У меня получились не самые яркие примеры, — надо специально подбирать, время не очень хочется на это тратить, но иногда у людей случайно получаются картинки, в которых
Не исключено, что эти эксперименты выльются
Либо такое смешивание найдёт использование как менее грубо вписанные в окружающий мир метки дополненной реальности. Сейчас это довольно чужеродно выглядящие коды, по типу
return в SectorC
Вчера перед сном пришло в голову, что один из недостатков языка SectorC, — отсутствие конструкции return, можно отчасти компенсировать средствами самого языка. Достаточно написать функцию return(), которая будет делать две вещи — возвращать значение (об этом ниже) и прерывать выполнение функции из которой её вызвали.
Я уже достаточно знаю об его внутренностях, чтобы понимать как это можно сделать.
Второе реализовать совсем просто, тут мне помогает некогда богатый опыт программирования на Ассемблерах. SectorC транслируется напрямую в машинный код, а значит адреса возвратов из функций хранятся на стеке. Так что надо всего лишь удалить верхний адрес возврата и мы вернёмся не в функцию, которая нас вызвала, а на уровень выше. Я делаю это командой pop ax.
Теперь посмотрим на первую задачу.
Как я уже писал язык устроен так, что присваивание переменных друг другу происходит через регистр AX, таким образом, присваивая переменную самой себе, мы помещаем её в этот регистр. Этот факт используется в стандартной библиотеке языка, так что можно считать, что это стабильное поведение.
Напрашивается следующая реализация, — перед вызовом присваиваем возвращаемую переменную самой себе, в функции return() записываем содержимое AX
Моя реализация вместе с примером использования ниже:
void return()
{
// mov [&return], ax
asm 163; asm 236; asm 229;
// pop ax (clear stack from prev return address)
asm 88;
}
void random()
{
// xor ax, ax int 0x1A xchg ax, dx
asm 49; asm 192; asm 205; asm 26; asm 146;
// xor dx, dx mov cx, 10
asm 49; asm 210; asm 185; asm 10; asm 0;
// div cx inc dx xchg ax, dx
asm 247; asm 241; asm 66; asm 146;
return();
}
void function()
{
i = 0; while( i < 20 ){
random();
if( i > return ){
i = i; return();
}
i = i + 1;
}
i = 0; return();
}
void main()
{
function();
print_num = return; print_u16();
}Кстати, возникает любопытный сторонний эффект — так как через AX делается не только присваивание, а вообще все операции, то функция return() захватывает любое последнее вычисленное выражение, что тоже может быть удобно.
Дефицит внимания к сериалу
При этом в других видах деятельности такого не наблюдается, — когда занимаюсь программированием или другими хобби, ухожу с головой.
Можно было бы подумать, что дело в качестве сериала, но тоже нет, — сейчас смотрю шестой сезон «Чёрного зеркала», очень нравится и сам сериал, и конкретно этот сезон.
Не понимаю.
Деревянный сердечник
В Московском энергетическом была такая байка, что некий студент написал в дипломной работе: «По причине того, что до сюда не дочитают, сердечник трансформатора рекомендуется сделать из дерева».
Который год являюсь членом государственной экзаменационной комиссии на двух кафедрах ИВМиИТ КФУ (бывший факультет ВМК) и всё это время меня не могу отделаться от ощущения, что многие студенты руководствуются правилом «всё равно это никто не будет читать».
Сегодня был первый день защиты дипломных работ в этом году и в большинстве дипломных работ схема базы данных вставлена как уменьшенная до полной нечитаемости картинка — буквы не просто мелкие, там уже разрешения не хватает, всё смазывается.
Ещё проблем доставляет мода на тёмные темы оформления — скриншоты с кодом теперь на бумаге выглядят как
Это 100% никто читать не будет, — просто потому, что прочесть это невозможно.
Шур-шур-шур
При переезде на новую квартиру вскрылась такая проблема: наша собака, когда ходит, очень громко шкрябает когтями по ламинату. Иногда друг друга не слышишь, настолько громко. Не припомню такой проблемы до переезда.
Есть тут собачники?
Законник
— Да. Я, конечно, не юрист, но…
— Этот вопрос решают не законники, а психологи. Теперь вся тяжесть проблемы легла на плечи Маллина, и он хорошо это понимал.
— «Маленький пушистик», Бим Пайпер, «Полярис», 1997
Одна из загадок, которая меня периодически мучает, — почему в американских книгах и фильмах постоянно действуют «законники». Кажется нигде вне этого контекста я больше не встречал это слово.
Я его понимаю, разумеется, но звучит
Дорогою бобра
Сегодня у дочки в школе был «выпускной» — после учебного года у них ещё месяц продолжаются занятия в формате школьного лагеря, а после этого проходит «капустник», который готовится силами учеников, выступают все желающие кто во что горазд.
Ева выступила дважды — сначала сольно спела песню «Лесной олень» (ей она очень нравится), а после в общем хоре — «Дорогою добра».
А в этой песне есть такая строчка: «иди, мой друг, всегда иди дорогою добра». И вот, во время выступления я слышу, что дети явно поют «дорогою бобра», при этом хихикают и косятся на мою доченьку. Оказывается, Ева в этом месте прикололась, всем детям понравилось, решили на концерте спеть «бобра».
Фамильные вещи
Знакомая, зная как я люблю старинные вещи, принесла посмотреть
От моей бабушки, папиной мамы, правда, досталась полтина непонятного происхождения и, кроме того, у меня лежат её награды, но хотелось бы
У жены ситуацию чуть получше — сохранился патефон деда, а у бабушки хранится икона, которая
Тесть ещё
Сложно сказать откуда во мне любовь к старинным предметам, но наверное, раз существуют музеи, я не один такой. Кажется, если бы я работал сотрудником с допуском к запасниками Национального музея, не вылезал бы оттуда месяцами, — говорят запасники там огромные!
Простейший HTTP-прокси
У Романа Парпалака прочитал про «простейший HTTP-прокси». Ну нет, действительно простейший HTTP-прокси
Выглядит он так:
<?php readfile($_SERVER["REQUEST_URI"]);Запускается так:
php -S 127.0.0.1:8080 proxy.phpА вот так работает:
Ещё о печати строк в SectorC (лонгрид)
Недавно познакомился с интересным компилятором подмножества языка Си — SectorC. Он интересен тем, что влезает в один сектор (512 байт), но позволяет писать вполне реальные программы. В реализованном языке очень многого нет, тем не менее, это очень интересное достижение и мне было интересно поразбираться как всё сделано. Кстати, результат автора мне удалось в несколько приёмов уменьшить на несколько байт.
Для того, чтобы рассказать в чём смысл, надо для начала немного углубиться в то как работает этот компилятор.
Компилятор, когда разбирает код, делит его на токены по пробелу, после каждый токен хешируется функцией atoi в двухбайтовое число и уже по нему определяется является ли встреченное ключевым словом языка, либо именем функции или переменной.
В последнем случае, имя, преобразованное в число, будет в машинных кодах использовано как смещение, указывающее на ячейку со значением переменной или с указателем на тело функции.
Отсюда следует, что последовательно называющиеся переменные — a, b, c и так далее, с будут в памяти располагаться последовательно со смещением в два байта, точностью до переполнения. При этом их даже не обязательно определять — переменная с любым именем существует с начальным нулевым значением.
Идём дальше.
В языке есть любопытная операция — &, позволяющая получить адрес переменной, который, напомню, равен одновременно хешу (atoi) к её имени. Для однобуквенных имён это позволяет по полученному адресу восстановить код символа — надо поделить полученное значение на два и добавить 48 — код символа 0.
Таким образом, передав в функцию адреса & H, & e, & l, & l, & o, мы сможем восстановить из них символы и составить из них слово Hello. Если записать эти адреса в переменные, которые располагаются в памяти подряд, можно, читая память последовательно, выводить закодированную строку.
Есть ли в языке способ прочитать
Теперь всё вышесказанное можно соединить в следующий довольно компактный код:
void print_str()
{
print_str_pointer = & _0;
while( *(int*) print_str_pointer ){
print_ch = ( *(int*) print_str_pointer >> 1 ) + 48; print_char();
print_str_pointer = print_str_pointer + 2;
}
}
void main()
{
_0 = & H; _1 = & e; _2 = & l; _3 = & l; _4 = & o; _5 = 0;
print_str(); // Hello
}Фотографии из дома на Маяковского, 26
Три года назад меня
Мне там удалось найти парочку почти целых газет за обоями, многочисленные кирпичные клейма, сфотографировать старинные обои и обзавестись парочкой интересных фотографий.
Фотографии я заметил далеко под лестницей через выломанную
Понадеявшись, что легко их атрибутирую, — на одной из фотографий упоминается некий закрытый кооператив «Вахитовец», я выложил фотографии в группу краеведов.
К моему разочарованию, никакой информацией обзавестись не удалось, — никто ничего не написал, да и попытки нагуглить «Вахитовец» в тот момент тоже ничего не дали. Несколько лет они у меня
Вот я и решил выложить фотографии сюда — несколько раз это неплохо срабатывало, может и на это фото
Несмотря на то, чтобы оба фото были найдены в одном месте, непонятно есть ли связь между двумя этими фотографиями, но как будто бы общая стилистика их оформления на неё указывает.
Вряд ли удастся
Чтение в параллель с размышлением
Каждый день стараюсь дочке читать перед сном хотя бы несколько страниц
Я только недавно узнал, что не все так умеют, но иногда при чтении вслух я размышляю
Недавно я вскользь упомянул об этом в разговоре, чем сильно удивил своего собеседника. Он уверен, что это невозможно и я всё придумываю.
Я же уверен прямо в противоположном, — на самом деле все так умеют, просто мало кто читает вслух
Плюсы контрастного душа
Вот уже три месяца каждое утро начинаю с контрастного душа.
Моей целью было улучшить сон, но я не уверен, что в этом отношении
Мне стало не особо холодно при +15 в одной футболке — в одну прогулку пришлось это узнать на опыте, резко похолодало, а дочка было легко одета, да и последствия переохлаждения на мне уже не так сказываются, — в прошлую поездку на рыбалку был дождь с ветром и довольно прохладно, но на следующий день со мной всё было в порядке. У меня наследственно слабые гланды и раньше я бы легко не отделался.
По итогу, если бы я раньше знал, что несколько минут этой процедуры каждое утро так мне помогут, я бы занялся этим уже много лет назад. Всем очень рекомендую!
You're welcome
Посмотрел сегодня фильм «Ренфилд», про который слышал, что Николас Коппола вновь в нём хорошо играет. Мне очень нравится этот актёр в своих ранних ролях, поэтому не мог упустить.
Очень классная задумка (не спойлер) — взгляд на вампира и фамильяра через современное представление о созависимых отношениях, — групповая терапия, книжки, попытки преодоления, вот это всё. Я смеялся, но очень жаль, что не посмотрел вместе с женой, — она получила высшее по психологии, практикует и мне нравится с ней делиться такими находками по этой теме.
Отдельное удовольствие доставил вот этот кадр, который я даже заскриншотил — сначала резануло, что вампир
Петлевой детектор транспорта
Если над петлёй стоит автомобиль, её индуктивность меняется, что позволяет включать «стрелки» на светофорах, только если это реально необходимо, — если есть кому поворачивать.
Бревно с клеймом «ТВЧ»
Пора, может, новый тег заводить — для клейм на брёвнах. Тема
Первое подобное клеймо я увидел в историческом районе Рахматуллина,
Там охрана, тогда меня туда разок пустили реставраторы, было очень интересно. Собирался туда
Новое клеймо найдено на чердаке дома на Волкова, 40. Дом расселили и нас пустили туда с разрешения нового владельца — глянуть нет ли на чердаке
По принадлежности клейма сказать ничего не могу — тема совершенно новая, исследований, кажется, нет. Надо рыть литературу, но не чувствую в себе достаточно огня, чтобы этим заняться.