2011/02/17

Парсим XML

Даны два xml-файла, отличающиеся только атрибутами
Файл 1:
<root>
<nodeA val1="1" val2="2" val3="3">
<nodeB val1="1" val2="2" val3="3"/>
</nodeA>
<nodeC val1="1" val2="2" val3="3"/>
</root>
Файл 2:
<root>
<nodeA val1="1" val2="X" val4="4">
<nodeB val1="1" val2="X" val4="4"/>
</nodeA>
<nodeC val1="1" val2="X" val4="4"/>
</root>
Надо реализовать на любом скриптовом языке слияние Файла 1 в Файл 2 так, чтобы в Файле 2:
1) остались уникальные атрибуты Файла 2;
2) присутствовали уникальные атрибуты Файла 1;
3) совпадающие атрибуты имели значения из Файл 1.

Я делал с помощью модуля lxml, которой нет в стандартной поставке питона. Чтобы использовать стандартный модуль xml, надо просто заменить первую строчку на import xml.etree.ElementTree as etree - интерфейсы в этом случае одинаковые.

from lxml import etree

file1 = open('1.xml', 'r')
tree1 = etree.parse(file1)
file1.close()
root1 = tree1.getroot()

file2 = open('2.xml', 'r')
tree2 = etree.parse(file2)
file2.close()
root2 = tree2.getroot()

for i in range(len(root1)):
    for ikey in root1[i].keys():
        root2[i].attrib[ikey] = root1[i].attrib[ikey]

    if len(root1[i]) > 0:
        for j in range(len(root1[i])):
            for jkey in root1[i][j].keys():
                root2[i][j].attrib[jkey] = root1[i][j].attrib[jkey]

file2 = open('2.xml', 'w')
file2.write(etree.tostring(root2))
file2.close()

Атрибуты и их значения здесь представлены в виде словарей, поэтому ими можно легко манипулировать. Более подробная информация здесь: http://lxml.de/tutorial.html

2011/02/16

Проверка логина на корректность

Условие такое:

Логин должен начинаться с латинской буквы, может состоять из латинских букв, цифр, точки и минуса и должен заканчиваться латинской буквой или цифрой. Минимальная длина логина – 1 символ. Максимальная – 20
символов.

import re
from operator import truth

def logincheck(login):
    if login == '' or len(login) > 20:
        print 'False'
        return
    elif len(login) > 2:
        if (truth(re.match('[a-zA-Z]', login[0])) + \
            truth(re.match('[a-zA-Z0-9]', login[-1])) + \
            truth(re.match('^([a-zA-Z0-9\-\.])+$', login[1:-1]))) == 3:
            print 'True'
        else: print 'False'
        return
    elif len(login) == 2:
        if (truth(re.match('[a-zA-Z]', login[0])) + \
            truth(re.match('[a-zA-Z0-9]', login[-1]))) == 2:
            print 'True'
        else: print 'False'
        return
    else:
        if (truth(re.match('[a-zA-Z]', login[0]))) == 1:
            print 'True'
        else: print 'False'

Здесь проверка разбита на несколько этапов: для логина > 2 символов, для = 2 символам и для = 1 символу. Можно, конечно, сделать в 1 регулярное выражение, но мои копошения так и не смогли вывести такую регулярку. Если кто покажет - буду очень рад.

2011/02/15

Преобразование числа в IP адрес

Возобновляю записи по питону! На сайте Яндекса можно найти много тренировочных задачек, что ж, приступим. :)

def ip2str(ip):
        if ip > 0xffffffff:
                raise ValueError('number must be 32 bit')
        ipstr = str(ip >> 24) + '.' + \
                str((ip & 0x00ffffff) >> 16) + '.' + \
                str((ip & 0x0000ffff) >> 8) + '.' + \
                str((ip & 0x000000ff))
        print ipstr

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

2011/02/14

Консоль - лучший друг линуксоида

Поэтому требует особенного внимания к себе. Недавно перешел на всеми любимый urxvt, и там есть возможность менять стандартные цвета терминала для лучшего восприятия информации. Но какие параметры за что отвечают? Вразумительного ответа в сети я не нашел и путем экспериментов выяснил сам. Во-первых, нужно создать файл, который будет выводить надписи в терминал разными цветами. Вот он:

#!/bin/bash

echo -e "\e[0;30mCOLOR_BLACK\t\e[1;30mCOLOR_BOLD_BLACK"
echo -e "\e[0;31mCOLOR_RED\t\e[1;31mCOLOR_BOLD_RED"
echo -e "\e[0;32mCOLOR_GREEN\t\e[1;32mCOLOR_BOLD_GREEN"
echo -e "\e[0;33mCOLOR_YELLOW\t\e[1;33mCOLOR_BOLD_YELLOW"
echo -e "\e[0;34mCOLOR_BLUE\t\e[1;34mCOLOR_BOLD_BLUE"
echo -e "\e[0;35mCOLOR_PURPLE\t\e[1;35mCOLOR_BOLD_PURPLE"
echo -e "\e[0;36mCOLOR_CYAN\t\e[1;36mCOLOR_BOLD_CYAN"
echo -e "\e[0;37mCOLOR_WHITE\t\e[1;37mCOLOR_BOLD_WHITE"

Настройки urxvt надо записывать в файл ~/.Xdefaults, среди которых есть color0-15, соответствие которых с выводом вышенаписанного скрипта представлено ниже:

color0 = COLOR_BLACK
color1 = COLOR_RED
color2 = COLOR_GREEN
color3 = COLOR_YELLOW
color4 = COLOR_BLUE
color5 = COLOR_PURPLE
color6 = COLOR_CYAN
color7 = COLOR_WHITE
color8 = COLOR_BOLD_BLACK
color9 = COLOR_BOLD_RED
color10 = COLOR_BOLD_GREEN
color11 = COLOR_BOLD_YELLOW
color12 = COLOR_BOLD_BLUE
color13 = COLOR_BOLD_PURPLE
color14 = COLOR_BOLD_CYAN
color15 = COLOR_BOLD_WHITE

Немного повозившись поставил следующие цвета:

URxvt.color0: #333333
URxvt.color1: #d43a2a
URxvt.color2: #00c800
URxvt.color3: #cdcd00
URxvt.color4: #005d9a
URxvt.color5: #cd68cd
URxvt.color6: #009f9f
URxvt.color7: #dddddd
URxvt.color8: #333333
URxvt.color9: #d43a2a
URxvt.color10: #00c800
URxvt.color11: #cdcd00
URxvt.color12: #005d9a
URxvt.color13: #cd68cd
URxvt.color14: #009f9f
URxvt.color15: #dddddd

Скриншот всего этого непотребства:

2010/08/21

MinimalGray — тема для OpenBox

Пару вечеров угробил на то, чтобы сделать самую лучшую тему для опенбокса, как я её себе представляю. Вдохновение дала популярная тема Dyne (при ближайшем рассмотрении которой выяснилось весьма кривое оформление кода).
Итак, что же в этой теме есть и чего там нет? В отличие от Dyne более светлые декорации окон, есть границы декорированных окон (1 пиксель), используется более читабельный нежирный шрифт с тенями, концептуальный индикатор переключения рабочих столов. Присутствует классическое затемнение декорации неактивного окна на один тон, что в общем-то не так заметно, но как бы традиционно. Кнопки управления окном появляются только при наведении. Все остальные понты и градиенты отсутствуют.


Скачивать архив тут. Распаковать нужно в /usr/share/themes или ~/.themes
Материал, использованный при подготовке.

2010/08/18

slock — самый лучший блокиратор экрана

Про эту программу можно с уверенностью сказать — она делает что-то одно и делает это хорошо. Slock блокирует и гасит экран без лишних понтов, разблокировка происходит без всяких приглашений ввести пароль, его просто надо ввести и нажать Enter. Я в первый раз чуть не обоссался, когда всё погасло и ничего не реагировало, так что не повторяйте моих ошибок.

А классический скринсейвер — это, по-моему, слишком расточительно. Мало того, что он жрет много процессорного времени, если там стоит мало-мальски серьезная сцена. Так и ещё много ненужного функционала, который работает постоянно, как например демон в xscreensaver.

Правда при использовании slock возможно придется изменить параметр, отвечающий за отключение экрана из-за неактивности в xorg.conf (по умолчанию 10 минут, маловато), нужно добавить в секцию ServerFlags (у меня этой секции вообще не было, пришлось добавить и её) следующую опцию: Option "BlankTime" "240". 240 — количество минут, оптимальное на мой взгляд время, чтобы экран точно не погас во время просмотра какого-нибудь фильма. :)

Ах да, страничка программы. Но лучше — ищите в репозиториях своих дистрибутивов.

2010/07/28

Поднимаем ZNC на gentoo

ZNC - известный irc bouncer, т.е. выступает в качестве прокси при соединении с серверами irc. Полезен не только в том плане, что сохраняет личные сообщения и статус онлайн в отсутствие клиента, но и может шифровать трафик от клиента до себя.

Ну и после появления у себя уютненького сервера на gentoo, я, разумеется, начал ставить туда всё что ни попадя. :) Собственно говоря, процесс поднятия ZNC практически одинаков для всех систем, под которые он предназначен, отличается лишь инсталляция. Я использовал emerge:
# emerge irc-net/znc
Добавление пользователя проще всего делать в интерактивном режиме:
$ znc --makeconf
Тут он спросит всякие настройки типа юзер/логин/порт/сервер/канал и сформирует конфиг ~/.znc/configs/znc.conf
Всё, теперь простой командой $ znc в фоне запускается процесс, слушающий порт, который был указан при конфигурации. Подключаться к нему нужно так, если бы это был простой irc сервер, т.е. в настройках указываем ip/port - физического сервера, на котором работает znc, и user/password - того, которого создали при конфигурировании znc.

Более подробная информация: http://en.znc.in/wiki/ZNC

2010/07/19

Простейший веб шелл на питоне

 #!/usr/local/bin/python
import cgitb, os, urllib, subprocess

cgitb.enable()
str_command = urllib.unquote(os.environ['QUERY_STRING'])

p = subprocess.Popen(['/usr/local/bin/bash', '-c', str_command],\
    stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
output = urllib.unquote(p.stdout.read())

print """Content-Type: text/html\n
<html><body>
<pre>
$ %s
%s
</pre>
</body></html>""" % (str_command, output)

Скрипт для изменения ориентации экрана (Lenovo Thinkpad X200t)

Забинден у меня на кнопочку, меняет ориентацию экрана (а также стилуса и тачскрина) по часовой стрелке при каждом нажатии. По идее должен подходить ко всем планшетным ноутам. Единственное, что может потребоваться изменить - это имена устройств, которые можно узнать командой xsetwacom --list dev.

#!/bin/bash

function set_normal {
xrandr -o normal
xsetwacom set cursor Rotate none
xsetwacom set touch Rotate none
xsetwacom set eraser Rotate none
orientation="normal"
}

function set_right {
xrandr -o right
xsetwacom set cursor Rotate cw
xsetwacom set touch Rotate cw
xsetwacom set eraser Rotate cw
orientation="right"
}

function set_left {
xrandr -o left
xsetwacom set cursor Rotate ccw
xsetwacom set touch Rotate ccw
xsetwacom set eraser Rotate ccw
orientation="left"
}

function set_inverted {
xrandr -o inverted
xsetwacom set cursor Rotate half
xsetwacom set touch Rotate half
xsetwacom set eraser Rotate half
orientation="inverted"
}

orientation="$(xrandr --query --verbose | grep 'LVDS1 connected' | awk '{print $5}')"

if [ "$orientation" = "normal" ]; then
        set_right
elif [ "$orientation" = "right" ]; then
        set_inverted
elif [ "$orientation" = "inverted" ]; then
        set_left
elif [ "$orientation" = "left" ]; then
        set_normal
fi

Использование wpa_supplicant

Очередным шагом в сторону стремления к минимуму энергии стал отказ от всяких богомерзких Network Manager'ов. Мало того, что они жрут оперативку и глючат, так ещё и занимают место в системном трее! Безобразие. Так что wpa_supplicant. Как бы не показалось по названию, эта утилита может работать с сетями не только WPA, но и всеми остальными (беспроводными, разумеется).
В ней есть конфиг /etc/wpa_supplicant.conf в котором по умолчанию много буков, поэтому его можно смело удалить. Сразу приведу пример конфига, по которому всё станет ясно:

network={
   ssid="AP1"
   priority=10
   key_mgmt=NONE
   wep_key0=355D3671207E37DC11E9D371E3
}

network={
   ssid="AP2"
   priority=5
   psk=b20a16a0622753f26c6660cdde815131cc11dcf5b8d46d8c1c3dd003bbe7c791
}

network={
   ssid="AP3"
   priority=1
   key_mgmt=NONE
}

Видно, что конфиг состоит из блоков network, в которых собственно описываются параметры сетей, к которым wpa_supplicant будет пытаться подключаться. В примере приведены параметры сетей для статического WEP, WPA1/2 PSK и открытой сети. Параметр priority явно задает приоритет подключения, хотя он и так рассчитывается (на основании секурности и силы сигнала, что не всегда устраивает). Параметр psk - закодированный пароль, его (а точнее весь блок network) можно получить командой wpa_passphrase. Ну и запуск всего этого дела происходит командой:
wpa_supplicant -B -D wext -i wlan0 -c /etc/wpa_supplicant.conf
Стоит отметить, что происходит только ассоциация с точной доступа, IP адрес всё еще нужно получить с помощью dhcpd или dhclient. Лучше это делать не сразу же после запуска wpa_supplicant, а через некоторое время (секунд 3-5), т.к. ассоциация происходит не мгновенно.