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

Взрывающийся компьютер

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

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

Два молодых человека в тёмном помещении с компьютерами: один стоит в кожаной куртке и красной футболке, другой сидит за столом, работает за старым монитором.
Логово хакера в пародийном фильме «Кунг Фьюри», не то, чтобы тут что-то взрывалось, но ничего более подходящего я не смог подобрать

Ну что ж, отныне можно говорить, что эти фильмы просто предвосхитили время:

Исследователи безопасности из китайской компании Tencent представили новый класс атак BadPower, нацеленный на поражение зарядных устройств для смартфонов и ноутбуков, поддерживающих протокол быстрой зарядки.

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

Как знать, может в скором будущем мы будем взламывать банки, летая через тоннели в сеточку, или программировать со скоростью машинистки, что-то рассматривая на шести чёрно-зелёных экранах?

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

Арктическое хранилище кода

Прочитал на «Оупеннете», что «Гитхаб» создал архив открытого кода в арктическом хранилище:

GitHub объявил о воплощении проекта по созданию архива открытых исходных текстов, размещённого в арктическом хранилище Arctic World Archive, способного уцелеть в случае наступления глобальной катастрофы. 186 плёночных накопителей piqlFilm, которые содержат фотоснимки информации и позволяют сохранять информацию более 1000 лет (по другим данным срок службы составляет 500 лет), успешно размещены в подземном хранилище на острове Шпицберген. Хранилище создано из заброшенной угольной шахты глубиной 150 метров, достаточной чтобы обеспечить сохранность информации даже в случае применения ядерного или электромагнитного оружия.

В архив попали все проекты, у которых по меньшей мере одна «звезда» и есть хотя бы один коммит, сделанный за год до снятия архива или позже, а так же проекты, у которых 250 «звёзд» и больше.

Раздел «Highlights» с текстом «Arctic Code Vault Contributor» и иконкой снежинки.

У каждого разработчика, чей код попал в архив, в профиле появилась отметка «Arctic Code Vault Contributor», у меня она тоже появилась. За шахматы на языке редактора sed и пару чужих проектов, в которые я даже не помню что коммитил и по какому поводу.

Забавно, что часть кода, написанного мной, будет гнить в какой-то арктической шахте в течение 5—10 веков.

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

Починил ucfirst в PHP

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

Интересно, что похожая функция — strtoupper тут работает прекрасно, то есть вот такой код на текущих версиях ПХП выдаёт false:

if (setlocale(LC_CTYPE, "ru_RU.cp1251") === false) {
    throw new RuntimeException();
}
// буква «я» имеет в кодировке «1251» код 255
var_dump(ucfirst(chr(255)) === strtoupper(chr(255));

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

Функция strtoupper как раз использует unsigned char, а ucfirst — char (который signed). Документация к toupper такую вольность по отношению к типам осуждает — там прямым текстом написано, что могут быть проблемы, так как внутри входной параметр будет расширен до int, знак перенесётся на старший разряд и всё сломается.

Что, собственно, и происходит с буквой «я», код которой как раз получается отрицательным. Удивительно, что с другими «отрицательными» буквами всё каким-то чудом работает.

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

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

«Магический шар» ★

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

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

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

Использование его в те годы могло бы выглядеть как-то так:

<A HREF=/cgi-bin/action.pl><IMG SRC=/i/pict.gif WIDTH=200 HEIGHT=100 ISMAP></A>

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

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

На тёмном фоне фиолетовый круг с надписью «My sources say no» (Мои источники говорят «нет»).
«Магический шар» из прекрасного фильма «Трасса 60»; с отрисовкой деталей я не стал заморачиваться

Я уже несколько лет как не верстаю, но почему-то этот атрибут ISMAP мне всё никак не давал покоя. Как будто брошенная на последней странице книга — всё тянуло найти ему какое-то применение.

И вот два года назад меня осенило использовать его в вёрстке «магического шара» из фильма «Трасса 60». Если не смотрели, там у главного героя был шар, который давал ответы на заданные вопросы, если его потрясти.

Мой шар «отвечает» в том случае, если на нём щёлкнуть мышкой. В качестве случайных значений используются координаты, передаваемые при помощи атрибута ISMAP, плюс картинка вращается при помощи CSS, поэтому даже под неподвижным курсором всегда разные координаты.

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

HTML с таким подходом становится довольно жирным — у меня получился 1,2 мегабайта, но по нынешним временам это не объём.

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

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

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

JUnix в книге

Пока ещё далеко не ушёл от этой темы, напишу.

Недавно выкладывал в открытый доступ свой проект начала нулевых — JUnix, «эмулятор» Линукса на ДжаваСкрипте. Заодно для интереса погуглил много ли ссылок осталось на прежний сайт проекта — junix.kzn.ru.

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

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

Страница учебника про эмуляторы Unix: заголовок 9.2, текст о JS-эмуляторе Степанищева, скриншот входа (JS Unix emulator v5.48b, IE 5.01, логин Alex) и пример man ls.
Упоминание JUnix в книге «Операционные системы. Практикум. Учебное пособие», Назаров С.В., Гудыно Л.П., Кириченко А.А.

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

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

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

JUnix ★

Вкратце: выложил на гитхаб свой старый проект «эмулятора» Линукса, который я писал в 90-е и начале 2000-х

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

Мне тогда этот язык невероятно нравился, я был в бешеном восторге и такое вот несерьёзное к нему отношение меня очень задевало. Как-то я фантазировал на тему того, что можно было бы такого интересного сделать в браузере, чтобы показать значимость ДжаваСкрипта, и как-то мало-помалу в голову пришла идея запрограммировать эмулятор «Линукса» — я как раз активно изучал эту ОС в те годы.

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

Скриншот терминала Unix-эмулятора JUnix v5.52b с командами whoami (root), df и mount, показывающими файловые системы и их параметры.
Старый, пыльный JUnix в современном браузере. Пришлось немного повозиться, чтобы запустить

Конечно настоящий эмулятор у меня не получился, да я и не пытался его создать, получилась имитация командной строки «Линукса» на том уровне знаний, который у меня был в те годы.

Реализованы кое-какие горячие клавиши, работа с историей и буфером обмена, основные команды (список выводится по команде «?»), перенаправление ввода-вывода, «пайп», работа с переменным, ветвления и циклы, виртуальная файловая система с возможностью написания плагинов и многое другое.

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

В своё время появление этого «эмулятора» понаделало шуму — о нём написали все основные российские сайты про программирование, а я каждый день получал письма от тех, кому понравилась моя игрушка.

Постепенно домен, на котором это всё располагалось, потерялся, а потом со старым винтом умер и бакап сайта. Осталась только копия в «Веб-архиве».

Так бы он там и лежал, но вчера в разговоре Леонидом Кагановым я случайно помянул почивший проект и Леонид, который его моментально вспомнил, предложил забрать сохранившееся с «Веб-архива» и куда-нибудь выложить.

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

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

Кстати, если вам нравится в таком копаться, можете посмотреть сколько костылей в то время приходилось городить и как беден был раньше этот ДжаваСкрипт.

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

Репозиторий проекта: https://github.com/bolknote/junix.
Сайт проекта, где можно посмотреть всё в действии: https://bolknote.github.io/junix.

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

99 бутылок: Старсет

Семьдесят четвёртый выпуск считалочки «песни о пиве», которую я пишу на разных языках программирования, для разнообразия сделаю на языке родом из СССР. Как-то я мало такому уделяю внимания, а ведь это тоже история!

74. Старсет — язык программирования высокого уровня, разработанный в Институте программных систем РАН в 1991 году. К сожалению, мне не удалось обнаружить компиляторов или интерпретаторов этого языка, и даже упоминания, что они вообще когда-либо были реализованы.

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

Оранжевая книга «Язык программирования СТАРГЕТ» М.М. Гилгула и А.П. Столбоушкина (Академия наук СССР, Наука) на фоне советской газеты с заголовками о границе и ТАРСС.
Книга «Язык программирования Старсет», М. М. Гилула, А. П. Столбоушкин, М., «Наука», 1991

Язык, кстати говоря, небезынтересный — в наличие имеется развитая работа со множествами и свой язык регулярных выражений («образцов»), который может применяться не только на скалярах, но и на множествах! Кроме того имеются операторы, позволяющие распараллеливать вычисления!

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

Например, попробуйте разобраться в этом отрывке («каноническая запись», как утверждается выше процитированного — это когда отброшены все незначащие нули):

Каноническим числовым представлением нуля будем считать слово 0. В частности, каноническим числовым значением слова 1 является оно само, каноническим представлением слова 2 является слово −6, каноническим представлением слова 3 — слово 67000000000000000.

Я, сколько ни пытался, не смог уловить закономерность.

Программы по внешнему виду сильно напоминают «Паскаль» — совпадают некоторые конструкции и принципы, но, конечно же, есть и вещи, которые сильно отличаются.

Выполнение программы выполняется с первой процедуры и завершается с выходом из неё. Возврат значения из функции (тут она называется «процедура-функция») осуществляется через переменную, совпадающую с именем функции. Все переменные, включая переменную для возврата, должны быть задекларированы в специальном блоке. Скалярные переменные декларируются в секции word, множества — в set, классы — в секции class.

/* Считалочка про пиво на языке «Старсет». Написал Евгений Степанищев */
/* https://bolknote.ru */

Func Бутылки(колво)
    Word: Бутылки, колво;

    Choice
        Case колво = 1 Do Бутылки := '1 bottle' End
        Case колво = 0 Do Бутылки := 'no bottles' End
        Otherwise Do Бутылки := колво^' bottles' End
Endfunc

Proc Песня()
    Word: колво, бутылок;

    колво := 99;
    бутылок := Бутылки(колво);

    While колво > 0 Do
        Write бутылок^' of beer on the wall, '^бутылок^' of beer.';
        колво := колво - 1;
        бутылок := Бутылки(колво);
        Write 'Take one down and pass it around, '^бутылок^' of beer on the wall.';
        Write ''
    End

    Write 'No more bottles of beer on the wall, no more bottles of beer.';
    Write 'Go to the store and buy some more, 99 bottles of beer on the wall.'
Endproc

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

Ещё необычно выглядит операция конкатенации — ^ и повторения строки — ^^. Из-за того, что в языке есть неявные преобразования, можно делать вот такое:

Write 'МА' ^^ '2 раза' /* Будет выведено «МАМА», так  как «2 раза» преобразуется к двойке */

С удовольствием познакомился с языком, благо он не выглядит, как что-то, сделанное «в стол», для «галочки» или исключительно для обучения школьников или студентов.

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

99 бутылок: Lua

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

73. Lua — скриптовый язык, который чаще всего применяют для встраивания, например — нередко используют для описания сценариев в играх. Объектная модель прототипная, напоминает ДжаваСкрипт, но в Луа она мощнее.

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

А вот стандартная библиотека подкачала, простой пример — в ней нет функции задержки, когда она мне понадобилась, пришлось её импортировать из Си. Или есть модуль, который хоть как-то позволяет работать с ЮТФ-8, но в нём даже нет простого способа получить символ по его номеру или поменять регистр строки.

function beer(b)
    if b == 1 then
        return '1 bottle'
    else
        return (b == 0 and 'no' or b) .. ' bottles'
    end
end

b = beer(99)

for i = 99, 1, -1 do
    print(b .. ' of beer on the wall, ' .. b .. ' of beer.')
    b = beer(i - 1)
    print('Take one down and pass it around, ' .. b .. ' of beer on the wall.\n')
end

print([[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.]])

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

День Радио ★

Сегодня, 7 мая в России отмечают День радио — в этот день, 125 лет назад российский физик Александр Степанович Попов на заседании Русского физико-химического общества продемонстрировал «прибор, предназначенный для показывания быстрых колебаний в атмосферном электричестве».

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

Таблица с эмодзи волн, взрывов и черепов, расположенных по строкам 01–10 и столбцам А–К на чёрном фоне.
Отладочный режим получившегося «Морского боя», в обычном режиме видно только мигание светодиода

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

В итоге, для этого я выбрал «Морской бой». В моём варианте игрок вводит информацию клавишей левого «Шифта», а компьютер отвечает, мигая светодиодом кнопки «Капс Лок». Чуть более подробные правила есть в репозитории проекта.

Обёртка и некоторые функции (мигание светодиодом, опрос «Шифта» и функция задержки) написаны на Си, остальная часть — на языке «Лу́а» (Lua). Давно хотелось изучить этот странноватый язык поглубже, а тут ещё удалось поучиться встраивать его в Си.

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

Код на C с вставками Lua: создание состояния Lua, загрузка скрипта battleship.lua или строки PROGRAM, обработка ошибок загрузки.
Диграфы в Си немного запутывают и вносят в код толику безумия

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

Для тех безумцев, которые захотят попробовать скопмилировать этот вариант «Морского боя» и сыграть, ещё раз привожу репозиторий проекта (только под «МакОСь») — https://github.com/bolknote/battleship.

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

«Разрабы»

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

Раньше к утру я был в относительной норме, но теперь чувствую, как внутри копится какое-то напряжение, похожее на сжатую пружину в механических часах, которое теперь только нарастает.

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

Скриншот интерфейса с кодом на Python для квантовых вычислений, включая функции make_qcirc, qrun и do_persimmon_run, а также таблицы данных и мониторинг гейтов.
Код на экране рабочего места русского программиста Сергея Павлова, одного из героев сериала

Вчера начал смотреть сериал «Разрабы» («Devs»), очень уж заинтересовало описание. На фоне предыдущего («Сказки из Петли») пока смотрится бледновато, но надеюсь ещё втянусь. По сюжету команда элитных программистов, называющихся «Разрабы» пишут какой-то загадочный софт для квантового компьютера.

Тема квантовых компьютеров находится на самой границе моих интересов, но всё же в их сторону я иногда поглядываю.

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

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

Язык программирования в центре — преимущественно Пайтон с подключенными модулями (из знакомых мне — математический пакет numpy и пакет квантовых вычислений qiskit), но видны вкрапления чего-то Си-подобного (последние несколько строк) и чего-то мною неопознанного (с операторами do, case и hypo).

Честно сказать, я ждал какого-нибудь «Ку-шарпа» (Q#) или какого-то другого языка, придуманного для квантовых вычислений, но почему бы и не «Пайтон», язык сейчас на коне.

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

Интересно для чего потребовалось делать мешанину из языков? Чтобы подчеркнуть, что это фантастика, а не реальный код? Или консультант тупо скопировал откуда-то готовые листинги и, не разбираясь, просто скроил из них нечто, что достаточно по-гиковски смотрится в кадре?

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

99 бутылок: CFAQ

Отдаю очередную дань своему давнему хобби — написанию американской традиционной песни про пиво на разнообразных языках программирования.

72. CFAQ (читается «СИФАК»). Очень люблю самодельные языки программирования, есть в них какое-то милое очарование, крафтовость с нотками олдскула. Услада сердцу после вездесущего Кровавого Энтерпрайза.

Когда узнал, что у известного писателя-фантаста Леонида Каганова есть собственный фреймворк для чипа ESP8266 со встроенным самописным скриптовым языком программирования «СИФАК», не мог пройти мимо. Леонид хоть и зарабатывает на жизнь литературными трудом, но когда-то работал программистом, разрабатывая на ассемблере модули устройств для геофизики и дозиметрии.

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

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

# 99.TXT. Написано Степанищевым Евгением, апрель 2020
B = 99
repeat -1 {
    Bt = {B}

    repeat 2 {
        if {Bt} = 0 {
            set S = no bottles
        } else {
            if {Bt} = 1 {
                set S = 1 bottle
            } else {
                set S = {Bt} bottles
            }
        }

        if {Bt} = {B} {
            echo {S} of beer on the wall, {S} of beer.<br>
        } else {
            echo Take one down and pass it around, {S} of beer on the wall.<br>
        }

        Bt -= 1
    }

    B -= 1

    if {B} = 0 {
        echo No more bottles of beer on the wall, no more bottles of beer.<br>
        echo Go to the store and buy some more, 99 bottles of beer on the wall.

        exit
    }
}

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

Скриншот интерфейса «Безумный Дом 3.0» с ошибкой «Error type: string», содержащей полный текст песни «10 бутылок пива на стене» от 10 до 0 и возврат к 99 бутылкам.
Выполнение программы на стенде, предоставленном автором языка

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

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

Три новые старые статьи

Свой собственный сайт появился у меня в ноябре 2000 года, кажется по адресу bolk.chat.ru. Позже мы познакомились с Алексом Экслером, который предложил хостится у него по адресу bolk.exler.ru, а в 2008-м году, после какого-то дискового сбоя, я переехал на свой домен bolknote.ru, где мой сайт обитает до сих пор. Недавно я перепечатал сюда часть своих бумажных дневников, начиная с 1989 года, и внизу, в подвале сайта у меня теперь в качестве старта сайта значится этот год.

Естественно моё присутствие в интернете началось не в 1989 году, но и до двухтысячного года что-то в интернет я писал. В частности, в 1999-м году опубликовал три статьи на «Цитфоруме» — «Хабре» того времени. В те времена это было очень круто, родители показывали бумажные распечатки своим знакомым.

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

Точные даты публикаций, к сожалению, неизвестны, но я восстановил примерные, ориентируясь на дату появления моих заметок на сайте «Веб-архива»:

Что нового в JavaScript версии 1.3 от Netscape
Найди картинку. Неизведанные возможности Web-дизайна
Блоки try… catch… finally… в JScript 5

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

Cookie в PHP 7.4

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

Выяснилось, что плюс появился сам собой, люди его и не думали ставить. Так я понял, что столкнулся с каким-то багом.

Сравнение значений HTTP-заголовков: в левом — "test=test+test%2Btest", в правом — "test=test%20test%2Btest", что демонстрирует разное кодирование пробелов и плюсов в URL.
Слева как куки ставились до ПХП 7.4, справа — как ставятся теперь, пробел кодировался как «+», «плюс» — как «%2B»

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

Проблема воспроизводится у тех комментаторов, которые оставили свой первый комментарий до того, как мой сайт перешёл на ПХП 7.4. В этой версии сменился способ кодирования пробела в «куках» (см. на скриншоте) — был +, стало %20.

В принципе, можно вернуть «статус-кво» следующим кодом:

if (strpos($_SERVER['HTTP_COOKIE'], '+') !== false) {
    parse_str(strtr($_SERVER['HTTP_COOKIE'], ['; ' => '&']), $_COOKIE);
}

Но хорошо бы внедрить в движок блога код, который будет перекодировать такие куки у пользователей.

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

FFI: баг не будет исправлен?

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

Очень не хочется это признавать, но похоже тот баг, который я обнаружил в реализации FFI (интерфейса к языку Си) в ПХП, исправлен не будет. Собственно, на это мне давно указал один из читателей в комментариях к прошлой заметке на эту тему, но мне всё не верилось.

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

Видимо, придётся жить с тем, что есть.

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

Но раз это навсегда, давайте избегать сторонние эффекты правильно. Тот же читатель предлагает более корректный способ:

Первый параметр memcpy должен быть указателем на отдельно выделенную память достаточного размера. И в FFI есть метод для выделения памяти: FFI::new. Его и надо использовать вместо str_repeat.

Таким образом правильная работа с указателями должна выглядеть примерно вот так:

function memcpy(?string &$dst, string $src):void
{
    $len = strlen($src);
    // изготавливаем тип, в котором уместится копируемая строка
    $type = FFI::arrayType(FFI::type('char'), [$len]);
    // выделяем место под изготовленный тип
    $destination = FFI::new($type);

    FFI::cdef('char *memcpy(char *dst, const char *src, size_t len);')
       ->memcpy($destination, $src, $len);
    // преобразуем область памяти в строку
    $dst = FFI::string($destination, $len);
}

$rock = "ROCK";
var_dump($rock); // «ROCK»
memcpy($rock, "SOCK");
var_dump($rock); // «SOCK»

Что тут происходит?

Мы хотим вызвать сишную функцию для копирования одной строки в другую. В месте, куда мы собираемся копировать, должно быть выделено достаточное количество памяти, мы её выделяем методом FFI::new, передавая ему на вход специально изготовленный тип — указатель на массив однобайтовых символов длиной c копируемую строку.

После копирования преобразуем область памяти в пхпешную строку. Память, выделенная при помощи FFI::new, освободится автоматически.

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

UnknownPlatformer

Скриншот окна программы «Unknown Platformer» с чёрным экраном и курсором мыши в центре.В одном из чатов по ПХП кинули файлом демку платформера, который использует для отрисовки OpenGL через FFI. Файл называется UnknownPlatformer.zip, это название я и вынес в заголовок.

В ней пока мало что есть — лес с эффектом параллакса, персонаж на первом плане, который управляется стрелками на клавиатуре, но всё это уже очень интересно.

Демка сделана на авторском микродвижке «Bic» (Because I Can), выглядит хорошо и я надеюсь на продолжение, к счастью автор забрасывать (пока?) его не намерен — следующим шагом собирается добавить камеру, нормальный viewport и внедрить паттерн «Entity component system». Движок мультиплатформенный, работает под всеми тремя основными операционными системами — «Виндоуз», «МакОС», «Линукс».

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

composer install
:; [[ $(uname) == "Darwin" ]] && brew install sdl2_image
php app.php

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

PHP 7.4 vs. PHP 8.0a

Резюме — в моём частном случае стало ощутимо быстрее, PHP 7.4 работал 63,9 секунд, 8.0a — 42,6.

Как многие знают, основной фишкой восьмой версии интерпретатора ПХП будет JIT. Обещают ускорение вычислительных задач, что немного не про веб, где в основном используется этот язык, но всё равно выглядит интересно.

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

Восьмой ПХП собрался на моём «Макбуке» следующей последовательностью команд:

PATH=/usr/local/Cellar/bison/3.5.3/bin/:$PATH ./buildconf
./configure --prefix=/opt/php-bin/ --without-iconv --disable-xml \
--without-libxml --disable-simplexml --disable-xmlwriter --disable-dom --disable-xmlreader
make -j4
make install

Версию 7.4 ставил через «брю», сборочную конфигурацию оставил как есть, ничего не менял.

После небольшой коррекции php.ini в информации об интерпретаторе появились OPcache и JIT:

Скриншот вывода phpinfo: Zend Engine v4.0.0-dev, Zend OPcache v8.0.0-dev; Opcache Up and Running, Optimization Enabled, SHM Cache Enabled, File Cache Disabled, JIT Enabled.
Скомпилированная версия PHP 8.0a со включенным JIT

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

Столбчатая диаграмма: PHP 7.4 — 72,3; PHP 7.4 + opcache — 63,9; PHP 8.0a — 60,8; PHP 8.0a + JIT — 42,6.
Сравнение PHP 7.4 и 8.0a, со включённым и выключенным opcache (меньше — лучше)

Каждую версию интерпретатора я тестировал со включенным и выключенным OPcache десять раз, а результаты усреднил. Как видите, JIT существенно ускорил выполнение программы в моём случае (там огромное количество циклов и ветвлений) — 63,9 секунды против 42,6.

Что интересно — PHP 8.a без OPcache обогнал версию 7.4 со включенным opcache, это примечательный результат— значит сам «голый» интерпретатор тоже оптимизируют.

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

Комментарии в Си

Из документации к языку Си на сайте «Микрософта», секция про комментарии, описывается нестандартное расширение спецификации:

Comments beginning with two forward slashes (//) are terminated by the next newline character that is not preceded by an escape character. […] the newline character is preceded by a backslash (\), creating an «escape sequence». This escape sequence causes the compiler to treat the next line as part of the previous line. (For more information, see Escape Sequences.)

The default for Microsoft C is that the Microsoft extensions are enabled. Use /Za to disable these extensions.

То есть в примере ниже, если его скомпилировать в «Визуал Студио», выражение i++; на самом деле будет частью комментарий и не выполнится:

// мой комментарий \
    i++;

Счастливой отладки!

Добавлено позднее: в компиляторе gcc тоже работает, причём раскрашивается как комментарий в редакторах vim и «Саблайм».

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

Юзерпики в «Эгее»

Во второй раз занимаюсь разовой конвертацией блогов в формат «Эгеи», надо бы записать кое-какие вещи, а то забывается. Авось придётся в третий, опять придётся разбираться.

В основном обращаться приходится к трём таблицам, имеющим довольно говорящие названия: Notes — сами заметки, Comments — комментарии к ним (там же хранятся и авторы комментариев, единого профиля у них нет) и Aliases — адреса, по которым доступны страницы (в моей схеме в этой таблице нет поля Alias, куда и записывается сам адрес).

Краткая схема БД «Эгея» 2.5: таблицы Notes, Aliases, Comments с полями и связями; форматы (raw, calliope, nearden), пути к иконкам и аватарам, условие IsGIPUsed.
Основные поля основных таблиц «Эгеи» версии 2.9

Назначения полей, в основном, понятны из названий, кроме разве что поля Stamp — это временная метка создания чего либо в секундах (timestamp) и поля с префиксом GIP, об этом чуть ниже.

Если вам интересны метки (теги), то понадобятся ещё две таблицы: Keywords — где хранится русское название метки и её урл и NotesKeywords, таблица, связывающая метки и заметки.

Теперь про GIP. Если флаг IsGIPUsed в таблице Comments установлен в ноль, то это прежняя схема хранения автора комментарий — без юзерпика, чтобы юзерпик появился, надо выставить IsGIPUsed в единицу, в поле GIP записать сервис, через который была проведена аутентификация (facebook, vk или twitter), а в GIPAuthorID записать некий идентификатор пользователя во внешнем сервисе.

Юзерпик нужно положить в pictures/avatar/ с именем, составленным из полей GIP и GIPAuthorID, записанных через дефисоминус. Например: vk-1.jpg — это был бы юзерпик Дурова, создателя «Вконтакте», если бы он зачем-то зашёл хоть на одну «Эгею».

Тут есть одна интересная деталь. Дело в том, что у меня в блоге, когда он ещё работал на самописном движке, уже были юзерпики, были они и у Олега Петровича, блог которого я переносил сегодня ночью. Причём и у меня, и у Олега авторизация была своя собственная, не обязательно через те сервисы, которые поддерживает «Эгея». Как же мне удалось перенести юзерпики?

«Эгея» в этом месте имеет простой механизм расширений — в принципе в неё несложно добавить любой внешний механизм аутентификации, что я и сделал. Подобрал в папке system/theme/images/, где движок ищет картинки внешних сервисов, подходящую картинку (email.svg) и написал фейковый плагин для сервиса email, который положил в файл system/gips/email.php:

<?php

class E2GIPEmail extends E2GIP {
  protected $type = 'email';

  private function _get_instance() {
    return (object) [];
  }

  public function get_auth_url() {
    return '';
  }

  public static function get_profile_url($id, $link) {
    return false;
  }

  public function callback() {
    return true;
  }
}

Файл плагина (и его тип) должны называться так же как и выбранная картинка — email и в базе его пользователи записываются с тем же значением поля GIP. В итоге, все свои старые комментарии я положил, как принадлежащие сервису email, а в качестве GIPAuthorID (это строка) взял хеш-сумму от сериализованной информации о пользователе.

Добавлено позднее: невероятно, но факт, оказалось, что GIP-плагины можно класть ещё и в users/gips/, что гораздо удобнее, так как в этой папке он не перетрётся при обновлении «Эгеи».

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

AppleScript Tetris ★

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

Недостатка в таких задачах у меня в голове не бывает, но руки приложить к ним получается нечасто. «Тетрис» на ЭплСкрипте — один из примеров такого «приложения рук», прошло три года, но он до сих пор мне так нравится, что я решил рассказать о нём ещё раз.Схематичное изображение: чёрные точки образуют прямоугольную рамку на светлом фоне, внутри — три точки, внизу справа — силуэты деревьев.

Для начала немного об ЭплСкрипте. Это скриптовый язык для автоматизации, который встроен в МакОС в незапамятные времена — в «Википедии» написано, что он появился аж в 1993 году, то есть широкоизвестный ПХП его младше аж на два года!

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

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

tell application "Microsoft Word" to quit
display dialog "Hello, world!"

print pages 1 thru 5 of document 2

Сильно популярным его не назовёшь, но в своей нише он хорош и продвинутые «маководы» о нём знают. До «Тетриса» я писал на нём «песню о пиве» и интерпретатор Брейфака.

За всё историю существования на ЭплСкрипте никто никогда не писал графических интерактивных игр. Причина проста: в языке нет поддержки графики и опроса клавиатуры. ?, расходимся!

Тем не менее идея создать на нём что-то подобное «Тетрису» мучала меня несколько лет, видимо интуиция жужжала где-то в фоне, что это возможно.

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

Четыре одинаковых элемента интерфейса с кнопкой «Helvetica» и иконкой шрифта, расположенные в два ряда по три и один.

Для этого, в припципе, всё есть — ЭплСкрипт умеет запускать программы и управлять размерами и расположением окон:

tell application "TextEdit"
    set the bounds of 1st window whose id is wid to {x, y, (x + |size|), (y + |size|)}
end

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

На снежном стекле нарисованы чёрными точками контур дома и несколько снежинок, на заднем плане видны ели.

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

В первом же прототипе появилась ещё одна проблема — наверху у «МакОСи» есть строка меню, приложения не могут на неё залезать, при попытке вывести в эти координаты окно, оно «сползает» вниз. В итоге первые несколько точек выводились в других координатах и всё рушилось. Было два решения — центрировать ещё и по вертикали или как-то измерить размер меню (кодировать его высоту константой мне показалось плохим решением — вдруг изменится).

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

-- Get height of menu bar
tell application "TextEdit"
	activate
	make new document at the front
	set the bounds of 1st window to {0, 0, 0, 0}
	set coords to bounds of 1st window
	close 1st window
end

set minimalY to coords's item 2

С графикой разобрались, а что с клавишами? В ЭплСкрипте, как я уже говорил, нет способов опросить клавиатуру, существуют плагины и сторонние решения, но их использование рушит всю идею. Хотелось чистого решения.

Голову пришлось ломать очень долго, пока в один момент я не додумался заиспользовать под это опрос значения громкости — уменьшение и увеличение громкости как кнопки влево/вправо, а отключение динамика — для поворота фигуры.

Панель управления медиаплеером с кнопками: закрыть, яркость, режимы отображения, перемотка, воспроизведение, громкость.
Сейчас на моём «Макбуке» аппаратных кнопок громкости уже нет, но «Тетрис» слушается и нарисованных на тачбаре

Для этого на пуске я устанавливаю громкость на середину и в цикле опрашиваю текущее значение. После каждого изменения значение опять сбрасывается на среднее:

on levelReset()
    set volume output volume volumeMiddle without muted
end

on checkDirection()
    set level to output volume of (get volume settings)
    levelReset()
    _sign(level - volumeMiddle)
end

on checkRotate()
    return output muted of (get volume settings)
end

Тут _sign — моя собственная функция взятия знака, у ЭплСкрипта нет встроенной.

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

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

Полный исходный код есть на гитхабе.

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

99 бутылок: V

71. V — один из языков, за развитием которых я пристально наблюдаю. Искренне желаю ему развития и процветания — под влиянием «Раста», «Гоу» и чего-то вроде Пе́рла, у авторов получается довольно интересный язык, который пока, правда, находится в стадии альфы.

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

Сильнее всего язык, кажется, похож на Гоу — есть даже синтаксически такой же оператор go, позволяющий запускать что-нибудь в отдельном потоке (позднее обещают сделать корутины), но и уши «Раста» торчат даже в моей небольшой программе: совпадение с образцом, условные операторы-конструкции, константные переменные (если не указан mut).

Есть обобщённое программирование (которого так не хватает в Гоу), интерполяция переменных в строках (привычная ребятам, программирующим на ПХП, Перле и шеллах) и ограниченная перегрузка операторов (как в Си++).

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

// 99.v by Evgeny Stepanischev Feb 2020

fn bottles(beer byte) string {
    return match beer {
        0 {
            'no bottles'
        }
        1 {
            '1 bottle'
        }
        else {
            '$beer bottles'
        }
    }
}

fn main() {
    mut b := bottles(99)

    for i := 98; i >= 0;  {
        println('$b of beer on the wall, $b of beer.')
        b = bottles(i--)
        println('Take one down and pass it around, $b of beer on the wall.\n')
    }

    println('No more bottles of beer on the wall, no more bottles of beer.')
    println('Go to the store and buy some more, 99 bottles of beer on the wall.')
}

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

← 1 17 18 19 20 21 67 →