На волне желания выгружать мозг, про которое я писал давеча, я таки сподобился завести Wiki.
Взял Gitit, запаковал в Docker, развернул на Dokku, который у меня уже давно вертится в дроплете на DigitalOcean. Так как хранить данные сразу было решено в Git, а именно — в GitHub, то пришлось научиться
- заводить в GitHub ключи для деплоя,
- пробрасывать эти ключи в Docker-образ,
- импортировать ключи и вообще работать с SSH из контейнера — добавлять сайт в known_hosts, и всё такое прочее.
Репозиторий пока синхронизируется только в одну сторону — push после каждого изменения. Как делать pull, я пока ещё не определился. Может git-sync возьму.
Но в итоге я доволен тем, что в итоге всё получилось. Теперь Wiki живёт тут: wiki.recursive.one. Да, лого и favicon навекторил тоже я сам, не удивляйтесь ;)
Ведём вики мы вдвоём с товарищем. Планируем использовать как базу знаний, но может я и цифрофой сад посажу там же — посмотрим. И обратные ссылки я тоже реализую, как только придумаю как.
Взял Gitit, запаковал в Docker, развернул на Dokku, который у меня уже давно вертится в дроплете на DigitalOcean. Так как хранить данные сразу было решено в Git, а именно — в GitHub, то пришлось научиться
- заводить в GitHub ключи для деплоя,
- пробрасывать эти ключи в Docker-образ,
- импортировать ключи и вообще работать с SSH из контейнера — добавлять сайт в known_hosts, и всё такое прочее.
Репозиторий пока синхронизируется только в одну сторону — push после каждого изменения. Как делать pull, я пока ещё не определился. Может git-sync возьму.
Но в итоге я доволен тем, что в итоге всё получилось. Теперь Wiki живёт тут: wiki.recursive.one. Да, лого и favicon навекторил тоже я сам, не удивляйтесь ;)
Ведём вики мы вдвоём с товарищем. Планируем использовать как базу знаний, но может я и цифрофой сад посажу там же — посмотрим. И обратные ссылки я тоже реализую, как только придумаю как.
Да, я знаю про опечатку.
Но поправить не смогу без потери прикреплённой картинки: при редактировании сообщения Telegram заменяет прикреп на превью первой же ссылки из текста. Если закрыть превью, то не будет прикреплено ничего. Вот такой вот UX...
Ну да ладно, я привык.
Но поправить не смогу без потери прикреплённой картинки: при редактировании сообщения Telegram заменяет прикреп на превью первой же ссылки из текста. Если закрыть превью, то не будет прикреплено ничего. Вот такой вот UX...
Ну да ладно, я привык.
Не могу не поделиться, отличная картинка и прям про меня!
Я как раз нахожусь в правом нижнем углу: вместо того, чтобы писать регулярно, используя единожды настроенное окружение, я раз за разом настраиваю новое — мне просто больше нравится процесс создания этого самого окружения, чем его последующее использование
Когда-то, году эдак в 2012 я поднял свой первый блог на Pelican. Сразу статический сайт, раздаваемый с GitHub pages, комментарии на базе disqus (тогда это было не стыдно делать). Начал писать статьи, выдал штук десять, причём длинных — пяток от силы. В основном же писал про то, как я где-то там выступил, и прикреплял слайды — просто чтобы не размещать их где-то отдельно.
Потом Pelican мне поднадоел, да и #haskell хотелось уже применить в бою. Перевёл блог на Hakyll, благо Markdown в качестве исходников был. Комментарии — с десяток за всё время — смигрировал, это тоже было не скучно: выгрузить в CSV, прогнать скриптом, загрузить обратно (Disqus тут соломки подстелил). В этот новый блог писал всякую мелочь, но зато поигрался со входными форматами: и в Org mode статейки были, и на Literate Haskell — и это тоже "процесс важнее результата".
Сейчас пишу сюда. И тут отсутствие возможности что-либо настраивать и менять движок пока останавливает от новых переездов :) Впрочем, контент можно выгрузить да и исходник всё равно храню в .org-файле. А комментарии я не прикручиваю принципиально — те, кому хочется что-то сказать, пишут в личку (редко, но метко!).
Помимо блог(а|ов) делал себе сайтики, несколько штук уже. И все — разными способами (ага, опять):
- astynax.me генерируется самодельным генератором на Haskell, и это вообще квинтэссенция поднятой сегодня темы — контента нет совсем, зато движок делать понравилось :)
- recursive.one генерируется с помощью Pollen, про это я писал ранее. Тут я тоже поигрался и с движком, и с Dokku (тоже см. выше). Контента опять нет, удовольствие от процесса получено
- tilde.town/~astynax генерируется не с помощью Pollen, но с помощью x-exps, его я тоже упоминал
- astynax.neocities.org вообще вручную свёрстан, ибо сама площадка обязывает
Теперь вот ещё и wiki завёл, пишу туда, нравится (в дурку пока не забрали©). А ведь тоже радовался процессу выбора инструмента, разворачиванию, написанию про разворачивание — всё как на картинке!
Я как раз нахожусь в правом нижнем углу: вместо того, чтобы писать регулярно, используя единожды настроенное окружение, я раз за разом настраиваю новое — мне просто больше нравится процесс создания этого самого окружения, чем его последующее использование
:)Когда-то, году эдак в 2012 я поднял свой первый блог на Pelican. Сразу статический сайт, раздаваемый с GitHub pages, комментарии на базе disqus (тогда это было не стыдно делать). Начал писать статьи, выдал штук десять, причём длинных — пяток от силы. В основном же писал про то, как я где-то там выступил, и прикреплял слайды — просто чтобы не размещать их где-то отдельно.
Потом Pelican мне поднадоел, да и #haskell хотелось уже применить в бою. Перевёл блог на Hakyll, благо Markdown в качестве исходников был. Комментарии — с десяток за всё время — смигрировал, это тоже было не скучно: выгрузить в CSV, прогнать скриптом, загрузить обратно (Disqus тут соломки подстелил). В этот новый блог писал всякую мелочь, но зато поигрался со входными форматами: и в Org mode статейки были, и на Literate Haskell — и это тоже "процесс важнее результата".
Сейчас пишу сюда. И тут отсутствие возможности что-либо настраивать и менять движок пока останавливает от новых переездов :) Впрочем, контент можно выгрузить да и исходник всё равно храню в .org-файле. А комментарии я не прикручиваю принципиально — те, кому хочется что-то сказать, пишут в личку (редко, но метко!).
Помимо блог(а|ов) делал себе сайтики, несколько штук уже. И все — разными способами (ага, опять):
- astynax.me генерируется самодельным генератором на Haskell, и это вообще квинтэссенция поднятой сегодня темы — контента нет совсем, зато движок делать понравилось :)
- recursive.one генерируется с помощью Pollen, про это я писал ранее. Тут я тоже поигрался и с движком, и с Dokku (тоже см. выше). Контента опять нет, удовольствие от процесса получено
- tilde.town/~astynax генерируется не с помощью Pollen, но с помощью x-exps, его я тоже упоминал
- astynax.neocities.org вообще вручную свёрстан, ибо сама площадка обязывает
:)Теперь вот ещё и wiki завёл, пишу туда, нравится (в дурку пока не забрали©). А ведь тоже радовался процессу выбора инструмента, разворачиванию, написанию про разворачивание — всё как на картинке!
:^DЗанялся добавлением контента по #racket на CodeBasics.
Поскольку курс преподносится как "крогозорорасширяющий", то можно дать себе волю и придумывать нескучные задачки (ха-ха!) или просто не разжёвывать материал настолько мелко, как это делается в новичковых курсах.
Сейчас пишу про списки, параллельно сижу в Racket Repl, выбираю, про что и как рассказывать. И мне положительно нравится рэкетова система контрактов тот факт, что оная прикручена к стандартной библиотеке. Насколько приятно видеть такую ошибку — не передать!
Это тоже проверка предусловий, но тут ещё и сообщение сделано вручную, с ориентацией на новичков. Вот что значит — учебный язык!
Система контрактов в Racket довольно таки развесистая. Можно даже делать контракты, согласно которым в функции ветвление будет организовано — можно почти pattern matching делать и multi clause функции!
Да, это "не настоящие типы" и проверки будут производиться во время исполнения. Но TypedRacket может использовать некоторые контракты при выводе типов, если я правильно помню. В любом случае, это интересная особенность языка, а я такие штуки люблю!
Поскольку курс преподносится как "крогозорорасширяющий", то можно дать себе волю и придумывать нескучные задачки (ха-ха!) или просто не разжёвывать материал настолько мелко, как это делается в новичковых курсах.
Сейчас пишу про списки, параллельно сижу в Racket Repl, выбираю, про что и как рассказывать. И мне положительно нравится рэкетова система контрактов тот факт, что оная прикручена к стандартной библиотеке. Насколько приятно видеть такую ошибку — не передать!
> (first (cons 1 2))
; first: contract violation
; expected: (and/c list? (not/c empty?))
; given: '(1 . 2)
(and/c list? (not/c empty?)) означает "список И НЕ пустой" — максимально понятно, даже не нужно словами описывать дополнительно! Но кое где и словами описано: вот, например, вызов map с неравными по длине списками:> (map + '(1 2 3) '(10 20))
; map: all lists must have same size
; first list length: 3
; other list length: 2
Это тоже проверка предусловий, но тут ещё и сообщение сделано вручную, с ориентацией на новичков. Вот что значит — учебный язык!
Система контрактов в Racket довольно таки развесистая. Можно даже делать контракты, согласно которым в функции ветвление будет организовано — можно почти pattern matching делать и multi clause функции!
Да, это "не настоящие типы" и проверки будут производиться во время исполнения. Но TypedRacket может использовать некоторые контракты при выводе типов, если я правильно помню. В любом случае, это интересная особенность языка, а я такие штуки люблю!
Накидал на днях прототип ещё одной реализации моего давнего проекта PixCell, все ипостаси которого реализуют простой редактор Pixel Art в виде Web-приложения.
Изначально концепция была такая: сделать такое приложение, которое будет всё состояние хранить в адресе страницы, без cookies, без local storage, без какого-либо состояния на сервере. Закладки в браузере вместо сохранения результатов работы, история браузера вместо Undo/Redo — как вам такое? На мой взгляд, весьма забавно!
Так как я не особенно люблю и умею во внутрибраузерные технологии, а также забавы ради, делал я предыдущие реализации исключительно на серверной шаблонизации: каждый клик по пикселю, смена цвета или инструмента просто заставляли перезагружать страницу — старая школа, Web 1.0. И верстал на таблицах всегда, конечно же — для аутентичности!
А тут решил таки сделать такую версию, которая была бы представлена самодостаточной HTML-страницей (один файл без ресурсов), которую можно было бы сохранить локально и использовать без подключения к Сети. Поэтому делать решил на #elm. Так как планировал пользоваться сам, в том числе и на планшете, то задумал сделать всё на SVG, чтобы масштабировалось произвольно.
Текущую версию можно пощупать тут: https://astynax.me/pixcell-elm
Пока не реализовано сохранение результата, планирую сделать выгрузку в PNG и SVG. Возможно, добавлю возможность делиться результатом через сохранение состояния в URL и загрузки из оного при открытии страницы. А ещё подумываю заменить Unicode-символы на кнопках инструментов на нормальные пиктограммы — может даже в PixCell и нарисую ;)
Вот такой вот проектик выходного дня: большую часть за один день накидал, и то возился в основном с генерацией SVG руками без обёрток.
Изначально концепция была такая: сделать такое приложение, которое будет всё состояние хранить в адресе страницы, без cookies, без local storage, без какого-либо состояния на сервере. Закладки в браузере вместо сохранения результатов работы, история браузера вместо Undo/Redo — как вам такое? На мой взгляд, весьма забавно!
Так как я не особенно люблю и умею во внутрибраузерные технологии, а также забавы ради, делал я предыдущие реализации исключительно на серверной шаблонизации: каждый клик по пикселю, смена цвета или инструмента просто заставляли перезагружать страницу — старая школа, Web 1.0. И верстал на таблицах всегда, конечно же — для аутентичности!
А тут решил таки сделать такую версию, которая была бы представлена самодостаточной HTML-страницей (один файл без ресурсов), которую можно было бы сохранить локально и использовать без подключения к Сети. Поэтому делать решил на #elm. Так как планировал пользоваться сам, в том числе и на планшете, то задумал сделать всё на SVG, чтобы масштабировалось произвольно.
Текущую версию можно пощупать тут: https://astynax.me/pixcell-elm
Пока не реализовано сохранение результата, планирую сделать выгрузку в PNG и SVG. Возможно, добавлю возможность делиться результатом через сохранение состояния в URL и загрузки из оного при открытии страницы. А ещё подумываю заменить Unicode-символы на кнопках инструментов на нормальные пиктограммы — может даже в PixCell и нарисую ;)
Вот такой вот проектик выходного дня: большую часть за один день накидал, и то возился в основном с генерацией SVG руками без обёрток.
По просьбе читателей даю ссылку на код приложения из предыдущей записи:
https://github.com/astynax/pixcell-elm
Код я не причёсывал, многое сделано "лишь бы работало" библиотеки применял только там, где самому делать было не интересно или сложно.
А вот одна из предыдущих инкарнаций проекта (не помню, писал ли я тут про неё): pixcell-clj.recursive.one — эта как раз всё в URL хранит, так что не шибко быстрая
https://github.com/astynax/pixcell-elm
Код я не причёсывал, многое сделано "лишь бы работало" библиотеки применял только там, где самому делать было не интересно или сложно.
А вот одна из предыдущих инкарнаций проекта (не помню, писал ли я тут про неё): pixcell-clj.recursive.one — эта как раз всё в URL хранит, так что не шибко быстрая
:P "clj" в имени намекает, на чём эта реализация написана ;)Промежуточный отчёт о прогрессе работы над PixCell/Elm.
Сейчас:
- Реализованы все инструменты, которые я обычно делал в других версиях
- Имеется выгрузка в PNG,
- Перерисованы все пиктограммы для кнопок с использованием самого редактора (выгрузил в PNG, закодировал в Base64, положил в константы, подставляю в SVG в процессе рисования GUI)
- GUI мастшабируется под размер экрана (ага, PNG мылятся, oldschool!), опробован на iPad — работает пристойно
Хотелки:
- Сохранение текущего состояния в URL, чтобы можно было "в закладку положить"
- Выпадающие меню для инструментов на манер docks у NeXTSTEP
- Сохранение результатов работы в Local Storage
Варианты путей для эволюции:
- Анимации на базе сохранённых в Local Storage "кадров" (уж больно не хочется делать управление задержкой между кадрами...)
- Большой коллаж из "тайлов" в Local Storage. Тут вам и некое подобие "знакомест" с фиксированными палитрами на тайл, и, опять же потенциально, редактор карт из тайлов. Можно даже PETSCII Art замутить, предварительно нарисовав все нужные символы, даже палитра для Commodore 64 уже есть (вторая из трёх, помимо EGA (первой) и Apple II (третьей)).
Вчера максимально быстро и лениво накидал галереею примеров того, что можно в редакторе нарисовать. Буду пополнять.
Сейчас:
- Реализованы все инструменты, которые я обычно делал в других версиях
- Имеется выгрузка в PNG,
- Перерисованы все пиктограммы для кнопок с использованием самого редактора (выгрузил в PNG, закодировал в Base64, положил в константы, подставляю в SVG в процессе рисования GUI)
- GUI мастшабируется под размер экрана (ага, PNG мылятся, oldschool!), опробован на iPad — работает пристойно
Хотелки:
- Сохранение текущего состояния в URL, чтобы можно было "в закладку положить"
- Выпадающие меню для инструментов на манер docks у NeXTSTEP
- Сохранение результатов работы в Local Storage
Варианты путей для эволюции:
- Анимации на базе сохранённых в Local Storage "кадров" (уж больно не хочется делать управление задержкой между кадрами...)
- Большой коллаж из "тайлов" в Local Storage. Тут вам и некое подобие "знакомест" с фиксированными палитрами на тайл, и, опять же потенциально, редактор карт из тайлов. Можно даже PETSCII Art замутить, предварительно нарисовав все нужные символы, даже палитра для Commodore 64 уже есть (вторая из трёх, помимо EGA (первой) и Apple II (третьей)).
Вчера максимально быстро и лениво накидал галереею примеров того, что можно в редакторе нарисовать. Буду пополнять.
В этом году опять не нашёл времени добить AdventOfCode, однако 46 звёздочек из 50 считаю неплохим результатом. Если что, AoC, это такой марафон по решению задачек с помощью кода. Я про него уже писал.
Решал я задачки на #Haskell, как водится. Довольствовался "просто нормальными решениями", которые было приятно реализовывать без необходимости погружаться в оптимизации. Итоги: удовольствие получено, нервов затрачено немного, руки размяты.
А вот общее впечатление от задачек в этого года, увы, смешанное. Возможно, дело в том, что это AoC'2019 был очень хорош, а нынешний просто получился "как раньше": с задачками на вида "пишите уже процедурщину, иначе не дождётесь окончания вычисления" (это могу терпеть) и "вспомнил известный алгоритм — решил, не вспомнил — не решил" (вот такое не люблю!). А ещё в этом году были самоповторы: три вариации конвеевской "Жизни" с незначительными отличиями, это не то, чего ждёшь от авторов. Возможно, год выдался тяжёлым и для них…
Так или иначе, advent calendars — это здорово! Подкину таковых на разные темы:
- "Advent of Haskell 2020" — познавательно-развлекательные статейки о #Haskell
- "Kotlin Christmas" — то же самое, но про #Kotlin
- "QEMU Advent Calendar 2020" — традиционный уже календарь всякого забавного, что можно запустить в QEMU (про этот календарь я тоже писал); день №12, например, это всё та же "Жизнь", но в виде самозагружаемой (без ОС!) программы на #Rust
Из прошлогодних могу упомянуть "‘A Language a Day’ — Advent Calendar 2019": 25 разных языков программирования по одному на день со ссылками на документацию и примерами кода.
Наконец, возвращаясь к AoC, отмечу, что в этих наших интернетах множество людей делится своими решениями в виде статей и прочих стримов. Вот, например, репозиторий со ссылками на решения AoC на куче языков (ЯП и не очень вроде jq) — вдруг кому захочется свои решения посравнивать с чужими.
И да, всех с Новым Годом!
Решал я задачки на #Haskell, как водится. Довольствовался "просто нормальными решениями", которые было приятно реализовывать без необходимости погружаться в оптимизации. Итоги: удовольствие получено, нервов затрачено немного, руки размяты.
А вот общее впечатление от задачек в этого года, увы, смешанное. Возможно, дело в том, что это AoC'2019 был очень хорош, а нынешний просто получился "как раньше": с задачками на вида "пишите уже процедурщину, иначе не дождётесь окончания вычисления" (это могу терпеть) и "вспомнил известный алгоритм — решил, не вспомнил — не решил" (вот такое не люблю!). А ещё в этом году были самоповторы: три вариации конвеевской "Жизни" с незначительными отличиями, это не то, чего ждёшь от авторов. Возможно, год выдался тяжёлым и для них…
Так или иначе, advent calendars — это здорово! Подкину таковых на разные темы:
- "Advent of Haskell 2020" — познавательно-развлекательные статейки о #Haskell
- "Kotlin Christmas" — то же самое, но про #Kotlin
- "QEMU Advent Calendar 2020" — традиционный уже календарь всякого забавного, что можно запустить в QEMU (про этот календарь я тоже писал); день №12, например, это всё та же "Жизнь", но в виде самозагружаемой (без ОС!) программы на #Rust
Из прошлогодних могу упомянуть "‘A Language a Day’ — Advent Calendar 2019": 25 разных языков программирования по одному на день со ссылками на документацию и примерами кода.
Наконец, возвращаясь к AoC, отмечу, что в этих наших интернетах множество людей делится своими решениями в виде статей и прочих стримов. Вот, например, репозиторий со ссылками на решения AoC на куче языков (ЯП и не очень вроде jq) — вдруг кому захочется свои решения посравнивать с чужими.
И да, всех с Новым Годом!
Рубрика "дичь, которую творил я когда-то": всё те же часы, только в железной версии (ATMega8).
Корпус из монтажной коробки, пена от коврика, светофильтр из ткани 3M, трубочки для коктейля в роли световодов, вот это вот всё. Макетка и сдвиговый регистр старше меня (макетка — сильно старше).
Забавно, что "часики-то тикают", хотя цать лет назад я даже не очень свежую батарейку ставил :)
Корпус из монтажной коробки, пена от коврика, светофильтр из ткани 3M, трубочки для коктейля в роли световодов, вот это вот всё. Макетка и сдвиговый регистр старше меня (макетка — сильно старше).
Забавно, что "часики-то тикают", хотя цать лет назад я даже не очень свежую батарейку ставил :)
Повозился тут со штуками вокруг Gemini (см выше).
Серверы
Именно статический "сайт" поднимать не особо хотелось, но таки поднял:
Потыкал пакеты из набора haskell-gemini: пока сыровато. Так что #Haskell с Gemini я подружу позже.
Зато приятно оказалось пользоваться Jetforce. Это фреймворк для #Python такой. Построен на Twisted, внутри типы проаннотированы, async тут и там, при этом код выглядит "как Flask", то есть как набор декорированных функций — современненько!
Мне интересно было именно "Gemini приложение" написать, то есть что-то, создающее контент на лету. Получилось вполне прилично: основная функциональность в Jetforce уже есть. Нужно только будет написать eDSL для более удобного (чем захват регулярками) описания параметров в путях.
Клиенты
На десктопе попробовал пожить с Castor, графическим клиентом, написанным на #Rust, опять же. Но клиент пока слишком юн, и им не слишком удобно пользоваться.
В итоге пересел на Lagrange. Вот этот — красавец! Написан на C11 и SDL, аппаратно ускоряет отрисовку, красиво показывает текст, может и графику показать inline, управляется хоткеями. Даже "лого" генерирует для ресурсов на основе их имени — как умолчательные аватары на GitHub, вы такие точно видели. Пока я крайне доволен пользованием, рекомендую!
На Android пока остановился на deedum. Он не слишком красив, но крайне шустр и нетребователен к ресурсам.
Контент
В Gemlogs — это такие дневники в Geminiverse — народ пишет, есть что почитать. А ещё есть зеркала Lobste.rs и HackerNews, даже с комментариями. Ту же Wikipedia можно почитать через такой прокси. Словом, уютненько
Серверы
Именно статический "сайт" поднимать не особо хотелось, но таки поднял:
gemini://recursive.one (он же через проксю). Раздаётся с помощью Agate, минималистичного Gemini-сервера, написанного на #Rust. Agate кроме раздачи статики ничего не умеет, так что пока статическая страница и повисит %)Потыкал пакеты из набора haskell-gemini: пока сыровато. Так что #Haskell с Gemini я подружу позже.
Зато приятно оказалось пользоваться Jetforce. Это фреймворк для #Python такой. Построен на Twisted, внутри типы проаннотированы, async тут и там, при этом код выглядит "как Flask", то есть как набор декорированных функций — современненько!
Мне интересно было именно "Gemini приложение" написать, то есть что-то, создающее контент на лету. Получилось вполне прилично: основная функциональность в Jetforce уже есть. Нужно только будет написать eDSL для более удобного (чем захват регулярками) описания параметров в путях.
Клиенты
На десктопе попробовал пожить с Castor, графическим клиентом, написанным на #Rust, опять же. Но клиент пока слишком юн, и им не слишком удобно пользоваться.
В итоге пересел на Lagrange. Вот этот — красавец! Написан на C11 и SDL, аппаратно ускоряет отрисовку, красиво показывает текст, может и графику показать inline, управляется хоткеями. Даже "лого" генерирует для ресурсов на основе их имени — как умолчательные аватары на GitHub, вы такие точно видели. Пока я крайне доволен пользованием, рекомендую!
На Android пока остановился на deedum. Он не слишком красив, но крайне шустр и нетребователен к ресурсам.
Контент
В Gemlogs — это такие дневники в Geminiverse — народ пишет, есть что почитать. А ещё есть зеркала Lobste.rs и HackerNews, даже с комментариями. Ту же Wikipedia можно почитать через такой прокси. Словом, уютненько
:^)👍1
Я вам скажу, с вводом данных в #Gemini работать не скучно: аналога POST в Gemini нет, как нет и URL encoded параметров! И cookies тоже отсутствуют, как класс, как вы помните. Да, вы можете привязаться к пользовательскому сертификату и таким образом реализовать сессионность, но это уже будет сквозное состояние, чего хотелось бы избежать.
Зато Gemini сервер может запросить строку специальным ответом. После чего клиент покажет пользователю диалог с заданным приглашением, а результат ввода отправит обратно на сервер в виде query string. Соответственно, если вы хотите получить несколько значений, то вам нужно будет каждое запросить отдельно и сохранить в URL (кроме последнего, которое будет в query string). При этом размер запроса ограничен килобайтом на всё про всё — много не попостишь. Но тем интереснее!
Лелею идею написать FSM, которая взяла бы на себя весь этот сбор параметров, чтобы в обработчике запроса уже иметь все данные введёнными. Для Jetforce описание параметров можно будет оформить как "eDSL #Python-style" — на декораторах.
Также было бы интересно попробовать воплотить в Gemini интерактивность, подобную той, что использует #Racket в своих Stateful Servlets. Там вы тоже пишете код так, что данные вводятся "запросами к пользователю": вы отравляете пользователю форму, и получаете результат тут же в коде. Внутри всё реализовано на сохранении состояния в URL и рэкетовых continuations, снаружи же выглядит как магия — люблю такое
Зато Gemini сервер может запросить строку специальным ответом. После чего клиент покажет пользователю диалог с заданным приглашением, а результат ввода отправит обратно на сервер в виде query string. Соответственно, если вы хотите получить несколько значений, то вам нужно будет каждое запросить отдельно и сохранить в URL (кроме последнего, которое будет в query string). При этом размер запроса ограничен килобайтом на всё про всё — много не попостишь. Но тем интереснее!
Лелею идею написать FSM, которая взяла бы на себя весь этот сбор параметров, чтобы в обработчике запроса уже иметь все данные введёнными. Для Jetforce описание параметров можно будет оформить как "eDSL #Python-style" — на декораторах.
Также было бы интересно попробовать воплотить в Gemini интерактивность, подобную той, что использует #Racket в своих Stateful Servlets. Там вы тоже пишете код так, что данные вводятся "запросами к пользователю": вы отравляете пользователю форму, и получаете результат тут же в коде. Внутри всё реализовано на сохранении состояния в URL и рэкетовых continuations, снаружи же выглядит как магия — люблю такое
;) А уж насколько магически выглядят Web Cells: вы имеете переменную, которая помнит состояние между вызовами обработчика запроса, и таких переменных даже может быть несколько!Сил оформлять полноценные статьи пока нет, выдам выжимку того, чем я сейчас занимаюсь. Может быть что-то из этого и разовьётся в статью-другую!
Продолжаю приобщаться к #Gemini, почитываю чужие gemlogs, подумываю поднять зеркало этого канала в рамках своей капсулы (в Gemini так называют серверы, участвующие в сети). Выгрузил данные канала в виде JSON, накидал транскодер в Org mode. Но тут оказало, что Telegram не выгружает изображения, добавляемые к сообщениям ботом — не "фото + заметка", а именно "сопровождающее изображение". Я таких написал достаточно, чтобы жалеть о потере. Поэтому поднятие зеркала пока подвисло, может пройдусь вручную по публикациям и утяну картинки, а может и так оставлю — посмотрим.
Членствую в чате RuGemini, "нас мало, но мы в тельняшках". Кто-то хочет "вернуть себе Web", кто-то хочет уйти из Web совсем и делает proxy для поиска по StackOverflow, чтобы читать из Acme) под Plan9 — развлекаются, проще говоря. В Gemini контента, как ни странно, чатовцы мало генерят.
А в самой Geminispace есть, что почитать перед сном. Вот только находить контент мне удобно на ПК, а читать удобно с телефона! Вот и подумываю о том, чтобы сделать свой сервис закладок или даже аналог Pocket. Может даже с проксированием HTML, чтобы читать в text-only виде и околотекстовый Web. Коль скоро в Gemini нет cookies, а аутентификация делается с помощью SSL-ключей, приватный proxy не выглядит таким уж небезопасным решением.
Помимо Gemini, закопался ещё и в IndieWeb — тоже занятный островок для недовольных современным Web. Эти недовольны его хрупкостью и зависимостью от больших корпораций (коих пренебрежительно называют silos) и призывают владеть своими данными, а так же развивать свою identity в сети. Микроформаты вроде h-card, публикация через MicroPub — есть, про что почитать и что себе на сайт утащить. Можно послушать подкаст — неплохая вводная в IndieWeb!
Вот как-то так. Может ещё и про железки напишу (пополнил коллекцию интересными штучкам от M5Stack) — в такой же манере, а может и более структурировано.
Продолжаю приобщаться к #Gemini, почитываю чужие gemlogs, подумываю поднять зеркало этого канала в рамках своей капсулы (в Gemini так называют серверы, участвующие в сети). Выгрузил данные канала в виде JSON, накидал транскодер в Org mode. Но тут оказало, что Telegram не выгружает изображения, добавляемые к сообщениям ботом — не "фото + заметка", а именно "сопровождающее изображение". Я таких написал достаточно, чтобы жалеть о потере. Поэтому поднятие зеркала пока подвисло, может пройдусь вручную по публикациям и утяну картинки, а может и так оставлю — посмотрим.
Членствую в чате RuGemini, "нас мало, но мы в тельняшках". Кто-то хочет "вернуть себе Web", кто-то хочет уйти из Web совсем и делает proxy для поиска по StackOverflow, чтобы читать из Acme) под Plan9 — развлекаются, проще говоря. В Gemini контента, как ни странно, чатовцы мало генерят.
А в самой Geminispace есть, что почитать перед сном. Вот только находить контент мне удобно на ПК, а читать удобно с телефона! Вот и подумываю о том, чтобы сделать свой сервис закладок или даже аналог Pocket. Может даже с проксированием HTML, чтобы читать в text-only виде и околотекстовый Web. Коль скоро в Gemini нет cookies, а аутентификация делается с помощью SSL-ключей, приватный proxy не выглядит таким уж небезопасным решением.
Помимо Gemini, закопался ещё и в IndieWeb — тоже занятный островок для недовольных современным Web. Эти недовольны его хрупкостью и зависимостью от больших корпораций (коих пренебрежительно называют silos) и призывают владеть своими данными, а так же развивать свою identity в сети. Микроформаты вроде h-card, публикация через MicroPub — есть, про что почитать и что себе на сайт утащить. Можно послушать подкаст — неплохая вводная в IndieWeb!
Вот как-то так. Может ещё и про железки напишу (пополнил коллекцию интересными штучкам от M5Stack) — в такой же манере, а может и более структурировано.
Ох, что-то я совсем канал подзабросил, и нельзя сказать, что не о чем было писать… Будем считать, что я брал академический отпуск.
Нужно будет как-то снова набрать обороты, и при этом делать записи вида "ссылка плюс абзац текста" мне не хочется. Да и накопившиеся темя я так не разгребу, потому что поигрался за полгода с самими разными штуками. Можно попробовать в каком-то смысле интерактивный режим: я перечислю то, о чём мог бы написать, а вы сможете понажимать кнопки
Итак, за полгода я, помимо прочего, делал нижеперечисленное.
1
Наконец-то добрался до полноценного погружения в Common Lisp, прочитал пару книжек, сделал игрушечный проект в виде веб-приложения с БД, шаблонами и HTTP-запросами к API внешнего сервиса. Понравилось!
2
Переехал на Debian c Ubuntu (что само по себе скучно описывать), в связи с чем пришлось какое-то время посидеть на XFCE, который я постарался довести до некоторого подобия старого окружения вокруг i3.
В процессе чуть было не начал писать на Vala — вот про это уже можно написать! А толчком стало желание заиметь индикатор работы Yandex.Disk. Упаковал весь инструментарий в Docker-контейнер, собрал "Hello World" с интерфейсом на GTK3, начал радоваться. А потом оказалось, что нынче пиктограммы в system tray, это устаревшая идея и в GTK саму возможность делать таковые убрали!
В итоге обошёлся обвязыванием виджета XFCE Generic Monitor — это такая основа для самодельных индикаторов. Про это тоже может получиться запись.
3
В очередной раз глянул на Kotlin, после того, как наткнулся на видео о http4k. Это такая библиотечка, авторы которой открыли для себя, что web-сервер, это функция из request в response и преподносят теперь это их открытие, как новшество
В результате знакомства сделал Kotlin-версию того же проекта, который делал на Common Lisp. Решать знакомую задачу новым способом — это вообще неплохой способ знакомиться с языками, как вы знаете. Тоже HTTP API client + SQLite в роли БД + http4k в роли сервера и вёрстка на DSL. Большие фреймворки трогать не хотел, поэтому выбрал библиотеки "по примерам в README". В итоге впечатления, что называется, смешанные.
4
Из того, что началось раньше, но продолжалось в эти полгода, ещё есть проект, который мы на пару с товарищем, реализуем в рамках серии видео-трансляций. Это игрушечный движок для текстовых Interactive Fiction, построенный на базе… Django (это такой большой Web-фреймворк для Python, если кто вдруг не знал). Выбран Django потому, что я его умею использовать, а тема IF выбрана потому, что такое на Django обычно не делают
Было ещё что-то более мелкое, буду вспоминать
Нужно будет как-то снова набрать обороты, и при этом делать записи вида "ссылка плюс абзац текста" мне не хочется. Да и накопившиеся темя я так не разгребу, потому что поигрался за полгода с самими разными штуками. Можно попробовать в каком-то смысле интерактивный режим: я перечислю то, о чём мог бы написать, а вы сможете понажимать кнопки
:Р.Итак, за полгода я, помимо прочего, делал нижеперечисленное.
1
Наконец-то добрался до полноценного погружения в Common Lisp, прочитал пару книжек, сделал игрушечный проект в виде веб-приложения с БД, шаблонами и HTTP-запросами к API внешнего сервиса. Понравилось!
2
Переехал на Debian c Ubuntu (что само по себе скучно описывать), в связи с чем пришлось какое-то время посидеть на XFCE, который я постарался довести до некоторого подобия старого окружения вокруг i3.
В процессе чуть было не начал писать на Vala — вот про это уже можно написать! А толчком стало желание заиметь индикатор работы Yandex.Disk. Упаковал весь инструментарий в Docker-контейнер, собрал "Hello World" с интерфейсом на GTK3, начал радоваться. А потом оказалось, что нынче пиктограммы в system tray, это устаревшая идея и в GTK саму возможность делать таковые убрали!
В итоге обошёлся обвязыванием виджета XFCE Generic Monitor — это такая основа для самодельных индикаторов. Про это тоже может получиться запись.
3
В очередной раз глянул на Kotlin, после того, как наткнулся на видео о http4k. Это такая библиотечка, авторы которой открыли для себя, что web-сервер, это функция из request в response и преподносят теперь это их открытие, как новшество
:). Функциональщики посмеиваются, знакомые с WSGI питонисты — тоже.В результате знакомства сделал Kotlin-версию того же проекта, который делал на Common Lisp. Решать знакомую задачу новым способом — это вообще неплохой способ знакомиться с языками, как вы знаете. Тоже HTTP API client + SQLite в роли БД + http4k в роли сервера и вёрстка на DSL. Большие фреймворки трогать не хотел, поэтому выбрал библиотеки "по примерам в README". В итоге впечатления, что называется, смешанные.
4
Из того, что началось раньше, но продолжалось в эти полгода, ещё есть проект, который мы на пару с товарищем, реализуем в рамках серии видео-трансляций. Это игрушечный движок для текстовых Interactive Fiction, построенный на базе… Django (это такой большой Web-фреймворк для Python, если кто вдруг не знал). Выбран Django потому, что я его умею использовать, а тема IF выбрана потому, что такое на Django обычно не делают
:). Причём Web-приложение получившееся пока даже не предполагает использование несколькими пользователями, что тоже для Django не характерно. Зато используется админка, в которую я протащил Graphwiz для построения интерактивной карты игрового мира.Было ещё что-то более мелкое, буду вспоминать
:P.Если что, уточняю: я напишу про всё упомянутое, скорее всего. Кнопочки влияют на порядок следования будущих тем :)
Итак, Common Lisp. Знаю я про его существование с того момента, как вообще узнал про существование лиспов. Но непосредственно CL я до этой весны не трогал, будучи пот этом знаком с кучкой диалектов Scheme, с Clojure и, по очевидным причинам, с Emacs Lisp.
Как-то раз я даже ставил SBCL (о нём ниже), но дальше пары команд в REPL дело не пошло. Думается, что именно это самое знакомство с семейством в целом мне и мешало: "ну что я там не видел, те же скобки, только в профиль". Несколько фундаментальных книжек в списке на прочтение висят уже давно. Статейки же про CL я никогда не читал — зачем, если я всё равно не собирался начинать знакомство.
Но статью "A road to Common Lisp" я почему-то прочитал, "и заверте…". У автора получилось обратить внимание именно на интересные для меня свойства языка и экосистемы. И я решил таки погрузиться, более того — следуя указанному в статье пути. Установил SBCL — компилятор CL в native code, живой и активно развивающийся. Завёл REPL, подключил к Emacs с помощью sly. Настало время почитать книги.
Прочитал рекомендованную "Common Lisp: A Gentle Introduction to Symbolic Computation", прорешал задания. Книга старая (переиздавалась в 2013, но основной материал ещё в 80х написан), но мне очень понравилась! Было интересно представлять себе то, как разные вещи появлялись в языке и почему это было сделано: наконец-то я увидел, откуда растут ноги у eLisp'овских
Задачки из книги, это хорошо. Но реальные проекты, состоящие более чем из одного модуля, нужно как-то оформлять и вообще управлять загрузкой кода в образ. Дело в том, что модули в CL, это, условно, команды, который выполняются в REPL и изменяют состояние виртуальной машины. Даже менеджер пакетов quicklisp выполняется как скрипт в рамках сеанса работы виртуальной машины и модифицирует её состояние так, чтобы VM понимала концепцию этих самых пакетов. Нет никаких конфигурационных файлов, есть программки на Lisp, меняющие систему до тех пор, пока та не придёт в требуемое состояние. После чего обычно делают снимок образа, хранящего состояние машины, и помечают "при восстановлении вызвать такую-то функцию". И если к снимку прилинковать бинарник виртуальной машины, то получится самодостаточный исполняемый файл! Причём этот файл может нести на борту и REPL, к которому можно будет подключиться из редактора и пообщаться с живой системой!
Кроме quicklisp есть ещё концепция систем, которые описывают то, какие модули и в каком порядке должны загружаться. За это отвечает ASDF, средство для описания систем. ASDF обычно идёт в комплекте с конкретной реализацией CL, но умеет лишь работать с модулями, которые у вас в системе уже лежат в привычных местах вроде пользовательской директории со всеми lisp-проектами. quicklisp же умеет скачать пакеты из сети и подать код так, что ASDF не заметит разницы. Надо ли упоминать, что и ASDF, и quicklisp написаны на CL?
Последний момент стоит отметить особо: в сообществе CL большинство авторов хоть сколько-нибудь открытого кода крайне озабочено тем, чтобы их код работал на разных реализациях CL, а в идеале — на любых! И большая часть публично доступных пакетов не привязана к конкретной реализации или паре таковых. Можно считать, что если у вашей реализации есть ASDF, то и quicklisp будет работать, и любые, установленные им, пакеты. Да, можно встретить код, который использует свойства конкретных реализаций, чтобы работать более эффективно, но обычно этот же код может работать в "режиме совместимости". Лично мне было крайне интересно познакомиться с такой экосистемой!
Продолжение следует…
Как-то раз я даже ставил SBCL (о нём ниже), но дальше пары команд в REPL дело не пошло. Думается, что именно это самое знакомство с семейством в целом мне и мешало: "ну что я там не видел, те же скобки, только в профиль". Несколько фундаментальных книжек в списке на прочтение висят уже давно. Статейки же про CL я никогда не читал — зачем, если я всё равно не собирался начинать знакомство.
Но статью "A road to Common Lisp" я почему-то прочитал, "и заверте…". У автора получилось обратить внимание именно на интересные для меня свойства языка и экосистемы. И я решил таки погрузиться, более того — следуя указанному в статье пути. Установил SBCL — компилятор CL в native code, живой и активно развивающийся. Завёл REPL, подключил к Emacs с помощью sly. Настало время почитать книги.
Прочитал рекомендованную "Common Lisp: A Gentle Introduction to Symbolic Computation", прорешал задания. Книга старая (переиздавалась в 2013, но основной материал ещё в 80х написан), но мне очень понравилась! Было интересно представлять себе то, как разные вещи появлялись в языке и почему это было сделано: наконец-то я увидел, откуда растут ноги у eLisp'овских
prog1 и прочих setq.Задачки из книги, это хорошо. Но реальные проекты, состоящие более чем из одного модуля, нужно как-то оформлять и вообще управлять загрузкой кода в образ. Дело в том, что модули в CL, это, условно, команды, который выполняются в REPL и изменяют состояние виртуальной машины. Даже менеджер пакетов quicklisp выполняется как скрипт в рамках сеанса работы виртуальной машины и модифицирует её состояние так, чтобы VM понимала концепцию этих самых пакетов. Нет никаких конфигурационных файлов, есть программки на Lisp, меняющие систему до тех пор, пока та не придёт в требуемое состояние. После чего обычно делают снимок образа, хранящего состояние машины, и помечают "при восстановлении вызвать такую-то функцию". И если к снимку прилинковать бинарник виртуальной машины, то получится самодостаточный исполняемый файл! Причём этот файл может нести на борту и REPL, к которому можно будет подключиться из редактора и пообщаться с живой системой!
Кроме quicklisp есть ещё концепция систем, которые описывают то, какие модули и в каком порядке должны загружаться. За это отвечает ASDF, средство для описания систем. ASDF обычно идёт в комплекте с конкретной реализацией CL, но умеет лишь работать с модулями, которые у вас в системе уже лежат в привычных местах вроде пользовательской директории со всеми lisp-проектами. quicklisp же умеет скачать пакеты из сети и подать код так, что ASDF не заметит разницы. Надо ли упоминать, что и ASDF, и quicklisp написаны на CL?
Последний момент стоит отметить особо: в сообществе CL большинство авторов хоть сколько-нибудь открытого кода крайне озабочено тем, чтобы их код работал на разных реализациях CL, а в идеале — на любых! И большая часть публично доступных пакетов не привязана к конкретной реализации или паре таковых. Можно считать, что если у вашей реализации есть ASDF, то и quicklisp будет работать, и любые, установленные им, пакеты. Да, можно встретить код, который использует свойства конкретных реализаций, чтобы работать более эффективно, но обычно этот же код может работать в "режиме совместимости". Лично мне было крайне интересно познакомиться с такой экосистемой!
Продолжение следует…
Меж тем выложили запись моего доклада на SECON'21, в рамках которого я пугал людей примерами кода на Haskell, Elm, PureScript и Clojure применительно к frontend development. Я-то хотел сначала рассказать сильно более пространный доклад про разные фишечки в нескучных языках — про акторы, true-прототипное ООП в Io, ленивость хаскельную. Но программный комитет решил, что это будет слишком сурово и выдать нужно что-то более приземлённо-насущное и при этом расширяющее кругозор. В итоге аудитория была в лёгком шоке, но доклад оценила положительно
:)Лиспоприключения, часто вторая.
Книжку я прочитал, SBCL/ASDF/quicklisp завёл, собрал несколько программок в "самодостаточные exe-шники". А потом передо мной встал вопрос: а что бы такое написать сравнительно большое и разностороннее? Решил написать web-приложение вокруг PokeAPI — это такой сервис, предоставляющий самую разную информацию о контенте большей части игр из серии "Pokemon" в виде HTTP JSON API. Авторы PokeAPI призывают пользователей вести себя хорошо, что означает необходимость кэшировать всё и всегда. А это уже подразумевает работу с персистентным хранилищем, например, с SQLite.
Чтобы реализовать нарисованный в уме проект, мне нужно было выбрать:
- Web-фреймворк
- HTML-шаблонизатор
- HTTP-клиент
- парсер JSON
- коннектор к SQLite3
- генератор SQL-запросов
С первым пунктом всё более-менее очевидно: наиболее популярен hunchentoot, поэтому и я его взял. Приложение с его помощью выглядит как один или несколько так называемых acceptors, которые нужно создать и запустить на нужных портах. Запуск акцептора не блокирует текущий поток, то есть всё сделано для того, чтобы запускать акцепторы один раз и потом только модифицировать их состояние без останова — разумеется, через eval S-выражений по горячей клавише прямо не выходя из Emacs, ведь у нас REPL-driven development, как-никак!
Роуты навешиваются через макросы, модифицирующие акцептор. У меня роутинг был простой: либо список покемонов вывожу, если параметра "?name=" нет, либо карточку покемона с указанным именем, поэтому и роут у меня всего один
Выглядит разметка так:
Книжку я прочитал, SBCL/ASDF/quicklisp завёл, собрал несколько программок в "самодостаточные exe-шники". А потом передо мной встал вопрос: а что бы такое написать сравнительно большое и разностороннее? Решил написать web-приложение вокруг PokeAPI — это такой сервис, предоставляющий самую разную информацию о контенте большей части игр из серии "Pokemon" в виде HTTP JSON API. Авторы PokeAPI призывают пользователей вести себя хорошо, что означает необходимость кэшировать всё и всегда. А это уже подразумевает работу с персистентным хранилищем, например, с SQLite.
Чтобы реализовать нарисованный в уме проект, мне нужно было выбрать:
- Web-фреймворк
- HTML-шаблонизатор
- HTTP-клиент
- парсер JSON
- коннектор к SQLite3
- генератор SQL-запросов
С первым пунктом всё более-менее очевидно: наиболее популярен hunchentoot, поэтому и я его взял. Приложение с его помощью выглядит как один или несколько так называемых acceptors, которые нужно создать и запустить на нужных портах. Запуск акцептора не блокирует текущий поток, то есть всё сделано для того, чтобы запускать акцепторы один раз и потом только модифицировать их состояние без останова — разумеется, через eval S-выражений по горячей клавише прямо не выходя из Emacs, ведь у нас REPL-driven development, как-никак!
Роуты навешиваются через макросы, модифицирующие акцептор. У меня роутинг был простой: либо список покемонов вывожу, если параметра "?name=" нет, либо карточку покемона с указанным именем, поэтому и роут у меня всего один
:)
HTML в лиспах генерят из S-выражений, но разные библиотеки делают это по-разному. Я попробовал несколько, в итоге остановился на spinneret, которая использует списки с keywords. Последнее было несколько досадно, потому что я-то хотел символы писать! Но зато в остальном библиотека приятная и не заставляет использовать какие-то сложные конструкции для подстановки одних фрагментов разметки в другие: вы одни макросы вызываете в теле других, дерево из списков растёт, но не "выполняется" до самого последнего момента — удобно, композируемо!Выглядит разметка так:
(:headПродолжение следует...
(:meta :name "viewport"
:content "width=device-width, initial-scale=1")
(:link :rel "stylesheet"
:href "https://unpkg.com/blocks.css/dist/blocks.min.css"
:media "screen")
(:title ,title " (CL-Pokedex)"))