Блог gigimon'аhttp://it4it.ru/2018-02-13T21:50:00+03:00Установка home-assistant и подключение Xiaomi датчиков2018-02-13T21:50:00+03:00gigimontag:it4it.ru,2018-02-13:2018/02/13/home-assistant-1/<p>Последние пару лет тема домашней автоматизации и internet of things (iot) стала очень популярной, из-за чего появилось куча как программных продуктов, таких как home-assistant, majordomo и т.п., так и аппаратных решений от различных производителей (xiaomi, apple с homekit, решения от мегафона, lg). Я для себя выбрал home-assistant + xiaomi для внутренних датчиков и самодельных в будущем. В этой статье установим home-assistant на linux машину, а также добавим в него отображение информации с xiaomi gateway + температурные датчики с настройкой внешнего вида дашборда</p>
<div class="section" id="id1">
<h2>0. Подготовка</h2>
<p>Для начала определим, что нам необходимо. Из аппаратного обеспечения:</p>
<ol class="arabic simple">
<li>Компьютер на linux</li>
<li><a class="reference external" href="http://www.mi.com/wangguan/?cfrom=list">Xiaomi gateway 2</a></li>
<li>Подключенные датчики темепратуры к xiaomi gateway и MiHome, у меня <a class="reference external" href="https://youpin.mi.com/detail?gid=731">такие</a></li>
</ol>
</div>
<div class="section" id="home-assistant">
<h2>1. Установка home-assistant</h2>
<p>Установить home-assistant можно разными способами:</p>
<ul class="simple">
<li>системный пакет для вашего дистрибутива</li>
<li>установка через pip</li>
<li>установка через docker. Как установить docker на ваш linux читать <a class="reference external" href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-using-the-convenience-script">тут</a></li>
</ul>
<p>Я выбрал установку через docker, т.к. это самый простой и быстрый способ установки.</p>
<p>Первое, что необходимо сделать, это создать папку на локальном диске, которая будет бэкапиться или которую вы не удалите, для того, чтобы хранить конфиги home-assistant и не потерять их, при работе с контейнером docker.</p>
<div class="highlight"><pre><span></span>mkdir /ваш/путь/homeassistant
</pre></div>
<p>Затем запускаем контейнер с последней версией home-assistant</p>
<div class="highlight"><pre><span></span><span class="n">docker</span> <span class="n">run</span> <span class="o">-</span><span class="n">d</span> <span class="o">--</span><span class="n">name</span><span class="o">=</span><span class="s2">"home-assistant"</span> <span class="o">-</span><span class="n">v</span> <span class="o">/</span><span class="err">ваш</span><span class="o">/</span><span class="err">путь</span><span class="o">/</span><span class="n">homeassistant</span><span class="o">/</span><span class="n">config</span><span class="p">:</span><span class="o">/</span><span class="n">config</span> <span class="o">-</span><span class="n">v</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">localtime</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">localtime</span><span class="p">:</span><span class="n">ro</span> <span class="o">--</span><span class="n">net</span><span class="o">=</span><span class="n">host</span> <span class="n">homeassistant</span><span class="o">/</span><span class="n">home</span><span class="o">-</span><span class="n">assistant</span>
</pre></div>
<p>Эта команда скачает образ для docker и запустит контейнер, пердав ему нашу папку с будущим конфигом (на хосте в папке /ваш/путь/), а также подключит веб интерфейс home-assistant на основной адрес сервера, на порт 8123. Чтобы проверить доступность home-assistant, необходимо в браузере зайти на адрес <strong>http://адрес_сервера:8123</strong> и увидете интерфейс home-assistant. По умолчанию home-assistant включает авто определение устройств в сети, поэтому на первой странице home-assistant вы возможно увидете какие-то устройства.</p>
</div>
<div class="section" id="xiaomi-gateway-home-assistant">
<h2>2. Добавление xiaomi gateway в home-assistant</h2>
<p>Добавление устройств (датчиков) в home-assistant проводится через редактирование конфигурационного файла. Если посмотреть в папку</p>
<div class="highlight"><pre><span></span>ls -la /ваш/путь/homeassistant/config/*.yaml
/ваш/путь/homeassistant/config/automations.yaml
/ваш/путь/homeassistant/config/configuration.yaml
/ваш/путь/homeassistant/config/customize_glob.yaml
/ваш/путь/homeassistant/config/customize.yaml
/ваш/путь/homeassistant/config/groups.yaml
/ваш/путь/homeassistant/config/scripts.yaml
/ваш/путь/homeassistant/config/secrets.yaml
</pre></div>
<p>то можно увидеть различные конфиги:</p>
<ol class="arabic simple">
<li>automations.yaml - конфигурация для скриптов автоматизации</li>
<li>configuration.yaml - главный файл, в котором подключаются все остальные</li>
<li>customize_glob.yaml - настройка внешнего вида для категорий датчиков</li>
<li>customize.yaml - настройка внешнего вида отдельных датчиков</li>
<li>groups.yaml - настройка зон (комнат)</li>
<li>scripts.yaml - скрипты</li>
<li>secrets.yaml - файл для хранения секретных данных (паролей)</li>
</ol>
<p>Для упрощения, добавим наш датчик в основной конфигурационный файл configuration.yaml, в конец файла</p>
<div class="highlight"><pre><span></span>xiaomi_aqara:
discovery_retry: 5
gateways:
- key: <your_key>
</pre></div>
<p>Где вместо <your_key> необходимо добавить ваш отключ доступа к шлюзу. Взять его можно через MiHome:
1. В MiHome нажать на шлюз
2. Затем … и выбрать пункт About
3. Нажать на версию (подержать), которая снизу, появится 2 дополнительных пункта
4. Нажать на пункт “local area network communication protocol” и в открывшемся окне необходимр включить “local area network communication protocol” и сохранить поле “password”, это и будет ключ, который надо вставить в конфиг</p>
<p>Затем, надо перезагрузить home-assistant, чтобы он прочитал новый конфиг, сделать это можно либо через docker (docker stop container_id && docker start container_id), либо через меню home-assistant Settings -> Common -> Restart</p>
</div>
[Перевод] Поиск утечек памяти в тестах с py.test2017-01-06T01:20:00+03:00gigimontag:it4it.ru,2017-01-06:2017/01/06/pytest-memory/<p><em>Данная заметка это перевод статьи <a href="https://nvbn.github.io/2017/02/02/pytest-leaking/">https://nvbn.github.io/2017/02/02/pytest-leaking/</a> посвященной поиску утечек памяти в тестах.</em></p>
<p>На одном из наших проектов у нас была проблема с утечкой памяти в тестах, проблема была очень велика, т.к. каждый раз какой-то из тестов утекал на несколько Гб. Мы пробовали <a href="pytest-leaks">https://github.com/abalkin/pytest-leaks</a>, но он оказался избыточен и не работал с нашей версией python. Поэтому мы написали свой небольшой детектор утечек.</p>
<p>В первую очередь мы получаем используемую <span class="caps">RAM</span> с помощью <a href="https://github.com/giampaolo/psutil">psutil</a>:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">psutil</span> <span class="kn">import</span> <span class="n">Process</span>
<span class="n">_proc</span> <span class="o">=</span> <span class="n">Process</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">get_consumed_ram</span><span class="p">():</span>
<span class="k">return</span> <span class="n">_proc</span><span class="o">.</span><span class="n">memory_info</span><span class="p">()</span><span class="o">.</span><span class="n">rss</span>
</pre></div>
<p>Затем мы создали лог использования <span class="caps">RAM</span> памяти, где <em>nodeid</em> это специальная репрезентация теста в pytest, например <em>tests/test_service.py::TestRemoteService::test_connection</em>:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">namedtuple</span>
<span class="n">START</span> <span class="o">=</span> <span class="s1">'START'</span>
<span class="n">END</span> <span class="o">=</span> <span class="s1">'END'</span>
<span class="n">ConsumedRamLogEntry</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span><span class="s1">'ConsumedRamLogEntry'</span><span class="p">,</span> <span class="p">(</span><span class="s1">'nodeid'</span><span class="p">,</span> <span class="s1">'on'</span><span class="p">,</span> <span class="s1">'consumed_ram'</span><span class="p">))</span>
<span class="n">consumed_ram_log</span> <span class="o">=</span> <span class="p">[]</span>
</pre></div>
<p>И логгируем использование памяти с помощью pytest хуков, просто добавив код в <em>conftest.py</em>:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">pytest_runtest_setup</span><span class="p">(</span><span class="n">item</span><span class="p">):</span>
<span class="n">log_entry</span> <span class="o">=</span> <span class="n">ConsumedRamLogEntry</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">nodeid</span><span class="p">,</span> <span class="n">START</span><span class="p">,</span> <span class="n">get_consumed_ram</span><span class="p">())</span>
<span class="n">consumed_ram_log</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">log_entry</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">pytest_runtest_teardown</span><span class="p">(</span><span class="n">item</span><span class="p">):</span>
<span class="n">log_entry</span> <span class="o">=</span> <span class="n">ConsumedRamLogEntry</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">nodeid</span><span class="p">,</span> <span class="n">END</span><span class="p">,</span> <span class="n">get_consumed_ram</span><span class="p">())</span>
<span class="n">consumed_ram_log</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">log_entry</span><span class="p">)</span>
</pre></div>
<p>Pytest вызывает <em>pytest_runtest_setup</em> до запуска каждого теста, а <em>pytest_runtest_teardown</em> после.</p>
<p>И после всех тестов мы выводим всю информацию об утечках в тестах превышающих допустимую границу (10Мб в нашем случае) через <em>pytest_terminal_summary</em> хук:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">itertools</span> <span class="kn">import</span> <span class="n">groupby</span>
<span class="n">LEAK_LIMIT</span> <span class="o">=</span> <span class="mi">10</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span>
<span class="k">def</span> <span class="nf">pytest_terminal_summary</span><span class="p">(</span><span class="n">terminalreporter</span><span class="p">):</span>
<span class="n">grouped</span> <span class="o">=</span> <span class="n">groupby</span><span class="p">(</span><span class="n">consumed_ram_log</span><span class="p">,</span> <span class="k">lambda</span> <span class="n">entry</span><span class="p">:</span> <span class="n">entry</span><span class="o">.</span><span class="n">nodeid</span><span class="p">)</span>
<span class="k">for</span> <span class="n">nodeid</span><span class="p">,</span> <span class="p">(</span><span class="n">start_entry</span><span class="p">,</span> <span class="n">end_entry</span><span class="p">)</span> <span class="ow">in</span> <span class="n">grouped</span><span class="p">:</span>
<span class="n">leaked</span> <span class="o">=</span> <span class="n">end_entry</span><span class="o">.</span><span class="n">consumed_ram</span> <span class="o">-</span> <span class="n">start_entry</span><span class="o">.</span><span class="n">consumed_ram</span>
<span class="k">if</span> <span class="n">leaked</span> <span class="o">></span> <span class="n">LEAK_LIMIT</span><span class="p">:</span>
<span class="n">terminalreporter</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'LEAKED {}MB in {}</span><span class="se">\n</span><span class="s1">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="n">leaked</span> <span class="o">/</span> <span class="mi">1024</span> <span class="o">/</span> <span class="mi">1024</span><span class="p">,</span> <span class="n">nodeid</span><span class="p">))</span>
</pre></div>
<p>И после запуска всех тестов, получаем список текучих тестов:</p>
<div class="highlight"><pre><span></span>LEAKED 712MB in tests/test_service.py::TestRemoteService::test_connection
</pre></div>Немного про py.test2016-02-11T00:16:00+03:00gigimontag:it4it.ru,2016-02-11:2016/02/11/pytest-1/<p>Последнее время я все чаще работаю с популярной библиотекой для тестирования - <a href="http://pytest.org/latest/">py.test</a>. В компании, где я работаю, мы полностью перешли на ее использование в написании, как unit тестов, так и интеграционных.</p>
<h2>Чем “крут” py.test?</h2>
<p>Из главных фишек py.test можно выделить следующие:</p>
<ol>
<li>Раскрытие asssert’ов - при выводе ошибки, он красиво показывает, что и с чем мы сравнили, выводит типы и доходчиво это выводит, пряча весь traceback, который привел к assert’у, а также пытаясь самостоятельно вывести уточняющий текст.</li>
<li>Система фикстур - специальные функции, которые неявно передаются в тестируемую функцию. Является очень мощным инструментом, т.к. позволяет делать глобальные/локальные setup/teardown вещи, легко переносимые между тестами.</li>
<li>Система плагинов построеная на хуках, с помощью которой очень просто писать дополнительные плагины. В данный момент, есть плагины реализующие практически все, что угодно (от дополнительных assert’ов и выводилок на экран, до мощных инструментов, таких как bdd, coverage и т.п.)</li>
<li>Возможность распределенного запуска тестов в автоматическом режиме и на разных машинах</li>
</ol>
<h3>Раскрытие assert’ов</h3>
<p>Возьмем для примера самый простой случай:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">test_simple</span><span class="p">():</span>
<span class="n">one</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">one_str</span> <span class="o">=</span> <span class="s1">'1'</span>
<span class="k">assert</span> <span class="n">one_str</span> <span class="o">==</span> <span class="n">one</span>
</pre></div>
<p>И выполним сначала nosetests:</p>
<div class="highlight"><pre><span></span>nosetests test.py
<span class="nv">F</span>
<span class="o">======================================================================</span>
FAIL: test.test_simple
----------------------------------------------------------------------
Traceback <span class="o">(</span>most recent call last<span class="o">)</span>:
File <span class="s2">"/Users/gigimon/workspace/python/scalr3/lib/python3.4/site-packages/nose/case.py"</span>, line 198, in runTest
self.test<span class="o">(</span>*self.arg<span class="o">)</span>
File <span class="s2">"/Users/gigimon/workspace/python/scalr3/test.py"</span>, line 4, in test_simple
assert <span class="nv">one_str</span> <span class="o">==</span> one
AssertionError
----------------------------------------------------------------------
Ran <span class="m">1</span> <span class="nb">test</span> in 0.002s
FAILED <span class="o">(</span><span class="nv">failures</span><span class="o">=</span>1<span class="o">)</span>
</pre></div>
<p>И видим стандартный traceback, где абсолютно не понятно, что с чем сравнилось и, что пошло не так. Теперь же py.test:</p>
<div class="highlight"><pre><span></span>py.test test.py
<span class="o">====================</span>
<span class="nb">test</span> session <span class="nv">starts</span>
<span class="o">====================</span>
collected <span class="m">1</span> items
test.py <span class="nv">F</span>
<span class="o">=====</span> <span class="nv">FAILURES</span> <span class="o">=====</span>
___ test_simple ___
def test_simple<span class="o">()</span>:
<span class="nv">one</span> <span class="o">=</span> 1
<span class="nv">one_str</span> <span class="o">=</span> <span class="s1">'1'</span>
> assert <span class="nv">one_str</span> <span class="o">==</span> one
E assert <span class="s1">'1'</span> <span class="o">==</span> 1
test.py:4: <span class="nv">AssertionError</span>
<span class="o">=====</span> <span class="m">1</span> failed
</pre></div>
<p>И тут мы сразу видим наш исходный код теста, конкретную строку, где упал тест, а также сравниваемые величины в понятном виде.</p>
<h3>Система фикстур</h3>
<p>Фикстуры - это функции, которые обернуты в декоратор @pytest.fixture и делающие setUp перед запуском теста, где их используют и teardown после выполнения теста. Также, их можно использовать и в самом тесте, если они что-либо возвращают. Помимо этого они могут выполняться в разном контексте исполнения: для каждой функции, для каждого модуля, для всей сессии тестирования, это значит, что если использовать в каждом тесте фикстуру, которая исполняется только на уровне сессии, то в каждую тест-функцию будет приходить 1 и тот же объект.</p>
<p>Рассмотрим пример из официальной документации, где фикстура подключается к smtp серверу и завершает коннект после каждого теста:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">smtplib</span>
<span class="kn">import</span> <span class="nn">pytest</span>
<span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s2">"module"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">smtp</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">smtp</span> <span class="o">=</span> <span class="n">smtplib</span><span class="o">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s2">"smtp.gmail.com"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">fin</span><span class="p">():</span>
<span class="n">smtp</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">request</span><span class="o">.</span><span class="n">addfinalizer</span><span class="p">(</span><span class="n">fin</span><span class="p">)</span>
<span class="k">return</span> <span class="n">smtp</span>
<span class="k">def</span> <span class="nf">test_ehlo</span><span class="p">(</span><span class="n">smtp</span><span class="p">):</span>
<span class="n">response</span><span class="p">,</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">smtp</span><span class="o">.</span><span class="n">ehlo</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">response</span> <span class="o">==</span> <span class="mi">250</span>
<span class="k">assert</span> <span class="n">b</span><span class="s2">"smtp.gmail.com"</span> <span class="ow">in</span> <span class="n">msg</span>
<span class="k">def</span> <span class="nf">test_noop</span><span class="p">(</span><span class="n">smtp</span><span class="p">):</span>
<span class="n">response</span><span class="p">,</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">smtp</span><span class="o">.</span><span class="n">noop</span><span class="p">()</span>
<span class="k">assert</span> <span class="n">response</span> <span class="o">==</span> <span class="mi">250</span>
</pre></div>
<p>Здесь фикстура делает следующее:</p>
<ol>
<li>Открывает smtp соединение</li>
<li>Отдает объект smtp</li>
<li>Хранит состояние возвращаемого объекта</li>
<li>В конце теста аккуратно закрывает соединение</li>
</ol>
<p>А в самом тесте, нам остается только указать в параметрах функции, какие фикстуры мы используем и py.test сам вызовет функцию с ней. Если внимательно посмотрите, то увидите, что наша функция smtp тоже принимает на вход параметр, который также, является системной фикстурой py.test. </p>
<p>Думаю, следует пояснить пункт №3. Т.к. фикстура объявлена со scope=”module”, то эта функция вызывается лишь 1 раз при импорте каждого модуля с тестами и каждая тест кейс внутри 1 модуля получает один и тот же объект smtp. А при завершении запуска тест-кейсов данного модуля, выполнится finalize функция smtp.close()</p>
<p>Механизм фикстур для новичков является большой магией, т.к. позволяет как сделать множетсов интересных вещей, так и нажить еще больше проблем с поиском причин багов.</p>
<h3>Плагины</h3>
<p>Плагинов для py.test написано уже множество, если судить по pip list, то их 227 на любой случай жизни. </p>
<p>Расширять py.test можно как с помощью отдельно написаных плагинов (таких как pytest-bdd, pytest-sugar), так и с помощью хуков, которые расположены непосредственно в ваших тестах.</p>
<p>В первом случае, py.test использует механизм setuptools entrypoint для поиска своих установленных плагинов и их загрузки</p>
<p>Во втором случае, он сканирует все дерево исходных кодов на предмет обнаружения hook-функций, которые вызываются на самые разнообразные действия движка начиная от инициализации (работа с передаными параметрами коммандной строки) и заканчивая выводом отчета и завершения теста.</p>
<p>Весь список хуков и их параметров можно посмотреть в исходных кодах, либо официальной <a href="http://pytest.org/latest/writing_plugins.html#pytest-hook-reference">документации</a>.</p>
<p>Например, рассмотрим простой хук, который перед запуском тестов проверяет, есть ли в директории теста fabfile.py и при его нахождении запускает fab prepare, для подготовки окружения к тестам:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">pytest_pycollect_makemodule</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">parent</span><span class="p">):</span>
<span class="n">fab_path</span> <span class="o">=</span> <span class="n">LocalPath</span><span class="p">(</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">)</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s1">'fabfile.py'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">fab_path</span><span class="o">.</span><span class="n">isfile</span><span class="p">():</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">check_call</span><span class="p">([</span><span class="s1">'/usr/local/bin/fab'</span><span class="p">,</span>
<span class="s1">'-f'</span><span class="p">,</span> <span class="n">fab_path</span><span class="o">.</span><span class="n">strpath</span><span class="p">,</span> <span class="s1">'prepare'</span><span class="p">],</span>
<span class="n">stdout</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">subprocess</span><span class="o">.</span><span class="n">STDOUT</span><span class="p">)</span>
</pre></div>
<h3>Распределенный запуск тестов</h3>
<p>py.test из коробки расчитан на запуск тестов распределенно, как многопоточно на данной машине, так и в разных процессах/интерпретаторах на других машинах, с помощью библиотеки execnet. Для запуска тестов распредленно свего лишь надо указать настройки через коммандную строку, например самый простой случай, в несколько потоков:</p>
<div class="highlight"><pre><span></span>py.test -n <span class="m">4</span> tests/
</pre></div>
<p>где n - количество потоков.
py.test автоматически создаст 4 потока, распределит тесты по ним, соберет статистику и результаты, а по завершению выдаст отчет, как будто запускали в 1 поток. Точно также он работает и при запуске тестов через ssh на других серверах:</p>
<div class="highlight"><pre><span></span>py.test --tx <span class="nv">ssh</span><span class="o">=</span>myhost//python<span class="o">=</span>python2.5 --tx <span class="nv">ssh</span><span class="o">=</span>myhost//python<span class="o">=</span>python2.6 tests/
</pre></div>
<p>Для первой статьи, думаю достаточно, в будущем постараюсь лучше раскрыть тему фикстур, а также плагинов.</p>Рекомендуемая структура Django проекта2014-12-03T16:43:00+03:00gigimontag:it4it.ru,2014-12-03:2014/12/03/django-recommended-layout/<p>Это перевод недавней статьи <a class="reference external" href="http://www.revsys.com/blog/2014/nov/21/recommended-django-project-layout/">Recommended Django Project Layout</a> от Франка Вильса (Frank Wiles) от 21 ноября 2014г.</p>
<div class="section" id="id1">
<h2>Какая оптимальная структура для ваших Django приложений, настроек и других ассоциированных директорий?</h2>
<p>Когда вышла Django 1.4 она включала обновленую структуру проекта, которая прошла долгий путь, чтобы стать основной, но здесь, собраны некоторые улучшения, чтобы сделать структуру лучше.</p>
<p>Подобный вопрос нам задают постоянно, поэтому я хочу потратить немного времени и рассказать все наше отношение к этому, чтобы всех клиентов можно было отправлять к этому документу. Эта заметка написана для Django 1.7.1, но может быть легко применена для всех Django версий выше 1.4.</p>
</div>
<div class="section" id="id2">
<h2>Почему данная структура лучше</h2>
<p>Рекомендуемая нами структура проекта имеет несколько преимуществ, таких как:</p>
<ol class="arabic simple">
<li>Позволяет вам держать, пересобирать и переисопльзовать индивидальные Django приложения для использования в других проектах. Ведь не всегда создаваемое приложение делается реиспользуемым, но в будущем, может вырасти в такое. Построение проекта описываемым способом, позволяет писать реиспользуемые приложения сразу же, а не только, когда потребуется.</li>
<li>Поощряет разработку реиспользуемых приложений</li>
<li>Индивидуальных настройки для каждого окружения. Никаких больше “if <span class="caps">DEBUG</span>==True” в едином монолитном файле настроек. Это позволяет легко видеть, какие настройки общие и что переопределяется на каждом окружении.</li>
<li>Индивидульный список pip зависимостей для каждого окружения.</li>
<li>Шаблоны проекта и статические файлы, если требуется, могут переопределять значения по умолчанию уровня приложений.</li>
<li>Небольшие более детальные тестовые файлы, которые легче для чтения и понимания.</li>
</ol>
<p>Предположим, у вас есть 2 приложения <em>blog</em> и <em>users</em> и 2 окружения <em>dev</em> и <em>prod</em>, значит, ваш проект должен иметь следующий вид:</p>
<div class="highlight"><pre><span></span>myproject/
manage.py
myproject/
__init__.py
urls.py
wsgi.py
settings/
__init__.py
base.py
dev.py
prod.py
blog/
__init__.py
models.py
managers.py
views.py
urls.py
templates/
blog/
base.html
list.html
detail.html
static/
…
tests/
__init__.py
test_models.py
test_managers.py
test_views.py
users/
__init__.py
models.py
views.py
urls.py
templates/
users/
base.html
list.html
detail.html
static/
…
tests/
__init__.py
test_models.py
test_views.py
static/
css/
…
js/
…
templates/
base.html
index.html
requirements/
base.txt
dev.txt
test.txt
prod.txt
</pre></div>
<p>Продолжение этой статьи расскажет, как привести свой проект к такой структуре и почему она лучше.</p>
</div>
<div class="section" id="id3">
<h2>Текущая структура по умолчанию</h2>
<p>Мы начнем с создания нового проекта с именем <strong>foo</strong>, да, я знаю, что это очень креативное название. Мы предполагаем здесь, что дальше проект будет расположен на домене <strong>foo.com</strong>, но почему название проекта должно точно повторять домен, ведь проект всеравно будет жить и без всяких подобных требований.</p>
<p>Если вы запустите свой проект с помощью команды <strong>django-admin.py startproject foo</strong>, вы получите следующую структуру:</p>
<div class="highlight"><pre><span></span>foo/
manage.py
foo/
__init__.py
settings.py
urls.py
wsgi.py
</pre></div>
<p>Эта схема очень хороша для старта. У нас есть корневая директория <em>foo</em>, которая содержит наш <em>manage.py</em> и директорию проекта <em>foo/foo</em>. Эту директорию можно добавить в свою систему контроля версия, например в git.</p>
<p>Вы можете подумать, что директория <em>foo/foo</em> начало проекта, где все кроме этого это Django приложения или вспомогательные файлы относящиеся к проекту.</p>
</div>
<div class="section" id="id4">
<h2>Исправляем настройки</h2>
<p>Наша первая миссия, это исправить ваш плохой файл настроек. Мы показали данную архитектуру нашим клиентам и были впечатлены, как мало людей знают, что такое можно реализовать. Я виню в этом тот факт, что каждый знает, что файл настроек это просто Python код, но они не думают о нем, как о Python коде.</p>
<p>И так, давайте исправим наши настройки. Для нашего проекта <em>foo</em> реализуем схему с 4 окружениями: dev, stage, jenkins, и production. Давайте дадим каждому окружения свой собственный файл. Процесс для этого следующий:</p>
<ol class="arabic simple">
<li>В <em>foo/foo</em> создадим директорию <em>settings</em> и пустой файл <em>__init__.py</em> внутри нее.</li>
<li>Перенесем <em>foo/foo/settings.py</em> в <em>foo/foo/settings/base.py</em></li>
<li>Создадим индивидуальные файлы <em>dev.py</em>, <em>stage.py</em>, <em>jenkins.py</em>, и <em>production.py</em> в <em>foo/foo/settings/</em>. Каждый из этих файлов должен содержать следующее</li>
</ol>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">base</span> <span class="kn">import</span> <span class="o">*</span>
</pre></div>
<p>Так, почему это важно? Для локальной разработки вам требуется <strong><span class="caps">DEBUG</span>=True</strong>, но вы также, можете случайно выкатить это и в продакшен, поэтому просто откройте <em>foo/foo/settings/production.py</em> и после первой строки импорта вставьте <strong><span class="caps">DEBUG</span>=False</strong>. Теперь, ваш продакшен сайт защищен от такой случайности.</p>
<p>Что еще вы можете настроить? Достаточно очевидно, что для каждого окружения вы захотите иметь различные базы данных, например на разных хостах. Для этого, просто внесите эти настройки в соответствубщие файлы настроек.</p>
</div>
<div class="section" id="id5">
<h2>Использование этих настроек</h2>
<p>Использование этих настроект очень легкое и не зависит от того, какой метод вы предпочитаете. Для использования настроек определенного окружения, вы должны всего лишь:</p>
<div class="highlight"><pre><span></span><span class="nb">export</span> <span class="nv">DJANGO_SETTINGS_MODULE</span><span class="o">=</span>“foo.settings.jenkins”
</pre></div>
<p>И бум, вы теперь используете <em>jenkins</em> настройки.</p>
<p>Или вы можете предпочесть передачу настроек через коммандную строку:</p>
<div class="highlight"><pre><span></span>./manage.py migrate —settings<span class="o">=</span>foo.settings.production
</pre></div>
<p>Или используя gunicorn:</p>
<div class="highlight"><pre><span></span>gunicorn -w <span class="m">4</span> -b 127.0.0.1:8001 —settings<span class="o">=</span>foo.settings.dev
</pre></div>
</div>
<div class="section" id="id6">
<h2>Что еще должно быть настроено?</h2>
<p>Другая часто используемая уловка с Django настройками, это изменить тип некоторых настроек с tuple на list. Для примера, INSTALLED_APPS изменить с:</p>
<div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">(</span>
<span class="err">…</span>
<span class="p">)</span>
</pre></div>
<p>на:</p>
<div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">[</span>
<span class="err">…</span>
<span class="p">]</span>
</pre></div>
<p>В <em>foo/settings/base.py</em> мы теперь можем проще добавлять и удалять приложения основываясь на конкретном файле настроек для текущего окружения. Для примера, возможно вам требуется модуль <em>django-debug-toolbar</em> установленным только в <em>dev</em> окружении.</p>
<p>Этот трюк также часто используется с настройками <strong>TEMPLATE_DIRS</strong> и <strong>MIDDLEWARE_CLASSES</strong>.</p>
<p>Еще один часто используемый трюк, это разбить ваши приложения на 2 списка, первый это глобальные зависимости, второй - специфичные для данного проекта. Как, например, здесь:</p>
<div class="highlight"><pre><span></span><span class="n">PREREQ_APPS</span> <span class="o">=</span> <span class="p">[</span>
<span class="err">‘</span><span class="n">django</span><span class="o">.</span><span class="n">contrib</span><span class="o">.</span><span class="n">auth</span><span class="err">’</span><span class="p">,</span>
<span class="err">‘</span><span class="n">django</span><span class="o">.</span><span class="n">contrib</span><span class="o">.</span><span class="n">contenttypes</span><span class="err">’</span><span class="p">,</span>
<span class="err">…</span>
<span class="err">‘</span><span class="n">debug_toolbar</span><span class="err">’</span><span class="p">,</span>
<span class="err">‘</span><span class="n">imagekit</span><span class="err">’</span><span class="p">,</span>
<span class="err">‘</span><span class="n">haystack</span><span class="err">’</span><span class="p">,</span>
<span class="p">]</span>
<span class="n">PROJECT_APPS</span> <span class="o">=</span> <span class="p">[</span>
<span class="err">‘</span><span class="n">homepage</span><span class="err">’</span><span class="p">,</span>
<span class="err">‘</span><span class="n">users</span><span class="err">’</span><span class="p">,</span>
<span class="err">‘</span><span class="n">blog</span><span class="err">’</span><span class="p">,</span>
<span class="p">]</span>
<span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="n">PREREQ_APPS</span> <span class="o">+</span> <span class="n">PROJECT_APPS</span>
</pre></div>
<p>Почему это часто используется? Во первых, это помогает лучше различать Django core компоненты, сторонние приложения и внутренние, специфичные для данного проекта. Тем не менее, <strong>PROJECT_APPS</strong> часто управляет списком специфичных пакетов, для вещей таких как: тестирование и покрытие кода тестами. Вы имеет список с <em>вашими</em> приложениями, поэтому можете легко и автоматизированно убедиться, что все тесты были запущены только для них, а не для каких-то посторонних модулей.</p>
</div>
<div class="section" id="id7">
<h2>Исправляем зависимости</h2>
<p>Большинство проектов содержат лишь один файл <em>requirements.txt</em>, который ставит зависимости примерно так:</p>
<div class="highlight"><pre><span></span>pip install -r requirements.txt
</pre></div>
<p>Этого достаточно для маленьких проектов, но малоизвестная возможность <em>requirements</em> файлов это использование ключа <strong>-f</strong> для включения других файлов:</p>
<div class="highlight"><pre><span></span>-r base.txt
<span class="nv">pytest</span><span class="o">==</span>2.5.2
<span class="nv">coverage</span><span class="o">==</span>3.7.1
</pre></div>
<p>Я признаю, что это не огромная выгода, но это позволяет разделить зависимости на каждое окружение. Но для успокоения совести скажу, что это позволяет увеличить скорость установки пакетов, ведь вам не требуется стаивть на продакшен инсталяции пакеты, которые не будут использоваться.</p>
</div>
<div class="section" id="id8">
<h2>Тестовые файлы</h2>
<p>Почему мы разделяем тесты так сильно? Главная причина, если вы пишете достаточное количество тестов в одном файле <em>tests.py</em> для каждого приложения, то в конце концов он станет огромным и не поддерживаемым. Это плохо для читабельности, но также это простой факт, что вы тратите много времени на пролистывание текста.</p>
<p>В итоге, вы уменьшите количество мердж конфликтов при работе в команде, что является положительной чертой. Маленькие файлы - ваши друзья.</p>
</div>
<div class="section" id="urls">
<h2>Ссылки (URLs)</h2>
<p>Для маленьких проектов заманчиво определять все ссылки в одном файле <em>foo/urls.py</em> для сохранения их в одном месте. Как бы то ни было, если ваша цель это ясность и реиспользование, вы должны определять ссылки в каждом приложении и загружать их в корневом файле. Вместо:</p>
<div class="highlight"><pre><span></span><span class="n">urlpatterns</span> <span class="o">=</span> <span class="n">patterns</span><span class="p">(</span><span class="err">‘’</span><span class="p">,</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="err">$’</span><span class="p">,</span> <span class="n">HomePageView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">home</span><span class="err">’</span><span class="p">),</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">blog</span><span class="o">/</span><span class="err">$’</span><span class="p">,</span> <span class="n">BlogList</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">blog_list</span><span class="err">’</span><span class="p">),</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">blog</span><span class="o">/</span><span class="p">(</span><span class="err">?</span><span class="n">P</span><span class="o"><</span><span class="n">pk</span><span class="o">></span>\<span class="n">d</span><span class="o">+</span><span class="p">)</span><span class="o">/</span><span class="err">$’</span><span class="p">,</span> <span class="n">BlogDetail</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">blog_detail</span><span class="err">’</span><span class="p">),</span>
<span class="err">…</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">user</span><span class="o">/</span><span class="nb">list</span><span class="o">/</span><span class="err">$’</span><span class="p">,</span> <span class="n">UserList</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">user_list</span><span class="err">’</span><span class="p">),</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">user</span><span class="o">/</span><span class="p">(</span><span class="err">?</span><span class="n">P</span><span class="o"><</span><span class="n">username</span><span class="o">></span>\<span class="n">w</span><span class="o">+</span><span class="p">)</span><span class="o">/</span><span class="err">$’</span><span class="p">,</span> <span class="n">UserDetail</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">user_detail</span><span class="err">’</span><span class="p">),</span>
<span class="p">)</span>
</pre></div>
<p>вы должны использовать:</p>
<div class="highlight"><pre><span></span><span class="n">urlpatterns</span> <span class="o">=</span> <span class="n">patterns</span><span class="p">(</span><span class="err">‘’</span><span class="p">,</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="err">$’</span><span class="p">,</span> <span class="n">HomePageView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="err">‘</span><span class="n">home</span><span class="err">’</span><span class="p">),</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">blog</span><span class="o">/</span><span class="err">‘</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="err">‘</span><span class="n">blog</span><span class="o">.</span><span class="n">urls</span><span class="err">’</span><span class="p">)),</span>
<span class="n">url</span><span class="p">(</span><span class="n">r</span><span class="err">’</span><span class="o">^</span><span class="n">user</span><span class="o">/</span><span class="err">‘</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="err">‘</span><span class="n">user</span><span class="o">.</span><span class="n">urls</span><span class="err">’</span><span class="p">)),</span>
<span class="p">)</span>
</pre></div>
</div>
<div class="section" id="id9">
<h2>Шаблоны и статические файлы</h2>
<p>Использование <em>templates/</em> и <em>static/</em> директорий на каждое приложение дает способность к реиспользованию этого приложения в другом проекте как есть, без изменений.</p>
<p>В этом случае, приложение предоставляет шаблоны по умолчанию, а также различные вспомогательные файлы, такие как специальные Javascript файлы и поставляется все это в одном пакете.</p>
<p>Также, это дает нам возможность переопределить шаблоны на каждый проект базируясь на директории <em>foo/templates/</em>. При добавлении шаблона <em>templates/blog/detail.html</em> мы перезаписываем или скрываем шаблон по умолчанию <em>blog/templates/blog/detail.html</em>.</p>
</div>
<div class="section" id="id10">
<h2>Переиспользование Django приложений</h2>
<p>Допустим, вы используете предлагаемую структуру проекта некоторое время, однажды, вы поймете, что ваш новый проект нуждается в блоге и один из ваших проектов прекрасно к этому подходит. Вы скопируете файлы в … НЕ ПРАВИЛЬНО! Теперь вы имеете две копии приложения. Исправления ошибок или новые функции в одном, будут вручную переноситься между проектами если предположить, что вы всегда помните про это.</p>
<p>Вместо этого, сделайте новый репозиторий для вашего блога и вставьте в него директорию <em>foo/blog/</em>. И настройте, чтобы ваш существующий проект <em>foo</em> и новый проект, для установки блога через pip.</p>
<p>Они смогут использовать различные версии приложения, если это важно, или использовать всегда последнюю версию для получения всех исправлений и новых функций, как и разработчик. Вы все еще можете переопределять шаблоны и статические файлы в каждом проекте отдельно.</p>
</div>
<div class="section" id="id11">
<h2>Дополнительные ресурсы</h2>
<p>Наши друзья Дэнни и Аудрей из <a class="reference external" href="http://www.cartwheelweb.com/">CartWheel Web</a> напомнили нам про <a class="reference external" href="https://github.com/audreyr/cookiecutter">Cookie Cutter</a> и специальный <a class="reference external" href="https://github.com/pydanny/cookiecutter-django">cookiecutter-django</a> от Дэнни, мощная утилита для создания начального проекта, быстро и повторяемо.</p>
<p>Кроме того, если вы ищете все про Django уловки и рекомендации, вы не можете пройти мимо книги <a class="reference external" href="http://www.amazon.com/gp/product/098146730X/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=098146730X&linkCode=as2&tag=revosystblog-20">Two Scoops of Django: Best Practices For Django 1.6</a> которую мы рекомендуем всем нашим клиентам.</p>
</div>
<div class="section" id="id12">
<h2>Обратная связь</h2>
<p>Мы надеемся, вы нашли данное улучшение архитектуры проекта полезным. Если вы нашли какой-то баг или имеет предложение иил просто хотите пообщаться, пишите нам. Спасибо за прочтение.</p>
</div>
Простой сервер для ловли GitHub webhooks на BaseHTTPServer2014-08-08T15:17:00+04:00admintag:it4it.ru,2014-08-08:2014/08/08/base-github-hooker/<p>Пришлось недавно освоить Github webhooks, чтобы автоматически обновлять на продакшене код, после пуша в мастер :)
Итак, те кто незнает, что это, прочитайте - <a class="reference external" href="https://developer.github.com/webhooks/">Github Webhooks</a> либо в двух словах.
При получении каждого коммита, гитхаб может отправить <span class="caps">POST</span> запрос с данными об этом коммите по указаной вами ссылке.</p>
<p>Для того, чтобы настроить такие уведомления, у репозитория в Settings->Webhooks надо добавить свой <span class="caps">URL</span>.</p>
<p>Собственно, погуглив интернетик я не нашел чего-то простого для получения таких хуков и обработки их.
Либо же это было на Flask/Django, либо не на Python, из-за чего пришлось написать быстренько самому на Python.</p>
<div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">functools</span>
<span class="kn">import</span> <span class="nn">BaseHTTPServer</span>
<span class="n">BASE_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">UPDATE_REPO_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">realpath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">BASE_PATH</span><span class="p">,</span> <span class="s1">'test_repo'</span><span class="p">))</span>
<span class="n">HOST_NAME</span> <span class="o">=</span> <span class="s1">'0.0.0.0'</span>
<span class="n">PORT_NUMBER</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span> <span class="k">else</span> <span class="mi">8000</span>
<span class="k">def</span> <span class="nf">update_repo</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">path</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">chdir</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
<span class="k">if</span> <span class="n">payload</span><span class="p">[</span><span class="s1">'ref'</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'refs/heads/master'</span><span class="p">:</span>
<span class="n">out</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">check_output</span><span class="p">([</span><span class="s1">'git'</span><span class="p">,</span> <span class="s1">'pull'</span><span class="p">,</span> <span class="s1">'origin'</span><span class="p">,</span> <span class="s1">'master'</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">print</span> <span class="s1">'Skip update because push not to master: </span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">payload</span><span class="p">[</span><span class="s1">'ref'</span><span class="p">]</span>
<span class="n">REPO_HANDLERS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">'Username/test_repo'</span><span class="p">:</span> <span class="n">functools</span><span class="o">.</span><span class="n">partial</span><span class="p">(</span><span class="n">update_repo</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="n">UPDATE_REPO_PATH</span><span class="p">),</span>
<span class="p">}</span>
<span class="k">class</span> <span class="nc">HookHandler</span><span class="p">(</span><span class="n">BaseHTTPServer</span><span class="o">.</span><span class="n">BaseHTTPRequestHandler</span><span class="p">):</span>
<span class="n">server_version</span> <span class="o">=</span> <span class="s2">"GitHubWebHookHandler/0.1"</span>
<span class="k">def</span> <span class="nf">do_GET</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="n">s</span><span class="o">.</span><span class="n">send_response</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
<span class="n">s</span><span class="o">.</span><span class="n">wfile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s1">'WAT!?'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">do_POST</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="n">length</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">headers</span><span class="p">[</span><span class="s1">'Content-Length'</span><span class="p">])</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">rfile</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="n">length</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">'utf-8'</span><span class="p">)</span>
<span class="n">post_data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">repository</span> <span class="o">=</span> <span class="n">post_data</span><span class="p">[</span><span class="s1">'repository'</span><span class="p">][</span><span class="s1">'full_name'</span><span class="p">]</span>
<span class="n">meth</span> <span class="o">=</span> <span class="n">REPO_HANDLERS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">repository</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
<span class="k">if</span> <span class="n">meth</span><span class="p">:</span>
<span class="n">meth</span><span class="p">(</span><span class="n">post_data</span><span class="p">)</span>
<span class="n">s</span><span class="o">.</span><span class="n">send_response</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
<span class="n">server_class</span> <span class="o">=</span> <span class="n">BaseHTTPServer</span><span class="o">.</span><span class="n">HTTPServer</span>
<span class="n">httpd</span> <span class="o">=</span> <span class="n">server_class</span><span class="p">((</span><span class="n">HOST_NAME</span><span class="p">,</span> <span class="n">PORT_NUMBER</span><span class="p">),</span> <span class="n">HookHandler</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">httpd</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
<span class="k">pass</span>
<span class="n">httpd</span><span class="o">.</span><span class="n">server_close</span><span class="p">()</span>
</pre></div>
<p>Итак, данный код делает следующее:</p>
<ol class="arabic simple">
<li>Висит либо на 8000 порту, либо который укажете и слушает <span class="caps">POST</span> запросы</li>
<li>Если получил <span class="caps">POST</span> запрос, то достает из него полное имя репозитория</li>
<li>Затем проверяет, может ли он такое имя обработать (проверяя REPO_HANDLERS) и если да, то вызывает ту функцию</li>
<li>А функция, всего лишь заходит в указаную папку и делает git pull origin master и все.</li>
</ol>
<p>У меня такая система обновляет 3 репозитория. Надеюсь, кому-нибудь пригодится</p>
Неделя #2: Небольшой прогресс и концепт “мультиаккаунта”2014-07-24T19:22:00+04:00gigimontag:it4it.ru,2014-07-24:2014/07/24/homefinance-2/<div class="section" id="id2">
<h2>Прогресс</h2>
<p>К сожалению, за больше чем месяц, ничего крутого не сделал, на дворе лето, программировать очень лениво :)
За это время я на Django сделал:</p>
<ul class="simple">
<li>добавление используемых валют, а также их курсов (либо использование автообновляемого раз в сутки)</li>
<li>создание/удаление счетов (пока выбрать тип можно, но плюшек никаких нет)</li>
<li>отображение счетов на главной с разбиением по валютам, какие есть у счета, показ суммы счета в выбраной валюте по умолчанию</li>
<li>отображение последних 30 транзакций по всем счетам, а если счет выбран, то для этого счета</li>
<li>расход/доход/перевод денег по счетам, в том числе в разной валюте и при переводе автоматическая конвертация (пока без каких-либо проверок на минус и другой логики)</li>
</ul>
</div>
<div class="section" id="id3">
<h2>Мультиаккаунтность</h2>
<p>Хочу сделать 2 режима мультиаккаунта:</p>
<ol class="arabic simple">
<li>Расшаривание определенных счетов между любым количеством аккаунтов</li>
<li>Саб-аккаунт - когда у подключаемого пользователя нету своих счетов, категорий, валют, а видит только те, которые имеются у “главного”</li>
</ol>
<p>В целом процедура расшаривания будет такой, в настройках пользователя пункт “Добавить пользователя”, где список всех подключенных пользователей и форма добавления нового (только e-mail и тип аккаунта), а после добавления можно выбрать, под которым показывать в истории.
Пользователю, которого вы пригласили, отправяется e-mail со ссылкой, при переходе на которую описывается все, что произойдет (если выбран второй тип подключения) и кнопки “Согласен”/”Не согласен”.</p>
<p>В настройках счетов будет пункт “Расшарить счет” и выбор на кого расшарить с правами “Только чтение”/”Полный доступ”.
При “Только чтение” подключенный человек будет только видеть суммы на счете и движение средств по нему, при полном же доступе, сможет добавлять “расход” и “доход”, а “переводы” можно делать как на обоюдно расшареный счет, так и на тот, который никто не видит (тогда в истории будет показываться “Личный” и имя)</p>
<p>Примерно такую систему прав и планирую, было бы хорошо выслушать “за” и “против”</p>
</div>
Неделя #1: Мой проектик бухгалтерии2014-06-05T19:22:00+04:00gigimontag:it4it.ru,2014-06-05:2014/06/05/homefinance-1/<p>Примерно год назад, когда мы с женой решили начать вести запиши о круговоре наших денег в природе, встал вопрос о выборе сервиса для этого. Посидев и погуглив, были найдены 3-5 сервиса для ведения домашней бухгалтерии и все опробованы. Какие сервисы пробовал. не буду говорить, но все они, не пришлись по вкусу совершенно, а по функциям, так темболее.</p>
<p>Проблемы которые мне встретились, были такие:</p>
<ol class="arabic simple">
<li>Интерфейс - половина из найденых сайтов была ужасна на вид и совершенно не интуитивно понятна, куда же тыкать.</li>
<li>Цена - считаю, что платить больше 2-3 долларов в месяц за такой сервис это идиотизм. Ведь он заменяет только блокнотик. Цена колеблется у таких сервисов как раз от 2-3$ в месяц и до 15$, хотя функционал везде примерно одинаковый.</li>
<li>Функционал - ни в одном сервисе я не нашел общих счетов (чтобы создать себе и жене аккаунт и вести один счет, видя, кто и сколько и на что потратил). Помимо этого, мало у кого есть нормальное приложение под телефоны, что тоже огорчает.</li>
</ol>
<p>В итоге я остановился на сервисе <a class="reference external" href="http://homemoney.com.ua">http://homemoney.com.ua</a> по следующим причинам:</p>
<ul class="simple">
<li>он дешевый</li>
<li>имеет хоть какое-то приложение на телефоны (правда очень посредственное и страшное)</li>
<li>минимально-достаточный функционал</li>
</ul>
<p>Но, к сожалению, в нем много багов, он тормозит и, похоже, разработчики положили на него болт.</p>
<p>И спустя >6 месяцев, мне надоело и я решил начать писать свой потихоньку, а про его написание каждую неделю писать пост в бложике :)</p>
<div class="section" id="id2">
<h2>Каким я его планирую сделать</h2>
<p>Итогом всей работы я буду считать проект у которого будут реализованы следующие функции:</p>
<ol class="arabic simple">
<li>Работа с общими счетами из нескольких аккаунтов</li>
<li>Продвинутая настройка счетов, связаная с банковскими услугами. Такими как, автоматический учет процент по кредитам/депозитам, лимиты, различные оповещение об изменении статусов счетов и т.п.</li>
<li>Интеграция с популярными клиент-банками и выписками из банков</li>
<li>Различные инструменты для анализа своих доходов/расходов (цели, графики)</li>
<li>Приложения под ios, android, windows phone с чтением расходов из смс (и возможно распознаванием чеков)</li>
<li>Кучу мелких удобств и дополнительных фишек (пока точно не придумал каких :)</li>
</ol>
</div>
<div class="section" id="id3">
<h2>Как планирую делать</h2>
<p>На данный момент написано очень мало: модуль регистрации/авторизации и зачатки главного - биллинга.
Разрабатывать конечный продукт собираюсь в три этапа:</p>
<ol class="arabic simple">
<li>Разработать прототип с основными функциями (пункты 1, 2) без особого удобства интерфейса, для проверки концепций моего кода (большие проекты не писал)</li>
<li>Доработка уже до публичной альфа/бета версии и написание приложений под ios/android с попутным добавлением фич (пункт 3, 4)</li>
<li>Возможно изменение дизайна, исправление багов, дописывание функционала, а также добавление удобства его использования за счет применения реактивных интерфейсов и т.п. новомодных фишек</li>
</ol>
<p>Разрабатываю его на Django, для <span class="caps">CSS</span> - SemanticUI, а для реактивности буду использовать либо angular.js, либо react.js (пока не решил и не смотрел)</p>
<p>Вот, собственно и основное описание проектика, на следующей неделе постараюсь написать побольше о написании кода.</p>
</div>
Полезная утилита для разработчиков - honcho2014-04-18T00:04:00+04:00gigimontag:it4it.ru,2014-04-18:2014/04/18/useful-honcho/<p>Бороздя просторы интернета, наткнулся на клевую штуковину от heroku - <a class="reference external" href="https://devcenter.heroku.com/articles/procfile">Procfile</a>
Это небольшая идеология (наверно), заключающаяся в быстром запуске каких-либо процессов используя специальный файл с именем Procfile, в котором описываются в формате “название команды: команда” команды для запуска процессов. Обычно это требуется для быстрого деплоя либо запуска чего-то постоянно. Я это использую при разработке и запуске dev окружения (поднятия вагранта, запуск базы, запуск воркеров), чтобы запустить сразу кучу процессов и разом их по Ctrl-C убить.</p>
<p>Для работы с этими Procfile существует целая куча программ написаных на разных языках, но обычно полностью совместимые между собой, как по командному интерфейсу, так и по выводу, можно отметить следующие:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/ddollar/foreman">Foreman</a> на Ruby</li>
<li><a class="reference external" href="https://github.com/nickstenning/honcho">Honcho</a> на православном Python</li>
<li><a class="reference external" href="https://github.com/hecticjeff/shoreman">Shoreman</a> на shell</li>
<li><a class="reference external" href="https://github.com/josh/norman">Norman</a> node.js имплементация О_о</li>
<li><a class="reference external" href="https://github.com/ddollar/forego">Forego</a> на модном Go</li>
</ul>
<p>Я же использую python реализацию - honcho.</p>
<p>Устанавливается он очень просто:</p>
<div class="highlight"><pre><span></span>pip install honcho
</pre></div>
<p>Все, после этого в системе доступен как honcho.</p>
<p>Затем, в любой директории где находимся создаем Procfile и наполняем его согласно своей нужде, для примера мой:</p>
<div class="highlight"><pre><span></span>celery: vagrant ssh -c <span class="s2">"cd /vagrant && celery worker -n worker.base -A workers -l DEBUG"</span>
meteor: bash -c <span class="s2">"cd front && exec meteor"</span>
</pre></div>
<p>Теперь, находясь в директории с этим Procfile мы можем запускать либо сразу все процессы, либо какой-то отдельный, используя следующие команды соответственно:</p>
<div class="highlight"><pre><span></span>honcho run
honcho start meteor
</pre></div>
<p>После этого, будет запущен honcho, который запустит эти процессы и красиво выведет их stdout:</p>
<div class="highlight"><pre><span></span>$ honcho start meteor
16:03:40 meteor.1 <span class="p">|</span> started with pid 89989
16:03:40 meteor.1 <span class="p">|</span> <span class="o">[[[[[</span> ~/workspace/python/src/meteor/front <span class="o">]]]]]</span>
16:03:40 meteor.1 <span class="p">|</span> <span class="o">=</span>> Started proxy.
<span class="o">=</span>> Started your app. Starting your app...
</pre></div>
<p>А если нажать Ctrl-C, то всем пошлется <span class="caps">SIGINT</span> и все должны будут завершиться.</p>
<p>Помимо этого, можно задать единые переменные окружения для всех процессов, для этого надо в этой же папке создать .env файл, куда перечислить все свои переменные окружения.</p>
<p>В целом, очень полезная утилита для разработчиков и хорошо показавшая себя в автоматизации ежедневной рутины</p>
Решение проблемы с русскими буквами в url django+nginx2014-02-19T16:41:00+02:00gigimontag:it4it.ru,2014-02-19:2014/02/19/django-russian-slug/<p>Недавно переезжал на новый сервер и переносил один старый Django проект (на 1.2 еще) с cherokee+uwsgi на nginx+fscgi (скорость не нужна)
Но была у этого проекта одна особенность, у него были местами русские буквы в ссылках. На cherokee все работало замечательно,
на nginx сайт тоже запустился без проблем (хвала vierualenv), но при тыкании сайта, все ссылки с русским не работали,
падали в 404, что не подходят ни по одному паттерну.</p>
<p>Пошел копать и дебажить, для этого добавил в джанго проект мелкую middleware, которая логировала request.path.
Через пару запросов увидел, что на debug сервере и на cherokee, в request.path приходят русские буквы не экранированные ничем
и не заквоченые (unquote, незнаю как по русски) (типа /goods/all/салфетки), а с nginx они вида /goods/all/%D0%91%D0%B5%D0%<span class="caps">BB</span>%D0%B8%D0%B7%D0%<span class="caps">BD</span>%D0%B0.</p>
<p>Для решения проблемы, оказалось надо поменять 1 fastcgi параметр в nginx:</p>
<div class="highlight"><pre><span></span>fastcgi_param REQUEST_URI <span class="nv">$request_uri</span><span class="p">;</span>
</pre></div>
<p>заменить на</p>
<div class="highlight"><pre><span></span>fastcgi_param REQUEST_URI <span class="nv">$uri</span><span class="p">;</span>
</pre></div>
<p>И все стало работать как надо. Потратил на дебаг минут 40 :(</p>
Прочитанные книги за последние 5-6 лет2014-02-09T00:31:00+02:00gigimontag:it4it.ru,2014-02-09:2014/02/09/my-books/<p>Недавно задумался о том, что нигде не записываю книги, которые прочитал,
из-за чего часто попадал на одни и теже названия и тратил время, чтобы осознать
читал я это или нет, да и сервисов удобных для этого лень искать, а те что знаю - ужасны.
Вот поэтому и решил записать в бложек (а заодно может кому и интересно будет) то, что
прочитал за последние лет 5-6, но это, к сожалению не весь список, т.к. многое не помню ни автора,
ни названия, но помню сюжет :)</p>
<ul>
<li><p class="first"><strong>Энн МакКефри</strong> - “Всадники Перна”, замечательный цикл больших книг со своим хорошо проработанным миром рассказывающий о драконах и их борьбе с напастью.</p>
</li>
<li><p class="first"><strong>Оксана Панкеева</strong> - “Хроники странного королевства”, русский фэнтези на 12 книг, с отличным юмором и сюжетом, который закручиваться начинает на первой книги, а на последней раскручивается :)</p>
</li>
<li><p class="first"><strong>Джером Сэлинджер</strong> - “Над пропастью во ржи”, думаю это не нуждается в представлении - мне понравилось.</p>
</li>
<li><p class="first"><strong>Айзек Азимов</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Основание” (Академия у некоторых), фантастика про спасение человечества от гибели с помощью математики</li>
<li><span class="dquo">“</span>И тьма пришла” - хороший постапокалипстический рассказ.</li>
</ul>
<p>Помимо этого у Азимова я прочитал кучу рассказов, по которым писали сюжет “Я, робот”, все отличные.</p>
</blockquote>
</li>
<li><p class="first"><strong>Роберт Хайнлайн</strong> - очень люблю его, как писателя, практически подряд и быстро прочитал пяток его книжек.</p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Пасынки вселенной” - о деградации человечества на огромном космическом корабле</li>
<li><span class="dquo">“</span>Дверь в лето” супер книга о путешествиях во времени, любви и котиках :)</li>
<li><span class="dquo">“</span>Человек, который продал луну” - о стремлении к своей мечте</li>
<li><span class="dquo">“</span>Дети Мафусаила” - о зависти обычных людей к долгожителям</li>
<li><span class="dquo">“</span>Взрыв всегда возможен” - небольшой рассказ о бренности бытия</li>
<li><span class="dquo">“</span>Имею скафандр, готов путешествовать” - немного о жизни, немного морали, путешествий и инопланетян</li>
<li><span class="dquo">“</span>Чужак, в чужой стране” - люди отправили на Марс эспедицию, но она пропала, через 30 лет отправили вторую и она вернулась с
человеческим ребенком, которого воспитывали марсиане и у него появились всякие возможности. Хорошая, легко читаемая книга</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Джон Уиндэм</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>День триффидов” - люди вывели растение, которое может передвигаться и стрелять в людей, но его держат под контролем, пока в один миг, на небе не пролетела комета и все кто на нее смотрел ослепли.</li>
<li><span class="dquo">“</span>Куколки” - N лет после атомной войны, люди стали сильно верующими и уничтожают всех, кто хоть немного отличается от нормы, вот про таких отличающихся и идет речь</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Саймон Кларк</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Ночь триффидов” - продолжение “День триффидов”, но слабее в пару раз.</li>
<li><span class="dquo">“</span>Кровавая купель” - в один миг, все взрослые стали убивать всех детей до 20 лет, вот дети и стали пытаться выжить. Отлично рассказано про социум</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Рэй Брэдберри</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Марсианские хроники” о событиях на планете тех времен, когда писалась книга, через призму придуманых рассказов связаных с марсом и обнаружеными там марсианами. Мне книга не очень понравилась, читая тяжело, нескладно.</li>
<li><span class="dquo">“</span>451 градус по Фаренгейту” - ну это классика, про сжигание всех культурных ценностей и подскаживание людей на “ТВ”</li>
<li><span class="dquo">“</span>Вино из одуванчиков” - взнляд на жизнь в небольшом городке глазами мальчика, заставляет задуматься о простых вещах, которые мы видим каждый день</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Оруэлл</strong> - “1984” классическая антиутопия про тоталитаризм. Как по мне, то читается очень тяжело, занудно и достаточно
очевидные вещи описаны</p>
</li>
<li><p class="first"><strong>Стерлинг Ланье</strong> - “Путешествие Иеро” - серия из нескольких книг (вроде 3), рассказывающая об изменившейся жизни
после ядерной войны, примерно через тысячу лет. Увлекательное чтиво, с элементами небольшо фэнтези о борьбе добра со злом</p>
</li>
<li><p class="first"><strong>Братья Стругацкие</strong> - к сожалению мало прочитал их творчества, хочу в будущем нагнать</p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Пикник на обочине” - “отец” всего сталкерного</li>
<li><span class="dquo">“</span>Понедельник начинается в субботу” - рассказы о жизни и работе НИИ колдовства и магии, веселая книжка.</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Сергей Тармашев</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Древний” - серия книг (около 8 книг кажется), повествующая о приключениях крутого спецназовца начиная с нашего времени и начала ядерной войны и заканчивая пятью тысячами лет вперед в космосе, в борьбе с космическим пожирателем материи. Можно почитать, т.к. написано достаточно неплохо с неплохим сюжетом, но чересчур банально.</li>
<li><span class="dquo">“</span>Наследие” - о плохом конце, если не остановимся и не перестанем использовать ГМО</li>
<li><span class="dquo">“</span>Ареал” - одна из вариаций на тему сталкерства, но причиной стало крушение инопланетного корабля.</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Кир Булычев</strong> - “Последняя война” - добрая книга о спасении жителей другой планеты после их ядерной войны</p>
</li>
<li><p class="first"><strong>Беркем аль Атоми</strong> - “Мародер” о жизни 1 человека после “продажи” чиновниками России всему миру и его попытках выжить. Такой себе постапокалипсис, но с большим количеством нецензурщины, слабым сюжетом и появлением мистики во второй книге.</p>
</li>
<li><p class="first"><strong>Дмитрий Глуховский</strong></p>
<blockquote>
<ul class="simple">
<li><span class="dquo">“</span>Метро 2033”, “Метро 2034” думаю не нуждаюстя в представлении, люди выживают в московском метро через 25 лет после войны</li>
<li><span class="dquo">“</span>Будущее” новая книга автора, которая пытается заставить задуматься о цене жизни, детях и отношениях к родителям.</li>
</ul>
</blockquote>
</li>
<li><p class="first"><strong>Роберт МакКаммон</strong> - “Песня Свон” постапокалипсис с миссией в стиле Стивена Кинга, добротное чтиво</p>
</li>
<li><p class="first"><strong>Стивен Кинг</strong> - “Противостояние” в мире бушует свирепая болезнь, 98% населения умерли, остальные разделились на 2 лагеря: одни примкнули к добру, другие ко злу (демону)</p>
</li>
<li><p class="first"><strong>Джон Скальци</strong> - “В бой идут одни старики” люди вышли в космос и основали колонию, которая ничего не говорит Земле о космосе, но забирает людей, которым наступило 80 лет в армию, создавая для них новые тела для войны с другими расами за планеты. Очень понравились все три книги цикла.</p>
</li>
<li><p class="first"><strong>Дивов</strong> - “Закон фронтира” люди стали терять память на месяц, два, потом она восстанавливалась и они смотрели, что натворили
за это время. Небольшая книжка с неплохим сюжетом</p>
</li>
<li><p class="first"><strong>Цормудян Сурен</strong> - “Второго шанса не будет” также, атомная война, попытки выжить, но тут приходят космонавты и говорят, что надо
отключить американскую погодную установку <span class="caps">HAARP</span>, иначе погода никогда не восстановится. И вот, группа из 5 человек двинулась из России в Америку.</p>
</li>
<li><p class="first"><strong>Дэвид Брин</strong> - “Почтальон” уже практически классическая постаполапстическая книга о том, как человек сам того не желая,
возродил почтовое сообщение и помог стране восстановиться после войны.</p>
</li>
<li><p class="first"><strong>Кормак МакКарти</strong> - “Дорога” очень тяжелая книга при этом очень легко читается о выживании отца с сыном во время ядерной зимы</p>
</li>
<li><p class="first"><strong>Андрей Круз</strong> - “Эпоха мертвых”, “Я еду домой” две серии книжек про зомби, хорошо продуманой реакцией общества на зомби,
неплохо написано, но чересчур много описаний оружия, а также ровность сюжета без каких либо взлетом или падений.
Второй цикл, “Я еду домой”, практчиески повторяет первый, только главный герой с Америки пытается вернуться домой.</p>
</li>
<li><p class="first"><strong>Владимир Вольный</strong> - “На развалинах мира” что-то произошло и огромное землетрясение уничтожило все и вся, но один человек спасся,
нашел жилье и стал жить, вдруг нашел малолетнюю бабу и пошло поехало. Затем нашел группу таких же выживших, врагов и в конце всех победил. Не советую читать, чушь редкостная, к тому же с большим количеством пошлятины</p>
</li>
<li><p class="first"><strong>Алексей Доронин</strong> - “Черный день” все стандартно, война, зима. Но повествование ведется сразу о нескольких людях и совсем не Чаках Норрисах. К сожалению, книга похоже недописана и не будет дописана</p>
</li>
<li><p class="first"><strong>Александр Бачило</strong> - “Помочь можно живым” небольшой рассказ о выживании после войны :)</p>
</li>
<li><p class="first"><strong>Уолтер Миллер</strong> - “Гим по Лейбовицу” об аббатстве, которое пытается сохранять знания. Очень тяжело читается и я не совсем осознал, о чем книга и для чего она была написана.</p>
</li>
<li><p class="first"><strong>Алексей Пехов</strong> - “Последний завет” через добрую тысячу лет, мир разделился на кланы выживших и одному парню из клана, надо доставить книгу в одно место и спасти свой клан. Достаточно легко читается, неплохой сюжет.</p>
</li>
<li><p class="first"><strong>Джек Лондон</strong> - “Алая чума” рассказ старика своему внуку о мире до войны.</p>
</li>
</ul>
<p>Уф, вроде немного, но находить и писать устал. В памяти кружится еще десяток книг, но, к сожалению, не помню ни авторов, ни примерных названий.</p>
Сбор статистики подкаста radio-t2014-01-26T22:12:00+02:00gigimontag:it4it.ru,2014-01-26:2014/01/26/radiot-stat/<p>Давно уже хотел отпарсить все выпуски подкаста <a class="reference external" href="http://radio-t.com">Радио-Т</a> и получить какую-нибудь статистику.
И вот, на выходных, от нечего делать решил воплотить это в жизнь.</p>
<p>Для этого был написан небольшой скриптик, который парсит <span class="caps">RSS</span> ленту, парсит оттуда информацию о подкасте
(ссылку, описание, откуда качать), скачивает кажыдй выпуск, узнаем продолжительность и ложит это все в sqlite базу.
Всего было скачано 368 подкастов (некоторые не получилось скачать) и нарисован 1 график по длительности подкаста в зависимости от года.
Весь процесс скачки в 10 потоков занял порядка 3-х часов работы скрипта.
Итак, теперь немного цифр:</p>
<ol class="arabic simple">
<li>Самый длинный подкаст - <a class="reference external" href="http://www.radio-t.com/p/2014/01/04/podcast-373/">выпуск 373</a> 186 минут!</li>
<li>Самый тяжелый - <a class="reference external" href="http://www.radio-t.com/p/2010/12/05/podcast-216/">выпуск 216</a> 112 мегабайт</li>
</ol>
<p>И вот картинка, длительность выпусков по годам</p>
<p><a class="reference external" href="http://it4it.ru/images/2014/01/radiot.jpg"><img alt="image0" src="http://it4it.ru/images/2014/01/radiot.jpg" /></a></p>
<p>Вся база, как и код качалки, выложены на <a class="reference external" href="https://github.com/gigimon/podcast-stat">гитхабе</a>, надеюсь ничьи права не ущемил, если что - удалю.</p>
Библиотека для работы с облаками libcloud2014-01-21T00:17:00+02:00admintag:it4it.ru,2014-01-21:2014/01/21/libcloud-basic/<p>Так как последние 2 года моя работа связана с новомодными облаками,
то хотелось бы рассказать про хорошую библиотеку для питона,
которая позволяет имея один интерфейс работать с облаками разных провайдеров.
Эта библиотека называется <a class="reference external" href="http://libcloud.org">libcloud</a>, поддерживает она большой список облачных провайдеров
от самых популярных <a class="reference external" href="http://aws.amazon.com/ec2/">Amazon <span class="caps">EC2</span></a> и до Ninefold (в том числе умеет новый <a class="reference external" href="http://digitalocean.com">DigitalOcean</a> и <a class="reference external" href="http://cloud.google.com/products/compute-engine"><span class="caps">GCE</span></a>).
Она дает интерфейс как к compute части облака (управление виртуальными машинами),
так и к дополнительным сервисам (S3, Load Balancer и т.д.)</p>
<div class="section" id="id1">
<h2>Установка</h2>
<p>Ставится она очень просто, как любой пакет питона.</p>
<div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">apache</span><span class="o">-</span><span class="n">libcloud</span>
<span class="n">pip</span> <span class="n">install</span> <span class="n">git</span><span class="o">+</span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">apache</span><span class="o">/</span><span class="n">libcloud</span><span class="o">.</span><span class="n">git</span>
</pre></div>
<p>Я рекомендую ставить ее из гитхаба, если не в продакшен, т.к. очень много багфиксов
коммитится прямо в мастер.</p>
</div>
<div class="section" id="id2">
<h2>Использование</h2>
<p>Для примера использования, подключимся к Amazon <span class="caps">EC2</span> и посмотрим, что оно отдаст нам:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">libcloud.compute.types</span> <span class="kn">import</span> <span class="n">Provider</span>
<span class="kn">from</span> <span class="nn">libcloud.compute.providers</span> <span class="kn">import</span> <span class="n">get_driver</span>
<span class="n">driver</span> <span class="o">=</span> <span class="n">get_driver</span><span class="p">(</span><span class="n">Provider</span><span class="o">.</span><span class="n">EC2</span><span class="p">)</span> <span class="c1">#выбрали провайдера</span>
<span class="n">conn</span> <span class="o">=</span> <span class="n">driver</span><span class="p">(</span><span class="s1">'key'</span><span class="p">,</span> <span class="s1">'secret'</span><span class="p">)</span> <span class="c1">#подключились с нашими ключами</span>
<span class="n">conn</span><span class="o">.</span><span class="n">list_sizes</span><span class="p">()</span> <span class="c1">#получили список размеров для инстансов</span>
<span class="p">[</span><span class="o"><</span><span class="n">NodeSize</span><span class="p">:</span> <span class="nb">id</span><span class="o">=</span><span class="n">t1</span><span class="o">.</span><span class="n">micro</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">Micro</span> <span class="n">Instance</span><span class="p">,</span>
<span class="n">ram</span><span class="o">=</span><span class="mi">613</span> <span class="n">disk</span><span class="o">=</span><span class="mi">15</span> <span class="n">bandwidth</span><span class="o">=</span><span class="bp">None</span> <span class="n">price</span><span class="o">=</span><span class="mf">0.02</span> <span class="n">driver</span><span class="o">=</span><span class="n">Amazon</span> <span class="n">EC2</span> <span class="o">...></span><span class="p">,</span>
<span class="o"><</span><span class="n">NodeSize</span><span class="p">:</span> <span class="nb">id</span><span class="o">=</span><span class="n">m1</span><span class="o">.</span><span class="n">small</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">Small</span> <span class="n">Instance</span><span class="p">,</span>
<span class="n">ram</span><span class="o">=</span><span class="mi">1740</span> <span class="n">disk</span><span class="o">=</span><span class="mi">160</span> <span class="n">bandwidth</span><span class="o">=</span><span class="bp">None</span> <span class="n">price</span><span class="o">=</span><span class="mf">0.065</span> <span class="n">driver</span><span class="o">=</span><span class="n">Amazon</span> <span class="n">EC2</span> <span class="o">...></span><span class="p">,</span>
<span class="o"><</span><span class="n">NodeSize</span><span class="p">:</span> <span class="nb">id</span><span class="o">=</span><span class="n">m1</span><span class="o">.</span><span class="n">medium</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">Medium</span> <span class="n">Instance</span><span class="p">,</span>
<span class="n">ram</span><span class="o">=</span><span class="mi">3700</span> <span class="n">disk</span><span class="o">=</span><span class="mi">410</span> <span class="n">bandwidth</span><span class="o">=</span><span class="bp">None</span> <span class="n">price</span><span class="o">=</span><span class="mf">0.13</span> <span class="n">driver</span><span class="o">=</span><span class="n">Amazon</span> <span class="n">EC2</span> <span class="o">...></span><span class="p">,</span>
<span class="o"><</span><span class="n">NodeSize</span><span class="p">:</span> <span class="nb">id</span><span class="o">=</span><span class="n">m1</span><span class="o">.</span><span class="n">large</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">Large</span> <span class="n">Instance</span><span class="p">,</span>
<span class="n">ram</span><span class="o">=</span><span class="mi">7680</span> <span class="n">disk</span><span class="o">=</span><span class="mi">850</span> <span class="n">bandwidth</span><span class="o">=</span><span class="bp">None</span> <span class="n">price</span><span class="o">=</span><span class="mf">0.26</span> <span class="n">driver</span><span class="o">=</span><span class="n">Amazon</span> <span class="n">EC2</span> <span class="o">...></span><span class="p">,</span>
<span class="o">...</span><span class="p">]</span>
</pre></div>
<p>Аналогично этому, мы можем смотреть список запущеных серверов, запускать/создавать инстансы,
управлять ключами, группами безопасности (security groups) и т.п.</p>
<p>На платформах, где поддерживается авторизация по ключам на серверах, можно делать так называемый deploy сервера.
Под деплоем понимается, что сервер выведется в состояние Running, дождемся <span class="caps">SSH</span> соединения и выполним указаные скрипты,
которые описываются на python.</p>
<div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">libcloud.compute.deployment</span> <span class="kn">import</span> <span class="n">ScriptDeployment</span>
<span class="kn">from</span> <span class="nn">libcloud.compute.deployment</span> <span class="kn">import</span> <span class="n">MultiStepDeployment</span>
<span class="n">script</span> <span class="o">=</span> <span class="n">ScriptDeployment</span><span class="p">(</span><span class="s2">"yum -y install emacs strace tcpdump"</span><span class="p">)</span>
<span class="n">msd</span> <span class="o">=</span> <span class="n">MultiStepDeployment</span><span class="p">([</span><span class="n">script</span><span class="p">])</span>
<span class="n">node</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">deploy_node</span><span class="p">(</span><span class="n">deploy</span><span class="o">=</span><span class="n">msd</span><span class="p">)</span>
</pre></div>
<p>В целом, данная библиотека очень хорошо подходит для поддержки многих облачных платформ, обладает понятным
и неплохо документированным <span class="caps">API</span>, а также ее авторы очень легко идут на контакт.
Чтобы сообщить о баге или что-то спросить, можно открыть тикет на гитхабе и втечение пары дней будет дан ответ.
А pull request обрабатываются почти всегда в 1 рабочий день, сам реквестил пяток новых фич/заплаток.</p>
</div>
Динамический ChoiceField в Django forms2012-08-08T21:20:00+03:00gigimontag:it4it.ru,2012-08-08:2012/08/08/dinamicheskij-choicefield-v-django-forms/<p>Достаточно часто у новичков возникает вопрос, а как сделать ChoiceField
динамическим? Существует несколько способов, зависящих от того, какие
данные вы хотите туда подставлять. Стандартными средставми форм можно
подставлять данные из других моделей (из queryset). Для этого, надо
исопльзовать ModelChoiceField и параметр queryset, для примера:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">PostForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
<span class="n">month</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">ModelChoiceField</span><span class="p">(</span><span class="n">queryset</span><span class="o">=</span><span class="n">Month</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">())</span>
</pre></div>
<p>Более подробно про такой способ описано в документации <a class="reference external" href="https://docs.djangoproject.com/en/1.4/ref/forms/fields/#django.forms.ModelChoiceField">здесь</a></p>
<p>В этой же статье, я расскажу про заполнение данными, если они берутся не
из базы, а откуда либо еще, либо если требуется какие-то фильтры.</p>
<p>Итак, для примера, у нас есть модель Post, при добавлении которой через
форму, требуется выбрать рубрику,название которых хранится в настройках
(в settings.py).</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Post</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">()</span>
<span class="n">category</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">255</span><span class="p">)</span>
</pre></div>
<p>Создадим для нее форму:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">PostForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">Post</span>
<span class="n">widgets</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'category'</span><span class="p">:</span> <span class="n">forms</span><span class="o">.</span><span class="n">CheckboxSelectMultiple</span><span class="p">,</span> <span class="p">}</span>
</pre></div>
<p>Если выведем эту форму, то увидим, что category не предоставляет
ниодного пункта выбора.</p>
<p>Для того, чтобы заполнить категории, нам требуется у формы
переопределить метод __init__ и именно в нем вставлять в поле варианты.</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">PostForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">Post</span>
<span class="n">widgets</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'category'</span><span class="p">:</span> <span class="n">forms</span><span class="o">.</span><span class="n">CheckboxSelectMultiple</span><span class="p">,</span> <span class="p">}</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="nb">super</span><span class="p">(</span><span class="n">PostForm</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="s1">'category'</span><span class="p">]</span><span class="o">.</span><span class="n">choices</span> <span class="o">=</span> <span class="p">((</span><span class="s1">'audio'</span><span class="p">,</span><span class="s1">'Audio'</span><span class="p">),(</span><span class="s1">'video'</span><span class="p">,</span><span class="s1">'Video'</span><span class="p">))</span>
</pre></div>
<p>Теперь же, если вывести форму, то увидим, что можно выбрать между Audio
и Video категориями.</p>
Авторизация на сайтах через urllib22012-06-11T23:17:00+03:00admintag:it4it.ru,2012-06-11:2012/06/11/avtorizaciya-na-sajtax-cherez-urllib2/<p>Стандартная библиотека питона для работы с вебом - urllib2, позволяет
с помощью использования различных хэндлеров добавлять различный
функционал. Будь то обработка ssl, работа с cookies либо какие-то
расширения http протокола. А если есть работа с cookies, то значит можно
авторизироваться на различных сайтах и ходить по “закрытой” их части :)</p>
<p>Для примера, залогинимся на <a class="reference external" href="http://linux.org.ru">лоре</a></p>
<p>Сначала нам требуется создать объект, который будет хранить наши куки,
этот объект создается из библиотеки cookielib</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">cookielib</span>
<span class="n">cookie</span> <span class="o">=</span> <span class="n">cookielib</span><span class="o">.</span><span class="n">CookieJar</span><span class="p">()</span>
</pre></div>
<p>После этого, создаем объект opener из urllib2, собственно, для общения
по протоколу http с добавлением cookie хэндлера</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">urllib2</span>
<span class="n">req</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">build_opener</span><span class="p">(</span><span class="n">urllib2</span><span class="o">.</span><span class="n">HTTPCookieProcessor</span><span class="p">(</span><span class="n">cookie</span><span class="p">))</span>
</pre></div>
<p>Чтобы не было проблем с некоторыми веб-серверами, добавим юзер агент, пораспространеннее</p>
<div class="highlight"><pre><span></span><span class="n">req</span><span class="o">.</span><span class="n">addheaders</span> <span class="o">=</span> <span class="p">[(</span><span class="s1">'User-Agent'</span><span class="p">,</span> <span class="s1">'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11'</span><span class="p">),</span> <span class="p">]</span>
</pre></div>
<p>и установим наш opener как глобальный (необязательно)</p>
<div class="highlight"><pre><span></span><span class="n">urllib2</span><span class="o">.</span><span class="n">install_opener</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">req</span><span class="p">)</span>
</pre></div>
<p>После этого, надо открыть страницу по определенному адресу и передать
туда параметры соответственно формы авторизации.</p>
<p>Чтобы определить адрес, на который отправлять данные, а также, как поля
формы называется, надо открыть исходники html страницы и найти форму
авторизации. Для примера, на lor она выглядит так:</p>
<div class="highlight"><pre><span></span><span class="err">Имя</span><span class="p">:</span>
<span class="err">Пароль</span><span class="p">:</span>
</pre></div>
<p>Из формы нам требуется адрес из тэга <form> и его аттрибут action, здесь
он login.jsp, что значит адрес для отправки будет
<a class="reference external" href="http://linux.org.ru/login.jsp">http://linux.org.ru/login.jsp</a></p>
<p>Данные, которые надо отправлять смотрим в тэгах <input> и аттрибут name,
здесь нам потребуются nick и passwd.</p>
<p>Итак, теперь попробуем залогиниться:</p>
<div class="highlight"><pre><span></span><span class="n">resp</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">'http://linux.org.ru/index.jsp'</span><span class="p">,</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span><span class="s1">'nick'</span><span class="p">:</span><span class="s1">'username'</span><span class="p">,</span> <span class="s1">'passwd'</span><span class="p">:</span><span class="s1">'password'</span><span class="p">}))</span>
</pre></div>
<p>В объекте resp лежит код, который нам отправил веб-сервер, если это 200,
то значит все прошло хорошо (обычно это так :)</p>
<p>Также, можем проверить объект cookies и увидеть, что там появился номер сессии</p>
<div class="highlight"><pre><span></span><span class="k">print</span> <span class="n">cookie</span>
<span class="n">cookielib</span><span class="o">.</span><span class="n">CookieJar</span><span class="p">[</span><span class="n">Cookie</span><span class="p">(</span><span class="n">version</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s1">'JSESSIONID'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="s1">'01626E21D72D336E302F5702AFE208A'</span><span class="p">,</span>
</pre></div>
<p>Чтобы прочитать содержимое страницы, используем resp.read()</p>
<p>Все, теперь используя объект resp мы можем ходить по сайту с куками и авторизованными</p>
Функциональное тестирование с freshen2011-09-28T22:05:00+03:00gigimontag:it4it.ru,2011-09-28:2011/09/28/funkcionalnoe-testirovanie-s-freshen/<p>Некоторое время назад, набрел в сети на пакет cucumber, который помогает
создавать различные тесты. Все действия в тесте описываюстя с помощью
файла сценария, который пишется на языке <a class="reference external" href="https://github.com/cucumber/cucumber/wiki/Gherkin">Grekhin</a> представляющий из
себя обычный, понятный для человека текст на любом языке. К сожалению
cucumber это разработка для Ruby, но у него есть практически полная
копия переписаная под Python с поддержкой nose и зовется <a class="reference external" href="https://github.com/rlisagor/freshen">freshen</a></p>
<p>Теперь, расскажу про создание теста на freshen</p>
<p>Файл сценарий содержит в себе:</p>
<ol class="arabic simple">
<li>Путь к файлу с шагами теста (steps файл)</li>
<li>Описание данного теста</li>
<li>Сценарии</li>
</ol>
<p>Для привязки шагов в коде с шагами в .feature файле используются декораторы.</p>
<p>Для примера, стандартный .feature файл с описанием сценария выглядит так
(пример из документации):</p>
<div class="highlight"><pre><span></span><span class="n">Using</span> <span class="n">step</span> <span class="n">definitions</span> <span class="n">from</span><span class="p">:</span> <span class="s1">'steps'</span><span class="p">,</span> <span class="s1">'step/page_steps'</span>
<span class="n">Feature</span><span class="p">:</span> <span class="n">Destroy</span> <span class="n">a</span> <span class="n">document</span>
<span class="n">In</span> <span class="n">order</span> <span class="n">to</span> <span class="n">take</span> <span class="n">out</span> <span class="n">one</span><span class="s1">'s anger on a document</span>
<span class="n">As</span> <span class="n">an</span> <span class="n">unsatisfied</span> <span class="n">reader</span>
<span class="n">I</span> <span class="n">want</span> <span class="n">to</span> <span class="n">be</span> <span class="n">able</span> <span class="n">to</span> <span class="n">rip</span> <span class="n">off</span> <span class="n">the</span> <span class="n">pages</span> <span class="n">of</span> <span class="n">the</span> <span class="n">document</span>
<span class="n">Scenario</span><span class="p">:</span> <span class="n">Rip</span> <span class="n">off</span> <span class="n">a</span> <span class="n">page</span>
<span class="n">Given</span> <span class="n">a</span> <span class="n">document</span> <span class="n">of</span> <span class="mi">5</span> <span class="n">pages</span>
<span class="n">And</span> <span class="n">the</span> <span class="n">page</span> <span class="ow">is</span> <span class="mi">3</span>
<span class="n">When</span> <span class="n">I</span> <span class="n">rip</span> <span class="n">off</span> <span class="n">the</span> <span class="n">current</span> <span class="n">page</span>
<span class="n">Then</span> <span class="n">the</span> <span class="n">page</span> <span class="ow">is</span> <span class="mi">3</span>
<span class="n">But</span> <span class="n">the</span> <span class="n">document</span> <span class="n">has</span> <span class="mi">4</span> <span class="n">pages</span>
</pre></div>
<p>Файл с шагами будет выглядеть примерно так:</p>
<div class="highlight"><pre><span></span><span class="nd">@Given</span><span class="p">(</span><span class="s1">'a document of 5 pages'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step1</span><span class="p">():</span>
<span class="k">pass</span>
<span class="nd">@Given</span><span class="p">(</span><span class="s1">'the page is 3'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step2</span><span class="p">():</span>
<span class="k">pass</span>
<span class="nd">@When</span><span class="p">(</span><span class="s1">'I rip off the current page'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step3</span><span class="p">():</span>
<span class="k">pass</span>
<span class="nd">@Then</span><span class="p">(</span><span class="s1">'the page is 3'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step4</span><span class="p">():</span>
<span class="k">pass</span>
<span class="nd">@Then</span><span class="p">(</span><span class="s1">'the document has 4 pages'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step5</span><span class="p">():</span>
<span class="k">pass</span>
</pre></div>
<p>Основные ключевые слова при использовании английского языка для
написания сценариев:</p>
<p>Given, When, Then, But, And</p>
<p>Также, для описания шага можно использовать регулярные выражения:</p>
<div class="highlight"><pre><span></span><span class="nd">@Given</span><span class="p">(</span><span class="s1">'the page is ([d]+)'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">step2</span><span class="p">(</span><span class="n">page</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
<p>Т.к. freshen поддерживает работу с nose, то для его запуска через nose
можно использовать такую команду:</p>
<p>nosetests —with-freshen test.feature</p>
<p>После выполнения тестов, если не было неудачно закончившихся шагов,
покажет что все хорошо, иначе покажет на каком степе остановился. Также,
freshen поддерживает тэги, которые можно повесить на сценарии и
запускать только по тэгам.</p>
Социальные штуки в Django с Redis часть 22011-06-04T15:15:00+03:00gigimontag:it4it.ru,2011-06-04:2011/06/04/socialnye-shtuki-v-django-s-redis-chast-2/<p>В прошлой части я рассказал, как использую Redis в Django для показа
онлайн пользователей. Во второй же части я расскажу, как сделать показ
новых комментариев для постов (количество у каждого поста и подсветка
новых в посте).</p>
<p>Разберемся сначала, из каких частей будет состоять вся “индикация”:</p>
<p>1. Тэг, показывающий сколько новых комментариев в топике у данного пользователя</p>
<p>2. Функция, возвращающая номера новых комментариев в посте и удаляющая
их из базы</p>
<p>3. Функция добавляющая новый комментарий в список ‘новых’ для всех пользователей</p>
<p>Для понимания работы этих функций, рассмотрим ключи в базе:</p>
<p><span class="quo">‘</span>users:%username%:posts’ - содержит номера новых постов</p>
<p><span class="quo">‘</span>users:%username%:%post.id%’ - содержит id комментариев для поста</p>
<p><span class="quo">‘</span>users:%username%’ - общее количество новых комментариев</p>
<p>Теперь, рассмотрим функции по работе с базой и их применение для каждого случая.</p>
<p>Все начинается с того, что при сохранении комментария его id
записывается в базу для каждого юзера:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_comment</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="n">comment</span> <span class="o">=</span> <span class="n">kwargs</span><span class="p">[</span><span class="s1">'instance'</span><span class="p">]</span>
<span class="k">if</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s1">'users'</span><span class="p">):</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">smembers</span><span class="p">(</span><span class="s1">'users'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">comment</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">username</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">sadd</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">comment</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
<span class="n">users</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">comment</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">sadd</span><span class="p">(</span><span class="s1">'users'</span><span class="p">,</span> <span class="n">comment</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">smembers</span><span class="p">(</span><span class="s1">'users'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">users</span><span class="p">:</span>
<span class="k">if</span> <span class="n">user</span> <span class="o">==</span> <span class="n">comment</span><span class="o">.</span><span class="n">author</span><span class="o">.</span><span class="n">username</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">user</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="n">redis_db</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">user</span><span class="p">))</span> <span class="o"><</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'UNREAD_LIMIT'</span><span class="p">,</span> <span class="mi">100</span><span class="p">):</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">incr</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">user</span><span class="p">)</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">sadd</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">comment</span><span class="o">.</span><span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">),</span> <span class="n">comment</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">sadd</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:posts'</span> <span class="o">%</span> <span class="n">user</span><span class="p">,</span> <span class="n">comment</span><span class="o">.</span><span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">user</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</pre></div>
<p>Работает код просто, сначала достаем список со всеми пользователями
(ключ ‘users’), а потом проходимся по каждому и добавляем номер
комментария в ключ с номером поста (‘users:%username%:%post.id%’) и
увеличиваем количество новых комментариев.</p>
<p>Данная функция сделана как сигнал и используется при сохранении комментария:</p>
<div class="highlight"><pre><span></span><span class="n">post_save</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">add_comment</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="n">Comment</span><span class="p">)</span>
</pre></div>
<p>Для отображения количества новых комментариев у каждого поста,
используется такой тэг:</p>
<div class="highlight"><pre><span></span><span class="n">register</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">Library</span><span class="p">()</span>
<span class="nd">@register.tag</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'newcom_count'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">get_count_newcom</span><span class="p">(</span><span class="n">parser</span><span class="p">,</span> <span class="n">token</span><span class="p">):</span>
<span class="n">bits</span> <span class="o">=</span> <span class="n">token</span><span class="o">.</span><span class="n">split_contents</span><span class="p">()</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
<span class="k">return</span> <span class="n">NewcomCountNode</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">bits</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">bits</span><span class="p">)</span> <span class="o">==</span> <span class="mi">5</span> <span class="ow">and</span> <span class="n">bits</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'as'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">NewcomCountNode</span><span class="p">(</span><span class="n">bits</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">bits</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">bits</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">template</span><span class="o">.</span><span class="n">TemplateSyntaxError</span><span class="p">,</span> <span class="s2">"</span><span class="si">%r</span><span class="s2"> tag requires a two argument, username and post_id"</span> <span class="o">%</span> <span class="n">token</span><span class="o">.</span><span class="n">contents</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">NewcomCountNode</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">Node</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">count</span><span class="p">,</span> <span class="n">varname</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">username</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">Variable</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">Variable</span><span class="p">(</span><span class="n">count</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">varname</span> <span class="o">=</span> <span class="n">varname</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">context</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">username</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
<span class="k">except</span> <span class="n">template</span><span class="o">.</span><span class="n">VariableDoesNotExist</span><span class="p">:</span>
<span class="n">username</span> <span class="o">=</span> <span class="s1">''</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">count</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">count</span><span class="o">.</span><span class="n">resolve</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
<span class="k">except</span> <span class="n">template</span><span class="o">.</span><span class="n">VariableDoesNotExist</span><span class="p">:</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">varname</span><span class="p">:</span>
<span class="n">context</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">varname</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_post_newcom</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
<span class="k">return</span> <span class="s1">''</span>
<span class="k">return</span> <span class="n">get_post_newcom</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">count</span><span class="p">)</span>
</pre></div>
<p>Он используется в темплейтах, как</p>
<div class="highlight"><pre><span></span><span class="p">{</span><span class="o">%</span> <span class="n">newcom_count</span> <span class="n">user</span><span class="o">.</span><span class="n">username</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span> <span class="k">as</span> <span class="n">newcom</span> <span class="o">%</span><span class="p">}</span>
</pre></div>
<div class="highlight"><pre><span></span><span class="err">Функция</span> <span class="err">для</span> <span class="err">работы</span> <span class="err">с</span> <span class="err">базой</span><span class="p">:</span>
</pre></div>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_post_newcom</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">post_id</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">count</span> <span class="o">=</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">scard</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">post_id</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">count</span><span class="p">)</span>
</pre></div>
<p>Она всего-лишь достает количество новых комментариев, если таких нет, то
вернет 0.</p>
<p>В самом посте, чтобы узнать какой комментарий является новым, используем
такую функцию:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">del_comment</span><span class="p">(</span><span class="n">post</span><span class="p">,</span> <span class="n">username</span><span class="p">):</span>
<span class="k">if</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">srem</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:posts'</span> <span class="o">%</span> <span class="n">username</span><span class="p">,</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">):</span>
<span class="n">comments</span> <span class="o">=</span> <span class="n">redis_db</span><span class="o">.</span><span class="n">smembers</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">))</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="n">post</span><span class="o">.</span><span class="n">id</span><span class="p">))</span>
<span class="n">count</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">redis_db</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">username</span><span class="p">))</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s1">'users:</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">username</span><span class="p">,</span> <span class="n">count</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">comments</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">comments</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">return</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">comments</span><span class="p">]</span>
</pre></div>
<p>На вход она принимает instance post и имя пользователя, а на выход
отдает список с id комментариев. В своей работе, она также удаляет из
ключа новые посты. Передача его в шаблон, позволяет простой проверкой
узнавать, новый или нет комментарий.</p>
<p>Я использую во вьюхе вывода поста:</p>
<div class="highlight"><pre><span></span><span class="n">newcomments</span> <span class="o">=</span> <span class="n">del_comment</span><span class="p">(</span><span class="n">post</span><span class="p">,</span> <span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">username</span><span class="p">)</span>
</pre></div>
<p>А в шаблоне делаю проверку:</p>
<div class="highlight"><pre><span></span><span class="p">{</span><span class="o">%</span> <span class="k">if</span> <span class="n">comment</span><span class="o">.</span><span class="n">id</span> <span class="ow">in</span> <span class="n">newcom</span> <span class="o">%</span><span class="p">}</span>
</pre></div>
<p>На этом все и заканчивается. Как видно из кода, все достаточно просто,
по сравнению с использованием реляционных баз.</p>
Социальные штуки в Django с Redis часть 12011-04-04T00:06:00+03:00gigimontag:it4it.ru,2011-04-04:2011/04/04/socialnye-shtuki-v-django-s-redis-chast-1/<p>Для одного из сайтов надо было писать начальные социальные штуки, типа
количество пользователей онлайн и количество новых комментариев для
постов. Т.к. реализация этого с sql базами достаточно затратно по
ресурсам и не самое простое дело, то было выбрано nosql хранилище Redis.
В нем легко хранить ключи и большое количество значений, которое легко
можно получить для конкретных нужд.</p>
<p>Сначала рассмотрим реализацию индикатора пользователей онлайн вместе с Django.</p>
<p>Рассмотрим сначала теоретическую часть работы такого индикатора. Т.к. в
вебе нет каких-либо четких механизмов узанавания, кто сейчас на сайте,
то применяется простая практика. Каждую минуту записывается, кто из
пользователей зашел на сайт, а раз в 5 минут делается выборка
(группировка юзеров в каждую минуту) и вычисляется сколько их было. В
моем конкретном примере, все пользователи зарегистрированы, т.е.
учитывать анонимов не требуется. В Django для учета каждого пользователя
и занесения его в базу очень подходит мидлварь (middleware). При заходе
пользователя на любую страницу сайта, миддлварь его обрабатывает и
заносит в базу со значением ключа указывающем время (например 23:10). А
при запросе счетчиком, будут выбираться 5 ключей (23:10, 23:09, 23:08,
23:07, 23:06) объединяться и отдаваться. Общий процесс можно увидеть на
картинке (не моей):</p>
<p><a class="reference external" href="http://it4it.ru/images/2011/04/presence-online-users-diagram.png"><img alt="image0" src="http://it4it.ru/images/2011/04/presence-online-users-diagram.png" /></a>Начнем рассмотрение кода:</p>
<p>Рассмотрим код миддлвари:</p>
<div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">OnlineUsersMiddleware</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">process_request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">dbwork</span><span class="o">.</span><span class="n">set_to_key</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
</pre></div>
<p>Как видно, вся работа миддлвари это получить id юзера и передать его в
функцию работы с базой.</p>
<p>Рассмотрим саму функцию dbwork.set_to_key():</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">current_key</span><span class="p">():</span>
<span class="k">return</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%H:%M'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">set_to_key</span><span class="p">(</span><span class="n">user_id</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">current_key</span><span class="p">()</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">sadd</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">user_id</span><span class="p">)</span>
<span class="n">redis_db</span><span class="o">.</span><span class="n">expire</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="mi">360</span><span class="p">)</span>
</pre></div>
<p>Первая (current_key) - выдает нам просто время (ее можно и соввместить
впринципе), вторая (set_to_key), получает ключ, добавляет в базу ключ
set, в который добавляем пользовательский id и устанавливаем на него
время жизни 6 минут.</p>
<p>Далее, рассмотри функцию, которая выводит количество пользователей онлайн:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_online</span><span class="p">():</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">interval</span> <span class="o">=</span> <span class="p">[</span><span class="n">now</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">)]</span>
<span class="n">interval</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">'%H:%M'</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">interval</span><span class="p">]</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">online</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">redis_db</span><span class="o">.</span><span class="n">sunion</span><span class="p">(</span><span class="n">interval</span><span class="p">))</span>
<span class="k">except</span><span class="p">:</span>
<span class="n">online</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">online</span><span class="p">)</span>
</pre></div>
<p>тут interval - это список наших ключей, который получается получением
дельты с текущим временем и 5 минут назад, потом по нему с помощью
sunion() получаем все id пользователей, а len - количество (т.к. мне не
нужны были имена, а только количество).</p>
<p>Для получения и выведения этого значения был написан контекст процессор,
т.к. значение требуется во всех шаблонах:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">users_online</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="n">users</span> <span class="o">=</span> <span class="n">get_online</span><span class="p">()</span>
<span class="k">return</span> <span class="p">{</span><span class="s1">'count_users_online'</span><span class="p">:</span> <span class="n">users</span><span class="p">}</span>
</pre></div>
<p>Во всех модулях, redis_db это конект к базе редиса через официальный
модуль Redis, примерно так открывающий коннект:</p>
<div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
<span class="n">redis_db</span> <span class="o">=</span> <span class="n">redis</span><span class="o">.</span><span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'REDIS_HOST'</span><span class="p">,</span> <span class="s1">'localhost'</span><span class="p">),</span>
<span class="n">port</span><span class="o">=</span><span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'REDIS_PORT'</span><span class="p">,</span> <span class="mi">6379</span><span class="p">),</span>
<span class="n">db</span><span class="o">=</span><span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'REDIS_DB'</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
<span class="n">password</span><span class="o">=</span><span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s1">'REDIS_PASS'</span><span class="p">,</span> <span class="s1">''</span><span class="p">),</span>
<span class="n">socket_timeout</span><span class="o">=</span><span class="mf">0.01</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">pass</span>
</pre></div>
<p>Все, после этого можно использовать. Как видно - делается легко и
просто, к тому же не захламляет sql базу и не сказывается на
производительности (nosql очень быстр). Вместо использования redis можно
использовать тот же memcache.</p>
Запуск Django в virtualenv из под cherokee2011-02-18T19:13:00+02:00gigimontag:it4it.ru,2011-02-18:2011/02/18/zapusk-django-v-virtualenv-iz-pod-cherokee/<p>Не так давно, перешел я на использование cherokee, т.к. он новый,
стильный, молодежный :)</p>
<p>А вообще, пал выбор на него, т.к. из коробки хорошая работа с wsgi и
другими штуками для python и ruby (да, пхп он тоже может). Также, не
надо писать конфиг, есть клевая админка, в которой все функции делаются
в пару кликов.</p>
<p>Также, за последнее время начал использовать virtualenv для питоно
сайтов, чтобы держать разные версии библиотек и не мешать друг другу. В
такое окружение я запихнул 1 старенький интернет-магазин на Django 1.1,
хотя в системе работают сайты и с Django 1.2.4, собственно почитать, что
такое virtualenx можно <a class="reference external" href="http://virtualenv.openplans.org/">тут</a></p>
<p>Для начала определимся, что нам потребуется в системе:</p>
<ol class="arabic simple">
<li>cherokee</li>
<li>uwsgi</li>
<li>python</li>
</ol>
<p>Итак, начнем с создания места расположения нашего django сайта.</p>
<p>У меня все сайты хранятся в /var/www/domain, либо для virtualenv
/var/www/virtualenv/domain, что позволяет различать, где что.</p>
<p>Первым делом, требуется установить virtualenv и создать окружение.</p>
<div class="highlight"><pre><span></span>pip install virtualenv
<span class="nb">cd</span> /var/www/virtualenv
virtualenv --no-site-packages newsite
</pre></div>
<p>Первая строка устанавливает virtualev (можно также через easy_install),
а вторая собственно, создает изолированное пространство, со своим
интерпретатором и библиотеками.</p>
<p>После этого, надо установить нужные пакеты в изолированное пространство:</p>
<div class="highlight"><pre><span></span><span class="nb">source</span> newsite/bin/activate
easy_install pip
pip install packages
</pre></div>
<p>При работе в таком окружении, предполагается использование его
интепретатора питона (версию можно другую поставить) и если оно активно
у вас, то скрипты будут запускаться изолированно.</p>
<p>Теперь, скопируем в наше окружение проект:</p>
<div class="highlight"><pre><span></span>cp from/path to/path/var/www/virtualenv/newsite/www
</pre></div>
<p>Раз весь пример на основе Django, то следует рассказать про запускной скрипт.</p>
<p>Наш django-сайт будет работать через wsgi в связке с uwsgi, поэтому
создадим в папке сайта файл: <strong>run.py с содержимым:</strong></p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'DJANGO_SETTINGS_MODULE'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'settings'</span>
<span class="kn">import</span> <span class="nn">django.core.handlers.wsgi</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">django</span><span class="o">.</span><span class="n">core</span><span class="o">.</span><span class="n">handler</span>
<span class="n">s</span><span class="o">.</span><span class="n">wsgi</span><span class="o">.</span><span class="n">WSGIHandler</span><span class="p">()</span>
</pre></div>
<p>И создадим файл uwsgi.xml с конфигурацией для uwsgi</p>
<div class="highlight"><pre><span></span>/var/www/virtualsites/aw-d.ru/www/src
RUN
</pre></div>
<p>Все, с настройкой сайта покончено, перейдем к cherokee.</p>
<p>Для начала, запустим админку:</p>
<div class="highlight"><pre><span></span>cherokee-admin -bваш_IP
</pre></div>
<p>После этого, заходим на этот <span class="caps">IP</span> порт 9090, вводим логин и пароль и видим
панель управления cherokee. Именно в этой админке, можно делать все
настройки сайтов и самого веб-сервера.</p>
<p>Для запуска сайта на Django в cherokee имеется мастер. Его мы и будем использовать:</p>
<p>Идем на вкладку vServers (вверху) затем слева на +, в окне выбираем
Platforms - Django - Add</p>
<p>В появившемся мастере для Django жмем сразу Next, в путь Django Local
Directory вписываем полный путь к джанго проекту, в моем случае /var/www/virtualsites/test/www</p>
<p>На следующем экране:</p>
<p><strong>New Host Name</strong> - название домена</p>
<p><strong>Document Root</strong> - где располагается проект</p>
<p>После нажатия на Create, в списке виртуальных серверов появится новый.</p>
<p>По-умолчанию, cherokee для django использует flup, поэтому надо будет
изменить способ запуска. Для этого идем во вкладку Sources - Слева
выбираем последний созданый источник (обычно DjangoNN)</p>
<p>В его настройках нам надо поле Interpreter, на такое:</p>
<div class="highlight"><pre><span></span>/путь/до/uwsgi -s 127.0.0.1:60407 -x /полный/путь/до/файла/wsgi.xml -H /путь/до/виртуального/окружения/сайта -t <span class="m">10</span> -M -p <span class="m">1</span> -R <span class="m">2000</span> -C
</pre></div>
<p>путь до виртуального окружения сайта вида: /var/www/virtualsites/site</p>
<p>Все, сохраняем эту конфигурацию и проверяем, как работает наш сайт.</p>
<p>Сайт должен будет работать, но без статики :)</p>
<p>Для настройки статики требуется прописать 1 правило в свойствах
виртуального сервера. Идем в vServers - выбираем ваш сайт - вкладка Behavior - Rule
management. Создаем новое нажатием на + и в появившемся окне выбираем Manual - Rule type - Directory, в Web
Directory вписываем ваш урл для статики (я обычно использую /static) и
жмем Add, пото заходим Handler и в Document Root вписываем полный путь
до папки со статикой.</p>
<p>Все, после сохранения конфигурации и перезагрузки cherokee, ваш сайт
должен работать.</p>
<p>Если сайт не работает, то следует проверить строку для запуска uwsgi,
просто скопируйте всю строку из Interpreter в консоль и запустите, если
wsgi процесс запустится, значит здесь проблем нет.</p>
hgweb на lighttpd2010-05-14T10:20:00+03:00gigimontag:it4it.ru,2010-05-14:2010/05/14/hgweb-na-lighttpd/<p>Опять давно ничего не писал :) А сегодня решил напомнить, что я жив и
рассказать, как поднять свой hg репозитарий с web мордой на веб-сервере Lighttpd.</p>
<p>Предположим, что mercurial и Lighttpd у вас уже установлены, а
репозитарии hg будут храниться в /var/www. Т.к. hgweb мы будем запускать
через fastcgi (единственный возможный на lighttpd, не считая прокси), то
нам потребуется .fcgi скрипт, который будет создавать wsgi сервер с
сокетом. Т.к. у меня кучка django сайтов, то я сделал папку
/var/www/fcgi, в которой все их и храню :)</p>
<ol class="arabic simple">
<li>Создадим такую папку и положим в файл hgweb.fcgi такой код:</li>
</ol>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">mercurial</span> <span class="kn">import</span> <span class="n">demandimport</span><span class="p">;</span> <span class="n">demandimport</span><span class="o">.</span><span class="n">enable</span><span class="p">()</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s2">"HGENCODING"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"UTF-8"</span>
<span class="kn">from</span> <span class="nn">mercurial.hgweb.hgwebdir_mod</span> <span class="kn">import</span> <span class="n">hgwebdir</span>
<span class="kn">from</span> <span class="nn">mercurial.hgweb.request</span> <span class="kn">import</span> <span class="n">wsgiapplication</span>
<span class="kn">from</span> <span class="nn">flup.server.fcgi</span> <span class="kn">import</span> <span class="n">WSGIServer</span>
<span class="k">def</span> <span class="nf">make_web_app</span><span class="p">():</span>
<span class="k">return</span> <span class="n">hgwebdir</span><span class="p">(</span><span class="s2">"hgweb.conf"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">wsgiapplication2</span><span class="p">(</span><span class="n">app_maker</span><span class="p">):</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">app_maker</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">run_wsgi</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">respond</span><span class="p">):</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">env</span><span class="p">[</span><span class="s1">'PATH_INFO'</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">'hgweb.fcgi/'</span><span class="p">,</span><span class="s1">''</span><span class="p">)</span>
<span class="n">env</span><span class="p">[</span><span class="s1">'PATH_INFO'</span><span class="p">]</span> <span class="o">=</span> <span class="n">path</span>
<span class="k">return</span> <span class="n">application</span><span class="p">(</span><span class="n">env</span><span class="p">,</span> <span class="n">respond</span><span class="p">)</span>
<span class="k">return</span> <span class="n">run_wsgi</span>
<span class="n">WSGIServer</span><span class="p">(</span><span class="n">wsgiapplication2</span><span class="p">(</span><span class="n">make_web_app</span><span class="p">))</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre></div>
<ol class="arabic simple" start="2">
<li>Тамже, положим файл hgweb.conf с конфигурацией нашего сервера:</li>
</ol>
<div class="highlight"><pre><span></span><span class="o">[</span>paths<span class="o">]</span>
/repo_name <span class="o">=</span> /path/to/repo
<span class="o">[</span>web<span class="o">]</span>
<span class="nv">style</span> <span class="o">=</span> gitweb
<span class="nv">allow_archive</span> <span class="o">=</span> bz2 gz zip
<span class="nv">baseurl</span> <span class="o">=</span>
</pre></div>
<p>В секции [paths] определяются все репозитории, которые будут видны в hgweb.</p>
<p>Baseurl - устанавливает префикс в url для доступа к репозитарию. В моем
случае, ссылка будет <a class="reference external" href="http://example.com/repo_name">http://example.com/repo_name</a>.</p>
<p>3. Создадим репозиторий hg, либо склонируем его с локальнйо машины по
ssh :)</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /path/to/repo
hg init
<span class="nb">cd</span> /path/to/repo
hg clone . ssh://login@example.com//path/to/repo
</pre></div>
<p>При клонировании по ssh, важно не забыть именно два слэша, после адреса.</p>
<ol class="arabic simple" start="4">
<li>Конфигурируем lighttpd.</li>
</ol>
<p>Создаем новый конфиг, я назвал его 15-hgweb.conf, имя значения не имеет
впринципе :) Кладем в папочку и включаем:</p>
<div class="highlight"><pre><span></span>/etc/lighttpd/conf-available/
ln -s /etc/lighttpd/conf-available/15-hgweb.conf /etc/lighttpd/conv-enabled/15-hgweb.conf
</pre></div>
<p>Содержимое файла 15-hgweb.conf:</p>
<div class="highlight"><pre><span></span><span class="nv">$HTTP</span><span class="o">[</span><span class="s2">"host"</span><span class="o">]</span> <span class="o">==</span> <span class="s2">"hg.example.com"</span> <span class="o">{</span>
server.document-root <span class="o">=</span> <span class="s2">""</span>
server.errorlog <span class="o">=</span> <span class="s2">"/var/log/lighttpd/hgweb.error.log"</span>
accesslog.filename <span class="o">=</span> <span class="s2">"/var/log/lighttpd/hgweb.access.log"</span>
accesslog.format <span class="o">=</span> <span class="s2">"%h %l %u %f %t "</span>%r<span class="s2">" %>s %b "</span>%<span class="o">{</span>Referer<span class="o">}</span>i<span class="s2">" "</span>%<span class="o">{</span>User-Agent<span class="o">}</span>i<span class="s2">""</span>
server.follow-symlink <span class="o">=</span> <span class="s2">"enable"</span>
url.rewrite-once <span class="o">=</span> <span class="o">(</span>
<span class="s2">"^/(.*)</span>$<span class="s2">"</span> <span class="o">=</span>> <span class="s2">"/hgweb.fcgi/</span><span class="nv">$1</span><span class="s2">"</span>,
<span class="o">)</span>
fastcgi.server <span class="o">=</span> <span class="o">(</span>
<span class="s2">"/hgweb.fcgi"</span> <span class="o">=</span>> <span class="o">(</span>
<span class="s2">"main"</span> <span class="o">=</span>> <span class="o">(</span>
<span class="s2">"socket"</span> <span class="o">=</span>> <span class="s2">"/tmp/hgweb.socket"</span>,
<span class="s2">"check-local"</span> <span class="o">=</span>> <span class="s2">"disable"</span>,
<span class="s2">"bin-path"</span> <span class="o">=</span>> <span class="s2">"/path/to/hgweb.fcgi"</span>,
<span class="s2">"broken-scriptfilename"</span> <span class="o">=</span>> <span class="s2">"enable"</span>,
<span class="s2">"min-procs"</span> <span class="o">=</span>> 1,
<span class="s2">"max-procs"</span> <span class="o">=</span>> 1,
<span class="o">)</span>
<span class="o">)</span>
<span class="o">)</span>
alias.url <span class="o">=</span> <span class="o">(</span>
<span class="s2">"/static"</span> <span class="o">=</span>> <span class="s2">"/usr/share/mercurial/templates/static"</span>,
<span class="o">)</span>
<span class="nv">$HTTP</span><span class="o">[</span><span class="s2">"querystring"</span><span class="o">]</span> <span class="o">=</span>~ <span class="s2">"cmd=unbundle"</span> <span class="o">{</span>
auth.backend <span class="o">=</span> <span class="s2">"htpasswd"</span>
auth.backend.htpasswd.userfile <span class="o">=</span> <span class="s2">"/path/to/passwd"</span>
auth.require <span class="o">=</span> <span class="o">(</span> <span class="s2">""</span> <span class="o">=</span>> <span class="o">(</span>
<span class="s2">"method"</span> <span class="o">=</span>> <span class="s2">"basic"</span>,
<span class="s2">"realm"</span> <span class="o">=</span>> <span class="s2">"gigimon Repo"</span>,
<span class="s2">"require"</span> <span class="o">=</span>> <span class="s2">"valid-user"</span>
<span class="o">)</span>
<span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>Последняя секция с авторизацией нужна для возможности делать push в
репозитории. Если хотите сделать его публичным дял просомтра, либо
убрать возможность пуша, то можете ее полностью убрать.</p>
<p>Также, для пуша требуется, чтобы в lighttpd был настроен <span class="caps">SSL</span>, в
дефолтной поставке дебиана такое есть. Проверить можно в
/etc/lighttpd/lighttpd.conf , обычно в самом низу:</p>
<div class="highlight"><pre><span></span><span class="nv">$SERVER</span><span class="o">[</span><span class="s2">"socket"</span><span class="o">]</span> <span class="o">==</span> <span class="s2">":443"</span> <span class="o">{</span>
ssl.engine <span class="o">=</span> <span class="s2">"enable"</span>
ssl.pemfile <span class="o">=</span> <span class="s2">"/etc/lighttpd/lighttpd.pem"</span>
<span class="o">}</span>
</pre></div>
<p>Файл с паролями, который указывается в auth.backend.htpasswd.userfile,
создается командой htpasswd входящей в apache2-utils</p>
<p>5. Теперь, если хотим разрешить пуш некоторым лицам, нам требуется
настроить сам репозиторий через файл hgrc</p>
<div class="highlight"><pre><span></span>cat /path/to/repo/.hg/hgrc
<span class="o">[</span>web<span class="o">]</span>
<span class="nv">allow_push</span> <span class="o">=</span> user1, user2
<span class="nv">description</span> <span class="o">=</span> <span class="s2">"example.com development"</span>
</pre></div>
<p>Также, помимо разрешения, в этом файле задаются многие параметры для
репозитория. Я использую авто апдейт кода при пуше в него, через строку:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>hooks<span class="o">]</span>
changegroup.upd <span class="o">=</span> hg update
</pre></div>
<p>После перезагрузки lighttpd</p>
<div class="highlight"><pre><span></span>/etc/init.d/lighttpd restart
</pre></div>
<p>По вашему адресу, должен будет появиться и работать hgweb, надеюсь у вас
он появился :)</p>
Создание VPN сети с помощью OpenVPN2010-01-26T01:13:00+02:00gigimontag:it4it.ru,2010-01-26:2010/01/26/sozdanie-vpn-seti-s-pomoshhyu-openvpn/<p>Потребовалось мне тут на досуге, реализовать <span class="caps">VPN</span> сеть для пары десятков
компьютеров, находящихся в разных точках Земли. Для этого выбрал
OpenVPN, а для сервера использовал свой <span class="caps">VPS</span>, который видят все.</p>
<p>Итак, первое что нам необходимо, это установить OpenVPN</p>
<div class="highlight"><pre><span></span>apt-get install openvpn
</pre></div>
<p>После этого, настрйока сервера и клиентов сводится к генерации ключей,
раздачи их клиентам и написании 2-х конфигов (для сервера и клиентов).</p>
<p>Идем в папку /usr/share/openvpn/easy-rsa/2.0 (в этйо папке хранятся
скрипты для создания ключей)</p>
<div class="highlight"><pre><span></span>cd /usr/share/openvpn/easy-rsa/2.0
</pre></div>
<p>Теперь, начнем генерацию ключей:</p>
<p>#. Редактируем файл vars, который хранит значения по-умолчанию (чтобы не
вводить кучу раз)</p>
<div class="highlight"><pre><span></span>nano vars
</pre></div>
<p>В самом низу, меняем</p>
<div class="highlight"><pre><span></span><span class="nb">export</span> <span class="nv">KEY_COUNTRY</span><span class="o">=</span><span class="s2">"RU"</span>
<span class="nb">export</span> <span class="nv">KEY_PROVINCE</span><span class="o">=</span><span class="s2">"Moscow oblast"</span>
<span class="nb">export</span> <span class="nv">KEY_CITY</span><span class="o">=</span><span class="s2">"Moscow"</span>
<span class="nb">export</span> <span class="nv">KEY_ORG</span><span class="o">=</span><span class="s2">"my-network"</span>
<span class="nb">export</span> <span class="nv">KEY_EMAIL</span><span class="o">=</span><span class="s2">"root@mynet.ru"</span>
</pre></div>
<p>Теперь экспортиуре этот файл и генерируем корневой сертификат:</p>
<div class="highlight"><pre><span></span><span class="nb">source</span> ./vars
./clean-all
./build-ca
</pre></div>
<p>После, генерируем ключ сервера:</p>
<div class="highlight"><pre><span></span>./build-key-server server
</pre></div>
<p>На последние 2 вопроса, отвечаем Y44</p>
<p>После, генерируем ключ Диффи-Хэлмана</p>
<div class="highlight"><pre><span></span>./build-dh
</pre></div>
<p>Он делается несколько минут, придется подождать</p>
<p>Теперь, генерируем ключи для каждого клиента</p>
<div class="highlight"><pre><span></span>./build-key client_name
</pre></div>
<p>После этого, отдаем клиентам их ключи, а также файл ca.crt</p>
<p>Для большей защиты, на файлы server.key установить права 600, а на
server.crt и dh1024.pem права 644</p>
<p>Теперь надо написать конфиг сервера.</p>
<div class="highlight"><pre><span></span>port <span class="m">1194</span> <span class="c1">#порт, на котором работать (рекомендуемый)</span>
proto udp <span class="c1">#протокол, можно tcp</span>
dev tun <span class="c1">#устройство, которое будет использоваться</span>
ca путь_до_файла_ca.crt
cert путь_до_файла_server.crt
key путь_до_файла_server.key
dh путь_до_файла_dh1024.pem
server 10.10.10.0 255.255.255.0 <span class="c1">#подсеть и маска для ВПН сети, из нее будут выдаваться адреса клиентам</span>
client-to-client <span class="c1">#разрешаем общение между клиентами</span>
ifconfig-pool-persist /etc/openvpn/ipp.txt <span class="c1">#это позволит выдавать клиентам один и тот же IP</span>
comp-lzo <span class="c1">#компрессия</span>
max-clients <span class="m">28</span> <span class="c1">#максимальное количество клиентов</span>
keepalive <span class="m">10</span> <span class="m">120</span> <span class="c1">#каждые 10 секунд пинг, если нет ответа 120 секунд, то откидывать клиента</span>
persist-key <span class="c1">#хранить ключи в памяти, не перечитывать с диска</span>
persist-tun <span class="c1">#позволять держать соединение</span>
status /tmp/openvpn-status.log <span class="c1">#статус сервера</span>
verb <span class="m">6</span> <span class="c1">#уровень отладки (нормально 2)</span>
log-append /var/log/openvpn.log <span class="c1">#файл логов</span>
</pre></div>
<p>Теперь нам надо подготовить конфиг для клиентов.</p>
<p>На Windows, OpenVPN устанавливается в C:Program FIlesOpenVPN, а конфиг в
папке config (логично :). Создадим в ней новый конфиг openvpn.ovpn и
кинем в нее же сгенерированные ключи и сертификаты.</p>
<p>Впишем в конфиг следующее:</p>
<div class="highlight"><pre><span></span>client <span class="c1">#указываем что мы клиент</span>
nobind <span class="c1">#не цепляться за интерфейс</span>
dev tun <span class="c1">#используемое устройство</span>
proto udp <span class="c1">#протокол</span>
remote IP_сервера порт <span class="c1">#куда конектиться</span>
resolv-retry infinite <span class="c1">#количество попыток, infinite-бесконечно</span>
persist-key <span class="c1">#хранить ключ в памяти</span>
persist-tun <span class="c1">#держать соединение</span>
comp-lzo <span class="c1">#сжатие</span>
ns-cert-type server
ca ca.crt <span class="c1">#ключи</span>
cert название.crt
key название.key
</pre></div>
<p>После этого, запустим OpenVPN, кликнем Connect, дождемся, когда
компьютерики станут зелеными (это будет значить, что к серверу успешно
подключились). Теперь можно открыть cmd и пропинговать шлюз, если пакеты
ходят, то значит что все хорошо :)</p>
Настройка VPN сервера на Win2003 через шлюз с Linux2010-01-15T00:22:00+02:00gigimontag:it4it.ru,2010-01-15:2010/01/15/nastrojka-vpn-servera-na-win2003-cherez-shlyuz-s-linux/<p>Был очень большой перерыв в бложике, писать было не о чем :) И вот на
работе появилась задача, подключить 1 комп ко внутренней сети. Думал
сначала взять OpenVPN, но решил, что незачем плодить сущности и пусть
сервер поработает хоть немного.</p>
<p>Итак, все описаное мной, было проверено на Windows 2003 <span class="caps">EN</span>. Приступим:</p>
<p>1. Для начала нам надо включить <span class="caps">RRAS</span> сервер (routing and remove access
), для этого идем Administrative tools - Routing and Remote access,
увидим свой сервер, жмем правой кнопкой на него Configure and Enable
Routing and Remote server, запустится мастер, ничего сложного, проходим
его до конца.</p>
<p>2. Появится пункт <span class="caps">IP</span> Routing, открываем его, идем в пункт <span class="caps">NAT</span>/Basic
Firewall, жмем правой кнопкой New Interface, добавляем внутренний и
внешний интерфейс. Заходим</p>
<p><a class="reference external" href="http://it4it.ru/images/2010/01/vpn1.png"><img alt="Окно с интерфейсами" src="http://it4it.ru/images/2010/01/vpn1-450x319.png" /></a>У меня интерфейс to-optima идет к интернет-шлюзу
(Linux машина) и он считается внешним, Lan - внутренняя сеть.</p>
<p>После этого, правой кнопкой на внешнем интерфейсе, Properties. отмечаем
галчоками Enable <span class="caps">NAT</span> Interface (если вам надо чтобы через этот интерфейс
пользователи могли выходить в интернет) и Enable a basic firewall.</p>
<p><a class="reference external" href="http://it4it.ru/images/2010/01/vpn2.png"><img alt="настройка внешнего интерфейса" src="http://it4it.ru/images/2010/01/vpn2-379x450.png" /></a></p>
<p>Затем идем в Services and Ports и ставим галочку напротив <span class="caps">VPN</span> Gateway
(<span class="caps">PPTP</span>).</p>
<p>В настройках внутреннего интерфейса, должен быть выбран пункт: Private
interface connected to private network</p>
<p>3. Затем идем в пункт Remote Access Policies жмем правой и new remote
access policy. Появистя мастер, походим его тыкая кнопку вперед. После
его появления, жмем правой кнопкой - Properties. В первом же окне,
ставим галочку у Grant remote access permission. Затем На вкладках
Authentication и Ecnryption выбираем методы авторизации и шифрования
(советую выбрать <span class="caps">MS</span>-<span class="caps">CHAP</span> 2, а в шифровании все пункты).</p>
<p>4. Идем в пункт Ports - Properties. Здесь мы видем возможные способы
подключения (<span class="caps">PPPOE</span>, <span class="caps">PPTP</span>, <span class="caps">L2TP</span>). Я оставил только <span class="caps">PPTP</span>. Чтобы выключить
остальные, выбираем их, жмем кнопку Configure и пункт maximum ports до
нуля. Но, следует отметить, что требуется установить нужное количество
соединений в нужном способе подключения (у меня 5 соединений в <span class="caps">PPTP</span>), в
конечном итоге у вас должно получиться что-то типа этого:</p>
<p><a class="reference external" href="http://it4it.ru/images/2010/01/vpn3.png"><img alt="Итоговая картина подключений" src="http://it4it.ru/images/2010/01/vpn3.png" /></a></p>
<p>5. Выбираем в меню свой сервер, правой кнопкой - Properties, первое меню
настраиваем так:</p>
<p><a class="reference external" href="http://it4it.ru/images/2010/01/vpn4.png"><img alt="Настройки 1" src="http://it4it.ru/images/2010/01/vpn4.png" /></a></p>
<p>Теперь идем на вкладку <span class="caps">IP</span> и там есть 2 выбора, либо отдавать <span class="caps">IP</span> клиентам
по <span class="caps">DHCP</span> (если он у вас настроен) либо из пула адресов (у меня из пула,
соответственно его надо добавить нажав по кнопке Add).</p>
<p>Внизу, выбираем внутренний адаптер.</p>
<p>6. Теперь надо дать нужным пользователям возможность заходить по <span class="caps">VPN</span>. У
меня все пользователи в домене, поэтому идем: Administrative tools -
Active Directory users, ищем нужного юзера, заходим в его настройки
Properties, открываем вкладку Dial-In и ставим галочки:</p>
<p><a class="reference external" href="http://it4it.ru/images/2010/01/vpn5.png"><img alt="Настройка юзера" src="http://it4it.ru/images/2010/01/vpn5-384x450.png" /></a></p>
<p>После этого, настройка на Windows 2003 заканчивается. Если у вас нету
перед ним шлюза на Linux, то можете пробовать подключиться (главное не
забудьте правильно выставить настройки шифрования в подключении у клиента).</p>
<p>Для тех, у кого есть шлюз на Linux, потребуется сделать несколько действий</p>
<p>1. В правила iptables сделать <span class="caps">DNAT</span> порта <span class="caps">VPN</span> tcp 1723 и протокола gre.
Это можно сделать следующими правилами:</p>
<div class="highlight"><pre><span></span><span class="nv">$IPT</span> -t nat -A PREROUTING -p tcp --dport <span class="m">1723</span> -j DNAT --to-destination <span class="nv">$your_server</span>
<span class="nv">$IPT</span> -t nat -A PREROUTING -p gre -j DNAT --to-destination <span class="nv">$your_server</span>
</pre></div>
<p>Ну и не забыть конечно разрешить <span class="caps">FORWARD</span> между внешним и внутренним
интерфейсами протокола gre.</p>
<p>Также требуется подгрузить модуль ip_nat_pptp (в 5 дебиане он есть
точно сразу)</p>
<div class="highlight"><pre><span></span>modprobe ip_nat_pptp
</pre></div>
Установка на Debian 5 - lighttpd + mod_deflate2009-10-06T23:41:00+03:00gigimontag:it4it.ru,2009-10-06:2009/10/06/ustanovka-na-debian-5-lighttpd-mod_deflate/<p>После переезда с 1 хостера к другому, решил сменить apache2 на Lighttpd.
Т.к. <span class="caps">VPS</span> мой на Debian 5 и там есть только Lighttpd версии 1.4.19, в
которой нету такого нужного модуля, как mod_deflate, для сжатия
передаваемых данных. Данный модуль появился только с версии 1.5, в 1.4
есть лишь mod_compress, который умеет только статчиеские файлы сжимать.
К счастью, патч, реализующий mod_deflate, доступен практически ко всей
ветке 1.4. В этой статье рассмотрим, как доабвить mod_deflate модуль.</p>
<p>Для начала, установим пакет build-essential для сборки lighttpd в .deb пакет</p>
<div class="highlight"><pre><span></span>apt-get install build-essential
</pre></div>
<p>Затем надо скачать сорцы lighttpd и патча:</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /usr/src
apt-get <span class="nb">source</span> lighttpd
wget http://redmine.lighttpd.net/attachments/download/632/lighttpd-1.4.19.mod_deflate.patch
</pre></div>
<p>Патчим:</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> lighttpd-1.4.19
patch -p1 < ../lighttpd-1.4.19.mod_deflate.patch
</pre></div>
<p>Теперь соберем в .deb пакет:</p>
<div class="highlight"><pre><span></span>dpkg-buildpackage
</pre></div>
<p>После выполнения команды, у вас наверняка появится ошибка подобно этой:</p>
<div class="highlight"><pre><span></span>dpkg-checkbuilddeps: Unmet build dependencies: debhelper <span class="o">(</span>><span class="o">=</span> 5.0.0<span class="o">)</span> cdbs libssl-dev zlib1g-dev libbz2-dev libattr1-dev libpcre3-dev libmysqlclient15-dev libldap2-dev libfcgi-dev libgdbm-dev libmemcache-dev liblua5.1-0-dev dpatch patchutils pkg-config uuid-dev libsqlite3-dev libxml2-dev
</pre></div>
<p>Это означает, что нехватает этих пакетов для сборки. Надо их установить:</p>
<div class="highlight"><pre><span></span>apt-get install cdbs libssl-dev zlib1g-dev libbz2-dev libattr1-dev libpcre3-dev
</pre></div>
<p>После их установки, еще раз выполняем команду</p>
<div class="highlight"><pre><span></span>build-essential
</pre></div>
<p>Если по окончанию программы никаких ошибок не выявится, вы должны будете
увидеть в папке на 1 уровень выше множество .deb пакет (примерно такого вида)</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> ..
ls -l
rwxr-xr-x <span class="m">8</span> root root <span class="m">4096</span> 2007-08-08 19:09 lighttpd-1.4.19
-rw-r--r-- <span class="m">1</span> root src <span class="m">861</span> 2007-08-08 19:07 lighttpd_1.4.19-5.dsc
-rw-r--r-- <span class="m">1</span> root src <span class="m">2000</span> 2007-08-08 19:12 lighttpd_1.4.19-5e_amd64.changes
-rw-r--r-- <span class="m">1</span> root src <span class="m">287998</span> 2007-08-08 19:12 lighttpd_1.4.19-5_amd64.deb
</pre></div>
<p>Теперь установим Lighttpd:</p>
<div class="highlight"><pre><span></span>dpkg -i lighttpd_1.4.19-5_amd64.deb
</pre></div>
<p>Теперь скопируем сам модуль mod_deflate, в папку модулей Lighttpd (патч
не патчит make файл, поэтому надо ручками)</p>
<div class="highlight"><pre><span></span>cp /usr/src/lighttpd-1.4.19/debian/tmp/usr/lib/lighttpd/mod_deflate.so /usr/lib/lighttpd
</pre></div>
<p>Проверим, установился ли модуль и видит его lighttpd:</p>
<div class="highlight"><pre><span></span>lighttpd -V
lighttpd-1.4.19 <span class="o">(</span>ssl<span class="o">)</span> - a light and fast webserver
Build-Date: Oct <span class="m">5</span> <span class="m">2009</span> 01:35:25
Event Handlers:
+ <span class="k">select</span> <span class="o">(</span>generic<span class="o">)</span>
+ poll <span class="o">(</span>Unix<span class="o">)</span>
+ rt-signals <span class="o">(</span>Linux 2.4+<span class="o">)</span>
+ epoll <span class="o">(</span>Linux 2.6<span class="o">)</span>
- /dev/poll <span class="o">(</span>Solaris<span class="o">)</span>
- kqueue <span class="o">(</span>FreeBSD<span class="o">)</span>
Network handler:
+ sendfile
Features:
+ IPv6 support
+ zlib support
+ bzip2 support
+ crypt support
+ SSL Support
+ PCRE support
+ mySQL support
+ LDAP support
+ memcached support
+ FAM support
+ LUA support
+ xml support
+ SQLite support
+ GDBM support
</pre></div>
<p>Следует обратить внимание на наличие строки bzip2, если она
присутствует, то mod_deflate установился.</p>
<p>После этих манипуляций, надо настроить сам модуль. Для этого создаем
конфиг и впишем в него нужные опции (они будут действовать для всех
хостов) и включим:</p>
<div class="highlight"><pre><span></span>nano -w /etc/lighttpd/conf-available/10-deflate.conf
<span class="c1">#включением</span>
deflate.enabled <span class="o">=</span> <span class="s2">"enable"</span>
<span class="c1">#степень компрессии</span>
deflate.compression-level <span class="o">=</span> 9
deflate.mem-level <span class="o">=</span> 9
deflate.window-size <span class="o">=</span> 15
deflate.bzip2 <span class="o">=</span> <span class="s2">"enable"</span>
deflate.min-compress-size <span class="o">=</span> 200
deflate.output-buffer-size <span class="o">=</span> 4096
deflate.work-block-size <span class="o">=</span> 512
<span class="c1">#типы файлов, которые сжимать</span>
deflate.mimetypes <span class="o">=</span> <span class="o">(</span><span class="s2">"text/html"</span>, <span class="s2">"text/plain"</span>, <span class="s2">"text/css"</span>, <span class="s2">"text/javascript"</span>, <span class="s2">"text/xml"</span><span class="o">)</span>
ln -s /etc/lighttpd/conf-available/10-deflate.conf /etc/lighttpd/conf-enabled/10-deflate.conf
</pre></div>
<p>После этого рестартим Lighttpd и проверяем с помощью Opera DragonFly или
<span class="caps">FF</span> FireBug (ну или чем вам удобно смотреть <span class="caps">HTTP</span> заголовки) на предмет сжатия.</p>
<div class="highlight"><pre><span></span>/etc/init.d/lighttpd restart
</pre></div>
<p>Все, после этого должно все работать :) Надеюсь это вам помогло</p>
Создание Linux виртуальной машины (domU) в Xen2009-09-26T16:55:00+03:00gigimontag:it4it.ru,2009-09-26:2009/09/26/sozdanie-linux-virtualnoj-mashiny-domu-v-xen/<p>После того, как установили dom0, можно приступить к установке в
него виртуальных машин (domU). Для начала рассмотрим общую схему по
установке, которую можно разделить на следующие этапы:</p>
<ol class="arabic simple">
<li>Создание “жесткого диска”</li>
<li>Написание конфига</li>
<li>Установка туда ОС, либо использование готового темплейта.</li>
</ol>
<p>Приступим к созданию виртуальной машины.</p>
<p>Для жесткого диска виртуальной машины, можно использовать либо файл,
либо отдельный раздел. Я буду рассматривать на примере <span class="caps">LVM</span> раздела.</p>
<p>Для начала, создадим жесткий диск под нашу виртуальную машину:</p>
<div class="highlight"><pre><span></span>lvcreate -L M -n Debian1 /dev/VolGroup00
mkfs.ext3 /dev/VolGroup00/Debian1
</pre></div>
<p>После этого, напишем конфиг нашей виртуальной машины debian1.cfg</p>
<div class="highlight"><pre><span></span>kernel <span class="o">=</span> <span class="s1">'/boot/xen.gz-2.6.18-164.el5'</span>
memory <span class="o">=</span> 512
name <span class="o">=</span> <span class="s1">'Debian1'</span>
vif <span class="o">=</span> <span class="o">[</span><span class="s1">'vifname=vifxenv0, mac=aa:00:7f:80:ca:01 '</span><span class="o">]</span>
vnc <span class="o">=</span> 1
<span class="nv">sdl</span> <span class="o">=</span> 0
<span class="nv">vncpasswd</span> <span class="o">=</span> <span class="s1">'1234567'</span>
<span class="nv">vncdisplay</span> <span class="o">=</span> 2
serial <span class="o">=</span> <span class="s1">'pty'</span>
disk <span class="o">=</span> <span class="o">[</span><span class="s1">'phy:/dev/VolGroup00/Debian1,sda1,w'</span><span class="o">]</span>
<span class="nv">root</span> <span class="o">=</span> <span class="s1">'/dev/sda1 ro'</span>
</pre></div>
<p>Рассмотрим параметры:</p>
<p><strong>kernel</strong> - указывает какое ядро надо использовать в виртуальной
машине. Ядро должно быть модифицировано для работы в Xen окружении (в
CentOs стандартное dom0 ядро поддерживает работу в domU)</p>
<p><strong>memory</strong> - объем <span class="caps">RAM</span> в Мб</p>
<p><strong>name</strong> - имя виртуальной машины, которое будет отображаться в xm list</p>
<p><strong>vif</strong> - настройки сети. vifname - какой виртуальный интерфейс
использовать в domU машине, mac - установить этот mac адрес</p>
<p><strong>vnc</strong> - включить <span class="caps">VNC</span> (для удаленного доступа)</p>
<p><strong>sdl</strong> - при включенном vnc не использовать библиотеку sdl, они
взаимоисключают друг друга</p>
<p><strong>vncpasswd</strong> - пароль на <span class="caps">VNC</span></p>
<p><strong>vncdisplay</strong> - на каком экране <span class="caps">VNC</span> будет эта виртуальная машина. Тут
имеется ввиду порт на dom0 машине, который устанавливается 5900 +
vncdisplay. В нашем случае этот порт будет 5902</p>
<p><strong>disk</strong> - Параметры жесткого диска. phy: значит физический раздел, с
полным путем к нему. В случае файла надо использовать file: Следующий
параметр после запятой, это под каким именем подключать этот раздел в
dom0 машину, следующий параметр, что можно с этим разделом w -
означает возможность читать и писать на него.</p>
<p><strong>root</strong> - параметр root передаваемый ядру при загрузке.</p>
<p>Теперь, нам надо либо установить ОС в виртуальную машину, либо
использовать уже готовый темплейт, что мы и будем делать.</p>
<p>Достаточно много темплейтов, можно найти на <a class="reference external" href="http://stacklet.com/">этом</a> сайте. Качаем Debian
Lenny с этого сайта</p>
<div class="highlight"><pre><span></span>wget http://stacklet.com/sites/default/files/debian/debian.5-0.x86.20090517.img.tar.bz2
tar -xfj debian.5-0.x86.20090517.img.tar.bz2
</pre></div>
<p>После этого, смонтируем наш “жесткий диск” для виртуальной машины и
образ .img</p>
<div class="highlight"><pre><span></span>mkdir /mnt/template
mkdir /mnt/fs<
mount -o loop debian.5-0.x86.20090517.img /mnt/template
mount /dev/VolGroup00/Debian1
</pre></div>
<p>Теперь скопируем все с образа на наш диск:</p>
<div class="highlight"><pre><span></span>cp -R /mnt/template/* /mnt/fs
</pre></div>
<p>Отмонтируем:</p>
<div class="highlight"><pre><span></span>umount /mnt/template
umount /mnt/fs
</pre></div>
<p>Все, наша domU машина готова, осталось только ее запустить</p>
<div class="highlight"><pre><span></span>xm create /path/to/config/debian1.cfg -c
</pre></div>
<p>У нас откроется консоль с запуском виртуальной машины, если все хорошо,
то перед нами будет диалог приветствия (шелл, с просьбой ввода логина и
пароля). Стандартный пароль на эти темплейты password.</p>
<p>После этого, можно проверить и <span class="caps">VNC</span> доступ. На удаленной машине
используем любой <span class="caps">VNC</span> клиент (я использую tightVNC)</p>
<div class="highlight"><pre><span></span>vncviewer server_ip:5902
</pre></div>
<p>Должно будет появиться окно ввода пароля, после его ввода увидим шелл.
Если все так и произошло, то поздравляю с первой виртуальной машиной в
Xen :)</p>
<p>Ссылки:
<cite><http://xgu.ru/wiki/Linux_в_Xen></cite>
<cite><http://stacklet.com/></cite></p>
<p><span class="caps">P.S.</span>надеюсь это руководство вам помогло.</p>
Установка Xen в CentOS2009-09-23T23:51:00+03:00gigimontag:it4it.ru,2009-09-23:2009/09/23/ustanovka-xen-v-centos/<p>Недавно начал пробовать систему виртуализации Xen. После быстрого чтения
мануалов, смог установить виртуальную машину с Debian, что говорит о
достаточно простой конфигурации (для начальных нужд). Итак, в качестве
хостовой машины (dom0) будет использоваться CentOS 5.2, запущенный на
компьютере с поддержкой аппаратной виртуализации (<span class="caps">AMD</span>-V или Intel-<span class="caps">VT</span>).
Поддержка аппаратной виртуализации нужна, если вы собираетесь запускать Windows.</p>
<p>Первое что необходимо, установить ядро с поддержкой Xen. В стандартных
репозитариях CentOS есть такое ядро, kernel-xen версии 2.6.18-164 с Xen 3.0</p>
<div class="highlight"><pre><span></span>yum install kernel-xen
</pre></div>
<p>После установки, в /boot появится ядро vmlinuz-2.6.18-164.el5xen. Теперь
надо загрузиться с ним. Можео либо вручную его выбрать при загрузке
grub, либо отредактировать файл /boot/grub/menu.lst и параметр default
сделать равным 0 (по-умолчанию, kernel-xen автоматчиески прописывает
себя первым ядром в меню grub).</p>
<p>После загрузки с ядром Xen’а, работу его можно проверить наличием
интерфейсов xenbr и vif в выводе ifconfig:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>root@gigi ~<span class="o">]</span><span class="c1"># ifconfig</span>
peth1 Link encap:Ethernet HWaddr FE:FF:FF:FF:FF:FF
inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:1484845567 errors:0 dropped:848 overruns:0 frame:0
TX packets:21318806 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:107304750948 <span class="o">(</span>99.9 GiB<span class="o">)</span> TX bytes:1495739489 <span class="o">(</span>1.3 GiB<span class="o">)</span>
Memory:dc080000-dc0a0000
vifxenv0 Link encap:Ethernet HWaddr FE:FF:FF:FF:FF:FF
inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:17643569 errors:0 dropped:0 overruns:0 frame:0
TX packets:1467766901 errors:0 dropped:390908 overruns:0 carrier:0
collisions:0 txqueuelen:32
RX bytes:863953497 <span class="o">(</span>823.9 MiB<span class="o">)</span> TX bytes:100008573528 <span class="o">(</span>93.1 GiB<span class="o">)</span>
vif0.1 Link encap:Ethernet HWaddr FE:FF:FF:FF:FF:FF
inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:3588998 errors:0 dropped:0 overruns:0 frame:0
TX packets:1483233162 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:370499902 <span class="o">(</span>353.3 MiB<span class="o">)</span> TX bytes:107193417651 <span class="o">(</span>99.8 GiB<span class="o">)</span>
xenbr1 Link encap:Ethernet HWaddr FE:FF:FF:FF:FF:FF
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:3930114 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2361888673 <span class="o">(</span>2.1 GiB<span class="o">)</span> TX bytes:0 <span class="o">(</span>0.0 b<span class="o">)</span>
</pre></div>
<p>А также, посмотреть вывод команды xm list, он должен выглядеть примерно так:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>root@gigi ~<span class="o">]</span><span class="c1"># xm list</span>
Name ID Mem<span class="o">(</span>MiB<span class="o">)</span> VCPUs State Time<span class="o">(</span>s<span class="o">)</span>
Domain-0 <span class="m">0</span> <span class="m">512</span> <span class="m">4</span> r----- 45273.0
</pre></div>
<p>Запись Domain-0 обозначает, что запущена машина с dom0 (наша хостовая)
и значит, все работает :)</p>
<p>Из известных проблем, следует упомянуть, не используйте сетевые карты
Realtek на чипсетах 8169 и ему подобном, т.к. при использовании такой
сетевой карты, не сохраняются сетевые параметры (не применяются при
создании моста xenbr), а также <span class="caps">MAC</span> адрес становится <span class="caps">FF</span>:<span class="caps">FF</span>:<span class="caps">FF</span>:<span class="caps">FF</span>:<span class="caps">FF</span>:<span class="caps">FF</span></p>
<p>В следующей заметке (очень скоро) расскажу про создание Linux и Windows
виртуальных машин.</p>
<p>Ссылки:</p>
<p>Официальный <a class="reference external" href="http://www.xen.org/">сайт</a></p>
<p>Официальная <a class="reference external" href="http://tx.downloads.xensource.com/downloads/docs/user">документация</a></p>
<p><a class="reference external" href="http://xgu.ru/wiki/Xen">Документация xen</a> на русском</p>
Подключаем django-debug-toolbar2009-08-19T12:43:00+03:00gigimontag:it4it.ru,2009-08-19:2009/08/19/podklyuchaem-django-debug-toolbar/<p>Очень полезным дополнением для Django является django-debug-toolbar.
Это своего рода отладочная панель, которая легко подключается, позволяет
просматривать множество данных (в том числе настройки, <span class="caps">SQL</span> запросы,
время выполнения, traceback). Приступим собственно к его установке :)</p>
<p>1. Установим собственно django-debug-toolbar. Можно из <a class="reference external" href="git://github.com/robhudson/django-debug-toolbar.git">git’a</a> или же
стабильную версию с помощью easy_install</p>
<div class="highlight"><pre><span></span><span class="n">easy_install</span> <span class="n">django</span><span class="o">-</span><span class="n">debug</span><span class="o">-</span><span class="n">toolbar</span>
</pre></div>
<p>2. Добавляем в наш проект. В секцию MIDDLEWARE_CLASSES добавим в конец ‘debug_toolbar.middleware.DebugToolbarMiddleware’,</p>
<p>3. В settings.py добавим секцию INTERNAL_IPS = (‘127.0.0.1’,) (если вы
работаете на локальной машине)</p>
<p>4. Добавим путь в TEMPLATE_DIRS до папки с темплейтами
django-debug-toolbar. У меня в Gentoo этот путь ’/usr/lib/python2.5/site-packages/django_debug_toolbar-0.7.0-py2.5.egg/debug_toolbar/templates/’,</p>
<p>5. Подключим к нашему проекту, в секции INSTALLED_APPS добавить ‘debug_toolbar’,</p>
<p>6. После этого, можно опционально добавить секцию
DEBUG_TOOLBAR_PANELS, в которой задаются активные панели.</p>
<div class="highlight"><pre><span></span><span class="n">DEBUG_TOOLBAR_PANELS</span> <span class="o">=</span> <span class="p">(</span>
<span class="s1">'debug_toolbar.panels.version.VersionDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.timer.TimerDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.settings_vars.SettingsVarsDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.headers.HeaderDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.request_vars.RequestVarsDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.template.TemplateDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.sql.SQLDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.signals.SignalDebugPanel'</span><span class="p">,</span>
<span class="s1">'debug_toolbar.panels.logger.LoggingPanel'</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
<p>Все, после этого, на каждой странице вверху, будет отображаться
тулбарчик с панелькой :)</p>
<p><span class="caps">P.S.</span>панель отображается только если в темплейте есть открывающийся и
закрывающийся тег <body></body></p>
Подключение Bluetooth гарнитуры через PulseAudio2009-08-06T22:09:00+03:00gigimontag:it4it.ru,2009-08-06:2009/08/06/podklyuchenie-bluetooth-garnitury-cherez-pulseaudio/<p>Решил все-таки написать статейку, после долгого летнего перерыва :)</p>
<p>После обновления ядра с 24 на 30, перестала работать bluetooth гарнитура
:( из-за того, что убрали mod_bt_sco, начал искать решение,
рекомендовали через PulseAudio (который не стоял из-за ненадобности).
Итак начнем, для начала обновим портежи и пересоберем мир с pulseaudio.</p>
<p>Добавляем в</p>
<div class="highlight"><pre><span></span>/etc/make.conf в секцию USE <span class="s2">"pulseaudio avahi"</span>
</pre></div>
<p>Обновляем мир</p>
<div class="highlight"><pre><span></span>emerge -avDNt world
</pre></div>
<p>Теперь установим компоненты PulseAudio</p>
<div class="highlight"><pre><span></span>emerge -av pulseaudio paprefs pavucontrol paman padevchooser pavumeter alsa-plugins
</pre></div>
<p>media-sound/pulseaudio - сам сервер
media-sound/paprefs - Графическая утилита для настройки параметров
сервера
media-sound/pavumeter - Графическая утилита, которая отображает
уровни звука (типа alsamixer)
media-sound/padevchooser - Утилита для настройки звуковых устройств и
потоков, создает иконку в трее, позволяет на лету переключать устройства
звука и многое другое
media-sound/paman - Утилита для тонкой настройки модулей
media-sound/pavucontrol - Утилита позволяющая переключать каналы ипотоки.</p>
<p>После этого, меняем профиль esd</p>
<div class="highlight"><pre><span></span>eselect esd <span class="nb">set</span> 2
</pre></div>
<p>Добавляем в автозагрузку avahi-daemon и pulseaudio</p>
<div class="highlight"><pre><span></span>rc-update add avahi-daemon default
rc-update add pulseaudio default
</pre></div>
<p>Добавим нужного пользователя в группу PulseAudio</p>
<div class="highlight"><pre><span></span>gpasswd -a USER pulse
gpasswd -a USER pulse-access
</pre></div>
<p>Теперь, настроим PulseAudio, редактируем /etc/conf.d/pulseaudio к такому виду:</p>
<div class="highlight"><pre><span></span><span class="nv">PA_OPTS</span><span class="o">=</span><span class="s2">"--log-target=syslog"</span>
<span class="nv">PULSEAUDIO_SHOULD_NOT_GO_SYSTEMWIDE</span><span class="o">=</span>YES
</pre></div>
<p>Затем в /etc/init.d/pulseaudio в секции start(), изменяем строчку на:</p>
<div class="highlight"><pre><span></span><span class="nv">PA_ALL_OPTS</span><span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">PA_OPTS</span><span class="si">}</span><span class="s2"> --fail=1 --daemonize=1"</span>
</pre></div>
<p>Настроим <span class="caps">ALSA</span>. В .asoundrc (в папке пользователя) добавляем:</p>
<div class="highlight"><pre><span></span>pcm.pulse <span class="o">{</span>
<span class="nb">type</span> pulse
<span class="o">}</span>
ctl.pulse <span class="o">{</span>
<span class="nb">type</span> pulse
<span class="o">}</span>
pcm.!default <span class="o">{</span>
<span class="nb">type</span> pulse
<span class="o">}</span>
ctl.!default <span class="o">{</span>
<span class="nb">type</span> pulse
<span class="o">}</span>
</pre></div>
<p>Эти строки говорят, что для всего по дефолту будет использоваться PulseAudio.</p>
<p>Теперь стартуем PulseAudio и рестартим <span class="caps">ALSA</span></p>
<div class="highlight"><pre><span></span>/etc/init.d/alsasound restart
/etc/init.d/pulseaudio start
</pre></div>
<p>Теперь запускаем pavucontrol и запускаем какой-нибудь аудио плеер, и
првоеряем, что звук играет и в pavucontrol появился этот поток. Если
появился, приступим к подключению гарнитуры.</p>
<p>Устанавливаем bluez версии 4.38 (4.39 почему-то не работает с
PulseAudio) и гуи к нему blueman</p>
<div class="highlight"><pre><span></span>emerge -va bluez blueman
</pre></div>
<p>Запускаем blueman-manager и спариваем свою гарнитуру с компьютером.
Затем подключаемся к ней ко службе <span class="caps">A2DP</span>. После этого, в pavucontrol во
вкладке Configuration должна появится наша гарнитура. Теперь на нее
можно направлять поток. Для этого на первой влкадке, напротив названия
потока жмем на галочку->Move stream и выбираем гарнитуру.</p>
<p>Надеюсь после этого, у вас гарнитура заработает :)</p>
<p><span class="caps">P.S.</span>все сказаное относится к Gentoo Linux</p>
Автомонтирование с помощью udev2009-06-07T13:05:00+03:00gigimontag:it4it.ru,2009-06-07:2009/06/07/avtomontirovanie-s-pomoshhyu-udev/<p>После перехода с kde на openbox, стал вопрос автомонтирования
устройств (особенно флэшек). Погуглив, нашел несколько способов:</p>
<ol class="arabic simple">
<li>с помощью инструментов kde</li>
<li>с помощью gnome-mount</li>
<li>xfce4-mount</li>
<li>ivman</li>
<li>udev</li>
</ol>
<p>Первые два не подходили, слишком много зависимостей. При третьем,
всегда пришлось бы держать в памяти апплет xfce и панель его, что тоже
не хотелось.
ivman я не смог заставить работать :( он тупо не монтировал, незнаю
почему.
А вот с udev немного разобрался, нагуглил готовое и теперь использую его.</p>
<p>Итак, автомонтирование устрйоств с помощью udev является простым,
требуется всего лишь написать 1 файл с правилами.
Создаем файл для правил:</p>
<div class="highlight"><pre><span></span>touch /etc/udev/rules.d/10-udev-automount.rules
</pre></div>
<p>И вписываем в него следующие правила:</p>
<div class="highlight"><pre><span></span><span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z]"</span>, <span class="nv">DRIVER</span><span class="o">==</span><span class="s2">"usb-storage"</span>, <span class="nv">GROUP</span><span class="o">=</span><span class="s2">"storage"</span><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>
<span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, <span class="nv">GROUP</span><span class="o">=</span><span class="s2">"storage"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/mkdir -p /media/</span><span class="nv">$env</span><span class="s2">{ID_FS_LABEL_ENC}"</span><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>
<span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, <span class="nv">PROGRAM</span><span class="o">==</span><span class="s2">"/lib/udev/vol_id -t %N"</span>, <span class="nv">RESULT</span><span class="o">==</span><span class="s2">"vfat"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/mount -t vfat -o rw,flush,quiet,nodev,noauto,noexec,nosuid,noatime,dmask=000,fmask=111,iocharset=utf8 /dev/%k /media/</span><span class="nv">$env</span><span class="s2">{ID_FS_LABEL_ENC}"</span><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>
<span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, <span class="nv">PROGRAM</span><span class="o">==</span><span class="s2">"/lib/udev/vol_id -t %N"</span>, <span class="nv">RESULT</span><span class="o">==</span><span class="s2">"ntfs"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/mount -t ntfs-3g -o rw,flush,quiet,nodev,noauto,noexec,nosuid,noatime,dmask=000,fmask=111,iocharset=utf8 /dev/%k /media/</span><span class="nv">$env</span><span class="s2">{ID_FS_LABEL_ENC}"</span><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>
<span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/mount -o rw,noauto,noexec,nodev,noatime,dmask=000,fmask=111 /dev/%k /media/</span><span class="nv">$env</span><span class="s2">{ID_FS_LABEL_ENC}"</span>
<span class="nv">ACTION</span><span class="o">==</span><span class="s2">"remove"</span>, <span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/umount /dev/%k"</span>
<span class="nv">ACTION</span><span class="o">==</span><span class="s2">"remove"</span>, <span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"sd[b-z][0-9]"</span>, RUN+<span class="o">=</span><span class="s2">"/bin/rmdir /media/</span><span class="nv">$env</span><span class="s2">{ID_FS_LABEL_ENC}"</span>
</pre></div>
<p>Перегружаем службу udev.
После этого, при установке usb флэшки, она будет монтироваться в
/media в папку с названием флэшки (название тома), с полным доступом
пользователям, а также нормальной кодировкой</p>
<p>Из известных багов, есть два:</p>
<ol class="arabic simple">
<li>Если у флэшки нет названия тома, то она монтируется прямо в /media</li>
<li>Если флэшка определяется как /dev/sdb без цифр, она не монтируется</li>
</ol>
Автоматический бэкап MS SQL 2005 Express базы2009-06-01T16:31:00+03:00gigimontag:it4it.ru,2009-06-01:2009/06/01/avtomaticheskij-bekap-ms-sql-2005-express-bazy/<p>При переходе на новую программу на работе, перешли и на использование
<span class="caps">MS</span> <span class="caps">SQL</span> Server, заместо FirebirdSQL и встал вопрос резервного копирования
базы данных. Для этих целей в полной версии <span class="caps">MS</span> <span class="caps">SQL</span> используется
встроенный планировщик, к сожалению, в Express версии его нету, поэтому
пришлось использовать внешние средства Windows (планировщик) и командную
строку с интерфейсом к <span class="caps">MS</span> <span class="caps">SQL</span>.
Весь процесс создания бэкапа разделен на 2 файла: backup.bat с
командами Windows и <span class="caps">MS</span> <span class="caps">SQL</span> скрипт backup.sql, который содержит команды
для бэкапа нашей базы.
Файл backup.sql содержит:</p>
<div class="highlight"><pre><span></span><span class="k">DECLARE</span> <span class="o">@</span><span class="n">pathName</span> <span class="n">NVARCHAR</span><span class="p">(</span><span class="mi">512</span><span class="p">)</span>
<span class="k">SET</span> <span class="o">@</span><span class="n">pathName</span> <span class="o">=</span> <span class="s1">'D:mssqlbackupdb_backup_'</span> <span class="o">+</span> <span class="k">Convert</span><span class="p">(</span><span class="nb">varchar</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span> <span class="n">GETDATE</span><span class="p">(),</span> <span class="mi">112</span><span class="p">)</span> <span class="o">+</span> <span class="s1">'.bak'</span>
<span class="n">BACKUP</span> <span class="k">DATABASE</span> <span class="p">[</span><span class="n">db_name</span><span class="p">]</span> <span class="k">TO</span> <span class="n">DISK</span> <span class="o">=</span> <span class="o">@</span><span class="n">pathName</span> <span class="k">WITH</span> <span class="n">NOFORMAT</span><span class="p">,</span> <span class="n">NOINIT</span><span class="p">,</span> <span class="n">NAME</span> <span class="o">=</span> <span class="n">N</span><span class="s1">'db_backup'</span><span class="p">,</span> <span class="n">SKIP</span><span class="p">,</span> <span class="n">NOREWIND</span><span class="p">,</span> <span class="n">NOUNLOAD</span><span class="p">,</span> <span class="n">STATS</span> <span class="o">=</span> <span class="mi">10</span>
</pre></div>
<p>где @pathName указывает путь сохранения, а также имя файла. В нашем
случае, будет создаваться файл с именем db_backup_20082009 (если
создавать бэкап 20 числа 8 месяца 2009 года), db_name - имя вашей базы</p>
<p>Файлик backup.bat:</p>
<div class="highlight"><pre><span></span>sqlcmd -S SERVER -U USER -P PASSWORD -i backup.sql
<span class="s2">"c:Program FilesWinRARRar.exe"</span> a -m2 d:mssqlbackupdb_backup_<span class="nv">%date%</span>.rar d:mssqlbackupdb_backup_*.bak
<span class="k">del</span> d:mssqlbackupdb_backup_*.bak
</pre></div>
<p>где, <span class="caps">SERVER</span> - адрес сервера, <span class="caps">USER</span> - пользователь для подключения,
<span class="caps">PASSWORD</span> - собственно пароль :)</p>
<p>Также, данный скрипт архивирует базу и оставляет только архив, убивая .bak</p>
<p>После создания этих двух файликов, кидаем их куда-нибудь вместе и в
Windows планировщике создаем задание, раз в сутки (ну или когда хотите)
запускать backup.bat</p>
Быстро развертываем Windows шару на Linux2009-05-19T21:53:00+03:00gigimontag:it4it.ru,2009-05-19:2009/05/19/bystro-razvertyvaem-windows-sharu-na-linux/<p>Для работы с Windows шарами (NetBios) в Linux применяется пакет Samba
(а также для сетевых принтеров, работы в домене…) Она имеет оочень
много опций и является мощнейшим инструментов для развертывания
файлопомойки или сетевого хранилища в Wndows сети.</p>
<p>Я хочу поведать о простейшем случае, когда надо просто расшарить пару
папок для чтения и записи :)</p>
<p>Для начала устанавливаем samba и редактируем конфиг расположеный в
/etc/samba/smb.conf и заполянем таким содержимым:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>global<span class="o">]</span>
<span class="nv">workgroup</span> <span class="o">=</span> MYHOME
netbios <span class="nv">name</span> <span class="o">=</span> SERVER
<span class="nv">security</span> <span class="o">=</span> share
client code <span class="nv">page</span> <span class="o">=</span> cp1251
</pre></div>
<p>где, [global] - название этого блока конфига</p>
<p>workgroup - рабочая группа, в котором находится машина</p>
<p>netbios name - имя компьютера, которое будут видеть windows пользователи
в сетевом окружении :)</p>
<p>security - тип режима работы самбы</p>
<p>client codepage - кодировка, в которую перекодировать все при показе
пользователю ( стоит cp1251, т.к это системная кодировка русской windows)</p>
<p>После этого, добавим нашу шару:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>share1<span class="o">]</span>
<span class="nv">path</span> <span class="o">=</span> /home/aliens/download
guest <span class="nv">ok</span> <span class="o">=</span> Yes
<span class="nb">read</span> <span class="nv">only</span> <span class="o">=</span> Yes
<span class="nv">writable</span> <span class="o">=</span> No
</pre></div>
<p>где, [share1] - название блока данных конфига и название пути для
данной шары</p>
<p>path - собственно путь до папки-шары</p>
<p>guest ok - возможность просмотра шары гостями (анонимными)</p>
<p>read only - установить возможность только чтения</p>
<p>writable - возможность записи</p>
<p>Соответственно, если хотите чтобы все могли писать в эту папку,
поменяйте в read only в No, а writable в Yes</p>
<p>После редактирования конфига, перегрузите сервис самбы и проверьте
работу шары :)</p>
Использование UUID разделов в fstab2009-05-15T12:30:00+03:00gigimontag:it4it.ru,2009-05-15:2009/05/15/ispolzovanie-uuid-razdelov-v-fstab/<p>Иногда бывают ситуации, когда система неправильно определяет разделы
(при добавлении нового жесткого в систему, смене ядра) и в итоге система
не грузится. Из-за этого приходилось сидеть и подбирать номера дисков.
Но недавно я открыл для себя <span class="caps">UUID</span> и возможность их использования в
fstab. <span class="caps">UUID</span> является уникальным номером раздела.</p>
<p>Теперь посмотрим, как использовать их в файле fstab.</p>
<p>Для начала, воспользуемся командой vol_id</p>
<div class="highlight"><pre><span></span>vol_id -u /dev/ваш_раздел
</pre></div>
<p>По ее выполнению получим номер <span class="caps">UUID</span>, который будем дальеш использовать:</p>
<div class="highlight"><pre><span></span>mars aliens <span class="c1"># vol_id -u /dev/sda6</span>
04291a41-5d69-4e2a-b025-1f651d036c2c
</pre></div>
<p>Теперь открываем /etc/fstab для редактирования и вписываем заместо
/dev/sda6 <span class="caps">UUID</span>=04291a41-5d69-4e2a-b025-1f651d036c2c. После всех
манипуляций, заместо</p>
<div class="highlight"><pre><span></span>dev/sda5 /home ext3 defaults <span class="m">0</span> 0
/dev/sda6 / ext3 defaults <span class="m">0</span> 1
</pre></div>
<p>Должны получить:</p>
<div class="highlight"><pre><span></span><span class="nv">UUID</span><span class="o">=</span>af359f86-36e0-415b-9caf-6038416da8c7 /home ext3 defaults <span class="m">0</span> 0
<span class="nv">UUID</span><span class="o">=</span>04291a41-5d69-4e2a-b025-1f651d036c2c / ext3 defaults <span class="m">0</span> 1
</pre></div>
<p>Все, теперь после любых манипуляций, разделы будут правильно примонтированны</p>
Узнаем температуру винчестеров в Linux и FreeBSD2009-05-08T01:11:00+03:00gigimontag:it4it.ru,2009-05-08:2009/05/08/uznaem-temperaturu-vinchesterov-v-linux-i-freebsd/<p>Очень часто для мониторинга работы системы требуется узнавать
температуру жестких дисков, для этого в Linux и FreeBSD существуют
разные программы.</p>
<p>В Linux, мы будем использовать программу hddtemp, а во FreeBSD - smartctl.</p>
<ol class="arabic simple">
<li>Использование в Linux</li>
</ol>
<p>Для начала установим данный пакет. В Gentoo Linux потребуется:</p>
<div class="highlight"><pre><span></span>emerge hddtemp
</pre></div>
<p>После установки пакета, его настройки не требуется, а можно сразу
узнавать температура винтов.</p>
<p>Чтобы узнать температура винта, требуется в консоли:</p>
<div class="highlight"><pre><span></span>hddtemp /dev/vint
</pre></div>
<p>где /dev/vint ваш жесткий диск (например: dev/sda)</p>
<p>После ввода команды, получим:</p>
<div class="highlight"><pre><span></span>trantor ~ <span class="c1"># hddtemp /dev/sda</span>
/dev/sda: ST31000340AS: 36°C
</pre></div>
<p>Также, полезным является ввод нескольких жестких дисков:</p>
<div class="highlight"><pre><span></span>trantor ~ <span class="c1"># hddtemp /dev/sda /dev/sdb</span>
/dev/sda: ST31000340AS: 36°C
/dev/sdb: ST3802110A: 34°C
</pre></div>
<p>У hddtemp есть еще 1 достаточно интересная функция для мониторинга, это
возможнонсть висеть демоном на опредленном порту и по запросу, отдавать
страницу с данными о температуре винтов в <span class="caps">CSV</span> формате. Для этого
требуется команда:</p>
<div class="highlight"><pre><span></span>trantor ~ <span class="c1"># hddtemp -4d /dev/sda /dev/sdb</span>
</pre></div>
<p>где -4d означает режим демона, но только по протоколу IPv4. По
умолчанию, он занимает порт 7634 и если на него зайти, то увидим:</p>
<div class="highlight"><pre><span></span><span class="p">|</span>/dev/sda<span class="p">|</span>ST31000340AS<span class="p">|</span>36<span class="p">|</span>C<span class="o">||</span>/dev/sdb<span class="p">|</span>ST3802110A<span class="p">|</span>34<span class="p">|</span>C<span class="p">|</span>
</pre></div>
<ol class="arabic simple">
<li>Использование smartctl во FreeBSD</li>
</ol>
<p>Для установки делаем следующее:</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /usr/ports/smartmontools
make install clean
</pre></div>
<p>После этого, нам становится доступна команда smartctl, которая будет
показывать информацию о винтах. Данная программа показывает не только
температуру, но и всю <span class="caps">S.M.A.R.</span>T информацию жесткого диска (но нас это
сейчас не интересует).</p>
<p>Для того, чтобы узнать температура жесткого диска вводим в консоли:</p>
<div class="highlight"><pre><span></span>smartctl -a /dev/ad0 <span class="p">|</span> grep Temp <span class="p">|</span> awk -F <span class="s2">" "</span> <span class="s1">'{print $10}'</span>
</pre></div>
<p>Результатом работы будет выведена температура диска в градусах Цельсия.</p>
<p>К сожалению, на некоторых винчестерах температуа может не показаться,
поэтому требуется использовать вывод полной информации <span class="caps">S.M.A.R.</span>T</p>
<div class="highlight"><pre><span></span>smartctl -a -s on /dev/ad0 <span class="p">|</span> grep Temp <span class="p">|</span> awk -F <span class="s2">" "</span> <span class="s1">'{print $10}'</span>
34
</pre></div>
<p>Помимо самой команды smartctl, в системе появилась smartd, которая
позволяет запустить демона для ведения логов о температуре в syslogd.</p>
Гигапиксельная фотка2009-05-01T00:02:00+03:00gigimontag:it4it.ru,2009-05-01:2009/05/01/gigapikselnaya-fotka/<p>Нашел в интернете ссылочку на гигапиксельную фотографию канадского
города Ванкувер. Фотка опупительная, можно видеть даже людей в окнах.</p>
<p>Сам сервис предоставляет удобную систему просмотра, с подгрузкой только
нужной области (аля гугл мапс).</p>
<p>Собственно, <a class="reference external" href="http://gigapixelphotography.com/vancouver-yaletown-condos">ссылка</a> на саму фотографию .</p>
<p>Кстати, на самом сайте, можно найти еще парочку фотографий очень
высокого разрешения, но, к ссожалению, не таких зрелищных</p>
Странное пианино в городе2009-04-27T00:27:00+03:00gigimontag:it4it.ru,2009-04-27:2009/04/27/strannoe-pianino-v-gorode/<p>В феврале месяце, идя в институт, заметил странное</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/04/dsc00039.jpg"><img alt="dsc00039" src="http://it4it.ru/images/2009/04/dsc00039-300x300.jpg" /></a></p>
<p><a class="reference external" href="http://it4it.ru/images/2009/04/dsc00038.jpg"><img alt="dsc00038" src="http://it4it.ru/images/2009/04/dsc00038-300x300.jpg" /></a> <a class="reference external" href="http://it4it.ru/images/2009/04/dsc00037.jpg"><img alt="dsc00037" src="http://it4it.ru/images/2009/04/dsc00037-300x300.jpg" /></a></p>
<p><a class="reference external" href="http://it4it.ru/images/2009/04/dsc00036.jpg"><img alt="dsc00036" src="http://it4it.ru/images/2009/04/dsc00036-300x300.jpg" /></a></p>
<p>К сожалению, фотки сделал только на второй день, на первый день еще
висело куча шариков.</p>
<p>Для чего и кто это сделал, я незнаю :) В течение 3-х месяцев я ждал, что
где-то на районе появится какой-нить магазин или еще что, но ничего.
Думаю, что кто-то так выкинул пианино. Кстати, так оно простояло неделю,
потом по кускам его разобрали)</p>
Скрипт получения состояния счета Djuice2009-04-26T23:53:00+03:00gigimontag:it4it.ru,2009-04-26:2009/04/26/skript-polucheniya-sostoyaniya-scheta-djuice/<p>Для своих нужд написал быстренько небольшой скрипт, который выводит
состояние текущего счета оператора Djuice Украина. Скрипт просто выводит
колчиество денег на счету, я его показываю в conky :)</p>
<p>Вот скрипт:</p>
<div class="highlight"><pre><span></span><span class="c1"># -*- coding: utf-8 -*-</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="kn">import</span> <span class="nn">urllib2</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="n">TEL_NUM</span><span class="o">=</span><span class="s2">"8097xxxxxxx"</span>
<span class="n">PASSWORD</span><span class="o">=</span><span class="s2">"asfdxczcx"</span>
<span class="n">urllib2</span><span class="o">.</span><span class="n">install_opener</span><span class="p">(</span><span class="n">urllib2</span><span class="o">.</span><span class="n">build_opener</span><span class="p">(</span><span class="n">urllib2</span><span class="o">.</span><span class="n">HTTPCookieProcessor</span><span class="p">))</span>
<span class="n">params</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span><span class="s2">"user"</span><span class="p">:</span><span class="n">TEL_NUM</span><span class="p">,</span><span class="s2">"password"</span><span class="p">:</span><span class="n">PASSWORD</span><span class="p">})</span>
<span class="n">stat</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s2">"https://my.djuice.com.ua/tbmb/login_djuice/perform.do"</span><span class="p">,</span><span class="n">params</span><span class="p">)</span>
<span class="n">sta</span> <span class="o">=</span> <span class="n">stat</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">regexp</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s1">r'([-d.]+)'</span><span class="p">)</span>
<span class="n">variables</span> <span class="o">=</span> <span class="n">regexp</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="n">sta</span><span class="p">)</span>
<span class="k">print</span> <span class="s2">"На счету: </span><span class="si">%s</span><span class="s2"> грн"</span> <span class="o">%</span> <span class="n">variables</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</pre></div>
<p>Может все-таки он и будет кому полезен</p>
Двойная загрузка виртуальных машин VMWare под Linux. Часть 2. Графика.2009-04-18T23:42:00+03:00Goletsatag:it4it.ru,2009-04-18:2009/04/18/dualboot-vmware-vm-linux-part-2/<p>Такие вкусные возможности, как то освобождение курсора из окна
виртуальной машины без нажатия горячих клавиш или Drag and Drop требуют
установки специальных драйверов.
Они входят как и в официальные <span class="caps">VMWARE</span> Tools так и в их открытую версию.</p>
<p>Ставим их штатными средствами:</p>
<div class="highlight"><pre><span></span>aptitude install xserver-xorg-video-vmware xserver-xorg-input-vmmouse open-vm-toolbox
</pre></div>
<p>Для переключения между драйверами при запуске компьютера можно
воспользоваться несложным скриптом, базирующемся частично на исходном
коде open-vm-tools:</p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/sh</span>
exit_if_not_in_vm <span class="o">()</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">[</span> ! -x /usr/bin/vmware-checkvm <span class="o">]</span> <span class="o">||</span> ! /usr/bin/vmware-checkvm > /dev/null 2><span class="p">&</span>1
<span class="k">then</span>
<span class="nb">echo</span> <span class="s2">"Not starting as we're not running in a vm."</span>
cp -f /etc/X11/xorg.conf.realpc /etc/X11/xorg.conf <span class="o">&&</span> <span class="nb">echo</span> “Real Videocard driver selected”
<span class="nb">exit</span> 0
<span class="k">fi</span>
<span class="o">}</span>
<span class="k">case</span> <span class="s2">"</span><span class="si">${</span><span class="nv">1</span><span class="si">}</span><span class="s2">"</span> in
start<span class="o">)</span>
<span class="c1"># Check if we're running inside VMWare</span>
exit_if_not_in_vm
cp -f /etc/X11/xorg.conf.vmware /etc/X11/xorg.conf <span class="o">&&</span> <span class="nb">echo</span> “VMWARE X Driver selected”
<span class="p">;;</span>
*<span class="o">)</span>
<span class="nb">echo</span> “VMWARE Video Driver Xorg config changer”<span class="p">;</span>
<span class="nb">exit</span> 1<span class="p">;</span>
<span class="p">;;</span>
<span class="k">esac</span>
</pre></div>
<p>Примерный вид xorg.conf.vmware:</p>
<div class="highlight"><pre><span></span>Section <span class="s2">"InputDevice"</span>
Identifier <span class="s2">"VMware Keyboard"</span>
Driver <span class="s2">"kbd"</span>
Option <span class="s2">"XkbRules"</span> <span class="s2">"xorg"</span>
Option <span class="s2">"XkbModel"</span> <span class="s2">"pc105"</span>
Option <span class="s2">"XkbLayout"</span> <span class="s2">"us"</span>
EndSection
Section <span class="s2">"InputDevice"</span>
Identifier <span class="s2">"VMware Mouse"</span>
Driver <span class="s2">"vmmouse"</span>
Option <span class="s2">"CorePointer"</span>
Option <span class="s2">"Device"</span> <span class="s2">"/dev/input/mice"</span>
Option <span class="s2">"Emulate3Buttons"</span> <span class="s2">"true"</span>
Option <span class="s2">"ZAxisMapping"</span> <span class="s2">"4 5"</span>
EndSection
Section <span class="s2">"Device"</span>
Identifier <span class="s2">"VMware SVGA"</span>
Driver <span class="s2">"vmware"</span>
EndSection
Section <span class="s2">"Screen"</span>
Identifier <span class="s2">"Default Screen"</span>
Device <span class="s2">"VMware SVGA"</span>
Monitor <span class="s2">"vmware"</span>
<span class="c1"># Don't specify DefaultColorDepth unless you know what you're</span>
<span class="c1"># doing. It will override the driver's preferences which can</span>
<span class="c1"># cause the X server not to run if the host doesn't support the</span>
<span class="c1"># depth.</span>
Subsection <span class="s2">"Display"</span>
<span class="c1"># VGA mode: better left untouched</span>
Depth 4
Modes <span class="s2">"640x480"</span>
ViewPort <span class="m">0</span> 0
EndSubsection
Subsection <span class="s2">"Display"</span>
Depth 15
Modes <span class="s2">"800x600"</span>
ViewPort <span class="m">0</span> 0
EndSubsection
Subsection <span class="s2">"Display"</span>
Depth 16
Modes <span class="s2">"800x600"</span>
ViewPort <span class="m">0</span> 0
EndSubsection
Subsection <span class="s2">"Display"</span>
Depth 24
Modes <span class="s2">"800x600"</span>
ViewPort <span class="m">0</span> 0
EndSubsection
EndSection
Section <span class="s2">"ServerLayout"</span>
Identifier <span class="s2">"Default Layout"</span>
Screen <span class="s2">"Default Screen"</span>
InputDevice <span class="s2">"VMware Keyboard"</span> <span class="s2">"CoreKeyboard"</span>
InputDevice <span class="s2">"VMware Mouse"</span> <span class="s2">"CorePointer"</span>
EndSection
Section <span class="s2">"Monitor"</span>
Identifier <span class="s2">"vmware"</span>
VendorName <span class="s2">"VMware, Inc"</span>
HorizSync 1-10000
VertRefresh 1-10000
EndSection
</pre></div>
<p>В нем настроен и сам адаптер чтобы можно было без нажатий на Hotkey
перемещать мышь между хостом и гостем, так и сам драйвер виртуальной
мышки, чтобы движения были не судорожными. При желании можно указать
другие разрешения и глубину цвета.</p>
<p>Соответственно в xorg.conf.realpc у вас должен быть конфигурационный
файл для обычной видеокарты, а в xorg.conf.vmware — для виртуальной.
Так же у вас обязательно должны стоять open-vm-tools, так как
программа для проверки реальный это компьютер или нет входит</p>
<p>Сам скрипт надо положить в /etc/init.d/checkvmvideo к примеру и сделать
его исполняемым:</p>
<div class="highlight"><pre><span></span>chmod +x /etc/init.d/checkvmvideo
</pre></div>
<p>Следующим шагом надо заставить этот скрипт стартовать при старте системы
что делается проще простого:</p>
<div class="highlight"><pre><span></span>update-rc.d checkvmvideo defaults
</pre></div>
<p>На что система вам ответит чемто похожим на:</p>
<div class="highlight"><pre><span></span>update-rc.d: warning: /etc/init.d/checkvmvideo missing LSB information
update-rc.d: see
Adding system startup <span class="k">for</span> /etc/init.d/checkvmvideo ...
/etc/rc0.d/K20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc1.d/K20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc6.d/K20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc2.d/S20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc3.d/S20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc4.d/S20checkvmvideo -> ../init.d/checkvmvideo
/etc/rc5.d/S20checkvmvideo -> ../init.d/checkvmvideo
</pre></div>
<p>Все. Теперь при старте системы будет проверка на виртуальную машину и
выбираться правильный конфиг X.org</p>
Двойная загрузка виртуальных машин VMWare под Linux. Часть 1.2009-04-13T15:18:00+03:00Goletsatag:it4it.ru,2009-04-13:2009/04/13/dualboot-vmware-vm-linux-part-1/<p>В нынешнем <span class="caps">IT</span> сообществе все чаще звучит слово “виртуализация”. Как
крупные компании типа Microsoft, так и небольшие представили свои
решения по работе с виртуальными компьютерами. Одним из таких решений
является линейка программ от компании VMWare. Среди интересных
возможностей этих продуктов нельзя не отметить возможность работать
напрямую с жестким диском вашего компьютера в виртуальной среде, что
может использоваться, к примеру, для запуска второй операционной системы
с вашего компьютера.</p>
<p>Все дальнейшее относится к Debian 5.0 “Lenny”</p>
<p>Но, так как большинство дистрибутивов вполне похоже, то это должно
подходить как к потомкам Debian (Ubuntu, Runtu , Mephis), так и к другим
(типа Gentoo, Fedora). Вопросы установки на физический диск, равно и как
вопрос установки самих ОС оставим на усмотрение читателя. Это в принципе
не представляет сложности и доступно пользователю. К тому же все
современные дистрибутивы уже обзавелись красивыми графическими
установщиками, которые еще сильнее упрощают жизнь неподготовленным пользователям.</p>
<p>После установки ОС следует поставить некоторые пакеты, улучшающие
производительность при запуске в виртуализированной среде VMWare. Нам
требуются open-vm-tools, open-vm-source, open-vm-toolbox . Последнее
ставим только если вам нужна графическая утилита для управления гостевой ОС.</p>
<div class="highlight"><pre><span></span>aptitude install open-vm-tools open-vm-source
</pre></div>
<p>В комплекте с этими утилитами есть небольшая программа , которая
проверяет, запущена ли ОС внутри <span class="caps">VMWARE</span> или на реальном железе. Например
ее вывод может быть таким:</p>
<div class="highlight"><pre><span></span>vmware-checkvm
</pre></div>
<p>VMware software version 6 (good)</p>
<p>Но при попытке запуска самих утилит ловим ошибку:</p>
<div class="highlight"><pre><span></span>/etc/init.d/open-vm-tools start
Loading open-vm-tools modules: vmhgfsFATAL: Module vmhgfs not found.
vmmemctlFATAL: Module vmmemctl not found.
vmsyncFATAL: Module vmsync not found.
.
Starting open-vm guest daemon: vmware-guestd.
</pre></div>
<p>Чтобы собрать модули ядра, необходимые для работы, требуется поставить
пакет module-assistant .</p>
<div class="highlight"><pre><span></span>aptitude install module-assistant
</pre></div>
<p>И соберем с помощью него необходимые модули ядра:</p>
<div class="highlight"><pre><span></span>m-a a-i open-vm
</pre></div>
<p>На вопросы о установке необходимых пакетов, отвечаем утвердительно “Y”</p>
<p>Перезапустим демон утилит и порадуемся загруженным модулям:</p>
<div class="highlight"><pre><span></span>/etc/init.d/open-vm-tools restart
Stopping open-vm guest daemon: vmware-guestd.
Removing open-vm-tools modules: vmhgfs vmmemctl vmsync.
Loading open-vm-tools modules: vmhgfs vmmemctl vmsync.
Starting open-vm guest daemon: vmware-guestd.
</pre></div>
<p>Теперь у нас настроены основные драйвера для гостевой <span class="caps">OS</span>.</p>
<p>При просмотре стартового скрипта <span class="caps">VM</span> Tools видно, что перед запуском
драйверов и утилит от <span class="caps">VMWARE</span> идет проверка запущено ли все на реальном
или виртуальном железе. Соответственно при запуске вне виртуальной
машины (при нормальном запуске) скрипты не отработают и не будут мешать
нормальной работе.</p>
<p>Остается проблема смены имени сетевого интерфейса, которая решается
небольшой правкой конфигурационых файлов демона udev.</p>
<p>Для начала следует узнать мак адреса сетевых карт (реальной и
виртуальной) с помощью ifconfig (или другим удобным вам способом).</p>
<div class="highlight"><pre><span></span>ifconfig
eth0 Link encap:Ethernet HWaddr 00:0c:29:40:10:d5
inet addr:192.168.136.128 Bcast:192.168.136.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe40:10d5/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:26188 errors:0 dropped:0 overruns:0 frame:0
TX packets:12926 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:34105677 <span class="o">(</span>32.5 MiB<span class="o">)</span> TX bytes:1144113 <span class="o">(</span>1.0 MiB<span class="o">)</span>
Interrupt:19 Base address:0x2000
</pre></div>
<p>В данном случае имя интерфейса eth0 и он имеет <span class="caps">MAC</span> адрес
00:0c:29:40:10:d5.
При запуске в другом окружении естественно адрес будет другим ( и имя
интерфейса тоже). После того как мы получили список нужных нам адресов самое время
заглянуть в папку /etc/udev/rules.d/ :</p>
<div class="highlight"><pre><span></span>ls /etc/udev/rules.d/
50-udev.rules 75-cd-aliases-generator.rules
60-persistent-input.rules 75-persistent-net-generator.rules
60-persistent-storage.rules 80-drivers.rules
60-persistent-storage-tape.rules 91-permissions.rules
60-persistent-v4l.rules 95-late.rules
70-persistent-cd.rules z60_xserver-xorg-input-wacom.rules
70-persistent-net.rules
</pre></div>
<p>Самое интересное для нас хранится в файле 70-persistent-net.rules.
Это строки вида:</p>
<div class="highlight"><pre><span></span><span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"net"</span>, <span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>, <span class="nv">DRIVERS</span><span class="o">==</span><span class="s2">"?*"</span>, ATTR<span class="o">{</span>address<span class="o">}==</span><span class="s2">"00:0c:29:40:10:d5"</span>, ATTR<span class="o">{</span>type<span class="o">}==</span><span class="s2">"1"</span>, <span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"eth*"</span>, <span class="nv">NAME</span><span class="o">=</span><span class="s2">"eth0"</span>
</pre></div>
<p>Соответственно указав две строки с одинаковыми именами интерфейсов и
разными <span class="caps">MAC</span> адресами, соответвующие определеным устройствам вашей
реальнойвиртуальной сети мы вне зависимости от того как запущена ОС
будет получать одни и теже адреса. Трудности могут возникнуть в связи с
тем что в правилах в файле 75-persistent-net-generator.rules зачемто
указано игнорировать интерфейсы <span class="caps">VMWARE</span>. Это можно обойти двумя методами
на мой взгляд:</p>
<p>1. Комментирование строки <span class="caps">ENV</span>{<span class="caps">MATCHADDR</span>}==”00:0c:29:*|00:50:56:*”,
<span class="caps">ENV</span>{<span class="caps">MATCHADDR</span>}=”” чтобы для виртуальных карт создавались правила (
обычно этого не происходит).
2. Изменение в конфигурационном файле *.vmx к примеру строк с</p>
<div class="highlight"><pre><span></span>ethernet0.addressType <span class="o">=</span> <span class="s2">"generated"</span>
ethernet0.generatedAddress <span class="o">=</span> <span class="s2">"00:0c:29:ee:30:5a"</span>
ethernet0.generatedAddressOffset <span class="o">=</span> <span class="s2">"0"</span>
</pre></div>
<p>на</p>
<div class="highlight"><pre><span></span>ethernet0.addressType<span class="o">=</span><span class="s2">"static"</span>
ethernet0.Address <span class="o">=</span> <span class="s2">"00:0c:29:40:10:d5"</span>
</pre></div>
<p>При этом первые три числа вероятно надо будет сделать отличными от
00:0c:29:*|00:50:56:*. (Не знаю правда к чему может привести смена
стандартных мак адресов для виртуальной сетевухи).
Или можно комбинировать оба метода. Закомментировав строчку не
создающую строчку в конфиге udev и вписав статический мак адрес для
сетевой карты ( тогда адрес желательно начинать с 00:50:56:).</p>
<div class="section" id="id1">
<h2>Заключение</h2>
<p>Как видно настроить ваше операционную систему на работу в двух разных
окружениях не составляет большого труда. И к тому же можно не
использовать стандартные vmware-tools идущие в комплекте с программой, а
полностью перейти на открытую версию, что упрощает дальнейшие обновления
системы, т.к. не приходится следить за совместимоситью вручную, за вас
это сделали мейнтейнеры ОС.</p>
</div>
Восстановление загрузчика GRUB2009-04-03T23:55:00+03:00gigimontag:it4it.ru,2009-04-03:2009/04/03/vosstanovlenie-zagruzchika-grub/<p>Иногда бывает нужным восстановить linux загрузчик <span class="caps">GRUB</span> и каждый раз я
что-то забывал :) Приходилось лезть в книжку по генте и смотреть. Решил записать.</p>
<p>Для начала загрузимся с livecd. В моем случае это livecd с Gentoo.</p>
<p>Монтируем корневой раздел</p>
<div class="highlight"><pre><span></span>mount -t ext3 /dev/sda6 /mnt/gentoo
</pre></div>
<p>Затем монтируем /proc и /dev в систему, которой восстанавливаем загрузчик:</p>
<div class="highlight"><pre><span></span>mount -t proc none /mnt/gentoo/proc
mount -o <span class="nb">bind</span> /dev/ mnt/gentoo/dev
</pre></div>
<p>После, chroot’имся в систему:</p>
<div class="highlight"><pre><span></span>chroot /mnt/gentoo /bin/bash
</pre></div>
<p>Теперь делаем команду:</p>
<div class="highlight"><pre><span></span>grep -v rootf /proc/mounts > /etc/mtab
</pre></div>
<p>И восстанови загрузчик. Есть 2 способа, автоматчиеский и ручной.
Рассмотрим сначала первый:</p>
<p>Надо всего-лишь запустить 1 команду:</p>
<div class="highlight"><pre><span></span>grub-install --no-floppy /dev/sda6
</pre></div>
<p>ключ —no-floppy используется если нет флоповод.</p>
<p>Либо ручной режим:</p>
<div class="highlight"><pre><span></span>grub
</pre></div>
<p>В появившейся колнсоли:</p>
<div class="highlight"><pre><span></span>root <span class="o">(</span>hd0,5<span class="o">)</span> --- раздел с /boot
setup <span class="o">(</span>hd0<span class="o">)</span> --- установка в MBR
quit
</pre></div>
<p>Все, после этого ребутимся и видим <span class="caps">GRUB</span> (ну если все хорошо прошло :)</p>
“Вечный” сервер :)2009-03-22T00:03:00+02:00gigimontag:it4it.ru,2009-03-22:2009/03/22/vechnyj-server/<p>Имеется в моем подчинении 1 сервер на Win2003, работает нормально,
достаточно по долгу (аптайму больше месяца мешает свет, даже <span class="caps">UPS</span> не
спасает :( ). В очередной раз, решил залезть на него, посмотреть его
аптайм и логи, моему удивлению не было предела, когда я увидел ЭТО:</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/gluk.png"><img alt="глюк" src="http://it4it.ru/images/2009/03/gluk.png" /></a></p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/gluk.png"><img alt="Посмотрите аптайм" src="http://it4it.ru/images/2009/03/gluk-449x227.png" /></a></p>
<p>Как видно из скриншота, аптайм сервера 6 лет! и это при учете, что
винда там установлена с начала 2008 года :)
Ну, чтобы не подумали что переводил время, скрин часов (говорю
честно, не менял, т.к. сервер держатель домена и бухгалтерии, где очень
важно изменение времени):</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/datetime.png"><img alt="Часики" src="http://it4it.ru/images/2009/03/datetime.png" /></a></p>
Обзорчик Bluetooth наушников Sony DR-BT21G и история выбора2009-03-12T00:55:00+02:00gigimontag:it4it.ru,2009-03-12:2009/03/12/obzorchik-bluetooth-naushnikov-sony-dr-bt21g-i-istoriya-vybora/<p>На протяжении последних пару лет, я очень хотел себе Bluetooth наушники,
но из-за дороговизны и нераспространенности их, только пускал слюни на
фотки в интернете :) Последние полгода, я активно искал наушники на
заказ в Украине, т.к. появилась работа, деньги, хотел свою мечту
исполнить :))</p>
<p>Сначала я смотрел на наушники от Logitech, но как оказалось потом, они
были не <span class="caps">BT</span>, а использовали свой передатчик :( (как и все от Logitech).
После этого, я наткнулся на гарнитурки от Genius и возможностью их
заказа в городе, вот такие модельки: <a class="reference external" href="http://genius.ru/Product.aspx?ProductID=15047&archive=0"><span class="caps">BT</span>-02N <span class="caps">SE</span></a>, <a class="reference external" href="http://genius.ru/Product.aspx?ProductID=13669&archive=0"><span class="caps">BT</span>-03A</a> , но
почитав интернет, было много отрицательных отзывов, не решился, т.к. 120
баксов :(</p>
<p>А примерно полугода назад, на сайте Sony увидел я <span class="caps">DR</span>-<span class="caps">BT21G</span> и был просто
в шоке. Во-первых на вид они офигенны, во-вторых по характеристикам
достойны, в-третьих по малочисленным отзывам, она действительно хорошо играла.</p>
<p>И вот, когда я полгода искал по интернет магазинам ее, и не находил, я
случайно зашел в магазин Фокстрот (суперкмаркеты техники, типа
эльдорадо, только в Украине) и увидел ее, за 400 гривен (меньше 50
долларов), новую, с гарантией, в упаковке!!!</p>
<p>Теперь, после недели ее использования, хочу рассказать про нее.</p>
<p>Итак, первое, конструкция.</p>
<p>Наушники складные, с затылочным креплением на голове, достаточно
небольшие в раскрытом виде и компактные в складном виде (в карман
рубашки помещаются легко). Привожу 2 фотографии в сравнении с обычной
комп мышкой:</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/dsc00047.jpg"><img alt="Собраный вид" src="http://it4it.ru/images/2009/03/dsc00047-450x320.jpg" /></a></p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/dsc00046.jpg"><img alt="Раскрытый вид" src="http://it4it.ru/images/2009/03/dsc00046-449x339.jpg" /></a></p>
<p>Шарниры, в которых она складывается, на вид выглядят надежно, они с
фиксатором, не шатаются.</p>
<p>Кнопки находятся только на правом наушнике, их:</p>
<ol class="arabic simple">
<li>Кнопкауправления громкостью, они являются единой кнопкой</li>
<li>Кнопка питания (и управления спариванием)</li>
<li>Кнопка управления плеером. Она ходит в обе стороны (песня
вперед/назад) и нажимается (старт/стоп)</li>
<li>Кнопка управления телефоном (ответить, активировать голосовой набор)</li>
<li>Собственно это не кнопка :) просто микрофон</li>
<li>Индикатор - два светодиода, голубой и розовый.</li>
</ol>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/dsc00050_2.jpg"><img alt="Кнопки" src="http://it4it.ru/images/2009/03/dsc00050_2-450x372.jpg" /></a></p>
<p>Управляющие кнопки нажимаются достаточно легко, с ходом, который можно почувствовать.</p>
<p>Теперь, рассмотрим взаимодействие с устройствами.</p>
<p>Т.к. наушники поддерживают одновременную связь с несколькими
устройствами, то проверялись они в таком режиме достаточно долго (если
так можно гвоорить о неделе использования вообще наушников :)
Спаривание устройств происходит 1 раз (наушники помнят до 10 устройств)
простым зажатием вкнопки включения на 7 секунд и последующим добавлением
их на телефоне/плеере/кпк. После этого, в любое время к ним может
подключиться знакомое устройство.</p>
<p>Я подключал телефон <span class="caps">SE</span> k800 и КПК Dell Axim x51v ( с <span class="caps">WM6</span>.1 и Broadcom драйверами).</p>
<p>При подключеных кпк и телефоне, управление музыкой происходит на КПК,
всеравно в какой последовательности он был подключен, а кнопки телефона
управляют непосредственно телефоном (включение голосового набора,
ответ). Очень приятным сюрпризом стало, что когда звонят на телефон, то
наушники останавливают плеер, а после звонка, включают его с того же места.</p>
<p>С подключением устройств и управления ими нареканий нет никаких. К
сожалению, при использовании одного телефона, я заметил странность. Где
бы телефон не лежал, при повороте головы вправо, связь прерывается, а
возвращая голову вперел, продолжается играть музыка. При использовании
КПК как плеера, такой проблемы нет, даже если он лежит в рюкзаке.</p>
<p>И вот, добрались до главной части, оценка качества звука.</p>
<p>Качество звука я проверял на свой слух на разнообразной музыки
проигрываемой с телефона и КПК, а также слушанием подкастов и приемом
звонков с мобильного (сравнивая с проводными наушниками Sennheiser
pmx100), парочкой друзей с разными музыкальными вкусами и возможностями,
и 1 “меломан” с почти музыкальным слухом с тяжелым роком. Сразу
оговорюсь, вся музыка была в mp3 с битрейтом от 192 до 320.</p>
<p>Я, как человек не сильно разбирающийся в музыке, слушал поочередно
синхайзеры и сони. Высокие и низкие отличаются не сильно, басы лучше у
сони (на удивление), и сони не начинают трещать при максимальной
громкости. На всех прослушаных композициях, сони были сравнимы или лучше
чем синхайзеры.</p>
<p>Друг, любитель тяжелой музыки, сразу сказал что Сони лучше. Помимо
синхайзеров, он сравнивал с достаточно качественными наушниками от
Walkman телефонов SonyEricsson. После такой оценки, был горд за Сони.</p>
<p>И последнее, сколько они живут :)</p>
<p>По моим замерам, при использовании с КПК и телефоном сразу в режиме
прослушивания музыки, они живут до 10-11 часов - это я слушал чтобы их
убить. Если слушать в моем режиме (2-3 часа музыки в день, часов 6 в
режиме ожидания), то они прожили 4 дня, что для себя, считаю
великолепным показателем.</p>
<p>На примере наушников Sony, я считаю, что Bluetooth наушники уже достигли
хорошего качества и времени работы, так что те, кто против проводов,
стоит задуматься над покупкой ;)</p>
Установка WindowsXP с флэшки 22009-03-11T00:36:00+02:00gigimontag:it4it.ru,2009-03-11:2009/03/11/ustanovka-windowsxp-s-fleshki-2/<p>После нескольких комментариев в первой версии установки WinXp с флэшки,
решил написать вторую, т.к. нашел другой образ (даже несколько) да и
немного более универсальную программку для записи образа на флэшку. Итак
приступим, для начала, надо скачать программу, которая записывает образ
на флэшку <a class="reference external" href="http://it4it.ru/files/flashboot_140.rar">FlashBoot</a>, а также <a class="reference external" href="http://it4it.ru/images/2009/03/boot98sc.rar">образ</a> “дискетки” созданую для Win98
:) (есть еще вот такой
<a class="reference external" href="http://it4it.ru/images/2009/03/universalbootdisk3_6.rar">образ</a>,
более навороченый, с поддержкой <span class="caps">NTFS</span> и парой полезных утилит, а вообще
их много всяких).</p>
<p>После этого устанавливаем FlashBoot, и копируем license.xml из архива, в
папку куда установили FlashBoot (C:Program FilesFlashBoot). После этого
распаковываем наш образ дискетки, запоминаем путь, куда распаковали.</p>
<p>Теперь запуска FlashBootWizard и жмем Next и устанавливаем в нем галочку
напротив Create Bootable flash disk as a copy of <span class="caps">DOS</span>-based floopy-disk</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/fbmain.png"><img alt="Главное окно FlashBoot" src="http://it4it.ru/images/2009/03/fbmain-450x315.png" /></a></p>
<p>После этого жмем Next, выбираем Load Image file available locally or via
network и выбираем наш файл-образ дискетки.</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/03/fbfile.png"><img alt="fbfile" src="http://it4it.ru/images/2009/03/fbfile-449x316.png" /></a></p>
<p>Жмем Next, и выбираем букву вставленной флэшки (предварительно
рекомендую ее отформатировать в <span class="caps">FAT</span>, и желательно чтобы флэшка была до
2-х Гб), жмем Next и пойдет запись на флэшку. Если все прошло успешно,
вылетит окошко что все хорошо :)</p>
<p>После этого, на эту флэшку надо скопировать папочку I386 с вашего
установочного диска WindowsxXP (можно даже с лицензионного-поставится нормально).</p>
<p>После перезагрузки и выбора загрузки с флэшки, мы загрузимся в сеанс
<span class="caps">MS</span>-<span class="caps">DOS</span>, где можно будет отформатировать диск (format), переразбить
жесткий (fdisk-ОСТОРОЖНО! Данные не сохранятся). Для установки WinXp,
сначала запускаем файл smartdrv, затем выполняем команды</p>
<dl class="docutils">
<dt>::</dt>
<dd>cd i386 winnt.exe</dd>
</dl>
<p>После этого, должен запуститься установщик WinXP. Сразу оговорю, что
должен быть хотя бы 1 раздел с <span class="caps">FAT</span> системой и объемом не меньше 2-х Гб</p>
Запуск Django с использованием mod_wsgi2009-02-24T01:03:00+02:00gigimontag:it4it.ru,2009-02-24:2009/02/24/zapusk-django-s-ispolzovaniem-mod_wsgi/<p>После недавнего окончания разработки первого своего сайта на Django,
пришло время его выставлять в свет :) Для этого на <span class="caps">VPS</span>, где крутился
Apache2, был установлен mod_wsgi. Чтобы заставить работать Django сайт
с mod_wsgi, надо лишь немного поправить конфиг Apache для вашего
виртуального хоста, и написать небольшой скрипт. В моем примере, сайт
будет лежать в /var/www/domain.net/www/ . Такая вложенность получилась
не просто так, при попытке запуска сайта из /var/www/domain.net, я
ловил ошибку о ненахождении модулей :(</p>
<p>Первое что сделаем, изменим запись о хосте. Открываем файл, где
прописаны настройки виртуального хоста и добавляем:</p>
<div class="highlight"><pre><span></span>ServerAdmin aliens@it4it.ru
ServerName domain.net
ServerAlias www.domain.net
DocumentRoot /var/www/domain.net/www
CustomLog /var/log/apache2/domainl-access.log combined
ErrorLog /var/log/apache2/domain-error.log
<span class="c1">#вот этой стрчокой прописываем алиас до вашей статики в виде: /урл_статики /папка_статики</span>
Alias /static/ /var/www/domain.net/www/media/
<span class="c1">#настройки wsgi, от чьего имени запускать и количество запросов и потоков</span>
WSGIProcessGroup aliens
WSGIDaemonProcess aliens <span class="nv">user</span><span class="o">=</span>aliens <span class="nv">group</span><span class="o">=</span>www-data <span class="nv">threads</span><span class="o">=</span><span class="m">2</span> maximum-requests<span class="o">=</span>1000
<span class="c1">#путь до скрипта, который будет запускать наш джанго проект</span>
WSGIScriptAlias / /var/www/domain.net/www/django.wsgi
<span class="c1">#алиас до статики для админки</span>
Alias <span class="s2">"/media/"</span> <span class="s2">"/var/lib/python-support/python2.5/django/contrib/admin/media/"</span>
SetHandler None
Order deny,allow
Allow from all
</pre></div>
<p>После этого, создаем и редактируем
файл /var/www/domain.net/www/django.wsgi с таким содержимым:</p>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">os.path</span>
<span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>
<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">'DJANGO_SETTINGS_MODULE'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'settings'</span>
<span class="kn">from</span> <span class="nn">django.core.handlers.wsgi</span> <span class="kn">import</span> <span class="n">WSGIHandler</span>
<span class="n">application</span> <span class="o">=</span> <span class="n">WSGIHandler</span><span class="p">()</span>
</pre></div>
<p>Все, после этого проверить права на файлы, и можно перезапускать Apache
и проверять работоспособность сайта.</p>
<p>Хочу предупредить, после любого изменения файлов сайта, надо
перезагрузить Apache</p>
Установка ejabberd с хранением данных в MySQL2009-02-06T20:47:00+02:00gigimontag:it4it.ru,2009-02-06:2009/02/06/ustanovka-ejabberd-s-xraneniem-dannyx-v-mysql/<p>Установка jabber сервера на свой сервер достаточно проста и производится
минут за 20 :)</p>
<blockquote>
Итак приступим:</blockquote>
<p>Для начала устновим ejabberd</p>
<div class="highlight"><pre><span></span>apt-get install ejabberd
</pre></div>
<p>Затем идем редактировать конфиг</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /etc/ejabberd
nano ejabberd.cfg
</pre></div>
<p>Редактируем строку admin:</p>
<div class="highlight"><pre><span></span>%% Admin user
<span class="o">{</span>acl, admin, <span class="o">{</span>user, <span class="s2">"admin_nick"</span>, <span class="s2">"host_server"</span><span class="o">}}</span>.
</pre></div>
<p>где, admin_nick ник того, кто может управлять серверов через веб и
другими средствами, host_server - это сервер, которым он может управлять</p>
<p>Потом меняем host:</p>
<div class="highlight"><pre><span></span>%% Hostname
<span class="o">{</span>hosts, <span class="o">[</span><span class="s2">"yourhost"</span><span class="o">]}</span>.
</pre></div>
<p>yourhost - ваш домен, где будет висеть жаббер сервер</p>
<p>Далее в секции listen, устанавливаем так:</p>
<div class="highlight"><pre><span></span><span class="o">{</span>5222, ejabberd_c2s, <span class="o">[</span>
<span class="o">{</span>access, c2s<span class="o">}</span>,
<span class="o">{</span>shaper, c2s_shaper<span class="o">}</span>,
<span class="o">{</span>max_stanza_size, 65536<span class="o">}</span>,
starttls, <span class="o">{</span>certfile, <span class="s2">"path_to_cert"</span><span class="o">}</span>
<span class="o">]}</span>,
%%
%% To <span class="nb">enable</span> the old SSL connection method <span class="o">(</span>deprecated<span class="o">)</span> in port 5223:
%%
<span class="o">{</span>5223, ejabberd_c2s, <span class="o">[</span>
<span class="o">{</span>access, c2s<span class="o">}</span>,
<span class="o">{</span>shaper, c2s_shaper<span class="o">}</span>,
<span class="o">{</span>max_stanza_size, 65536<span class="o">}</span>,
tls, <span class="o">{</span>certfile, <span class="s2">"path_to_cert"</span><span class="o">}</span>
<span class="o">]}</span>,
<span class="o">{</span>5269, ejabberd_s2s_in, <span class="o">[</span>
<span class="o">{</span>shaper, s2s_shaper<span class="o">}</span>,
<span class="o">{</span>max_stanza_size, 131072<span class="o">}</span>
<span class="o">]}</span>,
<span class="o">{</span>5280, ejabberd_http, <span class="o">[</span>
http_poll,
web_admin
<span class="o">]}</span>
</pre></div>
<p>Для регистрации через клиент, надо изменить в секции <span class="caps">ACCESS</span> <span class="caps">RULES</span>:</p>
<div class="highlight"><pre><span></span><span class="o">{</span>access, register, <span class="o">[{</span>deny, all<span class="o">}]}</span>. на <span class="o">{</span>access, register, <span class="o">[{</span>allow, all<span class="o">}]}</span>.
</pre></div>
<p>Для активации прослушивания портов и поддержки ssl соединений, а также
серверов со старым <span class="caps">SSL</span>.</p>
<div class="highlight"><pre><span></span><span class="o">{</span>s2s_certfile, <span class="s2">"path_to_cert"</span><span class="o">}</span>.
</pre></div>
<p>path_to_cert - путь к сертификату 9который сделаем чуть ниже)</p>
<p>Дальше включаем режим аутентификации через БД</p>
<div class="highlight"><pre><span></span><span class="o">{</span>auth_method, odbc<span class="o">}</span>.
</pre></div>
<p>В секции <span class="caps">DATABASE</span> <span class="caps">SETUP</span> раскомментируем секцию для базы которую будем
использовать (MySQL, <span class="caps">PG</span> и др), а также устаналиваем параметры соединения</p>
<div class="highlight"><pre><span></span><span class="o">{</span>odbc_server, <span class="o">{</span>mysql, <span class="s2">"server"</span>, 1234, <span class="s2">"database"</span>, <span class="s2">"username"</span>, <span class="s2">"password"</span><span class="o">}}</span>.
</pre></div>
<p>В секции modules заменяем</p>
<div class="highlight"><pre><span></span><span class="o">{</span>mod_last, <span class="o">[]}</span>, на <span class="o">{</span>mod_last_odbc, <span class="o">[]}</span>,
<span class="o">{</span>mod_offline, <span class="o">[]}</span>, на <span class="o">{</span>mod_offline_odbc, <span class="o">[]}</span>,
<span class="o">{</span>mod_roster, <span class="o">[]}</span>, на <span class="o">{</span>mod_roster_odbc, <span class="o">[]}</span>,
<span class="o">{</span>mod_vcard, <span class="o">[]}</span>, на <span class="o">{</span>mod_vcard_odbc, <span class="o">[{</span>search, true<span class="o">}</span>,
<span class="o">{</span>matches, infinity<span class="o">}</span>,
<span class="o">{</span>allow_return_all, true<span class="o">}]}</span>,
</pre></div>
<p>В mod_register можете поменять текст сообщения, которое будет
присылается новому зарегистрированному пользователю.</p>
<p>После этого, установим базу данных ejabberd. для MySQL базу берем <a class="reference external" href="http://svn.process-one.net/ejabberd/trunk/src/odbc/mysql.sql">тут</a></p>
<p>Импортируем ее любым доступным для вас способом, через phpmyadmin или
ручками, или еще как:</p>
<div class="highlight"><pre><span></span>mysql -D ejabberd -p -u ejabberd < mysql.sql
</pre></div>
<p>Для дебиана, надо установить клиент к БД. пакет можно взять <a class="reference external" href="http://blog.jwchat.org/download/ejabberd-mysql-20090114_1-2_all.deb">здесь</a></p>
<p>Теперь сгенерируем сертификат для работы сервера:</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /etc/ejabberd/
openssl rsa -in ssl.key -out ssl.key
cat ssl.crt ssl.key sub.class1.xmpp.ca.crt >ejabberd.pem
chown ejabberd.ejabberd ejabberd.pem
chmod <span class="m">400</span> ejabberd.pem
</pre></div>
<p>После этого можно запускать сервер:</p>
<div class="highlight"><pre><span></span>/etc/init.d/ejabberd start
</pre></div>
<p>Добавить первого пользователя можно через ejabberdctl:</p>
<div class="highlight"><pre><span></span>Первого пользователя зарегистрируйте админа :<span class="o">)</span>
Также, есть небольшая админка по адресу http://ваш_зост:5280/admin
Куда надо ввести jid админа и его пароль, чтобы войти.
Еще, иногда требуется добавить SRV поля для вашего домена в ДНС сервер:
_jabber._tcp IN SRV <span class="m">0</span> <span class="m">0</span> <span class="m">5269</span> ваш_домен_с_жаббером.
_xmpp-server._tcp IN SRV <span class="m">0</span> <span class="m">0</span> <span class="m">5269</span> ваш_домен_с_жаббером.
_xmpp-client._tcp IN SRV <span class="m">0</span> <span class="m">0</span> <span class="m">5222</span> ваш_домен_с_жаббером.
</pre></div>
<p>Все, после этого все должно работать :)</p>
Отдаем сгенерированную картинку сайту без сохранения2009-01-26T01:00:00+02:00gigimontag:it4it.ru,2009-01-26:2009/01/26/otdaem-sgenerirovannuyu-kartinku-sajtu-bez-soxraneniya/<p>Хочу рассказать немного про генерацию картинок и их отдачу на лету, с
помощью 1 примера, где надо было генерирвоать по полученым параметрам
(от js) картинку и отдавать ее - эта картинка становилась фоном. Если о
генерации ее вопросов не было, появился вопрос о том, как ее отдать. На
1 англйиском сайте нашел простео объяснение, что можно отдавать в
request. И так, пример:
В html страничке, делаем такой скрипт:</p>
<div class="highlight"><pre><span></span><span class="kd">var</span> <span class="nx">height</span> <span class="o">=</span> <span class="nx">innerHeight</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">width</span> <span class="o">=</span> <span class="nx">innerWidth</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">background</span> <span class="o">=</span> <span class="s2">"/utils/genback/?width="</span><span class="o">+</span><span class="nx">width</span><span class="o">+</span><span class="s2">"&height="</span><span class="o">+</span><span class="nx">height</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundAttachment</span> <span class="o">=</span> <span class="s1">'fixed'</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">backgroundPosition</span> <span class="o">=</span> <span class="s1">'right center'</span><span class="p">;</span>
</pre></div>
<p>Он узнает размера окна браузера и передает их скрипту по
адресу /utils/genback/?width=”+width+”&height=”+height; с помощью <span class="caps">GET</span>
запроса. В ответ получает картинку и устанавливает ее фоном. На стороне
сервера имеем вот такой скрипт: /utils/genback/?width=”+width+”&height=”+height;</p>
<p>На стороне сервера у нас такой скрипт:</p>
<div class="highlight"><pre><span></span><span class="c1">#-*-coding:utf8-*-</span>
<span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span><span class="p">,</span> <span class="n">ImageDraw</span>
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
<span class="k">def</span> <span class="nf">generation_background</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'GET'</span><span class="p">:</span>
<span class="n">screen_width</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'width'</span><span class="p">])</span>
<span class="n">screen_height</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">GET</span><span class="p">[</span><span class="s1">'height'</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">screen_width</span> <span class="o">=</span> <span class="mi">1024</span>
<span class="n">screen_height</span> <span class="o">=</span> <span class="mi">768</span>
<span class="n">COLOR</span> <span class="o">=</span> <span class="p">(</span><span class="mi">240</span><span class="p">,</span> <span class="mi">239</span><span class="p">,</span> <span class="mi">239</span><span class="p">,</span> <span class="mi">128</span><span class="p">)</span>
<span class="n">image</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"RGBA"</span><span class="p">,</span> <span class="p">(</span><span class="n">screen_width</span><span class="p">,</span> <span class="n">screen_height</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
<span class="n">draw</span> <span class="o">=</span> <span class="n">ImageDraw</span><span class="o">.</span><span class="n">Draw</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
<span class="n">draw</span><span class="o">.</span><span class="n">ellipse</span><span class="p">((</span><span class="mi">100</span><span class="p">,</span> <span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="mi">100</span><span class="o">+</span><span class="n">screen_width</span><span class="p">,</span> <span class="o">-</span><span class="mi">30</span><span class="o">+</span><span class="n">screen_width</span><span class="p">),</span> <span class="n">fill</span><span class="o">=</span><span class="n">COLOR</span><span class="p">,</span> <span class="n">outline</span><span class="o">=</span><span class="n">COLOR</span><span class="p">)</span>
<span class="k">del</span> <span class="n">draw</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="n">mimetype</span><span class="o">=</span><span class="s2">"image/png"</span><span class="p">)</span>
<span class="n">image</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="s1">'PNG'</span><span class="p">)</span>
<span class="k">return</span> <span class="n">response</span>
</pre></div>
<p>Данный скрипт, получает из <span class="caps">GET</span> запроса размеры, генерирует по ним фон
(круг), устанавливает тип запроса image/png: response =
HttpResponse(mimetype=”image/png”), сохраняет картинку в request и
возвращает ее.</p>
<p>Конечно специалисты и так знают, а новичкам в django будет помощь :)</p>
Собираем миранду до …2009-01-17T16:18:00+02:00gigimontag:it4it.ru,2009-01-17:2009/01/17/sobiraem-mirandu-do/<p>После чтения множестваспоров о том, что лучше, миранда или квип,
аргументы что миранду тяжело собрать до уровня квипа, решил написать
небольшйо мануал по сборке миранды.</p>
<p>Первое что надо сделать, скачать дистрибутив миранды. Все ниже описанное
будет проводиться на разрабатываемой версии 0.8 Test Build 26 Unicode,
взятая <a class="reference external" href="http://files.miranda-im.org/builds/miranda-v080a26w.zip">здесь</a></p>
<p>После этого, распакуем куда нибудь. И уберем ненужные нам файлы
(ChangeLog.txt и в папке plugins не нужные протоколы и плагины). В папке
plugins я удалил файлы:</p>
<p>chat.dll - плагин для поддержки чатов</p>
<p>clist_classic.dll, clist_mw.dll, clist_nicer.dll - плагины для вывода
контакт листа. Это разные вариации, мы будем использовать clist_modern.dll</p>
<p><span class="caps">GG</span>.dll, irc.dll, jabber.dll, msn.dll, yahoo.dll - плагины для поддержки
различных протоколов.</p>
<p>scriver.dll, srmm.dll - плагины для создания окон чата</p>
<p>Теперь <a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=3415">скачаем</a> файл русификации и распакованый положим в корень папки миранды.</p>
<p>После надо скачать и добавить некоторые полезные плагины:</p>
<p><a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=2455">smileyadd</a> unicode - поддержка смайликов</p>
<p><a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=1788">ieview</a> - окно чата с поддержкой Html тэгов, скинов, использующее
движок <span class="caps">IE</span> для вывода.</p>
<p><a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=2995">history++</a> - мощная система для ведения логов</p>
<p><a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=3717">tipper</a> - вывод всплывающего информационного окна для контакта</p>
<p><a class="reference external" href="http://addons.miranda-im.org/feed.php?dlfile=3526">fingerprint</a> - опознавание клиентов собеседников</p>
<p>После того как скачаете, распаковываете все, все .dll ложите в папку
plugins, а остальыне папки которые будут, в корень миранды (только
ieview и папку и .dll положить в plugins)</p>
<p>Теперь запустим миранду miranda32.exe. Появится окно для создания вашего
файла профиля, пишем любое имя.</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/01/crdb.png"><img alt="crdb" src="http://it4it.ru/images/2009/01/crdb.png" /></a></p>
<p>После ввода имени, жмем Создать. Увидим контакт лист и окно добавления
учетных записей. жмем на зеленый плюсик, и в появившемся окне вписываем
название учетной записи и выбираем протокол <span class="caps">ICQ</span>:</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/01/cruser.png"><img alt="cruser" src="http://it4it.ru/images/2009/01/cruser.png" /></a></p>
<p>Жмем ОК, выбираем созданую учетку, и вписываем свои <span class="caps">ICQ</span> номер и пароль и
жмем Ок</p>
<p>Увидим наш КЛ, теперь можем подключиться к сети.</p>
<p>После этого, будем настраивать наши плагины. заходим в настройки
(нажимаем на значок миранды, корону, настройки).</p>
<ol class="arabic simple">
<li>Настраиваем наше окно чата:</li>
</ol>
<p>Беседы-Журнал-Основной журнал сообщений —- выбираем IEView</p>
<p>Беседы-Журнал-Параметры —- Поддержка BBCode</p>
<p>Беседы-Журнал IEView-Общее —- Поддержка BBCode, Поддержка flash,
Включить прозрачность для <span class="caps">PNG</span></p>
<p>Беседы-Чаты —- Включить интеграцию чата</p>
<p>После этого перегружаем миранду.</p>
<p>Потом выбираем любой контакт, чтобы открыть окно чата, жмем
Контейнер-Настройки контейнера-Окно —- ставим галочки у Скрыть меню,
Показать инфо-панель</p>
<ol class="arabic simple" start="2">
<li>Настроим плагин <span class="caps">ICQ</span></li>
</ol>
<p>Настройки-Сеть-Входящие (и исходящие) сообщения —- Поставить галочку
Порты и вписать: 1050-1100, 2000-2900,34891, 32528, 26120</p>
<p>Сеть-<название вашего аккаунта <span class="caps">ICQ</span>, который писали в начале>
-Возможности —- Поставить галочку: только подтверждение с сервера.</p>
<ol class="arabic simple" start="3">
<li>Настроим всплывающее окно с информацией контактов</li>
</ol>
<p>Тонкая настройка-Подсказки —- и выбираете все на свой вкус :)</p>
<ol class="arabic simple" start="4">
<li>Настройка контакт листа</li>
</ol>
<p>Список контактов-Элементы строк-Аватар —- Значки на аватарах-Значок контакта</p>
<p>Список контактов-Элементы строк-Значок —- прятать значок протокола,
Значок хСтатуса вместо пзначка протокола</p>
<p>Список контактов-Элементы строк-Экстра значки —- Снять галчоки с
Протокол, Телефон/<span class="caps">SMS</span>, Web страница.</p>
<p>Т.к. все по русски, поизменяйте все на свой вкус.</p>
<p>Последний этап, это установка скинов.</p>
<ol class="arabic simple">
<li>Установим скин на КЛ</li>
</ol>
<p>Качаем любой стиль для Modern CList <a class="reference external" href="http://addons.miranda-im.org/index.php?action=display&id=93">отсюда</a></p>
<p>Я скачал BlackStyle. распаковываем его в корень мирандыthemesmodern</p>
<p>После этого, идем в</p>
<p>Настройки-Тонкая настройка-Скин списка —- жмем кнопку Обзор, выбираем
папку, куда скопировали скин и выбираем .msf файл, жмем Ок. Этот скин
появится в обозревателе, выберем его и нажмем применить. Вы могли
заметить, что у некоторых скинов есть свои кнопки быстрого доступа, и
получается две панели одинаковых кнопок. Чтоыб отключить кнопки миранды,
надо зайти:</p>
<p>Настройки-Тонкая настройка-Панель кнопок и снять галочку с Кнопки в
панели кнопок.</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/01/clist.png"><img alt="clist" src="http://it4it.ru/images/2009/01/clist.png" /></a> <a class="reference external" href="http://it4it.ru/images/2009/01/clist.png"><img alt="image0" src="http://it4it.ru/images/2009/01/clist.png" /></a></p>
<ol class="arabic simple" start="2">
<li>Установка скина для окна разговора (чата)</li>
</ol>
<p>Качаем любой скин для tabSrmm
<a class="reference external" href="http://addons.miranda-im.org/index.php?action=display&id=90">отсюда</a></p>
<p>Я взял скин BlackStyle. Скачаный архив распаковываем в tabsrmmskins</p>
<p>Потом идем в Настройки-Тонкая настройка-Скин окна беседы, жмем на “…”
и выбираем файл .tsk из распакованной папки. Ставим галочки на:
загружать этот скин при старте, загружать шрифты из скина. Жмем на
кнопку Применить скин</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/01/chat.png"><img alt="chat" src="http://it4it.ru/images/2009/01/chat.png" /></a></p>
<ol class="arabic simple" start="3">
<li>Установка скина для списка сообщений (ieview)</li>
</ol>
<p>Качаем
<a class="reference external" href="http://addons.miranda-im.org/index.php?action=display&id=83">отсюда</a>
любой скин для ieview и распаковываем его в themesieview</p>
<p>Затем, идем в</p>
<p>Настройки-Беседы-Журнал IEView-Журнал —- выбираем Шаблон, жмем “…”,
выбираем наш скин .ivt</p>
<ol class="arabic simple" start="4">
<li>Осталось последнее, поменять иконки статусов.</li>
</ol>
<p>Качаем стандартный набор <span class="caps">ICQ</span> иконок, распаковывем в Icons</p>
<p>Настройки-Значки-Статус-<span class="caps">ICQ</span>, жмем кнопку Выбрать набор значков, и
выбираем распакованный .dll файл, все иконки <span class="caps">ICQ</span> поменяются</p>
<p>В итоге получил :</p>
<p><a class="reference external" href="http://it4it.ru/images/2009/01/all.png"><img alt="all" src="http://it4it.ru/images/2009/01/all.png" /></a></p>
<p>К сожалению, не очень удачный скин, т.к. цвет шрифтов черный и совпадает
с фоном. Но думаю, вы сможете найти хорошие скины, это самое сложное )</p>
Рисуем с помощью PIL2009-01-16T14:58:00+02:00gigimontag:it4it.ru,2009-01-16:2009/01/16/risuem-s-pomoshhyu-pil/<p>Недавно потребовалось мне создавать картинку на лету. Решил спользовать
библиотеку для питона <span class="caps">PIL</span>. Она поддерживает кучу форматов, а также
множество цветовых систем (<span class="caps">RGB</span>, <span class="caps">RGBA</span> и более простые). Итак, рассмотрим
простейшее, как создать рисунок и что-либо на нем нарисовать.</p>
<p><img alt="image0" src="http://www.it4it.ru/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif" /></p>
<p>Для начала, подключим нужные модули.</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span><span class="p">,</span> <span class="n">ImageDraw</span>
</pre></div>
<p>Модуль Image управляет непосредственно источником изображения, позволяет
создавать, сохранять, октрывать рисунок. А ImageDraw, отвечает
непосредственно за рисование геометрических объектов.</p>
<p>Теперь создадим новый рисунок:</p>
<div class="highlight"><pre><span></span><span class="n">image</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"RGBA"</span><span class="p">,</span> <span class="p">(</span><span class="mi">320</span><span class="p">,</span><span class="mi">320</span><span class="p">),</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span>
</pre></div>
<p>Здесь, первый параметр это тип картинки, может быть: 1 (черно-белый), L
(монохромный, оттенки серого), <span class="caps">RGB</span>, <span class="caps">RGBA</span> (<span class="caps">RGB</span> с альфа каналом), <span class="caps">CMYK</span>,
YCbCr, I (32 bit Integer pixels), F (32 bit Float pixels).</p>
<p>Второй параметр, это объект типа tuple задающий размер изображения.</p>
<p>Третий параметр, это непосредственно цвет, т.к. у нас <span class="caps">RGBA</span>, то запись
(0,0,0,0) соответствует полной прозрачности.</p>
<p>После этого, чтобы нарисовать на нем что-либо, требуется создать объект
ImageDraw и передать ему наш рисунок:</p>
<div class="highlight"><pre><span></span><span class="n">draw</span> <span class="o">=</span> <span class="n">ImageDraw</span><span class="o">.</span><span class="n">Draw</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
</pre></div>
<p>Попробуем нарисовать красный эллипс:</p>
<div class="highlight"><pre><span></span><span class="n">draw</span><span class="o">.</span> <span class="n">ellipse</span><span class="p">((</span><span class="mi">10</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mi">300</span><span class="p">,</span><span class="mi">300</span><span class="p">),</span> <span class="n">fill</span><span class="o">=</span><span class="s2">"red"</span><span class="p">,</span> <span class="n">outline</span><span class="o">=</span><span class="s2">"red"</span><span class="p">)</span>
</pre></div>
<p>Здесь мы рсиуем эллипс, с координатами начальными: 10,10, и конечными:
300,300. Также, параметр fill задает цвет заливки, а outline - цвет
контура. Помимо кодовых названий, можно использовать <span class="caps">HTML</span> запись, либо
<span class="caps">RGB</span>(A) в виде tuple элемента.</p>
<p>Из доступных для рисования фигур доступны: кривая, линия, текст,
вырезаный эллипс, точка, полигон.</p>
<p>После этого удалим draw и сохраним рисунок:</p>
<div class="highlight"><pre><span></span><span class="k">del</span> <span class="n">draw</span>
<span class="n">image</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s2">"/path/to/save/test.png"</span><span class="p">,</span> <span class="s2">"PNG"</span><span class="p">)</span>
</pre></div>
<p>После этого мы получи .png файл, в котором будет красный круг на
прозрачном фоне :</p>
<p><img alt="Пример" src="http://it4it.ru/images/2009/01/test.png" /></p>
<p>Вот, думаю для начального понимания поможет кому-нибудь.</p>
<p>Нашел <a class="reference external" href="http://it4it.ru/images/2009/01/pil.pdf">краткую документацию</a> по официальной документации.</p>
<p>Официальный <a class="reference external" href="http://www.pythonware.com/library/pil/handbook/index.htm">сайт</a> с документацией</p>
Подключаем монитор и телевизор по hdmi2009-01-03T20:47:00+02:00gigimontag:it4it.ru,2009-01-03:2009/01/03/podklyuchaem-monitor-i-televizor-po-hdmi/<p>Последние 3 месяца заместо плохого по качеству кабельного ТВ использую
ресурс <a class="reference external" href="http://zombobox.com">ZomboBox</a> Множество каналов, возможность просмотра любой
программы в любое время и другие плюсы современного мира. Поэтому
используя вывод по hdmi на телевизор, показывал домашним ТВ :) Но есть 1
минус, при полноэкранном режиме, Flash плеер не дает убрать фокус с окна
и вылетает в небольшое окошко. Решил я эту задачу в любимом Linux :) с
помощью создания двух X серверов, и запуске на втором этого плеера в
полный экран :)</p>
<p>Сразу оговорю, видеокарта у меня <span class="caps">NVIDIA</span> <span class="caps">9600GT</span> с драйверами 180.18,
монитор подключен к <span class="caps">DVI1</span> Samsung <span class="caps">753DF</span>, а телевизор подключен к <span class="caps">HDMI</span> к
телевизору Phillips.</p>
<p>Итак, после всех моих проверок и читания, какой же режим нужен для
такой работы в драйверах <span class="caps">NVIDIA</span> (по выборам всяких режимах в
nvidia-settings), нам требуется режим Separate X screen с выключеным Xinerama.</p>
<p>После включения этого режима, можем получить такой xorg.conf:</p>
<div class="highlight"><pre><span></span>Section <span class="s2">"ServerLayout"</span>
Identifier <span class="s2">"Layout0"</span>
Screen <span class="m">0</span> <span class="s2">"Screen0"</span> <span class="m">0</span> 0
Screen <span class="m">1</span> <span class="s2">"Screen1"</span> <span class="m">1024</span> 0
EndSection
Section <span class="s2">"Files"</span>
EndSection
Section <span class="s2">"Module"</span>
Load <span class="s2">"dbe"</span>
Load <span class="s2">"extmod"</span>
Load <span class="s2">"type1"</span>
Load <span class="s2">"freetype"</span>
Load <span class="s2">"glx"</span>
EndSection
Section <span class="s2">"ServerFlags"</span>
Option <span class="s2">"Xinerama"</span> <span class="s2">"0"</span>
EndSection
Section <span class="s2">"Monitor"</span>
<span class="c1"># HorizSync source: builtin, VertRefresh source: builtin</span>
Identifier <span class="s2">"Monitor0"</span>
VendorName <span class="s2">"Unknown"</span>
ModelName <span class="s2">"CRT-0"</span>
HorizSync 28.0 - 55.0
VertRefresh 43.0 - 72.0
Option <span class="s2">"DPI"</span> <span class="s2">"96 x 96"</span>
Option <span class="s2">"DPMS"</span>
EndSection
Section <span class="s2">"Monitor"</span>
<span class="c1"># HorizSync source: edid, VertRefresh source: edid</span>
Identifier <span class="s2">"Monitor1"</span>
VendorName <span class="s2">"Unknown"</span>
ModelName <span class="s2">"Philips 1080p TV (3)"</span>
HorizSync 31.0 - 80.0
VertRefresh 47.0 - 85.0
Option <span class="s2">"DPI"</span> <span class="s2">"96 x 96"</span>
Option <span class="s2">"DPMS"</span>
EndSection
Section <span class="s2">"Device"</span>
Identifier <span class="s2">"Device0"</span>
Driver <span class="s2">"nvidia"</span>
VendorName <span class="s2">"NVIDIA Corporation"</span>
BoardName <span class="s2">"GeForce 9600 GT"</span>
BusID <span class="s2">"PCI:1:0:0"</span>
Screen 0
EndSection
</pre></div>
<p>Мышь и клавиатура работают через <span class="caps">HAL</span>, поэтому их упоминаний тут нету.</p>
<p>Также, помимом стандартных опций сгенерированных nvidia-settings, добавил</p>
<div class="highlight"><pre><span></span>Option <span class="s2">"DPI"</span> <span class="s2">"96 x 96"</span>
</pre></div>
<p>чтобы все нормально смотрелось :)</p>
<p>С таким конфигом, разрешение экрана на телевизоре меняется без
перезагрузки иксов.</p>
<p>Чтобы запустить чт-либо на втором Х сервере (телевизоре), используйте комманду:</p>
<div class="highlight"><pre><span></span><span class="nv">DISPLAY</span><span class="o">=</span>:<номер_экрана> <программа>
</pre></div>
<p>Удачи в работе на двух экранах :)</p>
Устанавливаем QGtkStyle в Gentoo Linux2008-12-23T20:35:00+02:00gigimontag:it4it.ru,2008-12-23:2008/12/23/ustanavlivaem-qgtkstyle-v-gentoo-linux/<p>После убиения <span class="caps">KDE</span> и перехода на софт <span class="caps">GTK</span> и Qt4 захотелось видеть их в
одинаковой цветовой гамме и с одинаковой темой. Подумал сначала
использовать gtk-engines-qt, но у него есть пара минусов: зависимости от
<span class="caps">KDE4</span> (чуть ли не полностью кеды) и малое количество тем для Qt4.
Наткнулся на недавнюю разработку от Qt Software для Qt версии 4.4 под
названием QGtkStyle, которая использует тему <span class="caps">GTK</span> для Qt приложений.
Итак, приступим:</p>
<ol class="arabic simple">
<li>QGtkStyle в портежах официальных нету, поэтому надо добавить оверлей voyageur.</li>
<li>Установить QGtkStyle с помощью команды emerge qgtkstyle</li>
<li>Выбрать нужную тему для <span class="caps">GTK</span> <img alt="gtk-chtheme" src="http://it4it.ru/images/2008/12/gtk-chtheme.png" /></li>
<li>В файл ~/.gtkrc-2.0 добавить строчку в начало файла gtk-theme-name =
“<span class="caps">NAME</span>”</li>
<li>В активный профиль /etc/profile добавить запись export GTK2_RC_FILES=”`pwd`/.gtkrc-2.0”</li>
<li>Перезагрузить активный профиль sorce /etc/profile</li>
<li>В qtconfig (qt4config) выбрать тему <span class="caps">GTK</span>, после этого перезапустить X
сервер и радоваться результату</li>
</ol>
<p><img alt="qtconfig" src="http://it4it.ru/images/2008/12/qtconfig.png" /></p>
<p>Результат:</p>
<p><img alt="smplayer" src="http://it4it.ru/images/2008/12/smplayer.png" /></p>
<p>К сожалению SMPlayer не очень информативен, но софта на Qt с кучей
кнопок нету :)</p>
<p>Замечания:</p>
<p>Следует не забывать добавлять строчку gtk-theme-name = “<span class="caps">NAME</span>”, т.к.
она требуется для работы QGtkStyle. Если ее не будет, то при выборе в
qtconfig темы <span class="caps">GTK</span>, вы будете получать ошибку: “QGtkStyle cannot be used
together with the GTK_Qt engine.” Также можно использовать патченую gtk-chtheme, патч и ебилд можно
взять <a class="reference external" href="http://bugs.gentoo.org/show_bug.cgi?format=multiple&id=250504">здесь</a></p>
Шрифты в Linux как в WinXP (CRT)2008-12-22T00:50:00+02:00gigimontag:it4it.ru,2008-12-22:2008/12/22/shrifty-v-linux-kak-v-winxp-crt/<p>Недавно надоело смотреть на корявенькие шрифты в Linux, стал гуглить, н
онаходил только настройку для <span class="caps">LCD</span> монитора, а у меня <span class="caps">CRT</span> еще. Узнал по
форумам, дали ссылку на проект <a class="reference external" href="http://sharpfonts.com/">SharpFonts</a>. Воспользовался мануалом,
получил шрифты как в винде. Хочу вот перевести ман, для тех кто слабо
знает английский.</p>
<p>Для начала надо убедиться, что в системе установлено:</p>
<ul class="simple">
<li>fontconfig (обычно идет во всех дистрибутивах)</li>
<li>freetype2 с поддержкой ByteCode Interpreter</li>
</ul>
<p>После этого, требуется скачать шрифты от Microsoft. Но сперва прочитайте
лицензию <a class="reference external" href="http://sharpfonts.com/MS-EULA.txt"><span class="caps">EULA</span></a>, и если согласны с ней, вперед, скачивать :)</p>
<p><a class="reference external" href="http://sharpfonts.com/fonts/andale32.exe">andale32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/arial32.exe">arial32.exe</a> <a class="reference external" href="arialb32.exe">arialb32.exe</a> <a class="reference external" href="comic32.exe">comic32.exe</a>
<a class="reference external" href="http://sharpfonts.com/fonts/courie32.exe">courie32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/georgi32.exe">georgi32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/impact32.exe">impact32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/tahoma32.exe">tahoma32.exe</a>
<a class="reference external" href="http://sharpfonts.com/fonts/times32.exe">times32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/trebuc32.exe">trebuc32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/verdan32.exe">verdan32.exe</a> <a class="reference external" href="http://sharpfonts.com/fonts/webdin32.exe">webdin32.exe</a></p>
<p>После того как скачаете, надо установить пакет cabextract и распаковать
эти пакеты командой (от рута):</p>
<div class="highlight"><pre><span></span>mkdir -p /usr/share/fonts/truetype/
cabextract -d /usr/share/fonts/truetype/ andale32.exe arial32.exe arialb32.exe comic32.exe courie32.exe georgi32.exe impact32.exe tahoma32.exe times32.exe trebuc32.exe verdan32.exe webdin32.exe
</pre></div>
<p>Затем, скачать <a class="reference external" href="http://sharpfonts.com/fontconfig.tbz">файлы</a> конфигурации и распаковать их в /etc/fonts с
заменой старых:</p>
<div class="highlight"><pre><span></span>tar xvjpf fontconfig.tbz -C /etc/fonts/
</pre></div>
<p>После перезапуска иксов, у вас будут шрифты как в WinXP</p>
<p>Удачи ;)</p>
<p>Авторство принадлежит <a class="reference external" href="http://sharpfonts.com/">SharpFonts</a></p>
Acer Aspire One2008-12-07T13:41:00+02:00gigimontag:it4it.ru,2008-12-07:2008/12/07/acer-aspire-one/<p>Попался мне недавно по работе в руки Acer Aspire One, с виду,
практически знаменитый Asus <span class="caps">EEE</span> <span class="caps">PC</span>, и позиционируется также, и начинка
такая же практически. Не буду останаливаться на технических
подробностях, их в интернете уйма, а вот каких-то фоток Linux интерфейса
и отзывов пользователей я не находил, вот решил поделиться.</p>
<p>Из больших недостатков конструкции,я выделил следующие:</p>
<ol class="arabic simple">
<li>Дешевый пластик, хуже чем у Asus <span class="caps">EEE</span> <span class="caps">PC</span></li>
<li>На пластике, особенно синего цвета остаются пальцы,прчием сильно и
тяжело стираются</li>
<li>Он нещадно скрипит, особенно если переносить 1 рукой, видно
сказывается плохое качество пластика</li>
<li>Стоящих у него единственный кулер, работает всегда, и тарахтит всегда
достаточно громко. Причем тарахтит не просто как обычные, на больших
оборотах, а наоборот, как будто спотыкается обо что-то, очень сильно раздражает</li>
<li>Он тормоз, толи процессор Atom, толи дисковая подсистема дают о себе знать.</li>
</ol>
<p>Впринципе из плюсов, даже незнаю что выделить, помимо двух картридеров
(дада,именно двух, для разных карт), наверное и нету плюсов</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/12/dsc00078.jpg"><img alt="image0" src="http://it4it.ru/images/2008/12/dsc00078-300x300.jpg" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/dsc00077.jpg"><img alt="image1" src="http://it4it.ru/images/2008/12/dsc00077-300x300.jpg" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/dsc00076.jpg"><img alt="image2" src="http://it4it.ru/images/2008/12/dsc00076-300x300.jpg" /></a></p>
<p>Помимо внешнего вида, хотел бы рассмотреть Linux интерфейс.</p>
<p>Изначально на нем установлена была Fedora 8 с <span class="caps">GNOME</span> + свой интерфейс
длядураков, т.е огромные кнопки, никуда не залезть. Быстрые кнопки
запуска терминала выключены, выход в другие терминалы выключен, ребут
иксов выключен. Для комфорта, Acer написал свою оболочку для управления
WiFi, индикации показателей бука (батарея) и менеджер обновлений (он
только умеет сидеть в трее и иногда спрашивать разрешение на обновление).</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-192926_1024x600_scrot.png"><img alt="image3" src="http://it4it.ru/images/2008/12/2008-11-09-192926_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-192850_1024x600_scrot.png"><img alt="image4" src="http://it4it.ru/images/2008/12/2008-11-09-192850_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-194149_1024x600_scrot.png"><img alt="image5" src="http://it4it.ru/images/2008/12/2008-11-09-194149_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-194122_1024x600_scrot.png"><img alt="image6" src="http://it4it.ru/images/2008/12/2008-11-09-194122_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-193832_1024x600_scrot.png"><img alt="image7" src="http://it4it.ru/images/2008/12/2008-11-09-193832_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-193959_1024x600_scrot.png"><img alt="image8" src="http://it4it.ru/images/2008/12/2008-11-09-193959_1024x600_scrot-450x263.png" /></a><a class="reference external" href="http://it4it.ru/images/2008/12/2008-11-09-193036_1024x600_scrot.png"><img alt="image10" src="http://it4it.ru/images/2008/12/2008-11-09-193036_1024x600_scrot.png" /></a></p>
<p><img alt="image9" src="http://it4it.ru/images/2008/12/2008-11-09-193036_1024x600_scrot-450x263.png" /></p>
<p>Помимо установленного файлового менеджера (наутилус), OOo, <span class="caps">FF</span>, FireBird
и мелких программок, есть штук 5 игр написаных асеровцами, прчием все из
них примитивные (типа тетриса), и за них просят денег, по 15 долларов за игру.</p>
Защита ssh от ботов с помощью sshguard2008-11-17T19:30:00+02:00gigimontag:it4it.ru,2008-11-17:2008/11/17/zashhita-ssh-ot-botov-s-pomoshhyu-sshguard/<p>После установки сервера и вывешивании его в интернет, практически
мгновенно на порт ssh (tcp-22) стали ломиться боты, пытаясь подобрать
юзера и пароль. Это подтверждают такие строчки в логах auth.log:</p>
<div class="highlight"><pre><span></span>Nov <span class="m">16</span> 09:34:27 solaria sshd<span class="o">[</span>3343<span class="o">]</span>: Failed password <span class="k">for</span> root from 221.132.118.11 port <span class="m">43083</span> ssh2
Nov <span class="m">16</span> 09:34:29 solaria sshd<span class="o">[</span>3345<span class="o">]</span>: reverse mapping checking getaddrinfo <span class="k">for</span> tw118-static11.tw1.com failed - POSSIBLE BREAK-IN ATTEMPT!
Nov <span class="m">16</span> 09:34:29 solaria sshd<span class="o">[</span>3345<span class="o">]</span>: <span class="o">(</span>pam_unix<span class="o">)</span> authentication failure<span class="p">;</span> <span class="nv">logname</span><span class="o">=</span> <span class="nv">uid</span><span class="o">=</span><span class="m">0</span> <span class="nv">euid</span><span class="o">=</span><span class="m">0</span> <span class="nv">tty</span><span class="o">=</span>ssh <span class="nv">ruser</span><span class="o">=</span> <span class="nv">rhost</span><span class="o">=</span>221.132.118.11 <span class="nv">user</span><span class="o">=</span>root
Nov <span class="m">16</span> 09:34:31 solaria sshd<span class="o">[</span>3345<span class="o">]</span>: Failed password <span class="k">for</span> root from 221.132.118.11 port <span class="m">43354</span> ssh2
Nov <span class="m">16</span> 09:34:34 solaria sshd<span class="o">[</span>3347<span class="o">]</span>: reverse mapping checking getaddrinfo <span class="k">for</span> tw118-static11.tw1.com failed - POSSIBLE BREAK-IN ATTEMPT!
Nov <span class="m">16</span> 09:34:34 solaria sshd<span class="o">[</span>3347<span class="o">]</span>: <span class="o">(</span>pam_unix<span class="o">)</span> authentication failure<span class="p">;</span> <span class="nv">logname</span><span class="o">=</span> <span class="nv">uid</span><span class="o">=</span><span class="m">0</span> <span class="nv">euid</span><span class="o">=</span><span class="m">0</span> <span class="nv">tty</span><span class="o">=</span>ssh <span class="nv">ruser</span><span class="o">=</span> <span class="nv">rhost</span><span class="o">=</span>221.132.118.11 <span class="nv">user</span><span class="o">=</span>root
Nov <span class="m">16</span> 09:34:37 solaria sshd<span class="o">[</span>3347<span class="o">]</span>: Failed password <span class="k">for</span> root from 221.132.118.11 port <span class="m">43623</span> ssh2
Nov <span class="m">16</span> 09:34:38 solaria sshd<span class="o">[</span>3349<span class="o">]</span>: reverse mapping checking getaddrinfo <span class="k">for</span> tw118-static11.tw1.com failed - POSSIBLE BREAK-IN ATTEMPT!
Nov <span class="m">16</span> 09:34:38 solaria sshd<span class="o">[</span>3349<span class="o">]</span>: <span class="o">(</span>pam_unix<span class="o">)</span> authentication failure<span class="p">;</span> <span class="nv">logname</span><span class="o">=</span> <span class="nv">uid</span><span class="o">=</span><span class="m">0</span> <span class="nv">euid</span><span class="o">=</span><span class="m">0</span> <span class="nv">tty</span><span class="o">=</span>ssh <span class="nv">ruser</span><span class="o">=</span> <span class="nv">rhost</span><span class="o">=</span>221.132.118.11 <span class="nv">user</span><span class="o">=</span>root
Решил поставить пакет sshguard, который банит по IP адресу, с помощью iptables ботов пытающихся подобрать пароль <span class="o">(</span>если больше n попыток за m секунд<span class="o">)</span>.
</pre></div>
<p>Итак, приступим к установке. Для начала установим пакет sshguard из
репозитария, либо скачаем с официального сайта и скомпилируем. После
этого надо: 1. Добавить правила в начало iptables:</p>
<div class="highlight"><pre><span></span>iptables -N sshguard
iptables -A INPUT -p tcp --dport <span class="m">22</span> -j sshguard
</pre></div>
<ol class="arabic simple" start="2">
<li>Сделать так, чтобы sshguard читал логи об авторизацци на 22 порт:</li>
</ol>
<div class="highlight"><pre><span></span>tail -n0 -F /var/log/auth.log <span class="p">|</span> /usr/sbin/sshguard<span class="p">;</span>
</pre></div>
<p>И добавим это правило в автозагрузку 3. Дать права рута sshguard, чтобы
он мог динамически менять правила iptables:</p>
<div class="highlight"><pre><span></span>chmod +s /usr/sbin/sshguard
</pre></div>
<p>После этого, в списке процессов должен появится sshguard</p>
<div class="highlight"><pre><span></span>root <span class="m">2299</span> 0.0 0.6 <span class="m">9984</span> <span class="m">784</span> ? Sl Nov15 0:00 /usr/sbin/sshguard
</pre></div>
<p>Теперь, в конфиге можем видет ьследующее:</p>
<div class="highlight"><pre><span></span>Nov <span class="m">17</span> 10:35:12 solaria sshd<span class="o">[</span>4614<span class="o">]</span>: Invalid user aaron from 221.130.184.137
Nov <span class="m">17</span> 10:35:12 solaria sshd<span class="o">[</span>4614<span class="o">]</span>: <span class="o">(</span>pam_unix<span class="o">)</span> check pass<span class="p">;</span> user unknown
Nov <span class="m">17</span> 10:35:12 solaria sshd<span class="o">[</span>4614<span class="o">]</span>: <span class="o">(</span>pam_unix<span class="o">)</span> authentication failure<span class="p">;</span> <span class="nv">logname</span><span class="o">=</span> <span class="nv">uid</span><span class="o">=</span><span class="m">0</span> <span class="nv">euid</span><span class="o">=</span><span class="m">0</span> <span class="nv">tty</span><span class="o">=</span>ssh <span class="nv">ruser</span><span class="o">=</span> <span class="nv">rhost</span><span class="o">=</span>221.130.184.137
Nov <span class="m">17</span> 10:35:12 solaria sshguard<span class="o">[</span>2299<span class="o">]</span>: Matched IP address 221.130.184.137
Nov <span class="m">17</span> 10:35:12 solaria sshguard<span class="o">[</span>2299<span class="o">]</span>: Blocking 221.130.184.137: <span class="m">4</span> failures over <span class="m">23</span> seconds.
Nov <span class="m">17</span> 10:35:12 solaria sshguard<span class="o">[</span>2299<span class="o">]</span>: Setting environment: <span class="nv">SSHG_ADDR</span><span class="o">=</span>221.130.184.137<span class="p">;</span><span class="nv">SSHG_ADDRKIND</span><span class="o">=</span>4<span class="p">;</span><span class="nv">SSHG_SERVICE</span><span class="o">=</span>10.
Nov <span class="m">17</span> 10:35:12 solaria sshguard<span class="o">[</span>2299<span class="o">]</span>: Run <span class="nb">command</span> <span class="s2">"case </span><span class="nv">$SSHG_ADDRKIND</span><span class="s2"> in 4) exec /sbin/iptables -A sshguard -s </span><span class="nv">$SSHG_ADDR</span><span class="s2"> -j DROP ;; 6) exec /sbin/ip6tables -A sshguard -s </span><span class="nv">$SSHG_ADDR</span><span class="s2"> -j DROP ;; *) exit -2 ;; esac"</span>: exited 0.
</pre></div>
<p>Вот и все ;)</p>
Подключение VPN с помощью pptp2008-11-13T01:59:00+02:00gigimontag:it4it.ru,2008-11-13:2008/11/13/podklyuchenie-vpn-s-pomoshhyu-pptp/<p>Недавно потребовалось подключиться к провайдеру с помощью <span class="caps">VPN</span> соединения
с Linux машины. Как всем известно, кроме как использовать пакет <span class="caps">PPTP</span>
способов подключиться нет.</p>
<p>Итак, устанавливаем пакет <span class="caps">PPTP</span></p>
<p>Для Debian:</p>
<div class="highlight"><pre><span></span>apt-get install pptp
</pre></div>
<p>Он автоматчиески вытянет все нужные зависимости. После этого надо
настроить конфиг соединения:</p>
<ol class="arabic simple">
<li>Идем в папку /etc/ppp/peers</li>
<li>Создаем файл с любым названием, у меня sevstar (название првоайдера ;)</li>
<li>Вносим туда настройки для него:</li>
</ol>
<div class="highlight"><pre><span></span>lock
noauth
<span class="c1">#не используем компресию и шифрование</span>
nobsdcomp
nodeflate
refuse-eap
refuse-pap
refuse-chap
nomppe
<span class="c1">#максимальное число попыток установления связи, если 0 - будут попытки пока не подключимя</span>
maxfail 0
<span class="c1">#использовать как шлюз по умолчанию</span>
defaultroute
<span class="c1">#установки MTU и MRU</span>
mru 1500
mtu 1500
persist
</pre></div>
<p>4. Открываем файл /etc/ppp/chap-secrets и добавляем туда логин и пароль
в таком виде:</p>
<div class="highlight"><pre><span></span>login PPTP password *
Собственно все. После этого, запускаем командой
pppd call sev2 pty <span class="s2">"pptp 10.10.0.1 --nolaunchpppd"</span>
</pre></div>
<p>И контроллируем, чтобы появился интерфейс ppp0</p>
Установка Windows XP с флэшки2008-11-10T20:01:00+02:00gigimontag:it4it.ru,2008-11-10:2008/11/10/ustanovka-windows-xp-s-fleshki/<p>Недавно потребовалось установить Windows <span class="caps">XP</span> с <span class="caps">USB</span> флэшки, т.к. на буке
нету привода, а внешний покупать не хотелось. Начал гуглить, нахдил кучу
мануалов, от простейших и странных, до невероятно сложных-но
функциональных :)</p>
<p>Остановился наверно на самом простом способе.</p>
<p>Нам потребуется <span class="caps">USB</span> Flash носитель, не меньше 1 Гб (чтоб не мучаться с
уменьшением дистрибутива винды), и образ дискеты с Win98, который можно
взять <a class="reference external" href="http://it4it.ru/images/2008/11/boot98se_vc.exe">boot98se_vc</a>, и собственно дистрибутив Windows <span class="caps">XP</span> (папка I386 в
любых сборках,обычно).</p>
<p>Итак, приступим:</p>
<p>#. Запускаем boot98se_vc.exe, видим окно, в котором выбираем Writing on
Drive, а в поле Drive выбираем букву, где находится флэшка, жмем Ок
#. Закидываем на флэшку папку I386 с диска с виндой
#. Загружаем с флэшки, появится окно Volkov Commander :)
#. запускаем I386winnt.exe
#. В появившемся окне, выбираем букву диска, где расположена папка I386
#. Устанавливаем как обычно винду</p>
<p>При установке. у меня возникло несколько проблем:</p>
<p>#. Винда перестала ставится без файла подкачки - надо предварительно
сделать хотя бы 1 отформатированный в Fat32 раздел
#. Очень долго копируются файлы - запустить smartdrv перед началом установки</p>
<p>После часа ожидания, получил установленную винду :)</p>
<p>Удачи</p>
Сравнение torrent качалок 32008-11-09T04:31:00+02:00gigimontag:it4it.ru,2008-11-09:2008/11/09/sravnenie-torrent-kachalok-3/<p>Давно я не развивал эту тему, т.к. остановился на transmission с clutch,
и ничего другого не пробовал. Но вот, после очередного обновления,
оказалось, что они встроили Clutch прямо в дистрибутив. Сначала я
обрадовался, но потом, очень сильно расстроился, т.к. было достаточно
много багов (закачка торрента несколько раз, неудобный web интерфейс
стал, длинныйй) и это на версии 1.35, которая являлась последней (да и
сейчас одна из последних). Стал искать замену, и выбрал
rTorrent+wTorrent для web интерфейса.</p>
<p>Связка rTorrent и wTorrent является клиент-серверной, в фоне (в screen-е
висит rTorrent) и через интерфейс xml-rpc общается с wTorrent. В свою
очередь wTorrent написан на <span class="caps">PHP</span>+Ajax и для него нужен любой http сервер
(у меня он стоял на ligHTTPd, а потом на Apache2).</p>
<p>Итак, рассмотрил функционал. Т.к. rTorrent является самостоятельной,
достаточно мощной консольной torrent качалкой, он умеет:</p>
<ol class="arabic simple">
<li>Основные функции управления торрентами</li>
<li>Регулирование общей скорости</li>
<li>Регулирование приоритетов</li>
<li>Скачка лишь некоторых файлов из торрента</li>
<li>Изменение трекера</li>
<li><span class="caps">DHT</span></li>
<li>Загрузка файлов из <span class="caps">RSS</span></li>
<li>Использовать Cookies для авторизации</li>
<li>Сохранять торренты в любое место на разделе</li>
</ol>
<p>Собственно, все эти функции поддерживает web-интерфейс wTorrent, за что
он мне и понравился.</p>
<p>Итак, приступим.</p>
<p>При заходе в wTorrent, видим окно авторизации (лог и пасс заводим при
установке wTorrent)</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/enter.jpg"><img alt="image0" src="http://it4it.ru/images/2008/11/enter.jpg" /></a></p>
<p>После авторизации, попадаем в список загрузок</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/list.jpg"><img alt="image1" src="http://it4it.ru/images/2008/11/list-450x165.jpg" /></a>Здесь мы можем видеть:</p>
<ol class="arabic simple">
<li>В верхней панели основные кнопки управления (Выход в список, добавить
торрент, управление <span class="caps">RSS</span>, настройка Cookies, настройка аккаунтов, выход)</li>
<li>Ниже строка оставшегося объема на жестком диске</li>
<li>Общая скорость отдачи и загрузки</li>
<li>Навигация по папкам (быстрый переход к различным видам торрентов по
статусу: скаченые,остановленные и т.д.)</li>
</ol>
<p>Среди всех папок, следует отметить папку Частное, торренты в этой папке
видны лишь админу, и пользователю который их туда закинул. В настройках,
помимо управления аккаунтами 9создание,удаление) можно лишь изменить
скорость, на этом настройки заканчиваются.</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/settings.jpg"><img alt="image2" src="http://it4it.ru/images/2008/11/settings-450x195.jpg" /></a></p>
<p>Список загружающихся торрентов выглядит так:</p>
<p><img alt="image3" src="http://it4it.ru/images/2008/11/active-450x292.jpg" /></p>
<p>Активные закачки написаны черным цветом на голубоватом фоне,
остановленные-красным, закаченые-синим и т.д. Торренты выделенные
штриховкой, означают какую-либо ошибку трекера (нераспознанная
информация от трекера, не найден такой торрент и т.д.)</p>
<p>В ячейке закачки, можем видеть основные кнопки управления:</p>
<ol class="arabic simple">
<li>Остановить закачку</li>
<li>Закрыть (переносит в другую папку)</li>
<li>Удалить закачку</li>
<li>Пересчитать хэш торрента</li>
<li>Прогресс закачки</li>
<li>Процентов закачено</li>
<li>Колчиество сидеров/пиров</li>
<li>Сколько скачано/осталось в Мб</li>
<li>Скорость отдачи/скачки, ратио, приблизительное время оставшееся до загрузки</li>
</ol>
<p>При нажатии на торрент, открывается информация о нем:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/info.jpg"><img alt="image4" src="http://it4it.ru/images/2008/11/info-450x71.jpg" /></a></p>
<p>Сразу показывается информация о количестве пиров, размерах, прогрессе
загрузки, куда сохраняется, название торрент файла. Помимо этого,
доступно еще 3 вида информации/управления:</p>
<p>1. Информация о загружаемых файлах, изменение приоритетов файлов,
загружать/не загружать файл</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/allfiles.jpg"><img alt="image5" src="http://it4it.ru/images/2008/11/allfiles-450x181.jpg" /></a></p>
<ol class="arabic simple" start="2">
<li>Список всех трекеров и количество пиров на нем</li>
</ol>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/peers.jpg"><img alt="image6" src="http://it4it.ru/images/2008/11/peers-450x61.jpg" /></a></p>
<ol class="arabic simple" start="3">
<li> Список всех пиров (их <span class="caps">IP</span>-адреса)</li>
</ol>
<p><a class="reference external" href="http://it4it.ru/images/2008/11/peers2.jpg"><img alt="image7" src="http://it4it.ru/images/2008/11/peers2-450x64.jpg" /></a></p>
<p>В общем, такая связка является достаточно хорошей. Справляется с
основными своими функциями на все 100%, качает изумительно, торренты
помнит нормально (не загружает по несколько раз 1 и тоже). За месяц
использования, нареканий нет.</p>
<p>Единственное, хотелось бы добавить несколько функций:</p>
<ol class="arabic simple">
<li>Кнопку удалить торрент и файлы данных</li>
<li>При добавлении торрента, чтобы спрашивала какие файлы качать</li>
</ol>
Плохой MTU2008-10-25T01:34:00+03:00gigimontag:it4it.ru,2008-10-25:2008/10/25/ploxoj-mtu/<p>Недавно на работе стал глючить инет, перестали открываться некоторые
тяжелые сайты. Все перепроверил, оказалось у провайдера по-умолчанию
стоит маленький <span class="caps">MTU</span>, порядка 1300. В настройках ppp соединения надо было
указать явно mtu 1500, и все стало работать. (привет Goletsa :)</p>
Сравнение RSS читалок с поддержкой подкастов для PDA2008-10-25T01:24:00+03:00gigimontag:it4it.ru,2008-10-25:2008/10/25/sravnenie-rss-chitalok-s-podderzhkoj-podkastov-dlya-pda/<p>Большинство новостей интернета, я читаю на первых парах в институте :) с
помощью <span class="caps">RSS</span> загруженых ночью на КПК, и практически каждую неделю я
сталкивался с проблемой подкастов, приходилось вручную их скачивать и
закидывать, это мне однажды надоело и решил я найти <span class="caps">RSS</span> агрегатор с
поддержкой подкастов. Сразу же я полез на всем КПКоводам сайт 4pda, и
обнаружил из более чем десятка <span class="caps">RSS</span> читалок, лишь 3, которые поддерживают
подкасты: BeyoundPOD, Egress, NewsBreak.</p>
<p>Итак, первая читалка BeyondPOD:</p>
<p>Из ее описания, она умеет:</p>
<ol class="arabic simple">
<li>Работа с лентой любой длины</li>
<li>Авторизация</li>
<li>Поддержка <span class="caps">RSS</span> и Atom лент, загрузка лент из <span class="caps">OPML</span> файлов</li>
<li>Загрузка подкастов, проигрывание их во встроенном плеере</li>
<li>Автоматический запуск</li>
<li>Категории</li>
</ol>
<p>Почитал описание, обрадовался, поставил, попробовал поюзать пару дней…</p>
<p>Свои ленты я храню в <span class="caps">OPML</span> файле, полученого из Google Reader. И как раз
с этим пошли первые проблемы. При загрузке списка с лентами, нельзя
выбрать все ленты и импортировать, надо по одной, а у меня их 80.
Потратил на это дело минут 2-, загрухил. Стал использовать. Вот как
выглядит с загружеными лентами:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen002.png"><img alt="image0" src="http://it4it.ru/images/2008/10/screen002-337x450.png" /></a> Практически сразу оказалось, что она иногда неправильно
подгружает ленты, не видит их обновлений. Помимо этого, я не нашел где
включить показывание картинок, вместо них стоят пустые квадратики :( По
скорости работы, работает оочень медленно, как будто написана на
JavaScript и использует <span class="caps">IE</span>. Настройками программа не богата, она незнает
настроек по-умолчанию для всех лент, поэтому приходится менять в каждой
ленте количество загружаемых записей и другие настрйоки по загрузке.</p>
<p>С подкастами работает не очень хорошо, поставить фильтр по расширению
нельзя, поэтому пытается качать и аудио и видео. Может составлять
плейлисты для скачаных подкастов и передавать внешнему плееру
(достаточно полезно оказалось).</p>
<p>Вот так выглядит чтение ленты</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen003.png"><img alt="image1" src="http://it4it.ru/images/2008/10/screen003-337x450.png" /></a> <a class="reference external" href="http://it4it.ru/images/2008/10/screen004.png"><img alt="image2" src="http://it4it.ru/images/2008/10/screen004-337x450.png" /></a></p>
<p>Из достоинств, следует отметить лишь приятный по внешнему виду
интерфейс, а также составление и скачку подкастов.</p>
<p>Рассматриваемая версия 3.0</p>
<p>Следующая читалка - NewsBreak:</p>
<p>Это вторая читалка, которая мне попалась с поддержкой подкастов
(добавленой кстати, лишь в последней версии).</p>
<p>Данный агрегатор умее все тоже самое, что и BeyondPOD, кроме своего
плеера. И, к сожалению, имеет такие же минусы: нет глобальных настроек,
иногда тупит с лентами, не нашел как включить автоматическую загрузку
картинок. Но и достоинства тоже есть: работает быстро,можно
импортировать все записи из <span class="caps">OPML</span> файла.</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen005.png"><img alt="image3" src="http://it4it.ru/images/2008/10/screen005-337x450.png" /></a> <a class="reference external" href="http://it4it.ru/images/2008/10/screen007.png"><img alt="image4" src="http://it4it.ru/images/2008/10/screen007-337x450.png" /></a> <a class="reference external" href="http://it4it.ru/images/2008/10/screen008.png"><img alt="image8" src="http://it4it.ru/images/2008/10/screen008.png" /></a> <a class="reference external" href="http://it4it.ru/images/2008/10/screen008.png"><img alt="image5" src="http://it4it.ru/images/2008/10/screen008-337x450.png" /></a></p>
<p>Не понравилась лишь невозможностью скачки картинок (либо я не нашел
как), а так отличная читалка.</p>
<p>Рассматрвиаемая версия: 2.1</p>
<p>Третьей по списку была программа Egress</p>
<p>Данный агрегатор позиционируется для управления 1 рукой, поэтому его
интерфейс имеет достаточно большие панельки, и управлять чтением ленты
можно пальцем, передвигая записи:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen009.png"><img alt="image6" src="http://it4it.ru/images/2008/10/screen009-337x450.png" /></a> <a class="reference external" href="http://it4it.ru/images/2008/10/screen010.png"><img alt="image7" src="http://it4it.ru/images/2008/10/screen010-337x450.png" /></a></p>
<p>` <{filename}/images/2008/10/screen010.png>`__По
функционалу, она стандартна, умеет тоже самое что и предыдущие две.
Однако, она позволяет сразу загружать все ленты из списка, имеет
глобальные настройки (!), достаточно шустро работает, показывает
картинки(!). К сожалению, из-за своего интерфейса, не всегда правильно
отрабатывает нажатие на ленту, оно не всегда срабатывает, поэтому не
сразу открывается нужная лента. Помимо этого, с подкастами работает
очень плохо, она не различает где какой формат, грузит совершенно все.
Если в ленте было выбрано загружать лишь 1 подкаст, а в ленте появится
подкаст и видео файл следующей записью, то подкаст она оставит, а видео
скачает :( Также, довольно часто удаляет скачаные подкасты
послеобновления всех лент, поэтому надо проверять, загрузила подкаст и
сохранила, либо удалила. К сожалению, на моем Dell x51v с <span class="caps">WM6</span>, почему-то
почти всегда вешает систему, при выходе из программы если включен WiFi</p>
<p>Egress из трех программ нравится больше всех, но хотелось бы лучшей
работы с подкастами :(</p>
Пишем конфиг conky2008-10-06T23:35:00+03:00gigimontag:it4it.ru,2008-10-06:2008/10/06/pishem-konfig-conky/<p>Решил недавно занять свободное пространство по бокам от панельки. ничего
лучше не придумал, как показывать туда системную информацию, для этого
избрал conky.</p>
<p>Итак, мой конфиг коньков, будет показывать:</p>
<ol class="arabic simple">
<li>Загрузка двух ядер</li>
<li>Индикация свободной/занятой <span class="caps">RAM</span> и <span class="caps">SWAP</span></li>
<li>Свободное пространство в / и /home/user (домашний каталог на
отдельном разделе винта)</li>
<li>День недели и аптайм</li>
<li>Название активных сетевых интерфейсов с <span class="caps">IP</span> адресами, скоростью в
данный момент (только для активных)</li>
</ol>
<p>Приведу сразу текст конфига:</p>
<div class="highlight"><pre><span></span>override_utf8_locale yes <span class="c1"># использование UFT-8 локаль (нужно для xft)</span>
use_xft yes <span class="c1"># используем xft</span>
xftfont Liberation Mono:size<span class="o">=</span><span class="m">7</span> <span class="c1"># используемый шрифтxftalpha 0.5 # коэффициент прозрачности</span>
update_interval 1.0 <span class="c1"># частота обновления (на самом деле период)</span>
own_window yes <span class="c1"># в отдельном окне</span>
own_window_type desktop <span class="c1"># на десктопе (так же может быть normal или override)</span>
own_window_colour <span class="m">000</span> <span class="c1"># цвет фона</span>
double_buffer yes <span class="c1"># двойная буферизация</span>
minimum_size <span class="m">1274</span> <span class="m">5</span> <span class="c1"># минимальный размер ширинаdraw_shades no # отключаем тенalignment bottom_left # расположение снизу слева</span>
gap_x <span class="m">0</span> <span class="c1"># начальные координаты: X</span>
gap_y <span class="m">0</span> <span class="c1"># начальные координаты: Y</span>
TEXT <span class="c1"># выводимая информация</span>
<span class="si">${</span><span class="nv">voffset</span><span class="p"> 2</span><span class="si">}${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>Core 1:<span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">cpu</span><span class="p"> cpu1</span><span class="si">}</span>%<span class="si">${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span> <span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>RAM: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">mem</span><span class="si">}</span>/<span class="si">${</span><span class="nv">memmax</span><span class="si">}${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span> <span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>ROOT: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">fs_free</span><span class="p"> /</span><span class="si">}</span>/<span class="si">${</span><span class="nv">fs_size</span><span class="p"> /</span><span class="si">}</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span> <span class="si">${</span><span class="nv">alignr</span><span class="si">}${</span><span class="nv">color</span><span class="p"> yellow</span><span class="si">}${</span><span class="nv">time</span><span class="p"> %a</span><span class="si">}${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">alignr</span><span class="si">}${</span><span class="nv">if_up</span><span class="p"> eth0</span><span class="si">}</span> eth0 <span class="si">${</span><span class="nv">color</span><span class="p"> gray</span><span class="si">}${</span><span class="nv">addr</span><span class="p"> eth0</span><span class="si">}${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span>><span class="si">${</span><span class="nv">color</span><span class="p"> gray</span><span class="si">}</span> ↓: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">downspeed</span><span class="p"> eth0</span><span class="si">}</span> kiB/s <span class="o">(</span><span class="si">${</span><span class="nv">totaldown</span><span class="p"> eth0</span><span class="si">}</span><span class="o">)</span> <span class="si">${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span><span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>↑: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">upspeed</span><span class="p"> eth0</span><span class="si">}</span> kiB/s <span class="o">(</span><span class="si">${</span><span class="nv">totalup</span><span class="p"> eth0</span><span class="si">}</span><span class="o">)</span><span class="si">${</span><span class="nv">endif</span><span class="si">}</span> <span class="si">${</span><span class="nv">uptime</span><span class="si">}</span>
<span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>Core 2:<span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">cpu</span><span class="p"> cpu2</span><span class="si">}</span>%<span class="si">${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span> <span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>SWAP: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">swap</span><span class="si">}</span>/<span class="si">${</span><span class="nv">swapmax</span><span class="si">}${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span> <span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>HOME: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">fs_free</span><span class="p"> /home/aliens</span><span class="si">}</span>/<span class="si">${</span><span class="nv">fs_size</span><span class="p"> /home/aliens</span><span class="si">}${</span><span class="nv">alignr</span><span class="si">}${</span><span class="nv">if_up</span><span class="p"> wlan0</span><span class="si">}</span> Wlan0 <span class="si">${</span><span class="nv">color</span><span class="p"> gray</span><span class="si">}${</span><span class="nv">addr</span><span class="p"> wlan0</span><span class="si">}${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span>><span class="si">${</span><span class="nv">color</span><span class="p"> gray</span><span class="si">}</span> ↓: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">downspeed</span><span class="p"> wlan0</span><span class="si">}</span> kiB/s <span class="o">(</span><span class="si">${</span><span class="nv">totaldown</span><span class="p"> wlan0</span><span class="si">}</span><span class="o">)</span> <span class="si">${</span><span class="nv">color</span><span class="p"> red</span><span class="si">}</span><span class="p">|</span> <span class="si">${</span><span class="nv">color</span><span class="p"> grey</span><span class="si">}</span>↑: <span class="si">${</span><span class="nv">color</span><span class="p"> white</span><span class="si">}${</span><span class="nv">upspeed</span><span class="p"> wlan0</span><span class="si">}</span> kiB/s <span class="o">(</span><span class="si">${</span><span class="nv">totalup</span><span class="p"> wlan0</span><span class="si">}</span><span class="o">)</span><span class="si">${</span><span class="nv">endif</span><span class="si">}</span>
</pre></div>
<p>Рассмотрим последнюю строчку, которая отвечает за выводимый текст.</p>
<p>Параметры (переменные) указываются в формате ${}, внутри блока пишется
команда. Текст, написаный не в блоке ${} будет просто выводиться на
панель. Основные использованные команды:</p>
<p>${color цвет} - указывает использующийся цвет после блока, до следующего
такого блока</p>
<p>${fs_free раздел} - показывает количество свободного места на указаном разделе</p>
<p>${fs_size раздел} - размер раздела</p>
<p>${cpu cpuN} - показывает загрузку процессора N</p>
<p>${if_up}, ${endif} - блок условие. Если условие выполняется (поднят
интерфейс или нет), то показывается весь код до ${endif}.</p>
<p>В конце, у меня получилась такая картина:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/conky.jpg"><img alt="image0" src="http://it4it.ru/images/2008/10/conky-450x8.jpg" /></a></p>
<p>Почитать про настройку можно на официальном <a class="reference external" href="http://conky.sourceforge.net/docs.html">сайте</a></p>
Телефон + 3G + КПК = ?2008-10-02T21:49:00+03:00gigimontag:it4it.ru,2008-10-02:2008/10/02/telefon-3g-kpk/<p>Приобрел месяц назад стартовый пакет нового оператора 3G связи Utel.
Сидел с телефона в интернете за 2 цента метр. И вот недавно попробовал
выйти в интернет с КПК через мобильник, и столкнулся с проблемой, что
нету мануала от Utel. До этого выходил в интернет используя Киевстар,
там было подробное описание настроек и в тома числе кода инициализации.
Мобильный у меня SonyEricsson k800i, КПК Dell Axim x51v (с Microsoft
Bluetooth Stack). Соединять устройствами будем по Bluetooth.</p>
<blockquote>
Итак приступим:</blockquote>
<p>1. Надо настроить нормальный интернет от Utel на мобиле. Описывать этот
процесс не буду, т.к. они высылают настройки. Полученный профиль Utel
Интернет надо поставить используемым по дефолту.</p>
<p>2. Включить в опциях Bluetooth на телефоне Bluetooth->Bluetooth
Интернет-> выбрать профиль Utel Интернет.</p>
<ol class="arabic simple" start="3">
<li>Включить Bluetooth на КПК, и спарить его с телефоном</li>
</ol>
<p>Заходим в Bluetooth, включаем его, сканируем устройства, находим свой
телефон, подключаем, выбираем <span class="caps">COM</span> Ports</p>
<p>После этого идем на вкладку <span class="caps">COM</span> Ports, и создаем здесь подключение к
порту телефона. В итоге должно появиться:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen13.jpg"><img alt="image0" src="http://it4it.ru/images/2008/10/screen13-337x450.jpg" /></a></p>
<p>4. Теперь надо создать интернет соединение. Идем в настройки Today-Settings-Connections</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen14.jpg"><img alt="image1" src="http://it4it.ru/images/2008/10/screen14-337x450.jpg" /></a></p>
<p>Заходим в Connections, жмем на Add a new modem connection</p>
<p>Заполняем поля, примерно так (имя любое, способ соединения Bluetooth):</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/10/screen15.jpg"><img alt="image2" src="http://it4it.ru/images/2008/10/screen15-337x450.jpg" /></a></p>
<p>Жмем Next, выбираем наш спареный телефон, жмем Next. В окне ввода
телефонного номера для набора вписываем *99*#, жмем Next. Окно учетной
записи оставляем полностью пустым.</p>
<p>Все, теперь при любом запросе интернет соединения, будет вылазить окно
ввода логина и пароля, и кнопки Connect. Если в это время телефон
подключен, то при нажатии Connect, КПК подключится и вы будете в
интернете :)</p>
<p><strong>Теперь небольшой обзор Utel</strong></p>
<p>Качество связи внутри сети Utel сверх всяких похвал. Слышется только
голос, никаких посторонних шумов и погрюкиваний. К сожалению покрытие
достаточно маленькое, но для телефонных разговорах, если даже нет
покрытия Utel, используется Beeline. В таком режиме даже в интернет
получается выйти, но рвется часто.</p>
<p>Также, мерил скорость интернета на протяжении дня. Максимальная отметка
была днем, на краю зоны покрытия 3G, тогда скорость достигла примерно
45-50 кбайт/с (400-500 кбит/с). Мерил днем, дома, скорость оказалась
около 10 кбайт/с, что ненамного лучше <span class="caps">GPRS</span> (: Зато дешево.</p>
Браузер Arora - из GIT2008-09-23T20:13:00+03:00gigimontag:it4it.ru,2008-09-23:2008/09/23/brauzer-arora-iz-git/<p>Решил недавно поискать браузеры использующие движок Webkit, и написаные
на Qt4. В итоге, нашел лишь один мультиплатформенный браузер <a class="reference external" href="http://code.google.com/p/arora/">Arora</a>. В
настоящее время он имеет версию 0.3, и разрабатывается 0.4. Умеет он
пока что мало:</p>
<ul class="simple">
<li>Табы</li>
<li>Закладки</li>
<li>История посещеных сайтов</li>
<li>Автоматическое дополнение запросов в строку поиска google из истории</li>
<li>Качалка файлов</li>
<li>Режим приватности (не записываются логи)</li>
</ul>
<p>Но, хоть версия и мала, браузер достаточно стабильно работает и быстро
(благо WebKit из <span class="caps">SVN</span>, а Qt4.4).</p>
<p>Хочу рассказать, как обновить его до актуального состояния, т.е. собрать
из <span class="caps">GIT</span> ;)</p>
<p>Для этого нам требуется в системе установленое Qt4.4 и Qt4-webkit (его я
поставил для удовлетворения зависимостей, и для других приложений).
После этого:</p>
<ol class="arabic simple">
<li>Скачиваем исходные коды с помощью команды</li>
</ol>
<div class="highlight"><pre><span></span>git clone git://github.com/Arora/arora.git
</pre></div>
<ol class="arabic simple" start="2">
<li> Теперь надо взять последнюю версию WebKit:</li>
</ol>
<div class="highlight"><pre><span></span>svn checkout http://svn.webkit.org/repository/webkit/trunk WebKit
</pre></div>
<ol class="arabic simple" start="3">
<li>Собираем WebKit</li>
</ol>
<div class="highlight"><pre><span></span><span class="nb">cd</span> WebKit
./WebKitTools/Scripts/build-webkit --qt --release
</pre></div>
<p>4. Настраиваем переменные окружения, для сборки Arora с последним WebKit:</p>
<div class="highlight"><pre><span></span><span class="nb">cd</span> /path/to/arora/source
<span class="nb">export</span> QT<span class="se">\_</span>WEBKIT<span class="o">=</span>webkit<span class="se">\_</span>trunk
<span class="nb">export</span> <span class="nv">WEBKITDIR</span><span class="o">=</span>/pat/to/webkit/source
</pre></div>
<ol class="arabic simple" start="5">
<li>Собираем Arora:</li>
</ol>
<div class="highlight"><pre><span></span>qmake <span class="s2">"CONFIG-=debug"</span> -r
make clean
make
</pre></div>
<p>Впринципе, пункты 2,3,4 можно пропустить, но тогда будет использована
слишком старая версия WebKit. Для сравнения производительности, приведу
цифры, сравнивая с Opera 9.60 Beta1 build 2424.</p>
<p><strong>Тест Acid3:</strong></p>
<p>Opera 9.60 Beta1 build 2424 - 85/100</p>
<p>Arora с Qt4-webkit из репозитария - 41/100</p>
<p>Arora с WebKit из <span class="caps">SVN</span> - 96/100</p>
<p><strong>Тест `SunSpide`_r (цифры за весь тест):</strong></p>
<p>Opera 9.60 Beta1 build 2424 - 14035.8ms +/- 4.3%</p>
<p>Arora с Qt4-webkit из репозитария - 24818.0ms +/- 5.2%</p>
<p>Arora с WebKit из <span class="caps">SVN</span> - 4695.4ms +/- 10.0%</p>
<p>Как не трудно догадаться, советую WebKit обновлять ;)</p>
Двигатель толпы - ?2008-09-21T15:54:00+03:00gigimontag:it4it.ru,2008-09-21:2008/09/21/dvigatel-tolpy/<p>Все знают о популярности конференций и выступлений Стив Джобса, о его
умении говорить и т.п. Но никто почему-то (или мало) не упоминают о
Стиве Балмере, который не меньше может заводить публику и делать
презентации, в чем убедился, посмотрев некотоыре части конференций на
ютубе и аналогичных сервисах. Он заводит публику по-другому, не как
Джобс, спокойно, медленно, наоборот - энергии в нем дофига и больше, и
получается у него не хуже. :)</p>
<p>Собственно, к чему это я? Я задумался, а почему про него говорят только
плохого, а о Джобсе только хорошее? Лишь из-за того, что сейчас Apple
это круто, а <span class="caps">PC</span> фигня? Т.е. люди смотрят в первую очередь на
популярность продукта, и говорят за него же, хотя уверен, каждый кто
обсирает Microsoft, Билла Гейтса, Балмера - все (99% в СНГ) начинали с
Windows. Так что же получается - толпой двигает не разум, а что-то
другое? Какое-то общее мнение?</p>
<p>Кажется, что если поставить Баллмера вести Mac World презентацию, то он
сразу станет “приятным” типом,а Джобс - унылым. Очень сильно
расстраивает, что людьми в большиснтве своем, двигает не разум, а мнение
других :) (прощу прощения за тавтологию).</p>
<p>Возьмем для примера аудиоплеер. Что бегут покупать 95% людей (не
музыкантов) ищущих плеер? Да, iPod, хотя в интернете множество тестов,
обсуждений, что у iPod не самая лучшая начинка, не лучший звук, а
стоимость не маленькая, по сравнению с аналогами от Samsung, iRiver,
Sony. Опять же, что двигает? Верно, стереотипы и мнение толпы, а также
банальные понты!</p>
<p><span class="caps">P.S.</span>я не защищаю <span class="caps">MS</span> и не обсираю Apple, уважаю обе фирмы, и обоих
Стивов (и даже Билла) :) Хотелось высказать свою точку зрения толпы
<span class="caps">P.S.S.</span>Нашел видео, точнее нарезка классная, переслушиваю раз 100 уже
наверно, думаю баян для многих</p>
<p><a class="reference external" href="http://www.youtube.com/watch?v=KMU0tzLwhbE">Developers</a></p>
Простая хранилка паролей2008-09-19T23:35:00+03:00gigimontag:it4it.ru,2008-09-19:2008/09/19/prostaya-xranilka-parolej/<p>После начала работы системным администратором, я задумался о
конфиденциальности своей информации, а также серверов. После этого я
стал менять пароли везде, где может быть моя лияная информация (например
почта). Практически сразу задумался о средстве хранения паролей, и
желательно простое и мультиплатформенное. Немного погуляв по интернету,
нашел единственную, по-настоящему мультиплатформенный органайзер для
паролей KeePassX.</p>
<p>KeePassx - удовлетворяет всем моим требованиям:</p>
<ul class="simple">
<li>без всяких наворотов и лишних функций</li>
<li>работа с несколькими базами</li>
<li>блокирование доступа к базе</li>
<li>шифрование базы по <span class="caps">AES</span></li>
<li>и самое главное: поддержка Windows, Linux, и Windows Mobile!
Последнее особо нравится, т.к. имеется у меня КПК на ней :)</li>
</ul>
<p>Помимо этого, она умеет:</p>
<ul class="simple">
<li>Импортировать пароли из PWManager и KWallet</li>
<li>Использовать для шифрования Twofish 256 бит</li>
<li>Генерировать пароли :)</li>
</ul>
<p>Linux версия:</p>
<p>Итак, программа написана с использованием Qt, поэтому требуется
установленная библиотека Qt у Linux пользователей. Работы с программой
очень простая, вот так она выглядит с записями:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/09/2008-09-19-215519_1280x800_scrot1.png"><img alt="image0" src="http://it4it.ru/images/2008/09/2008-09-19-215519_1280x800_scrot1-450x281.png" /></a></p>
<p>Все главное окно программы состоит из:</p>
<ol class="arabic simple">
<li>Небольшой панельки быстрых кнопок (открыть, закрыть, новая запись,
пароль на блокировку)</li>
<li>Слева, панель категорий. Поддерживает подкатегории (3 уровня точно)</li>
<li>Справа верхняя, показывается таблица со всеми записями в категории</li>
<li>Справа нижняя, показывает информацию о выбраной записи</li>
</ol>
<p>Окно добавления новой записи, выглядит вот так:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/09/2008-09-19-215657_1280x800_scrot.png"><img alt="image1" src="http://it4it.ru/images/2008/09/2008-09-19-215657_1280x800_scrot-413x450.png" /></a></p>
<p>Здесь все легко и понятно:</p>
<ol class="arabic simple">
<li>Выбор категории (группы)</li>
<li>Заголовок (описание)</li>
<li>Имя пользователя</li>
<li>Пароль, дважды</li>
<li>Оценка пароля</li>
<li>Комментарий</li>
<li>До какого числа действует</li>
<li>Приложеный файл (полезно, если используется авторизация по ssl сертификату)</li>
</ol>
<p>Режим блокировки доступа, можно поставить на время. либо на
закрытие/сворачивание программы. У меня стоит через 30 секунд
блокироваться и сворачиваться в трей. Когда программа заблокирована,
просит пароль на базу:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/09/2008-09-19-222500_1280x800_scrot.png"><img alt="image2" src="http://it4it.ru/images/2008/09/2008-09-19-222500_1280x800_scrot-450x238.png" /></a></p>
<p>Windows Mobile версия:</p>
<p>Собственно, умеет тоже самое, кроме блокировки базы, и поддерживает
только <span class="caps">AES</span> алгоритм.</p>
<p>Покажу лишь скриншоты, думаю и так все понятно:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/09/screen06.jpg"><img alt="image3" src="http://it4it.ru/images/2008/09/screen06-337x450.jpg" /></a><a class="reference external" href="http://it4it.ru/images/2008/09/screen07.jpg"><img alt="image4" src="http://it4it.ru/images/2008/09/screen07-337x450.jpg" /></a><a class="reference external" href="http://it4it.ru/images/2008/09/screen08.jpg"><img alt="image5" src="http://it4it.ru/images/2008/09/screen08-337x450.jpg" /></a></p>
<p>Вот и все :) Базы перекидываются и работают и там и там. Единственный
минус, нету единой синхронизации баз :( поэтому я автоматически скидываю
базу на сервак, и также автоматически ее забираю… синхронизация лишь
односторонняя, т.к. на кпк пароли только смотрю.</p>
<p>Официальный <a class="reference external" href="http://www.keepassx.org/">сайт</a></p>
Истерия вокруг Google Chrome2008-09-15T16:59:00+03:00admintag:it4it.ru,2008-09-15:2008/09/15/isteriya-vokrug-google-chrome/<p>Все знают о выходе браузера от Google. На протяжении 2-х недель я его
не видел (нету его под Linux официально, а париться с компиляцией
лениво), но начитался вдоволь, что надоело. Решил сегодян поставить его
и посмотреть, чем же он так хорош.</p>
<p>#.Очень не понравилось, почему нажимая на кнопку на официальном
сайте: Скачать , у меня скачивается программа, которая его вытягивает? а
если я хочу на флэшку, или дать другу его?
#.При первом включении он автоматчиески берет закладки из другого
браузера. Я не хочу этого! Почему не спрашивается?
#.Голубая рамка (обрамление окна) выделяющееся из системы. Используя
WindowsBlinds, это жутко раздражает. Видимо я отвык от Windows-way,
когда у каждого окна свой вид %).
#.Неудачно стыреный из Оперы Speed-dial, выводящий туда историю.
#.Закрывая последний таб, программа закрывается - это вообще бред.
Да, я понимаю, что это как бы берет ноги из новой технологии
“песочницы”, чтобы табы были независимыми. Но почему нельзя открывать
новый таб, чисты, и закрывать старый? Я же нажал не закрыть программу, а
закрыть таб, не логично.
#.Скудность настроек - но это ладно, т.к. глубочайшая бета.
#.Он очень плохо берет из кэша (если вообще берет). Опера при кнопке
назад, открывает моментально из кэша, хром же, грузит заново вроде (по
ощущениям)
#.Он запоминает введеные в поля значения, и автоматически
подставляет даже если не просил.</p>
<p>Собственно, из плюсов я увидел только, что это первый браузер (кроме
Safari), который использует WebKit в Windows, а также очень быстрая V8
javascript машина, за это конечно плюс.</p>
<p>Поработав в нем пару часов, заметил что крошится достаточно часто,
причем весь. При сравнении занимаемой ОЗУ с Opera 9.51, последняя ест
значительно меньше памяти. При открытых 5 вкладках (редактирование поста
в wordpress, bash, lor, habrahabr, linuxforum, почта яндекса) Chrome
весь занимал 142 метра, опера - 74!</p>
<p>Собственно, исходя из всего этого, для меня браузер Chrome не юзабелен,
да и не вижу из-за чего такая истерия вокруг него. хотя на этот счет
есть мнение.</p>
<p>Истерия вокруг Chrome, это ходящие по всему интернету статьи в плане
прикручивания к хрому напильником всяких приблуд, ассоциирование кучи
всяких картинок с хромом и т.д. Для примера, на ХабраХабре, в обзоре
про миниатюрную программу для установки горячих клавиш, запускают
Chrome, со словами - теперь он всегда со мной, и никто другой так не
может. Жутко бесит…</p>
<p>Собственно, истерия мне кажется вызвана лишь тем, что он от Google!
Много людей сейчас Google чуть ли не благословляют. Это ж круто!
использовать браузер от гугла. бррр. Уверен на 99%, если б гугл выложил
пересобраный ФФ, со своим баром и какой-нибудь приблудой, любой, все б
стали переходить на него. Тоже самое, если бы Chrome сделала неизвестная
фирма, никто б даже внмиания на него не обратил, даже будь он в 10 раз
быстрее всех. Увы, люди стадные животные, которыми легко можно рулить.</p>
Настройка NFS сервера и клиента2008-09-14T14:45:00+03:00gigimontag:it4it.ru,2008-09-14:2008/09/14/nastrojka-nfs-servera-i-klienta/<p>Имеется у меня дома два компьютера и один сервер-шлюз-качалка. Причем 1
компьютер находится в другой комнате и соединен с ними по Wi-Fi. Общим
местом для обмена информацией между компьютерами долгое время был фтп,
но как-то раз решил я использовать нормальную сетевую ФС. Выбор пал на
<span class="caps">NFS</span>, т.к. ее и Windows умеет примаунчивать. В этой заметке, хочу
рассказать про свой опыт настройки на основе Gentoo Linux на сервере и клиенте.</p>
<ol class="arabic simple">
<li>Общие настройки для сервера и клиента</li>
</ol>
<p>Для начала, надо убедиться что поддержка <span class="caps">NFS</span> включена в ядро, как модуль
или вкомпилено в ядро.</p>
<p>Я вкомпилил в ядро:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/09/kernelnfs.png"><img alt="image0" src="http://it4it.ru/images/2008/09/kernelnfs-450x155.png" /></a></p>
<p>Если у вас собрано как модуль ядра, то в lsmod должы быть подгружены:
nfs и nfsd, если их нет, то подгрузите, командой: modprobe nfs &&
modprobe nfsd.</p>
<p>После этого, надо установить пакет nfs-utils на сервере и на клиенте, а
также проверить, что установлен пакет portmap.</p>
<ol class="arabic simple" start="2">
<li>Настройка сервера</li>
</ol>
<p>Настройка сервера заключается в редактировании файла /etc/exports, для
указания расшареных папок, а также прав на них для разных компьютеров
сети. Формат этого файла такой:</p>
<div class="highlight"><pre><span></span>directory machineA<span class="o">(</span>option,option<span class="o">)</span> machineB<span class="o">(</span>option,option<span class="o">)</span> ...
</pre></div>
<p>Где:</p>
<p>directory - папка, которую надо расшарить.</p>
<p>machineA, machineB - адрес клиента, которому разрешен доступ к папке.</p>
<p>option - опции для этого клиента.</p>
<p>Адрес клиента можно задавать указаием <span class="caps">IP</span>-адреса, указанием его имени, а
также указанием подсети.</p>
<p>В моем случае, я расшаривал домашнюю папку на сервере /home/aliens,</p>
<div class="highlight"><pre><span></span>/home/aliens 192.168.66.0/24<span class="o">(</span>async,no_subtree_check,rw<span class="o">)</span>
</pre></div>
<p>После этого, можно запускать <span class="caps">NFS</span> сервер:</p>
<div class="highlight"><pre><span></span>/etc/init.d/nfs start
</pre></div>
<p>Если появится ошибка: Cannot register service: <span class="caps">RPC</span>: Unable to receive;
errno=Connection refused, то проверьте, что у вас запущен portmap (
/etc/init.d/portmap start )</p>
<p>Если запустился удачно, то стоит добавить в автозагрузку</p>
<div class="highlight"><pre><span></span>rc-update add nfs default
rc-update add portmap default
</pre></div>
<ol class="arabic simple" start="3">
<li>Настройка клиента</li>
</ol>
<p>Чтобы примаунтить удаленную папку, можно использовать команду mount в виде:</p>
<div class="highlight"><pre><span></span>mount адрес_сервера:/путь_до_папки точка_монтирования
</pre></div>
<p>В моем случае:</p>
<div class="highlight"><pre><span></span>mount 192.168.66.250:/home/aliens /media/server
</pre></div>
<p>Если portmap запущен и установлены nfs-utils, то команда mount сработает
и в точке монтирования найдете удаленное содержимое.</p>
<p>Чтобы папка <span class="caps">NFS</span> монтировалась автоматчиески при запуске системы, следует
в /etc/fstab добавить слеюущую строку:</p>
<div class="highlight"><pre><span></span>x.x.x.x:/directory /mount_directory nfs rw <span class="m">0</span> 0
</pre></div>
<p>А также, добавить в автозапуск сервис nfsmount</p>
<div class="highlight"><pre><span></span>rc-update add nfsmount default
</pre></div>
<p>Для более подробного разбора опций прав, можно прочитать <a class="reference external" href="http://gentoo-wiki.com/HOWTO_Share_Directories_via_NFS">тут</a></p>
<p>Либо в официальном мане.</p>
<p>Надеюсь кому-то эта статья поможет. Удачи ;)</p>
Написание GUI для Python с помощью EasyGUI2008-09-11T20:05:00+03:00gigimontag:it4it.ru,2008-09-11:2008/09/11/napisanie-gui-dlya-python-s-pomoshhyu-easygui/<p>Хочу начать по-тихоньку переводить некоторые полезные статьи относящиеся
к компьютерах. Как проба пера, хочу перевести небольшую инструкцию по
использованию EasyGui. Объективная, не грубая критика принимается в комментариях.</p>
<p>В большинстве случаев, для создания графического интерфейса используют
библиотеку Tkinter, либо аналогичную другую. Чаще всего, это делают люди
обладающие достаточным опытом программирования на Python, т.к. требуется
достаточно много сложного кода. К счастью, модуль EasyGUI добавляет
возможность быстро и легко написать качественный <span class="caps">GUI</span> для вашего скрипта.
Используя EasyGUI, требуется всего лишь несколько строк, для создания
визуальных элементов.</p>
<p>Лучший путь изучения EasyGUI раскрывается при использовании его с уже
существующим скриптом. Данный пример будет строиться на создании <span class="caps">GUI</span>
интерфейса к программе Pygmynote - простой менеджер информации,
созданный для личного использования, записи заметок, ссылок. Хотя
Pygmynote и не сложен в использовании, добавим к нему несколько строчек
ввода, сделающие его более легким для управления записями.</p>
<p>Перед началом работы, надо установить EasyGUI. Скачайте последнюю версию
с официального сайта, распакуйте полученный архив и перенесите файл
easygui.py в директорию /usr/lib/python2.5/site-packages. Для
импортирования модуля EasyGUI используйте в своем скрипте строчку (в
начале скрипта)</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">easygui</span> <span class="kn">import</span>
</pre></div>
<p>Теперь можно приступать к изучению.</p>
<p>Для начала создадим окно приветствия программы Pygmynote, которое будет
встречать пользователей при запуске с помощью всплывающего окна
MessageBox. Функция msgbox требует всего-лишь один обязательный
параметр, текст сообщения:</p>
<div class="highlight"><pre><span></span><span class="n">msgbox</span><span class="p">(</span><span class="s2">"Pygmynote is ready."</span><span class="p">)</span>
</pre></div>
<p>Помимо этого, у нее есть еще три параметра, которые можно использовать
для задания различных функций сообщения: заголовок (box title), подпись
кнопки (the button label) и картинку. Вы можете использовать последний
параметр для выделения окна с помощью .gif рисунка. Пример окна со всеми
тремя параметрами:</p>
<div class="highlight"><pre><span></span><span class="n">image</span> <span class="o">=</span> <span class="s2">"pygmynote.gif"</span>
<span class="n">msgbox</span><span class="p">(</span><span class="s2">"Pygmynote is ready."</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="n">ok_button</span><span class="o">=</span><span class="s2">"Pile up!"</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="n">image</span><span class="p">)</span>
</pre></div>
<p>Для более легкого использования Pygmynote, можно создать меню со
списком, содержащее все команды. Пользователь сможет выполнить эту
команду выбрав ее из списка и нажав на кнопку “Ok”, или с помощью
двойного клика по выбранной команде. Чтобы это сделать, можно
использовать EasyGui’s choicebox функции. Также как и msgbox, checkbox
имеет три параметра: сообщение (the choicebox’s message), заголовок (the
window title), и список опций (a list of options):</p>
<div class="highlight"><pre><span></span><span class="n">msg</span> <span class="o">=</span><span class="s2">"What's your favorite fruit?"</span>
<span class="n">title</span> <span class="o">=</span> <span class="s2">"Fruity"</span>
<span class="n">choices</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Apple"</span><span class="p">,</span> <span class="s2">"Apricot"</span><span class="p">,</span> <span class="s2">"Pineapple"</span><span class="p">]</span>
<span class="n">choice</span> <span class="o">=</span> <span class="n">choicebox</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">choices</span><span class="p">)</span>
</pre></div>
<p>Когда пользователь выберет один из параметров и нажмет на кнопку “Ok”
(или двойной клик на выбраном), то функция вернет имя выбранного
элемента. Чтобы создать choicebox для Pygmenot, надо в список добавить
параметры программы:</p>
<div class="highlight"><pre><span></span><span class="n">msg</span> <span class="o">=</span><span class="s2">"Select command and press OK"</span>
<span class="n">title</span> <span class="o">=</span> <span class="s2">"Pygmynote"</span>
<span class="n">choices</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Help"</span><span class="p">,</span> <span class="s2">"Insert new record"</span><span class="p">,</span> <span class="s2">"Show all records"</span><span class="p">,</span> <span class="s2">"Quit"</span><span class="p">]</span>
<span class="n">command</span> <span class="o">=</span> <span class="n">choicebox</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">choices</span><span class="p">)</span>
</pre></div>
<p>Если вы сейчас запустите скрипт, то увидите окно choicebox с
отсортированным по алфавиту содержимым. Почему EasyGUI не соблюдает
порядок установки параметров? Чтобы этого избежать, надо использовать
такую запись: “1 - Insert new record” или “X - Quit”.</p>
<p>Следующая часть разработки нашего скрипта, это отображение найденых
результатов. Следующий код, показывает все полученные значения:</p>
<div class="highlight"><pre><span></span><span class="k">elif</span> <span class="n">command</span><span class="o">==</span><span class="s2">"a"</span><span class="p">:</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"SELECT * FROM notes ORDER BY id ASC"</span><span class="p">)</span>
<span class="n">rows</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchall</span> <span class="p">()</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
<span class="k">print</span> <span class="s2">"n </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> [</span><span class="si">%s</span><span class="s2">]"</span> <span class="o">%</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="k">print</span> <span class="s2">"n Number of records: </span><span class="si">%d</span><span class="s2">"</span> <span class="o">%</span> <span class="n">cursor</span><span class="o">.</span><span class="n">rowcount</span>
</pre></div>
<p>Используя функцию textblock можно отобразить множество строк в приятном
text box. Чтобы это создать, вам надо немного изменить код возвращающий
каждую найденую запись в виде строки. Используйте result_list = [] для
создания пустого списка, и метод .append для добавления в него записей:</p>
<div class="highlight"><pre><span></span><span class="k">elif</span> <span class="n">command</span><span class="o">==</span><span class="s2">"Show all records"</span><span class="p">:</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"SELECT * FROM notes ORDER BY id ASC"</span><span class="p">)</span>
<span class="n">rows</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchall</span> <span class="p">()</span>
<span class="n">result_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
<span class="n">record_str</span> <span class="o">=</span> <span class="s2">"n</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> [</span><span class="si">%s</span><span class="s2">]"</span> <span class="o">%</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="n">result_list</span><span class="o">.</span><span class="n">append</span> <span class="p">(</span><span class="n">record_str</span><span class="p">)</span>
<span class="n">textbox</span> <span class="p">(</span><span class="s2">"Found records:"</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="n">result_list</span><span class="p">)</span>
</pre></div>
<p>EasyGui’s boolbox функция позволяет вручную контролировать потоки
скрипта. Для примера, когда вы обновляете запись в Pygmynote, скрипт
спрашивает, уверены ли вы в обновлении записи или тэга. Оригинальный код
выполняющий данную функцию таков:</p>
<div class="highlight"><pre><span></span><span class="k">elif</span> <span class="n">command</span><span class="o">==</span><span class="s2">"u"</span><span class="p">:</span>
<span class="n">input_id</span><span class="o">=</span><span class="nb">raw_input</span><span class="p">(</span><span class="s2">"Record id: "</span><span class="p">)</span>
<span class="n">input_type</span><span class="o">=</span><span class="nb">raw_input</span><span class="p">(</span><span class="s2">"Update note (n) or tags (t): "</span><span class="p">)</span>
<span class="k">if</span> <span class="n">input_type</span><span class="o">==</span><span class="s2">"n"</span><span class="p">:</span>
<span class="n">input_update</span><span class="o">=</span><span class="nb">raw_input</span><span class="p">(</span><span class="s2">"Note: "</span><span class="p">)</span>
<span class="n">sqlstr</span><span class="o">=</span><span class="n">escapechar</span><span class="p">(</span><span class="n">input_update</span><span class="p">)</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"UPDATE notes SET note='"</span> <span class="o">+</span> <span class="n">sqlstr</span> <span class="o">+</span> <span class="s2">"' WHERE id='"</span> <span class="o">+</span> <span class="n">input_id</span> <span class="o">+</span> <span class="s2">"'"""</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">input_update</span><span class="o">=</span><span class="nb">raw_input</span><span class="p">(</span><span class="s2">"Tags: "</span><span class="p">)</span>
<span class="n">sqlstr</span><span class="o">=</span><span class="n">escapechar</span><span class="p">(</span><span class="n">input_update</span><span class="p">)</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"UPDATE notes SET tags='"</span> <span class="o">+</span> <span class="n">sqlstr</span> <span class="o">+</span> <span class="s2">"' WHERE id='"</span> <span class="o">+</span> <span class="n">input_id</span> <span class="o">+</span> <span class="s2">"'"""</span><span class="p">)</span>
<span class="k">print</span> <span class="s2">"nRecord has been updated."</span>
</pre></div>
<p>Функция boolbox позволяет вам показать диалоговое окно с двумя кнопками.
Функция возвратит 1, если нажата первая кнопка, и 0 - если вторая. Вот
простой пример:</p>
<div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">boolbox</span><span class="p">(</span><span class="s2">"What do monkeys like most?"</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"Bread"</span><span class="p">,</span> <span class="s2">"Bananas"</span><span class="p">]):</span>
<span class="n">msgbox</span> <span class="p">(</span><span class="s2">"Well, not really."</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">msgbox</span> <span class="p">(</span><span class="s2">"Yep, that's what they like most."</span><span class="p">)</span>
</pre></div>
<p>В нашем случае, вы можете использовать функцию boolbox для показа
диалогового окна с двумя кнопками выбора “Note” или “Tag”, и
перенаправления на обработку этого выбора:</p>
<div class="highlight"><pre><span></span><span class="k">elif</span> <span class="n">command</span><span class="o">==</span><span class="s2">"Update record"</span><span class="p">:</span>
<span class="n">input_id</span><span class="o">=</span><span class="n">enterbox</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s1">'Record ID: '</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s1">'Pygmynote'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">if</span> <span class="n">boolbox</span><span class="p">(</span><span class="s2">"What do you want to update?"</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"Note"</span><span class="p">,</span> <span class="s2">"Tags"</span><span class="p">]):</span>
<span class="n">input_update</span><span class="o">=</span><span class="n">enterbox</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s1">'Enter note: '</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s1">'Pygmynote'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">sqlstr</span><span class="o">=</span><span class="n">escapechar</span><span class="p">(</span><span class="n">input_update</span><span class="p">)</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"UPDATE notes SET note='"</span> <span class="o">+</span> <span class="n">sqlstr</span> <span class="o">+</span> <span class="s2">"' WHERE id='"</span> <span class="o">+</span> <span class="n">input_id</span> <span class="o">+</span> <span class="s2">"'"""</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">input_update</span><span class="o">=</span><span class="n">enterbox</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s1">'Enter tags: '</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s1">'Pygmynote'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">sqlstr</span><span class="o">=</span><span class="n">escapechar</span><span class="p">(</span><span class="n">input_update</span><span class="p">)</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"UPDATE notes SET tags='"</span> <span class="o">+</span> <span class="n">sqlstr</span> <span class="o">+</span> <span class="s2">"' WHERE id='"</span> <span class="o">+</span> <span class="n">input_id</span> <span class="o">+</span> <span class="s2">"'"""</span><span class="p">)</span>
<span class="n">msgbox</span> <span class="p">(</span><span class="s2">"Record has been updated."</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="n">ok_button</span><span class="o">=</span><span class="s2">"Close"</span><span class="p">)</span>
</pre></div>
<p>Для создания imput box только с числовыми вариантами, можно использовать
функцию integerbox. В параметры функции можно задать верхний и нижний
диапазон. Для примера, можно модифицировать часть скрипта Pygmynote
отображающего календарь с месяцами от 1 до 12:</p>
<div class="highlight"><pre><span></span><span class="n">inputmonth</span><span class="o">=</span><span class="n">integerbox</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s1">'"Month (1-12): "'</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s1">'Pygmynotes'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span> <span class="n">argLowerBound</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">argUpperBound</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span>
</pre></div>
<p>Также, EasuGUI предлагает функцию diropenbox, которая показывает dialog
box выбора директории. Вы можете добавить эту функцию в часть скрипта
Pygmynote для выбора пути сохранения всех записей pygmynote.txt..
Оригинальная часть кода сохраняющая все записи в исходную папку, но
используя diropenbox для указания пользователем папки сохранения:</p>
<div class="highlight"><pre><span></span><span class="k">elif</span> <span class="n">command</span><span class="o">==</span><span class="s2">"Save all records as pygmynote.txt"</span><span class="p">:</span>
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span> <span class="p">(</span><span class="s2">"SELECT * FROM notes ORDER BY id ASC"</span><span class="p">)</span>
<span class="n">rows</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchall</span> <span class="p">()</span>
<span class="n">filedir</span> <span class="o">=</span> <span class="n">diropenbox</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s2">"Select directory"</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">filedir</span> <span class="o">+</span> <span class="n">os</span><span class="o">.</span><span class="n">sep</span> <span class="o">+</span> <span class="s2">"pygmynote.txt"</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">rows</span><span class="p">:</span>
<span class="nb">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s1">'a'</span><span class="p">)</span>
<span class="nb">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2">t</span><span class="si">%s</span><span class="s2">t[</span><span class="si">%s</span><span class="s2">]n"</span> <span class="o">%</span> <span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">row</span><span class="p">[</span><span class="mi">2</span><span class="p">]))</span>
<span class="nb">file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">msgbox</span> <span class="p">(</span><span class="s2">"Records have been saved in the pygmynote.txt file."</span><span class="p">,</span> <span class="s2">"Pygmynote"</span><span class="p">,</span> <span class="n">ok_button</span><span class="o">=</span><span class="s2">"Close"</span><span class="p">)</span>
</pre></div>
<p>EasyGui не может заменить полнофункциональные библиотеки для создания
интерфейсов, такие как TKinter, WxPython, <span class="caps">GTK</span>+, <span class="caps">QT</span>, но является
замечательным средством для создания интерфейсов простых скриптов новичками.</p>
<p>Ссылки: <a class="reference external" href="http://www.linux.com/feature/145949">первоисточник</a></p>
<p>Официальный сайт <a class="reference external" href="http://easygui.sourceforge.net/">EasyGUI</a></p>
<p>Скрипт <a class="reference external" href="http://code.google.com/p/pygmynote/">Pygmynote</a></p>
<p><a class="reference external" href="http://www.ferg.org/easygui/tutorial.html">EasyGui tutorial</a></p>
Мои любимые подкасты2008-06-26T14:03:00+03:00gigimontag:it4it.ru,2008-06-26:2008/06/26/moi-lyubimye-podkasty/<p>В продолжении предыдущего поста, хочу рассказать про подкасты которые я
часто слушаю</p>
<p>#. <a class="reference external" href="http://radio-t.com">Радио-Т</a> - это еженедельный Hi-Tech подкаст. Авторы и приглашенные
гости импровизируют на околокомпьютерные темы.
<strong>Ведущие:</strong> umputun, bobuk, olyapka.
<strong>Частота выхода:</strong> 1 раз в неделю, по субботам.
<strong>Количество выпусков (в момент написания):</strong> 92
<strong>Тип трансляции:</strong> возможность прослушивания прямого эфира,
обсуждение в jabber. Либо скачать отдельно mp3 файл
<strong>Продолжительность:</strong> 70-100 минут
<strong>Качество звука:</strong> Во время прослушивания прямого эфира и в Mp3
файле - отличное
<strong>Мнение:</strong> Один из старейших технических подкастов. Слушаю каждый
его выпуск, авторы хорошие ИТ специалисты. Хорошо рассуждают, имеют
большой опыт подкастинга, не спотыкаются. Советую послушать всем.
#. <a class="reference external" href="http://pod.internetno.net/">Podштучки</a> - еженедельный подкаст по мотивам сайта <a class="reference external" href="http://internetno.net/">Интернет
штучки</a>
<strong>Ведущие:</strong> Текст читает: Наталья Семашева, Автор текста: Илья Новиков.
<strong>Частота выхода:</strong> 1 раз в 7-10 дней (иногда чаще)
<strong>Количество выпусков (в момент написания):</strong> 40
<strong>Тип трансляции:</strong> Только mp3-файл
<strong>Продолжительность:</strong> 10-15 минут
<strong>Качество звука:</strong> Очень хорошее
<strong>Мнение:</strong> Освещение событий интернета по мотивам сайта. Тексты
интересные, читает приятный женский голос. Интонация хорошая.
Удручает то, что выходит не регулярно.
#. <a class="reference external" href="http://gray.podfm.ru/it/"><span class="caps">IT</span>-мысли</a> - подкаст <span class="caps">IT</span> тематики.
<strong>Ведущие:</strong>Gray
<strong>Частота выхода:</strong> Последнее время раз в неделю. Но довольно часто
бывают большие паузы между выпусками
<strong>Количество выпусков (в момент написания):</strong> 22
<strong>Тип трансляции:</strong> Только mp3-файл
<strong>Продолжительность:</strong> 20-30 минут
<strong>Качество звука:</strong> Хорошее
<strong>Мнение:</strong> Gray освещает темы за прошедшее время, + иногда
рассказывает про свою работу в Яндексе. Обычно слушаю из-за
последнего фактора, т.к. интересно. К сожалению у него нехватает
опыта по изложению материала, достаточно часто повторяется в
подкасте. Ну а так, достаточно интересный подкаст.
#. <a class="reference external" href="http://podcast.dvice.ru/">Dvicecast</a> (бывший Radio-U) - ведущие перевели свой подкаст на
обсуждение тем с сайта dvice.ru
<strong>Ведущие:</strong>freetonik <span class="amp">&</span> gimlis
<strong>Частота выхода:</strong> Стараются раз в неделю, но бывают и перерывы.
<strong>Количество выпусков (в момент написания):</strong> 2 9если не брать в
расчет ~20 выпусков Radio-U)
<strong>Тип трансляции:</strong> Только mp3-файл
<strong>Продолжительность:</strong> ~45 минут
<strong>Качество звука:</strong> Хорошее, иногда шумит
<strong>Мнение:</strong> freetonik и gimlis достаточно хорошо освещают темы, не
спотыкаются. К сожалению из-за занятости обоих, подкаст не регулярный :(
#. <a class="reference external" href="http://podcast.umputun.com/"><span class="caps">UWP</span></a> - еженедльный подкаст от umputun
<strong>Ведущие:</strong>umputun
<strong>Частота выхода:</strong> Раз в неделю, преимущественно суббота-понедельник
<strong>Количество выпусков (в момент написания):</strong> 181
<strong>Тип трансляции:</strong> Только mp3-файл
<strong>Продолжительность:</strong> ~45 минут
<strong>Качество звука:</strong> Отличное
<strong>Мнение:</strong> Известны (для меня) по подкасту Radio-T ведущий umputun
рассказывает о своей жизни в Америке. Очень интересно слушать, как
живут люди в Америке со стороны русского.
#. <a class="reference external" href="http://rosnovsky.ru">Rosnovsky Park</a> - подкаст о жизни Артема Росновского, ведущего на радио Маяк
<strong>Ведущие:</strong>Артем Росновский
<strong>Частота выхода:</strong> Раз в неделю, по воскресеньям
<strong>Количество выпусков (в момент написания):</strong> 101
<strong>Тип трансляции:</strong> Только mp3-файл
<strong>Продолжительность:</strong> 30-40 минут
<strong>Качество звука:</strong> Отличное
<strong>Мнение:</strong> Человек с большим опытом говорения, рассказывает про
свою жизнь :) отличный голос + отличные выражения, подкаст слушается на 1 дыхании.</p>
<p>Ну вот, описал подкасты которые слушаю я всегда, все новые выпуски.
есть еще кучка покдастов, которые я пытался слушать, но что-то в них не
понравилось, не буду их называть.
<span class="caps">P.S.</span> 2 umputun, слышал, что вы по гуглу ходите и смотрите где
упоминаетесь, если тут вдруг будете, оставьте комментарий пожалуйста :)
2 Gray - 21 выпуск, когда говорил, что быстро говоришь, такой темп
лучше всего звучал.</p>
Что послушать по дороге…2008-06-06T00:30:00+03:00gigimontag:it4it.ru,2008-06-06:2008/06/06/chto-poslushat-po-doroge/<p>Давно я не писал. Дела к сожалению, сессия и т.п. Вот все же выделил
время и решил написать статью про набирающую обороты в интернете тему
подкастов (podcast).</p>
<p>Собственно, для тех кто не в теме, подкаст - это аудиозапись, где 1 и
больше людей беседуют на какую-либо тему, либо что-то рассказывает.
Большинство подкастов выходит раз в неделю, обычно в определенные дни
(так специально для удобства слушателей стараются авторы подкастов).
Подкаст может проходить как в режиме реального времени, с возможностью
последующей скачки записи, либо только запись (большиство). Длительность
подкастов от 30 до 120 минут, меньше или больше встерчаются достаточно
редко. Тематика подкастов в настоящее время может быть совершенно
разная, от разговоров ни о чем, до высоких технологий и коллайдера
(модное слово типа :) ).
Ну, думаю после этой маленькой заметки, слушателей подкастов станет
немного больше ;)
Сайты где можно найти подкасты и почитать про подкастинг:
<a class="reference external" href="http://rpod.ru">rpod</a> ; <a class="reference external" href="http://podfm.ru">podfm</a> ; <a class="reference external" href="http://www.podcastim.ru/">подкастим</a></p>
<p><span class="caps">P.S.</span>сам я слушаю подкасты уже больше полугода, они азменяют мне
музыку в дороге</p>
Сравнение консольных torrent качалок с web мордой (часть 2)2008-04-20T12:36:00+03:00gigimontag:it4it.ru,2008-04-20:2008/04/20/sravnenie-torrent-kachalok-chast-2/<p>Ну вот, дошли руки до написания второй части. Сегодня хочу рассказать
про <a class="reference external" href="http://developer.berlios.de/projects/tf-b4rt/">torrentflux</a> качалку.</p>
<p>Начнем с обзора.</p>
<p>На ее родном сайте, написано, что она испольузется как фронтэнд к
transmission, bittornado. Ну прочитав такое, обрадовался, ведь
трансмишшин стоит! Написан он весь на <span class="caps">PHP</span>.</p>
<p>Итак, начал устанавливать. Установка происходит легко, распаковал в
папку сервера, зашел браузером, указал лог/пасс на базу и все. Зашел, и
получил сразу окно настроек:</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/04/tfx.png"><img alt="Главное окно настроек" src="http://it4it.ru/images/2008/04/tfx-150x150.png" /></a></p>
<p><a class="reference external" href="http://it4it.ru/images/2008/04/tfx.png"><img alt="image0" src="http://it4it.ru/images/2008/04/tfx.png" /></a> Первое что бросилось в глаза, он не обнаружил мой transmission.
Строчка:”Executable is not TorrentFlux-bundled transmissioncli” Т.е. ему
нужен его трансмишшин :( Заставить работать с моим трансмишшионом я не смог.</p>
<p>Посмотрев по папке torrentflux, обнаружил исходники трансмишшиона версии 1.06.</p>
<p>Настроек у него тьма тьмущая, в основном относящиеся к управлению
качалками и управлениями пользователями, которые действительно полезны
(управление правами). Также, он очень убедительно требовал установленого
unrar, unzip, vlc. Для чего,я незнаю, т.к. найти какие-то функции с
использованиех оных не смог.</p>
<p>Полазив по настройкам, обнаружил, что можно его запускать как демона
(зачем,я незнаю, если это всего лишь фронтэнд как пишут). Но просто так
запустить как демона не смог. У него есть 2 режима запуска как демона,
<span class="caps">PHP</span>+fluxcli.php и <span class="caps">PHP</span>+DBi/<span class="caps">DBD</span>. Ни с каким не заработало. ошибок нет.</p>
<p>Ладно, т.к. проверить качалку торрент в этот раз не судьба, зашел просто
на страницу управления задачами.</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/04/tfx1.png"><img alt="image1" src="http://it4it.ru/images/2008/04/tfx1-150x150.png" /></a></p>
<p>` <{filename}/images/2008/04/tfx1.png>`__Ну решил
хотя бы првоерить скачку по обычным протоколам с помощью wget. Закинул в
задачи пару файлов, и ни один не пошел качаться. Долго шло Connecting и
потом Error.</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/04/tfx2.png"><img alt="image2" src="http://it4it.ru/images/2008/04/tfx2-150x150.png" /></a></p>
<p>Увы, как то заставить работать, замечательный на вид, клиент так и не получилось.</p>
<p><span class="caps">P.S.</span>примерно полгода назад, я ставил его transmissioncli. Он его
обнаруживал, но всеравно не качал, почему, дял меня осталось загадкой.</p>
Что ж такое mercurial2008-04-20T11:24:00+03:00admintag:it4it.ru,2008-04-20:2008/04/20/chto-zh-takoe-mercurial/<p>Недавно появилась проблемка, пишу 1 проектик с двух компьютеров, а
таскать на флэхе или фтп стало лень. Т.к. имеется компьютер, который
видят оба компьютера, то решил поиспользовать систему контроля версий.
Хотел поставить старую добрую <span class="caps">SVN</span>, но ребята с
<a class="reference external" href="mailto:pythonua@conference.jabber.ru">pythonua@conference.jabber.ru</a> быстро отговорили,и сказали что теперь
модно использовать не централизованные систему, и посоветовали Mercurial.</p>
<p><a class="reference external" href="http://www.selenic.com/mercurial/">Mercurial</a> представляет собой децентрализованную систему контроля
версий (как и git). Он написан на питоне, но очень оптимизирован и
работает очень шустро.</p>
<p>Ну вот, приблизились к суте заметки, хочу рассказать основные действия
при работе с ним.</p>
<p>#. Первое что надо сделать для своего проекта, это создать репозитарий!
Для этого надо зайти в нужную папку и выполнить команду “hg init”.
#. Теперь можно и добавитьвсе файлы в проект командой “hg add”
#. Теперь занесем ка все в свой, домашний репозитарий командой “hg
commit -m “your message”“, чтобы просмотреть свой результат,
воспользуемся “hg log”, где и увидиим что добавили.
#. Если хотим скопировать наш репозитарий куда-то, то пишем “hg clone .
<a class="reference external" href="ssh://user@ip/folder">ssh://user@ip/folder</a>“, где . это указывает гед находится репозитарий
который клонировать, точка обозначает ,что вы в папке с ним.
#. Чтобы забрать изменения с какого-то источника, можно использовать “hg
pull”
#. Ну а если хотите куда-то перенести изменения, то “hg push”</p>
<p>Ну вот и все, как бы не сложно для начала. У mercurial множество еще
всяких опций и функций, у него встроеный веб сервер для просомтра
репозитария есть “hg serve” ;)</p>
<p>Надеюсь эта заметка хоть кому то поможет с ознакомлением)</p>
Скрипт для скачки аниме с dattebayo2008-04-18T17:17:00+03:00gigimontag:it4it.ru,2008-04-18:2008/04/18/skript-dlya-skachki-anime-s-dattebayo/<p>Решил поделиться своим скриптом для скачки аниме с <a class="reference external" href="http://dattebayo.com">dattebayo</a> . Там
выкладываются релизы от dattebayo. Последнее время там: bleach, naruto.</p>
<p>Собственно, мой скрипт качает серии блича (наруто я не смотрю) с главной
страницы сайта.</p>
<p>Вот весь скрипт:</p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="k">class</span> <span class="nc">getsBleach</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url_site</span><span class="o">=</span><span class="s2">"http://dattebayo.com/"</span><span class="p">,</span> <span class="nb">file</span><span class="o">=</span><span class="s2">"bleach"</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">url_site</span> <span class="o">=</span> <span class="n">url_site</span>
<span class="bp">self</span><span class="o">.</span><span class="n">file</span> <span class="o">=</span> <span class="nb">file</span>
<span class="k">def</span> <span class="nf">find_link</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">):</span>
<span class="sd">"""В этом методе, получим из страницы все ссылки на торрент с бличем"""</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">site</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">url_site</span><span class="p">)</span>
<span class="k">except</span> <span class="n">URLError</span><span class="p">:</span>
<span class="k">print</span> <span class="s2">"Error URL"</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="n">site</span> <span class="o">=</span> <span class="n">site</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">razdel</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s1">r'( Bleach d+ )'</span><span class="p">)</span> <span class="c1">#делаем паттерн</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">razdel</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span> <span class="n">site</span> <span class="p">)</span> <span class="c1">#находим все по паттерну в список</span>
<span class="k">for</span> <span class="n">rez</span> <span class="ow">in</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
<span class="n">episode_num</span> <span class="o">=</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">rez</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">)[</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span> <span class="c1">#находим нмоер эпизода</span>
<span class="k">if</span> <span class="n">episode_num</span> <span class="o">></span> <span class="bp">self</span><span class="o">.</span><span class="n">getOldNum</span><span class="p">():</span> <span class="c1">#проверка на новизну</span>
<span class="n">link</span> <span class="o">=</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">""")[1] #ссылка</span>
<span class="s2"> self.saveNewEpisode(episode_num) #передаем на обработку ссылки</span>
<span class="s2"> def getOldNum(self):#тут получаем из файла номер последней серии</span>
<span class="s2"> try:</span>
<span class="s2"> numfile = open( self.file, "r" )#имя файла при инициализации</span>
<span class="s2"> except:</span>
<span class="s2"> return 0</span>
<span class="s2"> numOldEpisode = numfile.readline()</span>
<span class="s2"> file.close</span>
<span class="s2"> return numOldEpisode</span>
<span class="s2"> def saveNewEpisode( self, newEpisode, tor_com="transmission-remote -a" ):</span>
<span class="s2"> tor_url = self.url_site + "t/b" + newEpisode + ".torrent" #создаем ссылку</span>
<span class="s2"> fileurl = urllib.urlretrieve(tor_url) #скачиваем торрент</span>
<span class="s2"> os.system("</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">" % (tor_com, fileurl[0]))#отправляем торрент транмишиону</span>
<span class="s2"> file = open( self.file, "w+" )#записываем номер эпизода</span>
<span class="s2"> file.write( "</span><span class="si">%s</span><span class="s2">" % newEpisode )</span>
<span class="s2"> file.close()</span>
<span class="s2">starting = getsBleach()</span>
<span class="s2">numep = starting.getOldNum()</span>
<span class="s2">starting.find_link(numep)</span>
</pre></div>
<p>Торренты скачиваются в /tmp (ну или временную папку системы), и
передаются на скачку transmission-remote.</p>
<p>Скрипт удобно держать в cron’e, чтобы автоматизировать скачку аниме ;)</p>
Сравнение консольных torrent качалок с web мордой (часть 1)2008-04-14T19:04:00+03:00admintag:it4it.ru,2008-04-14:2008/04/14/sravnenie-konsolnyx-torrent-kachalok-s-web-mordoj-chast-1/<p>Недавно появился “лишний” компьютер, который захотел использовать как
качалку файлов из интернета, и тестовую лабораторию. И встала передо
мной проблема выбора torrent качалки, не требующая иксов (Х сервера). Из
требований нужно было:</p>
<ol class="arabic simple">
<li>самое важное, это наличие удобного web гуя ( не один я буду
использовать сервер свой)</li>
<li>чтобы не был забанен серверами - да, бывают и такие :)</li>
<li>удобный, с возможностью работы в режиме демона</li>
<li>стабильный!</li>
</ol>
<p>Ну, требований впринципе достаточно мало, самое важное это web морда.
Немного погуглив, нашел следуюшие:</p>
<ol class="arabic simple">
<li>Transmission <a class="reference external" href="http://www.transmissionbt.com/">http://www.transmissionbt.com/</a></li>
<li>ctorrent <a class="reference external" href="http://ctorrent.sourceforge.net/">http://ctorrent.sourceforge.net/</a></li>
<li>rtorrent <a class="reference external" href="http://libtorrent.rakshasa.no/">http://libtorrent.rakshasa.no/</a></li>
<li><span class="caps">BTG</span> <a class="reference external" href="http://btg.berlios.de/">http://btg.berlios.de/</a></li>
<li>TorrentFlux <a class="reference external" href="http://www.torrentflux.com/">http://www.torrentflux.com/</a></li>
</ol>
<p>Теперь давайте с каждым поподробнее.</p>
<p>1. Начнем с Transmission. Это самостоятельная разработка, основывающая
на своей библиотеки, имеет сборки под Mac <span class="caps">OS</span> X, и собственно Linux на
<span class="caps">GTK</span>+.</p>
<p>Transmission написан на С. Может работать в режиме демона, что как раз
мне и нужно было ;). Управлять им можно с помощью утилитки идущей с ним
transmission-remote. Возможности демона довольно просты:</p>
<ul class="simple">
<li>добавление/удаление торрента</li>
<li>установка лимитов скорости</li>
<li>управление торрентами, старт/стоп</li>
<li>проверить данные</li>
<li>сменить порт</li>
<li>изменить настройки прокси сервера</li>
</ul>
<p>Для него нашел только одну веб морду под названием <a class="reference external" href="http://clutchbt.com/">Clutch</a> . Для ее
установки требуется установленный <span class="caps">PHP</span> 5, с поддержкой сокетов. Установка
довольно простая, закинул в папку сервера, изменил права на сокет
Transmission’a, зашел на сервер и вуаля, все заработало.</p>
<p><a class="reference external" href="http://it4it.ru/images/2008/04/clutch.png"><img alt="image0" src="http://it4it.ru/images/2008/04/clutch-150x150.png" /></a></p>
<p>Возможности не велики, как видно из скриншота, можно добавлять/удалять
торрент файл, ставить на паузу, запускать отдельные торренты,
ограничивать скорость, смотреть информацию о торрент файле. Большой плюс
то, что все написано на JavaScript, поэтому не требуется перегружать
страницу ;) очень удобно. Хоть функционал и мал, его достаточно почти всегда.</p>
<p>Плюсы Transmission + Clutch:</p>
<ul class="simple">
<li>удобный</li>
<li>не перегружен функциями</li>
<li>отлично качает</li>
<li>web морда полностью на JavaScript (хоят может и минус)</li>
<li>не теряет торренты при внезапных перезагрузках, очень стабилен</li>
</ul>
<p>Минусы:</p>
<ul class="simple">
<li>долго делает верификацию данных</li>
<li>Иногда не качает по неизвестным мне причинам (вроде и сидеры есть, и
трекер отвечает, но прцоент загрузки не увеличивается :( )</li>
</ul>
<p>Ну, в общем хороший клиент для отдельного качания, не требующим
бооольшой функционал.</p>
<p>Ну вот, на этом первая часть обзора закончена ;) В следующий раз
расскажу про другой клиент.</p>
<p><span class="caps">P.S.</span>сам я как раз и использую эту связку Transmission + Clutch</p>
Скрипт отправки на dpaste.com2008-04-11T23:55:00+03:00admintag:it4it.ru,2008-04-11:2008/04/11/skript-otpravki-na-dpastecom/<p>Хочу показать свой скрипт, написанный на Python для отправки содержимого
файла на сервич публикования кода ( ну или как они называются )
<a class="reference external" href="http://dpaste.com">dpaste.com</a> .</p>
<p>Собственно вот код скрипта:</p>
<div class="highlight"><pre><span></span><span class="ch">#!/usr/bin/env python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="c1">#Script for send to dpaste.com</span>
<span class="kn">import</span> <span class="nn">urllib</span><span class="o">,</span><span class="nn">sys</span>
<span class="c1">#Список хедеров</span>
<span class="n">header</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'content'</span><span class="p">:</span><span class="s2">""</span><span class="p">,</span>
<span class="s1">'language'</span><span class="p">:</span><span class="s2">"Python"</span><span class="p">,</span>
<span class="s1">'title'</span><span class="p">:</span><span class="s2">""</span><span class="p">,</span>
<span class="s1">'poster'</span><span class="p">:</span><span class="s2">""</span><span class="p">,</span>
<span class="s1">'hold'</span><span class="p">:</span><span class="s2">""</span>
<span class="p">}</span>
<span class="n">url</span> <span class="o">=</span> <span class="s2">"http://dpaste.com/"</span>
<span class="c1">#првоеряем аргументы введеные при запуске</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span> <span class="p">)</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">parameters</span> <span class="o">=</span> <span class="nb">iter</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span>
<span class="c1">#првоерка на наличие аргументов</span>
<span class="k">for</span> <span class="n">argument</span> <span class="ow">in</span> <span class="n">parameters</span><span class="p">:</span>
<span class="k">if</span> <span class="n">argument</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"-"</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="n">next</span><span class="p">();</span>
<span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"-"</span><span class="p">):</span>
<span class="k">print</span> <span class="s2">"Vvedite parametr posle klu4a "</span><span class="o">%</span><span class="n">s</span><span class="s2">""</span> <span class="o">%</span> <span class="n">argument</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">StopIteration</span><span class="p">:</span>
<span class="k">print</span> <span class="s2">"ERROR"</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">if</span> <span class="n">argument</span> <span class="o">==</span> <span class="s2">"-l"</span><span class="p">:</span>
<span class="n">header</span><span class="p">[</span><span class="s1">'language'</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">if</span> <span class="n">argument</span> <span class="o">==</span> <span class="s2">"-t"</span><span class="p">:</span>
<span class="n">header</span><span class="p">[</span><span class="s1">'title'</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">if</span> <span class="n">argument</span> <span class="o">==</span> <span class="s2">"-p"</span><span class="p">:</span>
<span class="n">header</span><span class="p">[</span><span class="s1">'poster'</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">if</span> <span class="n">argument</span> <span class="o">==</span> <span class="s2">"-h"</span><span class="p">:</span>
<span class="n">header</span><span class="p">[</span><span class="s1">'hold'</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
<span class="k">if</span> <span class="n">argument</span> <span class="o">==</span> <span class="s2">"-f"</span><span class="p">:</span>
<span class="n">name_file</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">files</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">name_file</span><span class="p">,</span><span class="s2">"r"</span><span class="p">)</span>
<span class="n">header</span><span class="p">[</span><span class="s1">'content'</span><span class="p">]</span> <span class="o">=</span> <span class="n">files</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">files</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">openurl</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">url</span><span class="p">,</span><span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">header</span><span class="p">))</span>
<span class="n">adress</span> <span class="o">=</span> <span class="n">openurl</span><span class="o">.</span><span class="n">geturl</span><span class="p">()</span>
<span class="k">print</span> <span class="s2">"Your script on: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">adress</span>
</pre></div>
<p>Работает скрипт довольно просто, отправляет данные на dpaste, с помощью
их веб формы для добавления кода.</p>
<p>Использовать скрипт крайне легко, он имеет несколько ключей:</p>
<p>-l —- язык, на котором написан код ( по-умолчанию питон ;) )</p>
<p>-t —- заголовок</p>
<p>-p —- имя автора</p>
<p>-h —- заблокировать или нет</p>
<p>-f —- путь к файлу для публикации.</p>
<p>Обязательным является только ” -f “</p>
<p><span class="caps">P.S.</span>Написан на чистом питоне, работоспособность проверена лишь в Linux.
Закинул его в /usr/sbin и юзаю через ‘ dpaste -f /path/to/file ‘</p>
<p>Удачи в использовании, если что-то непонятно,пишите, на
профессиональность кода не расчитываю)</p>