Как отключить ALPS-тачпад в Archlinux

В некоторых моделях ноутбуков (не миновала сия участь и мой Dell Inspiron 7720) в Archlinux тачпад определяется как “PS/2 Generic Mouse”. Разумеется, при этом он отказывается конфигуриться (и отключаться) драйвером Synaptic. Хотя вики советует устанавливать некий самопальный модуль с AUR, есть способ проще.

  1. Определяем id устройства:
    xinput list
  2. Отключаем устройство (id=13):
    xinput set-prop 13 "Device Enabled" 0
  3. Optional: добавляем алиас для удобства вызова команды в будущем.

Perl is dead baby, Perl is dead.

Ура, я наконец-то перешел на Python в качестве основного языка разработки. Довольно долгое время моим основным орудием был Perl, но в последнее время я все чаще стал посматривать на альтернативы (i.e. на Python). Немного о том, что мне не нравится в Perl, в произвольном порядке.

  • Perl, пожалуй, худший выбор в качестве первого языка программирования. Этот язык упорот настолько, что поюзав его несколько лет переключиться на что-то вменяемое становится сложно. Чего стоит, например, передача аргументов в функцию в виде массива @_, реализация областей видимости переменных, etc.

  • Стремление к сходству с естественным языком (на Perl можно даже писать стихи). Звучит прикольно, но на практике лишь раздувает синтаксис и делает код менее читабельным/поддерживаемым.

  • Мантры TMTOWTDI (There’s More Than One Way To Do It) и DWIM (Do What I Mean). Чем больше существует способов “сделать это”, тем сложнее язык в изучении и понимании. Попытка заставить интерпретатор строить догадки также ни к чему хорошему не приводит.

  • Отсутствие вменяемого ООП. А без ООП нынче никуда.

  • Отсутствие спроса. Тренды последних лет указывают на то, что новых проектов на Perl5 с каждым годом все меньше. Типичная вакансия Perl-разработчика чуть реже чем всегда подразумевает поддержку древней базы говнокода, переписывать которую на более современных языках слишком долго и дорого.

  • Очень узкая ниша. На мой взгляд – это относительно небольшие (одноразовые) скрипты, позволяющие быстро выполнить задачу. Причем “быстро” как по времени написания кода, так и его выполнения.

  • Perl – единственный язык, в котором имеется goatse operator =)

На этом унылом фоне всё лучше смотрится Python. Он на порядок читабельней, более строгий и полностью объектно ориентированный. Наконец, его гораздо легче набивать вслепую из-за минимума пунктуации ) И еще, я уже давно собирался на него перейти…

Фиксированные имена сетевых интерфейсов в Archlinux

Как известно, в Linux имена сетевых интерфейсов обычно имеют вид “eth0″, “eth1″ и назначаются ядром при загрузке системы. Поскольку модули соответствующих драйверов загружаются асинхронно, порядок обнаружения интерфейсов не является постоянным. Поэтому, если в системе имеется несколько сетевых интерфейсов, их имена могут периодически меняться при перезагрузке. Это может доставлять проблемы для приложений, использующих имена интерфейсов (e.g. фаерволы, сетевые мониторы).

Начиная с версии v197 systemd/udev автоматически назначает постоянные фиксированные имена для всех Ethernet, WLAN и WWAN интерфейсов. Для имен используются префиксы en, wl и ww соответственно и автоматически сгенерированные идентификаторы. Пример для ethernet-интерфейса: enp1s0.

При обновлении с более ранних версий systemd в Archlinux эта фича остается отключенной, благодаря наличию файла /etc/udev/rules.d/80-net-name-slot.rules:

$ cat /etc/udev/rules.d/80-net-name-slot.rules 
# This file masks persistent renaming rules for network devices. If you
# delete this file, /usr/lib/udev/rules.d/80-net-name-slot.rules may
# rename network devices according to ID_NET_NAME_{ONBOARD,SLOT,PATH}
# properties of your network devices, with priority in that order. See
# the output of 'udevadm test-builtin net_id /sys/class/net/$interface'
# for details on what that new name might be.
# 
# http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames

Чтобы для всех интерфейсов использовалось постоянное сгенерированное имя, достаточно удалить файл /etc/udev/rules.d/80-net-name-slot.rules. Посмотреть, какое имя будет назначено интерфейсу можно командой

udevadm test-builtin net_id /sys/class/net/eth0

SSH-соединения с использованием промежуточных хостов

Иногда возникает необходимость в использовании SSH-соединения с хостом, к которому прямого доступа нет. В таких случаях приходится соединяться сперва с промежуточным хостом, а с него уже с нужным. К счастью, этот процесс легко автоматизировать.

Предположим нам надо зайти на хост B (недоступный с текущего места) и мы можем зайти на хост A (с которого доступен хост B). В настройках ssh (e.g. ~/.ssh/config) указываем, что соединение с хостом B должно проксироваться через хост A, используя опцию -W:

Host B
  HostName myhost
  ProxyCommand ssh -q -W %h:%p A

После этого просто используем команду ssh B. Имя myhost должно резолвиться хостом A и указывать на хост B. По аналогии можно добавить произвольное число промежуточных хостов.

Надо заметить, что опция -W появилась в OpenSSH 5.4 (март 2010г). Для более ранних версий можно использовать netcat:

ProxyCommand ssh A nc %h %p

Данная простая настройка делает возможным установку соединения с хостом одной командой, а также открывает доступ к нему приложениям rsync, git, etc., использующим SSH в качестве транспорта.

OAuth 2.0: введение

В октябре текущего года стандарт OAuth 2.0 наконец-то вышел из статуса “черновика” и превратился в RFC. Все больше сервис-провайдеров начинают поддерживать OAuth в своих API. Что же такое OAuth и зачем он нужен?

Согласно RFC, этот протокол позволяет предоставить третьему лицу (клиенту) ограниченный доступ к какому-либо HTTP-сервису от имени пользователя. При этом клиент использует для авторизации не параметры доступа пользователя (e.g. логин и пароль), а полученный от сервиса токен. Это во многом повышает секьюрность модели аутентификации:

  1. Клиенту не надо хранить параметры доступа пользователя в виде плэйнтекста.
  2. Возможность ограничить полномочия клиента, в т.ч. длительность их предоставления.
  3. Возможность отозвать полномочия у конкретного клиента, не затрагивая остальных.
  4. Компрометирование какого-либо клиента не приводит к утечке параметров доступа пользователя.

Рассмотрим как происходит OAuth-авторизация с использованием авторизационного кода. Именно такая схема используется во многих приложениях для авторизации в Facebook и других сервисах.

  1. Приложение (клиент) перенаправляет пользователя на урл авторизации сервиса. В параметрах запроса содержится идентификатор клиента, запрашиваемые права, случайная последовательность символов и урл, на который следует перенаправить пользователя после того, как он подтвердит (или отменит) авторизацию.
  2. Сервис (он же authorization server, он же resource server) авторизует у себя пользователя и устанавливает, подтверждает ли он предоставление запрошенных прав клиенту.
  3. После того, как пользователь подтвердил предоставление прав, сервис редиректит его обратно к клиенту, используя урл, предоставленный в первом запросе. В параметрах урла включается код авторизации, а также случайная последовательность символов, переданная в первом запросе.
  4. Клиент делает запрос к сервису, содержащий полученный код авторизации, а также параметры доступа клиента.
  5. Сервис проверяет параметры доступа клиента, код авторизации и возвращает access token.
  6. Profit!

В принципе, это самая сложная схема авторизации в OAuth 2.0 в настоящий момент.

Схема с обменом реквизитов пользователя на access token, например, гораздо проще и по сути представляет собой обычную авторизацию, используемую во многих web-приложениях.

6 полезных приемов для работы с DBIx::Class

DBIx::Class – это мощный ORM, написанный на Perl. Его функцией является прозрачное преобразование результатов запросов к реляционной БД в перловые объекты. Разработчик может использовать эти объекты для взаимодействия с БД, не прибегая к написанию SQL. Это значительно ускоряет разработку и делает код более простым для понимания. К достоинствам DBIx::Class также относятся потрясающая гибкость и интуитивность использования (DWIM). В этой заметке я приведу несколько приемов, которые помогут вам использовать DBIx::Class более эффективно.

  1. Автоматическая генерация классов с помощью DBIx::Class::Schema::Loader.

    Как известно, прежде чем начать работу с DBIx::Class, необходимо предварительно создать несколько классов: класс схемы и Result-классы для нужных таблиц. Этот шаг можно автоматизировать, и поможет в этом утилита dbicdump, которая устанавливается вместе с вышеуказанным модулем. Она берет информацию о таблицах из БД (столбцы, ключи, связи, etc.) и создает нужные классы для всех таблиц.

    dbicdump -o dump_directory=lib 
        MyApp::Schema dbi:Pg:dbname=myapp user pass
    

    Теперь можно использовать сгенерированные модули в приложении.
    При внесении каких-либо изменений в схему БД, классы необходимо пересоздать аналогичным образом. Для удобства можно создать shell-скрипт или alias, вызывающий dbicdump с нужными параметрами.

  2. Объединение нескольких таблиц в одном запросе с помощью join и prefetch.

    Если в схеме БД созданы вторичные ключи, и вы воспользовались приемом №1, можно использовать атрибуты join и prefetch во многих методах DBIx::Class для объединения нескольких таблиц в одном запросе. join используется когда необходимо выполнить поиск либо сортировку результатов по одному или более столбцу связанной таблицы, e.g.

    my $rs = $schema->resultset('CD')->search(
        { 'artist.name' => 'Rainbow' },
        { join => 'artist' }
    );

    Хотя join и объединяет несколько таблиц, в полученных объектах содержатся данные лишь из одной таблицы – cds. Т.е. если вызвать $cd->artist, будет сделан дополнительный запрос к БД. Для того, чтобы получить все данные из связанных таблиц одним запросом, вместо join следует использовать prefetch. И join, и prefetch могут иметь произвольный уровень вложенности.

  3. Добавление методов в Result/ResultSet-классы.

    Мы уже знаем, что в DBIx::Class для каждой таблицы должен быть задан Result-класс, который представляет строку из данной таблицы. В этот класс можно добавлять дополнительные методы для работы со строками. Например, если в таблице есть столбец email, можно добавить метод gravatar_url:

    sub gravatar_url {
        my ($self) = @_;
        return "http://www.gravatar.com/avatar/".md5_hex(lc $self->email);
    }

    В ResultSet-классы в свою очередь добавляются методы для работы с наборами строк: поиск с заданными критериями, сортировкой, etc. Это позволяет инкапсулировать часть логики в модели.

  4. Использование компонентов для добавления функционала в базовые классы DBIx::Class.

    Функционал любого класса в DBIx::Class (e.g. Schema, Result) можно расширить с помощью компонента:

    __PACKAGE__->load_components(qw(MyComponent));

    При этом MyComponent добавляется в цепочку наследования класса и может добавлять новые методы в класс, либо переопределять уже имеющиеся. Например, компонент DBIx::Class::Validation переопределяет методы insert и update в Result-классе и добавляет в них валидацию значений.

  5. Использование чистого SQL с параметрами.

    В некоторых случаях нужный SQL-запрос в DBIx::CLass можно сгенерировать лишь с использованием кастомного SQL. Данный подход используется в крайнем случае, и, как правило, можно обойтись и без этого. Чтобы включить строку SQL в сгенерированный запрос, она передается как ссылка на скаляр (подробный синтаксис можно посмотреть в perldoc SQL::Abstract). Несколько примеров:

    #  WHERE YEAR(birthday) = ?
    $rs->search(['YEAR(birthday) = ?', [dummy => $year]]);
    
    #  ORDER BY myfunction(mycol, ?, ?) DESC
    $rs->search(undef, {
        order_by => [
            'myfunction(mycol, ?, ?) DESC', map [dummy => $_], $v1, $v2
        ]
    });
    
    #  SET price = price + ?
    $rs->update({
       price => ['price + ?', [dummy => $v]],
    });
  6. Использование транзакций.

    Транзакции позволяют выполнять несколько операций над данными как одно действие. В случае какого-либо сбоя, вся транзакция целиком откатывается. Таким образом обеспечивается целостность данных.

    DBIx::class позволяет выполнить любой код в транзакции с помощью метода txn_do класса схемы:

    $schema->txn_do(sub {
        my $user = $schema->resultset('User')->create({
            username => $username,
            first_name => $first_name,
            last_name => $last_name,
        }); 
        $schema->resultset('Token')->validate($token_id) or die "Bad token: $token_id"; 
        $user->add_to_tokens({ token_id => $token_id });
    });

Вождение МКПП: double clutching

Недавно решил освоить прием переключения передач с двойным выжимом сцепления. Применяется он для более легкого и быстрого переключения передач (как правило, вниз), что особенно актуально для старых трансмиссий. Попробуем разобраться, как это работает. Continue reading

Бэкап FreeBSD-слайса на удаленную машину

Понадобилось слить данные с ноутбука с установленной FreeBSD: два слайса, примонтированные в /var и /usr. Рабочее решение:

  1. Загружаемся с линуксового Live-CD. В моем случае на ноутбуке уже был установлен Linux в одном из разделов, поэтому я загрузил его.
  2. Находим файлы устройств для нужных слайсов, например пробным монтированием. В моем случае это были /dev/sda9 и /dev/sda11.
  3. Дампим слайс с помощью dd и копируем на удаленную машину через ssh:

    dd if=/dev/sda9 |
        ssh -c blowfish user@host "dd of=var.img"
  4. В линуксе примонтировать полученный файл можно следующей командой:

    mount -r -t ufs -o loop,ufstype=ufs2 var.img /mnt

svn: как удалить N последних ревизий из репозитория

Иногда возникает необходимость полностью выпилить 1 или более последних ревизий из svn-репозитория. Если вы админ svn-сервера, это делается очень просто:

# mv repo repo.bak
# svnadmin create repo
# svnadmin dump -r 0:9999 repo.bak | svnadmin load repo

Клиентам, которые уже скачали себе эти ревизии, необходимо заново сделать checkout.

Если же доступа непосредственно к файлам репозитория нет, единственный вариант – это откатить сделанные изменения, создав еще один коммит. Это можно сделать с помощью команды svn merge с указанием ревизий в обратном порядке, e.g.

$ svn merge --revision 303:302 ^/calc/trunk
$ svn commit -m "Undoing change committed in r303."