вторник, 29 декабря 2009 г.

Странности в gentoo-lisp-overlay

Что-то стали в gentoo-lisp-overlay кривые пакеты попадаться: для bordeaux-threads-0.7.0 файл с версией не копируется, для parenscript-20090921 зависимости не указаны... Как они их делаю?.. Точнее, как делают понятно, но почему не проверяют - вот это мне не понятно. И исправлений никаких уже долго нет, один я что-ли им пользуюсь... Эх, фиксю и помещаю исправления в свой форк.

понедельник, 28 декабря 2009 г.

restas-directory-publisher на lisper.ru

Больше для демонстрации, чем из реальной необходимости, включил пример использования плагина restas-directory-publisher в состав сайта lispe.ru, смотреть здесь.

Код тривиален:
(restas:define-site-plugin rulisp-files (#:restas.directory-publisher)
(restas.directory-publisher:*baseurl* '("files"))
(restas.directory-publisher:*directory* (merge-pathnames "files/" *vardir*))
(restas.directory-publisher:*autoindex-template*
(lambda (data)
(rulisp.view.fine:main-frame (list :title (getf data :title)
:css (css-files-data '("style.css" "autoindex.css"))
:user (compute-user-login-name)
:main-menu (main-menu-data)
:content (restas.directory-publisher.view:autoindex-content data)
:callback (hunchentoot:request-uri*))))))

среда, 23 декабря 2009 г.

Элементы функциональных языков. Резюме.

Дочитал таки статью "Элементы функциональных языков", мысль по прочтению только одна: если бы хаскелисты освоили Common Lisp, то большинство из них забыло бы про Haskell как про страшный сон :)

Динамическая область видимости

Прочитал в последнем номере журнала "Практика функционального программирования" в статье про "Элементы функциональных языков" буквально следующее:
В языке LISP присутствовали замыкания с динамической областью видимости, нарушавшие законы лямбда-исчисления и, вообще говоря, неудобные в использовании. Emacs LISP— практически единственный используемый на практике современный язык программирования, где используется динамическая область видимости.
Т.е. тут два посыла:
  • Динамическое область видимости неудобна
  • Динамическая область видимости осталась только в ELisp
Теперь вот сижу, пытаюсь найти мотивацию для дальнейшего прочтения, это же надо, так высказаться об одном из ключевых и наиболее удобных свойств Common Lisp: динамические переменные это потрясающе удобно и поэтому используются в коде на Common Lisp чрезвычайно широко.

вторник, 22 декабря 2009 г.

И ещё пара слов о Russian Lambda Planet

Когда проект Russian Lambda Planet был только запущен, это было даже интересно, там было мало блогов, много о ФП и я добавил её в свой RSS-реадер. Месяца три назад я оттуда её удалил, ибо проект превратился неизвестно во что. Куча блогов, в которых теперь очень мало пишут про ФП, зачем-то агрегируются в одну ленту, тему которой, иначе как "Мои ЖЖ друзья", теперь-то и определить сложно.

Почему бы не отбирать сообщения по тэгам? Может движок не позволят? Ну тогда, почему бы не переписать её на "великом и ужасном" Erlang? вроде как и фрэймворки для веба есть... Или даже на Haskell? вдруг и на нём можно подобное писать (в этом, я правда сильно сомневаюсь)?

При чём, работы то там на один вечер. Для сравнения, размер исходного кода Russian Lisp Planet - 240 строк. Ведь все же видят, что в планете сплошной мусор. Переписали бы на Erlang, вот и материал для журнала: "вот сайт, вот код, вот инструкция по установке, а делали мы это так...". И не надо будет больше читать про то, что "GSM убивает тараканов" (с). Нет же, учавствовать в бесконечных холиварах желающих толпы, а как код писать - так у всех "почасовая оплата" (с), ну что за народ...

colorize

Для подсветки кода сейчас для Common Lisp есть пакет colorize, который не обновлялся с 2004-года (но svn-сервер с ним работает исправно, хе, но там только один коммит). С другой стороны, есть приложение lisppaste, которое включает в себя colorize, обращаю внимание, что не использует, а именно включает, т.е. оба этих пакета имеют общий набор файлов. Вообще, ситуация довольно дикая, я не стал вникать в историю (если она даже где-то описана), но подобный подход разработчиков представляется мне довольно безответственным. Так вот, в lisppaste в данный момент поддерживает несколько больший набор языков, чем colorize (сам выбор этих языков представляется мне довольно странным, здесь можно опять порассуждать о безответственности). А ведь, этот функционал является довольно важным, если вы хотите разрабатывать на Common Lisp приложения типа форума, вики, pastebin и т.п.

В общем, я взял colorize, взял изменения из lisppaste, и создал отдельный репозиторий: http://github.com/archimag/colorize. Желающие добавить поддержку новых языков могут слать мне патчи :)

Да, есть один нюанс. Для правильного форматирования кода на Common Lisp пакету требуется установленный HyperSpec. В оригинальном коде он ищётся в домашнем каталоге, но меня такой подход не впечатлил. Я сделал как в Gentoo, где HyperSpec размещается в каталоге #P"/usr/share/doc/hyperspec-7.0/HyperSpec/" - если у вас он находитсья в другом месте, то необходимо открыть файл clhs-lookup.lisp и изменить в нём значение *hyperspec-pathname*.

P.S. Проделав всё это захотел проверить как colorize будет обрабатывать код на теперь поддерживаемых Erlang или Haskell. Думаю, где же искать этот код, если не на Russian Lambda Planet? - пошёл туда, ага, как же. На Russian Lambda Planet есть всякие забавные фотки (кошечки или там разные предметы мебели), есть разная болтовня про мотоциклы, или даже я видел про баб, есть немного словоблудия про ФП в основном в виде ссылок с восторженными комментариями, но там совершенно нет кода на функциональных языках. Нет, справедливости ради, должен заметить, что иногда там всё таки бывает код на Erlang или Haskell (когда-то я там его видел), но кажется что кода на C или Java там значительно больше. Я думаю, что редакция журнала "Практика функционального программирования" несколько погорячилась с этим конкурсом - если какие решения и появятся, то скорей всего это будет Java или PHP :), уж очень не верится, что люди, столько неохотно пишущие код, сподобятся написать что-либо более-менее серьёзное... тем более, столь бесполезное для большинства...

воскресенье, 20 декабря 2009 г.

restas-colorize

Закончил отделение кода "форматтера кода" (обычно подобные приложения называют pastebin) от исходного кода lisper.ru и сейчас он доступен как отдельный restas-плагин: restas-colorize. Перевёл lisper.ru на использование этого плагина. Как побочный результат - новая возможность, теперь можно форматировать код не только на Common Lisp, поддерживаются и некоторые другие языки программирования. Планирую в будущем расширить список поддерживаемых языков, но это не имеет отношения к restas-colorize, а только к библиотеке colorize.

Сейчас для настройки плагина можно использовать следующие переменные (из пакета #:restas-colorize):
  • *max-on-page* - при просмотре списка "pastes" определяет максимальное их количество на одной странице
  • *finalize-page* - служит для "встраивания" плагина в сайт, задания общего оформления
  • *colorize-user-function* - плагин не имеет своей системы авторизации, предпочитает использовать внешнюю
  • *storage* - пожалуй самый интересный параметр, в состав плагина входит только хранилище в памяти, которое позволяет хранить "pastes" в памяти только во время выполнения. Для реального сайта необходимо, скорей всего, использовать хранение в базе, но плагин не берётся судить о том, какая структура базы будет оптимальной для всех сайтов, поэтому на стороне сайта необходимо создать объект *storage*, реализующий требуемый протокол и передать в этой переменной в плагин.
На lisper.ru данный плагин сейчас подключается следующим образом:
(restas:define-site-plugin rulisp-format (#:restas.colorize)
(restas.colorize:*baseurl* '("apps" "format"))
(restas.colorize:*max-on-page* 15)
(restas.colorize:*storage* *rulisp-db-storage*)
(restas.colorize:*colorize-user-function* #'compute-user-login-name)
(restas.colorize:*finalize-page* (lambda (content)
(rulisp.view.fine:main-frame (list :title (getf content :title)
:css (css-files-data '("style.css" "colorize.css"))
:user (compute-user-login-name)
:main-menu (main-menu-data)
:content (getf content :content)
:callback (hunchentoot:request-uri*))))))
Посмотреть используемую реализацию storage можно здесь.

четверг, 17 декабря 2009 г.

20 000 строк кода на Common Lisp

Подсчитал с помощь SLOCCount, что за последние полтора года написал на Common Lisp чуть менее 20 000 строк кода, половина - открытый код.

среда, 16 декабря 2009 г.

restas-directory-publisher и cgi-скрипты

Добавил к restas-directory-publisher возможность исполнять cgi-скрипты, которую предоставляет пакет hunchentoot-cgi. Запустить, например, веб-морду к git на основе gitweb.cgi (который поставляется вместе с git) сейчас можно следующим образом:
(asdf:operate 'asdf:load-op '#:restas-directory-publisher)

(restas:defsite #:gitweb
(:use #:cl))

(in-package #:gitweb)

(restas:define-site-plugin git (#:restas.directory-publisher)
(restas.directory-publisher:*baseurl* '("gitweb"))
(restas.directory-publisher:*directory* #P"/usr/share/git/gitweb/")
(restas.directory-publisher:*enable-cgi-by-type* '("cgi")))

(restas:start-site '#:gitweb :port 8080)
Теперь открываем в браузере адрес http://localhost:8080/gitweb/gitweb.cgi и видим знакомый, полностью функционирующий интерфейс.

Это даже проще, чем настроить Apache для решения данной задачи :)

git-репозиторий с hunchentoot

С исходным кодом Hunchentoot невозможно работать, ибо он лежит под Subversion. Это просто ненормально, 2010-й год на носу. Ладно, теперь есть и под git: http://github.com/archimag/hunchentoot. Обязуюсь регулярно синхронизировать с основным репозиторием и не вносить каких-либо своих изменений. Т.е. это будет чистая копия. Может кто-нибудь форкнет, в конце-то концов...

www-restas и cl-gtk2

Внёс изменения в свой форк gentoo-lisp-overlay: добавил новую категорию www-restas и перенёс в неё пакеты restas-planet, restas-wiki и restas-directory-publisher.

Кроме того, добавил пакеты из cl-gtk2-overlay, который поддерживает dmitry_vk: всё таки git мощная штука :)

вторник, 15 декабря 2009 г.

RESTAS-daemon

Ранее я рассказывал, как можно написать демона на "pure lisp" и таким образом обойтись без граблей в виде Screen или detachtty. С тех пор, у меня развелось некоторое колличество подобных демонов для разных сервисов, с общим базовым кодом и незначительными отличиями. Я использовал технику copy/paste, что меня сильно огорчало, да и неудобства заметные - время от времени я правлю базовый код и изменения надо руками разносить по разным файлам (на разных серверах). Желание сделать некую общую схему с повторным использованием у меня было с самого начала, но вот сделать универсальный "демонизатор" не так просто. В итоге, я решил отказаться от универсального решения, и сделать скрипт для запуска как демонов web-приложений на базе RESTAS. Это довольно просто, ибо все эти приложения запускаются однотипно: загрузить нужную asdf-систему и вызвать restas:start-site с именем сайта, определенным с помощью макроса restas:defsite. Получившийся скрипт я назвал restas-daemon.lisp и положил в директорию contrib пакета RESTAS. Теперь запустить демона для web-приложения на базе RESTAS очень просто:
sbcl --noinform --no-userinit --no-sysinit --load /path/to/restas/contrib/restas-daemon.lisp /path/to/daemon.conf COMMAND
Как видно, данный скрипт принимает два параметра: путь к файлу конфигурации демона и имя команды. Поддерживаются следующие команды:
  • start - запуск
  • stop - остановка
  • restart - рестарт
  • kill - убийство, если почему-то демон не хочет останавливаться с помощью stop
  • zap - удалят pid-файл, это может потребоваться, если демон был остановлен как-нибудь грубо
  • nodaemon - в основном тоже, что и start (в том числе происходит смена прав и т.п.), но при этом процесс не делает себе fork и не отключается от терминала, что даёт возможность наблюдать весь его вывод - удобно для отладки демона.
Файл конфигурации демона может содержать определение нескольких переменных, влияющих на поведение демона, вот полный конфиг моего домашнего демона:
(defparameter *name* "homesite")

(defparameter *user* "andrey")

(defparameter *swankport* 9000)

(defparameter *asdf-central-registry*
'(#P"/usr/share/common-lisp/systems/" #P"/home/andrey/development/common-lisp/common-lisp-systems/"))

(defparameter *asdf-load-systems* '(#:homesite))

(defparameter *sites* '((#:homesite nil 80)))
Возможны следующие параметры:
  • *name* - имя демона, в данный момент единственный обязательный параметр
  • *user* - имя пользователя, от которого должен работать демон, по-умолчанию совпадает с именем демона
  • *group* - группа пользователя
  • *fasldir* - путь к каталогу, в который будут складываться fasl-файлы, по-умолчанию определяется из имени демона как (format nil "/var/cache/~A/fasl/" *name*)
  • *pidfile* - pid-файла демона, по-умолчанию (format nil "/var/run/~A/~A.pid" *name* *name*)
  • *swankport* - порт, на котором следует запускать swank, если не указан или nil, то swank не запускается
  • *default-host-redirect* - в RESTAS сайты запускаются с помощью restas:start-site, при этом можно указать имя хоста (аналог виртуальных хостов), данная переменная указывает хост, на который будет производиться редирект, если для хоста запроса нет сайта, например, на lisper.ru можно попасть набрав в браузере www.lisper.ru, lisp.catap.ru или просто прямой адрес, все такие запросы перенаплавляются на lisper.ru
  • *asdf-central-registry* - список директорий, в которых будет производиться поиск систем
  • *asdf-load-systems* - список систем, которые необходимо загрузить при старте демона
  • *sites* - список сайтов, которые необходимо запустить при запуске демона с помощью функции restas:start-site. В качестве сайта может быть указано просто имя, либо список, например '(#:rulisp "lisper.ru" 80). Сайты определяются с помощью restas:defsite - это происходит при загрузке указанных asdf-систем.
Для систем на базе Gentoo есть специальная поддержка. При установке restas с помощью моего форка gentoo-lisp-overlay в каталог /etc/init.d/ добавляется скрипт restas.lo. Теперь, для создания initd-скрипта необходимо создать симлинк на этот файл и создать конфигурационный файл в /etc/conf.d/, например:
cd /etc/init.d/
ln -s restas.lo homesite
emacs /etc/conf.d/homesite.conf
/etc/init.d/homesite start
Схема может быть ещё не совсем устоявшаяся, но уже рабочая :)

пятница, 11 декабря 2009 г.

archimag/gentoo-lisp-overlay

Немного поразмышляв решил форкнуть gentoo-lisp-overlay, в конце концов, ведь именно для этого и придумали git :) Итак, http://github.com/archimag/gentoo-lisp-overlay, помимо прочего содержит мои пакеты:
Кроме того, он также содержит cl-typesetting и мой форк cl-pdf, который включает в себя поддержку salza2, zpb-ttf и некоторые мои изменения.

При использовании layman проще всего подключить этот форк вместо оригинальной версии следующим образом:
cd /usr/local/portage/layman/lisp
git remote rm origin
git remote add origin git://github.com/archimag/gentoo-lisp-overlay.git
git config branch.master.remote origin
git config branch.master.merge master
(Пишу по памяти, могу немного напутать)
Теперь
layman --sync lisp
Будет брать обновления из моего репозитория, который я обещаю регулярно синхронизировать с основным.

Открыт приём багов и предложений :)

понедельник, 7 декабря 2009 г.

restas-wiki

Закончил отделение исходного кода wiki, используемой на lisper.ru, от собственно исходного кода lisper.ru и оформил это дело в виде отдельного restas-плагина - restas-wiki. Теперь, весь код для поддержки wiki на lisper.ru выглядит следующим образом:
(restas:define-site-plugin rulisp-wiki (#:restas.wiki)
(restas.wiki:*baseurl* '("wiki"))
(restas.wiki:*wiki-dir* #P"/var/rulisp/wiki/")
(restas.wiki:*wiki-user-function* #'compute-user-login-name)
(restas.wiki:*finalize-page* #'(lambda (content)
(rulisp.view.fine:main-frame (list :title (getf content :title)
:css (css-files-data '("style.css" "wiki.css"))
:user (compute-user-login-name)
:main-menu (main-menu-data)
:content (getf content :content)
:callback (hunchentoot:request-uri*))))))

пятница, 4 декабря 2009 г.

Common Lisp и WEB

Я хотел бы озвучить тезис, который для меня является совершенно очевидным, но который, как мне кажется, не находит широко понимания среди людей, интересующихся Common Lisp. Итак:
Наиболее важная и перспективная область применения Common Lisp это web-технологии
Текущая ситуация в IT такова, что язык, не пригодный для web-разработки, обречён на прозябание и наоборот, язык, цветущий в мире web, будет находить всё новые и новые области применения. Тут хотелось бы заострить внимание на двух мифах.

Миф 1
Есть мнение, что изучение некоторых языков (к коим часть говорящих относит и Common Lisp) является очень важным для развития мышления и т.п. Т.е. нет необходимости и не очень много смысла писать на этих языках реальный софт, достаточно просто уделять их изучению некоторое время. Это можно сравнить с посещением спортивного зала: посидел пару часов над XXX, прокачал мозг, и можешь снова возвращаться в реальный мир Java/C#/т.п. где без сомнения будешь с лёгкость превосходить всех прочих...

Я думаю, что это полный бред. Язык это всего лишь инструмент. Великий скульптор создаст шедевр вооружившись одним только каменным топором, я же, при всём богатстве современных инструментов, не смогу создать даже подобия скульптуры. Ни в одной другой области человеческой деятельности мне не доводилось слышать мнения о принципиальной важности изучения инструментов для развития способностей в этой области. Зато, практически во всех областях (с которыми я сталкивался) отмечается важность изучения предшествующего опыта. И вот загвоздка: среди образцов кода и идей, которые производили на меня впечатление, чаще всего втречается C и PHP. Зачем изучать Lisp, Haskell и т.п., если наиболее ценные образцы кода написаны на языках, которые и изучать то особо не надо (настолько они просты) ...

Миф 2
Ещё говорят, что у каждого языка есть своя область применений и при построении реальных больших систем надо использовать разные языки для разных компонентов, а Common Lisp - язык для программирования искусственного интеллекта. Т.е. например пишем на CL какой-нибудь очень интеллектуальный модуль, а веб-морду к нему делаем на PHP. Ну и т.п.

Я абсолютно уверен, что ни один из утверждающих подобное не пробовал применить свой рецепт на практике. Я вот попробовал, и проблемы взаимодействия, проблемы разделения логики и сопутствующие проблемы дублирования кода однозначно привели меня к мысли, что универсальный язык в проекте должен быть только один. Попытки лёгкой интеграции за счёт использования технологий, подобных COM, .Net, JVM и т.п. порождают проблемы, в значительной степени обесценивающие получаемые преимущества. Да, есть DSL, такие как XSLT, которые восхитительно хороши для решения некоторых частных задач, но смешивать в одном проекте, например, Python, Perl и Common Lisp по крайней мере не разумно.

Повторюсь, что я имел опыт подобного смешивания, я использовал Common Lisp для самой интеллектуальной части системы и результатом этого явилось понимание, что если я хочу использовать Common Lisp, то я должен быть готов использовать его для построения всей системы, а не только одного компонента.

Что мы имеем сейчас
Человек, "реально" (ну т.е. примерно как я :)) смотрящий на вещи и заинтересовавшийся Common Lisp найдёт очень удручающую картину. Использовать CL для написания небольших скриптов и десктопных приложений фактически нельзя, что связано с временем запуска, требования к памяти и размеров генерируемых образов. Ну т.е. теоретически можно, но расчитывать на широкое использование CL на десктопе несколько наивно, он (CL) создавался явно не для этого. Да и вообще, декстоп это не очень интересно. Итак, остаётся веб. Вот тут картина так просто ужасающая, пройдитесь по основным ресурсам, например
Что мы там найдём? Жуткий интерфейс примитивной вики, apache 1.3 и cgi-скрипты, PHP. Картина маслом. Для усиления эффекта можно сразу после этого зайти, например, на jboss.org и сделать какой-нибудь недвусмысленный вывод. Не очень впечатлительные люди могу проигнорировать это и попробовать разобраться с имеющимися библиотеками и это достойно отдельного обсуждения :) Например, если ранее вы писали на C++ и таки не смогли "отстрелить себе ногу", то у вас есть реальный шанс отстрелить себе сразу голову с помощью Weblocks или UCW. Или, если вы настольгируте по cgi-скриптам на Perl, то наверняка вам придётся по вкусу единственная (!) известная библиотека шаблонов html-template. Ну и т.д.

На днях появился пост Why I chose Common Lisp over Python, Ruby, and Clojure - я просто плакал, на фоне жалкой аргументации больше всего запоминается признание того факта, что сделать каркас с помощью RoR или Django было бы намного быстрее.

И, кстати, для любителей творчества Пола Грэма, будет небезынтересно узнать, что Viaweb был переписан на Perl и С++ почти сразу после его ухода :)

Удивительное рядом
Больше всего меня поражает, что под кучей хлама скрывается суть, сам Common Lisp - удивительно мощный и яркий язык. И для него существую такие блестящие реализации, как SBCL. Конечно, это возможно вопреки текущему уровню интереса только благодаря 50 годам непрерывного развития. В последнее время ситуация стала несколько изменяться, стали появляться качественные современные библиотеки, например, ironclad или iolib. И мне кажется, что этот накопившийся хлам можно расчистить. Но для этого нужен прорыв, и этот прорыв должен быть сделан в области web, ибо достижения в других областях никто особо не оценит.

Так вот, я предлагаю вместо бесконечных споров, которые можно наблюдать в интернете, по поводу "мифических свойств" CL, и которые отбирают часы времени только на прочтение, - писать код, писать реальный код, писать реальный код для веб, и да, пусть это будет open source. Если вы хотите способствовать развитию и популяризации Common Lisp, то вы можете сделать это только через реальные проекты, ибо только код имеет ценность. Ну и конечно, надо избавляться от PHP и прочих подобных технологий на ресурсах, связанных с Common Lisp - любой должен быть в состоянии убедиться, что о CL можно не только рассуждать, но и писать на нём реальные системы.

P.S. Если ранее вы не занимались разработкой на Common Lisp для веб, но хотите попробовать - обращайтесь (можно здесь, но лучше на lisper.ru) - буду рад помочь.

среда, 2 декабря 2009 г.

closure-template-html-mode

На ELisp никогда не писал, но поскольку начал активно использовать cl-closure-template в своих проектах, то встала проблема редактирования файлов шаблонов и пришлось таки что-то придумывать, ибо редактировать как простой текст, мягко говоря, не очень удобно. По-началу использовал html-mode, но всё равно не то. Итак, мой первый опыт программирования на ELisp - closure-template-html-mode. Режим основа на sgml-mode и, пока, добавляет только подсветку синтаксиса шаблонов (с небольшими помарками), что, в принципе, тоже неплохо. Для полного (моего) счастья надо написать closure-template-indet-line, но для этого надо разобраться с работой sgml-indent-line, которая выглядит несколько устрашающе. Буду премного благодарен, если кто-нибудь сможет помочь с написание данной функции.

вторник, 1 декабря 2009 г.

restas-planet

Полностью отделил код планеты, используемой на lisper.ru, от кода rulisp, теперь это совершенно независимый restas-плагин. Его можно использовать для создания планеты как независимого приложения, так и в рамках какого-либо сайта. Вот простейший кода, использующий этот плагин:
(asdf:operate 'asdf:load-op '#:restas-planet)

(restas:defsite #:myplanet
(:use #:cl))

(in-package #:myplanet)

(restas:define-site-plugin planet (#:restas.planet)
(restas.planet:*feeds* #P"/path/to/feeds/description")
(restas.planet:*name* "My Planet"))

(restas:start-site '#:myplanet :port 8080)
В качестве значения restas.planet:*feeds* должен использоваться путь к файлу, подобному следующему:
(feed "http://swizard.livejournal.com/data/atom" :category "lisp")
(feed "http://lisp.tomsk.ru/wordpress/feed/")
Для настройки плагина можно использовать следующие параметры (все из пакета #:resas.planet):
  • *baseurl* - базовый url
  • *feeds* - путь к файлу с описаниями лент (см. выше)
  • *name* - имя планеты, по-умолчанию "PLANET"
  • *template* - функция генерирующая html-код, по умолчанию - 'restas.planet.view:feed-html
  • *schedule* - расписание обновления лент в формате библиотеки clon, по-умолчанию - '(:hour *) (обновление раз в час)
  • *cache-dir* - каталог для кэша, в том числе, кэша лент. Если не указан - кэш не используется.
Исходный код плагина доступен здесь: http://github.com/archimag/restas-planet
Патчи приветствуются (как и просто желающие принять участие в разработке).