<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Юникс и другие &#187; Programming</title>
	<atom:link href="http://boombick.org/blog/posts/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://boombick.org/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Tue, 29 Nov 2011 22:14:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>50 цитат о программировании</title>
		<link>http://boombick.org/blog/posts/198</link>
		<comments>http://boombick.org/blog/posts/198#comments</comments>
		<pubDate>Fri, 07 Jan 2011 15:17:50 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/?p=198</guid>
		<description><![CDATA[Наткнулся на Хабре на отличный перевод коллекции цитат о программировании. Публикую здесь без купюр :) 50. Программирование сегодня — это гонка разработчиков программ, стремящихся писать программы больше и с лучшей идиотоустойчивостью, и вселенной, которая пытается создавать больших и лучших идиотов. Пока вселенная побеждает. — Rick Cook 49. Lisp — это не язык, а строительный материал. [...]]]></description>
			<content:encoded><![CDATA[<p>Наткнулся на Хабре на отличный перевод коллекции цитат о программировании. Публикую здесь без купюр :)</p>
<p><strong>50.</strong> Программирование сегодня — это гонка разработчиков программ, стремящихся писать программы больше и с лучшей идиотоустойчивостью, и вселенной, которая пытается создавать больших и лучших идиотов. Пока вселенная побеждает.<br />
<em>— Rick Cook</em><br />
<span id="more-198"></span><br />
<strong>49.</strong> Lisp — это не язык, а строительный материал.<br />
<em>— Alan Kay</em></p>
<p><strong>48.</strong> Ходить по воде и разрабатывать программы, следуя спецификации, очень просто… если они заморожены.<br />
<em>— Edward V Berard</em></p>
<p><strong>47.</strong> Они больше не делают баги, как Банни (Bugs Bunny).<br />
<em>— Olav Mjelde.</em></p>
<p><strong>46.</strong> Низкоуровневый язык — это когда требуется внимание к вещам, которые никак не связаны с программами на этом языке.<br />
<em>— Alan J. Perlis.</em></p>
<p><strong>45.</strong> Программирование на С похоже на быстрые танцы на только что отполированном полу людей с острыми бритвами в руках<br />
<em>— Waldi Ravens.</em></p>
<p><strong>44.</strong> Я всегда мечтал о том, чтобы моим компьютером можно было пользоваться так же легко, как телефоном; моя мечта сбылась: я уже не могу разобраться, как пользоваться моим телефоном.<br />
<em>— Bjarne Stroustrup</em></p>
<p><strong>43.</strong> Обучение программированию не может научить быть экспертом, также как и изучение кистей и красок не может превратить кого-либо в художника.<br />
<em>— Eric S. Raymond</em></p>
<p><strong>42.</strong> Не волнуйтесь, если что-то не работает. Если бы всё работало, вас бы уволили.<br />
<em>— Mosher’s Law of Software Engineering</em></p>
<p><strong>41.</strong> Я думаю, что Microsoft назвал технологию .Net для того, чтобы она не показывалась в списках директорий Unix.<br />
<em>— Oktal</em></p>
<p><strong>40.</strong> Хорошо, Java, ВОЗМОЖНО, хороший пример того как должен выглядеть язык. Но тогда программы на Java — это хороший пример как НЕЛЬЗЯ писать программы.<br />
<em>— pixadel</em></p>
<p><strong>39.</strong> Учитывая текущее плачевное состояние наших программ, можно сказать, что программирование определенно все ещё черная магия и, пока, мы не можем называть его технической дисциплиной.<br />
<em>— Bill Clinton</em></p>
<p><strong>38.</strong> Использование COBOL калечит разум; исходя из этого, обучение этому языку должно быть признано уголовно наказуемым преступлением.<br />
<em>— E. W. Dijkstra</em></p>
<p><strong>37.</strong> Объектно-ориентированная версия «спагетти кода» — это, конечно, «лазанья код» (очень много слоев).<br />
<em>— Roberto Waltman</em></p>
<p><strong>36.</strong> FORTRAN — это не цветок, а сорняк: он вынослив, иногда расцветает и произрастает в каждом компьютере<br />
<em>— Alan J. Perlis.</em></p>
<p><strong>35.</strong> Для меня долгое время было загадкой, как что-то очень дорогое и технологичное может быть столь бесполезным. И вскоре я осознал, что компьютер — это глупая машина, обладающая способностями выполнять невероятно умные вещи, тогда как программисты — это умные люди, у которых талант делать невероятные глупости. Короче, они нашли друг друга.<br />
<em>— Bill Bryson</em></p>
<p><strong>34.</strong> По моему эгоистическому мнению, большинство программ на C должны быть отформатированы с отступами на 2 метра вниз и засыпанными землей.<br />
<em>— Blair P. Houghton.</em></p>
<p><strong>33.</strong> Когда кто-то говорит: «Я хочу язык программирования, который может делать все, что ему скажу», то я даю этому человеку леденец.<br />
<em>— Alan J. Perlis</em></p>
<p><strong>32.</strong> Эволюция языков: FORTRAN — не строго типизированный язык, С — слабо типизированный язык. Ada — сильно типизированный язык. С++ — сильно раздутый язык.<br />
<em>— Ron Sercely</em></p>
<p><strong>31.</strong> В хорошем дизайне добавление вещи стоит дешевле, чем сама эта вещь.<br />
<em>— Thomas C. Gale</em></p>
<p><strong>30.</strong> Если называть Python заменой BASIC, то тогда и трансформер Optimus Prime — это только замена грузовика.<br />
<em>— Cory Dodt</em></p>
<p><strong>29. </strong>Болтовня ничего не стоит. Покажите мне код.<br />
<em>— Linus Torvalds</em></p>
<p><strong>28.</strong> Как видно, совершенство достигается не тогда, когда уже нечего прибавить, но когда уже ничего нельзя отнять.<br />
<em>— Antoine de Saint-Exupéry</em> (моя любимая цитата на все времена &#8211; <i>boombick</i>)</p>
<p><strong>27.</strong> С — это причудливый, несовершенный, но невероятно успешный язык.<br />
<em>— Dennis M. Ritchie.</em></p>
<p><strong>26.</strong> В теории, теория и практика неразделимы. На практике это не так.<br />
<em>— Yoggi Berra</em></p>
<p><strong>25.</strong> Вы не можете создавать хорошие программы без хорошей команды, но большинство софтверных команд ведут себя как проблемная семья.<br />
<em>— Jim McCarthy</em></p>
<p><strong>24.</strong> PHP — это маленькое зло, созданное некомпетентными новичками, в то время как Perl — это большое и коварное зло, созданное умелыми, но извращёнными профессионалами.<br />
<em>— Jon Ribbens</em></p>
<p><strong>23.</strong> Программирование — это как бить себя по лицу, рано или поздно ваш нос будет кровоточить.<br />
<em>— Kyle Woodbury</em></p>
<p><strong>22.</strong> Perl — это тот язык, который одинаково выглядит как до, так и после RSA шифрования…<br />
<em>— Keith Bostic</em></p>
<p><strong>21.</strong> Намного легче портировать шелл, чем скрипт на шелле.<br />
<em>— Larry Wall</em></p>
<p><strong>20.</strong> Я изобрел понятие «объектно-ориентированный», но могу заявить, что не имел в виду C++ при этом.<br />
<em>— Alan Kay</em></p>
<p><strong>19.</strong> Изучение программирования имеет такое же отношение к проектированию интерактивных систем, как обучение слепой печати к написанию стихов.<br />
<em>— Ted Nelson</em></p>
<p><strong>18.</strong> Лучшие программисты не чуть-чуть лучше хороших. Они на порядок лучше по любым меркам: концептуальное мышление, скорость, изобретательность и способность находить решения.<br />
<em>— Randall E. Stross</em></p>
<p><strong>17.</strong> Если бы McDonalds была бы софтверной компанией, то у них один из ста Биг Маков был бы отравленным, и их ответ на это был бы: «Мы сожалеем, вот вам купон на ещё два Биг Мака.&#8221;<br />
<em>— Mark Minasi</em></p>
<p><strong>16.</strong> Опасайтесь багов в приведенном выше коде; я только доказал корректность, но не запускал его.<br />
<em>— Donald E. Knuth.</em></p>
<p><strong>15.</strong> Анализ компьютерных систем — это как воспитание детей; можно нанести огромный вред, но нельзя гарантировать успех.<br />
<em>— Tom DeMarco</em></p>
<p><strong>14.</strong> Меня не интересует, будет ли это работаеть на ваших машинах! Мы не отдаем их заказчику!<br />
<em>— Vidiu Platon.</em></p>
<p><strong>13.</strong> Иногда лучше остаться спать дома в понедельник, чем провести всю неделю отлаживая написанный в понедельник код.<br />
<em>— Christopher Thompson</em></p>
<p><strong>12.</strong> Измерять продуктивность программирования подсчетом строк кода — это так же, как оценивать постройку самолета по его весу.<br />
<em>— Bill Gates</em></p>
<p><strong>11.</strong> Отладка кода вдвое сложнее, чем его написание. Так что если вы пишете код настолько умно, насколько можете, то вы по определению недостаточно сообразительны, чтобы его отлаживать.<br />
<em>— Brian W. Kernighan.</em></p>
<p><strong>10.</strong> Люди считают, что программирование — это наука избранных, но в реальности все наоборот — просто много людей создают программы, которые используют чужие программы, как-будто строя стену из маленьких кирпичиков.<br />
<em>— Donald Knuth</em></p>
<p><strong>9.</strong> Сначала учите науку программирования и всю теорию. Далее выработаете свой программистский стиль. Затем забудьте все и просто программируйте.<br />
<em>— George Carrette</em></p>
<p><strong>8.</strong> Многие из вас знакомы с достоинствами программиста. Их всего три, и разумеется это: лень, нетерпеливость и гордыня.<br />
<em>— Larry Wall</em></p>
<p><strong>7.</strong> Большинство программ на сегодняшний день подобны египетским пирамидам из миллиона кирпичиков друг на друге и без конструктивной целостности — они просто построены грубой силой и тысячами рабов.<br />
<em>— Alan Kay</em></p>
<p><strong>6.</strong> Трудность работы с програмистом заключается в том, что вы не можете понять что он делает до тех пор пока не стало слишком поздно.<br />
<em>— Seymour Cray</em></p>
<p><strong>5.</strong> Итерация свойственна человеку, рекурсия божественна.<br />
<em>— L. Peter Deutsch</em></p>
<p><strong>4.</strong> Меня два раза спрашивали [члены Парламента]: «Скажите на милось, мистер Бэббидж, что случится, если вы введете в машину неверные цифры? Cможем ли мы получить правильный ответ?» Я не могу себе даже представить какая путаница в голове может привести к подобному вопросу.<br />
<em>— Charles Babbage</em></p>
<p><strong>3.</strong> Большинство хороших программистов делают свою работу не потому, что ожидают оплаты или признания, а потому что получают удовольствие от программирования.<br />
<em>— Linus Torvalds</em></p>
<p><strong>2.</strong> Всегда пишите код так, будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете.<br />
<em>— Martin Golding</em></p>
<p><strong>1.</strong> Есть два способа создания дизайна программы. Один из них, это сделать его настолько простым, что в нем, очевидно, не будет недостатков. Другой способ — сделать его настолько запутанным, что в нем не будет очевидных недостатков.<br />
<em>— C.A. R. Hoare</em></p>
<p>via <a href="http://habrahabr.ru/blogs/htranslations/111348/">HabraHabr</a></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/198/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Тестируем MariaDB</title>
		<link>http://boombick.org/blog/posts/99</link>
		<comments>http://boombick.org/blog/posts/99#comments</comments>
		<pubDate>Wed, 26 May 2010 14:33:09 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/99</guid>
		<description><![CDATA[На недавно прошедшей DevConf выступал с докладом Michael &#8220;Monty&#8221; Widenius, автор и идейный вдохновитель MySQL. Он рассказал про то, что Oracle потихоньку убивает MySQL и презентовал форк под названием MariaDB. Меня заинтересовала эта СУРБД и вот представляю вам свой опыт ее использования :) Итак, по шагам. Эксперементировать решил на Debian, коий и поднял в виртуальной [...]]]></description>
			<content:encoded><![CDATA[<p>На недавно прошедшей <a href="http://devconf.ru">DevConf</a> выступал с докладом <a href="http://en.wikipedia.org/wiki/Michael_Widenius">Michael &#8220;Monty&#8221; Widenius</a>, автор и идейный вдохновитель MySQL. Он рассказал про то, что Oracle потихоньку убивает MySQL и презентовал форк под названием <a href="http://askmonty.org/wiki/MariaDB_versus_MySQL">MariaDB</a>.<br />
Меня заинтересовала эта СУРБД и вот представляю вам свой опыт ее использования :)<br />
<span id="more-99"></span><br />
Итак, по шагам.<br />
Эксперементировать решил на Debian, коий и поднял в виртуальной машине. Меня, в первую очередь, интересовало ее применение на собственных проектах и совместимость с моими скриптами и сайтиками :)<br />
Итак, сначала выполняем следующие действия:</p>
<p>Добавляем ключ репозитория в хранилище и добавляем репозиторий в sources.list</p>
<blockquote><pre>
wget -O- http://ourdelta.org/deb/ourdelta.gpg | sudo apt-key add -
    sudo wget http://ourdelta.org/deb/sources/lenny-mariadb-ourdelta.list \
      -O /etc/apt/sources.list.d/ourdelta.list
</pre>
</blockquote>
<p>Затем устанавливаем, собственно, сервер и клиентскую либу. Все остальное, что нам будет нужно, потянется по зависимостям</p>
<blockquote><pre>
aptitude install libmariadbclient16 mariadb-server-5.1
 </pre>
</blockquote>
<p><a href='http://boombick.org/blog/wp-content/uploads/2010/05/password_setup.png' title='password_setup.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/password_setup.png' alt='password_setup.png' /></a><br />
Все, как в mysql :) Вводим желаемый пароль root для входа в mariadb</p>
<p><a href='http://boombick.org/blog/wp-content/uploads/2010/05/login.png' title='login.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/login.png' alt='login.png' /></a><br />
Затем логинимся</p>
<blockquote><pre>
mysql -u root -p
</pre>
</blockquote>
<p>Все до боли привычно и знакомо :)<br />
Ну чтож, пока все отлично (даже запускается как /etc/init.d/mysql start), проверим, как оно дружит с PHP</p>
<p>Сначала я хотел запустить стандартные бенчмарки, но жестоко обломался :) В репозитории были версии только для 64-битных систем<br />
<a href='http://boombick.org/blog/wp-content/uploads/2010/05/test_failed.png' title='test_failed.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/test_failed.png' alt='test_failed.png' /></a></p>
<p>Ну и фиг с ним, подрубаем PHP</p>
<blockquote><pre>
aptitude install php5-cli php5-mysql
</pre>
</blockquote>
<p>создаем тестовую табличку<br />
<a href='http://boombick.org/blog/wp-content/uploads/2010/05/create_table.png' title='create_table.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/create_table.png' alt='create_table.png' /></a><br />
и проверяем</p>
<p><a href='http://boombick.org/blog/wp-content/uploads/2010/05/test_connect.png' title='test_connect.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/test_connect.png' alt='test_connect.png' /></a></p>
<p><a href='http://boombick.org/blog/wp-content/uploads/2010/05/test_connect_result.png' title='test_connect_result.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/test_connect_result.png' alt='test_connect_result.png' /></a></p>
<p>Как видите, со стороны PHP все абсолютно прозрачно и никаких лишних телодвижений совершать не приходится. Это радует :)<br />
Для эксперимента можно поставить Wordpres<br />
Доставляем apache и все необходимое для него и пробуем<br />
<a href='http://boombick.org/blog/wp-content/uploads/2010/05/wp_install.png' title='wp_install.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/wp_install.png' alt='wp_install.png' /></a></p>
<p><a href='http://boombick.org/blog/wp-content/uploads/2010/05/wp_installed.png' title='wp_installed.png'><img src='http://boombick.org/blog/wp-content/uploads/2010/05/wp_installed.png' alt='wp_installed.png' /></a></p>
<p>Все отлично :)</p>
<p>PS Моей целью не было выяснение всех отличий MariaDB от MySQL, меня интересовала именно возможность применять ее в собственных проектах и дальнейшего отказа от MySQL. Возможность проверил, в дальнейшем попробую поставить ее на реальный сервер и попробовать в  production на каких-нибудь не очень критичных проектах :)<br />
О результатх будет отдельный пост.</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/99/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Установка Django на devio.us</title>
		<link>http://boombick.org/blog/posts/95</link>
		<comments>http://boombick.org/blog/posts/95#comments</comments>
		<pubDate>Tue, 04 May 2010 08:02:31 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/95</guid>
		<description><![CDATA[Как, наверняка, всем известно, недавно появился проект Devio.us, который предлагает всем желающим бесплатный shell-хостинг на базе OpenBSD. В нагрузку к шеллу также предлагается домен третьего уровня, вида %username%.devio.us или devio.us/~%username%, одна база данных MySQL и 100 мегов места. За пару баксов в месяц эти показатели можно улучшить :) На сервере установлен PHP (версии 5.2.12) как [...]]]></description>
			<content:encoded><![CDATA[<p>Как, наверняка, всем известно, недавно появился проект <a href="http://devio.us">Devio.us</a>, который предлагает всем желающим бесплатный shell-хостинг на базе OpenBSD. В нагрузку к шеллу также предлагается домен третьего уровня, вида %username%.devio.us или devio.us/~%username%, одна база данных MySQL и 100 мегов места. За пару баксов в месяц эти показатели можно улучшить :)<br />
На сервере установлен PHP (версии 5.2.12) как модуль апача (весьма, кстати, древнего &#8211; 1.3.29) и предлагается CGI-интерфейс. Ну и также доступны perl 5.10.1 и python 2.5.4. Целью проекта является привлечение новых членов в коммьюнити OpenBSD. При регистрации необходимо указать причину, по которой вам кровь из носу надо получить там аккаунт :) Процент отказов, к слову, довольно мал.<br />
Итак, поигравшись с PHP, захотелось чего-то большего. И так как на сервере присутствует python, захотелось прикрутить туда Django.<br />
<span id="more-95"></span><br />
<strong>Установка Django</strong><br />
Проведя ревизию модулей apache я выяснил, что ни mod_python, ни mod_wsgi не установлены. Грустно, но ладно. Для начала я просто залил туда дистрибутив django (версии 1.1.1)</p>
<blockquote>
<pre>
$ scp Django-1.1.1.tar.gz devio.us:</pre>
</blockquote>
<p>и распаковал его</p>
<blockquote>
<pre>
$ gunzip Django-1.1.1.tar.gz
$ tar xvf Django-1.1.1.tar
$ ln -s Django-1.1.1 django #  для дальнейшего удобства</pre>
</blockquote>
<p>Добавим переменную окружения PYTHONPATH для корректной работы Django</p>
<blockquote>
<pre>
$ export PYTHONPATH='/home/boombick/django'
$ echo "export PYTHONPATH='/home/boombick/django'" &gt;&gt; ~/.profile</pre>
</blockquote>
<p>И создадим симлинк для django-admin</p>
<blockquote>
<pre>
$ mkdir ~/bin
$ ln -s /home/boombick/django/django/bin/django-admin.py /home/boombik/bin/django-admin.py</pre>
</blockquote>
<p>Дальше все просто: создаем новый проект Django</p>
<blockquote>
<pre>
$ django-admin.py startproject djtest
$ cd djtest</pre>
</blockquote>
<p>И на этом этапе я просто запустил dev-сервер из поставки Django на высоком порту (занять порт с номером ниже 1024 без привелегий root не получится)</p>
<blockquote>
<pre>
$ python manage.py runserver 0.0.0.0:32000</pre>
</blockquote>
<p>Зайдя на http://boombick.devio.us:32000 я увидел приветственную страницу пустого проекта Django. Все получилось :)</p>
<p><strong>Запуск Django через CGI</strong><br />
В принципе, можно было бы оставить все и так. Но.<br />
1. Хотелось все-таки ходить к себе на страничку по 80 порту<br />
2. На free-аккаунте нельзя детачить приложения. Т.е. нельзя оставить запущенным сервер и разлогиниться. Что, впрочем, логично, иначе сервер превратился бы в рассадник IRC-ботов :)<br />
Можно, конечно, извратиться и держать логин постоянно, восстанавливая оборванное подключение и перезапуская сервер, но это не наш путь.</p>
<p>Итак.<br />
Сначала я просто пробрасывал запросы к Django через PHP (в виде index.php) :) Эдакий PHP-Proxy, но мало того, что это запредельно криво, так еще и не очень понятно, что делать с POST-запросами. Выход был один &#8211; заставить Django работать через CGI.<br />
Помучив гугл я нашел несколько разноненных мануалов и приступил к выполнению.<br />
Для начала создадим в директории <code>$HOME/public_html</code> файл django.cgi вот с таким содержанием:</p>
<blockquote>
<pre>
#!/usr/local/bin/python
# encoding: utf-8
"""
django.cgi

A simple cgi script which uses the django WSGI to serve requests.
Rewrited for use on devio.us shell hosting

Code copy/pasted from PEP-0333 and then tweaked to serve django.

http://www.python.org/dev/peps/pep-0333/#the-server-gateway-side

This script assumes django is on your sys.path, and that your site code is at
/home/mycode/mysite. Copy this script into your cgi-bin directory (or do
whatever you need to to make a cgi script executable on your system), and then
update the paths at the bottom of this file to suit your site.

This is probably the slowest way to serve django pages, as the python
interpreter, the django code-base and your site code has to be loaded every
time a request is served. FCGI and mod_python solve this problem, use them if
you can.

In order to speed things up it may be worth experimenting with running
uncompressed zips on the sys.path for django and the site code, as this can be
(theorectically) faster. See PEP-0273 (specifically Benchmarks).

http://www.python.org/dev/peps/pep-0273/

Make sure all python files are compiled in your code base. See

http://docs.python.org/lib/module-compileall.html

"""

import os, sys
sys.path.append("/home/boombick/django") # Поменяйте на путь к Django
sys.path.append("/home/boombick/djtest")  # Поменяйте на путь к вашему проекту

import django.core.handlers.wsgi

def run_with_cgi(application):

    environ                      = dict(os.environ.items())
    environ['wsgi.input']        = sys.stdin
    environ['wsgi.errors']       = sys.stderr
    environ['wsgi.version']      = (1,0)
    environ['wsgi.multithread']  = False
    environ['wsgi.multiprocess'] = True
    environ['wsgi.run_once']     = True

    if environ.get('HTTPS','off') in ('on','1'):
        environ['wsgi.url_scheme'] = 'https'
    else:
        environ['wsgi.url_scheme'] = 'http'

    headers_set  = []
    headers_sent = []

    def write(data):
        if not headers_set:
             raise AssertionError("write() before start_response()")

        elif not headers_sent:
             # Before the first output, send the stored headers
             status, response_headers = headers_sent[:] = headers_set
             sys.stdout.write('Status: %s\r\n' % status)
             for header in response_headers:
                 sys.stdout.write('%s: %s\r\n' % header)
             sys.stdout.write('\r\n')

        sys.stdout.write(data)
        sys.stdout.flush()

    def start_response(status,response_headers,exc_info=None):
        if exc_info:
            try:
                if headers_sent:
                    # Re-raise original exception if headers sent
                    raise exc_info[0], exc_info[1], exc_info[2]
            finally:
                exc_info = None     # avoid dangling circular ref
        elif headers_set:
            raise AssertionError("Headers already set!")

        headers_set[:] = [status,response_headers]
        return write

    result = application(environ, start_response)
    try:
        for data in result:
            if data:    # don't send headers until body appears
                write(data)
        if not headers_sent:
            write('')   # send headers now if body was empty
    finally:
        if hasattr(result,'close'):
            result.close()

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
run_with_cgi(django.core.handlers.wsgi.WSGIHandler())</pre>
</blockquote>
<p>Затем меняем в <code>/path/to/dajngo-project/settings.py</code> параметр <code>ROOT_URLCONF</code> на <code>urls</code> вместо <code>projectname.urls</code><br />
Делаем файл исполняемым</p>
<blockquote>
<pre>
$ chmod a+x public_html/django.cgi</pre>
</blockquote>
<p>И проверяем работоспособность :)</p>
<p>http://boombick.devio.us/django.cgi</p>
<p><a href="http://boombick.org/blog/wp-content/uploads/2010/05/djangocgi.png" title="djangocgi.png"><img src="http://boombick.org/blog/wp-content/uploads/2010/05/djangocgi.thumbnail.png" alt="djangocgi.png" /></a><br />
Если все ок, то можно переходить к следующему шагу. А если нет и вы получаете 500 ошибку, то смотрите лог. Который, кстати, лежит в <code>/var/www/logs/error_log</code> В процессе установки очень удобно было его мониторить в отдельной консольке при помощи <code>tail -f</code><br />
Учтите только, что в этот лог падают сообщения о всех ошибках и вам надо отделять свои запросы от остальных :)</p>
<p><strong>Настройка Apache</strong><br />
Теперь надо настроить Apache для переадресации всех запросов к нашему django.cgi. Я очень давно не ковырялся с Apache (в последнее время использую исключительно nginx) и с трудом и доками вспоминал синтаксис mod_rewrite<br />
В результате родился вот такой вот файлик <code>.htaccess</code>, который надо положить в директорию <code>public_html</code></p>
<blockquote>
<pre>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /django.cgi%{REQUEST_URI}?%{QUERY_STRING}</pre>
</blockquote>
<p><strong>Проверяем</strong><br />
В <code>~/djtest/urls.py</code> добавим правило для обработки всех адресов</p>
<blockquote>
<pre>
from django.conf.urls.defaults import *
from views import test_page

urlpatterns = patterns('',
    (r'^(.*)$', test_page)
)</pre>
</blockquote>
<p>И создадим файл <code>~/djtest/views.py</code> с, собственно, обработчиком</p>
<blockquote>
<pre>
from django.http import HttpResponse       

def test_page(request, url):
    html = "WORKING! Url is %s" % url
    return HttpResponse(html)</pre>
</blockquote>
<p>Заходим на http://boombick.devio.us/foo/bar<br />
<a href="http://boombick.org/blog/wp-content/uploads/2010/05/django.png" title="django.png"><img src="http://boombick.org/blog/wp-content/uploads/2010/05/django.thumbnail.png" alt="django.png" /></a><br />
Все работает :)</p>
<p><strong>Благодарности</strong><br />
Хочу сказать большое спасибо ребятам из конференции django@conference.jabber.ru, а конкретно <strong>ne_formal</strong> за неоценимую помощь :) Без него этот процесс затянулся бы куда больше!</p>
<p><strong>Важное замечание</strong><br />
Если вы читали комментарии в начале файла django.cgi, то не могли не заметить такой абзац:</p>
<blockquote><p>This is probably the slowest way to serve django pages, as the python<br />
interpreter, the django code-base and your site code has to be loaded every<br />
time a request is served. FCGI and mod_python solve this problem, use them if<br />
you can.
</p></blockquote>
<p>Что в вольном переводе выглядит как:<br />
<em>Это самый медленный путь для работы с django. На каждый запрос создается экземпляр интерпретатора Python. Если у вас есть возможность использовать FCGI или mod_python &#8211; используйте их!</em><br />
Так что статью прощу рассматривать исключительно как proof of concept или выход из совсем уж безвыходной ситуации! :)<br />
Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/95/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Ловушки bash</title>
		<link>http://boombick.org/blog/posts/94</link>
		<comments>http://boombick.org/blog/posts/94#comments</comments>
		<pubDate>Thu, 29 Apr 2010 18:24:33 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/94</guid>
		<description><![CDATA[Программирование на shell в общем и на bash в частности богато своими нюансами, которые, зачастую, упускаются из вида. В результате мы имеем проблемы на очевидных, вообщем-то, операциях. И как результат, зачастую, бывает &#8220;а ну его, этот баш! Перепишу на php/perl/python/ruby/etc&#8221; Эта статья написана для обсуждения и путей решения нескольких самых часто встречающихся &#8220;камней преткновения&#8221; при [...]]]></description>
			<content:encoded><![CDATA[<p>Программирование на shell в общем и на bash в частности богато своими нюансами, которые, зачастую, упускаются из вида. В результате мы имеем проблемы на очевидных, вообщем-то, операциях. И как результат, зачастую, бывает &#8220;а ну его, этот баш! Перепишу на php/perl/python/ruby/etc&#8221;<br />
Эта статья написана для обсуждения и путей решения нескольких самых часто встречающихся &#8220;камней преткновения&#8221; при программировании на bash. Я лично очень полюбил программировать на bash в последнее время и хочу поделиться кусочком знаний с вами :)<br />
<span id="more-94"></span><br />
<strong>1. for i in `ls *.mp3`</strong><br />
Знакомо? :) Если в имени файла встретится пробел, то все ваши усилия будут напрасны. Каждая из составляющих имени попадет в отдельную итерацию.</p>
<blockquote>
<pre>
 for i in `ls *.mp3`; do # Неверно!
    some command $i      # Неверно!
 done</pre>
</blockquote>
<p>Не получится и &#8220;закавычить&#8221; вывод <code>ls</code></p>
<blockquote>
<pre>
 for i in "`ls *.mp3`"; do # Неверно!
 ...</pre>
</blockquote>
<p>В этом случае ВЕСЬ вывод ls будет рассматриваться в контексте одной итерации. Это немного не то, чего хотелось бы добиться :) Решение есть</p>
<blockquote>
<pre>
for i in *.mp3; do  # Надо делать вот так и...
   some command "$i" # ...во втором пункте мы рассмотрим и это "узкое" место.
 done</pre>
</blockquote>
<p><strong>2. cp $file $target</strong><br />
Если в <code>$file</code> или <code>$target</code> окажутся пробелы, то вас ждет разочарование :)<br />
Выход не менее очевиден</p>
<blockquote>
<pre>
 cp "$file" "$target"</pre>
</blockquote>
<p><strong>3. Имена файлов, начинающиеся с дефисов</strong><br />
Всем известно, что параметры многих команд начинаются с дефиса <code>-</code>. В том случае, если с дефиса начинается имя файла, то оно будет ошибочно воспринято как параметр и вы получите ошибку. В лучшем случае.<br />
Одно из решений &#8211; поместить перед именами передаваемых фалов два дефиса <code>--</code>. Это сигнализирует команде (например <code>cp</code>) о том, что список параметров закончен и дальше идут аргументы:</p>
<blockquote>
<pre>
 cp -- "$file" "$target"</pre>
</blockquote>
<p>Но более элегантным решением, все-таки, будет цикл (причем с указанием каталога в пути к файлу):</p>
<blockquote>
<pre>
 for i in ./*.mp3; do
   cp "$i" /target
   ...</pre>
</blockquote>
<p>В этом случае аргумент, начинающийся с дефиса, будет передан как <code>./-foo.mp3</code> и все сработает нормально.</p>
<p><strong>4. [ $foo = "bar" ]</strong><br />
В bash вам необходимо заботиться о своих переменных. Иначе получите кучу ошибок :) Пример из заголовка выдаст ошибку в двух случаях:</p>
<ul>
<li>Если переменная, переданная в <code>[</code> не объявлена или пустая, то команда <code>[</code> "увидит" выражение<br />
<blockquote>
<pre>[ $foo = "bar" ]</pre>
</blockquote>
<p>как</p>
<blockquote>
<pre>[ = "bar" ]</pre>
</blockquote>
<p>и вы получите ошибку <em>unary operator expected</em> (ожидается унарный оператор). Так как оператор <code>=</code> бинарный, то <code>[</code> будет несколько шокирована :)</li>
<li>Если в <code>$foo</code> содержаться пробелы, то сравнение также будет некорректным<br />
<blockquote>
<pre>[ multiple words here = "bar" ]</pre>
</blockquote>
<p>И если вам это может показаться нормальным, то для <code>[</code> это довольно неожиданно :)</li>
</ul>
<p>Более корректно будет записать выражение как</p>
<blockquote>
<pre> [ "$foo" = bar ] # Все отлично</pre>
</blockquote>
<p>но, опять-таки, выполучите ошибку, если текст в переменной начинается с <code>-</code><br />
В bash есть ключевое слово <code>[[</code>, которое является расширением старой команды <code>test</code>, также известной как <code>[</code> и это решение всех подобных проблем :)</p>
<blockquote>
<pre>[[ $foo = bar ]] # Правильно</pre>
</blockquote>
<p>В случае с использованием <code>[[ ]]</code> вам не надо заключать переменную в кавычки, так как эта конструкция корректно обрабатывает и пустые переменные, и переменные, содержащие пробелы, и переменные, значение которых начинается с дефиса.<br />
Также вам может встретиться вот такой вариант:</p>
<blockquote>
<pre>[ x"$foo" = xbar ]</pre>
</blockquote>
<p><code>x"$foo"</code> - это хак для старых версий шелла, в которых вы вынуждены использовать <code>[</code>. И чтобы позаботиться о значении переменных, наичнающихся с дефиса, то можно использовать вот такую конструкцию.</p>
<p>А если одна из сторон сравниваемого выражения константа, то просто поместите переменную в правую часть :) <code>[</code> не обращает внимания на то, что находится справа</p>
<blockquote>
<pre>[ bar = "$foo" ]</pre>
</blockquote>
<p>Только левая часть выражения требует вашего особого внимания, на случай значения, начинающегося с дефиса.</p>
<p>Продолжение следует :)</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/94/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Advanced grep</title>
		<link>http://boombick.org/blog/posts/88</link>
		<comments>http://boombick.org/blog/posts/88#comments</comments>
		<pubDate>Wed, 24 Feb 2010 12:48:17 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/88</guid>
		<description><![CDATA[Написал небольшой скриптик, который красиво форматирует результаты рекурсивного поиска по исходникам (вообще-то по любым файлам, но я писал это все именно для поиска по дереву исходников :)) Вот так выглядят результаты его работы &#8211; это поиск слова &#8216;function&#8217; по всем файлам во всех вложенных подпапках Как видно на скрине, результаты поиска группируются по файлам, показывается [...]]]></description>
			<content:encoded><![CDATA[<p>Написал небольшой скриптик, который красиво форматирует результаты рекурсивного поиска по исходникам (вообще-то по любым файлам, но я писал это все именно для поиска по дереву исходников :))<br />
<span id="more-88"></span><br />
Вот так выглядят результаты его работы &#8211; это поиск слова &#8216;function&#8217; по всем файлам во всех вложенных подпапках<br />
<a href="http://boombick.org/blog/wp-content/uploads/2010/02/screen.png" title="screen.png"><img src="http://boombick.org/blog/wp-content/uploads/2010/02/screen.thumbnail.png" alt="screen.png" /></a><br />
Как видно на скрине, результаты поиска группируются по файлам, показывается на какой строке файла найдено совпадение, сама искомая строка подсвечивается.<br />
Поиск регистронезависимый.</p>
<p>@FIXME<br />
При подсветке слова регистр слова сбрасывается</p>
<p>@TODO<br />
Сделать разбивку результатов по страницам<br />
Вынести настройки в конфиг (например такие, как цвет в результатах поиска)</p>
<p>Для работы использует bash, awk, grep, sed.<br />
В скрипте есть такая строка</p>
<blockquote>
<pre>
grep -vE '(svn|jquery)'</pre>
</blockquote>
<p>Это, собственно, исключения, которые надо выбрасывать из результатов поиска. Т.е. строки, в которых эти &#8220;буквосочетания&#8221; есть, в результаты не попадут. Если вам это не нужно, просто выкиньте эту часть (в последствии это тоже уйдет в конфиг) :)</p>
<p>Изначально все писалось для FreeBSD, посему если у вас bash установлен не по пути <code>/usr/local/bin/bash</code>, то либо поменяйте путь к интерпретатору, либо сделайте симлинк :)</p>
<p>Скрипт распространяется под BSD-лицензией, о багах пишите сюда :)<br />
Скачать: <a href="http://code.google.com/p/srch/">http://code.google.com/p/srch/</a><br />
Вот, вообщем-то, и все, enjoy! Надеюсь, кому-нибудь пригодится :)<br />
UPD: Спасибо за совет с размещением на GoogleCode!</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/88/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Хватит писать foreach()</title>
		<link>http://boombick.org/blog/posts/87</link>
		<comments>http://boombick.org/blog/posts/87#comments</comments>
		<pubDate>Fri, 19 Feb 2010 11:04:59 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/87</guid>
		<description><![CDATA[По крайней мере в php :) Обращаюсь к php-разработчикам &#8211; подумайте, сколько раз за рабочий день вы пишите for() и foreach()? Я, например, довольно много :) Сейчас я пишу на php 5.3, а в нем есть очень удобные средства для того, чтобы обойтись без обхода массива в цикле &#8211; это функции для работы с массивами, [...]]]></description>
			<content:encoded><![CDATA[<p>По крайней мере в php :) Обращаюсь к php-разработчикам &#8211; подумайте, сколько раз за рабочий день вы пишите for() и foreach()? Я, например, довольно много :) Сейчас я пишу на php 5.3, а в нем есть очень удобные средства для того, чтобы обойтись без обхода массива в цикле &#8211; это функции для работы с массивами, которые принимают callback в качестве аргумента и <em>замыкания</em><br />
<span id="more-87"></span><br />
Я говорю о <a href="http://www.php.net/manual/en/function.array-map.php">array_map</a>(), <a href="http://www.php.net/manual/en/function.array-reduce.php">array_reduce</a>(), <a href="http://www.php.net/manual/en/function.array-filter.php%0A">array_filter</a>() и <a href="http://www.php.net/manual/en/function.uasort.php">uasort</a>() (ну и похожих на них). Использование этих функций &#8211; неплохой способ обойтись без обхода массивов в цикле.<br />
В PHP4 и PHP5.2 использование коллбэков выглядело весьма и весьма громоздко. Вы должны были определить функцию (или метод), а затем передать ее имя (или массив, содержащий имя класса и имя публичного или статического метода) в качестве аргумента. Можно было извернуться через create_function, но все равно это выглядело громоздко.<br />
В PHP5.3 вы можете определить анонимную функцию где-нибудь в коде (или даже непосредственно в вызове функции). Эти функции выглядят как обычные переменные и вы спокойно можете передавать их как аргумент.<br />
Я, конечно, не поклонник смешивания функционального и объектно-ориентированного подхода (тем более, что в PHP оба имеют проблемы с реализацией :)), но подобный прием поможет избавиться в коде от шума, который создают циклы, предназначенный для обхода массивов.</p>
<blockquote>
<pre>
// обычный массив простых чисел до 20
$primeNumbers = array(2, 3, 5, 7, 11, 13, 17, 19);

// array_map() применяет callback-функцию к каждому элементу массива и
// возвращает результат
$square = function($number) {
    return $number * $number;
};
$squared = array_map($square, $primeNumbers);
echo "Квадраты простых чисел: ",
     implode(', ', $squared), "\n";

// array_reduce() рекурсивно применяет фнукцию к парам значений
// и превращает массив в одно единственное значение
// Очень похоже на array_sum(),
// но использование callback открывает неплохие перспективы
$sum = function($a, $b) {
    return $a + $b;
};
$total = array_reduce($primeNumbers, $sum);
echo "Сумма простых чисел: ", $total, ".\n";

// array_filter() оставляет в массиве значения,
// которые удовлетворяют условию
$even = function($number) {
    return $number % 2 == 0;
};
$evenPrimes = array_filter($primeNumbers, $even);
echo "Четные простые числа: ",
     implode(', ', $evenPrimes), ".\n";

// uasort() сортирует массив и
// сохраняет связь междя ключом и значением
// похожа на asort(), но использует callback
$compare = function($a, $b) {
    if ($a == $b) {
        return 0;
    }
    return ($a &gt; $b) ? -1 : 1;
};
uasort($primeNumbers, $compare);
echo "Упорядоченный по убыванию массив простых чисел: ",
     implode(', ', $primeNumbers), ".\n";</pre>
</blockquote>
<p>UPDATE:<br />
Обещанные замеры производительности. Тест, конечно, весьма синтетический, но и он весьма нагляден. Я, честно говоря, был слегка удивлен.<br />
Код теста:</p>
<blockquote><pre>
echo "We're using the PHP " . phpversion() . "\n";

$array = $array2 = range(0, 10000, 1);

echo "Array contains " . count($array) . " elements\n";

$t1 = microtime(1);
echo "BEGIN array_map\n";

array_map(
        function($number){
                return $number * $number;
        },
        $array
);
$t2 = microtime(1);
$res = $t2 - $t1;
echo "END array_map: " . round($res, 4) . "\n\n";

$t1 = microtime(1);
echo "BEGIN foreach:\n";
foreach ($array2 as $key => $value){
        $array2[$key] = $value * $value;
}
$t2 = microtime(1);
$res = $t2 - $t1;
echo "END foreach: " . round($res, 4) . "\n\n";
</pre>
</blockquote>
<p>И вот результаты:</p>
<pre>
[boombick@srv01 /tmp]$ php -f test.php
We're using the PHP 5.3.1
Array contains 10001 elements
BEGIN array_map
END array_map: 0.0109

BEGIN foreach:
END foreach: 0.0052

[boombick@srv01 /tmp]$
</pre>
<p>Как видно из результата, array_map действительно проигрывает по скорости foreach</p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/87/feed</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>100 команд vim, которые должен знать каждый программист</title>
		<link>http://boombick.org/blog/posts/84</link>
		<comments>http://boombick.org/blog/posts/84#comments</comments>
		<pubDate>Tue, 29 Sep 2009 13:18:27 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/84</guid>
		<description><![CDATA[Небольшая подсказка по vim, будет полезна всем, я думаю. Это не руководство для начинающих (т.е. команд типа :wq здесь нет) Комментарии приветствуются :) Поиск /word Искать слово &#8220;word&#8221; сверху вниз ?word Искать слово &#8220;word&#8221; снизу вверх /jo[ha]n&#62; Искать &#8220;john&#8221; или &#8220;joan&#8221; /\&#60; the Искать слова, начинающееся на &#8220;the&#8221; /the\&#62; Искать слова, заканчивающиеся на &#8220;the&#8221; /\&#60; [...]]]></description>
			<content:encoded><![CDATA[<p>Небольшая подсказка по vim, будет полезна всем, я думаю. Это не руководство для начинающих (т.е. команд типа <code>:wq</code> здесь нет)<br />
Комментарии приветствуются :)<br />
<span id="more-84"></span></p>
<h2>Поиск</h2>
<table border="0" cellspacing="3">
<tr>
<td>/word</td>
<td>Искать слово &#8220;word&#8221; сверху вниз</td>
</tr>
<tr>
<td>?word</td>
<td>Искать слово &#8220;word&#8221; снизу вверх</td>
</tr>
<tr>
<td>/jo[ha]n&gt;</td>
<td>Искать &#8220;john&#8221; или &#8220;joan&#8221;</td>
</tr>
<tr>
<td>/\&lt; the</td>
<td>Искать слова, начинающееся на &#8220;the&#8221;</td>
</tr>
<tr>
<td>/the\&gt;</td>
<td>Искать слова, заканчивающиеся на &#8220;the&#8221;</td>
</tr>
<tr>
<td>/\&lt; the\&gt;</td>
<td>Искать &#8220;the&#8221;</td>
</tr>
<tr>
<td>/\&lt; …. \&gt;</td>
<td>Искать слова из четырех символов</td>
</tr>
<tr>
<td>/fred\|joe</td>
<td>Искать &#8220;fred&#8221; или &#8220;joe&#8221;</td>
</tr>
<tr>
<td>/\&lt;\d\d\d\d\&gt;</td>
<td>Искать 4 цифры подряд</td>
</tr>
<tr>
<td>/^\n\{3}</td>
<td>Искать 3 пустые строки</td>
</tr>
<tr>
<td>:bufdo /searchstr/</td>
<td>Искать во всех открытых файлах</td>
</tr>
</table>
<h2>Замена</h2>
<table border="0" cellspacing="3">
<tr>
<td>:%s/old/new/g</td>
<td>Заменить все вхождения &#8220;old&#8221; на &#8220;new&#8221;</td>
</tr>
<tr>
<td>:%s/old/new/gw</td>
<td>Заменить все вхождения &#8220;old&#8221; на &#8220;new&#8221;  с запросом подтверждения</td>
</tr>
<tr>
<td>:2,35s/old/new/g</td>
<td>Заменить все вхождения &#8220;old&#8221; на &#8220;new&#8221; между 2 и 35 строками</td>
</tr>
<tr>
<td>:5,$s/old/new/g</td>
<td>Заменить все вхождения &#8220;old&#8221; на &#8220;new&#8221; начиная с 5 строки и до конца файла</td>
</tr>
<tr>
<td>:%s/^/hello/g</td>
<td>Добавить &#8220;hello&#8221; в начало каждой строки</td>
</tr>
<tr>
<td>:%s/$/Harry/g</td>
<td>Добавить &#8220;Harry&#8221;  в конец каждой строки</td>
</tr>
<tr>
<td>:%s/onward/forward/gi</td>
<td>Заменить &#8220;onward&#8221; на &#8220;forward&#8221;  с учетом регистра</td>
</tr>
<tr>
<td>:%s/ *$//g</td>
<td>Убрать все пробелы</td>
</tr>
<tr>
<td>:g/string/d</td>
<td>Удалить все строки, содержащие &#8220;string&#8221;</td>
</tr>
<tr>
<td>:v/string/d</td>
<td>Удалить все строки, не содержащие &#8220;string&#8221;</td>
</tr>
<tr>
<td>:s/Bill/Steve/</td>
<td>Заменить первое вхождение &#8220;Bill&#8221; на &#8220;Steve&#8221; в текущей строке</td>
</tr>
<tr>
<td>:s/Bill/Steve/g</td>
<td>Заменить все вхождения &#8220;Bill&#8221; на &#8220;Steve&#8221; в текущей строке</td>
</tr>
<tr>
<td>:%s/\r//g</td>
<td>Убрать символ возврата каретки (Такие тексты обычно приходят от windows-пользователей)</td>
</tr>
<tr>
<td>:%s#&gt;[^&lt;]\+&gt;##g</td>
<td>Очистить текст от HTML-тегов</td>
</tr>
<tr>
<td>:%s/^\(.*\)\n\1$/\1/</td>
<td>Удалить строки, повторяющиеся дважды</td>
</tr>
<tr>
<td>Ctrl+a</td>
<td>Увеличить число под курсором на единицу</td>
</tr>
<tr>
<td>Ctrl+x</td>
<td>Уменьшить число под курсором на единицу</td>
</tr>
<tr>
<td>ggVGg?</td>
<td>Преобразовать текст в Rot13</td>
</tr>
</table>
<h2>Регистр</h2>
<table border="0" cellspacing="3">
<tr>
<td>Vu</td>
<td>Перевести строку в нижний регистр</td>
</tr>
<tr>
<td>VU</td>
<td>Перевести строку в верхний регистр</td>
</tr>
<tr>
<td>g~~</td>
<td>Инвертировать регистр</td>
</tr>
<tr>
<td>vEU</td>
<td>Перевести слово под курсором в верхний регистр</td>
</tr>
<tr>
<td>vE~</td>
<td>Инвертировать регистр слова</td>
</tr>
<tr>
<td>ggguG</td>
<td>Перевести весь текст в нижний регистр</td>
</tr>
<tr>
<td>:set ignorecase</td>
<td>Регистронезависимый поиск</td>
</tr>
<tr>
<td>:set smartcase</td>
<td>Игнорировать регистр при поиске, если в искомом выражении нет символов верхнего регистра</td>
</tr>
<tr>
<td>:%s/\&lt;./\u&#038;/g</td>
<td>Перевести первую букву каждого слова в верхний регистр</td>
</tr>
<tr>
<td>:%s/\&lt;./\l&#038;/g</td>
<td>Перевести первую букву каждого слова в нижний регистр</td>
</tr>
<tr>
<td>:%s/.*/\u&#038;</td>
<td>Перевести первую букву первого слова в каждой строке в верхний регистр</td>
</tr>
<tr>
<td>:%s/.*/\l&#038;</td>
<td>Перевести первую букву первого слова в каждой строке в нижний регистр</td>
</tr>
</table>
<h2>Чтение/запись файлов</h2>
<table border="0" cellspacing="3">
<tr>
<td>:1,10 w outfile</td>
<td>Записать в <em>outfile</em> с первой по десятую строки</td>
</tr>
<tr>
<td>:1,10 w >> outfile</td>
<td>Добавить в <em>outfile</em> с первой по десятую строки</td>
</tr>
<tr>
<td>:r infile</td>
<td>Вставить содержимое файла <em>infile</em></td>
</tr>
<tr>
<td>:23r infile</td>
<td>Вставить содержимое файла <em>infile</em> после 23 строки</td>
</tr>
</table>
<h2>Навигация по ФС</h2>
<table border="0" cellspacing="3">
<tr>
<td>:e .</td>
<td>Открыть встроенный файл-менеджер</td>
</tr>
<tr>
<td>:Sex</td>
<td>Разбить окно и открыть встроенный файл менеджер</td>
</tr>
<tr>
<td>:browse e</td>
<td>Графический файл-менеджер</td>
</tr>
<tr>
<td>:ls</td>
<td>Список буферов</td>
</tr>
<tr>
<td>:cd ..</td>
<td>Перейти в родительскую директорию</td>
</tr>
<tr>
<td>:args</td>
<td>Список открытых файлов</td>
</tr>
<tr>
<td>:args *.php</td>
<td>Открыть все файлы с расширением *.php</td>
</tr>
<tr>
<td>:grep expression *.php</td>
<td>Показать список файлов с расширением php, содержащих в имени <em>expression</em></td>
</tr>
<tr>
<td>gf</td>
<td>Открыть файл с именем, равным слову, находящемуся под курсором</td>
</tr>
</table>
<h2>Взаимодействие с ОС</h2>
<table border="0" cellspacing="3">
<tr>
<td>:!pwd</td>
<td>Выполнить команду <code>pwd</code> и вернуться</td>
</tr>
<tr>
<td>!!pwd</td>
<td>Выполнить команду <code>pwd</code> и вставить результат в редактор</td>
</tr>
<tr>
<td>:sh</td>
<td>Открыть шелл</td>
</tr>
<tr>
<td>$exit</td>
<td>Вернуться в редактор из шелла</td>
</tr>
</table>
<h2>Выравнивание</h2>
<table border="0" cellspacing="3">
<tr>
<td>:%!fmt</td>
<td>Выровнять все строки</td>
</tr>
<tr>
<td>!}fmt</td>
<td>Выровнять все строки в текущей позиции</td>
</tr>
<tr>
<td>5!!fmt</td>
<td>Выровнять следующие 5 строк</td>
</tr>
</table>
<h2>Вкладки</h2>
<table border="0" cellspacing="3">
<tr>
<td>:tabnew</td>
<td>Создать новую вкладку</td>
</tr>
<tr>
<td>gt</td>
<td>Перейти на следующую вкладку</td>
</tr>
<tr>
<td>:tabfirst</td>
<td>Перейти на первую вкладку</td>
</tr>
<tr>
<td>:tablast</td>
<td>Перейти на последнюю вкладку</td>
</tr>
<tr>
<td>:tabm n(position)</td>
<td>Изменить порядок вкладок</td>
</tr>
<tr>
<td>:tabdo %s/foo/bar/g</td>
<td>Выполнить команду во всех вкладках</td>
</tr>
<tr>
<td>:tab ball</td>
<td>Поместить все открытые файлы во вкладки</td>
</tr>
</table>
<h2>Разделение окна</h2>
<table border="0" cellspacing="3">
<tr>
<td>:e filename</td>
<td>Редактировать <em>filename</em> в текущем окне</td>
</tr>
<tr>
<td>:split filename</td>
<td>Разделить окно и открыть <em>filename</em></td>
</tr>
<tr>
<td>ctrl-w + стрелка ВВЕРХ</td>
<td>Переместить курсор в верхнее окно</td>
</tr>
<tr>
<td>ctrl-w ctrl-w</td>
<td>Переместить курсор в следующее окно</td>
</tr>
<tr>
<td>ctrl-w_</td>
<td>Максимизировать текущее окно</td>
</tr>
<tr>
<td>ctrl-w=</td>
<td>Подогнать окна по размеру</td>
</tr>
<tr>
<td>10 ctrl-w+</td>
<td>Увеличить текущее окно на 10 строк</td>
</tr>
<tr>
<td>:vsplit file</td>
<td>Вертикально разделить окно</td>
</tr>
<tr>
<td>:sview file</td>
<td>Разделить окно и открыть <em>file</em> только для чтения</td>
</tr>
<tr>
<td>:hide</td>
<td>Закрыть текущее окно</td>
</tr>
<tr>
<td>:only</td>
<td>Закрыть все окна, кроме текущего</td>
</tr>
<tr>
<td>:b 2</td>
<td>Открыть #2  в текущем окне</td>
</tr>
</table>
<h2>Автодополнение</h2>
<table border="0" cellspacing="3">
<tr>
<td>Ctrl+n Ctrl+p (в режиме вставки)</td>
<td>Дополнить слово</td>
</tr>
<tr>
<td>Ctrl+x Ctrl+l</td>
<td>Дополнить строку</td>
</tr>
<tr>
<td>:set dictionary=dict</td>
<td>Установить словарь</td>
</tr>
<tr>
<td>Ctrl+x Ctrl+k</td>
<td>Дополнение из словаря</td>
</tr>
</table>
<h2>Метки</h2>
<table border="0" cellspacing="3">
<tr>
<td>mk</td>
<td>Пометить текущую позиция как k</td>
</tr>
<tr>
<td>‘k</td>
<td>Перейти к метке k</td>
</tr>
<tr>
<td>d’k</td>
<td>Удалить все до метки k</td>
</tr>
</table>
<h2>Сокращения</h2>
<table border="0" cellspacing="3">
<tr>
<td>:ab mail mail@provider.org</td>
<td>Определить <em>mail</em> как сокращение от <em>mail@provider.org</em></td>
</tr>
</table>
<h2>Отступы</h2>
<table border="0" cellspacing="3">
<tr>
<td>:set autoindent</td>
<td>Включить автоматическую расстановку отступов</td>
</tr>
<tr>
<td>:set smartindent</td>
<td>Включить &#8220;умную&#8221; расстановку отступов</td>
</tr>
<tr>
<td>:set shiftwidth=4</td>
<td>Установить отступ равный 4 пробелам</td>
</tr>
<tr>
<td>ctrl-t, ctrl-d</td>
<td>Убрать/добавить отступ в режиме вставки</td>
</tr>
<tr>
<td>&lt;&lt;</td>
<td>Добавить отступ</td>
</tr>
<tr>
<td>&gt;&gt;</td>
<td>Убрать отступ</td>
</tr>
</table>
<h2>Подсветка синтаксиса</h2>
<table border="0" cellspacing="3">
<tr>
<td>:syntax on</td>
<td>Включить подсветку</td>
</tr>
<tr>
<td>:syntax off</td>
<td>Выключить подсветку</td>
</tr>
<tr>
<td>:set syntax=perl</td>
<td>Установить режим подсветки</td>
</tr>
</table>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/84/feed</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Логирование писем, отосланных через функцию mail()</title>
		<link>http://boombick.org/blog/posts/77</link>
		<comments>http://boombick.org/blog/posts/77#comments</comments>
		<pubDate>Fri, 31 Jul 2009 11:20:22 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/77</guid>
		<description><![CDATA[Если у вас свой сервер (или хостинг-сервер), на котором расположено множество различных проектов, то, возможно, вы сталкивались со следующей проблемой: из-за уязвимости в скрипте на один из проектов попал вредоносный код, занимающийся рассылкой спама. Найти виновника порой бывает весьма проблематично. Так что оптимальным выходом будет просто логировать действия функции mail() Все крайне просто Создайте файл [...]]]></description>
			<content:encoded><![CDATA[<p>Если у вас свой сервер (или хостинг-сервер), на котором расположено множество различных проектов, то, возможно, вы сталкивались со следующей проблемой: из-за уязвимости в скрипте на один из проектов попал вредоносный код, занимающийся рассылкой спама. Найти виновника порой бывает весьма проблематично. Так что оптимальным выходом будет просто логировать действия функции mail()<br />
<span id="more-77"></span><br />
Все крайне просто<br />
Создайте файл <code>/usr/local/bin/phpsendmail</code> и поместите в него следующий код:</p>
<blockquote>
<pre>
#!/usr/bin/php
&lt;?php
/**
  This script is a sendmail wrapper for php to log calls of the php mail() function.
  Author: Till Brehm, www.ispconfig.org
*/

$sendmail_bin = '/usr/sbin/sendmail';
$logfile = '/var/log/mail.form';

//* Get the email content
$logline = '';
while ($line = fgets(STDIN)) {
	if(stristr($line,'to:') || stristr($line,'from:')) $logline .= trim($line).' ';
	$mail .= $line;
}

//* compose the sendmail command
$command = 'echo "'.$mail.'" | '.$sendmail_bin.' ';
for ($i = 1; $i &lt; $_SERVER['argc']; $i++) {
	$command .= $_SERVER['argv'][$i].' ';
}

//* rotate log if it gets too big
if(is_file($logfile) &amp;&amp; filesize($logfile) &gt; 10000000) {
	if(is_file($logfile.'.old')) unlink($logfile.'.old');
	exec('cp -pf '.$logfile.' '.$logfile.'.old');
	exec('cat /dev/null &gt; '.$logfile);
}

//* Write the log
system('echo "'.date("Y-m-d H:i:s").' '.$_ENV['PWD'].' '.$logline.'" &gt;&gt; '.$logfile);

//* Execute the command
return shell_exec($command);
?&gt;</pre>
</blockquote>
<p>Это логгер всех сообщений с ротированием лог-файла.<br />
Не забудьте указать верный путь к <code>sendmail</code> в переменной <code>$sendmail_bin</code></p>
<p>Затем сделайте скрипт исполняемым</p>
<blockquote><p> chmod +x /usr/local/bin/phpsendmail</p></blockquote>
<p>Создайте лог-файл, смените владельца на пользователя, от которого запускается веб-сервер и дайте ему права на запись</p>
<blockquote><p> touch /var/log/mail.form<br />
chown www-data:www-data /var/log/mail.form<br />
chmod 0700 /var/log/mail.form</p></blockquote>
<p>Приведите ваш конфигурационный файл php.ini к следующему виду (измените параметр sendmail_path)</p>
<blockquote>
<pre>
[mail function]
; For Win32 only.
;SMTP = localhost
;smtp_port = 25

; For Win32 only.
;sendmail_from = me@example.com

; For Unix only.  You may supply arguments as well (default: "sendmail -t -i").
sendmail_path = /usr/local/bin/phpsendmail</pre>
</blockquote>
<p>И перезапустите веб-сервер</p>
<blockquote><p>/etc/init.d/apache2 restart</p></blockquote>
<p>Проверить логгер можно с помощью нехитрого скрипта:</p>
<blockquote>
<pre>
&lt;?php
mail('yourname@yourdomain.com','This is a test message subject','This is a test message body');
echo 'Mail sent.';
?&gt;</pre>
</blockquote>
<p>Запустите этот сценарий через web и проверьте лог:</p>
<blockquote><p>cat /var/log/mail.form</p></blockquote>
<p><noindex><strong>Оригинал:</strong> <a href="http://howtoforge.org/how-to-log-emails-sent-with-phps-mail-function-to-detect-form-spam">http://howtoforge.org/how-to-log-emails-sent-with-phps-mail-function-to-detect-form-spam</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/77/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Собственный видеохостинг</title>
		<link>http://boombick.org/blog/posts/72</link>
		<comments>http://boombick.org/blog/posts/72#comments</comments>
		<pubDate>Thu, 21 May 2009 15:40:56 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[highload]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/72</guid>
		<description><![CDATA[Статья описывает процесс построения собственного видеохостинга (как, например, YouTube) на базе lighttpd с модулем mod_flv_streaming для трансляции потокового видео в формате .flv и модулем mod_secdownload для предотвращения хотлинкинга. В качестве проигрывателя мы возьмем FlowPlayer, который поддерживает mod_flv_streaming. Также мы опишем процесс перекодировки видео различных форматов (.mp4 .mov .mpg .3gp .mpeg .wmv .avi) в формат FLV, [...]]]></description>
			<content:encoded><![CDATA[<p>Статья описывает процесс построения собственного видеохостинга (как, например, YouTube) на базе lighttpd с модулем <em>mod_flv_streaming</em> для трансляции потокового видео в формате .flv и модулем<br />
<em>mod_secdownload</em> для предотвращения хотлинкинга. В качестве проигрывателя мы возьмем <noindex><a href="http://flowplayer.org/">FlowPlayer</a></noindex>, который поддерживает <em>mod_flv_streaming</em>. Также мы опишем процесс перекодировки видео различных форматов (.mp4 .mov .mpg .3gp .mpeg .wmv .avi) в формат FLV, который будет использоваться на нашем сайте<br />
<span id="more-72"></span><br />
<strong>Необходимые замечания</strong><br />
Перед описанием непосредственно процесса давайте определим используемые в статье некоторые параметры, которые могут отличаться от ваших (и наверняка отличаются :))<br />
Все происходит на сервере с адресом <code>server1.example.com</code> и IP-адресом <code>192.168.0.100</code>. Предполагается, что на сервере уже установлен lighttpd и php с поддержкой MySQL<br />
В Лайти также включена поддержка PHP. В качестве операционной системы мы используем Debian Etch<br />
Итак, приступим</p>
<p><strong>Устанавливаем LAME</strong><br />
<noindex><a href="http://lame.sourceforge.net/">LAME</a></noindex> &#8211; это mp3-декодер. Он необходим нам для того, чтобы в наших сконвертированных видеофайлах сохранялась аудиодорожка. В репозитриях Etch LAME отсутствует, поэтому мы будем собирать его вручную.<br />
Установим необходимые пакеты:</p>
<blockquote><p> apt-get install build-essential</p></blockquote>
<p>Затем скачаем и скомпилируем LAME</p>
<blockquote>
<pre>
cd /tmp
wget http://mesh.dl.sourceforge.net/sourceforge/lame/lame-3.97.tar.gz
tar xvfz lame-3.97.tar.gz
cd lame-3.97
./configure --enable-shared --prefix=/usr
make
make install</pre>
</blockquote>
<p><strong>Устанавливаем ffmpeg</strong><br />
Для перекодирования видео мы будем использовать <code>ffmpeg</code>. Установим его и плагины к нему</p>
<blockquote><p> apt-get install ffmpeg libavcodec0d libavformat0d libavifile-0.7c2 libpostproc0d libasound2-plugins avifile-player avifile-utils avifile-mad-plugin avifile-mjpeg-plugin avifile-vorbis-plugin</p></blockquote>
<p>Проблема LAME в Debian заключается в том, что он не поддерживает кодирование mp3 из-за патентных ограничений, а значит наше видео превратится в &#8220;немое кино&#8221;. Чтож, немного поправим пакет</p>
<blockquote><p> cd /usr/src/<br />
apt-get source ffmpeg<br />
cd ffmpeg-0.cvs20060823</p></blockquote>
<p>Отредактируем файл <code>debain/rules</code>. В начале файла есть две строки <code>confflags</code> с опциями сборки. Добавим в одну из них <code>--enable-mp3lame</code> и сохраним файл</p>
<blockquote>
<pre>
[...]
confflags += --enable-gpl --enable-pp --enable-pthreads --enable-mp3lame
confflags += --enable-vorbis --enable-libogg --enable-a52 --enable-dts --enable-libgsm
[...]</pre>
</blockquote>
<p>Соберем пакет</p>
<blockquote><p> dpkg-buildpackage</p></blockquote>
<p><code>dpkg-buildpackage</code>, скорее всего, будет &#8220;ругаться&#8221; на отсутствующие пакеты, которые нужны ему для сборки <code>ffmpeg</code></p>
<blockquote>
<pre>
server1:/usr/src/ffmpeg-0.cvs20060823# dpkg-buildpackage
dpkg-buildpackage: source package is ffmpeg
dpkg-buildpackage: source version is 0.cvs20060823-8
dpkg-buildpackage: source changed by Sam Hocevar (Debian packages) <sam+deb@zoy.org>
dpkg-buildpackage: host architecture i386
dpkg-buildpackage: source version without epoch 0.cvs20060823-8
dpkg-checkbuilddeps: Unmet build dependencies: debhelper (&gt;= 4.0) quilt libogg-dev libvorbis-dev liba52-dev libdts-dev zlib1g-dev libsdl1.2-dev libfreetype6-dev libimlib2-dev texi2html libraw1394-dev libdc1394-13-dev libtheora-dev (&gt;&gt; 0.0.0.alpha4) libgsm1-dev
dpkg-buildpackage: Build dependencies/conflicts unsatisfied; aborting.
dpkg-buildpackage: (Use -d flag to override.)
server1:/usr/src/ffmpeg-0.cvs20060823#
</sam+deb@zoy.org></pre>
</blockquote>
<p>Если вы видите что-то подобное, то просто доставьте недостающие пакеты</p>
<blockquote><p> apt-get install debhelper quilt libogg-dev libvorbis-dev liba52-dev libdts-dev zlib1g-dev libsdl1.2-dev libfreetype6-dev libimlib2-dev texi2html libraw1394-dev libdc1394-13-dev libtheora-dev libgsm1-dev</p></blockquote>
<p>и запустите <code>dpkg-buildpackage</code> снова</p>
<blockquote><p> dpkg-buildpackage</p></blockquote>
<p>Процесс создания нового пакета займет некоторое время, а результатом его будут *.deb-файлы в директории <code>/usr/src</code>. Установим их командой</p>
<blockquote><p> cd ..<br />
dpkg -i *.deb</p></blockquote>
<p><strong>Устанавливаем flvtool2</strong><br />
При перекодировке видео неплохо было добавить некоторые метаданные в конечные файлы, например информацию о длительности, чтобы наш плеер смог корректно показывать счетчик времени. Для этого воспользуемся утилитой <noindex><a href="http://rubyforge.org/projects/flvtool2/">flvtool2</a></noindex>. Она написана на Ruby, поэтому сначала установим его</p>
<blockquote><p> apt-get install ruby</p></blockquote>
<p>Затем скачаем и установим flvtool2</p>
<blockquote><p> cd /tmp<br />
wget http://rubyforge.org/frs/download.php/17497/flvtool2-1.0.6.tgz<br />
tar xvfz flvtool2-1.0.6.tgz<br />
cd flvtool2-1.0.6<br />
ruby setup.rb config<br />
ruby setup.rb setup<br />
ruby setup.rb install</p></blockquote>
<p><strong>Подгототавливаем директории для видео</strong><br />
Корневой директорией для Лайти в нашем случае является <code>/var/www</code> (по умолчанию в Debian так и есть). Конечно же мы не хотим хранить оригинальные и сконвертированные видеофайлы в этой директории, иначе их смогут скачать все, кто захочет (зная прямую ссылку). Поэтому директорию с оригинальными видео (<code>/var/videos/incoming</code>) и сконвертированными (<code>/var/videos/flv</code>) мы расположим <strong>вне</strong> DocumentRoot</p>
<blockquote><p> mkdir -p /var/videos/incoming<br />
mkdir -p /var/videos/flv</p></blockquote>
<p>Вы (или ваши пользователи) смогут загружать файлы в <code>/var/videos/incoming</code> через FTP или WEB-интерфейс, а вы будете их перекодировать (вручную или автоматически) в FLV-формат и хранить в <code>/var/videos/flv</code></p>
<p><strong>Перекодирование видео</strong><br />
Предположим, что у нас есть файл <code>video.avi</code> в директории <code>/var/videos/incoming</code> (или .mp4 .mov .mpg .3gp .mpeg .wmv). Мы хотим сконвертировать его в <code>fideo.flv</code> и сохранить в <code>/var/videos/flv</code>. Разрешение конечного файла должно быть 320&#215;240, звук 44100 Hz и частота кадров 12 fps</p>
<blockquote><p> ffmpeg -i /var/videos/incoming/video.avi -s 320&#215;240 -ar 44100 -r 12 /var/videos/flv/video.flv</p></blockquote>
<p>(для дополнительной информации рекомендую обратиться к <code>man ffmpeg</code>). Это займет некоторое время, а вывод будет похож на</p>
<blockquote>
<pre>
server1:~# ffmpeg -i /var/videos/incoming/video.avi -s 320x240 -ar 44100 -r 12 /var/videos/flv/video.flv
FFmpeg version SVN-rUNKNOWN, Copyright (c) 2000-2004 Fabrice Bellard
  configuration:  --enable-gpl --enable-pp --enable-pthreads --enable-mp3lame --enable-vorbis --enable-libogg
 --enable-a52 --enable-dts --enable-libgsm --enable-dc1394 --disable-debug --enable-shared --prefix=/usr
  libavutil version: 0d.49.0.0
  libavcodec version: 0d.51.11.0
  libavformat version: 0d.50.5.0
  built on Aug 14 2007 15:02:25, gcc: 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
Input #0, avi, from '/var/videos/incoming/video.avi':
  Duration: 00:10:53.8, start: 0.000000, bitrate: 5455 kb/s
  Stream #0.0: Video: mpeg4, yuv420p, 1024x576, 24.00 fps(r)
  Stream #0.1: Audio: ac3, 48000 Hz, 5:1, 448 kb/s
Output #0, flv, to '/var/videos/flv/video.flv':
  Stream #0.0: Video: flv, yuv420p, 320x240, q=2-31, 200 kb/s, 12.00 fps(c)
  Stream #0.1: Audio: mp3, 44100 Hz, stereo, 64 kb/s
Stream mapping:
  Stream #0.0 -&gt; #0.0
  Stream #0.1 -&gt; #0.1
No accelerated IMDCT transform found
Press [q] to stop encoding
frame= 7847 q=2.0 Lsize=   21682kB time=653.8 bitrate= 271.7kbits/s
video:16061kB audio:5108kB global headers:0kB muxing overhead 2.427536%
server1:~#</pre>
</blockquote>
<p>Обратите особое внимание на секцию <code>Output</code> &#8211; там должно быть два потока: видео и аудио. Если вы видите там только видеопоток, то значит какие-то проблемы с аудиокодированием, внимательно проверьте наши инструкции по подключению LAME<br />
После кодирования добавим метаданные</p>
<blockquote><p> cat /var/videos/flv/video.flv | flvtool2 -U stdin /var/videos/flv/video.flv</p></blockquote>
<p><strong>Настройка Lighttpd</strong><br />
Теперь приступим к настройке Лайти. Откроем главный конфигурационный файл <code>/etc/lighttpd/lighttpd.conf</code>  активируем в нем модули <code>mod_secdownload</code> и <code>mod_flv_streaming</code>. Обратите внимание: крайне важно, чтобы модуль <code>mod_secdownload</code> шел <em>перед</em> модулем <code>mod_flv_streaming</code> в секции <code>server.modules</code>. В обратном случае будут проблемы с отображением видео FlowPlayer&#8217;ом</p>
<blockquote>
<pre>
[...]
server.modules              = (
            "mod_access",
            "mod_alias",
            "mod_accesslog",
            "mod_fastcgi",
#           "mod_rewrite",
#           "mod_redirect",
#           "mod_status",
#           "mod_evhost",
#           "mod_compress",
#           "mod_usertrack",
#           "mod_rrdtool",
#           "mod_webdav",
#           "mod_expire",
            "mod_secdownload",
            "mod_flv_streaming",
#           "mod_evasive"
 )
[...]</pre>
</blockquote>
<p>Также добавьте в конец конфига следующие строки</p>
<blockquote>
<pre>
[...]
flv-streaming.extensions = ( ".flv" )
secdownload.secret          = "somesecret"
secdownload.document-root   = "/var/videos/flv/"
secdownload.uri-prefix      = "/dl/"
secdownload.timeout         = 120</pre>
</blockquote>
<p>Не забудьте заменить <code>somesecret</code> на реальную парольную фразу<br />
Как работает <code>mod_secdownload</code>:<br />
На web-странице расположена ссылка примерно следующего вида:<br />
<em>&lt;uri-prefix&gt;/&lt;token&gt;/&lt;timestamp-in-hex&gt;/&lt;rel-path&gt; </em> (например: <em>/dl/d8a8cb150f7e5962f6a8443b0b6c6cc2/46c1d9f6/video.flv</em>)<br />
Где &lt;token&gt; &#8211; это md5-хэш от</p>
<ul>
<li>Секретной строки</li>
<li>&lt;rel-path&gt; (начинающегося с /)</li>
<li></li>
<li>&lt;timestamp-in-hex&gt;</li>
<p><code>mod_secdownload</code> перенаправит эту ссылку на файл, расположенный в  <code>secdownload.document-root</code> (который вне основного корня веб-сервера) и обеспечит доступ к нему в течении <code>secdownload.timeout</code> секунд. По истечении времени ссылка перестанет быть валидной и доступ будет закрыт.<br />
После установки FlowPalyer мы будем генерировать валидные сслыки для <code>mod_secdownload</code> при помощи PHP-скрипта. Дополнительную информацию по <code>mod_secdownload</code> можно получить <noindex><a href="http://trac.lighttpd.net/trac/wiki/Docs%3AModSecDownload">здесь</a></noindex><br />
Не забудьте перезапустить Лайти</p>
<blockquote><p> /etc/init.d/lighttpd restart</p></blockquote>
<p><strong>Установка FlowPlayer</strong><br />
Скачайте последнюю версию плеера с <noindex><a href="http://flowplayer.org/download">http://flowplayer.org/download</a></noindex> и приготовьте его к работе</p>
<blockquote><p> cd /tmp<br />
wget http://belnet.dl.sourceforge.net/sourceforge/flowplayer/flowplayer-1.19.zip<br />
unzip flowplayer-1.19.zip<br />
mv flowplayer /var/www/</p></blockquote>
<p><strong>Настройка FlowPlayer</strong><br />
Плеер установлен, теперь давайте создадим файл, с помощью которого можно будет посмотреть наше видео. В нашем примере это <code>/var/www/flowplayertest.php</code>, в котором расположены все параметры для запуска плеера и генерируются валидные ссылки для <code>mod_secdownload</code></p>
<blockquote>
<pre>
&lt;?php
$secret = "somesecret";
$uri_prefix = "/dl/";

# filename
$f = "/video.flv";

# current timestamp
$t = time();

$t_hex = sprintf("%08x", $t);
$m = md5($secret.$f.$t_hex);

?&gt;

&lt;object type="application/x-shockwave-flash" data="/flowplayer/FlowPlayerThermo.swf"&gt;
    width="320" height="256" id="FlowPlayer"&gt;
&lt;param name="allowScriptAccess" value="sameDomain"&gt;&lt;/param&gt;
&lt;param name="movie" value="/flowplayer/FlowPlayerThermo.swf"&gt;&lt;/param&gt;
&lt;param name="quality" value="high"&gt;&lt;/param&gt;
&lt;param name="scale" value="noScale"&gt;&lt;/param&gt;
&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;
&lt;param name="flashvars" value="config={videoFile: '&lt;?php printf('%s%s/%s%s', $uri_prefix, $m, $t_hex, $f, $f); ?&gt;', streamingServer: 'lighttpd', loop: 'false', useNativeFullScreen: true}"&gt;&lt;/param&gt;
&lt;/object&gt;</pre>
</blockquote>
<p>Не забудьте позаботиться о том, чтобы переменная <code>$secret</code> совпадала со значением, указанным в конфиге Лайти. Также должны совпадать <code>$uri_prefix</code> и <code>secdownload.uri-prefix</code>. Если все верно, то ссылки точно будут рабочими. В переменной <code>$f</code> содержится имя видеофайла, начинающееся со слеша (&#8220;/&#8221;). В нашем примере имя &#8220;жестко&#8221; зашито в код, но вы можете получать его из БД, например.<br />
В тэгах <code>&lt;object&gt;&lt;/object&gt;</code> содержатся конфигурационные параметры для FlowPlayer. Плеер может использовать разные скины (в нашем примере это <code>FlowPlayerThermo</code>), видео имеет размер 320&#215;240 и панель управления имеет высоту 16px. Пожтому мы указали ширину равной 320px и высоту (240+16) 256px. Если вы используете другой скин, поправьте эти параметры. За документацией по FlowPlayer обращайтесь на <noindex><a href="http://flowplayer.org/demos/index.html">официальный сайт</a></noindex><br />
В параметре <code>&lt;param name="flashvars"...</code> содержатся настройки окружения плеера. Важным параметром является <code>videoFile</code> &#8211; это ссылка на файл, которую генерирует наш скрипт. Другая важная опция &#8211; это <code>streamingServer: 'lighttpd'</code>, которая указывает, что для потоковой трансляции файла мы используем <code>mod_flv_streaming</code> Остальные опции (<code>loop, useNativeFullScreen</code>) являются необязательными. Например, если вы установите опцию <code>useNativeFullScreen</code> в <code>true</code> (это поддержка нативного полноэкранного режима для Flash Player 9), то вы должны включить в object строку &lt;param name=&#8221;allowFullScreen&#8221; value=&#8221;true&#8221; /&gt; и не можете использовать &lt;param name=&#8221;wmode&#8221; value=&#8221;transparent&#8221; /&gt;<br />
За дополнительными настройками FlowPlayer обратитесь к документации</p>
<p><strong>Проверим?</strong><br />
Зайдем браузером на <code>http://192.168.0.100/flowplayertest.php</code> &#8211; видео должно работать (со звуком)<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/05/2.png" title="2.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/05/2.thumbnail.png" alt="2.png" /></a><br />
И даже в полноэкранном режиме<br />
<a href="http://boombick.org/blog/wp-content/uploads/2009/05/3.png" title="3.png"><img src="http://boombick.org/blog/wp-content/uploads/2009/05/3.thumbnail.png" alt="3.png" /></a><br />
Enjoy.</p>
<p><strong>Оригинал:</strong> <noindex><a href="http://howtoforge.org/video_streaming_lighttpd_flowplayer">http://howtoforge.org/video_streaming_lighttpd_flowplayer</a></noindex></ul>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/72/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Виртуальные хосты на lighttpd с хранением конфигурации в MySQL</title>
		<link>http://boombick.org/blog/posts/49</link>
		<comments>http://boombick.org/blog/posts/49#comments</comments>
		<pubDate>Wed, 28 Jan 2009 10:29:07 +0000</pubDate>
		<dc:creator>boombick</dc:creator>
				<category><![CDATA[*NIX]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[web-servers]]></category>

		<guid isPermaLink="false">http://boombick.org/blog/posts/49</guid>
		<description><![CDATA[Статья посвящена настройке виртуальных хостов для lighttpd, работающего под управлением Debian, с хранением всех конфигурационных данных в MySQL. Главная особенность в том, что мы не будем использовать модуль для Лайти mod_mysql_vhost, который позволяет хранить в базе лишь имя хоста и его корневой раздел. Наша конфигурация более гибкая и позволяет хранить в БД все директивы для [...]]]></description>
			<content:encoded><![CDATA[<p>Статья посвящена настройке виртуальных хостов для lighttpd, работающего под управлением Debian, с хранением всех конфигурационных данных в MySQL. Главная особенность в том, что мы не будем использовать модуль для Лайти <code>mod_mysql_vhost</code>, который позволяет хранить в базе лишь имя хоста и его корневой раздел. Наша конфигурация более гибкая и позволяет хранить в БД все директивы для каждого виртуального хоста<br />
<span id="more-49"></span><br />
<b>Установка MySQL 5.0</b><br />
Устанавливаем MySQL:</p>
<blockquote><p>apt-get install mysql-server mysql-client</p></blockquote>
<p>Задаем пароль для пользователя <code>root</code> (замените <code>yourrootsqlpassword</code> на ваш пароль)</p>
<blockquote><p>mysqladmin -u root password yourrootsqlpassword</p></blockquote>
<p>Проверим, какие адреса слушает MySQL, при помощи команды</p>
<blockquote><p>netstat -tap | grep mysql</p></blockquote>
<p>Вывод должен быть примерно таким:</p>
<blockquote><pre>
tcp        0      0 localhost.localdo:mysql *:*                     LISTEN     2713/mysqld
</pre>
</blockquote>
<p>Это значит, что MySQL слушает только <code>localhost.localdomain</code> и вы установили пароль. Если  же вывод похож на:</p>
<blockquote><pre>
tcp        0      0 *:mysql *:*                     LISTEN     2713/mysqld
</pre>
</blockquote>
<p>вам необходимо также установить пароль для вашего хоста (в нашем примере это <code>server1.example.com</code>), иначе кто-угодно сможет подключиться к БД и манипулировать данными</p>
<blockquote><pre>
mysqladmin -h server1.example.com -u root password yourrootsqlpassword
</pre>
</blockquote>
<p><b>Устанавливаем Lighttpd, Python и python-mysqldb</b><br />
Мы будем использовать скрипт, написанный на Python, для чтения конфигурации из БД. Устанавливаем все необходимое:</p>
<blockquote><p>
apt-get install lighttpd python python-mysqldb
</p></blockquote>
<p><b>Подготовка базы данных</b><br />
Подключаемся к MySQL:</p>
<blockquote><p>mysql -u root -p</p></blockquote>
<p>создаем базу данных и пользователя. А также даем пользователю привилегии SELECT для запросов к нашей базе</p>
<blockquote><pre>
CREATE DATABASE lighttpd;
GRANT SELECT ON lighttpd.* TO lighttpd@localhost IDENTIFIED BY 'secret';
GRANT SELECT ON lighttpd.* TO lighttpd@localhost.localdomain IDENTIFIED BY 'secret';
FLUSH PRIVILEGES;
</pre>
</blockquote>
<p>Не забудьте заменить &#8220;<code>secret</code>&#8221; на реальный пароль<br />
Осталось создать таблицу для наших виртуальных хостов и подготовка БД на этом закончена</p>
<blockquote><pre>
USE lighttpd;
CREATE TABLE IF NOT EXISTS domains (
domain varchar(64) NOT NULL PRIMARY KEY,
docroot varchar(128) NOT NULL,
config text
);
quit;
</pre>
</blockquote>
<p><b>Сценарий для получения данных из БД</b><br />
Создаем скрипт на python, который будет читать из БД конфигурацию виртуальных хостов</p>
<blockquote><pre>
#!/usr/bin/env python
import sys
import MySQLdb

# load configuration data from the database
db=MySQLdb.connect(host='localhost', db=sys.argv[1], user=sys.argv[2], passwd=sys.argv[3])
cur = db.cursor()
cur.execute("SELECT * FROM domains")
rs=cur.fetchall()
db.close()

for domain in rs:

    print "$HTTP[\"host\"] == \"%s\" {\nserver.document-root = \"%s\"\n%s\n}" % (domain[0], domain[1], domain[2])
</pre>
</blockquote>
<p>и сохраняем его в <code>/usr/share/lighttpd/mysql_vhost.py</code><br />
Делаем скрипт исполняемым</p>
<blockquote><p>chmod 755 /usr/share/lighttpd/mysql_vhost.py</p></blockquote>
<p>Теперь надо настроить Лайти для использования нашего срипта. Для этого открываем конфиг <code>/etc/lighttpd/lighttpd.conf</code> и добавляем в конец следующую строчку</p>
<blockquote><pre>
[...]
include_shell "/usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret"
</pre>
</blockquote>
<p>(первый параметр &#8211; это имя БД, второй &#8211; имя пользователя БД, третий &#8211; пароль для доступа к БД)<br />
После всех изменений перезапустим lighttpd</p>
<blockquote><p>/etc/init.d/lighttpd restart</p></blockquote>
<p><b>Настройка виртуальных хостов</b><br />
В примере мы настроим два виртуальных хоста: <code>www.example.com</code> (с корневым разделом в <code>/var/www/www.example.com/web</code>) и <code>www.example.org</code> (с корневым разделом в <code>/var/www/www.example.org/web</code>). Мы будем использовать различные параметры для каждого хоста для демонстрации возможностей :)<br />
Для <code>www.example.com</code> мы разрешим листинг директорий и создадим алиас <code>test</code>, который будет указывать на DocumentRoot. Для <code><br />
www.example.org</code> листинг директорий будет отключен.</p>
<p>Если корневые разделы еще не существуют, то создадим их:</p>
<blockquote><p>
mkdir -p /var/www/www.example.com/web<br />
mkdir -p /var/www/www.example.org/web</p></blockquote>
<p>Подключаемся к MySQL и добавим описание наших хостов</p>
<blockquote><pre>
INSERT INTO domains VALUES ('www.example.com','/var/www/www.example.com/web/','dir-listing.activate = "enable"\nalias.url = ( "/test" => "/var/www/www.example.com/web" )');
INSERT INTO domains VALUES ('www.example.org','/var/www/www.example.org/web/','dir-listing.activate = "disable"');
</pre>
</blockquote>
<p>Обратите внимание на первый запрос <code>INSERT</code>. Если вы хотите использовать более одной директивы, то поместите между ними управляющий символ &#8220;\n&#8221;<br />
Все, виртуальные хосты настроены. Для проверки корректности работы нашего скрипта, запустим его из командной строки:</p>
<blockquote><p>/usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret</p></blockquote>
<p>В выводе должна содержаться корректная информация о наших хостах:</p>
<blockquote><pre>
server1:~# /usr/share/lighttpd/mysql_vhost.py lighttpd lighttpd secret
$HTTP["host"] == "www.example.com" {
server.document-root = "/var/www/www.example.com/web/"
dir-listing.activate = "enable"
alias.url = ( "/test" => "/var/www/www.example.com/web" )
}
$HTTP["host"] == "www.example.org" {
server.document-root = "/var/www/www.example.org/web/"
dir-listing.activate = "disable"
}
server1:~#</pre>
</blockquote>
<p>В отличие от <code>mod_mysql_vhost</code>, наш способ требует перезапуска сервера</p>
<blockquote><p>/etc/init.d/lighttpd restart</p></blockquote>
<p><b>Тестируем</b><br />
Пришло время проверить, верно ли работают наши виртуальные хосты. В корневых директориях хостов нет индексных файлов<br />
<code>http://www.example.com</code> (листинг директорий включен)<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/11.png' title='11.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/11.thumbnail.png' alt='11.png' /></a></p>
<p><code>http://www.example.com/test</code> Директории <code>test</code> не существует, но мы прописали алиас для этого пути. Поэтому мы видим содержимое DocumentRoot<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/21.png' title='21.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/21.thumbnail.png' alt='21.png' /></a></p>
<p><code>http://www.example.org</code> Мы получаем ошибку 404, потому что индексного файла нет, а листинг директорий отключен<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/31.png' title='31.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/31.thumbnail.png' alt='31.png' /></a></p>
<p><code>http://www.example.org/test</code> Листинг директорий отключен, и мы не делали алиасов для этого хоста. Поэтому все та же ошибка 404<br />
<a href='http://boombick.org/blog/wp-content/uploads/2009/01/4.png' title='4.png'><img src='http://boombick.org/blog/wp-content/uploads/2009/01/4.thumbnail.png' alt='4.png' /></a></p>
<p><noindex><b>Оригинал:</b> <a href="http://howtoforge.org/creating-advanced-mysql-based-vhosts-on-lighttpd-debian-etch">http://howtoforge.org/creating-advanced-mysql-based-vhosts-on-lighttpd-debian-etch</a></noindex></p>
]]></content:encoded>
			<wfw:commentRss>http://boombick.org/blog/posts/49/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	<img style='margin:0;padding:0;border:0;' width='1px' height='1px' src="http://boombick.org/blog/wp-content/plugins/mystat/mystat.php?act=time_load&id=0&rnd=2013553202" /></channel>
</rss>

