917 заметок с тегом

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

Загрузка на «Спектруме»

Игра «Ливингстон, я полагаю?», созданная испанскими разработчиками в ноябре 1986 года, выпускалась и версия под ДОС

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

Мощи́ у компьютера хватало лишь на небольшое разрешение 256×192, пиксели были по современным меркам чудовищной величины и чтобы их ещё больше не растягивать, но сделать экран зрительно больше, создатели «Спектрума» сделали вокруг экрана специальную одноцветную область «бордюра» — используя 254-й порт ей можно было задавать один из небольшого набора цветов.

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

Так выглядел процесс загрузки стандартным загрузчиком

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

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

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

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

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

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

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

7 июня   speccy   программирование

Файл, состоящий из нулей

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

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

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

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

2 июня   rust   программирование

Копирование при записи и reset

Когда-то в ПХП жили без копирования при записи (copy-on-write). Думаю некоторые олдскульщики ещё помнят, как когда-то приходилось для экономии обмазывать всё ссылками. Копирование при записи очень облегчает жизнь, но настолько расслабляет, что всё реже задумываешься как всё работает под капотом.

Многие ли увидят тут проблему?

function array_first(array $array)
{
	return reset($array);
}

Проблема в том, что reset меняет внутреннее состояние массива, а значит вызывает копирование при записи — в этот момент массив будет удвоен. Это небольшая неприятность для небольших массивов, но если в нём миллион элементов…

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

Но в общем случае использование тут reset — плохая идея, на мой взгляд, лучше сделать так:

function array_first(array $array)
{
	return current(array_slice($array, 0, 1));
}

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

К слову, в ПХП 7.2 функция each объявлена устаревшей.

25 мая   php   программирование

99 бутылок: Rust

64. Rust — довольно известный язык, на слуху, очень интересный своими концепциями. Пока писал «песню о пиве», даже захотелось познакомиться с ним поближе.

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

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

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

Тип u8 — это тип «байт», match — конструкция проверяющая совпадение с образцом, мощная вещь, умеет сопоставлять что угодно — значения, типы, реализованные методы и так далее, mut — ключевое слово, указывающая, что переменную можно модифицировать, по-умолчанию они константны, println с восклицательным знаком — макрос, в языке очень хороший макроязык, с поддержкой рекурсии.

// Beer song. Evgeny Stepanischev, 2018
fn bottles(beer: u8) -> String {
    match beer {
    	0 => "no bottles".to_string(),
    	1 => "1 bottle".to_string(),
    	_ => format!("{} bottles", beer)
    }
}

fn main() {
	let mut beer = 99;
	while beer > 0 {
	    println!("{} of beer on the wall, {0} of beer.", bottles(beer));
	    beer -= 1;
	    println!("Take one down and pass it around, {} of beer on the wall.\n", bottles(beer));
	}

	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.");
}
22 мая   99   rust   программирование

Как сконвертировать bytea

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

Ограничусь фотографией на которой почти ничего не видно, дабы не эпатировать публику

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

def decodeBytea(bytes: bytearray, charset: str) -> str:
	if bytes[:2] == b'\\x':
		return bytearray.fromhex(bytes[2:].decode()).decode(charset)
	else:
		raise ValueError('Invalid format')

Формат немудрёный — впереди слеш-экс, дальше идут шестнадцатеричные коды байт, которые надо превратить в символы.

20 мая   postgres   python   программирование

Модуль PHP на Go

Потешную штуку показали на днях — php-go, позволяет писать модули для ПХП на Гоу. У меня как-то такой потребности не возникало, но попробовать-то интересно!

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

Ссылка давно протухла, но «Вебархив», к счастью, имеет копию страницы — статья называется «Ridiculous UTF-8 character counting».

Программа там на Си, я её минимально подпилил, чтобы она нормально компилировалась, завернул через cgo в Гоу, а оттуда при помощи php-go протащил как модуль ПХП.

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

Зато попробовал php-go, вещь предельно простая, в случае нужды можно будет что-то быстренько набросать с её использованием.

15 мая   php   программирование   язык гоу

Функция sleep и сигналы

Век живи, век учись. Вот уж не знал, что при получении сигнала программой на ПХП, моментально прерывается выполнение функции sleep (и родственных ей time_nanosleep и usleep):

$ php -r 'pcntl_signal(SIGUSR1, "_"); var_dump(sleep(PHP_INT_MAX));' &
[1] 3177
$ kill -USR1 3177
$ int(4294967288)

Вообще в Си так же, но где ПХП и где Си. Как и в Си, назад возвращается количество секунд, которые функция не «доспала» (time_nanosleep возвращает массив из секунд и наносекунд, а usleep — NULL). Правда под Виндой есть особенность — sleep при «недосыпе» всегда возвращает 192 (значение константы WAIT_IO_COMPLETION).

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

function bulletproof_sleep(int $seconds): bool
{
    $period = ['seconds' => $seconds, 'nanoseconds' => 0];

    while (array_sum($period) > 0) {
        $period = time_nanosleep($period['seconds'], $period['nanoseconds']);

        if (is_bool($period)) {
            return $period;
        }
    }

    return true;
}
14 мая   php   программирование

Как проверить не битая ли картинка

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

convert path_to_image null: 2>&- || echo File is corrupted

Если картинка path_to_image разрушена, то этот однострочник выведет «File is corrupted».

Утилита convert входит в состав пакета «Imagemagick» и достаточно распространена.

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

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

Конечно, картинка должна быть в формате, который утилита понимает, но всё хоть немного распростанённое туда входит.

7 мая   bash   программирование

RabbitMQ и место на диске

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

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

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

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

Heredoc и nowdoc в PHP

Не очень-то люблю использовать heredoc и nowdoc в ПХП из-за того, что они портят форматирование (а оно важно в больших проектах). Хотя вещь удобная — внутри можно использовать оба вида кавычек без экранирования, это бывает актуально в эскуэль-запросах.

В Перле давным-давно можно нормально смещать эту конструкцию вправо, она сама обрежет лишние пробелы, а теперь и в ПХП сделали то же — с версии 7.3 можно будет делать вот так:

$values = [<<<END
      a
     b
    c
    END];

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

26 апреля   php   php7   программирование
Ранее Ctrl + ↓