программирование
«99 бутылок» на языке «Электроники МК-61»
59. Язык калькулятора Электроника
В детстве такие калькуляторы я видел только на картинках в журнале «Наука и жизнь», а программы для них были
Вчера мне в руки попал настоящая «Электроника
Так выглядят мои «99 бутылок…» на этом калькуляторе:
8112000 Х→П c 8 + ИНВ Х→П b Вх 10 ÷ [X] Х→П d 8 + ИНВ Х→П e В/О ПРГ
П→Х 0 1 0 ÷ [x] Х→П 1 Вх {x} 1 0 × Х→П 2
1 1 Х→П 8 1 2 Х→П 7 П→Х 2 ПП 34 Х→П a
1 4 Х→П 8 1 3 Х→П 7 П→Х 1 ПП 34 П→Х a
^ С/П
6 - /-/ x<0 45 9 + К П→Х 7 + ИНВ В/О
1 + К П→Х 7 + ИНВ К П→Х 8 ^ В/ОПоскольку у меня в блоге скорее всего отсутствуют любители работать каждый день с калькуляторами советских времён, то я не буду придерживаться принятой нотации с номерами — не думаю, что
Вкратце о языке. Больше всего это похоже на крайне примитивный ассемблер с гипертрофированным математическим сопроцессором. Всё то же — переходы на адрес, одно- и двухбайтные инструкции с операндами, регистры с определёнными назначениями, сильно ограниченная память (105 команд), наличествует косвенная адресация и подпрограммы (стек вызовов размером в пять вхождений).
До запуска программы нужно в регистр «0» поместить стартовое значение (например, «99», «Х→П», «0») и запустить программу «В/О», «С/П».
Это я сделал
Поэтому на вход подаётся нужное число, например, «42», а на выходе мы можем полюбоваться фразой «BEEr 42». Не весть что, но что вы хотели от калькулятора? Кстати, выводимая фраза — не строка (спойлер: а число), о том как мне пришлось помучаться я ещё расскажу.
Подпилил переподсоединялку вайфая
Чуть поменял «переподсоединялку вайфая» для Мака — теперь пингуется не 8.8.8.8 (это ДНС Гугла), а адрес гейта, что более надёжно. Правда с конца октября, когда я её написал много воды утекло — вайфай у меня отваливается теперь очень редко, уж не знаю что изменилось.
Дерево в цепочках

Я тут в блоге
В общем, там где мне совсем сильно жмёт, я пишу иногда небольшие скрипты. Недавно написал очередной и решил поделиться. Этот скрипт (написан на ПХП7) позволяет развернуть дерево в формате GEDCOM (это общепринятый формат для хранения информации о родословной) в цепочки — то есть простраивает все пути от указанного человека до каждого его предка.
Это позволяет быстро увидеть какие ветки у вас проработаны, а какие нет. Классическое дерево на моих объёмах это уже не показывает — его просто невозможно охватить взглядом и понять где есть проблема.
Для запуска требуются два параметра: нужно указать путь до файла дерева и идентификатор человека, от которого нужно простроить цепочки, его надо посмотреть внутри файла (GEDCOM текстовый формат). Для этого нужно найти внутри запись нужной персоны и выше неё — строку вида «0 @буквыцифры@ INDI», вот часть «@буквыцифры@» и будет требуемым идентификатором.
strtr vs. str_replace
Кроме того, часто выход
Среди подобных текстов есть и вредные. Речь об одном из них и пойдёт. Впервые на сравнение производительности функций str_replace и strtr (с одним параметром) я наткнулся очень много лет назад, тогда с ним разобрался и тему для себя закрыл.
Но такие исследования возникают постоянно, а авторы совершенно не утруждают себя ответом на вопрос «почему», так что я решил написать этот небольшой текст.
Итак, есть две функции, которые ведут себя очень похожим образом — заменяют в строке
Обратите внимание на этот код:
$r = ['xo' => 'xaxе', 'xa' => 'xo'];
$s = 'xoxo';
var_dump(str_replace(array_keys($r), array_values($r), $s)); // xoxеxoxе
var_dump(strtr($s, $r)); // xaxеxaxеОчевидно результаты разные, но почему? Потому что str_replace делает замену «в лоб» — проходя строку несколько раз, по числу заданных замен. Поэтому получается «xoxo» → «xaxexaxe» → «xoxexoxe».
Функция strtr куда более хитрая, но работает более… естественным что ли образом — т. е. так как обычно человек ждёт от функции множественной замены. Самое главное — в сделанной замене она уже ничего не заменяет.
Есть и другое отличие:
$r = ['user1' => 'one', 'user11' => 'eleven'];
$s = 'user11';
var_dump(str_replace(array_keys($r), array_values($r), $s)); // one1
var_dump(strtr($s, $r)); // elevenМой пример выглядит несколько искусственно, но это часть случая из жизни, правда очень упрощённого. Тут беда в том, что str_replace применяет свои замены слева направо — в порядке перечисления, тогда как strtr сначала сортирует их по длине.
Как видите, эти функции совершенно разные по своему действию и сравнивать по производительности их просто некорректно.
Void в PHP
ПХП7
Я сначала не понял зачем вводить в язык новое ключевое слово, можно было бы использовать для такого указания уже существующее ключевое слово null, но оказалось, что авторы под void имели ввиду, что функция не может вернуть никакого значения:
function returns_null(): void {
return null; // Fatal error: A void function must not return a value
}включая null, потому что это определённо значение, хоть и со специальным смыслом. При этом вот такое работает:
function returns_nothing(): void {
return; // valid
}Таким образом в языке произошло неявное изменение: раньше ситуации с пустым return и с return null не различались, сейчас они будут иметь разный смысл.
Отрицательное количество элементов (PHP)
Сегодня утром с разработчиками обсуждали фрагмент кода, где автор очень уж параноидально подошёл к проверке:
if (count($this->to) <= 0) {
$this->validation_errors[] = "Неверный отправитель";
}Проверять возвращает ли функция count значение меньшее нуля действительно странно, но я вдруг подумал — а можно ли в ПХП в припципе заставить эту функцию вернуть такое значение?
Дело в том, что функцию count можно использовать не только с примитивными типами (чаще всего её используют с массивами), но и с объектами, которые реализуют интерфейс Countable.
Оказалось вполне нормально работает:
$var = new class implements \Countable {
public function count()
{
return -1;
}
}
var_dump(count($var)); // выведет int(-1)Выше код написан в синтаксисе ПХП7, который выйдет сегодня, но его можно переписать и на «пятёрку» — надо только дать имя классу.
99 бутылок: Эллочка
58. Эллочка. Мне написал автор языка программирования «Эллочка» с предложением написать на нём «99 бутылок…», как вы знаете, у меня есть хобби — писать такие программы на разных языках.
Для этого языка есть единственный, авторский интерпретатор под ДОС (и очень важно использовать в файле программы символы перевода ДОС/Виндоуз, иначе ничего не будет работать), а сам язык напоминает странноватый Бейсик, без поддержки функций и процедур. Их можно эмулировать, используя трюк со специальной переменной «@», которая содержит номер текущей строки.
В языке есть ряд интересных возможностей, но их затмевают недостатки разного калибра, что характерно для языков без сообщества. Даже в таком простом примере мне пришлось побороться за работоспособность программы. Например, перед числами
!99 beer song by Evgeny Stepanischev
!Used variables: B, R, $1
B=99
@cycl
R=@+2
goto @beer
list ' of beer on the wall, '
R=@+2
goto @beer
list '.'\
list 'Take one down and pass around'\
decr B
R=@+2
goto @beer
list ' of beer on the wall.'\
list ''\
wait
clsc
esli B >> 0; @cycl
list 'No more bottles of beer on the wall, no more bottles of beer.'\
list 'Go to the store and buy some more, 99 bottles of beer on the wall.'
exit
@beer
esli B >> 0; +3\
list 'No bottles'
goto R
esli B == 1; +5\
$1=B
$1=%MID($1,2,10)
list $1+' bottles'
goto R
list '1 bottle'
goto RСложение массивов в PHP
Некоторые ребята не знают, что в ПХП есть операция «плюс» над массивами, а открыв её для себя случайным чтением инструкции по языку, не знают чем она отличается от array_merge. Между тем отличия разительные, если их не знать, легко наплодить ошибок в коде.
Операция сложения («плюс») с массивами работает проще всего: если в левом массиве уже есть значение с таким ключом, оно и остаётся:
["L"] + ["R"]; // будет ["L"]
["a" => "L"] + ["a" => "R", "b" => "R"]; // будет ["a" => "L", "b" => "R"]Операция слияния массивов (array_merge) работает
array_merge(["L"], ["R", 4 => "R"]); // ["L", "R", "R"], значения целых ключей правого массива потерялись, сам массив добавился в конец
array_merge(["a" => "L"], ["a" => "R"]); // ["a" => "R"], совпадение строковых ключей
array_merge(["L", "a" => "L"], ["R", "a" => "R", 4 => "R"]); // ["L", "a" => "R", "R", "R"], разные типы ключей вместеОперация «плюс» очень полезна для добавления группы ключей строковых со значениями (для объединения ассоциативных массивов):
$arr = ["key1" => "value1", "key2" => "value2"];
// вместо
$arr["key3"] = "value3";
$arr["key4"] = "value4";
// проще написать так:
$arr += ["key3" => "value3", "key4" => "value4"];Но на этом её применение не заканчивается, конечно.
99 бутылок: CMake
57. CMake. Писать «Песни про пиво» на различных языках программирования — давнее моё увлечение, ему столько же лет, сколько этому блогу. В этот раз «поёт»
CMake — автоматизированная система сборки пакетов, имеющая развитый, хотя и несколько уродливый макроязык. Инструкции, большей частью, знакомые, разве что способ возврата значений несколько из макросов и функций несколько странный — через параметры и глобальные переменные.
Никакого ООП, само собой, и всё весьма примитивно по меркам развитых языков.
# 99.cmake
# to run: cmake -P 99.cmake
# Written by Evgeny Stepanischev, 2015
cmake_minimum_required(VERSION 3.0)
macro(bottles beer ret)
if(${beer} EQUAL 0)
set(${ret} "No bottles")
elseif(${beer} EQUAL 1)
set(${ret} "1 bottle")
else()
set(${ret} "${${beer}} bottles")
endif()
endmacro()
foreach(beer RANGE 99 1 -1)
bottles(beer bottles)
math(EXPR beer "${beer}-1")
bottles(beer bottless)
message("${bottles} of beer on the wall, ${bottles}.")
message("Take one down and pass it around, ")
message("${bottless} of beer on the wall.")
message("")
endforeach()
message("No more bottles of beer on the wall, no more bottles of beer.")
message("Go to the store and buy some more, 99 bottles of beer on the wall.")Строка для запуска во второй строке файла.
Тег HYPE (Netscape HYPE tag sound)
Пятнадцать лет назад, ковыряя исходники браузера «Нетскейп», я наткнулся, в частности, на тег HYPE — в интернете того времени писали, что он воспроизводит
Сегодня за завтраком, по другому случаю наткнувшись на свою же статью об этом теге, я подумав, что
Но времена же изменились! Теперь у нас есть виртуализация, образы виртуальных машин и быстрый интернет!
Файл оказался в формате .snd, который нормально открылся и проигрался уже в современном «Маке». Его содержимое — фраза «What is global hypermedia?» (из документа NCSA Mosaic Demo 1993 года, как объясняется на одной из страниц в интернете).
Я сконвертировал его в обычный МП3 и, если ваш браузер достаточно современный, можете послушать как звучит тот самый секретный тег:
Кстати, жаль, что я не догадался проиграть его на оригинальном «Макинтоше» в музее Эпл, в Москве. Если представиться случай, обязательно попробую!
Переподсоединялка вайфая

Вышло очередное обноление «Эль Капитана» на «Маке», а проблема с вайфаем на «Макбуках Про» так никуда и не делась. Я планирую
В общем, сделал себе на «Баше» утилиту переподключающую вайфай при пропадании пингов до 8.8.8.8 (это ДНС «Гугла»). Сегодня уже целый день её использую, так гораздо комфортнее.
Блокировка экрана на «Маке» из Си
CGSCreateLoginSession(NULL);
// теперь выдаёт
// Assertion failed: (sid != NULL), function CGSCreateLoginSession, file Services/Connection/CGSSession.c, line 418.Возможно
В общем, покапался я в заголовочных файлах, подбором и интуицией родил код, который блокирует экран
// получаем словарик с атрибутами текущей сессии
CFDictionaryRef dict = CGSCopyCurrentSessionDictionary();
// выбираем из него идентификатор текущей сессии, получаем его в виде int
CFNumberRef number = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("kCGSSessionIDKey"));
CGSSessionID currentSession;
CFNumberGetValue(number, kCFNumberIntType, ¤tSession);
// блокируем текущую сессию
CGSCreateLoginSession(¤tSession);Обновлённая версия лежит там же — на «Гитхабе».
Где это я был?

Нацарапал утилитку на «Баше», которая помогает узнать к каким
Чудны́ дела твои, PHP
var_dump(array_pop(range(0,5)));
// Strict Standards: Only variables should be passed by reference in Command line code on line 1
// int(5)
var_dump(array_pop( (range(0,5)) ));
// int(5)В первом случае ПХП обращает наше внимание на то, что функция array_pop требует передачи значения по ссылке, что возможно только для переменной. Поскольку мы передаём результат работы функции, то логично, что ПХП в этом месте нам на это пеняет. Но если обернуть функцию в скобки, то интерпретатор уже всё устраивает.
Я не смотрел
65536
Если
Когда я начал заниматься историей, к этому всему добавились ещё числа. Пока у меня это только года. 1834 — второй год восьмой ревизии, 1850 — девятая ревизия и год, когда Бугульминский уезд перешёл из Оренбургской губернии в Самарскую и так далее.
Поэтому, увидев на часах 18:34, я улыбаюсь этому числу, как старому знакомому — я его за последние годы видел на тысячах, а то и десятках тысяч архивных листах. Номер 386 на авто так же привлекает моё внимание, так же как номер квартиры 256 (степень двойки). Для меня это очень особенные числа — события связаные с ними, как будто сами ложаться в память.
А в ваших профессии и хобби есть такие числа?
«Кремниевая долина»
Пока отхожу от операции, смотрю сериал «Кремниевая долина» и дабы не заржавел мозг, сделал расшифровку надписи на футболке Эрлиха — одного из героев сериала, на трёх языках: Перле, Пайтоне и Тикле. Листинг один для трёх языков:
#\
"@{[$\=qq{\n},\
print map {chr $_} (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110)]}";#\
__END__ = 1;\
print(''.join(chr(b) for b in (0b1000010, 0b1101001, 0b1110100, 0b1100011, 0b1101111, 0b1101001, 0b1101110))); #\
"""
foreach name {01000010 01101001 01110100 01100011 01101111 01101001 01101110} {
puts -nonewline [binary format B* $name]
}
puts {} ;#"""Дольше всего с Перлом возился, пока не вспомнил, что у него есть вычисление выражений внутри строк через конструкцию @{[…]}. Нужно рассказать как всё работает?
Политкорректный Unicode 8
Я всё ждал, когда это появится, и вот наконец в восьмом Юникоде обнаружились модификаторы цвета кожи. Модификаторов в Юникоде — пруд пруди, это специальные символы, которые сами по себе ничего не значат — они привносят

Вот восьмой Юникод вводит модификаторы цвета (на картинке выше), при комбинировании с которыми цветные «эмоджи», которые уже давно входят в Юникод, могут менять свой цвет:
Юникод всё усложняется и усложняется, чувствую, однажды они придут
Изучаю TCL
Учу «Тикль» потихонечку — вечерами, урывками. Язык нравится очень простым синтаксисом, который позволяет делать крутые штуки — всё в языке считается строкой, а вопросом интерпретации строки занимается код. Это даёт возможность, например, расширять язык по необходимости.
Попробую пояснить как это работает. В данном случае все три параметра, передаваемых команде puts эквивалентны:
puts Hello; # это строка
puts "Hello"; # это тоже строка
puts {Hello}; # и это строка!То есть фигурные скобки — это не «блок кода», а строка, правда со своими особыми правилами интерполяции. Это, вместе с конструкциями изменения уровня выполнения и позволяет создавать собственные дополнения к языку. Например, добавил в язык конструкцию unless (это такой if, только проверяется не истинность, а ложность условия):
proc unless {condition body} {
;# uplevel — конструкция, позволяющая выполнить блок выше по стеку
;# то есть, в данном случае, мы выполняем код в контектсе вызвавшего
;# процедуру unless кода, что позволяет увидеть все переменные, которые там определены
uplevel [list if !($condition) $body]
}
set var false
;# Это наша новая команда
unless { $var } {
puts "False: $var" ;# напечатает «False: false»
}
set var true
;# А это обычный if, которые есть в языке
if { $var } {
puts "True: $var" ;# напечатает «True: true»
}Надо бы, конечно,
Tcl/tk и Retina
О, оказывается, можно «ретинизировать» интерпретатор Тикля — сделать так, чтобы программы на этом языке хорошо смотрелись на маковской ретине (см. скриншот).

Для этого нужно скачать программу Retinizer и бросить в неё Wish.app, который находится в /System/Library/Frameworks/Tk.framework/Versions/Current/Resources/
Странный PHP
А вот ПХП, в отличие от ДжаваСкрипта действительно странный. Давайте посмотрим на такой вот код и его результат:
$ php -a
Interactive shell
php > $a = 1; echo $a + $a++;
3
php > $a = 1; echo $a + $a + $a++;
3Как видите, в том и другом случае у нас один результат — «3». Даже первая «тройка», казалось бы, противоречит здравому смыслу, а вторая — тем более. Что же происходит? Давайте разбираться.
Как работает первый пример?
Операция сложения левоассоциативна — разбор агрументов начинается слева направо. Двигаясь таким образом, парсер видит выражение в котором две операции — сложение и постинкремент, у постинкремента приоритет выше, поэтому вычисляется сначала он — возвращая в качестве значения «1» и увеличивая переменную на единицу, потом вычисляется операция сложения, складывая полученную единицу с двойкой (так как постинкремент увеличил значение переменной на единицу). Получается «три».
Похожим образом обрабатывается умножение вместе со сложением: 2 + 2 * 2 = 6, а не 8, потому что умножение имеет более высокий приоритет.
Во втором случае всё происходит похожим образом, но чуть иначе — парсер, обрабатывая левоассоциативное сложение, берёт первые два аргумента, складывает их, получает «двойку», двигается дальше, видит двойку, сложение и постинкремент переменной. Постинкремент более приоритетный, он его вычисляет раньше, возвращая в сложение «единицу», значение переменной увеличивается, но его уже никто не использует — складываются числа «2» (от предыдущего сложения) и «1» (вернул постинкремент). Получается «три».

Тут с восьмой строки начинается второй пример (правда присваивание единицы во втором примере я опустил — как видите второй операции ASSIGN нет).