Этот пост несколько дней лежал неопубликованным, потому что я не решался опубликовать эти субъективные размышления, так как они существенно отличаются от тематики предыдущих публикаций. Но сегодня случайно наткнулся на эту статью. Кому легче читать на русском(статья достаточно эмоциональна, а эмоции легче воспринимаются на родном языке) - вот здесь я видел перевод.
После прочтения статьи я стер всё, что написал ранее, потому что не cмог так точно передать свои мысли. Я прочел в этой статье не ненависть к "проприетарному миру", а увидел в ней свою же ненависть к людям, которые обществом ставятся выше меня. Это и начальство, которое мне как назло попадается недалекое. И различные менеджеры, утратившие(или никогда и не имевшие) способность созидать. И преподаватели, которые откровенно глупы. И вся эта кодла бюрократов, официалов, authorities и проч.
У каждого человека есть своя цена. И как неприятно ощущать, что твои познания о ценообразовании никуда не годны, и в реальном мире стоимость человека определяется по параметрам, которые тебе или непонятны, или, что нередко, отвратительны.
Friday, November 14, 2008
Об отношении к вышестоящим
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, программирование
Thursday, August 28, 2008
IPv6 не будет
Слегка адаптированная мной заметка по мотивам http://www.extremetech.com/article2/0,2845,2328258,00.asp:
Arbor Networks измерили объем IPv6 траффика, проходящего через 2400 бэкбонов и роутеров у 87 провайдеров Интернет по всему миру. Учет велся с Июня 2007 по Июль 2008 года. Полученные данные были использованы для исследования, которое компания считает наиболее всеохватывающим исследованием ситуации с IPv6 на сегодняшнее время. В целом Arbor отследил 15 экзабайт траффика - при этом все человеческое знание занимает 4 экзабайта, как заявляют представители компании.Со своей стороны хочется добавить, что это исследование раскрыло мне глаза на то, насколько все плохо с IPv6. Возможно, понимание того, что мы еще в самом начале пути, подстегнет крупные компании, представителей государства и простых пользователей и продвижение пойдет быстрее.
Это исследование показало, насколько плачевна ситуация в стане IPv6. Если верить полученным данным, объем междоменного IPv6 траффика составил всего 0.0026% от объема IPv4 траффика. Были замечены два пика активности между 4 ноября и Рождеством 2007 года, на пике процентное соотношение поднялось до 0.012%. При этом, процент соответствия IPv6 и IPv4 траффика оставался неизменным за все время исследования.
Я уже писал о том, что такое IPv6 и насколько переход на него с устаревшего IPv4 важен. В действительности, если не будет существенных сдвигов в ближайшее время, то по некоторым оценкам уже к 2011 году IPv4 адреса закончатся и развитие сети Интернет остановится. Переход же на IPv6 даст возможность использовать 340 миллиардов миллиардов миллиардов миллиардов адресов, чего должно хватить на ближайшее будущее :)
"Я не думаю, что переход уже начался", - говорит Scott Iekel-Johnson, основной автор исследования и главный специалист по программному обеспечению в компании Arbor, -"Не похоже, что хотя бы в какой-нибудь значительной части из охваченных исследованием регионов были существенные сдвиги"
Как это ни дико, по заявлениям исследователей, один из пиков совпал с собранием рабочей группы проектирования Интернет (IETF) - одной из групп, которая яростно толкает индустрию к использованию IPv6 адресования. Во время собрания, как говорят представители Arbor, участников попросили выключить IPv4 функциональность на своих компьютерах и роутерах и проверить, какие сайты будут доступны. Чтобы протестировать инфраструктуру, они смотрят онлайн-видео, качают файлы больших объемов. Предполагается, что это и вызвало учтенный пик.
Тем не менее, на этом собрании было зарегистрировано только 1168 человек. Т.е., по данным компании, всего чуть более тысячи человек вызвали самый высокий всплеск IPv6 активности за последние 12 месяцев. Это говорит о многом.
Исследователи видят два способа разрешения проблемы. Первый - поддержка идеи компаниями и государственными органами. Второй - проникновение идеи глубоко в массы. Iekel-Johnson делает ставку на первый вариант. Он приводит пример: "Если Comcast(ISP - прим. моё) скажет своим клиентам: 'Окей, вам нужно использовать IPv6, потому что у нас кончаются адреса, а мы хотим добавлять новых пользователей' - это приведет к существенным продвижениям".
Чтобы избежать обвинения в искажении фактов при адаптации я предлагаю поучаствовать в полном переводе статьи - сам я не смогу довести ее до читабельного вида без существенных правок. Поучаствовать и почитать текущий вариант перевода можно здесь
Posted by
Sergey Kishchenko
at
11:26 AM
0
comments
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, программирование, статьи
