<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-895282391928669909</id><updated>2024-09-05T23:28:09.863+06:00</updated><category term="Python"/><category term="заметки на полях"/><category term="PHP"/><category term="linux"/><category term="проекты"/><category term="MySQL"/><category term="Django"/><category term="графика"/><category term="конференции"/><category term="Ruby"/><category term="kindle"/><category term="open source"/><category term="базы данных"/><title type='text'>Блог Дениса Малиновского</title><subtitle type='html'>Эксперименты, открытия и находки</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-6675127864172071985</id><published>2013-04-01T17:01:00.001+07:00</published><updated>2013-04-01T17:01:44.761+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="конференции"/><title type='text'>Мои впечатления о последнем CodeFest</title><content type='html'>&lt;p&gt;Организаторы и докладчики были на высоте, примерно на уровне прошлой конференции. В этот раз впервые были англоязычные докладчики, подробнее ниже. Как всегда, было много стендов разных компаний, ребята из JetBrains даже соблазнили меня попробовать PyCharm, но после пяти минут я плюнул и вернулся к старому доброму Vim — очень уж давно я с ним работаю, всё настроено под себя, и с клавиатурой работать гораздо быстрее, чем с мышкой.&lt;/p&gt;

&lt;p&gt;Теперь немного о запомнившихся докладах.&lt;/p&gt;

&lt;h2&gt;День первый&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://2013.codefest.ru/dokladchik/3147/&quot;&gt;Аксель Раушмайер&lt;/a&gt; выступил с докладом о будущем JavaScript — ECMAScript 6. Обещается много нового и полезного, большую часть из чего можно обеспечить уже сейчас в ECMAScript 5 с помощью CoffeeScript, underscore и CommonJS.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://2013.codefest.ru/doklad/31&quot;&gt;Майкл Палотас&lt;/a&gt; из eBay в Цюрихе (привет аборигенам!) рассказал о QA в его компании, как их развивают, холят и лелеют, ну хоть прям щас в eBay, менять специализацию.&lt;/p&gt;

&lt;p&gt;Окончание докладов я пропустил, нужно было торопиться на ДР дочери. День вышел насыщенным.&lt;/p&gt;

&lt;h2&gt;День второй&lt;/h2&gt;

&lt;p&gt;Харизматичный &lt;a href=&quot;http://2013.codefest.ru/dokladchik/3183/&quot;&gt;Денис Шергин&lt;/a&gt; из томской компании Unigine заставил испытать гордость за отечественных программистов — команда из 25 человек успешно конкурирует с крупнейшими конторами из сотен и тысяч людей в области 3D-движков.&lt;/p&gt;

&lt;p&gt;Интересно было послушать про опыт &lt;a href=&quot;http://2013.codefest.ru/doklad/46&quot;&gt;открытия нового офиса 2ГИС в Киеве&lt;/a&gt;. Ещё интереснее было бы услышать, в чём разница между украинскими и российскими разработчиками, докладчики упомянули об этом, но, к сожалению, без подробностей.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://2013.codefest.ru/kvartirniki/opera-webkit/&quot;&gt;Вадим Макеев&lt;/a&gt; из Opera рассказал, почему же они бросили свой браузерный движок и переключились на Webkit. Вкратце — из-за проблем совместимости сайтов, игнорировании Оперы западными программистами и т.п. Теперь Опера тоже будет вносить патчи в код Webkit.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://2013.codefest.ru/doklad/53&quot;&gt;Никита Прокопов&lt;/a&gt; зажигательно поведал о Clojure, сразу захотелось попробовать ClojureScript в деле.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://2013.codefest.ru/doklad/58&quot;&gt;Денис Бесков&lt;/a&gt; рассказал о том, как создавать новый продукт. Доклад был интересным, но многое (если не всё) из этого освещено в знаменитой книжке 37signals «&lt;a href=&quot;http://gettingreal.37signals.com/&quot;&gt;Getting Real&lt;/a&gt;».&lt;/p&gt;

&lt;p&gt;И в заключение &lt;a href=&quot;http://2013.codefest.ru/doklad/61&quot;&gt;Глеб Кудрявцев&lt;/a&gt; весело и живо сделал доклад о том, как PM найти общий язык с программистами к взаимному удовлетворению.&lt;/p&gt;

&lt;h2&gt;Мораль&lt;/h2&gt;

&lt;p&gt;В очередной раз убедился, что не так важна тема доклада, как личность докладчика. Нужно тренироваться делать доклады, снимать себя на видео, смотреть, анализировать и учиться.&lt;/p&gt;

&lt;p&gt;CodeFest очень вдохновляет. Я понял, как соскучился по работе с людьми offline, в одном офисе. Всё-таки два года удалёнки дают о себе знать. Погрел самооценку осознанием своей востребованности для многих компаний, в том числе интересных мне. Нужно больше общаться. :)&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/6675127864172071985/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2013/04/codefest.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/6675127864172071985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/6675127864172071985'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2013/04/codefest.html' title='Мои впечатления о последнем &lt;a href=&quot;http://2013.codefest.ru/&quot;&gt;CodeFest&lt;/a&gt;'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total><georss:featurename>Новосибирск, Новосибирская область, Россия</georss:featurename><georss:point>55.018804 82.933948999999984</georss:point><georss:box>54.435469000000005 81.643055499999988 55.602139 84.22484249999998</georss:box></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-1535209367685559812</id><published>2012-11-11T19:46:00.002+07:00</published><updated>2012-11-11T19:46:50.271+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="kindle"/><title type='text'>Типографика в Kindle</title><content type='html'>&lt;h2&gt;Status quo&lt;/h2&gt;

&lt;p&gt;Давным-давно я работал верстальщиком, а последние 10 лет — программистом, но любовь к красиво оформленному тексту осталась. Ещё я заядлый библиофил, львиную долю книг поглощаю в электронном виде, последний год с помощью Amazon Kindle.&lt;/p&gt;

&lt;p&gt;Kindle, к сожалению, не поддерживает переноса текста по слогам; при этом выравнивание у него не левое и даже не полное, а «недополное» (обратите внимание на предпоследнюю строчку первого абзаца):&lt;/p&gt;

&lt;img src=&quot;http://img-fotki.yandex.ru/get/6518/675668.5e/0_83719_e5c55d63_L.jpg&quot; alt=&quot;«Недополное» выравнивание&quot; /&gt;


&lt;h2&gt;Слева&lt;/h2&gt;

&lt;p&gt;Бесплатные или платные книги, скаченные с самого Amazon, можно привести к левому выравниванию. Правда, способ этот работает не для всех книг, а только для тех, где явно не указывается выравнивание текста. Для этого нужно закрыть текущую книгу, подключить Kindle через USB к компьютеру и отредактировать там скрытый файл &lt;code&gt;system/com.amazon.ebook.booklet.reader/reader.pref&lt;/code&gt;, добавив строчку &lt;code&gt;ALLOW_JUSTIFICATION_CHANGE=true&lt;/code&gt;. После чего файл сохраняем, книжку отключаем и перезагружаем её. Для этого нужно зайти в меню &lt;code&gt;Settings&lt;/code&gt;, а там уже выбираем меню &lt;code&gt;Restart&lt;/code&gt;. Вуаля! — появился новый элемент меню «Justification»:&lt;/p&gt;

&lt;img src=&quot;http://img-fotki.yandex.ru/get/6617/675668.5e/0_83718_9d84ab51_L.jpg&quot; alt=&quot;Меню «Justification»&quot; /&gt;


&lt;p&gt;Этот финт ушами, к сожалению, не работает с книжками, купленными в &lt;a href=&quot;http://www.litres.ru/&quot;&gt;Литрес&lt;/a&gt; или скаченными в русскоязычных &lt;a href=&quot;http://lib.rus.ec/&quot;&gt;пиратских&lt;/a&gt; &lt;a href=&quot;http://flibusta.net/&quot;&gt;библиотеках&lt;/a&gt; — там выравнивание в файлах &lt;code&gt;mobi&lt;/code&gt; указано явно. Нам поможет программа для конвертации форматов электронных книг &lt;a href=&quot;http://calibre-ebook.com/&quot;&gt;Calibre&lt;/a&gt;. Она содержит набор программ для командной строки (для Mac OS их нужно дополнительно &lt;a href=&quot;http://manual.calibre-ebook.com/cli/cli-index.html#cli&quot;&gt;установить&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Скачиваем/покупаем нужную книгу в формате FB2 и обрабатываем с помощью простой команды:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ebook-convert book.fb2 book.mobi --change-justification left
&lt;/code&gt;&lt;/pre&gt;

&lt;img src=&quot;http://img-fotki.yandex.ru/get/6516/675668.5e/0_8371b_c58069ea_L.jpg&quot; alt=&quot;Выравнивание слева&quot; /&gt;


&lt;h2&gt;PDF&lt;/h2&gt;

&lt;p&gt;Другой вариант — преобразовывать FB2 в PDF с помощью кросс-платформенного проекта на Java &lt;a href=&quot;https://sites.google.com/site/fb2pdfj/&quot;&gt;fb2pdf&lt;/a&gt;. Можно достаточно гибко настроить форматировать, текст будет поддерживать буквицы, переносы, висячие строки и прочие вкусности.&lt;/p&gt;

&lt;p&gt;Минусы: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;размер и тип шрифта нельзя менять после создания книги;&lt;/li&gt;
&lt;li&gt;размер файла PDF в несколько раз больше аналогичного mobi;&lt;/li&gt;
&lt;li&gt;аннотации не работают. Впрочем, поиск по файлу и просмотр слова в словаре доступны.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;«Мягкие» переносы&lt;/h2&gt;

&lt;p&gt;В Kindle 3 (aka Keyboard) и новее в последних версиях прошивки появилась поддержка нового формата K8. Это значит, что доступны многие теги HTML5 и атрибуты CSS3, вдобавок к ним и &lt;a href=&quot;http://en.wikipedia.org/wiki/Soft_hyphen&quot;&gt;мягкие переносы&lt;/a&gt;. Они предназначены для разбивки слов по слогам и становится видимы только на правой границе строки — программа использует их для переноса текста по слогам, т.е. то, что нам и нужно.&lt;/p&gt;

&lt;p&gt;Минус: размер подготовленного файла незначительно больше «сырого»;&lt;/p&gt;

&lt;p&gt;Зато все остальные плюсы в наличии — размер шрифта легко менять по ходу чтения, поиск и аннотации работают корректно, все счастливы.&lt;/p&gt;

&lt;p&gt;Для создания таких книг я создал небольшую &lt;a href=&quot;https://github.com/dmalinovsky/fb2-hyphens&quot;&gt;программку&lt;/a&gt; под *nix, расставляющую переносы в FB2-файле. Для конвертирования в AZW3 (это формат для Kindle, который собственно и поддерживает K8), можно использовать в качестве образца прилагаемый &lt;a href=&quot;https://github.com/dmalinovsky/fb2-hyphens/blob/master/fb2mobi.sh.example&quot;&gt;скрипт&lt;/a&gt;.&lt;/p&gt;

&lt;img src=&quot;http://img-fotki.yandex.ru/get/6617/675668.5e/0_8371a_4a6caf28_L.jpg&quot; alt=&quot;Переносы&quot; /&gt;


&lt;p&gt;Для счастливых обладателей Windows есть более &lt;a href=&quot;http://www.the-ebook.org/forum/viewtopic.php?t=24335&quot;&gt;удобный вариант&lt;/a&gt;.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/1535209367685559812/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2012/11/kindle.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1535209367685559812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1535209367685559812'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2012/11/kindle.html' title='Типографика в Kindle'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-7747174762987719194</id><published>2012-04-01T17:42:00.000+07:00</published><updated>2012-04-01T17:44:25.270+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="конференции"/><title type='text'>CodeFest</title><content type='html'>Очень долго ничего не писал, а тут такой повод появился — &lt;a href=&quot;http://codefest.ru/&quot;&gt;CodeFest&lt;/a&gt;! Вообще это вторая IT-конференция в моём ленивом опыте, она же крупнейшая. Более 1300 человек, три зала, куча интересных людей, энергия так и пышет. Организаторы на высоте, единственный минус — душно. Но это, наверное, больше проблема помещения.&lt;br /&gt;
&lt;br /&gt;
В первый день на web-секции больше всего запомнился полный харизмы и оптимизма доклад &lt;a href=&quot;http://blog.evtuhovich.ru/&quot;&gt;Ивана Евтуховича&lt;/a&gt; из &lt;a href=&quot;http://evilmartians.ru/&quot;&gt;«Evil Martians»&lt;/a&gt; «Как мы делали Групон». У такого человека я бы хотел работать. Автор — явно многосторонняя личность, первый дан по айкидо среди прочего.&lt;br /&gt;
&lt;br /&gt;
Ещё отжёг весёлый матерщинник Андрей Аксёнов из Sphinx. Но у него я бы работать не хотел. :)&lt;br /&gt;
&lt;br /&gt;
Во второй день в секции PM + HR блеснули Александр Орлов и Вячеслав Панкратов из &lt;a href=&quot;http://www.stratoplan.ru/&quot;&gt;Стратоплана&lt;/a&gt;. Тема доклада —&amp;nbsp;конструктивная обратная связь в менеджменте — мне была не очень близка, но мастерство докладчиков позволяет красиво донести любую инфу, наверное.&lt;br /&gt;
&lt;br /&gt;
Главный бонус посещения конференции — заряд энергии, желания двигаться и шевелиться. Полезно временами вылезать из своей раковины в большой живой мир.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/7747174762987719194/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2012/04/codefest.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7747174762987719194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7747174762987719194'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2012/04/codefest.html' title='CodeFest'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-3577758209250409364</id><published>2011-04-25T10:17:00.001+07:00</published><updated>2011-04-25T10:17:33.977+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Соглашение о вызовах</title><content type='html'>Интересная статья о всевозможных вариантах вызова и использования функций: сопрограммы (coroutines), рекурсия, хвостовая рекурсия (tail call optimization), каррирование и многое другое.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://jjinux.blogspot.com/2011/04/call-me-crazy-calling-conventions.html&quot;&gt;http://jjinux.blogspot.com/2011/04/call-me-crazy-calling-conventions.html&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/3577758209250409364/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/04/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3577758209250409364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3577758209250409364'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/04/blog-post.html' title='Соглашение о вызовах'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-1860796960045165668</id><published>2011-03-14T16:17:00.001+06:00</published><updated>2011-06-19T18:49:05.177+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><category scheme="http://www.blogger.com/atom/ns#" term="проекты"/><title type='text'>Делимся Питоном с миром</title><content type='html'>Когда питоновские скрипты приобретают какую-то готовую форму, и ими хочется поделиться с другими, возникает вопрос: как это правильно и красиво сделать?&lt;br /&gt;
&lt;br /&gt;
Стандартом для распространения программ на Python является &lt;a href=&quot;http://pypi.python.org/pypi&quot;&gt;Python Package Index&lt;/a&gt;, своего рода центральный Python-репозиторий. О процессе публикации &lt;a href=&quot;http://docs.python.org/distutils/index.html#distutils-index&quot;&gt;много&lt;/a&gt; &lt;a href=&quot;http://packages.python.org/distribute/setuptools.html&quot;&gt;написано&lt;/a&gt;, покажу, как это делается, на своём примере.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Есть известный сайт-библиотека Lib.ru с разделом для писателей — &lt;a href=&quot;http://zhurnal.lib.ru/&quot;&gt;СамИздат&lt;/a&gt;, СИ. С помощью &lt;a href=&quot;http://www.riverbankcomputing.com/software/pyqt/download&quot;&gt;PyQt&lt;/a&gt; и &lt;a href=&quot;http://packages.python.org/pyquery/&quot;&gt;pyquery&lt;/a&gt; я написал &lt;a href=&quot;https://bitbucket.org/dmalinovsky/si-news/&quot;&gt;программку&lt;/a&gt; для слежения за новинками СИ. &lt;br /&gt;
&lt;br /&gt;
Первая важная деталь — в отличие от поделок &quot;для себя&quot;, настройки нельзя хранить в текущем каталоге, для Linux нужно использовать что-то вроде `$HOME/.si_news/`:&lt;br /&gt;
&lt;pre class=&quot;python&quot; name=&quot;code&quot;&gt;# Folder to store all configuration
HOMEDIR = os.path.expanduser(os.path.join(&#39;~&#39;, &#39;.si_news&#39;))
if not os.path.isdir(HOMEDIR):
    os.mkdir(HOMEDIR)

# File name with list of friends
CFG_FRIENDS = os.path.join(HOMEDIR, &#39;friends.cfg&#39;)
&lt;/pre&gt;&lt;br /&gt;
Для простоты весь код размещается в одном файле, si_news.py. Следующий этап — выкладывание упакованных исходников на сайте PyPI. Создаём setup.py с заполненными метаданными приложения:&lt;br /&gt;
&lt;pre class=&quot;python&quot; name=&quot;code&quot;&gt;from setuptools import setup

setup(
    name=&#39;si-news&#39;,
    version=&#39;0.1.1&#39;,
    description=&#39;Tracks updates for zhurnal.lib.ru authors&#39;,
    author=&#39;Denis Malinovsky&#39;,
    author_email=&#39;dmalinovsky@gmail.com&#39;,
    url=&#39;https://bitbucket.org/dmalinovsky/si-news/&#39;,
    py_modules=[&#39;si_news&#39;],
    install_requires=[&#39;distribute&#39;, &#39;pyquery&#39;],
    license=&#39;gpl&#39;,
    classifiers=[
        &#39;Development Status :: 3 - Alpha&#39;,
        &#39;Environment :: MacOS X&#39;,
        &#39;Environment :: Win32 (MS Windows)&#39;,
        &#39;Environment :: X11 Applications :: Qt&#39;,
        &#39;Intended Audience :: End Users/Desktop&#39;,
        &#39;License :: OSI Approved :: GNU General Public License (GPL)&#39;,
        &#39;Natural Language :: Russian&#39;,
        &#39;Operating System :: OS Independent&#39;,
        &#39;Programming Language :: Python&#39;,
        &#39;Topic :: Internet :: WWW/HTTP&#39;,
        &#39;Topic :: Utilities&#39;,
        ],
    entry_points = {
        &#39;gui_scripts&#39;: [
            &#39;si_news = si_news&#39;,
            ]
        },
)
&lt;/pre&gt;&lt;br /&gt;
Встроенный в Python distutils не позволяет обрабатывать зависимости при установке, поэтому я использовал наследника брошенного setuptools, &lt;a href=&quot;http://packages.python.org/distribute/&quot;&gt;distribute&lt;/a&gt;. Метаданные в setup.py говорят сами за себя, два комментария — classifiers позволяет отнести программу к нужным категориям PyPI, а entry_points создаёт команды для запуска разных частей нашего приложения.&lt;br /&gt;
&lt;br /&gt;
Затем запускаем `&lt;code&gt;python setup.py register sdist upload&lt;/code&gt;` для регистрации на сайте PyPI, упаковки исходников в tar.gz и загрузки на сайт.&lt;br /&gt;
&lt;br /&gt;
К сожалению, PyQt нельзя установить с помощью setuptools и т.п., приходится ставить по старинке, с помощью `&lt;code&gt;apt-get install python-qt4&lt;/code&gt;`. Зато саму программу можно установить с помощью замечательного инсталлятора &lt;a href=&quot;http://www.pip-installer.org/en/latest/index.html&quot;&gt;pip&lt;/a&gt;: `&lt;code&gt;pip install si-news&lt;/code&gt;`.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/1860796960045165668/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post_14.html#comment-form' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1860796960045165668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1860796960045165668'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post_14.html' title='Делимся Питоном с миром'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-8068000245468930874</id><published>2011-03-07T20:31:00.002+06:00</published><updated>2011-04-14T10:16:51.306+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><category scheme="http://www.blogger.com/atom/ns#" term="проекты"/><title type='text'>Реанимация данных</title><content type='html'>Жена с дочкой используют внешний USB-винт для хранения видео и всего такого. На днях прикупил новый, стал копировать данные со старого, и — бац! — I/O error! Битые сектора, они же бэд-блоки.&lt;br /&gt;
&lt;br /&gt;
В итоге не удалось скопировать 4 видеофайла. Тут на помощь приходит старая добрая утилитка &lt;a href=&quot;http://www.garloff.de/kurt/linux/ddrescue/&quot;&gt;ddrescue&lt;/a&gt; — при ошибке ввода-вывода продолжает копировать посекторно, пропуская плохие участки, в итоге удаётся бóльшую часть данных вытащить; позволяет копировать как целое устройство, так и отдельный файл. Видео спасти получилось, благо небольшая доля мусора внутри файла не мешает его воспроизводить.&lt;br /&gt;
&lt;br /&gt;
К сожалению, ddrescue не позволяет копировать целые директории рекурсивно. Тогда я написал простой скрипт на Python, &lt;a href=&quot;https://bitbucket.org/dmalinovsky/rddr&quot;&gt;rddr&lt;/a&gt; (Recursive DDRescue), копирующий каталог целиком с помощью того же ddrescue.&lt;br /&gt;
&lt;br /&gt;
Но этот эпизод с винтом меня смутил — ведь есть же &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_SMART&quot;&gt;SMART&lt;/a&gt;, почему Ubuntu мне не сказал о непригодном состоянии диска? Оказалось, что состояние его &quot;хорошее&quot;, но есть несколько плохих секторов. Есть у SMART такой атрибут, показывающий количество секторов, ожидающих замены из специальной дисковой зоны &quot;хороших&quot; секторов, причём замена происходит при попытке записи, а не чтения. Теперь на помощь приходит программа &lt;a href=&quot;http://e2fsprogs.sourceforge.net&quot;&gt;badblocks&lt;/a&gt; — она позволяет прогонять тесты чтения/записи по всему устройству. Тесты записи на винт заняли около одиннадцати часов, данные при этом затёрлись. 19 секторов из 20 восстановились из резервной области. &lt;br /&gt;
&lt;br /&gt;
Вердикт: винчестер можно использовать для некритичных данных, видео хранить вполне годится.&lt;br /&gt;
&lt;br /&gt;
P.S. Прекрасное руководство для восстановления данных с помощью Linux можно &lt;a href=&quot;https://help.ubuntu.com/community/DataRecovery&quot;&gt;здесь&lt;/a&gt; почитать.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/8068000245468930874/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post_07.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8068000245468930874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8068000245468930874'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post_07.html' title='Реанимация данных'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-8517694786645799647</id><published>2011-03-04T15:23:00.000+06:00</published><updated>2011-03-04T15:23:52.759+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Django"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>Скоро выйдет Django 1.3</title><content type='html'>3 марта &lt;a href=&quot;http://www.djangoproject.com/weblog/2011/mar/03/13-rc/&quot;&gt;вышел&lt;/a&gt; кандидат в релизы Django 1.3. Я не вытерпел и полюбовался на внушительный &lt;a href=&quot;http://docs.djangoproject.com/en/dev/releases/1.3/&quot;&gt;список изменений&lt;/a&gt; будущей версии. &lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;b&gt;Что нового&lt;/b&gt;&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/class-based-views/&quot;&gt;Вьюхи (views, как это лучше перевести?), основанные на классах.&lt;/a&gt; Это значит, что view может состоять из набора методов, их можно переопределить в унаследованных вьюхах без особых затрат по написанию кода. Вот &lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/generic-views-migration/&quot;&gt;дока по миграции&lt;/a&gt; со старых вьюх на функциях в новые на классах.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/logging/&quot;&gt;Логирование&lt;/a&gt; — добавляется поддержка стандартного модуля &lt;code&gt;logging&lt;/code&gt; на уровне фреймворка. Что важно, теперь письма об ошибках №500 обрабатываются как событие лога.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/&quot;&gt;Расширенная обработка статических файлов&lt;/a&gt; — для этой цели добавляется новое приложение в contrib, &lt;code&gt;&#39;django.contrib.staticfiles&#39;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Поддержка &lt;a href=&quot;http://pypi.python.org/pypi/unittest2&quot;&gt;unittest2&lt;/a&gt; — Django включает в себя эту библиотеку из Python 2.7, портировав под Python 2.4.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/db/transactions/#transaction-management-functions&quot;&gt;Контекстные менеджеры транзакций&lt;/a&gt; — пользователи Python версии &amp;gt;=2.5 могут использовать ключевое слово with. Что-то похожее я для MySQL &lt;a href=&quot;http://dmalinovsky.blogspot.com/2010/06/mysql-python.html&quot;&gt;использовал&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.on_delete&quot;&gt;Настройка каскадного удаления&lt;/a&gt; — теперь можно указывать, в каких случаях связанный объект удаляется.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/i18n/internationalization/#contextual-markers&quot;&gt;Контекстные маркеры&lt;/a&gt; и &lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/i18n/internationalization/#translator-comments&quot;&gt;комментарии к строкам перевода&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/ref/template-response/&quot;&gt;TemplateResponse&lt;/a&gt; — теперь можно изменять ответ после его создания вьюхой, например, можно сменить шаблон или добавить контекстные данные.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/cache/&quot;&gt;Изменения в работе кэша&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/auth/&quot;&gt;Права доступа неактивных пользователей&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MEDIA_URL&lt;/code&gt; и &lt;code&gt;STATIC_URL&lt;/code&gt; должны заканчиваться слэшом.&lt;/li&gt;
&lt;li&gt;И &lt;a href=&quot;http://draft.blogger.com/post-create.g?blogID=895282391928669909&quot;&gt;множество&lt;/a&gt; более мелких правок.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;&lt;a href=&quot;http://docs.djangoproject.com/en/dev/releases/1.3/#backwards-incompatible-changes-in-1-3&quot;&gt;Куча изменений&lt;/a&gt;, несовместимых с прежними версиями. Поддержка mod_python прекратится к версии 1.5. Да здравствует &lt;a href=&quot;http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/&quot;&gt;mod_wsgi&lt;/a&gt;!&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/8517694786645799647/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/django-13.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8517694786645799647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8517694786645799647'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/django-13.html' title='Скоро выйдет Django 1.3'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-7428759451492243293</id><published>2011-03-02T17:18:00.000+06:00</published><updated>2011-03-02T17:18:07.229+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Волшебная кнопка</title><content type='html'>Несколько раз я сталкивался с тем, что запущенная в линуксе программа начинает отжирать всю доступную память, система сваливается в штопор, и закрыть виновницу удаётся с большим трудом... Простой пример для теста — откройте XML файл в несколько мегабайт в Firefox. ;)&lt;br /&gt;
&lt;br /&gt;
Уже гораздо позже я узнал, что есть т.н. &quot;&lt;a href=&quot;http://en.wikipedia.org/wiki/Magic_SysRq_key&quot;&gt;волшебная кнопка&lt;/a&gt;&quot; — &quot;бесполезная&quot; клавиша SysRq (она делит место жительства с PrintScreen). Это единственная прямая связь с ядром линукса, работающая всегда (конечно, если работает и ядро). Тест из первого абзаца проходится с помощью &lt;i&gt;SysRq+Alt+f&lt;/i&gt; — вызывается обработчик ситуации нехватки памяти, который и завершает самый &quot;тяжёлый&quot; процесс. Из любимого ещё убиение X-сервера — &lt;i&gt;SysRq+Alt+k&lt;/i&gt;.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/7428759451492243293/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7428759451492243293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7428759451492243293'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/blog-post.html' title='Волшебная кнопка'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-3427213087019608210</id><published>2011-03-02T16:18:00.000+06:00</published><updated>2011-03-02T16:18:51.727+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Статический анализ кода в Python</title><content type='html'>В &lt;a href=&quot;http://habrahabr.ru/blogs/python/114745/&quot;&gt;статье&lt;/a&gt; на Хабре наткнулся на упоминание &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B0%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7_%D0%BA%D0%BE%D0%B4%D0%B0&quot;&gt;статических анализаторов кода&lt;/a&gt; для Python. Инструмент этот очень полезен при регулярном его использовании. Немножко подробнее расскажу о &lt;a href=&quot;http://pypi.python.org/pypi/pep8&quot;&gt;pep8&lt;/a&gt;, &lt;a href=&quot;http://www.logilab.org/project/pylint&quot;&gt;pylint&lt;/a&gt; и &lt;a href=&quot;http://divmod.org/trac/wiki/DivmodPyflakes&quot;&gt;pyflakes&lt;/a&gt;.&lt;br /&gt;
&lt;h4&gt;pep8&lt;/h4&gt;Этот анализатор проверяет соответствие кода знаменитому &lt;a href=&quot;http://www.python.org/dev/peps/pep-0008/&quot;&gt;PEP 8&lt;/a&gt; — руководству по стилю кода Python. В больших и не очень командах хорошая штука, ибо &quot;&lt;a href=&quot;http://www.python.org/dev/peps/pep-0020&quot;&gt;Readability counts&lt;/a&gt;&quot;!&lt;br /&gt;
&lt;h4&gt;pylint&lt;/h4&gt;Самый придирчивый анализатор из всех трёх, хотя стиль кода проверяет немножко иначе, чем pep8 — акцент на &quot;дурно пахнущем&quot; и неоптимальном коде, выдаёт и предложения о рефакторинге. Бонусная опция — генерация UML-диаграмм с помощью команды &lt;a href=&quot;http://www.logilab.org/project/pylint&quot;&gt;pyreverse&lt;/a&gt;.&lt;br /&gt;
Угодить pylint весьма сложно, порой он ошибается — к счастью, настройки достаточно гибкие.&lt;br /&gt;
&lt;h4&gt;pyflakes&lt;/h4&gt;В отличие от pylint, проверяет только на логические ошибки в программе, стиль не учитывает.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
На мой взгляд, золотая середина — pyflakes, поначалу можно использовать и pep8, дабы привить соблюдение стиля.&lt;br /&gt;
&lt;br /&gt;
Бонус для пользователей Vim — вызов pyflakes или pylint после каждого сохранения редактируемого файла, сообщения об ошибках помещаются в окошко &quot;quickfix&quot;:&lt;br /&gt;
&lt;pre&gt;command Pylint :call Pylint()
function! Pylint()
    setlocal makeprg=(echo\ &#39;[%]&#39;;\ pylint\ %)
    setlocal efm=%+P[%f],%t:\ %#%l:%m
    silent make
    cwindow
endfunction

command Pyflakes :call Pyflakes()
function! Pyflakes()
    let tmpfile = tempname()
    execute &quot;w&quot; tmpfile
    execute &quot;set makeprg=(pyflakes\\ &quot; . tmpfile . &quot;\\\\\\|sed\\ s@&quot; . tmpfile .&quot;@%@)&quot;
    silent make
    cwindow
endfunction

autocmd BufWrite *.{py} :call Pyflakes()
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/3427213087019608210/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/python.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3427213087019608210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3427213087019608210'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/03/python.html' title='Статический анализ кода в Python'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-5672265441876502255</id><published>2011-02-25T17:23:00.000+06:00</published><updated>2011-02-25T17:23:26.624+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Обработка ссылок mailto в Google Chrome</title><content type='html'>Наконец нашёл решение давней несуразности: в отличие от Firefox, линуксовый Google Chrome при попытке открыть почтовую ссылку (протокола &quot;mailto&quot;) запускает почтовую программу, а мне нужен Gmail. Замечательный &lt;a href=&quot;http://superuser.com/questions/32493/how-do-i-make-mailto-links-open-gmail-in-ubuntu/132306#132306&quot;&gt;superuser.com&lt;/a&gt; подсказал, что в Ubuntu для этого достаточно установить пакет desktop-webmail (плюс к этому я выбрал Desktop Webmail в настройках Preferred Applications/Mail Reader — возможно, это необязательно).</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/5672265441876502255/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/mailto-google-chrome.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/5672265441876502255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/5672265441876502255'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/mailto-google-chrome.html' title='Обработка ссылок mailto в Google Chrome'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-901522770874658836</id><published>2011-02-22T17:03:00.000+06:00</published><updated>2011-02-22T17:03:12.135+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><category scheme="http://www.blogger.com/atom/ns#" term="базы данных"/><title type='text'>Репликация и устойчивое хэширование в memcached</title><content type='html'>&lt;a href=&quot;http://memcached.org/&quot;&gt;Memcached&lt;/a&gt; работает просто и быстро, как электровеник, и не поддерживает репликации, которая может понадобиться при горизонтальном масштабировании серверов memcached.&lt;br /&gt;
&lt;br /&gt;
Есть как минимум два варианта решения этой задачи. Первый используется для репликации мастер-мастер и не зависит от языка программирования — &lt;a href=&quot;http://repcached.sourceforge.net/&quot;&gt;repcached&lt;/a&gt;, патч к memcached, добавляющий репликацию между серверами. (&lt;a href=&quot;http://adminco.org/2010/05/memcached-master-to-master-replication/&quot;&gt;Инструкция по установке&lt;/a&gt;.) Из минусов — устанавливать придётся, скорее всего, из исходников и поддерживается не самая последняя версия memcached (примерно полуторагодовалой давности).&lt;br /&gt;
&lt;br /&gt;
Другой способ специфичен для PHP (впрочем, наверняка есть схожие решения и для других языков). Модуль php5-memcache позволяет реализовать подобие репликации с помощью хранения каждого ключа на N серверах. В случае, если один из серверов падает, ключ будет храниться на оставшемся и каком-то N+1 сервере. С помощью этого модуля можно хранить и сессии с избыточностью. Выдержка из readme:&lt;br /&gt;
&lt;code&gt;# When enabled the client sends requests to N servers in parallel, resulting in&lt;br /&gt;
# a somewhat crude reduncancy or mirroring, suitable when used as a session &lt;br /&gt;
# storage. &lt;br /&gt;
#&lt;br /&gt;
# If data integrity is of greater importance a real replicating memcached &lt;br /&gt;
# backend such as &quot;repcached&quot; (http://sourceforge.net/projects/repcached/) is &lt;br /&gt;
# recommended&lt;br /&gt;
&lt;br /&gt;
memcache.redundancy = &lt;int&gt;                     # default 1&lt;br /&gt;
memcache.session_redundancy = &lt;int&gt;             # default 2&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Для большинства приложений такой надёжности достаточно.&lt;br /&gt;
&lt;br /&gt;
Вдобавок этот модуль использует т.н. &quot;устойчивое хэширование&quot; (&lt;a href=&quot;http://en.wikipedia.org/wiki/Consistent_hashing&quot;&gt;&quot;consistent hashing&quot;&lt;/a&gt;). Вкратце, этот алгоритм позволяет привязывать ключи к определённым серверам memcached и при удалении/добавлении серверов бóльшая часть ключей останется привязана к тем же серверам. Таким образом, для распределения нагрузки без использования репликации достаточно встроенных средств php5-memcache. &lt;br /&gt;
&lt;br /&gt;
Для Python такую функциональность предоставляет модуль &lt;a href=&quot;http://amix.dk/blog/post/19370&quot;&gt;hash_ring&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/901522770874658836/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/memcached.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/901522770874658836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/901522770874658836'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/memcached.html' title='Репликация и устойчивое хэширование в memcached'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-7267296724066889483</id><published>2011-02-18T11:26:00.001+06:00</published><updated>2011-02-18T11:27:23.957+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><title type='text'>Новое в PHP</title><content type='html'>Господин Ilia Alshanetsky (судя по всему, выходец из СССР) опубликовал прекрасную презентацию о малоизвестных фичах в PHP, в частности, PHP 5.3: &lt;a href=&quot;http://ilia.ws/files/zendcon_2010_hidden_features.pdf&quot;&gt;PDF (3 МБ)&lt;/a&gt;. В свою очередь хочу упомянуть о появлении в PHP 5.3 &lt;a href=&quot;ru2.php.net/manual/en/functions.anonymous.php&quot;&gt;анонимных функций&lt;/a&gt;, с помощью которых можно реализовывать и &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BC%D1%8B%D0%BA%D0%B0%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)&quot;&gt;замыкания&lt;/a&gt; (closures). Не так удобно, как в &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BC%D1%8B%D0%BA%D0%B0%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)#Ruby&quot;&gt;других&lt;/a&gt; &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BC%D1%8B%D0%BA%D0%B0%D0%BD%D0%B8%D0%B5_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)#Python&quot;&gt;языках&lt;/a&gt;, но сам факт радует.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/7267296724066889483/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/php.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7267296724066889483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7267296724066889483'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/php.html' title='Новое в PHP'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-4337231254294843878</id><published>2011-02-09T16:34:00.000+06:00</published><updated>2011-02-09T16:34:02.871+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ruby"/><title type='text'>Чёрная магия Ruby</title><content type='html'>На работе понадобилось поменять &lt;a href=&quot;http://www.redmine.org/issues/7349&quot;&gt;пару&lt;/a&gt; &lt;a href=&quot;http://www.redmine.org/issues/7586&quot;&gt;вещей&lt;/a&gt; в &lt;a href=&quot;http://www.redmine.org/&quot;&gt;Redmine&lt;/a&gt; — написан он на Ruby on Rails. Случилось то, что так давно откладывал — я познакомился с Ruby и &lt;acronym title=&quot;Ruby on Rails&quot;&gt;RoR&lt;/acronym&gt;.&lt;br /&gt;
&lt;br /&gt;
Ruby произвёл неоднозначное впечатление большого хака, из которого к тому же торчат уши зубодробительного Perl. Но хак этот эффективный и в умелых руках работает со страшной силой. К RoR эти слова применимы в квадрате — это ещё бóльшая чёрная магия. Японское происхождение частично объясняет странность Ruby. &lt;br /&gt;
&lt;br /&gt;
Избранные места из документации Ruby:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;В Ruby всё — объекты. Даже числа. Чего стоит, например, такой код:&lt;br /&gt;
&lt;pre class=&quot;ruby&quot; name=&quot;code&quot;&gt;5.times { |i| print i, &#39; &#39; }&lt;/pre&gt;Этот кусочек иллюстрирует ещё одну странную, но мощную фишку — передача кусков кода в виде аргументов функции. Похоже на &lt;a href=&quot;http://docs.python.org/tutorial/controlflow.html#lambda-forms&quot;&gt;lambda-функции в Python&lt;/a&gt;, но мощнее и применяется повсеместно.&lt;/li&gt;
&lt;li&gt;При записи числа допустима, например, следующая форма:&lt;br /&gt;
&lt;pre class=&quot;ruby&quot; name=&quot;code&quot;&gt;a = 1_000_000&lt;/pre&gt;Чтобы, значит, читабельность кода увеличить.&lt;/li&gt;
&lt;li&gt;Ruby вообще любит использовать ASCII-таблицу по максимуму. Функция проверки валидности может называться &lt;code&gt;valid?&lt;/code&gt;, а сортировка массива &quot;in place&quot; — &lt;code&gt;sort!&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Как и многие языки, в Ruby объекты могут наследоваться лишь от одного родителя. Но можно включать в класс код из других модулей, при этом их функции становятся методами данного класса — это ж настоящий&amp;nbsp;&lt;a href=&quot;http://en.wikipedia.org/wiki/Monkey_patch&quot;&gt;monkey patching&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;Определение класса может состоять из несколько кусков. Т.е. мы начали определять класс A, потом пошло определение класса B, потом мы опять продолжили определить класс A. На практике это означает, что можно переопределить поведение даже базовых классов, того же String. Вот это действительно monkey patching.&lt;/li&gt;
&lt;li&gt;И ещё для Ruby написано &lt;a href=&quot;http://mislav.uniqpath.com/poignant-guide/&quot;&gt;самое странное руководство&lt;/a&gt; из тех, что я встречал.&lt;/li&gt;
&lt;/ul&gt;В заключение можно ещё раз повторить: Ruby — очень эффективный инструмент в умелых руках. В неумелых он вносит хаос в код и мозг программиста.&lt;br /&gt;
&lt;br /&gt;
Лично мне ближе элегантность Python, замешанная на &lt;a href=&quot;http://www.python.org/dev/peps/pep-0020/&quot;&gt;дзене&lt;/a&gt;. ;)</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/4337231254294843878/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/ruby.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4337231254294843878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4337231254294843878'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2011/02/ruby.html' title='Чёрная магия Ruby'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-7620779741992990665</id><published>2010-12-10T13:56:00.002+06:00</published><updated>2010-12-10T14:19:56.933+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="графика"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Новый старый PNG</title><content type='html'>Оказывается, формат PNG не так уж и прост. Среди прочего он позволяет эффективно сжимать &lt;a href=&quot;http://en.wikipedia.org/wiki/Portable_Network_Graphics#Filtering&quot;&gt;градиентную заливку&lt;/a&gt; внутри картинки, отсюда вывод — если требуется на градиентный фон что-то наложить, эффективнее будет сделать фон отдельной картинкой, а сверху наложить другую с объектами переднего плана и прозрачным фоном.&lt;br /&gt;
Есть &lt;a href=&quot;http://en.wikipedia.org/wiki/Portable_Network_Graphics#Optimizing_tools&quot;&gt;несколько утилит&lt;/a&gt; для оптимизации размера PNG, одна из лучших открытых — &lt;a href=&quot;http://optipng.sourceforge.net/&quot;&gt;OptiPNG&lt;/a&gt;, есть удобные обёртки под Windows, Mac и Linux. Но ещё лучше по степени сжатия — бесплатная утилитка &lt;a href=&quot;http://advsys.net/ken/utils.htm&quot;&gt;PNGOUT&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/7620779741992990665/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/12/png.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7620779741992990665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/7620779741992990665'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/12/png.html' title='Новый старый PNG'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-3930003196609947226</id><published>2010-11-19T14:10:00.000+06:00</published><updated>2010-11-19T14:10:59.313+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MySQL"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Грабли в MySQL</title><content type='html'>Сегодня, как обычно случайно, выяснил, что если подключиться к одной базе и начать там транзакцию с помощью &lt;code&gt;START TRANSACTION&lt;/code&gt;/&lt;code&gt;BEGIN&lt;/code&gt;, то любой запрос к другой базе приостанавливается — MySQL ждёт, когда вы закончите открытую транзакцию к первой базе.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/3930003196609947226/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/11/mysql.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3930003196609947226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/3930003196609947226'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/11/mysql.html' title='Грабли в MySQL'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-201899569511019344</id><published>2010-10-21T10:58:00.001+07:00</published><updated>2010-11-19T14:12:06.956+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Вся мощь Vim</title><content type='html'>Я люблю Vim странной долгой любовью. :) Встречая &lt;a href=&quot;http://www.rayninfo.co.uk/vimtips.html&quot;&gt;такие мануалы&lt;/a&gt;, понимаю, что только начинаю изучать его. Осталось понять сей славный документ, и можно называться Vim-гуру. B-)</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/201899569511019344/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/10/vim.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/201899569511019344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/201899569511019344'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/10/vim.html' title='Вся мощь Vim'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-2656766167292060120</id><published>2010-09-08T13:21:00.001+07:00</published><updated>2010-11-19T14:11:41.082+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PHP"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><category scheme="http://www.blogger.com/atom/ns#" term="заметки на полях"/><title type='text'>Server-side jQuery</title><content type='html'>jQuery настолько прекрасен, что портируется и на серверные языки, дабы упростить написание всевозможных парсеров. Я использую два порта, &lt;a href=&quot;http://pypi.python.org/pypi/pyquery&quot;&gt;pyquery&lt;/a&gt; и &lt;a href=&quot;http://code.google.com/p/phpquery/&quot;&gt;phpquery&lt;/a&gt;, соответственно — для Python и PHP. Весьма облегчают жизнь.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/2656766167292060120/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/09/server-side-jquery.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2656766167292060120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2656766167292060120'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/09/server-side-jquery.html' title='Server-side jQuery'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-4361933597760978210</id><published>2010-06-25T12:46:00.000+07:00</published><updated>2010-06-25T12:46:39.251+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MySQL"/><title type='text'>XtraDB и MariaDB</title><content type='html'>Оказывается, правильные пацаны потихоньку переходят на &lt;a href=&quot;http://www.percona.com/docs/wiki/percona-xtradb:start&quot;&gt;XtraDB&lt;/a&gt;. Как пишет &lt;a href=&quot;http://ru.wikipedia.org/wiki/InnoDB&quot;&gt;Википедия&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;В последнее время из-за излишней закрытости разработки MySQL компанией Sun Microsystems появилось много сторонних (например, от компании Google) патчей с улучшениями производительности и исправлениями ошибок, большинство из которых были включены в форк InnoDB под названием XtraDB, созданный компанией Percona.&lt;/blockquote&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.percona.com/about-us/our-team/&quot;&gt;Percona&lt;/a&gt; была создана в 2006 году для консультирования и поддержки MySQL-пользователей. И основатели её имеют знакомо звучащие имена, как то Peter Zaitsev и Vadim Tkachenko. В общем, наши люди.&lt;br /&gt;
&lt;br /&gt;
Как известно, &lt;a href=&quot;http://www.innodb.com/&quot;&gt;InnoDB&lt;/a&gt; — это лучший движок для таблиц MySQL с нормальной поддержкой транзакций, внешних ключей и т.п. XtraDB, по заявлениям авторов, работает быстрее плюс позволяет осуществлять бэкап таблиц на лету. У InnoDB тоже есть такой инструмент, но он платный, в отличие от XtraDB. Формат таблиц используют они один и тот же, т.е. можно существующую базу пересадить с одного движка на другой без проблем.&lt;br /&gt;
&lt;br /&gt;
А ещё есть форк MySQL под названием &lt;a href=&quot;http://askmonty.org/wiki/MariaDB&quot;&gt;MariaDB&lt;/a&gt;. Это детище основателя MySQL Michael &quot;Monty&quot; Widenius. Формат БД, API, имена файлов и т.п. полностью совместимы с MySQL. Взамен &lt;a href=&quot;http://askmonty.org/wiki/MariaDB_versus_MySQL&quot;&gt;обещается&lt;/a&gt; ускорение и новые фичи. Ну и движок XtraDB включён в комплект вместо InnoDB.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/4361933597760978210/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/06/xtradb-mariadb.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4361933597760978210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4361933597760978210'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/06/xtradb-mariadb.html' title='XtraDB и MariaDB'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-692767886819350625</id><published>2010-06-09T18:21:00.000+07:00</published><updated>2010-06-09T18:21:28.465+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="MySQL"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>О MySQL в многопоточном Python&#39;е</title><content type='html'>В проекте возникла необходимость доступа к MySQL из разных потоков (threads). Я внимаааааааааательно прочитал официальную документацию библиотеки для доступа MySQL из Python, и она &lt;a href=&quot;http://mysql-python.sourceforge.net/MySQLdb.html#functions-and-attributes&quot;&gt;заявляет&lt;/a&gt;, что нельзя использовать одно и то же подключение к БД в разных потоках.&lt;br /&gt;
&lt;br /&gt;
На помощь спешит &lt;a href=&quot;http://code.google.com/p/pysqlpool/&quot;&gt;PySQLPool&lt;/a&gt;, в нём есть методы для создания &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%BD%D1%8B%D0%B9_%D0%BF%D1%83%D0%BB&quot;&gt;пула&lt;/a&gt; подключений к MySQL. &lt;br /&gt;
&lt;br /&gt;
Я использую движок таблиц (table engine) &lt;a href=&quot;http://www.innodb.com/&quot;&gt;InnoDB&lt;/a&gt; с нормальной поддержкой транзакций. Совсем неинтересно каждый раз писать BEGIN TRANSACTION/COMMIT, это ж Python! Должен быть способ! И он нашёлся.&lt;br /&gt;
&lt;br /&gt;
В версии 2.5 добавили оператор &lt;a href=&quot;http://docs.python.org/reference/compound_stmts.html#with&quot;&gt;with&lt;/a&gt; и &lt;a href=&quot;http://docs.python.org/library/stdtypes.html#context-manager-types&quot;&gt;контекстные менеджеры&lt;/a&gt;. Я написал простенький &lt;a href=&quot;https://bugs.launchpad.net/pysqlpool/+bug/583656/&quot;&gt;патч&lt;/a&gt;, и  использование транзакций стало простым и красивым:&lt;br /&gt;
&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;q = PySQLPool.getNewQuery(connection)
with q: # внутренние запросы обёрнуты в транзакцию
            q.Query(&#39;INSERT INTO peer SET PeerName=%s&#39;, (name,))&lt;/pre&gt;&lt;br /&gt;
Есть и маленькая ложка дёгтя в виде заявленного автором &lt;a href=&quot;https://bugs.launchpad.net/pysqlpool/+bug/583656/comments/2&quot;&gt;бага&lt;/a&gt; при работе с транзакциями из нескольких тредов. В общем-то, ко времени релиза нашего проекта либо я исправлю этот баг, либо автор, либо вы. ;)</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/692767886819350625/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/06/mysql-python.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/692767886819350625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/692767886819350625'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/06/mysql-python.html' title='О MySQL в многопоточном Python&#39;е'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-1607904160938399608</id><published>2010-05-14T16:52:00.000+07:00</published><updated>2010-05-14T16:52:43.966+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>Сетевое программирование в Python</title><content type='html'>Нашёл хороший &lt;a href=&quot;http://heather.cs.ucdavis.edu/~matloff/Python/PyNet.pdf&quot;&gt;туториал&lt;/a&gt; (PDF) на английском про сетевое программирование в Python — чётко изложена сама теория, кое-чего я и сам не знал, и даны хорошие базовые примеры на Python.&lt;br /&gt;
&lt;a href=&quot;http://heather.cs.ucdavis.edu/~matloff/python.html&quot;&gt;На сайте автора&lt;/a&gt; есть и другие неплохие туториалы про Python.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/1607904160938399608/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/05/python.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1607904160938399608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1607904160938399608'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/05/python.html' title='Сетевое программирование в Python'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-1551615304368047060</id><published>2010-05-05T14:25:00.005+07:00</published><updated>2010-05-06T12:35:57.550+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>UDP-траспорт</title><content type='html'>В проекте, над которым я работаю, понадобилось использовать асинхронный UDP-траспорт. Как выяснилось, есть в этой задаче несколько подводных камней — о них и пойдёт речь. &lt;br /&gt;
&lt;br /&gt;
Хотелось что-то максимально простое с помощью встроенных в Python средств.&lt;br /&gt;
&lt;br /&gt;
Первый вариант — &lt;a href=&quot;http://docs.python.org/library/socketserver.html&quot;&gt;класс SocketServer.UDPServer&lt;/a&gt;. Минус его в том, что он использует блокирующие сокеты; для обхода этого в том же пакете есть и неблокирующие версии, реализованные с помощью тредов или даже отдельных процессов на каждого клиента. Но это не совсем асинхронность.&lt;br /&gt;
&lt;br /&gt;
Второй способ — пакет &lt;a href=&quot;http://docs.python.org/library/asyncore.html&quot;&gt;asyncore&lt;/a&gt;, который как раз для асинхронных сообщений и предназначен. Правда, только для TCP. Создать нужный класс несложно, но есть несколько тонкостей:&lt;br /&gt;
&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;class UdpTransport(asyncore.dispatcher, object):
    def __init__(self, addr=None):
        super(UdpTransport, self).__init__()
        self.ignore_log_types = set() # Для вывода дополнительных ошибок в asyncore, подсмотрел в исходниках asyncore :)
        self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
        # Размер этого буфера очень важен
        # Если входящий пакет будет больше него, остаток отбрасывается
        self.ReadBufferSize = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF)
        if addr:
            self.bind(addr) # Единственное отличие серверного сокета в использовании bind()
        
    def handle_close(self):
        self.close()

    def writable(self):
        return False

    def handle_read(self):
        try:
            data, addr = self.recvfrom(self.ReadBufferSize) 
        except socket.error: # Исключение возникает при чтении данных из сокета: когда они заканчиваются, следующая попытка вылетает
            pass
        # обработка данных

    def send(self, msg, toaddr):
        self.socket.sendto(msg, toaddr)

    handle_connect = handle_read # Нарыл где-то на просторах инета
    # Без этого asyncore не работает с UDP, первую порцию данных он интерпретирует как инициализацию подключения
&lt;/pre&gt;Наследуемся и от object для использования super и отладки с помощью &lt;a href=&quot;http://dmalinovsky.blogspot.com/2010/04/python.html&quot;&gt;метакласса&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Вот, собственно, и всё, все хитрости прокомментированы в коде. Естественно, нам не требуется &lt;code&gt;connect()&lt;/code&gt; для серверных сокетов, а вместо &lt;code&gt;socket.send/recv&lt;/code&gt; нужно использовать методы &lt;code&gt;sendto/recvfrom&lt;/code&gt;. Сперва я путался, в каких случаях что нужно применять — документация лаконична — но нашёл хороший источник с примерами, это наш родной &lt;code&gt;`man`&lt;/code&gt;. ;) Например, &lt;code&gt;`man bind`&lt;/code&gt; (или &lt;code&gt;`man 2 bind`&lt;/code&gt;, если быть точным) показывает документацию С-шного сетевого API, обёрткой вокруг которого &lt;a href=&quot;http://docs.python.org/library/socket.html&quot;&gt;socket&lt;/a&gt;, собственно, и является. Если на вашем *nix такой странички нет, нужно установить пакет manpages-dev (в Debian и Ubuntu, по крайней мере).</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/1551615304368047060/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/05/udp.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1551615304368047060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/1551615304368047060'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/05/udp.html' title='UDP-траспорт'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Россия, Новосибирская область, Новосибирск</georss:featurename><georss:point>55.0392304 82.9278181</georss:point><georss:box>54.6457824 81.9939801 55.4326784 83.86165609999999</georss:box></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-2005923481355488840</id><published>2010-04-28T17:53:00.000+07:00</published><updated>2010-04-28T17:53:03.896+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>Мощь Python</title><content type='html'>Я не так давно читал про &lt;a href=&quot;http://habrahabr.ru/blogs/python/65625/&quot;&gt;метаклассы в Питоне&lt;/a&gt;, и тут представился случай их использовать.&lt;br /&gt;
Задача: нужно отладить код сетевого приложения, дебаггером по нему не пройдёшь — при пошаговой отладке состояние сокетов теряется. Я решил печатать имя и аргументы каждого вызванного метода сетевых классов. Вариант со вставкой print в каждый метод — это явно &lt;a href=&quot;http://en.wikipedia.org/wiki/DRY&quot;&gt;не наш&lt;/a&gt; метод. :)&lt;br /&gt;
&lt;br /&gt;
Получился вот такой метакласс:&lt;br /&gt;
&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;class DebugMetaclass(type):
    &#39;&#39;&#39;Вывод вызова каждого метода объекта с параметрами, удобно при отладке
    сетевых приложений. ;)&#39;&#39;&#39;
    def __new__(cls, name, bases, attrs):
        cls.last_signature = None
        for elem in attrs:
            if inspect.isfunction(attrs[elem]):
                attrs[elem] = DebugMetaclass.decorator(attrs[elem])
        return super(DebugMetaclass, cls).__new__(cls, name, bases, attrs)
    
    @classmethod
    def decorator(cls, func):
        &#39;&#39;&#39;Возвращает обёрнутую функцию.&#39;&#39;&#39;
        @wraps(func)
        def wrapper(*args, **kwargs):
            signature = &#39;%s.%s(%s, %s)&#39; % (args[0].__class__.__name__, 
                                           func.__name__, &#39;, &#39;.join([str(a) for a in args]), 
                                           kwargs)
            if cls.last_signature != signature: # Добавлено для подавления повторяющихся сообщений
                print signature
                cls.last_signature = signature
            return func(*args, **kwargs)
        return wrapper
&lt;/pre&gt;&lt;br /&gt;
Класс, который будет использовать этот метакласс, должен наследоваться от object. В моём случае выглядит примерно так:&lt;br /&gt;
&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;class UdpTransport(asyncore.dispatcher, object):
    __metaclass__ = DebugMetaclass&lt;/pre&gt;&lt;br /&gt;
Сам dispatcher — это &lt;a href=&quot;http://www.python.org/download/releases/2.2.3/descrintro/&quot;&gt;old-style class&lt;/a&gt;, поэтому я добавляю ещё одного родителя, но если поместить его первым, лезут баги.&lt;br /&gt;
&lt;br /&gt;
Прекрасные материалы о метаклассах, new-style классах и прочей магии Питона есть &lt;a href=&quot;http://habrahabr.ru/blogs/python/84235/&quot;&gt;на Хабре&lt;/a&gt;.&lt;br /&gt;
Про обёртки, сиречь декораторы, можно почитать в блоге &lt;a href=&quot;http://vorushin.ru/blog/26-decorators-python/&quot;&gt;Романа Ворушина&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/2005923481355488840/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/python.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2005923481355488840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2005923481355488840'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/python.html' title='Мощь Python'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Россия, Новосибирская область, Новосибирск</georss:featurename><georss:point>55.0392304 82.9278181</georss:point><georss:box>54.6457824 81.9939801 55.4326784 83.86165609999999</georss:box></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-8820532447101964620</id><published>2010-04-23T16:14:00.001+07:00</published><updated>2010-04-28T17:54:19.837+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>В поисках утраченных исходников</title><content type='html'>Сегодня я работал над модульными тестами для своего Python-проекта. Для простоты файлы тестов называю так же, как и файлы тестируемых модулей. Я решил перенести тесты в другой каталог и мимодумно скопировал их в каталог модулей. Исходники модулей, конечно, затёрлись.&lt;br /&gt;
&quot;А-а-а-а!!!&quot; — подумал я. К счастью, остались оригинальные *.pyc-файлы — скомпилированный байт-код Python, который, по идее, можно превратить обратно в исходник.&lt;br /&gt;
Быстрый поиск выдал &lt;a href=&quot;http://stackoverflow.com/questions/48211/free-phttp://stackoverflow.com/questions/48211/free-python-decompiler-that-is-not-an-online-serviceython-decompiler-that-is-not-an-online-service&quot;&gt;замечательный пост&lt;/a&gt; на не менее замечательном StackOverflow. Бесплатная утилита &lt;a href=&quot;http://sourceforge.net/projects/unpyc/&quot;&gt;UnPyc&lt;/a&gt; помогла почти полностью восстановить один из файлов, но споткнулась на другом, с &lt;a href=&quot;http://docs.python.org/tutorial/datastructures.html#list-comprehensions&quot;&gt;list comprehensions&lt;/a&gt;. Тогда я решил воспользоваться онлайн-сервисом &lt;a href=&quot;http://depython.net/&quot;&gt;DePython&lt;/a&gt;, но у него два ограничения:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;размер файла должен быть меньше 5 КБ;&lt;/li&gt;
&lt;li&gt;версия Python &amp;lt;= 2.5.&lt;/li&gt;
&lt;/ol&gt;У меня была 2.6. В том же замечательном посте &lt;a href=&quot;http://stackoverflow.com/questions/48211/free-python-decompiler-that-is-not-an-online-service/194063#194063&quot;&gt;привели программку&lt;/a&gt; для конвертирования pyc-файла в версию 2.3 — вся идея в том, чтобы заменить первые 4 байта файла на соответствующие версии Python. Ещё &lt;a href=&quot;http://stackoverflow.com/questions/2263356/are-python-2-5-pyc-files-compatible-with-python-2-6-pyc-files/2263434#2263434&quot;&gt;немножко поиска&lt;/a&gt; помогло узнать magic-строку для версии 2.5.&lt;br /&gt;
К счастью, модулей было всего два :), осталась последняя закавыка — текст на русском раскодировался в виде \xx-последовательностей. Тогда я обернул текст исходников в такой код:&lt;br /&gt;
&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;print &quot;&quot;&quot;
&amp;lt;здесь перекодированный код&amp;gt;
&quot;&quot;&quot;&lt;/pre&gt;При запуске скрипта в консоли с локалью UTF-8 вывелись строчки с чистым русским текстом. Ура!&lt;br /&gt;
&lt;br /&gt;
Мораль сего такова: будьте внимательны, чаще коммитьте и не отчаивайтесь.</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/8820532447101964620/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/blog-post_23.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8820532447101964620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/8820532447101964620'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/blog-post_23.html' title='В поисках утраченных исходников'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Россия, Новосибирская область, Новосибирск</georss:featurename><georss:point>55.0392304 82.9278181</georss:point><georss:box>54.6457824 81.9939801 55.4326784 83.86165609999999</georss:box></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-4837268748402166273</id><published>2010-04-04T10:26:00.001+07:00</published><updated>2010-04-23T19:49:08.311+07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="open source"/><category scheme="http://www.blogger.com/atom/ns#" term="графика"/><title type='text'>Ретуширование картинок</title><content type='html'>Недавно наткнулся на видео с показом тестовой фишки в PhotoShop — Content-Aware Fill (заливка, зависимая от содержимого картинки):&lt;br /&gt;
&lt;object height=&quot;385&quot; width=&quot;480&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/NH0aEp1oDOI&amp;hl=ru_RU&amp;fs=1&amp;&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/NH0aEp1oDOI&amp;hl=ru_RU&amp;fs=1&amp;&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;br /&gt;
Open source уже &lt;strike&gt;два года&lt;/strike&gt; восемь лет &lt;small&gt;(спасибо, prokoudine!)&lt;/small&gt; как имеет в своём распоряжении такой же &lt;a href=&quot;http://www.logarithmic.net/pfh/resynthesizer&quot;&gt;плагин для Gimp&lt;/a&gt;. :)&lt;br /&gt;
&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWW5T4KBfNQKD1tWNdMLCjf19jYy0BelBHgZwp2cXS2JWqBKeLqAULrC0FmUc4ZpHxsJdtVNKr-pn8c5HNbai1ZtW_kYBAjfjegrmzVMOSTtAG7-VHzJ5i7987V9IWP00WPbEm-oQvhf4/s1600/bashkir_01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWW5T4KBfNQKD1tWNdMLCjf19jYy0BelBHgZwp2cXS2JWqBKeLqAULrC0FmUc4ZpHxsJdtVNKr-pn8c5HNbai1ZtW_kYBAjfjegrmzVMOSTtAG7-VHzJ5i7987V9IWP00WPbEm-oQvhf4/s320/bashkir_01.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTDShHLXyCTTHNdGAhrar1a93Al6o0f2d8TjjphmDFYeLW4lCVYfVmLSyPrXNAOUH1kaPpVNXcPqnEPSwa0zf19KA4dSQXR40NoDallf1BnPng1q8DXpW6SAlRVMl2pFjKo87DpP9cvX4/s1600/bashkir_01-re.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTDShHLXyCTTHNdGAhrar1a93Al6o0f2d8TjjphmDFYeLW4lCVYfVmLSyPrXNAOUH1kaPpVNXcPqnEPSwa0zf19KA4dSQXR40NoDallf1BnPng1q8DXpW6SAlRVMl2pFjKo87DpP9cvX4/s320/bashkir_01-re.jpg&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;До&lt;/td&gt; &lt;td&gt;После (убрал собачку и дома)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Ну разве это не красота?</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/4837268748402166273/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/blog-post.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4837268748402166273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/4837268748402166273'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/04/blog-post.html' title='Ретуширование картинок'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWW5T4KBfNQKD1tWNdMLCjf19jYy0BelBHgZwp2cXS2JWqBKeLqAULrC0FmUc4ZpHxsJdtVNKr-pn8c5HNbai1ZtW_kYBAjfjegrmzVMOSTtAG7-VHzJ5i7987V9IWP00WPbEm-oQvhf4/s72-c/bashkir_01.jpg" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-895282391928669909.post-2995441298142404381</id><published>2010-02-05T14:41:00.002+06:00</published><updated>2010-02-05T14:41:39.896+06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="проекты"/><title type='text'>Delete your account</title><content type='html'>С ростом популярности соцсетей появляются и такие сервисы, как &lt;a href=&quot;http://deleteyouraccount.com/&quot;&gt;Delete Your Account&lt;/a&gt;. :)</content><link rel='replies' type='application/atom+xml' href='http://dmalinovsky.blogspot.com/feeds/2995441298142404381/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://dmalinovsky.blogspot.com/2010/02/delete-your-account.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2995441298142404381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/895282391928669909/posts/default/2995441298142404381'/><link rel='alternate' type='text/html' href='http://dmalinovsky.blogspot.com/2010/02/delete-your-account.html' title='Delete your account'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00727453302528453672</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>