Using named branches in Mercurial can be rather difficult especially when it gets to merging these branches. There are several useful techniques and process improvements that simplify the development/release loop. You can find some of them in the talk slides I did on Oct 11, 2012 here at Quickoffice(aka DoctorMobile). It doesn't restrain any development flow and can be useful for any Mercurial (or even non-Mercurial) user. For those who are not familiar with Mercurial at all I recommend to read some guides before looking at the slides. What every programmer should know about merging branches in Mercurial Sources for the slides can be found here
Thursday, October 11, 2012
Talk: What every programmer should know about merging branches in Mercurial
Posted by
Sergey Kishchenko
at
5:48 PM
0
comments
Labels: open source, python, программирование, советы
Wednesday, August 3, 2011
Kharkov DOU Hackathon - отчёт об участии
A hackathon, a hacker neologism, is an event when programmers meet to do collaborative computer programming(c) wikiВышеобозначеный хакатон проходил в Харькове 30-31 августа в соревновательном виде. За сутки нужно было написать что-нибудь интересное и команда Von Neumann Architecture в составе двух человек приняла вызов. В качестве задачи мы выбрали портирование Pascal игрушки 1994-го года на HTML5/JS посредством написания Haskell транслятора. Исходники здесь. Полноценный отчёт можно почитать здесь. Также можно посмотреть онлайн демку, демка доделывалась уже после Хакатона. Цитата:
Повторяю, вы видите как работает интерпретатор многопоточного (yield) Javascript, сконвертированного (via Haskell) из Turbo Pascal, сам интерпретатор Javascript-а "Rhino" написан на Java, портирован (via gwt + ножницы) в Javascript.
Внизу работающая программа, проверено под Chrome, Mozilla. Если в опере загрузить ее отладчик DragonFly, то там отчего-то тоже начинает работать.
Posted by
Sergey Kishchenko
at
11:55 AM
0
comments
Labels: contests, haskell, open source, программирование
Friday, April 1, 2011
Talk: (Non) Comprehensive Guide to C/C++ Source Code Quality
I did a talk on C/C++ source code quality tools here at Quickoffice. I believe it could be helpful for the C/C++/ObjC developers(especially for those who care about quality). Here goes the list of the tools mentioned:
- CPD
- gcc
- clang
- Valgrind
- cppcheck
- EDoc++
- GCOV
- gcovr
- LCOV
- avalanche
- frama-c
You can find LaTeX source and .cpp source files at github
Posted by
Sergey Kishchenko
at
7:00 PM
0
comments
Labels: C/C++, open source, tdd, программирование
Tuesday, July 7, 2009
Bachelor Thesis in Computer Science. Part 3. Слайды в LaTeX-beamer
Лучше поздно, чем никогда - предлагаю вам обещанную третью часть с описанием того, что есть LaTeX-beamer и как его можно использовать при написании бакалаврской работы.
beamer - класс LaTeX, который позволяет быстро создавать красивые слайды. Если вы не знаете, что это такое или ни разу не пробовали - попробуйте, и вам больше никогда не захочется запускать громоздкие системы WISIWYG для создания слайдов.
Основные достоинства beamer, на которые хотелось бы обратить внимание:
- Полное разделение оформления и содержания. Сначала пишите текст, а оформление можно сменить в любой момент
- Очевидный плюс, но забывать о нём нельзя: можно использовать все возможности LaTeX
- Красивые и удобные темы оформления "из коробки"
- Широкие возможности в настройке и доводке
Пример применения
Эта статья не задумывалась как учебное пособие по beamer, ее цель - дать представление и заинтересовать. Поэтому сразу перейдём к скриншотам и некоторым советам. Титульная страница, которую любезно сгенерирует вам beamer после заполнения некоторых полей:
Один из слайдов:
Как видите, слайды выглядят весьма привлекательно. К тому же, представьте, что каждый слайд - это всего пара строчек текста. А теперь, как я и обещал, несколько советов подкрепленные кодом:
- Не пытайтесь изменить шрифт, чтобы вместить на слайд как можно больше информации. Выполненные в PowerPoint с 12pt шрифтом презентации навевают тоску и абсолютно нечитаемы с расстояния в 5-10 метров. Если уж очень нужно разместить на слайде побольше, а количества строк не хватает - используйте двухколоночную вёрстку. Тогда даже большое количество формул может поместиться на один слайд:
Для верстки в две колонки используйте пакет multicol(на примере вставки изображений в две колонки):\usepackage{multicol}
%%....
\begin{multicols}{2}
\begin{figure}[!ht]
\begin{center}
\includegraphics[width=\columnwidth]{../img/positioning_slides1}
\end{center}
\end{figure}
\begin{figure}[!ht]
\begin{center}
\includegraphics[width=\columnwidth]{../img/positioning_slides2}
\end{center}
\end{figure}
\end{multicols} - Создатели тем оформления beamer не подумали, что название может быть длинным и сократить его будет нельзя. Поэтому во многих темах длинные названия не влазят на слайд. Однако это можно исправить - например, использование подправленной темы оформления, которую вы видели на скриншотах:
Этот небольшой сниппет может стать отправной точкой для написания собственных тем оформления - в нём совсем несложно разобраться по названиям команд\usetheme{Antibes}
\useinnertheme{rounded}
\setbeamertemplate{headline}
{%
\begin{beamercolorbox}[wd=\paperwidth,ht=6.5ex,dp=1.125ex,%
leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}
\usebeamerfont{title in head/foot}\parbox[b]{0.95\paperwidth}{\@title}
\end{beamercolorbox}
\begin{beamercolorbox}[wd=\paperwidth,ht=2.5ex,dp=1.125ex,%
leftskip=.3cm,rightskip=.3cm plus1fil]{section in head/foot}
\usebeamerfont{section in head/foot}%
\ifthenelse{\value{page}>1}{\hskip2pt\raise1.9pt\hbox{\vrule width0.4pt height1.875ex\vrule width 5pt height0.4pt}}{}
\hskip1pt%
\insertsectionhead
\end{beamercolorbox}
\begin{beamercolorbox}[wd=\paperwidth,colsep=1.5pt]{lower separation line head}
\end{beamercolorbox}
}
\setbeamertemplate{footline}
{%
\leavevmode%
\hbox{\begin{beamercolorbox}[wd=.5\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm plus1fill,rightskip=.3cm]{author in head/foot}%
\usebeamerfont{author in head/foot}\insertshortauthor
\end{beamercolorbox}%
\begin{beamercolorbox}[wd=.5\paperwidth,ht=2.5ex,dp=1.125ex,leftskip=.3cm,rightskip=.3cm plus1fil]{title in head/foot}%
\usebeamerfont{title in head/foot}Слайд \insertframenumber
\end{beamercolorbox}}%
\vskip0pt%
} - Скриптованные презентации никому не нужны. Я имею в виду моргающие анимированные слайды со сложной системой переходов, которые можно создать в Microsoft Office или OpenOffice. Для улучшения восприятия достаточно простейших эффектов, которых можно легко добиться в beamer. Единственной полезной вещи, которой может не хватать в beamer по сравнению с PowerPoint и Impress - воспроизведение видео. Однако встроить видео в PDF тоже можно! Пример:
Этот код отводит отдельный слайд под видео. Стоит отметить, что видео можно будет проиграть только в Adobe Reader (я не знаю свободных альтернатив, которые бы поддерживали видео). Также обратите внимание, что я использую внешний плеер. Использование внешнего плеера гарантирует максимальную кросс-платформенность вашего PDF документа\usepackage{movie15}
%%...
\frame
{
\includemovie[externalviewer]{}{}{../vid/mouse_emulation.avi}
}
Выводы
Используйте LaTeX, используйте beamer. Забудьте о медленных, неудобных офисных пакетах, полных недостатков и ошибок.
P.S.
Здесь вы можете найти исходники презентации (без изображений и видео)
Posted by
Sergey Kishchenko
at
2:00 AM
5
comments
Labels: linux, open source, советы, статьи
Wednesday, June 24, 2009
Django CouchDB backend 0.1
Не так давно стараниями 42cc была выпущена версия 0.1 бэкенда к CouchDB для Django ORM. Доступ к нему можно получитьна github, также есть трак. Так как я принимал в этом проекте весьма деятельное участие, то мне бы хотелось рассказать про него поподробнее.
Я не буду останавливаться на том, нужна или не нужна CouchDB. Вы можете прочитать об этом здесь или в google. Мне бы хотелось отметить один из недостатков CouchDB - он непривычен для людей, привыкших к реляционным базам данных, а следовательно, может показаться неудобным. Это и стало одной из причин разработки django-couchdb.
Основная цель разработки - позволить описывать взаимодействие приложений на Django с CouchDB на знакомом "языке" - на языке Django ORM. Для поверхностного использования не понадобится даже знания о том, что такое CouchDB - достаточно прописать backend в DATABASE_ENGINE и использовать его. Простейшие примеры того, что умеет django-couchdb(в виде теста):
class Boo(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField()
class Meta:
unique_together = ('title', 'slug')
class Foo(models.Model):
boo = models.ForeignKey(Boo)
boo2 = models.ForeignKey(Boo, related_name="foo2_set")
b1 = Boo(title="1", slug="1")
b1.save()
b11 = Boo(title="11", slug="1")
b11.save()
b2 = Boo(title="2", slug="2")
b2.save()
f1 = Foo(boo=b1)
f1.save()
f2 = Foo(boo=b2)
f2.save()
f3 = Foo(boo=b1,boo2=b2)
f3.save()
assert_equal(Foo.objects.filter(boo__title="1").count(), 2)
assert_equal(Foo.objects.filter(boo__title="11").count(), 0)
assert_equal(Foo.objects.filter(Q(boo__title="1") | Q(boo__slug="2")).count(), 3)
assert_equal(Foo.objects.filter(Q(boo__title="1") & Q(boo2__title="2")).count(), 1)
assert_equal(Foo.objects.filter(Q(boo__title="1") & Q(boo2__title="11")).count(), 0)
А именно: работает генерация "схемы" из моделей, insert, update, delete, select, joins(не все). Не работает - ManyToManyField, aggregates. Поэтому django.contrib(например, admin) работает, но не полностью.
Перспективы развития
Дальнейшее развитие будет вестись в нескольких направлениях:- Исправление недостатков, поддержка других возможностей ORM
- Развитие backend для использования сильных сторон CouchDB
- Увеличение производительности
Выводы
Получился очень удобный инструмент, скрывающий особенности реализации (JS, HTTP запросы). Спасибо за внимание, ожидайте новые версии и новые возможности :)
Posted by
Sergey Kishchenko
at
7:00 PM
7
comments
Labels: django, open source, python, новости, программирование
Tuesday, June 16, 2009
Bachelor Thesis in Computer Science. Part 2. Верстка в LaTeX
В предыдущей статье было дано краткое видеоописание программного продукта, который появился в результате написания бакалаврской работы. Во второй части хотелось бы рассказать про вёрстку диплома в LaTeX - ведь именно она заняла большую часть времени, которое я потратил на диплом(в несколько раз больше, чем было затрачено на программу :( ). Для нетерпеливых сразу дам ссылку на конечный вариант (в формате PDF) - скачать(~800kb).
Я уже как-то упоминал про LaTeX. С момента публикации той заметки, я занимался написанием и версткой диплома с использованием этого замечательного инструментария. Я не буду давать подробные описания, но хотелось бы отметить основные пункты. Cкачать исходные тексты можно здесь(~2mb).
Сборка
Для сборки я использовал scons. Рекомендую. Достаточно написать простейший Sconstruct файл:DEFAULT_TARGET = 'main.dvi'
env=Environment()
env.Alias('dvi', 'main.dvi')
env.Alias('pdf', 'main.pdf')
src=['main.tex','preamble.tex']
main_dvi = env.DVI('main.dvi', src)
main_pdf = env.PDF('main.pdf', src)
Default(DEFAULT_TARGET)После этого полная сборка выполняется командой scons или scons pdf.Класс
Для написания диплома был использован видоизменённый rusthesis класс - я назвал его uadiplom. Многие изменения, связанные с требованиями моего ВУЗа были учтены в нём, однако многое было сделано отдельно - с использованием дополнительных пакетов.Списки TODO
При написании диплома я пользовался замечательным пакетом todonotes, который и вам рекомендую попробовать. Для того, чтобы его использовать, понадобится:\usepackage[paperwidth=210mm,paperheight=297mm,left=25mm,right=35mm,top=2cm,bottom=2cm]{geometry} % нужно оставить поле справа
\usepackage[colorinlistoftodos, shadow, textwidth=3cm, textsize=tiny]{todonotes} % и установить размер пометок
\usepackage{hyperref} % для ссылок
\hypersetup{colorlinks=true, linkcolor=blue, citecolor=blue, filecolor=blue, urlcolor=blue}
Также для удобства я использовал такие команды:\newcommand{\toaddtext}[1]{\todo[color=green!40]{#1}}
\newcommand{\toaddref}{\todo[color=red!40]{Добавить ссылку}}
\newcommand{\torewrite}[1]{\todo[color=blue!40]{#1}}Эти команды можно использовать прямо в тексте. Чтобы сгенерировать список TODO, достаточно вставить команду \listoftodos. Предлагаемые todonotes выглядят красиво и очень удобны. Настройки заголовков
Одной из норм, которые приняты в моем ВУЗе, являются странноватые подписи к таблицам. А именно - подпись идёт сверху, в две строки, первая из которых - "Таблица ##" курсивом справа, а вторая - название таблицы жирным по центру. Для того, чтобы добиться этого, был использован пакет caption:\usepackage[labelsep=period,justification=centering]{caption}
\DeclareCaptionLabelFormat{uatablelabelformat}{\hfill\textit{#1~#2}}
\DeclareCaptionFormat{uatableformat}{#1#2\\#3}
\DeclareCaptionTextFormat{uatabletextformat}{\textbf{#1}}
\captionsetup[table]{format=uatableformat,labelformat=uatablelabelformat,textformat=uatabletextformat}Оформление библиографии
Был использован bibtex. Стиль - модифицированный gost780u (который я назвал uabib). Единственная модификация, которая понадобилась - изменение подхода к аббревиатурам.Оформление рисунков
Для вставки рисунков были добавлены простенькие шорткаты:\newcommand{\coolfigure}[3]{\coolwfigure{#1}{#2}{#3}{\textwidth}}
\newcommand{\coolwfigure}[4]{\begin{figure}[!ht]\begin{center}\includegraphics[width=#4]{#1}\end{center}\caption{#2}\label{#3}\end{figure}}Т.е., для вставки рисунка достаточно указать адрес изображения, название и метку.Оформление таблиц
Такой же шорткат был создан и для таблиц:\newcommand{\cooltable}[4]{
\begin{longtable}{#1}
\kill
\caption{#3\label{#2}}\\
\endfirsthead
\kill
\multicolumn{\LT@cols}{c}{\parbox{\textwidth}{\hfill \textit{Продолжение таблицы~\ref{#2}}}}\\
\endhead
#4
\end{longtable}}
Он принял такой вид, чтобы правильно обрабатывать разрывы страниц (с надписью "Продолжение таблицы ##" в правом верхнем углу). Назначение параметров можно понять по представленному коду.Выводы
LaTeX можно и нужно использовать при написании текстов со сложной версткой. Он очень удобен и обладает неоспоримыми преимуществами, среди которых одним из важнейших является возможность каскадных изменений. Основные неудобства связаны с нежеланием ВУЗов переходить на использование LaTeX. Например, в моем случае пример титулки был выдан в виде .DOC файла(поэтому официальную титулку я делал в OpenOffice, в предложенном архиве - заглушка), а пример рамок для плакатов - вообще в формате Visio. Что уж сетовать на неточность требований и неквалифицированность нормоконтролёра.Также одним из недостатков LaTeX является его сложность в некоторых вещах по отношению к WYSIWIG редакторам(к примеру, вспомните таблицы). Этот недостаток уравновешивается тем, что квалифицированную помощь всегда можно найти, например, в комнате #latex на freenode. Спасибо за внимание! В следующей части я расскажу про использование beamer для создания презентаций.
Posted by
Sergey Kishchenko
at
8:15 PM
0
comments
Labels: computer science, open source, советы
Friday, June 12, 2009
Bachelor Thesis in Computer Science. Part 1
Finally, my bachelor thesis has come to an end! And now I am going to publish the most interesting stuff I've done. Let me introduce you CamTrack, a simple OpenCV based tool that can be used to control your desktop using webcam. There is nothing breaking new in there (it is only a bachelor thesis and in Ukraine it is not something difficult). But I think, it can be a strong open source competitor to the CamSpace software.
You can find the source code on bitbucket. Or use direct link to download latest version. Don't hesitate to ask if you have any problems with installation.
If you're interested in this software or if you want to take part in it - please contact me.
Announcement for russian readers: I am also going to publish my thesis papers and give some suggestions about writing thesis using LaTeX. Stay tuned.
Posted by
Sergey Kishchenko
at
1:30 AM
4
comments
Labels: C/C++, computer science, open source, программирование
Wednesday, April 1, 2009
Links: tddspry, ItQuest.ru
Link 1. tddspry
Что такое tddspry? Это небольшой набор утилит для тестирования django-приложений с помощью nosetests. Если по какой-то причине Вы не можете воспользоваться Django Test-execution Framework или джанговские тесты просто Вас раздражают, то обязательно обратите внимание на этот небольшой проект. На данный момент в состав tddspry включены хэлперы для написания тестов, а также моки для БД и twill. В дальнейшем возможно включение поддержки Windmill, etc. Проект открыт для предложений. :)Пример использования:
class TestUI(TwillMock, DbMock):
def setup(self):
super(TestUI,self).setup()
login_to_admin(username='admin', password='admin')
@show_on_error
def test_order_add_no_transport(self): # ticket:9
go(SITE + '/shop/order/add/')
code(200)
assert not "Transport" in show(), show()
Link 2. ItQuest.ru
Возможно, многие из читателей уже слышали о таком сервисе, как ItQuest.ru. А если не слышали - обязательно обратите на него внимание. Ресурс идейно схож с StackOverflow - большая база вопросов и ответов на IT тематику. Так что если у Вас есть вопрос, ответ на который не знает даже Google, попробуйте задать его здесь.P.S. Сайт написан на Django. Еще один повод присмотреться.
Posted by
Sergey Kishchenko
at
3:30 AM
3
comments
Labels: django, open source, python, tdd, web, интернет, программирование
Sunday, March 22, 2009
Настройка удобного переключения раскладки клавиатуры для трёх и более языков
Многие пользователи ПК пользуются всего двумя раскладками клавиатуры - для родного и для английского языка. Если Вы привыкли к использованию двух раскладок, то переход на использование трёх или более раскладок может быть очень болезненным: Вы будете случайно попадать не на ту раскладку, писать белиберду и страшно ругаться. Для того, чтобы облегчить себе жизнь с тремя и более раскладками(у меня английская, русская и украинская), я настроил такую схему переключения раскладок: левый Shift + левый Ctrl переключает между первой и второй раскладкой, а правый Shift + правый Ctrl переключает циклически все раскладки. Так как обычно я переключал раскладку левой рукой, то привычная комбинация введением новых раскладок нарушена не была, при этом сохранилась возможность перейти на любую добавленную раскладку.
Основным источником информации для меня стал вот этот сайт. Ниже руководство для нетерпеливых :)
Итак, первым делом скажу, что я не захотел полностью следовать советам с указанного выше сайта, так как предложенный там способ задания конфигурационных файлов предполагал редактирование xorg.conf, а также добавление собственных конфигурационных файлов в папки настроек Xorg. Таким образом, я пошел по пути наименьшего сопротивления и моё решение - "fast and dirty".
В данном руководстве я предполагаю, что переключение раскладок по Shift + Ctrl уже настроено, все раскладки уже добавлены. Начнём с того, что получим текущую настройки XKB:
xkbcomp :0, где :0 - id вашего X Display (скорее всего он у вас :0). Эта команда создаст файлик server-N.xkb , где N - указанный Вами id. Откройте этот файлик и найдите там описание символов ISO_Next_Group, ISO_Prev_Group, ISO_First_Group и ISO_Last_Group. У меня описания выглядят примерно так:
interpret ISO_Next_Group+AnyOfOrNone(all) {
virtualModifier= AltGr;
useModMapMods=level1;
action= LockGroup(group=+1);
};
interpret ISO_Prev_Group+AnyOfOrNone(all) {
virtualModifier= AltGr;
useModMapMods=level1;
action= LockGroup(group=-1);
};
interpret ISO_First_Group+AnyOfOrNone(all) {
action= LockGroup(group=1);
};
interpret ISO_Last_Group+AnyOfOrNone(all) {
action= LockGroup(group=2);
};ISO_Next_Group, ISO_Prev_Group, ISO_First_Group и ISO_Last_Group - это специальные символы, которые как раз и отвечают за переключение раскладок. В варианте указанном выше ISO_Next_Group переключает на следующую раскладку, ISO_Prev_Group - на предыдущую, ISO_First_Group - на первую, а ISO_Last_Group - на вторую. Осталось переназначить клавиши, чтобы они указывали на другие символы. Дифф для трёх раскладок (для четырёх и более - добавятся новые группы):keyТ.е, заменим для комбинации клавиши LFSH + LCTL символ ISO_Prev_Group на ISO_First_Group и ISO_Last_Group в зависимости от раскладки.{ [ Return ] };
- key{ [ Control_L, ISO_Prev_Group ] };
+ key{
+ symbols[Group1]= [ Control_L, ISO_Last_Group ],
+ symbols[Group2]= [ Control_L, ISO_First_Group ],
+ symbols[Group3]= [ Control_L, ISO_First_Group ] };
key{
type= "ALPHABETIC",
symbols[Group1]= [ a, A ],
@@ -1262,7 +1265,9 @@ xkb_symbols "pc+us+ru(winkeys):2+ua(wink
};
key{
type= "PC_CONTROL_LEVEL2",
- symbols[Group1]= [ Shift_L, ISO_Prev_Group ]
+ symbols[Group1]= [ Shift_L, ISO_Last_Group ],
+ symbols[Group2]= [ Shift_L, ISO_First_Group ],
+ symbols[Group3]= [ Shift_L, ISO_First_Group ]
};
После того, как Вы отредактировали файл, осталось залить настройки. Делается это так:
xkbcomp file.xkb :0, где file.xkb - ваш сохранённый файл, а :0 - display id.
Хочу отметить, что при перезагрузке иксов все ваши настройки сбросятся. Т.е., для того, чтобы настройки загружались при старте, их надо добавить в автозагрузку. Минус такого подхода в том, что если обновить X Server, то настройки могут стать несовместимыми и иксы могут зависать. Поэтому я просто добавил шорткат для применения настроек и запускаю его тогда, когда мне нужно.
Еще один важный момент: xkbcomp перезаписывает все настройки. Т.о., если Вы переназначите какие-нибудь клавиши через xmodmap, то Вам нужно будет заново создавать файл настроек, иначе при применении настроек сделанные через xmodmap переназначения пропадут. Удачи с настройкой!
Posted by
Sergey Kishchenko
at
5:00 PM
2
comments
Labels: linux, open source, советы
Monday, March 2, 2009
Reia - скриптовый язык для виртуальной машины Erlang`а
Лично я считаю Erlang одним из самых простых яызков программирования, а среди знакомых мне функциональных языков - самым простым. К тому же на Erlang благодаря его направленности на создание конкурентных приложений написано уже множество проектов, таких как Yaws, CouchDB, ejabberd, которые являются для него наилучшей рекламой.
Таким образом, Erlang - функциональный язык с простым и понятным синтаксисом, который нашёл свою нишу, и если вы интересуетесь созданием масштабируемых конкурентных систем - вам стоит выучить его. Однако из-за того, что Erlang - функциональный, его синтаксис и стиль понятен не всем - он слишком отличается от императивных языков(таких как С и подобные) и даже от Ruby/Python, которые включают в себя частицы функционального подхода.
Если Вы столкнулись с такой проблемой - обратите внимание на Reia - скриптовый Ruby/Python like язык для виртуальной машины BEAM(эта виртуальная машина используется также и в Erlang). Язык Reia совместим с Erlang и может использоваться для создания конкурентых приложений, однако используя при этом скриптовый синтаксис. Вот простейший пример:
module FooРезультат:
def bar
receive
when msg
["Received ",msg].join().puts()
bar()
pid = Process.spawn(fun {Foo.bar()})
pid ! "Hello"
pid ! "World"
Received HelloВ язык заложено очень много возможностей(как по мне - слишком много :) ): отсылка сообщений процессам и объектам, встроенные регулярные выражения, pattern matching, асинхронные вызовы функции, лямбда функции, а также многое-многое другое. Многое из этого не реализовано(например, циклы), но часть функциональности уже существует и работает, как можно увидеть из примера.
Received World
Выводы
- Reia - многообещающий ЯП, которому, однако, не хватает разработчиков. Возможно, если реализации будет уделяться больше времени, то этот ЯП станет мостиком, по которому толпы приверженцев императивного подхода ринутся в страну Erlang
- Как по мне, синтаксис Reia перегружен. Этот вывод только подкрепляет моё убеждение, что Erlang - отлично спроектирован и очень элегантен
Posted by
Sergey Kishchenko
at
1:15 PM
2
comments
Labels: erlang, open source, python, ruby, программирование, статьи
Wednesday, February 25, 2009
app-engine-patch 1.0 is out!
Не далее как 24-го февраля сего года увидела свет новая версия одной незаменимой вещи для разработки под Google AppEngine, а именно app-engine-patch.
Кажется, ничего особенного на этом скриншоте нет - всего лишь Django admin интерфейс. Однако, я не зря запостил этот скриншот - это админка Django запущенная под app-engine-patch! Теперь и под GAE можно получить эту "killer" feature Django. Об остальных нововведениях можно прочитать здесь. Меня особенно радует, что портировано django.contrib.sites, однако пока я не могу заставить django.contrib.sitemaps работать.
P.S. Еще два поинта, на которые я хотел бы указать. Во-первых, планы на будущее - "Native Django support (including Model class)."(с). Во-вторых, появилась некая тулза, которая пытается проверять импорты на правильность(кто сталкивался со страшными ошибками при случайных рекурсивных импортах - поймёт, насколько это хорошо :) )
Posted by
Sergey Kishchenko
at
1:25 PM
0
comments
Labels: django, open source, python, новости, программирование
Tuesday, February 10, 2009
Знакомьтесь: Geany!
Введение
Я уже писал, что мне очень нравится редактор SciTE и поэтому я его постоянно использую, например, при программировании на Python. Однако в GTK версии есть несколько недостатков:- Открытие большого числа вкладок невозможно - не работает прокрутка и multiline
- Глюки с юникодом - если написать \что-то при редактировании TeX документа, получим несуразные символы. Эти же несуразные неудаляемые символы также иногда появляются в строке поиска
- Нет нормальной интеграции с shell. В итоге для простейшей проверки конструкции в ipython приходится переключаться на терминал

На этом скриншоте он уже немного подконфигурирован для моего удобства. Возможности Geany:
- Подсветка, фолдинг - аналогично SciTE
- Нормальные табы
- Поддержка VTE
- Symbol explorer
- Плагины(в числе встроенных FileBrowser, SplitWindow и т.д.)
- Автодополнение по символам(неплохое, но для Python хотелось бы лучше. Geany - Open Source, так что возможно это желание будет реализовано)
- Автозакрытие тегов
- Сессии
Конфигурирование
В этом разделе я хочу дать описание моего рабочего окружения в Geany. Оно не блещет уникальностью, но весьма удобно. Конечный внешний вид - на скриншоте выше. По пунктам:- Ставим. Я просто выполнил "emerge -av geany". Думаю, в остальных Linux дистрибутивах его можно поставить сходным же образом. Для Windows пользователей - есть инсталляторы
- Убираем Sidebar, дабы сэкономить площадь
- Задаем комбинации клавиш для удобного перемещения по табам
- Настраиваем терминал - самая интересная часть. Я выбрал себе темную темку и запустил внутри screen - в итоге я могу переключаться между логами сервера, ipython и дополнительными консолями. Для меня терминал в Geany - самый важный инструмент. В нём я работаю с git и hg, в нём я отлаживаю приложение, в нём же я и лажу по файлам("geany file_name" открывает файл в новой вкладке). Таким образом, терминал мне заменяет File Browser, Debugger и VCS Inegration
- Настраиваем шрифт, остальные комбинации клавиш и интерфейс по вкусу
bindkey -d ^@ stuff ^? # пофикс backspaceДо сих пор нормально не работает скролл на мышке, прокрутка вверх генерит "^[[A". Если у кого-то есть уже решение - поделитесь :) Если разберусь сам - проапдейчу.
hardstatus on
hardstatus alwayslastline
hardstatus string "%{Gk}| %-w%{+u}%n %t%{-}%+w |%=(%l) %d/%m %c"
Выводы
Geany - отличный редактор, полностью покрывающий мои запросы. На данный момент я использую его для Python разработки и редактирования TeX файлов. Для С++ же я предпочитаю IDE Anjuta, хоть Geany можно использовать и здесь.
Posted by
Sergey Kishchenko
at
10:45 PM
9
comments
Labels: open source, программирование, статьи
Wednesday, January 28, 2009
Debugging with app-engine-patch and pdb
If you ever tried to use pdb in application written using app-engine-patch, you should notice, that pdb is not working here at all. All pdb output is shown directly in browser. Thanks to Antonin Hildebrand from this thread now we have a way to use pdb for debugging GAE applications. Use following code to put trace in your app:
def b():For me it worked without any dev_appserver.py patches. Try it out!
import pdb, sys
sys.__stdout__.write('\a')
sys.__stdout__.flush()
debugger = pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__)
debugger.set_trace(sys._getframe().f_back)
#...
#...
##########################
b()#here I want to start tracing
Posted by
Sergey Kishchenko
at
11:23 PM
0
comments
Labels: django, open source, python, программирование
Monday, January 12, 2009
C++: Как поймать опасные исключения
Существует множество мнений по поводу механизма исключений: некоторые называют исключения "скрытым goto", другие же считают исключения отличным механизмом и предлагают его использовать везде и всегда. Единственное, с чем согласны все - исключения нужно использовать с особой осторожностью. Ведь даже с виду совсем безобидный код может привести к тому, что ваше приложение упадёт в самый неподходящий момент.
С++, как многим известно, предоставляет некий механизм спецификации исключений - exceptions spectifications(п.15.4), простейший пример которого представлен ниже:
void foo() throw(Exception1, Exception2)В этом небольшом примере функцию foo описывают как функцию, которая может бросить исключения Exception1 и Exception2. Однако, как пишут в Boost Requirements and Guidelines:
{
//...
}
The biggest problem with exception-specifications is that programmers use them as though they have the effect the programmer would like, instead of the effect they actually have.или
Основная проблема со спецификацией исключений в том, что программисты используют их, как будто они работают так, как этого хочет программист, а не так, как они действуют на самом делеДействительно, попробуйте в функции foo бросить исключение Exception3 и скомпилировать при помощи GCC(другие компиляторы я не использую, но думаю, что они действуют также). Ничего не произошло? И у меня то же самое :)
Т.е., спецификация исключений - вещь относительно бесполезная, а иногда и вредная(некоторые компиляторы не инлайнят функции с exception specifications). Существует много тредов-обсуждений в листе рассылки GCC по поводу возможности вывода предупреждений о несоответствующем спецификации использовании исключений(вот это сообщение - самое полезное, по-моему). В конце концов, подобные запросы отклоняются, ибо "невозможно реализовать из-за сложности межпроцедурного анализа. GCC не предназначен для такого".
Однако, это не остановило проект EDoc++, о котором и хотелось бы рассказать подробней. Он использует пропатченный GCC для анализа кода на ошибки при использовании исключений. Например, у нас есть код:
#include <iostream>
class C1{};
class C2{};
void foo() throw (C1)
{
throw C2();
};
class C
{
public:
~C()
{
foo();
}
};
int main()
{
C c;
}
В этом примере есть несколько ошибок, связанных с исключениями:
- Не соблюдается спецификация в функции foo
- Бросается исключение из деструктора
- Исключение выходит за функцию main, что приводит к аварийному завершению программы
EDOC -> g++ -fedoc-source -c ~/dev/sandbox/t.cpp -o ~/dev/sandbox/t.oEDoc++ создает дополнительный файлик, который при опции -fedoc-source попадает в ~/dev/sandbox/t.cpp.edc. Показываем полученные результаты:
EDOC -> edoc --show-all --format simple ~/dev/sandbox/t.cpp.edcКажется, лучше сообщение об ошибке и не укажешь. Исправим ошибку - будем делать throw C1; вместо throw C2;. Перекомпилируем и посмотрим:
F: _GLOBAL__D__Z3foov()
F: _GLOBAL__I__Z3foov()
F: foo()
F: __static_initialization_and_destruction_0(int, int)
F: C::~C()
F: main()
ERROR(ECRASH_SPEC): Exception may propogate through restrictive specifier :The function: foo() can throw an exception of type: C2 that is not allowed by its specifier list: throws(C1)
EDOC -> edoc --show-all --format simple ~/dev/sandbox/t.cpp.edcАга! Мы чуть-чуть не упустили исключение за пределы деструктора. Это ужасно. Уберём наконец throw С1; из foo для того чтобы проверить, как EDoc++ отреагирует на спецификацию без реального выбрасывания исключений:
[...skip...]
ERROR(EMAIN_EXC): An exception may propogate out the main function. :The exception: C1 may propagate out the main function which may cause a program abort.
WARNING(WDESTR_EXC): An exception may propogate through a destructor. :Destructor: C::~C(), Exception: C1
EDOC -> edoc --show-all --format simple ~/dev/sandbox/t.cpp.edcМолчит. Т.е., он не принимает во внимание спецификации, если эти спецификации врут, что, в принципе, правильно.
[...skip...]
EDoc++ обладает еще множеством достоинств: он поддерживает множество форматов вывода, множество способов хранения .edc информации, судя по отличной документации он правильно работает с указателями на функции, которые бросают исключения, и умеет находить ошибки даже в тех случаях, когда они делятся между несколькими модулями компиляции. В общем, отличный инструмент, спасибо создателям :)
Posted by
Sergey Kishchenko
at
3:00 PM
2
comments
Labels: C/C++, open source, программирование, статьи
Wednesday, December 10, 2008
SciTE incremental autocompletion
I am a big fan of these "holy" editors, like vim and emacs (yes, I use both). But I am also a big fan of SciTE - simple text editor for developers. It is not so popular like vim or emacs, but I like it. So I decide to improve one of its features - autocompletion. I called the result "Incremental autcompletion". Look at this video:
Isn't it cool? I think it is :) If you like it, you can use this patchset. To use feature after applying patches and compiling, just add "autocompleteword.incremental=1" to the properties file.
I started a thread in scite-interest group. I hope, this feature will be accepted by Neil Hodgson (SciTE and Scintilla creator), because for me it is acceptable open source alternative for some of Visual Assist autocompletion features.
UPD 1. Don't forget to add all of these lines
autocompleteword.automatic=1
autocomplete.choose.single=0
autocompleteword.incremental=1to your properties file.UPD 2. Frank Wunderlich noticed the bug in implementation. Please use the second version of patch
Posted by
Sergey Kishchenko
at
6:00 PM
2
comments
Labels: C/C++, open source, программирование
Friday, November 14, 2008
Об отношении к вышестоящим
Этот пост несколько дней лежал неопубликованным, потому что я не решался опубликовать эти субъективные размышления, так как они существенно отличаются от тематики предыдущих публикаций. Но сегодня случайно наткнулся на эту статью. Кому легче читать на русском(статья достаточно эмоциональна, а эмоции легче воспринимаются на родном языке) - вот здесь я видел перевод.
После прочтения статьи я стер всё, что написал ранее, потому что не cмог так точно передать свои мысли. Я прочел в этой статье не ненависть к "проприетарному миру", а увидел в ней свою же ненависть к людям, которые обществом ставятся выше меня. Это и начальство, которое мне как назло попадается недалекое. И различные менеджеры, утратившие(или никогда и не имевшие) способность созидать. И преподаватели, которые откровенно глупы. И вся эта кодла бюрократов, официалов, authorities и проч.
У каждого человека есть своя цена. И как неприятно ощущать, что твои познания о ценообразовании никуда не годны, и в реальном мире стоимость человека определяется по параметрам, которые тебе или непонятны, или, что нередко, отвратительны.
Posted by
Sergey Kishchenko
at
1:15 PM
2
comments
Labels: open source, личное, программирование, размышления
Monday, October 20, 2008
Произносим числа словами, альтернатива SayNumber в Asterisk
Казалось бы, совсем детская задачка - имея на входе число, например, 42, получить на выходе строку символов - "сорок два". Вот и в Asterisk(программная АТС с открытым исходным кодом) есть встроенная функция SayNumber, которая "произносит"(проигрывает) число в канал. На самом деле, это ничем не отличается от простого преобразования числа в последовательность слов - Asterisk просто проигрывает звуковые файлы, которые имеют соответствующие словам названия.
Asterisk предоставляет простейшую функциональность по локализации звуковых файлов - вместо стандартной озвучки можно подставить свою, например русскую. И тогда 42 будет произноситься не как "fourty two", а как "сорок два". Однако, такая локализация не полная - при ближайшем рассмотрении можно заметить, что в русском языке числа произносятся совсем не так, как в английском. Например, 201 произносится как "двести один", а не как "два сотня один". Более того, в русском языке есть еще падежи, единственное/множественное число, мужской/женский/средний род. И когда нужно произнести что-то вроде "одна тысяча четыреста один рубль" или "две тысячи сорок пять рублей", встроенные средства совсем не подходят.
На voip-info.org даже есть ссылка на альтернативную реализацию SayNumber, которая настраивается через конфигурационные файлы(на voip-info.org неправильная ссылка, правильная на данный момент - альтернатива SayNumber от www.beronet.com ). Однако она реализована на С, в виде модуля, так что слабо портируема между версиями Asterisk: я не смог использовать ее в Asterisk 1.4.x. И тогда мне пришла в голову мысль написать свою альтернативную реализацию. В качестве требований выступили:
- Возможность гибкой настройки(решение: использовать конфигурационные файлы)
- Переносимость между версиями, удобство установки и использования(решение: использовать механизм AGI)
- Элегантность (решение: использовать Python :) )
Или без подсветки: Plain text.
Я старался комментировать и документировать код, чтобы он был прост и понятен. Также надеюсь, что он оказался достаточно элегантен (любые замечания или исправления приветствуются). Осталось только показать, как его использовать:
exten => _X.,n,AGI(pysaynumber.agi|42r|ru.conf), где pysaynumber.agi - название скрипта, 42r - что надо произнести, ru.conf - название конфигурационного файла.
Конфигурационный/ные файлы нужно положить рядом с pysaynumber.agi в agi-bin (его местоположение разнится в зависимости от места установки Asterisk)
Пример конфигурационного файла: здесь
Формат конфигурационного файла. Частично позаимствован из наработок www.beronet.com. Каждая строка состоит из двух частей, разделенных ":". Первая часть - регулярное выражение, без начального "^" и конечного "$"(они подставляются автоматически). Вторая часть - список действий, разделенных ";". Алгоритм прост - идем подряд по всем правилам и если находим match с номером, который мы желаем "произнести", то выполняем подряд все действия по соответствующему списку. Видов действий три. Если строка действия представляет собой конечное "слово" (например, rublei, 40), то мы просто "произносим" его. Если строка действия начинается с number, то это второй тип действия. Параметры указываются в скобках, вот так - (индекс|суффикс). При выполнении этого действия "произносится" конечное "слово", составленное из символа, который находится в исходном номере по индексу и суффикса. Третье действие - recursive. Параметры - (индекс[,индекс...]|суффикс). Запускает весь алгоритм рекурсивно, но уже для номера составленного из символов, которые берутся из исходного номера по индексам, и суффикса.
Приведенный мной код может использоваться не только для Asterisk(проверялось на Asterisk 1.4.18.1), а и для других нужд. Также для того, чтобы ускорить работу скрипта можно использовать FastAGI, тогда можно будет хранить таблицу уже проинициализированной и не запускать интерпретатор каждый раз заново.
UPD. Используйте FastAGI. По непонятной причине подобным образом написанные скрипты приводят к подвисанию Asterisk со 100% загрузкой процессора. С применением FastAGI таких проблем не наблюдалось.
Posted by
Sergey Kishchenko
at
1:00 PM
4
comments
Labels: open source, python, voip, программирование
Friday, August 22, 2008
Использование Boost Python
“...one of the most highly regarded and expertly designed C++ library projects in the world.”Действительно, библиотека Boost - это живой пример того, насколько С++ может быть крут. И Boost.Python - не исключение.
— Herb Sutter and Andrei Alexandrescu, C++ Coding Standards
Итак, Boost.Python - это библиотека, которая позволяет писать на С++ модули-расширения для Python, а также использовать возможности Python из С++. Зачем это может быть нужно? Например,
- Переписывание bottlenecks на С/C++
- Сокрытие части реализации в компилируемом модуле(весьма важно для распространениея коммерческих приложений)
- Использование существующих библиотек(как на С/С++, так и на Python)
Этим постом я не хочу повторять документацию по Boost.Python. Я ставлю целью скорее показать мощность Boost.Python и то, как он преобразует все вокруг :) И так как код - лучшая демонстрация, то я буду использовать фрагменты кода с пояснениями.
Итак, простейший модуль-расширение на С++:
#include <boost/python.hpp>
using namespace boost::python;
struct World
{
World(std::string msg_): msg(msg_) {}
std::string greet()
{
return msg;
}
std::string msg;
};
BOOST_PYTHON_MODULE(имя_модуля)
{
class_<World>("World", init<std::string>())
.def("greet", &World::greet)
;
}Этот пример должен быть знаком тем, кто заглядывал в документацию. В нем ничего сложного нет - наш модуль включает в себя класс с конструктором и одной функцией. Предлагаю его взять в качестве основы и добавлять в него фрагменты ниже. Но сначала - как собирать этот пример. Предлагаю сохранить этот файл как имя_файла.cpp, после этого сборка может производиться при помощи gcc так:gcc -shared -Wl,-soname,имя_модуля.so -o имя_модуля.so имя_файла.cpp -I /usr/include/python2.5/ -lboost_pythonОбратите внимание, что имя_модуля должно совпадать с именем, указанным в файле. Также я использую python2.5. Тем, кто использует другую версию, нужно также поменять номер версии в пути для include.Естественно, модуль не обязан состоять из одного файла, однако для сборки больших проектов рекомендую использовать distutils. Документация по нему достаточно подробная, чтобы собрать любой модуль. Самое главное - не забыть в описание Extension включить libraries=['boost_python'], а также указать то же имя Extension, что и внутри файлов используется.
После того, как простейший модуль собран и опробован,
In [1]: from имя_модуля import World
In [2]: w = World("Hello!")
In [3]: w.greet()
Out[3]: 'Hello!'
, можно приступать к самому интересному - к полезным обрывкам кода:/*добавим две функции к World, "экспорт" их описывать не буду, можно по аналогии*/
void set(std::string msg) { this->msg = msg; }
void anotherWorldSet(World * world, std::string msg)
{
world->set(msg);
}Проверяем:In [1]: from hello_ext import World
In [2]: w1 = World("w1")
In [3]: w2 = World("w2")
In [4]: w1.anotherWorldSet(w2,"w2_new")
In [5]: w2.greet()
Out[5]: 'w2_new'Т.е., Boost.Python прекрасно понимает, когда вы хотите получить объект по значению, а когда по ссылке. Более того, можно использовать и ссылки (void anotherWorldSet(World& world, std::string msg);) - разницы нет. Дальше перейдем к самому интересному - к boost::python::object. Это класс, который эмулирует работу Python объекта. Вот так, например:void anotherObjectSet(object obj, std::string msg)
{
obj.attr("set")(msg);
}И это работает, также как и предыдущий вариант. Обратите внимание на метод attr(). Его можно использовать как для вызова методов(см. выше), так и для получения значений:std::string get_version()
{
/*Так импортятся Python модули. В качестве имени можно использовать и разделенные точкой названия*/
object sys = import("sys");
return extract<std::string>(sys.attr("version"));/*так преобразуются Python объекты в С++ объекты*/
}
std::string get_some(object myObj,std::string str)/*еще один пример*/
{
return extract<std::string>(myObj.attr(str.c_str()));
}Раз уж зашла речь о Python объектах, то стоит рассказать о Python str и dict объектах:dict foo_dict()
{
dict result;
result["1"]="2";
result["2"]="3";
return result;
}
object foo_string()
{
char buf[12]={0};
sprintf(buf,"%08XHELP",4242);
str s(buf,12);/*12 - длина строки*/
std::vector m;
m.push_back('1');m.push_back('2');m.push_back('3');m.push_back('4');
s += str(&m[0],m.size());
s += str("super test 2",12);
return s;
} Т.е., работать с dict и str - одно удовольствие. Идем дальше, одна из пречудеснейших возможностей:object get_func()
{
return make_function(&World::func);/*make_function - это чистая магия :)*/
}
std::string func()
{
return "I am func!";
}Использование предыдущих фрагментов я не демонстрировал из Python, так как они очень просты. Представленный выше фрагмент ничуть не сложнее, но я все же покажу, как его использовать:In [1]: from hello_ext import World
In [2]: w = World("Hello")
In [3]: f = w.get_func()
In [4]: f(w)
Out[4]: 'I am func!'Обратите внимание на вызов f(w), здесь w - это self.В общем, основные моменты я осветил. Многое еще можно найти в документации, во многом можно положиться на Boost.Python - он работает именно так, как вы от него ожидаете(например, C++ исключения транслируются в Python и т.д.).
Отдельно хочется упомянуть о нескольких важных вещах, которые могут привести к ошибкам:
- В документации прекрасно описано наследование в Python от С++ классов. Однако, если вы переопределяете конструктор - обязательно вызывайте конструктор базового класса, даже если в базовом С++ классе он тривиален. Пренебрежение этим может вызвать непонятные ошибки
- Если вы передаете Python объект по ссылке в С++ модуль, а потом сохраняете его там для дальнейшего использования - помните, что ссылка может стать невалидной - Python GC может и удалить его, если ссылка останется лишь в С++ части
Ну, и на десерт. Если вы используете совместно С++ и Python модули (например, С++ модули используются для сокрытия функционала) и если вы используете логгирование, то скорее всего, вам захочется, чтобы логгирование всех модулей велось однотипно. Очень удобно было бы для этого использовать стандартный Python модуль logging. Чтобы было легче использовать этот модуль из С++, я написал небольшой класс:
/*----------------------------------------*/
/*logging.hpp*/
/*----------------------------------------*/
#pragma once
#include <boost/python.hpp>
#include <map>
#include <string>
class Logging
{
public:
static boost::python::object getLogger(const std::string& name);
static boost::python::object debug(const std::string& name);
static boost::python::object info(const std::string& name);
static boost::python::object warning(const std::string& name);
static boost::python::object error(const std::string& name);
static boost::python::object critical(const std::string& name);
static boost::python::object log(const std::string& name);
private:
typedef std::map<std::string,boost::python::object> LoggersMap;
static LoggersMap m_LoggersMap;
};
/*----------------------------------------*/
/*logging.cpp*/
/*----------------------------------------*/
#include "logging.hpp"
Logging::LoggersMap Logging::m_LoggersMap;
boost::python::object Logging::getLogger(const std::string& name)
{
static boost::python::object logging = boost::python::import("logging");
static boost::python::object settings = boost::python::import("conf.settings");/*Допустим, здесь хранятся настройки, в том числе и настройки логгирования*/
LoggersMap::iterator it = m_LoggersMap.find(name);
if(it != m_LoggersMap.end())
{
return (*it).second;
}
else
{
boost::python::object logger = logging.attr("getLogger")(name);
boost::python::object level = settings.attr("LOG_MODULES")[name];/*LOG_MODULES - dict, который ставит имя в соответствие с logging level*/
logger.attr("setLevel")(level);
m_LoggersMap[name] = logger;
return logger;
}
}
boost::python::object Logging::debug(const std::string& name)
{
return getLogger(name).attr("debug");
}
boost::python::object Logging::info(const std::string& name)
{
return getLogger(name).attr("info");
}
boost::python::object Logging::warning(const std::string& name)
{
return getLogger(name).attr("warning");
}
boost::python::object Logging::error(const std::string& name)
{
return getLogger(name).attr("error");
}
boost::python::object Logging::critical(const std::string& name)
{
return getLogger(name).attr("critical");
}
boost::python::object Logging::log(const std::string& name)
{
return getLogger(name).attr("log");
}
Использовать этот код очень просто:Logging::getLogger("SomeLogger").attr("debug")("1.Logging stuff %s %s\n","1","2");
Logging::info("SomeLogger")("2.Logging stuff %s %s\n","1","2");
Logging::debug("SomeLogger2")("3.Logging stuff %s %s\n","1","2");
Logging::warning("SomeLogger")("4.Logging stuff %s %s\n","1","2");
Logging::error("SomeLogger2")("5.Logging stuff %s %s\n","1","2");
Logging::critical("SomeLogger2")("6.Logging stuff %s %s\n","1","2");Спасибо за внимание! Буду рад любым исправлениям, корректировкам и дополнениям.
Posted by
Sergey Kishchenko
at
12:00 PM
8
comments
Labels: C/C++, open source, python, программирование, статьи
Tuesday, July 29, 2008
Совместное редактирование исходных текстов
Многие знают про технику парного программирования: это когда два программиста работают за одним компьютером, причем один набирает текст, а второй следит за ошибками и поправляет, периодически они меняются. Основной плюс данного подхода - в общении между членами команды (перечислять все преимущества не буду, читайте тут). С другой стороны, при таком подходе частенько хочется отобрать клавиатуру и написать быстренько самому, чем словами объяснять коллеге, что вы хотите.
Решений этой проблемы несколько. Некоторые стараются привнести идею парного программирования в обычную командную разработку, настаивая на регулярных мини-миттингах и "небольших" коммитах. Нельзя сказать, что этот способ плох, но все же он предполагает разделение задач между участниками команды.
В этой статье я хочу описать опыт использования инструмента для совместного редактирования кода Gobby - как по мне, это практически идеальное решение для парного программирования. Возможно, для кого-то из читателей это будет в новинку.
Итак, что такое Gobby - это бесплатный инструмент для совместного редактирования текста, который позволяет работать с несколькими документами одновременно, в котором есть чат и который работает во всех основных операционных системах (Linux, MacOS X, Windows, *nix). В действительности, Gobby - это просто редактор, который поддерживает технику парного(и более) программирования - только теперь вместо одной клавиатуры на всех у каждого программиста есть своя собственная.
Собственно об опыте использования: это невероятно! :) По пунктам:
- Еесли твой коллега находится далеко, то не нужно постоянно переключаться из окна IM мессенджера в окно редактора - все видно тут же.
- Смотреть, как появляется из ниоткуда исходный текст - это невероятно интересно!
- Очень удобно, что можно одновременно проверять работоспособность кода на разных машинах.
- Программистов может быть и не два, а больше, при этом так как вклад каждого отображается цветом, не запутаешься (в отличие от систем контроля версий, в которых выяснить, чья же это строчка кода, бывает трудно)
- Довольно удобный редактор с подсветкой синтаксиса без лишней функциональности
Скриншоты можно посмотреть здесь: http://gobby.0x539.de/trac/wiki/Screenshots
Чего не хватает: думаю, весьма полезен был бы централизованный сервер, на котором можно было бы любым желающим создавать сессии.
Аналоги: я не задавался целью найти что-нибудь аналогичное Gobby. Насколько мне известно, Eclipse поддерживает совместную работу. За любые указания на другие аналоги буду благодарен.
Posted by
Sergey Kishchenko
at
1:20 PM
3
comments
Labels: open source, программирование, статьи
Monday, June 9, 2008
Апплет для Gnome на Python
Постановка задачи.
Как и многим другим разработчикам, мне приходится контролировать затраченное на работу время - для написания тайм-репортов и даже просто самоконтроля. Конечно, можно было бы использовать готовые приложения, например Gnome Time Tracker, но у всех подобных программ есть один существенный для меня недостаток - они требуют к себе слишком много внимания. К тому же, на моих предпочтениях сказывается и специфика работы - я работаю в офисе на постоянной основе, а отчеты составляю лишь к концу месяца, при этом особая детализация в этих отчетах не требуется - нужно лишь предоставить временные интервалы. Т.о., мне нужно небольшое приложение, при помощи которого я смог бы легко записывать время прихода и ухода. Задача действительно тривиальна, написание подобной утилитки под силу любому школьнику.Однако, чтобы было интересней, я решил оформить решение в виде апплета для панели Gnome. Так приложение будет всегда на виду и легко доступно, а при желании я смогу и расширить его функциональность. Задача немного усложняется тем, что из тех мануалов о написании апплетов, что я нашел, все были устаревшими, так что многое пришлось подбирать методом проб и ошибок.
Но не будем слишком углубляться. Для начала, нам понадобится подобный .server файл, описывающий фабрику(TimeTrackApplet_Factory.server):
<oaf_info>
<oaf_server iid="OAFIID:TimeTrackApplet_Factory" type="exe"
location="/usr/lib/gnome-panel/timetrackapplet">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:Bonobo/GenericFactory:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Time Track Applet Factory"/>
<oaf_attribute name="description" type="string" value="Factory to create the time track applet"/>
</oaf_server>
<oaf_server iid="OAFIID:TimeTrackApplet" type="factory"
location="OAFIID:TimeTrackApplet_Factory">
<oaf_attribute name="repo_ids" type="stringv">
<item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
<item value="IDL:Bonobo/Control:1.0"/>
<item value="IDL:Bonobo/Unknown:1.0"/>
</oaf_attribute>
<oaf_attribute name="name" type="string" value="Time Track Applet"/>
<oaf_attribute name="description" type="string" value="TimeTrack applet"/>
<oaf_attribute name="panel:category" type="string" value="Amusements"/>
<oaf_attribute name="panel:icon" type="string" value="myicon.png"/>
</oaf_server>
</oaf_info>Содержимое файла говорит само за себя. Если кратко - здесь содержится описание нашего апплета и всего, что нужно для его запуска. Стоит отметить, что название фабрики - TimeTrackApplet_Factory должно совпадать с именем файла. Также стоит запомнить путь /usr/lib/gnome-panel/timetrackapplet - это место, где будет размещаться исполняемый файл апплета. Естественно, при желании можно менять любые описания, названия и иконки.Обычно этот .server файл помещается в каталог /usr/lib/bonobo/servers/. После того, как мы создали и поместили этот файл в нужное место, перейдем к самому апплету. Ниже я приведу полный исходный код, благо он не очень велик:
#! /usr/bin/env python
# -*- coding: UTF-8 -*-
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import gnome
import gnomeapplet
import logging
from datetime import datetime
logging.basicConfig(filename="path/to/applet.log") # я решил, что простого сохранения в лог мне хватит :)
log = logging.getLogger("TimeTrack")
log.setLevel(logging.INFO)
class TimeTrackApplet(gnomeapplet.Applet):# основной класс
def update_tooltip(self, text = None):
if text is None:
self.tooltip.set_tip(self.applet, self.tooltip_text)
else:
self.tooltip_text = text
self.update_tooltip()
def update_text(self,text=None):
if text is None:
self.temp.set_text(self.data)
else:
self.data = text
self.update_text()
def create_applet(self): # создание апплета, самая смыслонагруженная часть
app_window = self.applet
event_box = gtk.EventBox()
event_box.set_events(gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.POINTER_MOTION_MASK |
gtk.gdk.POINTER_MOTION_HINT_MASK |
gtk.gdk.CONFIGURE )
self.temp = gtk.Label()
self.data = "TT" # я не стал искать иконку и ограничился надписью TT
self.update_text()
self.inside_applet = gtk.HBox()
self.inside_applet.pack_start(self.temp)
self.tooltip = gtk.Tooltips() # в качестве демонстрации, создадим также всплывающую подсказку
self.tooltip_text = "Middle click for tooltip update"
self.update_tooltip()
event_box.add(self.inside_applet)
app_window.add(event_box)
app_window.show_all()
return event_box
def button_pressed(self, widget, event, *args, **kwargs):
if event.button==2:# средняя кнопка мыши, обновить подсказку
self.update_tooltip(datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"))
elif event.button==1:# левая кнопка мыши, записать в лог
log.info("Button Pressed: %s",datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"))
def __init__(self,applet,iid):
self.__gobject_init__()
self.applet = applet
self.box = self.create_applet()
self.applet.connect("button-press-event",self.button_pressed) # добавляем обработчик события клика
log.info("Applet created succesfully")
gobject.type_register(TimeTrackApplet)
DEBUG = False
def timetrack_applet_factory(applet, iid): # Реализация фабрики
log.info("Creating the applet...")
TimeTrackApplet(applet, iid)
return True
log.info("Starting...")
gnomeapplet.bonobo_factory("OAFIID:TimeTrackApplet_Factory",
TimeTrackApplet.__gtype__,
"TimeTrack",
"0.1",
timetrack_applet_factory) # Запуск всего механизма
log.info("Stopping...")Данный файл нужно скопировать на то место, которое указано в .server файле. Большая часть кода - gnome-specific, поэтому я постарался объяснить только самые общие моменты(экскурс в gnome+python не является моей целью сейчас) при помощи комментариев.Итак, для тех, кто код прочитал( :) ), понятно, что по щелчку левой кнопкой мыши дата и время щелчка (в UTC) записываются в лог-файл. Для меня это удобно - в конце месяца я смогу восстановить по этому файлу временные интервалы, а если когда забуду щелкнуть, то вряд ли будет трудно разобраться в этом человеку(это объяснение тому, что я не добавил в утилиту возможность автоматического подсчета интервалов).
Надеюсь, этот простой пример поможет кому-нибудь в написании собственных апплетов. Удачи!
Ссылки по теме:
-http://www.gnome.org/projects/ORBit2/appletstutorial.html (примеры на С)-http://www.pygtk.org/articles/applets_arturogf/ (устаревший пример на Python)
-http://computertemp.berlios.de/ (готовый апплет, наиболее полезным оказался)
-http://www.pygtk.org/docs/pygtk/ (reference для pygtk)
Posted by
Sergey Kishchenko
at
7:03 PM
1 comments
Labels: open source, python, программирование
