Небольшой персональный «блог» (публичный сетевой дневник). Тематика записей по плану включает в себя изложение обрывочных мыслей и идей по программированию, радиолюбительской практике, простой электронике, и вообще занимательной науке.
Материалы оформлены с применением языка разметки Markdown (а точнее говоря, его варианта,
commonmark, хотя раньше я успешно применял вариант, поддерживаемый конвертером
kramdown+GFM, в какой-то момент переставшим работать без видимых причин; потом пытался
использовать конвертер redcarpet, но тоже не очень удачно) и размещены на халяву
небезызвестном ресурсе GitHub с использованием статического генератора Jekyll в связке
с функциональностью непрерывной интеграции, предоставляемой [относительно новым] механизмом
GitHub Actions (для поддержки произвольных модулей расширения — плагинов —
Jekyll, в частности, плагинов поддержки -формул, по невнятным причинам
отключенных во встроенном в GitHub Pages и работающем в безопасном режиме Jekyll-генераторе).
(Статичность {или условная, «переходная» статичность, с учетом использования генерации на стороне сервера} может показаться пережитком девяностых годов, но это — вполне адекватное решение для небольшого блога; из ограничений такого подхода в первую очередь следует назвать невозможность организовать, e.g., полнотекстовый поиск и обратную связь посредством размещаемых читателями и публикуемых [полу]автоматически комментариев {эти ограничения имеют свои обходные пути решения с использованием сторонних сервисов и клиентских сценариев}. Если не нужны поиск {из-за малого размера блога} и комментарии {в силу необходимости их, возможно обременительной, [пре]модерации}, то и генерация страниц, например cgi-скриптом, при каждом запросе всё-равно будет излишеством.)
До этого я пытался использовать сторонние сервисы непрерывной интеграции (CI/CD) вроде Travis CI, Circle CI и некоторые другие, но для верстки статичного блога это кажется перебором (к тому же, web-интерфейсы Circle CI, и в особенности Travis CI, немного не дружат с используемыми мною web-обозревателями; с API для некоторых задач, типа создания новых проектов и привязки их к GitHub-репозиториям, пока не разобрался).
Впрочем, настроить GitHub Actions оказалось тоже не так просто (кажется, что скудная
документация и нестабильное контр-интуитивное поведение суть не случайности, но меры
— своеобразный фильтр — против наплыва пользователей при ограниченных ресурсах
самого GitHub’а :) ). Вначале я пробовал размещать исходные данные (т.е., в основном,
*.md
-файлы) в единственной на тот момент ветви master
, в которую же и помещались
сгенерированные файлы. Это решение выглядело неплохим, но на деле выяснилось, что
даже после успешной сборки блога, сервер срабатывает неадекватно и при посещении
ассоциированных web-адресов (в данном случае, http://circiter.github.io
и http://circiter.tk) выдаётся http-ошибка 404, причем поведение сервера
при указании тех или иных конкретных страниц менялось от опыта к опыту неким
несистематичным, непредсказуемым образом. Временно помогал трюк с клонированием
репозитория и отправкой пустого набора изменений (команда git commit
с ключем
--allow-empty
), но и это работало лишь изредка.
Положительные изменения произошли лишь после реорганизации хранилища путем перенесения
исходных данных в новую ветвь source
. Размещенные вне ветви master
конфигурационные файлы
(«workflows») механизма GitHub Actions оказались вполне работоспособными, заодно избавив от
необходимости применения дополнительных ухищрений, вроде удаления директории .github
перед
инициированной конфигурационным файлом GitHub Actions отправкой сгенерированных файлов в
ветвь master
(данный трюк был использован, — как позже выяснилось, зря, — во-избежание
возможных проблем с рекурсивным выполнением назначенных автоматических действий).
Но даже после этого, оставалась одна проблема с серверным хранением
актуальных версий отдаваемых пользователям-посетителям сайта/блога данных. Предположительно, серверное
кэширование приводило к невозможности некоторое время увидеть изменения в публикуемых
страницах даже после их успешной сборки. [Надёжный] способ обхода мне не известен, а может быть
пока и не существует (кроме вышеупомянутого хака с clone
/commit
/push
, — именно его-то я и
попытался применить на этом блоге, впрочем, безуспешно — автоматизировать выполнение этой
странной операции с помощью сценария оболочки, выполняющегося при сборке всего проекта
после операции git push origin source
мне не удалось, не исключено, что именно из-за
существования защиты от рекурсии в GitHub Actions). Впрочем, в какой-то момент, эта проблема исчезла
сама собой, без заметных причин…
Также, к репозиторию, хранящему данный блог, было подключено GitHub-приложение TeXify (но de-facto не было задействовано, в том числе по причине наличия на данный момент некоторых проблем в генерируемых данным приложением SVG-файлах) для поддержки формул в Markdown-файлах, просматриваемых в web-интерфейсе GitHub.
В качестве темы оформления сначала была выбрана тема Hacker, в некоторой степени из-за лицензии, но в основном просто из-за внешнего вида. Потом я применил в качестве шаблона другую готовую Jekyll-тему Hyde, так как Hacker с темным фоном мало совместима с печатью страниц на бумаге, в частности и в особенности при наличии на страницах формул (иначе бы их пришлось визуализировать дважды – с черным и с белым текстом) и тем-более диаграмм с цветными элементами на прозрачном фоне. Естественно, пришлось внести достаточно много мелких изменений в файлы темы оформления, в частности исправить поведение картинок (в исходных каскадных таблицах творилось нечто мало совместимое с внутристрочными картинками-формулами). (Для интересующихся всё-таки темой оформления Hacker, до-кучи приведу ссылку на производную тему hacker-blog.)
Так как я не использую чёткую привязку сообщений к датам, то я не стал использовать каталог
_posts
, а создал свой (_blog_posts
) и внес его в список коллекций в конфигурационном файле
_config.yml
. Но на поверхность всплыли проблемы совместимости механизма Jekyll-коллекций с
метками и категориями — если для обычных постов из папки _posts
свойства-поля (доступные
в ruby-плагинах и liquid-разметке) site.tags
и site.categories
заполняются всеми имеющимися,
соответственно метками и категориями автоматически, то при использовании коллекций эти свойства
оказались пусты, что привело к необходимости правки и адаптации известных решений по работе с метками
(типа liquid-кода или плагинов для отображения облака меток). В частности, для генерации облака меток
был применен, с некоторыми изменениями, плагин jekyll.tag-cloud.rb
, а для генерации страниц,
связанных с метками и перечисляющих соответствующие посты – достаточно простой кусок ruby-кода,
сохраненный в файл-плагин tags.rb
.
Плагин font-awesome.rb
, очевидно, не нуждается в комментариях. Хотя кроме этого набора значков
(«иконок») я применил (с помощью файла _sass/svg-icons.scss
из репозитория
jekyll-now)
набор
Free-Social-Icons.
В процессе наполнения дневника случайно обнаружил, что kramdown даже при включенной поддержке GFM
(варианта Markdown, использующегося на GitHub Pages по-умолчанию, а также при отображении
Markdown-файлов в web-интерфейсе для обзора репозиториев и связанных ресурсов, типа wiki, средства
информирования об ошибках, etc.) не считает web-ссылки, не окруженные угловыми «скобками» <...>
,
собственно ссылками, и не генерирует соответствующую разметку (т.е. не подсвечивает их). Однако,
и здесь сразу же нашелся маленький плагин (потребовавший минимальной модификации), решивший эту
проблему (kramdown_easy_link.rb
). Когда я перешёл к использованию redcarpet, а потом
commonmark, плагин перестал использоваться и был удален.
До сих пор сохраняются проблемы с [автоматической] расстановкой переносов в словах. Сейчас для
расстановки переносов служит небольшой самописный плагин hyphenate.rb
, являющийся обёрткой над
библиотекой Text::Hyphen. Возможно, стоит всё
оставить как есть, переносы всё-таки работают.
Для работы с метками и облаками меток используются плагины jekyll.tag-cloud.rb
и tags.rb
для
создания, соответственно, облака меток и связанных с метками страниц, содержащих списки ссылок
на сообщения с этими метками.
(В Gemfile
и _config.yml
также можно обраружить подключенными плагины jekyll-feed
,
jekyll-scholar
, jekyll-sitemap
, jekyll-titles-from-headings
,
jekyll_inline_highlight
, jekyll-toc
, jekyll-commonmark-ghpages
.)
Плагин jekyll-scholar
используется для верстки библиографических списков и внутритекстовых
ссылок на них (пока я только начинаю использовать этот плагин, постепенно адаптируя имеющиеся
блог-посты); этот плагин использует обычные *.bib
-файлы (для ) в качестве базы данных библиографических записей, но для описания стилей
оформления записей и ссылок используются не
*.bst
, а *.csl
-файлы. На данный момент почему-то
не верстаются гиперссылки в списке литературы, но опция bibliography_template
таки позволила
инъецировать необходимый html-код в обход стилевого файла, так что такое положение дел можно
считать приемлемым компромиссом.
Для нумерации объектов (теорем, рисунков, etc.) был написан [очень простой] плагин
numbered-labels.rb
; пока он не годится для нумерации формул, набранных в liquid-окружении {% raw %}
. При включении режима shared_context: true
в группе опций
simplemath:
в конфигурационном файле _config.yml
, можно попытаться пользоваться штатными
средствами ’а для автоматической нумерации формул; это рекомендуемый способ, но
он пока нестабилен (а по-умолчанию всё-равно отключен). N.B., плагин
numbered-labels.rb
обрабатывает исходный документ только один раз, повторный проход разбора не требуется, и, тем не
менее, ссылки могут указывать на объекты, определённые как выше, так и ниже по тексту (в
[ближайшем] будущем, возможно, будет добавлена поддержка гиперссылок для быстрого перехода
внутри документа).
Для визуального выделения блоков с утверждениями (лемм, теорем и т.д.) используется
«псевдоокружение» (на самом деле это пара liquid-тегов) {% sentence_begin %} ... {% sentence_end %}
. Содержимое этого псевдоокружения
просто оборачивается в html-тег <div>
с css-классом sentence-block
.
Кстати, хотя это и не относится к нумерации объектов, но раз уж зашла речь о плагинах,
определяющих новые теги, то стоит здесь упомянуть и об окружении {% abstract %} ... {% endabstract %}
, которое может быть использовано вместо
свойства abstract:
, указываемого в yaml-заголовке и содержащего аннотацию к сообщению
дневника. В отличии от yaml-свойства, окружение abstract
помещается прямо в markdown-сообщение
(практически в любом месте; можно в начале, сразу после yaml-заголовка) и позволяет при верстке
аннотации задействовать те же самые возможности, что и при верстке основного сообщения; в
частности, это позволяет включать формулы в аннотацию (формулы из yaml-заголовка, к сожалению,
не верстаются; в т.ч. пока не получается включать формулы в названия сообщений).
Для поддержки формул пришлось написать отдельный простой плагин (simplemath.rb
), производящий
верстку исходного кода формул с помощью полноценного -движка (из TeXLive) с
последующей конвертацией
*.dvi
-файлов либо сначала (с помощью dvips) в [encapsulated]
PostScript, а потом (с помощью ImageMagick convert
) в PNG, либо сразу из *.dvi
в *.png
с
помощью dvipng. Из-за проблем с отображением формул на схемах, нарисованных с помощью пакета
circuitikz, в настоящий момент, применены промежуточная верстка с помощью pdflatex
и
последующее преобразование из *.pdf
в *.png
(но тоже с помощью утилиты convert
). При этом
формулы предварительно оборачиваются в необходимый -код, который в случае
внутристрочных формул, среди прочего, содержит команды записи некоторых параметров формулы (а
именно её типографской «глубины» и высоты в пунктах) во внешний файл, содержимое которого,
вместе с сообщаемой командой
identify
(тоже от ImageMagick) фактической высотой изображения в
пикселях, используется для более корректного позиционирования готовых картинок на html-странице
(хотя до сих пор с такой коррекцией что-то не так – некоторые формулы отображаются слишком
низко относительно базовой линии окружающего текста).
Реализован (но пока тестируется) режим верстки формул в общем контексте – если параметр
shared_context
равен false
, то каждая формула оборачивается в отдельный .tex
-файл, но при
включении режима shared_context: true
, все формулы одного .md
-файла собираются в единый файл
.tex
. Это, правда, влечёт за собой некоторые нежелательные побочные эффекты (по крайней мере
сейчас), вроде недоступности кэширования уже сверстанных формул или необходимость в дву- и даже
трёхпроходной обработке исходного текста, но зато позволяет обращаться с формулами в
markdown-файле так же как и с формулами в обычном документе , в частности, как
уже было замечено выше, нумеровать их автоматически. Особых преимуществ режим
shared_context: true
не имеет: например, для разрешения ссылок требуется запускать -движок
дважды или трижды, в то время как для режима
shared_context: false
достаточно одного прохода
(но зато аж для всех формул… территория компромиссов указывает на оптимальность решения,
иногда :) ).
Осталось заметить, что пока, по техническим причинам, \def
-макроопределения, сделанные в одном
-блоке, например в формуле, не видны в другом, поэтому рекомендуется, при
необходимости, использовать команду
\gdef
.
Режим fisher_rule: true
нумерует все выключенные (т.е. не являющиеся внутристрочными) формулы
(имеет смысл только если shared_context: true
и simple_numbering: true
). Этот режим (правило
Фишера) позволяет сэкономить на одном лишнем проходе верстки, а также упростить указание на
формулы в вашем тексте другими людьми (или другими [разумными] агентами :) ) даже если вы сами
на эти формулы не ссылались. (Я пока не тестировал этот режим и не знаю, работает ли он.)
И хотя опытный драматург уже смог бы на основе предыдущего раздела написать сценарий к фильму
ужасов, тем не менее это не конец истории. Ведь описанный конвейер работает в Docker-контейнере!
Т.е., инструкции из workflows-файла частично выполняются на ubuntu linux, клонируется
репозиторий, затем скачивается и инициализируется Docker-контейнер на основе Alpine linux, уже в
нем выполняется скрипт build.sh
, скачивающий и устанавливающий немало вещей, включая
относительно тежеловесные ruby, bundler, jekyll, bash, git, imagemagick и т.д. После этого
происходит сборка блога, верстка и конвертация всех формул, с последующей отправкой всех
сгенерированных файлов в ветвь master
репозитория этого блога.
Готовый Docker-контейнер, включающий именно нужную комбинацию ПО, найти не удалось; и хотя правильнее
было бы сделать новый контейнер, я пока обошёлся таким способом (вначале просто не предполагая, как
далеко всё зайдет). Теперь для оптимизации всего этого определенно требуется хотя-бы настроить
кэширование (естественным коррелятом эффективности которого может быть время сборки блога, измеренное
от момента отправки исходных данных в ветвь source
до появления ожидаемых изменений на главной
странице)…
Предполагаемые процессорные и сетевые затраты выглядят несоразмерными с решаемой задачей, но ведь многие интернет-ресурсы, включая некоторые крупные форумы, давно используют верстаемые на стороне сервера формулы, и не исключено, что с меньшими накладными расходами; эта возможность должна стать практически общепринятой. (К сожалению, по-факту, очень часто, слишком часто приходится сталкиваться с клиентским рендерингом на основе какого-нибудь MathJax’а.)
Трудно не согласиться, что описанный конвейер выглядит избыточным,
но более простые решения вроде mimeTeX оказались слишком ограниченными.
Впрочем, можно ещё попробовать встроенный в GitHub, но плохо документированный API-механизм
(http://render.githubusercontent.com/render/math?math=<url_encoded_formula>
)
рендеринга формул. Странно, что эта возможность за все время своего существования не стала
стандартным способом отображения формул. (Возможно, я бы и сам воспользовался именно этим способом,
если бы была возможность извлечь базовую линию, т.е. глубину, из продуцируемых изображений.)
Существует конечно и Google Chart, неплохо документированное средство визуализации диаграмм, графиков и формул; а также много других похожих русурсов. Но все с теми же недостатками и без эффективной интеграции с GitHub.
Даже для работающего в kramdown (реализации markdown, ранее использовавшейся в моем дневнике, но впоследствии заменённой на commonmark) MathJax-плагина есть компромиссное решение с предкомпиляцией формул (результат, впрочем, опять неудовлетворителен – клиентские JavaScript-сценарии не нужны, но требуются css-стили и подгружаемые шрифты, а сверстанные формулы являются кусками текста, а не изображениями).
Для полноты картины стоит упомянуть, что уже по своему определению, размещение статичного
блога не обязательно требует выполнения кода на стороне сервера и генерация может осуществляться
на машине публикующего. В этом случае я лично не вижу особых причин в использовании Jekyll+ruby,
— мне бы хватило и какого-нибудь bashblog’a,
модифицированного для поддержки формул, или конверторов типа htlatex
или pandoc+GladTeX, позволяющих
конвертировать -исходники (
*.tex
) в *.html
-файлы.
Интересной представляется идея использования упомянутых генераторов/конвертеров (bashblog, pandoc+GladTeX) и на стороне сервера, в комбинации с GitHub Actions. Особых преимуществ перед Jekyll, конечно, нет; разве что bashblog будет заведомо менее громоздким решением чем Jekyll.
Но GitHub предоставляет уникальную возможность, или, по крайней мере, более или менее удачно реализует довольно уникальную идею поддержки Jekyll для сопровождения git-репозиториев. Вполне закономерно, что этой комбинацией возможностей, и в особенности после внедрения GitHub Actions, многие стремятся воспользоваться. Разработчики GitHub уже проводили небольшой опрос среди пользователей, предлагая заполнить анкету с указаниев потенциальных проблем механизма Actions. Я, отвечая на вопросы анкеты (в количестве двух штук, если не считать дополнительное поле для жалоб и предложений в свободной форме), указал на недостаточность документации и некоторые сложности с отладкой кода, работающего в рамках этого механизма (референсным «идеалом» для меня вообще является банальный ssh-протокол); интересно было бы узнать общую статистику по результатам этого опроса…
С целью предъявления читателю относительно счастливой концовки, спешу упомянуть, что блог всё-таки заработал, с примерно сотого «commit»’а.