30 декабря 2011 г.

Graphviz [заметки о визуализации графов на python]

В последней заметке цикла будет рассмотрена самая, пожалуй, популярная бибилотека для визуализации графов graphviz. Биндинги для неё существуют для большинства популярных языков, в том числе и для python.

В отличии от рассмотренных ранее библиотек, graphviz предназначен исключительно для визуализации. Никаких алгоритмов внутри вы не найдёте. Поэтому чаще всего для манипулирования графами берут другие библиотеки, а полученные результаты представляют в виде dot-файла и отдают graphviz.

29 декабря 2011 г.

graph-tool [заметки о визуализации графов на python]

Третья заметка цикла посвящена python модулю graph-tool.
Базируется он на шибко резвой Boost Graph Library (BGL), а для визуализации использует graphviz.
Вообще, у BGL есть собственные биндинги на Python, однако
  • BGL-Python bindings are no longer being maintained.  
  • BGL не имеет инструментов для визуализации и нацеленна на использование в паре с graphviz.
  • Готовые яйца под питон так и не появились, а ставить руками столь широкие вещи весьма трудоёмко.
Думаю именно по этим причинам была написана graph-tool.

Итак, ближе к телу =)

27 декабря 2011 г.

iGraph [заметки о визуализации графов на python]

Тема второй заметки о визуализации графов - библиотека igraph, имеющая биндинги под python. Для визуализации она использует библиотеку Cairo.

Документация библиотеки детальная и подробнейшая, но абсолютно лишена даже базовых примеров. Примеры однако доступны в бета версии туториала - там всё детально и подробно расписано, правда на R =)
Что касается визуализации - то данный раздел туториала ещё не сделан, что в целом не сильно мешает.

По аналогии с предыдущей заметкой мерить будем время работы и пиковое потребление памяти алгоритма расстановки графа. Исходные данные для работы взяты идентичные использованным в тойже первой заметке цикла.

22 декабря 2011 г.

NetworkX [заметки о визуализации графов на python]

В заметках этого цикла будут рассмотренны несколько известных библиотек для визуализации графов, имеющие python-api.
В каждой заметке произведено сравнение скорости работы различных алгоритмов расстановки графов, а также примерные значения требуемой памяти.
Все сравнения я буду производить на невзвешенном ориентированном графе, включающем около 5 тысяч вершин и 18 тысяч рёбер.
Тестовая машинка - 4GB RAM + i3 540 3.07 GHz (x4).

Мерить будем пиковое значение памяти и время работы, поскольку для меня именно эти метрики являются критичными.

7 декабря 2011 г.

NetBeans 7.* и Python

Из стандартных плагинов недоступна, однако же есть дев версия плагина.
  1. Идём в Tools -> Plugins -> Settings
  2. Жмакаем кнопочку Add
  3. Называем новый источник как угодно и вставляем ссыль http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/nbms/updates.xml.gz
  4. Обратно Available Plugins и жмакаем кнопочку Reload Catalog
  5. Ищем питон и ставим как обычно
Ура товарищи! Удаляем нетбинсу 6.9 если (как я) держали оную для питона =)

Matplotlib и "FloatingPointError: underflow encountered in multiply"

Случилось мне столкнуться с мистической ошибкой при использовании matplotlib - библиотеки для рисования графиков и визуализации различных математических результатов, имеющей крайне Matlab Like API =)

Ошибка поставляется вместе с тучным traceback-ом, указывающим в итоге на
File "/usr/lib/python2.6/site-packages/numpy/ma/core.py", line 772, in __call__ 
return umath.absolute(a) * self.tolerance >= umath.absolute(b)
Тобишь ошибочка гдето внутрях ядра numpy, который библиотека юзает для своих целей.

Мистика заключается в том, что получить эту ошибку мне удалось только в связке версий 1.0.1 и 1.6.1 для matplotlib и numpy соответственно и только на python-е версии 2.6.5.

10 ноября 2011 г.

Переводим cron-скрипты на Zend

Часто бывает, что cron-скрипты Zend приложений работают с теми же ресурсами, что и само приложение. Само собой, хочется перенести эти скрипты в привычное окружение зенда. Один из вариантов этой процедуры я и приведу.

Сразу оговорюсь - представленная реализация наверняка не самая лучшая и имеет множество изъянов, да и некоторые моменты у меня самого вызывают вопросы (просто когда понадобилось перенести все крон скрипты на зенд времени на детальное рассмотрение небыло совершенно). Поэтому буду рад всем фидбеками и замечаниям по коду =)

19 октября 2011 г.

Zend cache manager + application.ini

Если кешей в приложении на зенде много (а так обычно и бывает, если у вас не хоум пейдж), рекомендую использовать их через специальный кеш менеджер, для которого существует соответствующий ресурс приложения.
В принципе, пример не сильно отличается от оф доки, разве что Вы также нарвались на упоминания в оной неких статический методов класса Zend_Cache_Manager, которых давно уже нет в коде =)

17 октября 2011 г.

Отдача .PDF с помощью Zend

Бывает результатом работы action-а зенда является отдача файла.
По хорошему, файлы надо отдавать напрямую сервером, но бывает файл генерится автоматически да ещё отталкиваясь от прав. В этом случае от зенда уже не отмазаться =))

13 октября 2011 г.

Zend и контроль доступа

Основы контроля доступа в приложениях на зенде разжёваны в интернетах вдоль и поперёк, поэтому подробно рассматривать эту тему я смысла не вижу.
Если вкратце:
  1. Создали ACL (статически или динамически)
  2. Определили роль юзера (как правило используются сессии)
  3. Проверили наличие привилегии к ресурсу
  4. Разрешили или отказали (способов отказа как правило несколько, от редиректа до исключения)
Если в Вашем приложении эти четыре пункта часто повторяются, рекомендую завернуть их в некоторую абстракцию. Свой вариант этой обёртки в виде action helper-а я и приведу.

MongoDB под python (основы)

Решил запостить основные рецепты дабы не потерялись. Постепенно буду пополнять.

Сборник cоветов по компонентам Zend-а

В процессе рефакторинга часто встречаются различные "прелести", оставшиеся от старых версий тех или иных библиотек. Есть такие и у зенда. Буду дополнять этот сборник по мере работы.

29 сентября 2011 г.

Absolute URL and helper url() (view/action)

Столкнулся с забавным поведением внешне идентичных view хелпера url() и одноимённого action хелпера.


Делаем в контроллере следущее:

var_dump(
        $this->view->url(array(), 'staticRegisterActivate', true),
        $this->_helper->url->url(array(), 'staticRegisterActivate', true)
);


Видим два урла:
http://dseye.local/registertoken.html
и
/registertoken.html

Почему при одинаковом коде в обоих хелперах (там по 2 строки) мы получаем разный вариант? И заодно как же поступить - в контроллере нужно брать абсолютный урл по роутеру (не хотелось бы ещё и serverUrl туда приплетать).

Есть подозрение что хелпер вида что то ещё рендерит перед тем как роутер заасемблить, но подтверждений не нарыл =(

UPD:
Докопался до причины =)) Оказалось это я сам переопределил стандартный хелпер вида для вывода абсолютных адресов
$this->view->serverUrl() . $router->assemble($urlOptions, $name, $reset, $encode)

Так что тревога отменяется =)

28 сентября 2011 г.

Libcurl + c-ares (установка из сорцов)

c-ares дают возможность делать асинхронные DNS запросы через pycurl (биндинги для libcurl). Мне это понадобилось для скоростного краба на питоне.
Под Windows все уже в порядке (.exe сетапник уже включает в себя скомпилированную поддержку 'c-ares').
На сервере же (Linux/FreeBSD) приходится ставить ручками (О_о). Далее приложу инструкцию для линуксы.

26 сентября 2011 г.

Zend_Log + application.ini + multiply logs

Понадобилось более сложная логика в Zend_Log и сразу хотелось сделать по хорошему, через application.ini
Удалось не всё =(

10 августа 2011 г.

Простое кеширование вызовов Zend_Db_Table

Кеширование вызовов моделей (да и любых других классов) в зенде классически реализуется с помощью Zend_Cache_Frontend_Class.

В оригинале это выглядит примерно так:

Copy Source | Copy HTML
  1. $model = MyModel();
  2. $model_cached = MyModelCached();
  3.  
  4. $values_direct = $model->doStuff();
  5. $values_cached = $model_cached->doStuff();


Этот путь мне не понравился сразу по нескольким причинам. 
Во первых - удваивание количества сущностей. Когда моделей много и Вы используете не по одной модельке на запрос монструозненько получается.
Во вторых - слишком много настроек кеша. Это очень хорошо и к месту, когда логика кеша сложна или нетривиальна. В моём случае весь кеш работает с одними и теми же настройками и совершать лишних телодвижений по его инстанцированию не хотелось бы.


28 июля 2011 г.

Zend + action helpers + application.ini

Action helpers иногда бывают очень полезны. В частности как замена плагинов фронт-контроллера с возможностью доступа к экземпляру конкретного контроллера действия. Примеры конфигурирования оных я и приведу.

14 июля 2011 г.

Zend_Db set timeout in app.ini

В интернете не нашёл примера для указания таймаута ресурса Db в app.ini.
resources.db.params.driver_options.2 = 6000  ;PDO::ATTR_TIMEOUT
А всё потому, что в ini файле не исполнить PDO::ATTR_TIMEOUT =(

Zend_Db_Select + UNION + COUNT

Часто бывает нужно вывести часть данных и показать сколько ещё осталось. Сделать это можно разными способами, в данном случае я использую 2 отдельных запроса.
Весело становится когда запрос на выборку данных у нас составляется UNION-ами, к которому простой COUNT(*) не применить толком =)

Нашёл лаконичное решение через пагинатор.

8 июля 2011 г.

Настройка VDS под dseye.ru

Решил переехать на более производительный тариф и заодно записать все типовые шаги в настройке (постоянно что нибудь да забуду).

Описание краткое, просто чтобы не забыть.

4 июля 2011 г.

Zend_Paginator + Cache (memcached)

Столкнулся с проблемой при попытке прикрутить нативное кеширование к пагинатору (DbTableSelect адаптер)

бутстрап (производим кеш и скармливаем пагинатору)

Copy Source | Copy HTML
  1. $backendOptions = array(
  2.             'servers' => array( array(
  3.                     'host' => '127.0.0.1',
  4.                     'port' => (APPLICATION_ENV == 'production') ? 12245 : 11211,
  5.                     'persistent' => true,
  6.                     'weight' => 1,
  7.                     'timeout' => 10,
  8.                     'retry_interval' => 15,
  9.                     'status' => true,
  10.                     'failure_callback' => null ) ) );
  11.  
  12.         $frontendOptions = array(
  13.             'lifetime' => 3600
  14.             'automatic_serialization' => true,
  15.             'caching' => (APPLICATION_ENV == 'production') ? true : true,
  16.             'cache_id_prefix' => 'dseyeUP_',
  17.             'ignore_user_abort' => true );
  18.  
  19.         $cache = Zend_Cache::factory(
  20.                         'Core',
  21.                         'Memcached',
  22.                         $frontendOptions,
  23.                         $backendOptions);
  24.         Zend_Registry::set('upCoreMem', $cache);
  25.  
  26.         Zend_Paginator::setCache($cache);
  27.  

контроллер

Copy Source | Copy HTML
  1. $count = $this->_worlds->getPlayersCount($this->idW);
  2. $this->view->paginator = $paginator = $this->_players->listWorldPlayers($this->idW, $page, $count);


По всем мануалам всё должно работать, но нет:
во первых ZFDebug показывает лишний коннект к БД перед запросом данных пагинатора
во вторых этот запрос не кешируется никогда

Долго гуглил и копал сорцы, но как то безуспешно =(

Нашёл пару багов, где у людей файловый кеш пагинатора не работал при включенном профилировании через фаербаг, но показалось что проблема не та.

Версия 1.11.0, но и на продакшене 1.11.3 тоже самое.

Сам кеш разумеется работает нормально, без проблем подцепился к метаданным DbTable, да и ручками много где используется =)

Как временно решение прикрутил ручками кеширование этого запроса по составному ключу из параметров.

Скрытая фишечка хeлпера FormRadio

Случайно наткнулся в сорцах ZF на возможность задавать атрибуты лейбла у радиобатонов.
Делается посредством конкатенации строки "label_" к имени атрибута.

Например:
Copy Source | Copy HTML
  1. $this->formRadio('filter_alliance_mod',
  2.                   isset($this->searchProp->filterAllianceMod) ? $this->searchProp->filterAllianceMod : 'only',
  3.                   array('label_class' => 'text-top'),
  4.                   array('only' => 'только', 'not' => 'исключая'),
  5.                   ' ');

Стандартный роутер ZF или "будь бдителен!"

В zf, как известно, существует стандартный роутер по имени "default". Но есть и возможность описывать свои "человекоподобные" урлы.

Итак:
Есть пачка роутеров с параметрами. Параметров много, в роутерах задаются дефолтные значения и регулярки для валидации. Казалось бы - в контроллере эти переменные проверять ненадо, ведь если человек дошёл до контроллера, значит все проверки роутера выполнились. И тут (ВНЕЗАПНО!) я вспоминаю про стандартный роутер, без всех этих проверок.
Само собой ничего критичного там нет, да и prepared state дают защиту от SQL inject, но возможность вывести сразу все данные на одной странице (пагинация с изменяемым количеством итемов на странице) тоже может доставить хлопот.

Собственно вопрос: можно ли как то запретить переходить по стандартному роутеру для действий, к которым прописан кастомный роутер?

Доку пролистал вдоль и поперёк. Что нарыл:
1.Можно убить стандартный роутер вообще (ну или заменить на заведомо левый). Но этот вариант заставляет писать роутеры для всех страниц
2.Можно в критичных действиях проверять ($this->getFrontController()->getRouter()->getCurrentRouteName() == 'default' ). Достаточно гибкое решение, но генерирует слишком много повторного кода.
3. Зашить предыдущую проверку в плагин фронт контроллера и сочинить конфиг (для определения критичных действий). Тут уже можно разгуляться, но всё равно это смотрится костылём.