На работу

В комментариях к статье на Хабре о сравнении зарплат и стоимости жизни в Москве и других местах, народ начал писать о своих затратах на дорогу до работы. Я тоже прикинул:

5 минут до троллейбуса/автобуса + 0−10 минут на ожидание + 10−15 минут езды + 3−7 минут до рабочего места = 22−33 минуты — от 20 рублей,
или
3,5 км за рулём — 10−20 минут (рекорды — 5 и 40) — 15−20 рублей на бензин (зависит от стиля езды и состояния дороги) + другие расходные материалы + ремонт и техобслуживание + страховка и налог + амортизация = 50—100 рублей,
или
на такси — за то же время (и даже чуть быстрее — не надо искать место парковки) от 90 рублей, если верить Яндексу,
или
на велосипеде — 15−20 минут, но сейчас парковаться негде, а от забора его уже угоняли — бесплатно, если не считать ущерб от угона,
или
пешком — 30−50 минут.

Умножим на 20 рабочих дней в месяце и ещё на два (надо же и домой вернуться) — получится, что:

  • недостижимое на практике самое быстрое перемещение заняло бы 400 минут — 6⅔ часа, то есть, 6 часов 40 минут, и обошлось бы в 600 рублей по весьма оптимистичной оценке (да ну?), тыщи в две по более трезвой и в четыре — по самой грустной,
  • если считать расход исходя из полной стоимости владения автомобилем, то на такси — дешевле,
  • езда на общественном транспорте —  400−460 рублей и от 15 до 22 часов — 2−3 рабочих дня,
  • очень быстрая ходьба может оказаться более выигрышной даже по времени, чем езда на общественном транспорте, если сравнивать с непиковыми периодами, когда интервалы велики́.

P. S. Судя по статье, из российских городов-миллионников самый бедный с точки зрения IT-разработчика в 2019 году — это Челябинск: стоимость жизни у нас всего 58 % от столичной, но медианная зарплата — жалкие 42 %.

Симметричный шестиугольный блок

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

<style>
    .out, .in {
        display: inline-block;
        overflow: hidden;
    }
</style>
<body>
    <div class="out" style="transform: skew(α)">
        <div class="in" style="transform: skew(β)">
            <img src="picture.png" alt="Board" style="transform: skew(γ)">
        </div>
    </div>

где α, β и γ — углы, на которые проводится скос элементов.

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

Для углов α = 20° (20deg в CSS), β = −30°, γ = 40° и картинки, состоящей из квадратов результат будет таким:

Можно заметить, что для возвращения картинки к нормальному положению углы α и γ должны совпадать. Угол β больше, чем α, но не в два раза — меньше. Для того, чтобы углы картинки обрезались симметрично, надо, чтобы тангенсы углов α и β относились как 1 к −2.

Можно CSS-правило трансформации записать в виде матрицы, где указывается тангенс: transform: matrix(1, 0, тангенс, 1, 0, 0) — тогда вместо вычисления углов путём взятия арктангенса, который есть, например, в дополнительных пакетах к Sass, но не в нём самом (и уж тем более не в CSS), можно будет пользоваться простым умножением:

$tan: .5;

.out, .in {
    display: inline-block;
    overflow: hidden;
}

.out, .in img {
    transform: matrix(1, 0, $tan, 1, 0, 0);
}

.in {
    transform: matrix(1, 0, -2*$tan, 1, 0, 0);
}

Результат — группа из стоя́щих друг на друге квадратов режется по диагонали:

Для $tan: .577350269 (tg 30°) углы будут кратны тридцати градусам:

Треугольники

В обоих случаях Google Chrome режет неидеально: углы правильные, но некоторые линии разреза параллельно перенесены на несколько точек. Firefox рисует аналогично. Хотя если не заниматься пиксельхантингом рассматривать придирчиво каждую точку, результат выходит вполне приемлемым.

Дополнение/: если наружному элементу .out задать нулевую высоту строки line-height: 0, то линии разреза переноситься не будут ни в Хроме, ни в Файрфоксе — станет как надо.

Не бравурно

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

make
lilypond a4.ly
GNU LilyPond 2.18.2
Processing `a4.ly'
Parsing...
Interpreting music...
MIDI output to `part-bass.midi'...
Interpreting music...
MIDI output to `part-soprano1.midi'...
Interpreting music...
MIDI output to `part-soprano2.midi'...
Interpreting music...
MIDI output to `part-alto1.midi'...
Interpreting music...
MIDI output to `part-alto2.midi'...
Interpreting music...[8][16][24][32][40][48]
Preprocessing graphical objects...
warning: no glyph for character U+E062 in font `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
warning: no glyph for character U+E0A4 in font `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
warning: no glyph for character U+E0A4 in font `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
warning: no glyph for character U+E0A4 in font `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
warning: no glyph for character U+E0A4 in font `/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
warning: no glyph for character U+E050 in font 

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

Да и внешне результат далёк от желаемого:

Ноты с ошибками

Причина оказалось простой, но из лога совершенно невозможно понять в чём же дело — действительно, LilyPond не мог найти нужных символов, но шрифт DejaVu Sans тут ни при чём — символов не было, потому что используемый в этих нотах шрифт Bravura (хороший, кстати, шрифт — крут как тот, что в лилипонде по умолчанию, но при этом в нём скрипичный ключ не имеет лишних изгибов) отсутствовал в системе. Решается легко — копированием шрифтовых файлов в /usr/share/lilypond/ВЕРСИЯ/fonts/otf

Юбилейный пушкинский концерт «Мечты»

Концерт вокально-хоровой музыки, посвящённый 220-летию А. С. Пушкина и 10-летию академического женского хора «Мечта».
Челябинск, Дворец культуры железнодорожников, 10.11.2019.

В программе — стихотворения, романсы, хоровые произведения на стихи поэта.

Исполнители:
лауреаты международных конкурсов:
академический женский хор «Мечта»,
академический мужской хор
Русского культурного центра города Челябинска,

Солисты:
Надежда Ворониченко,
лауреаты международных конкурсов Дарья Денисова, Глеб Кораблёв, Артём Подалюк.

Художественный руководитель коллективов и дирижёр, педагог по вокалу, автор композиции и чтец —
Заслуженный работник культуры РСФСР
Владимир Шереметьев.

Концертмейстер — лауреат международных конкурсов Лариса Яновская.

Цветной Subversion

Git умеет «из коробки» раскрашивать то, что выводит в консоль, а Subversion — нет. Надоело руками каждый раз перенаправлять вывод svn diff в colordiff — написал простенькую раскрашивалку. Когда-то умела красить только вывод подкоманды status, теперь понимает blame (praise, annotate, ann), diff (di), help (?, h), status (stat, st) — и сами подкоманды, и их синонимы.

https://github.com/shoorick/svn-st-color

Тестирование PHP-приложений из Geany

Когда-то я настраивал запуск тестов перловых Mojolicious-приложений прямо из IDE Geany. Потом довелось попробовать микрофреймворк Slim для PHP — ну да, работает, хотя тесты там более многословные по сравнению с перловыми.

А теперь попробуем настроить Geany для запуска тестов в современных PHP-приложениях — например, для использующих уже упомянутый Slim. Для запуска тестов в PHP существует PHPUnit — это не единственный инструмент, хоть и весьма популярный. Настройки тестирования зависят от проекта — в каждом проекте они могут быть своими. В Geany 1.27 настройки вызываются через меню: Project → Properties → вкладка Build либо Build → Set Build Commands:

  1. Задаём имя команды, под которым она будет отображаться в меню — нажимаем на пустую кнопку в столбце Label (в моём примере это была вторая сверху кнопка, на которой теперь написано Test).
  2. Указываем в столбце Command путь к PHPUnit — он может лежать, например, в подкаталоге vendor/bin относительно корня приложения. В случае, если он лежит внутри проекта, базовый путь проекта можно записать как %p.
  3. В столбце Working directory указываем путь к корневой папке приложения.
  4. В строке Error regular expression указываем регулярное выражение для поиска ошибок:
    ^(.+):(\d+)$
    PHPUnit выводит в сообщении об ошибке разделённые двоеточием полный путь к файлу и номер строки с ошибкой. Если даблкликнуть^W дважды щёлкнуть по сообщению, можно быстро перейти к соответствующей строке, кроме того, все строки, вызвавшие ошибки тестирования, выделяются подчёркиванием красной волнистой линией.

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

Подсчёт числа DOM-элементов при тестировании через Test::Mojo

Модуль Test::Mojo позволяет проверить, нашлось ли нужное количество DOM-элементов:

$t = $t-&gt;element_count_is('div.foo[x=y]', 5);
$t = $t-&gt;element_count_is('html body div', 30, 'thirty elements');

Но так можно проверить лишь равенство ожидаемого и полученного, в то время как иногда нужны другие операции.

$t-&gt;get_ok("$ROOT/some.xml");
my @items = $t-&gt;tx-&gt;res-&gt;dom-&gt;find('rss channel item')-&gt;each;
ok scalar @items &gt; 42, 'More than 42 items in some.xml';

Майские концерты

Академический хор русского культурного центра города Челябинска в начале мая даст пару разных концертов в Челябинской области:

  • 5 мая, Челябинск, храм Сергия Радонежского (проспект Победы, 398, корпус 1) — пасхальная программа — русская и зарубежная духовная музыка.
  • 9 мая, Каслинский район, посёлок Вишневогорск — программа ко Дню Победы — советские военные песни и музыка современных композиторов.

В состав хора входят лауреат всероссийских и международных конкурсов Мужской хор русского культурного центра города Челябинска и женский хор «Мечта».
Художественный руководитель коллективов и дирижёр — Заслуженный работник культуры РСФСР Владимир Александрович Шереметьев,
хормейстер — Евгений Николаевич Недоспасов,
концертмейстер — лауреат международных конкурсов Наталья Сергеевна Важенина.