<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><title>Светлячный Dev Лог</title><link href="http://dev.svetlyak.ru" rel="alternate" /><id>http://dev.svetlyak.ru</id><updated>2012-05-14T16:06:00Z</updated><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/dev-svetlyak/all" /><feedburner:info uri="dev-svetlyak/all" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><title>Link Roundup #3</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/VlBnYgc4VU4/" rel="alternate" /><updated>2012-05-14T16:06:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/link-roundup-3/</id><summary type="html">&lt;h2&gt;Разработка&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Что-то пошла мода на "легковесные" очереди задач. Недавно Vincent Driessen &lt;a href="http://python-rq.org/"&gt;опубликовал свой RQ&lt;/a&gt;, а теперь вот и &lt;a href="http://justcramer.com/2012/05/04/distributing-work-without-celery/"&gt;David Cramer пишет&lt;/a&gt;, что они в DISCUS пришли к чему-то подобному.&lt;/li&gt;
&lt;li&gt;На Highscalability появилась &lt;a href="http://highscalability.com/blog/2012/5/10/paper-paxos-made-moderately-complex.html"&gt;ссылка на новую статью про Paxos&lt;/a&gt;. Говорят, там всё хорошо расписано, и обсуждаются детали реализации.&lt;/li&gt;
&lt;li&gt;Про то, что &lt;a href="http://highscalability.com/blog/2012/5/9/cell-architectures.html"&gt;масштабируемые сервисы&lt;/a&gt; нужно разделять переборками, чтобы повысить их плавучесть.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mailcatcher.me/"&gt;MailCatcher&lt;/a&gt; — простой SMTP сервер, для отладки отправки писем. Перехватывает все проходящие через него сообщения, и показывает из в веб-интерфейсе.
Попробовал &lt;a href="http://swiftype.com/"&gt;swiftypy.com&lt;/a&gt; — поисковый движок для сайтов. Морфологию русскую, увы, не поддерживает. Но выглядит круто. И пока бесплатен.&lt;/li&gt;
&lt;li&gt;Небольшая заметка &lt;a href="http://www.quora.com/Pinterest/How-does-Pinterest-know-the-title-and-creator-when-I-pin-a-deep-linked-Flickr-image-1"&gt;о том, как ребята из Pinterest продвигают формат oEmbed&lt;/a&gt;, и с его помощью по непонятному урлу картинки с flickr, получают реальный адрес страницы, с этим изображением.&lt;/li&gt;
&lt;li&gt;Статья про то, как &lt;a href="http://qq.is/article/git-flow-on-github"&gt;применять GitFlow и работать с GitHub&lt;/a&gt;. Правда ничего не говорится о том, как майнтейнер апстрима будет мерджить твою feature ветку, ведь если он сделает это через интерфейс гитхаба, то git-flow будет нарушен. Жаль, gitflow мне приглянулся.&lt;/li&gt;
&lt;li&gt;Статья про то, почему команда GitHub &lt;a href="http://scottchacon.com/2011/08/31/github-flow.html"&gt;не использует git-flow&lt;/a&gt; в своей работе.&lt;/li&gt;
&lt;li&gt;Статья &lt;a href="http://lincolnloop.com/blog/2012/apr/23/ginger-tech-stack/"&gt;о том, как устроен Ginger&lt;/a&gt; — сервис общения для команд. Схема асинхронного IO такая: Django -&amp;gt; Redis PubSub -&amp;gt; Node.js -&amp;gt; Socket.io -&amp;gt; Браузер.&lt;/li&gt;
&lt;li&gt;Обширное, хоть и старое (2008) года, &lt;a href="http://deron.meranda.us/python/comparing_json_modules/"&gt;сравнение JSON библиотек&lt;/a&gt; для Python.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://hynek.me/articles/python-deployment-anti-patterns/"&gt;Антипаттерны деплоя Python&lt;/a&gt; кода. Согласен со всеми пунктами.&lt;/li&gt;
&lt;li&gt;Статья про то, &lt;a href="http://blog.getprismatic.com/blog/2012/4/17/clustering-related-stories.html"&gt;как кластеризуют документы&lt;/a&gt; ребята из стартапа Prismatic. Присутствует пара практических советов, как бороться с нехваткой памяти и ресурсов CPU при больших объемах подобных вычислений. Суть проста — не хранить и не делать лишнего.&lt;/li&gt;
&lt;li&gt;Пост про то, &lt;a href="http://www.mikealrogers.com/posts/face-of-the-faceless.html"&gt;почему плохо заводить организации&lt;/a&gt; для проектов на GitHub.&lt;/li&gt;
&lt;li&gt;Про &lt;a href="http://blog.arongriffis.com/post/dynamic-virtualenvwrapper"&gt;динамическую подгрузку&lt;/a&gt; функций virtualenvwrapper и &lt;a href="http://mathematism.com/2009/07/30/presentation-pip-and-virtualenv/"&gt;скринкастик про сам враппер&lt;/a&gt;. Посмотрел всё это и и понял, что мне это не нужно, потому что я крайне редко переключаюсь между окружениями в одной консоли, у меня для этого tmux есть.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Полезные сервисы&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://githire.com/"&gt;GitHire&lt;/a&gt; — сервис для найма активных гиттеров.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/blog/985-git-io-github-url-shortener"&gt;git.io&lt;/a&gt; — сокращала урлов для GitHub. Оказывается уже почти полгода существует, а я и не знал.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/VlBnYgc4VU4" height="1" width="1"/&gt;</summary><category term="roundup" /><feedburner:origLink>http://dev.svetlyak.ru/link-roundup-3/</feedburner:origLink></entry><entry><title>Link Roundup #2</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/cF9O5Yrj3y0/" rel="alternate" /><updated>2012-04-23T13:15:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/link-roundup-2/</id><summary type="html">&lt;h2&gt;Python&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Статья о том, &lt;a href="http://charlesleifer.com/blog/using-redis-pub-sub-and-irc-for-error-logging-with-python/"&gt;как пушить стэктрейсы через PubSub Redis'a в IRC канал&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Мой &lt;a href="https://github.com/svetlyak40wt/osbench/"&gt;клон Homebrew, но для Linux и на Python&lt;/a&gt;, пока очень очень alpha, но уже умеет устанавливать пакетики, и скоро научится удалять :))).&lt;/li&gt;
&lt;li&gt;Один из коллег опубликовал на GitHub &lt;a href="https://gist.github.com/2397652"&gt;python скриптик, чтобы считать IO по файлам в Linux&lt;/a&gt;. Сначала статистика собирается через TAP, а потом этим скриптиком аггрегируется: &lt;code&gt;stap filestat.stp bsc-srch-base-8 | python -u aggregate_filestat.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;А вот &lt;a href="http://github.enthought.com/chaco/"&gt;Chaco&lt;/a&gt; — python библиотечка для рендеринга интерактивных графиков.&lt;/li&gt;
&lt;li&gt;Кеннет Рейнц написал &lt;a href="http://www.kennethreitz.com/repository-structure-and-python.html"&gt;статью&lt;/a&gt; про "правильную" структуру репозитория для Python проекта. Всё очевидно и разжевано. Можно рекомендовать новичкам.&lt;/li&gt;
&lt;li&gt;Доклад &lt;a href="http://www.youtube.com/watch?v=Adr_QuDZxuM"&gt;Python Metaprogramming for Mad Scientists and Evil Geniuses&lt;/a&gt;, с PyCon2012. Много интересного про манкипатчинг.&lt;/li&gt;
&lt;li&gt;Так же, я потестил PyPy на маленьком Bottle+Gunicorn проектике, и получил прирост производительности всего на 30%. Не впечатлен. Настмотревшись &lt;a href="http://speed.pypy.org/"&gt;их графиков&lt;/a&gt;, ожидал большего.&lt;/li&gt;
&lt;li&gt;Кстати, вы знали, что в gunicorn можно передавать не только путь до application, но и фунцию, которая этот app генерит? Как-то так: &lt;code&gt;gunicorn 'mysite:app_generator()'&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Разное&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Огромная подборка статей &lt;a href="http://www.smashingmagazine.com/2011/07/22/responsive-web-design-techniques-tools-and-design-strategies/"&gt;про Responsive Design&lt;/a&gt;. Отложил в закладки, когда-нибудь пригодится, хоть я и не верстальщик и не дизайнер.&lt;/li&gt;
&lt;li&gt;Интересная статья про то, &lt;a href="http://jeditoolkit.com/2012/04/26/code-logic-not-mechanics.html"&gt;как правильно писать асинхронный код&lt;/a&gt; на Javascript. Предлагаемая концепция немного напоминает Deferred в Twisted Python, и обертку inlineCallbacks.&lt;/li&gt;
&lt;li&gt;Старая статья Guy Kawasaki о том, что &lt;a href="http://blog.guykawasaki.com/2005/12/the_102030_rule.html"&gt;презентация должна быть&lt;/a&gt; на 10 страницах, за 20 минут и крупным 30pt шрифтом.&lt;/li&gt;
&lt;li&gt;Описание формата &lt;a href="http://oembed.com/"&gt;oEmbed&lt;/a&gt;, позволяющего посредством GET запросов получать информацию о ресурсах сайта по урлу. Например для встраивания их в другие сайты. Оказывается, этот oEmbed много кто поддерживает.&lt;/li&gt;
&lt;li&gt;Твиттер принес ссылку на еще один GUI клиент к MongoDB — &lt;a href="http://www.jumperz.net/index.php?i=2&amp;amp;a=0&amp;amp;b=9"&gt;MonjaDB&lt;/a&gt;. Пока не смотрел. Судя по скриншотам, довольно развесистый, и на Java и под Eclipse.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Полезные сервисы&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://chartbeat.com/"&gt;ChartBeat&lt;/a&gt; — онлайн аналитика посещений. По словам разработчиков, их сервис отличается от Google Analytics или Яндекс Метрики тем, что позволяет отслеживать то, чем занимаются пользователи вышего сервиса прямо сейчас, в "реальном" времени. Хотел попробовать, но они хотят даже для триала, получить данные моей кредитки. Отказался.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://hidemyass.com"&gt;Hide-My-Ass&lt;/a&gt; — прокси, который не нужно настраивать.&lt;/li&gt;
&lt;li&gt;19 апреля, Python хостинг &lt;a href="http://ep.io"&gt;http://ep.io&lt;/a&gt; объявил о скором закрытии. Не выдержали конкуренции. Вовремя я перевел один свой маленький сайтик с него, на хостинг яндекса.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/cF9O5Yrj3y0" height="1" width="1"/&gt;</summary><category term="python" /><category term="roundup" /><feedburner:origLink>http://dev.svetlyak.ru/link-roundup-2/</feedburner:origLink></entry><entry><title>Link Roundup #1</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/bJ8v3k0oB5w/" rel="alternate" /><updated>2012-04-16T12:54:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/link-roundup-1/</id><summary type="html">&lt;p&gt;Решил делать еженедельные подборки ссылок на разные темы. Это первый такой пост.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Думаю переползать с Munin на Collectd, но попутно наткнулся на проектик &lt;a href="https://github.com/samuel/python-munin"&gt;python-munin&lt;/a&gt;, упрощающий написание плагинов для Munin на python. Мне уже вряд ли пригодится. Кстати, для collectd тоже можно на питончике писать плагины, но запускаются они более разумно.&lt;/li&gt;
&lt;li&gt;На прошлой неделе я написал &lt;a href="https://github.com/svetlyak40wt/things-periodical-tasks"&gt;things-periodical-tasks&lt;/a&gt;, но позже осознал его бесполезность. Во-первых, в things есть периодические задачи, хоть их и неудобно добавлять, если нужно указывать дни недели. Во-вторых, на постоянно выключаемом ноуте, cron пропускает задачи, запланированные на то время, которое он проспал.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kolyaj/Yaxy"&gt;Yaxy&lt;/a&gt; — прокси сервер для разработчика, позволяет на лету подменять урлы, заголовки, куки, и т.д..&lt;/li&gt;
&lt;li&gt;&lt;a href="http://horicky.blogspot.com/2012/04/mongodb-architecture.html"&gt;MongoDB Architecture&lt;/a&gt; — заметка про особенности разработки под MongoDB. Наверное всё это можно найти в официальной документации, но там оно разбросано по разделам, а здесь на одной странице.&lt;/li&gt;
&lt;li&gt;Амазон запустил &lt;a href="http://aws.typepad.com/aws/2012/04/amazon-cloudsearch-start-searching-in-one-hour.html"&gt;Cloud Search&lt;/a&gt; и об этом не написал только ленивый. Вообще, довольно очевидная идея и странно, что ни один поисковый гигант до сих пор не выпустил такого продукта.&lt;/li&gt;
&lt;li&gt;Статейка про &lt;a href="http://cookbook.mongodb.org/patterns/perform-two-phase-commits/"&gt;Two Phase Commit&lt;/a&gt; в MongoDB и прочих noSQL — про то, как в отсутствии нормальных транзакций, организовать гарантированное изменение нескольких объектов в базе данных.&lt;/li&gt;
&lt;li&gt;Статейка про &lt;a href="http://www.ixbt.com/storage/hdd-smart-testing.shtml"&gt;S.M.A.R.T&lt;/a&gt; и то, что означают те или иные пункты отчета. Кстати, для OSX в Homebrew есть консольная утилитка smartmontools.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;В догонку, я нашел страницу с &lt;a href="https://github.com/mxcl/homebrew/wiki/Interesting-Branches"&gt;описанием разных форков Homebrew&lt;/a&gt;. И целых три форка Homebrew под Linux:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/paxan/homebrew"&gt;https://github.com/paxan/homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rubiojr/homebrew"&gt;https://github.com/rubiojr/homebrew&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ndevenish/homebrew"&gt;https://github.com/ndevenish/homebrew&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Из них попробовал пока только последний, от ndevenish. Но там не всё так гладко. Тот же collectd — не собирается потому что не видит dev библиотек, установленных в Ubuntu. Пока отложил.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/bJ8v3k0oB5w" height="1" width="1"/&gt;</summary><category term="python" /><category term="roundup" /><feedburner:origLink>http://dev.svetlyak.ru/link-roundup-1/</feedburner:origLink></entry><entry><title>Periodical Tasks For Things</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/ZlLGdezF7AQ/" rel="alternate" /><updated>2012-04-11T15:19:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/things/</id><summary type="html">&lt;p&gt;Пару дней назад, я почитал такой забавный документ, под названием "&lt;a href="http://gtdfh.branchable.com/"&gt;GTD для хакеров&lt;/a&gt;" и почерпнул из него несколько интересных идей.
Одна из таких идей — завести чеклисты для вещей, которые нужно делать периодически и про которые время от времени забываешь.&lt;/p&gt;
&lt;p&gt;Я уже использую &lt;a href="http://culturedcode.com/things/"&gt;Things&lt;/a&gt; от Cultured Code, для ведения списка дел. Однако там нет такой полезной фичи, как периодические таски. Работать оно должно так же, как периодические события в календаре — добавил один раз, указав интервал времени, и задача у тебя появляется сама собой. Вот этого то в Things и не хватает.&lt;/p&gt;
&lt;p&gt;Но есть же Apple Script, который позволяет делать почти всё, что угодно!&lt;/p&gt;
&lt;p&gt;И вот я сел, и примерно за час времени родил скрипт из 10 строк, добавляющий в Things таск прямо из командной строки терминала. Дальше уже дело техники — запускаешь crontab и добавляешь по строчке на каждой задание, которое должно возникать само собой.&lt;/p&gt;
&lt;p&gt;В итоге, получилась весьма гибкая система, решающая нужную мне задачу, и не требующая дополнительной программы или вебсервиса.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/svetlyak40wt/things-periodical-tasks"&gt;Исходники скрипта&lt;/a&gt; доступны на GitHub. Форкайте, правьте.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/ZlLGdezF7AQ" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/things/</feedburner:origLink></entry><entry><title>Unittesting With Tdaemon And Tmux</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/rQs9ZIXzXV8/" rel="alternate" /><updated>2012-04-06T16:39:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/unittesting-with-tdaemon-and-tmux/</id><summary type="html">&lt;p&gt;Некоторое время назад я нашел интересный watchdog для запуска юнит-тестов — &lt;a href="https://github.com/svetlyak40wt/tdaemon/tree/develop"&gt;tdaemon&lt;/a&gt;. Инетересн он был прежде всего тем, что
работал без использования inotify, что позволяло мне запускать его в диреткториях, подмонтированных внутрь VirtualBox.&lt;/p&gt;
&lt;p&gt;Впрочем, &lt;a href="https://github.com/svetlyak40wt/tdaemon/tree/develop"&gt;tdaemon&lt;/a&gt; оказался написан из рук вон плохо. Он тормозил, и поддерживал лишь ограниченный список систем для запуска юнит-тестов.
Зато это проект на Python. В итоге, я переписал там основной функционал. Теперь он работает шустро, не грузит зря проц бесконечным поллингом файловой системы.&lt;/p&gt;
&lt;p&gt;На днях я, решив попробовать новый севис для записи скринкастов, &lt;a href="http://ascii.io/a/228"&gt;сделал ролик&lt;/a&gt;, в котором демонструрую работу с &lt;a href="https://github.com/svetlyak40wt/tdaemon/tree/develop"&gt;tdaemon&lt;/a&gt;, &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt; и специальным плагином &lt;a href="https://github.com/svetlyak40wt/nose-notify-tmux"&gt;nose-notify-tmux&lt;/a&gt;, который умеет показывать прогресс юниттестов прямо в табике &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Вот уже производная этого ролика, переснятая и с саундтреком:&lt;/p&gt;
&lt;iframe src="http://player.vimeo.com/video/39888128" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen&gt;&lt;/iframe&gt;

&lt;p&gt;Кто хочет нормального качества, тем в &lt;a href="http://ascii.io/a/228"&gt;ascii плеер&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/rQs9ZIXzXV8" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/unittesting-with-tdaemon-and-tmux/</feedburner:origLink></entry><entry><title>Исправление работы django-kombu с InnoDB</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/IVckvmVkv9g/" rel="alternate" /><updated>2011-12-26T03:42:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/kombu-fix/</id><summary type="html">&lt;p&gt;Наверное многие из вас используют &lt;a href="https://github.com/ask/django-celery"&gt;django-celery&lt;/a&gt;, или хотя бы слышали про этот
инструмент для асинхронного выполнения задач. В самом простейшем случае, когда
нет желания взводить дополнительные redis или AMQP сервера, очередь задач
организуется через уже имеющуюся базу данных. В моем случае это был MySQL.&lt;/p&gt;
&lt;p&gt;В случае, когда очередь организуется через базу, &lt;a href="https://github.com/ask/celery"&gt;Celery&lt;/a&gt; использует специальный
бэкенд &lt;a href="https://github.com/ask/django-kombu"&gt;django-kombu&lt;/a&gt;, который устроен довольно просто — при добавлении сообщения, оно
сериализуется и кладется в табличку БД, при операции pop, запись из базы изымается.
Такой вот AMQP для бедных.&lt;/p&gt;
&lt;p&gt;&lt;img alt="by weelakeo@flickr" src="http://farm3.staticflickr.com/2521/3815108314_8a67832b89.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;Итак, я использовал MySQL и &lt;a href="https://github.com/ask/celery"&gt;celery&lt;/a&gt; работал отлично до тех пор, пока не было принято решение
сконвертировать все таблички в InnoDB дабы использовать транзакции.
После такого изменения, celery перестал "подхватывать" новые задачи и выполнял их только после рестарта.&lt;/p&gt;
&lt;p&gt;В интернетах предлагалось три решения этой проблемы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;откатить все таблички &lt;a href="https://github.com/ask/django-kombu"&gt;django-kombu&lt;/a&gt; обратно на движок MyISAM;&lt;/li&gt;
&lt;li&gt;установить в конфиге MySQL &lt;code&gt;ISOLATION LEVEL READ-COMMITTED&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;раскомментировать некую строчку в сорцах &lt;a href="https://github.com/ask/django-kombu"&gt;django-kombu&lt;/a&gt;, после чего он станет переоткрывать
    коннекты к базе при каждой операции.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Объясню, почему все три никуда не годятся.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Вариант, предлагающий держать часть табличек в MyISAM, лишает нас транзакционности.&lt;/li&gt;
&lt;li&gt;Установка иного &lt;code&gt;ISOLATION LEVEL&lt;/code&gt;, глобально или в рамках сессии, может привести к некоторым
   "спецэффектам" при выполнении задач, рассчитанных на более строгую изоляцию.&lt;/li&gt;
&lt;li&gt;Переустановка соединения с базой каждый раз — просто грязный хак, замедляющий работу очереди
   в несколько раз.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Пришлось лезть в кишки django-kombu и править все самому. Оказалось, что по время опроса очереди,
библиотека держит коннект с базой открытым и все селекты выполняются в рамках одной длиииной трензакции.
Это означает, что все сообщения, которые будут добавлены в очередь в процессе, kombu не увидит
из за того, что в MySQL по умолчанию установлен &lt;code&gt;ISOLATION LEVEL REPEATABLE READ&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;В итоге, я обернул несколько методов в декоратор commit_on_success, и всё заработало как надо. При этом
небольшой тест показал производительность в 3 раза больше чем у версии с "грязным" хаком.&lt;/p&gt;
&lt;p&gt;Попутно поправил еще один баг, связанный с тем, что celery завершала свою работу в случае, когда MySQL
становился недоступен.&lt;/p&gt;
&lt;p&gt;Создал &lt;a href="https://github.com/ask/django-kombu/pull/9"&gt;Pull Request&lt;/a&gt;, но пока его не смерджили, исправления в &lt;a href="https://github.com/svetlyak40wt/django-kombu/commits/durability"&gt;моей ветке на GitHub&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/IVckvmVkv9g" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/kombu-fix/</feedburner:origLink></entry><entry><title>GitHub в Цифрах</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/9NaMuybm-yo/" rel="alternate" /><updated>2011-10-15T09:20:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/github-stats/</id><summary type="html">&lt;p&gt;Некоторое время назад мне в голову пришла идея сделать &lt;a href="http://dev.svetlyak.ru/github-trends/"&gt;сервис вокруг гитхаба&lt;/a&gt;. В первую очередь, он должен быть полезен тем, у кого много репозиториев и тем, кто следит за большим количеством кодеров или репозиториев.&lt;/p&gt;
&lt;p&gt;Основной паттерн моего использования социальных возможностей гитхаба таков: я фолловлю других кодеров для того, чтобы видеть в ленте какие проекты он находят, комментят и коммитят. Таким образом, я периодически обнаруживаю что-нибудь интересненькое. Вот только работало это лишь до определенного момента — пока объем данных в ленте не вырос настолько, что я стал лениться ее читать.&lt;/p&gt;
&lt;p&gt;Тут то и возникла идея — как-то агрегировать данные ленты, чтобы вычленять из нее интересные проекты. Например учитывая возросший к ним интерес людей из твоего первого или второго круга.&lt;/p&gt;
&lt;p&gt;Кроме того, сервис должен будет упростить отслеживание того, что происходит в форках ваших репозиториев. Это уже будет полезно тем, у кого десятки публичных репозиториев. Такая функциональность у меня даже реализована, но в виде простенького скрипта, который генерирует RSS с новыми коммитами в форках.&lt;/p&gt;
&lt;p&gt;А еще, можно сделать пузомерку для гиков, с медальками, рейтингами и титулами. Это просто прикольно: сделал десяток коммитов в полночь получи титул "Midnight code warrior" :)&lt;/p&gt;
&lt;p&gt;Однако, прежде чем ввязываться в затратное дело — создание отдельного сервиса для всех, я решил посчитать некоторую статистику отностиельно того, сколько же людей потенциально смогут оценить достоинства этого моего сервиса. Очень уж я не люблю делать бесполезные штуки :)&lt;/p&gt;
&lt;h2&gt;Прогресс&lt;/h2&gt;
&lt;p&gt;Для начала, я написал выкачивалку всех гитхаб пользователей. Что она делает. Она берет указанный логин, сохраняет его профиль, выкачивает список тех, кого за кем он следит, и добавляет их в очередь, если их профили еще не скачаны. Затем все повторяется для каждого логина, который в очереди, до тех пор, пока очередь не опустеет.&lt;/p&gt;
&lt;p&gt;Поскольку у API гитхаба есть ограничение в 5000 запросов в час, то процесс выкачивания всего графа затянулся почти на два дня.&lt;/p&gt;
&lt;p&gt;Всего было выкачано &lt;strong&gt;57 тысяч&lt;/strong&gt; профилей пользователей и около &lt;strong&gt;500 тысяч&lt;/strong&gt; репозиториев. На мой взгляд, пользователей маловато, но позможно так оно и есть. Раз мой скрипт до кого-то не добрался, значит его никто не фоловит, так что аккаунт скорее всего заброшен.&lt;/p&gt;
&lt;p&gt;Так выглядел процесс выкачивания. По этому графику хорошо заметен момент, когда очередь "на закачку" перестала расти и начала убывать.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
&lt;img alt="" src="http://chart.apis.google.com/chart?cht=lxy&amp;amp;chs=800x300&amp;amp;chd=e:AAApBSB7CkDND2EfFIFxGaHDHrIUI9JmKPK4LhMKMzNcOFOuPXQAQpRSR7SkTNT1UeVHVwWZXCXrYUY9ZmaPa4bhcKczdceFeufXgAgohRh6ijjMj1kelHlwmZnCnroUo9pmqPq4rhsKsztbuEutvWv.woxRx6yjzMz10e1H1w2Z3C3r4U495m6O637g8J8y9b-E-t.W..,FtSbbKjQmuqvthvwxU0D043Z5o5d7N-I8X8K9B9X-V...e.8-z-z.Y.o.A-K-J9w736D7Q6C425S3P23000dzuyMy-y2ySy1xyw6wcuyuFtFrQrAqGpPphomnNmpnsmQmSkhjVh9hTfselfjecczeVcPbfavZMcRbUaIYgXnWwV4UyUTSCRLPIN4MaKrJJHpGIEzDSCJAH&amp;amp;chtt=%D0%9F%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81%20%D0%B2%D1%8B%D0%BA%D0%B0%D1%87%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;amp;chxt=y,x,y,x&amp;amp;chxl=2:%7c%D0%BE%D1%87%D0%B5%D1%80%D0%B5%D0%B4%D1%8C%7c3:%7c%D0%BA%D0%BE%D0%BB-%D0%B2%D0%BE%20%D0%B2%D1%8B%D0%BA%D0%B0%D1%87%D0%B0%D0%BD%D1%8B%D1%85%20%D0%BF%D1%80%D0%BE%D1%84%D0%B8%D0%BB%D0%B5%D0%B9&amp;amp;chxr=0,0,3707%7c1,0,57001&amp;amp;chxp=2,50%7c3,50&amp;amp;chg=25,25,1,0" /&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;h2&gt;Наблюдай и следи&lt;/h2&gt;
&lt;p&gt;Самое важное для моего проекта — доли пользователей, которые наблюдают за большим количеством репозиториев или следят за большим количеством других разработчиков:&lt;/p&gt;
&lt;center&gt;

&lt;p&gt;&lt;img alt="" src="http://chart.apis.google.com/chart?cht=p3&amp;amp;chs=500x150&amp;amp;chd=s:EbZAFA&amp;amp;chtt=%D0%A1%D0%BB%D0%B5%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%B7%D0%B0%20%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F%D0%BC%D0%B8&amp;amp;chco=208020&amp;amp;chl=%3C1000%20%287.0%25%29%7c%3C100%20%2843.7%25%29%7c%3C10%20%2841.7%25%29%7c%3C10000%20%2852%29%7cnot%20watching%20%287.4%25%29%7c%3E10000%20%281%29" /&gt; | &lt;img alt="" src="http://chart.apis.google.com/chart?cht=p3&amp;amp;chs=500x150&amp;amp;chd=s:ANdT&amp;amp;chtt=%D0%9A%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE%20%D0%B7%D0%B0%D1%84%D0%BE%D0%BB%D0%BE%D0%B2%D0%BB%D0%B5%D0%BD%D1%8B%D1%85&amp;amp;chco=208020&amp;amp;chl=%3E100%20%28410%29%7c%3C100%20%2820.5%25%29%7c%3C10%20%2847.3%25%29%7cnot%20following%20%2831.4%25%29" /&gt;&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;Отсюда видно, что почти 50% пользователей, следят более чем за 10 репозиториями и 7% (около 4 тысяч) — более чем за 100. Так же мне интересны те 20% (11 тысяч), что фоловят более 10 человек, они наверняка не успевают прочитывать весь свой News Feed. И уж наверняка оставшиеся 410 пользователей, что фоловят больше сотни по достоинству оценят аггрегатор новостной ленты. Сам я, как раз вхожу в последнюю категорию, так как фоловлю 331 разработчика.&lt;/p&gt;
&lt;h2&gt;Количество репозиториев&lt;/h2&gt;
&lt;p&gt;Среднее количество публичных репозиториев у гитхаб пользователя — &lt;strong&gt;8&lt;/strong&gt;, из них &lt;strong&gt;3&lt;/strong&gt;, это форки чужих проектов.&lt;/p&gt;
&lt;center&gt;

&lt;p&gt;&lt;img alt="" src="http://chart.apis.google.com/chart?cht=p3&amp;amp;chs=500x150&amp;amp;chd=s:PlJA&amp;amp;chtt=%D0%9A%D0%BE%D0%BB-%D0%B2%D0%BE%20%D0%BF%D1%83%D0%B1%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D1%85%20%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B5%D0%B2&amp;amp;chco=208020&amp;amp;chl=%3C100%20%2824.4%25%29%7c%3C10%20%2860.1%25%29%7cno%20reps%20%2815.2%25%29%7c%3E100%20%28158%29" /&gt; | &lt;img alt="" src="http://chart.apis.google.com/chart?cht=p3&amp;amp;chs=500x150&amp;amp;chd=s:mIPA&amp;amp;chtt=%D0%9A%D0%BE%D0%BB-%D0%B2%D0%BE%20%D0%BF%D1%83%D0%B1%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D1%85%20%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B5%D0%B2%20%28%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%8F%20%D1%84%D0%BE%D1%80%D0%BA%D0%B8%29&amp;amp;chco=208020&amp;amp;chl=%3C10%20%2862.1%25%29%7c%3C100%20%2813.4%25%29%7cno%20reps%20%2824.4%25%29%7c%3E100%20%2854%29" /&gt;&lt;/p&gt;
&lt;/center&gt;

&lt;p&gt;На этом графике видно, что 60% пользователей имеют меньше 10 публичных репозиториев, а у 15% их нет вообще. Зато почти у четверти пользователей гитхаба публичных репозиториев от 10-100, и они являются потенциальными пользователями моего сервиса.&lt;/p&gt;
&lt;p&gt;При этом, процент активных репозиториев, таких в которые был хотя бы один push за последний месяц, всего 10%.&lt;/p&gt;
&lt;h2&gt;И еще…&lt;/h2&gt;
&lt;p&gt;Всего я выкачал информацию чуть больше чем по &lt;strong&gt;500 тысячам&lt;/strong&gt; репозиториев, и примерно &lt;strong&gt;40%&lt;/strong&gt; из них, это форки. Удивительно, я думал что форков должно быть гораздо гораздо больше.&lt;/p&gt;
&lt;p&gt;Посчитал я и то, насколько больше "второй круг", по сравнению с первым.
В среднем, пользователь гитхаба фоловит 9 человек, и следит за 33 репозиториями, это его "первый круг". Второй круг, это те, кого фоловят те, кого фоловят ты. Второй круг, уже составляет 230 пользователей и 800 репозиториев. И это в среднем. Для нерепрезентативных вроде меня цифры другие: 11548 и 42882 соответственно. Это почти 1/5 всего гитхаба!&lt;/p&gt;
&lt;p&gt;Кроме этого, я посчитал соотношение &lt;strong&gt;обычных пользователей&lt;/strong&gt;  и &lt;strong&gt;организаций&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
&lt;img alt="" src="http://chart.apis.google.com/chart?cht=p3&amp;amp;chs=500x150&amp;amp;chd=s:7C&amp;amp;chtt=%D0%A2%D0%B8%D0%BF%D1%8B%20%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%B9&amp;amp;chco=208020&amp;amp;chl=User%20%2896.41%25%29%7cOrganization%20%283.59%25%29" /&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;h2&gt;Немножко Топов, я знаю, они всем нравятся :)&lt;/h2&gt;
&lt;style&gt;
  div.top {width: 40%; float: left; margin-right: 10%;}
  br.clear {border: 0px; clear: both;}
&lt;/style&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_++++++++"&gt;Top 20 компаний&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Компания&lt;/th&gt;
&lt;th&gt;Кол-во&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td /&gt;
&lt;td&gt;37965&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ThoughtWorks&lt;/td&gt;
&lt;td&gt;75&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mozilla&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freelance&lt;/td&gt;
&lt;td&gt;56&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Twitter&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Japan&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yandex&lt;/td&gt;
&lt;td&gt;39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freelancer&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Globo.com&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yahoo!&lt;/td&gt;
&lt;td&gt;33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intridea&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Facebook&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Student&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emergya&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pivotal Labs&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Engine Yard&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_+++++++"&gt;Top 20 городов&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Город&lt;/th&gt;
&lt;th&gt;Кол-во&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td /&gt;
&lt;td&gt;23657&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;San Francisco&lt;/td&gt;
&lt;td&gt;1441&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;London&lt;/td&gt;
&lt;td&gt;962&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New York&lt;/td&gt;
&lt;td&gt;578&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paris&lt;/td&gt;
&lt;td&gt;474&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chicago&lt;/td&gt;
&lt;td&gt;458&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seattle&lt;/td&gt;
&lt;td&gt;457&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokyo&lt;/td&gt;
&lt;td&gt;430&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Berlin&lt;/td&gt;
&lt;td&gt;423&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Germany&lt;/td&gt;
&lt;td&gt;417&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portland&lt;/td&gt;
&lt;td&gt;346&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toronto&lt;/td&gt;
&lt;td&gt;317&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boston&lt;/td&gt;
&lt;td&gt;288&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Austin&lt;/td&gt;
&lt;td&gt;280&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sydney&lt;/td&gt;
&lt;td&gt;272&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stockholm&lt;/td&gt;
&lt;td&gt;261&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Japan&lt;/td&gt;
&lt;td&gt;244&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Los Angeles&lt;/td&gt;
&lt;td&gt;230&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brooklyn&lt;/td&gt;
&lt;td&gt;226&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Melbourne&lt;/td&gt;
&lt;td&gt;221&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_++++++++++++++"&gt;Top 20 "последователей"&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Логин&lt;/th&gt;
&lt;th&gt;Фолловит&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;snytkine&lt;/td&gt;
&lt;td&gt;3242&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mtsoerin&lt;/td&gt;
&lt;td&gt;1983&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;webiest&lt;/td&gt;
&lt;td&gt;1903&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;superfeedr&lt;/td&gt;
&lt;td&gt;1710&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;charlenopires&lt;/td&gt;
&lt;td&gt;1236&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stonegao&lt;/td&gt;
&lt;td&gt;1205&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marak&lt;/td&gt;
&lt;td&gt;1068&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;speedygonzalez&lt;/td&gt;
&lt;td&gt;1059&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tyru&lt;/td&gt;
&lt;td&gt;1022&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;esneko&lt;/td&gt;
&lt;td&gt;867&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;josegonzalez&lt;/td&gt;
&lt;td&gt;640&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c9s&lt;/td&gt;
&lt;td&gt;556&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kanzure&lt;/td&gt;
&lt;td&gt;555&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;take-cheeze&lt;/td&gt;
&lt;td&gt;517&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;elliottcable&lt;/td&gt;
&lt;td&gt;495&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sannis&lt;/td&gt;
&lt;td&gt;475&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mattn&lt;/td&gt;
&lt;td&gt;462&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;j2labs&lt;/td&gt;
&lt;td&gt;453&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dpree&lt;/td&gt;
&lt;td&gt;446&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rkh&lt;/td&gt;
&lt;td&gt;444&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_++++_++++++++"&gt;Top 20 "кого фолловят"&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Логин&lt;/th&gt;
&lt;th&gt;Последователей&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;defunkt&lt;/td&gt;
&lt;td&gt;4005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torvalds&lt;/td&gt;
&lt;td&gt;3803&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jeresig&lt;/td&gt;
&lt;td&gt;3466&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;mojombo&lt;/td&gt;
&lt;td&gt;3248&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ryanb&lt;/td&gt;
&lt;td&gt;2737&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;schacon&lt;/td&gt;
&lt;td&gt;2429&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;paulirish&lt;/td&gt;
&lt;td&gt;2316&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dhh&lt;/td&gt;
&lt;td&gt;2170&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wycats&lt;/td&gt;
&lt;td&gt;2044&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ry&lt;/td&gt;
&lt;td&gt;2032&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rails&lt;/td&gt;
&lt;td&gt;1946&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;facebook&lt;/td&gt;
&lt;td&gt;1802&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jquery&lt;/td&gt;
&lt;td&gt;1767&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;technoweenie&lt;/td&gt;
&lt;td&gt;1572&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pjhyett&lt;/td&gt;
&lt;td&gt;1563&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;visionmedia&lt;/td&gt;
&lt;td&gt;1554&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cyanogen&lt;/td&gt;
&lt;td&gt;1410&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;douglascrockford&lt;/td&gt;
&lt;td&gt;1380&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tpope&lt;/td&gt;
&lt;td&gt;1369&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;android&lt;/td&gt;
&lt;td&gt;1317&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_++_++++++++++++"&gt;Top 20 "по репозиториям"&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Логин&lt;/th&gt;
&lt;th&gt;Репозиториев&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gitpan&lt;/td&gt;
&lt;td&gt;21976&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vim-scripts&lt;/td&gt;
&lt;td&gt;3735&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;emacsmirror&lt;/td&gt;
&lt;td&gt;3101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Epictetus&lt;/td&gt;
&lt;td&gt;911&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;panega&lt;/td&gt;
&lt;td&gt;612&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jenkinsci&lt;/td&gt;
&lt;td&gt;602&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dev2dev&lt;/td&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wave2future&lt;/td&gt;
&lt;td&gt;411&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CyanogenMod&lt;/td&gt;
&lt;td&gt;342&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MechanisM&lt;/td&gt;
&lt;td&gt;329&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rjbs&lt;/td&gt;
&lt;td&gt;325&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tokuhirom&lt;/td&gt;
&lt;td&gt;297&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rwldrn&lt;/td&gt;
&lt;td&gt;297&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aculich&lt;/td&gt;
&lt;td&gt;287&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rainly&lt;/td&gt;
&lt;td&gt;282&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;albertobraschi&lt;/td&gt;
&lt;td&gt;278&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;idega&lt;/td&gt;
&lt;td&gt;272&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rafl&lt;/td&gt;
&lt;td&gt;266&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;apache&lt;/td&gt;
&lt;td&gt;258&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kristianmandrup&lt;/td&gt;
&lt;td&gt;244&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;div class="top"&gt;

&lt;h3 id="top_20_++++++++_1"&gt;Top 20 "вотчеров"&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Логин&lt;/th&gt;
&lt;th&gt;Наблюдает за&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gitpan&lt;/td&gt;
&lt;td&gt;21976&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vim-scripts&lt;/td&gt;
&lt;td&gt;3736&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;emacsmirror&lt;/td&gt;
&lt;td&gt;3588&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stonegao&lt;/td&gt;
&lt;td&gt;2789&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;abecciu&lt;/td&gt;
&lt;td&gt;2474&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;igrigorik&lt;/td&gt;
&lt;td&gt;2415&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;charlenopires&lt;/td&gt;
&lt;td&gt;2339&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stan&lt;/td&gt;
&lt;td&gt;2318&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;matagus&lt;/td&gt;
&lt;td&gt;2160&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;smtlaissezfaire&lt;/td&gt;
&lt;td&gt;1955&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rmetzler&lt;/td&gt;
&lt;td&gt;1916&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shanlalit&lt;/td&gt;
&lt;td&gt;1897&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;willi&lt;/td&gt;
&lt;td&gt;1896&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Epictetus&lt;/td&gt;
&lt;td&gt;1821&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;filipeamoreira&lt;/td&gt;
&lt;td&gt;1812&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;arden&lt;/td&gt;
&lt;td&gt;1783&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;andrew&lt;/td&gt;
&lt;td&gt;1746&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;methodmissing&lt;/td&gt;
&lt;td&gt;1665&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rkh&lt;/td&gt;
&lt;td&gt;1571&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lgs&lt;/td&gt;
&lt;td&gt;1511&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;h2&gt;Всё&lt;/h2&gt;
&lt;p&gt;Наверняка по той базе, что у меня теперь есть, можно посчитать еще что-нибудь интересненькое. Но пока это всё. Будут идеи — присылайте.&lt;/p&gt;
&lt;p&gt;P.S. — думаю, проектик найдет свою аудиторию в несколько тысяч человек. Осталось придумать, как его монетизировать, чтобы окупать аренду серверных мощностей.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/9NaMuybm-yo" height="1" width="1"/&gt;</summary><category term="git" /><category term="github" /><feedburner:origLink>http://dev.svetlyak.ru/github-stats/</feedburner:origLink></entry><entry><title>For-Else in Python</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/VlGdtjSuZQ4/" rel="alternate" /><updated>2011-04-18T11:18:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/for-else/</id><summary type="html">&lt;p&gt;Пользовались ли вы когда-нибудь ключевым словом &lt;a href="http://docs.python.org/reference/compound_stmts.html#the-for-statement"&gt;&lt;code&gt;else&lt;/code&gt;&lt;/a&gt;, совместно с &lt;code&gt;for&lt;/code&gt;? Нет? Мне тоже не приходилось.
А оказывается, это чрезвычайно удобно в тех случаях, когда в теле цикла используется ключевое слово &lt;code&gt;break&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Как работает &lt;code&gt;else&lt;/code&gt;? Очень просто. Код этой секции выполняется в том случае, если основной цикл завершился
естественным образом, без эксепшена или вызова &lt;code&gt;break&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;То есть, это ключевое слово будет полезно тогда, когда вам нужно выполнить какой-то код только в том случае,
если в цикле были перебраны все элементы. Я на этом сделал аналог &lt;code&gt;switch&lt;/code&gt; с поддержкой регекспов и значением
по-умолчанию:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;REGEXES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r&amp;#39;some ([^ ]+)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;do_some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;r&amp;#39;another ([^ ]+)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;do_another&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;REGEXES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REGEXES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_to_check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regexes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;regexes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_to_check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;blah minor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;REGEXES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;do_default_action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/VlGdtjSuZQ4" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/for-else/</feedburner:origLink></entry><entry><title>Git helper for GitHub Users</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/Dm0ceqbUZ-0/" rel="alternate" /><updated>2011-04-14T12:26:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/hub/</id><summary type="html">&lt;p&gt;Нашел тут &lt;a href="http://defunkt.io/hub/"&gt;скриптик&lt;/a&gt;, облегчающий работу с гитхабом из командной строки. Все что нужно, это иметь установленный ruby (в Mac OS X, он уже есть). Скрипт достаточно скачать куда-нибудь в &lt;code&gt;PATH&lt;/code&gt;, и сделать на него алиас &lt;code&gt;alias git=hub&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Для полноценной работы, нужно так же добавить в &lt;code&gt;~/.gitconfig&lt;/code&gt; секцию с вашим именем и токеном:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="k"&gt;[github]&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;svetlyak40wt&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;а-тут-секретный-токен&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;После этого можно будет, к примеру, по-быстрому форкнуть мой проект &lt;a href="http://github.com/svetlyak40wt/forkfeed"&gt;ForkFeed&lt;/a&gt;, который, кстати, тоже полезен пользователям GitHub:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;clone&lt;/span&gt; &lt;span class="n"&gt;svetlyak40wt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;forkfeed&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="n"&gt;forkfeed&lt;/span&gt;
&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="nb"&gt;fork&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Наслаждайтесь!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/Dm0ceqbUZ-0" height="1" width="1"/&gt;</summary><category term="git" /><feedburner:origLink>http://dev.svetlyak.ru/hub/</feedburner:origLink></entry><entry><title>Github Trends</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/PClDKRMVq5A/" rel="alternate" /><updated>2011-04-05T10:29:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/github-trends/</id><summary type="html">&lt;p&gt;Знаете, какой мой основной паттерн использования GitHub? Помимо хранения в нем кода своих проектиков, конечно.
Я подписан на множество людей, которые постоянно вотчат разные репозитории. И у меня есть RSS фид, в котором
только информация о том, кто чем заинтересовался. Периодически я этот фид просматриваю, и если вижу, что
у какого-то репозитория появилось много вотчеров, то присматриваюсь к проекту поближе.&lt;/p&gt;
&lt;p&gt;И вот вчера меня посетила идея, сделать проект, показывающий рост интереса пользователей к тем или иным проектам
на GitHub. Но прежде чем браться за реализацию, я пошел погуглил и оказалось, что:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;во-первых, такая &lt;a href="https://github.com/languages/Python"&gt;информация уже есть&lt;/a&gt; на самом GitHub, но за ней совершенно неудобно следить, так как нет подписки;&lt;/li&gt;
&lt;li&gt;во-вторых, есть &lt;a href="https://github.com/oscardelben/github-trends/"&gt;проект&lt;/a&gt;, который превращает гитхабовскую информацию в RSSки.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Однако, все же это немного не то, чего бы мне хотелось. Ведь гитхаб показывает просто топ самых популярных проектов,
а хотелось бы видеть кривую роста популярности для каждого из проектов.&lt;/p&gt;
&lt;p&gt;Тем не менее, пока не буду писать свой велосипед, и попробую воспользоваться &lt;a href="3/"&gt;GitHub Trends&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/PClDKRMVq5A" height="1" width="1"/&gt;</summary><category term="git" /><category term="github" /><feedburner:origLink>http://dev.svetlyak.ru/github-trends/</feedburner:origLink></entry><entry><title>Асинхронное тестирование с Twisted</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/PNtxCtKWLxo/" rel="alternate" /><updated>2011-03-01T10:53:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/async-testing/</id><summary type="html">&lt;p&gt;Недавно &lt;a href="http://twitter.com/svetlyak40wt/status/38659219838337024"&gt;я писал&lt;/a&gt; в твиттере, что мне нравится писать юниттесты для программ, использующих Python фреймворк &lt;a href="http://twistedmatrix.com"&gt;Twisted&lt;/a&gt;. В твиттере всего не уместишь, поэтому я решил оформить пояснение отдельным постом.&lt;/p&gt;
&lt;p&gt;Дело в том, что я сейчас разрабатываю распределенный, отказоустойчивый сервис локов. Внутри он асинхронный, использует Twisted. Ноды общаются между собой по TCP, используя собственный текстовый протокол, а наружу предоставляют HTTP интерфейс в духе REST. Мне очень важно обеспечить стабильность и консистентность моего сервиса, потому что от него будет зависеть синхронизация других задач. Поэтому первое что я сделал, это написал тесты. Эти тесты даже и unit-тестами назвать нельзя, они скорее, функциональные.&lt;/p&gt;
&lt;p&gt;Итак, мои тесты тестируют взаимодействие нескольких нод. Ноды обмениваются данными по сети. Но как такой тест запускать? Стартовать ли несколько процессов? И если да, то как их отлаживать?&lt;/p&gt;
&lt;p&gt;Отладка сетевого взаимодействия сложная штука. Но тут (барабанная дробь), на сцену выходит Twisted!&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://img-fotki.yandex.ru/get/5005/alexander-artemenko.e/0_755a1_e15d9963_L" /&gt;&lt;br /&gt;
by &lt;a href="http://www.flickr.com/photos/dirkscircusimages/2785357852/"&gt;dirkjanranzijn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Во-первых, твистед позволил мне запустить все мои пять нод в одном процессе, на одном реакторе. Это позволило ставить &lt;code&gt;pdb.set_trace()&lt;/code&gt; в любом месте, где мне нужен отладчик.&lt;/p&gt;
&lt;p&gt;Во-вторых, я заменил сетевой слой, который они используют для общения, на его упрощенную модель, где сообщения доставляются с некоторой случайной задержкой. Так как генератором случайных чисел можно управлять, то я получил возможность воспроизводить разные "псевдо-случайные" глюки, происходящие в моей системе.  Вот как выглядит процесс тестирования (все происходит автоматически):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;перед запуском теста, &lt;code&gt;TestCase&lt;/code&gt; класс вызывает &lt;code&gt;random.seed(some_value)&lt;/code&gt; и запоминает значение &lt;code&gt;some_value&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;если тест сломался, то помимо обычного сообщения об ошибке, &lt;code&gt;TestCase&lt;/code&gt; выводит &lt;code&gt;RANDOM SEED: some_value&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;чтобы запустить тест, явно инициализировав генератор случайных чисел, я его декорирую:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="nd"&gt;@seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_my_broken_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вот класс &lt;code&gt;TestCase&lt;/code&gt; и декоратор &lt;code&gt;seed&lt;/code&gt;, реализующие данную функциональность:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;twisted.trial&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_random_seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;_random_seed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;seed_info_adder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;#39; (random seed: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s"&gt;)&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;failure&lt;/span&gt;

        &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addErrback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed_info_adder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Что думаете по поводу такого метода отладки? &lt;span style="color: white;"&gt;13558447.88548999.1298975203.fe8d17be47add1425588f6f16d9ae6e9 и 1120000000000244.1354.1298974870.96d80d1dda087b5185ebddd707442782&lt;/span&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/PNtxCtKWLxo" height="1" width="1"/&gt;</summary><category term="python" /><category term="twisted" /><feedburner:origLink>http://dev.svetlyak.ru/async-testing/</feedburner:origLink></entry><entry><title>Еще одна HTTP либа</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/JHiXUFymU3U/" rel="alternate" /><updated>2011-02-16T11:11:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/yet-another-http/</id><summary type="html">&lt;p&gt;Порой в твиттере прилетают интересные ссылки. Так, например, вчера Юрий Юревич заретвитил несколько обновлений с PyPi. Одно из них — новая &lt;a href="http://pypi.python.org/pypi/requests/"&gt;библиотечка для работы с HTTP&lt;/a&gt;. По сути, это всего лишь обертка над стандартными urllib и urllib2, призванная сделать работу с ними проще и понятней. Однако, уже по дизайну этого велосипеда видно, что где его можно улучшить.&lt;/p&gt;
&lt;p&gt;Например, для того, чтобы использовать аутентификацию с именем пользователя и паролем, там предлагается сначала создать некий Auth объект и потом использовать его во всех вызовах:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;conv_auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;requeststest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;requeststest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;https://convore.com/api/account/verify.json&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conv_auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Зачем? Если этот объект только и делает, что хранит имя пользователя и пароль, почему не использовать вместо него tuple (username, password)??? Если уж делаешь просто, почем не идешь до конца?&lt;/p&gt;
&lt;p&gt;И еще пара замечаний по коду. Использовать с python2.5 его нельзя, потому что автор забыл про &lt;code&gt;from __future__ import absolute_import&lt;/code&gt;, try except блоки тоже newstyle, в главном методе, посылающем запрос, чудовищный ifelse блок на два экрана. И еще, он пытается сам вызывать манкипатчинг, если присутствуют библиотеки eventlet или gevent. Что будет, если у меня они установлены в системе, но я не собираюсь их использовать?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/JHiXUFymU3U" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/yet-another-http/</feedburner:origLink></entry><entry><title>Zen для каждого</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/JajNr9mB3HY/" rel="alternate" /><updated>2011-02-15T10:03:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/zen-for-everyone/</id><summary type="html">&lt;p&gt;Есть такой &lt;a href="http://www.python.org/dev/peps/pep-0020/"&gt;PEP-0020&lt;/a&gt;, с которым рекомендуется ознакомиться всем начинающим питонистам как только они изучат &lt;a href="http://www.python.org/dev/peps/pep-0008/"&gt;PEP-0008&lt;/a&gt;. Это краткий свод правил, которых следует придерживаться, программируя на питоне (да и не только не нем, кстати). Правила составил Тим Петерс и они, кстати, доступны прямо из интерпретатора. Достаточно сделать &lt;code&gt;import this&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Но сегодня я хочу дать ссылку на &lt;a href="http://artifex.org/~hblanks/talks/2011/pep20_by_example.html"&gt;приложение к PEP-0020&lt;/a&gt;, написанное Хантером Бланксом. В нем он приводит краткие иллюстрации каждого пункта из "The Zen of Python". Получилось очень наглядно.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/JajNr9mB3HY" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/zen-for-everyone/</feedburner:origLink></entry><entry><title>Эволюция проектов на GitHub</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/gQRPNXxam-s/" rel="alternate" /><updated>2011-02-09T12:11:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/forkfeed/</id><summary type="html">&lt;p&gt;Сегодня зарелизил небольшую но очень полезную тулзу для пользователей GitHub. Проект называется &lt;a href="https://github.com/svetlyak40wt/forkfeed"&gt;Forkfeed&lt;/a&gt;. Он предназначен для слежения за развитием форков ваших проектов на гитхабе.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://img-fotki.yandex.ru/get/5602/alexander-artemenko.e/0_73de3_97d804f1_L" /&gt;&lt;br /&gt;
by &lt;a href="http://www.flickr.com/photos/graeme_pow/4534266872/in/photostream/"&gt;GraemePow@flickr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Часто бывает такое, что кто-то форкает ваш проект, начинает его развивать, а pull реквестов не присылает. А за всем ведь не уследишь. Поэтому я написал скрипт, который обходит все форки всех моих проектов, смотрит какие их коммиты новее моих, и создает Atom фид. &lt;a href="http://forkfeed.svetlyak.ru/svetlyak40wt.xml"&gt;Фид&lt;/a&gt; обновляется по крону, на моем VPS. Теперь я всегда буду в курсе новых форков каждого из моих проектов.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/gQRPNXxam-s" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/forkfeed/</feedburner:origLink></entry><entry><title>Кролик в Бутылке</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/Sn3-P4uaLRE/" rel="alternate" /><updated>2011-02-01T00:35:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/cony-in-the-bottle/</id><summary type="html">&lt;p&gt;Полторы недели назад, в заметке "&lt;a href="http://dev.svetlyak.ru/facebook-bunny1/"&gt;Командная строка для интернетов&lt;/a&gt;", я писал о довольно полезном сервисе умных закладок, которые каждый может дописать под свои нужды и запустить либо на локальной машине, либо на собственном сервере.&lt;/p&gt;
&lt;p&gt;Поковыряв код этого проекта, я пришел к выводу, что он для такой простой идеи, реализация чересчур сложна. И конечно же, решил все переписать :-)&lt;/p&gt;
&lt;p&gt;Теперь &lt;a href="http://github.com/svetlyak40wt/cony/"&gt;мой форк&lt;/a&gt; называется не Bunny, а Cony, что является синонимом слова кролик.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://img-fotki.yandex.ru/get/5800/alexander-artemenko.e/0_735d1_b947df73_L" /&gt;&lt;br /&gt;
by &lt;a href="http://flic.kr/p/6bLmMR"&gt;animalvegetable@flickr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Если Bunny1 тянет за собой большой и толстый CherryPy, то Cony гораздо скромнее. Он основан на микро-фреймворке &lt;a href="http://github.com/defnull/bottle"&gt;Bottle&lt;/a&gt;, а Bottle, это всего лишь один файл, который лежит прямо в репозитории проекта.&lt;/p&gt;
&lt;h2&gt;Расширяй&lt;/h2&gt;
&lt;p&gt;Благодаря отсутствию зависимостей, установка Cony предельно проста — клонируем репозиторий, и запускаем &lt;code&gt;./cony.py&lt;/code&gt;. Дописывание своих шоткатов тоже предельно просто — достаточно положить в текущей директории файлик &lt;code&gt;local_commands.py&lt;/code&gt;. Готовые примеры некоторых команд лежат в директории &lt;code&gt;examples&lt;/code&gt;. Можно в начале &lt;code&gt;local_commands.py&lt;/code&gt; сделать &lt;code&gt;from examples import *&lt;/code&gt; чтобы подключить их все, либо импортировать только нужные функции.&lt;/p&gt;
&lt;h2&gt;Клонируй и делись&lt;/h2&gt;
&lt;p&gt;Если ты написал интересный шоткат, и считаешь, что он будет полезен другим — не ленись, &lt;a href="http://github.com/svetlyak40wt/cony/"&gt;форкни проект&lt;/a&gt; на GitHub, и добавь команду отдельным файлом в examples, а затем пришли Pull Request.&lt;/p&gt;
&lt;h2&gt;И немного про бутылку&lt;/h2&gt;
&lt;p&gt;Bottle мне вполне понравился. Очень минималистичный. В нем есть роутинг урлов и своя реализация шаблонов. Впрочем, шаблонизатор можно использовать любой, как и ORM. Для небольших проектиков вроде этого, когда нужно быстренько поднять сервер и сверстать пару страниц — самое оно.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/Sn3-P4uaLRE" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/cony-in-the-bottle/</feedburner:origLink></entry><entry><title>OpenSource Переводы</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/2jO2Uv3TfvI/" rel="alternate" /><updated>2011-01-27T14:55:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/transifex/</id><summary type="html">&lt;p&gt;Где-то неделю назад, в рассылке &lt;a href="http://groups.google.com/group/django-developers"&gt;django-developers&lt;/a&gt; пробежал анонс, что отныне работать над многочисленными переводами джанги, можно будет через онлайновый сервис переводов &lt;a href="http://www.transifex.net"&gt;Transifex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Transifex, предоставляет интерфейс для работы над переводами. Процесс выглядит так:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Регистрируешься.&lt;/li&gt;
&lt;li&gt;Добавляешь свой проект.&lt;/li&gt;
&lt;li&gt;Указываешь какие у него есть PO файлы, загружая уже готовые переводы.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Дальше нужно чтобы вокруг проекта образовалось некоторое количество желающих его перевести. Они организуются в команды.&lt;/p&gt;
&lt;p&gt;После того, как перевод готов, можно скачать готовые PO файлы.&lt;/p&gt;
&lt;p&gt;Ради эксперимента, я добавил туда один свой небольшой проектик &lt;a href="http://www.transifex.net/projects/p/django-faces/"&gt;django-faces&lt;/a&gt;. Если знаете язык, отличный от английского и русского, попробуйте перевести. Строк для перевода совсем немного.&lt;/p&gt;
&lt;p&gt;Кстати, всего я насчитал на Transifex около 600 проектов, и лишь в половине из них есть ресурсы для перевода. Это значит, что разработчики начинают играться с интерфейсом, но что-то им мешает довести дело до конца. Интерфейс действительно местами очень непонятный. К примеру, я так и не смог понять, как поискать интересный проект, который бы можно было перевести на русский.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/2jO2Uv3TfvI" height="1" width="1"/&gt;</summary><category term="web" /><category term="tools" /><feedburner:origLink>http://dev.svetlyak.ru/transifex/</feedburner:origLink></entry><entry><title>Командная строка для Интернетов</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/F6EabkIeHgw/" rel="alternate" /><updated>2011-01-20T11:11:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/facebook-bunny1/</id><summary type="html">&lt;p&gt;Пользуетесь ли вы поисковыми сокращениями, позволяющими после шотката ввести запрос прямо в адресной строке браузера? Если да, то вам наверняка будет интересно узнать, что можно не только подключать к вашему браузеру готовые поисковые движки, но и писать более изощренные обработчики запросов прямо на Python.&lt;/p&gt;
&lt;p&gt;Вчера я отрыл на гитхабе интересный проект, разработанный когда-то в недрах Facebook. Проект носит странное название &lt;a href="https://github.com/facebook/bunny1/"&gt;Bunny1&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://resizer.co/?image=http%3A%2F%2Ffarm1.static.flickr.com%2F120%2F256250194_ac05247901_o.jpg&amp;amp;w=600" /&gt;&lt;br /&gt;
by &lt;a href="http://www.flickr.com/photos/opid/256250194/"&gt;serenionion@flickr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bunny1, это вебсервер, который принимает команду и некоторый запрос, а затем либо редиректит куда-то, либо показывает HTML страницу с результатом. Если подключить URL этого сервера в качестве поиска по умолчанию, то вы получаете командную строку прямо в браузере. И самое полезное тут то, что:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;это будет работать во всех современных браузерах;&lt;/li&gt;
&lt;li&gt;команды можно дописывать самому, на python.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;К примеру, можно написать обработчик, который по запросу &lt;code&gt;tw Доброе утро Москва!&lt;/code&gt; будет твитить в ваш аккаунт и редиректить на страничку этого твита.&lt;/p&gt;
&lt;p&gt;Справедливости ради, стоит отметить, что идея не нова. Существует, к примеру, отдельный сервис &lt;a href="http://yubnub.org/"&gt;YubNub&lt;/a&gt;, реализующий эту функциональность, и плагин для Firefox &lt;a href="https://mozillalabs.com/ubiquity/"&gt;Ubiquity&lt;/a&gt;. Но первый содержит множество лишних команд и там нельзя дописать новые, а второй работает только под Firefox.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/F6EabkIeHgw" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/facebook-bunny1/</feedburner:origLink></entry><entry><title>Отладчик с блэкджеком</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/wAy_cc0PG5Y/" rel="alternate" /><updated>2011-01-18T14:13:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/debugger-with-blackjack/</id><summary type="html">&lt;p&gt;Я решил придерживаться определенного графика публикации постов. Попробую выкладывать что-нибудь интересное каждый вторник и четверг.&lt;/p&gt;
&lt;p&gt;Сегодня я хочу рассказать вам о довольно полезном инструменте, а именно — об отладчике. Если вы не любитель развесистых IDE, то наверняка пользовались стандартным отладчиком питона pdb. Он покрывает 90% необходимой мне функциональности, но все же, несколько неудобен. Например, в нем нет автокомплита и несколько напрягает необходимость периодически набирать команду для вывода листинга, чтобы посмотреть на контекст текущей строки.&lt;/p&gt;
&lt;p&gt;Эти, а так же некоторые другие проблемы, призван решить проект &lt;a href="https://bitbucket.org/antocuni/pdb/src"&gt;pdbpp&lt;/a&gt;. Вот несколько фич, которые оказались мне наиболее полезны:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sticky mode — в этом режиме отладчик перерисовывает текущую функцию после каждого шага интерпретатора;&lt;/li&gt;
&lt;li&gt;автокомплит по табу — больше не надо вызывать &lt;code&gt;dir(obj)&lt;/code&gt; чтобы ознакомиться с интерфейсом объекта;&lt;/li&gt;
&lt;li&gt;подсветка синтаксиса — pdbpp использует Pygments, чтобы сделать код еще прекраснее чем он есть (ведь твой код прекрасен, разве нет?).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Кроме этого, там есть такие штуки, как вызов редактора для исправления трассируемого файла, умный парсинг команд, команда &lt;code&gt;longlist (ll)&lt;/code&gt; для вывода на экран текущей функции или метода.&lt;/p&gt;
&lt;p&gt;Вот так выглядит типичная сессия pdbpp:&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://bitbucket.org/antocuni/pdb/raw/0c86c93cee41/screenshot.png" /&gt;&lt;/p&gt;
&lt;p&gt;А для того, чтобы использовать этот чудесный инструмент, достаточно установить его в систему любым из доступных вам способов, после чего, как обычно, можно использовать &lt;code&gt;import pdb; pdb.set_trace()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; записал короткую демку того, как это работает.&lt;/p&gt;
&lt;p&gt;&lt;object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,115,0' width='560' height='345'&gt;&lt;param name='movie' value='http://screenr.com/Content/assets/screenr_1116090935.swf' &gt;&lt;/param&gt;&lt;param name='flashvars' value='i=158211' &gt;&lt;/param&gt;&lt;param name='allowFullScreen' value='true' &gt;&lt;/param&gt;&lt;embed src='http://screenr.com/Content/assets/screenr_1116090935.swf' flashvars='i=158211' allowFullScreen='true' width='560' height='345' pluginspage='http://www.macromedia.com/go/getflashplayer' &gt;&lt;/embed&gt;&lt;/object&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/wAy_cc0PG5Y" height="1" width="1"/&gt;</summary><category term="python" /><feedburner:origLink>http://dev.svetlyak.ru/debugger-with-blackjack/</feedburner:origLink></entry><entry><title>Социальные закладки на GitHub</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/a3foh6KBvHA/" rel="alternate" /><updated>2011-01-13T11:17:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/gitmarks/</id><summary type="html">&lt;p&gt;Сегодня я хочу рассказать вам о довольно интересном проекте, появившемся недавно на GitHub.
Разрабатывается он некой девой Hilary Mason и называется &lt;a href="https://github.com/hmason/gitmarks/"&gt;gitmarks&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Суть проекта в следующем. Он позволяет сохранять URL в закладки и делиться ими
с другими пользователями через GitHub. Для каждой закладки, скрипт выкачивает
содержимое залинкованной страницы. Так же, можно задать теги и описание
ссылки. Ну и конечно же, можно использовать &lt;code&gt;git grep&lt;/code&gt; для поиска по своим
закладкам. Добавлять ссылки можно как из командной строки, так и с помощью
букмарклета, но для этого нужно запустить локальный вебсервер.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://farm3.static.flickr.com/2262/2201268993_a560441f47.jpg" /&gt;&lt;br /&gt;
Автор фотографии &lt;a href="http://www.flickr.com/photos/eikumpel/2201268993/"&gt;Ei! Kumpel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Однако, у этого проекта есть, и несколько недостатков.&lt;/p&gt;
&lt;p&gt;Во-первых, код выглядит довольно безобразно из-за того, что Хилари не
придерживается общепринятых в Python сообществе, соглашений.&lt;/p&gt;
&lt;p&gt;Во-вторых, из той документации, что есть, совершенно непонятно, где следует
хранить закладки. В каком репозитории? Из-за этого, многие уже начали форкать
репозиторий, и добавлять закладки прямо в него, рядом с кодом, что захламляет
&lt;a href="https://github.com/hmason/gitmarks/network"&gt;network graph&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Стоило бы специальным образом отделить код проекта от контента, чтобы не
путать разработку с жизнью сервиса.&lt;/p&gt;
&lt;p&gt;Ну и в третьих, есть всякие мелочи, которые доставляют неудобства. Например,
предполагается, что люди могут комментировать закладки друг друга, прямо на
GitHub, оставляя коммент к коммиту. Однако сейчас страничка каждого коммита
выглядит довольно страшно, поскольку включает в себя весь HTML код по
добавленному URL. Этого можно было бы избежать, преобразуя HTML в читаемый
текст.&lt;/p&gt;
&lt;p&gt;В общем, надеюсь что проект получит развитие, и у нас появится новый,
распределенный сервис закладок.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/a3foh6KBvHA" height="1" width="1"/&gt;</summary><category term="python" /><category term="git" /><feedburner:origLink>http://dev.svetlyak.ru/gitmarks/</feedburner:origLink></entry><entry><title>Diff Git Cached в Vim</title><link href="http://feedproxy.google.com/~r/dev-svetlyak/all/~3/g_Vz5tdw0nI/" rel="alternate" /><updated>2011-01-09T14:04:00Z</updated><author><name>Александр Артеменко</name></author><id>http://dev.svetlyak.ru/diff-git-cached/</id><summary type="html">&lt;p&gt;Оказывается в Vim есть полезная штука для просмотре диффа при редактировании commit message git. Она появилась, начиная с версии 7.2. Называется эта команда :DiffGitCached.&lt;/p&gt;
&lt;p&gt;Дифф можно вызывать вручную, а можно прописать в конфиг такую строчку:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;autocmd&lt;/span&gt; &lt;span class="n"&gt;FileType&lt;/span&gt; &lt;span class="n"&gt;gitcommit&lt;/span&gt; &lt;span class="n"&gt;DiffGitCached&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;wincmd&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;И тогда дифф будет открываться автоматически после запуска &lt;code&gt;git commit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Этот хинт я почерпнул из книги &lt;a href="http://vim.runpaint.org/extending/integrating-vim-with-git/"&gt;Vim Recipes&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/dev-svetlyak/all/~4/g_Vz5tdw0nI" height="1" width="1"/&gt;</summary><category term="vim" /><category term="git" /><feedburner:origLink>http://dev.svetlyak.ru/diff-git-cached/</feedburner:origLink></entry></feed>

