Categories: Всячина

mini-notes-issue-6/

Главные темы шестого выпуска: комбинаторика на Haskell, исправление кодировки без использования iconv, полуавтоматическая поисковая оптимизация заголовков, настройка unbound и pptp, а также создание мгновенного снимка файловой системы под FreeBSD. Предыдущие выпуски: первый , второй , третий , четвертый и пятый .

1. Размещение «шариков» по «коробкам» на Haskell

Дано N разноцветных шариков, M коробок различной вместимости, а также стол бесконечной вместимости. Нужно получить список всех возможных размещений (не путать с размещением в комбинаторике ) шариков по коробкам и столу. Вместо шариков могут быть яблоки или посылки, а вместо коробок — корзины или грузовики, суть от этого не меняется. Решение на Haskell:

module Placements where

import Data . List

— первый аргумент — список «шариков»
— второй аргумент — вместимость «коробок»
placements :: Eq a => [ a ] -> [ Int ] -> [ [ [ a ] ] ]
placements itemsList [ ] = [ [ itemsList ] ]
placements itemsList ( maxItems:maxItemsTail ) =
[ ( s:t ) | s <- seqList , t <- allTails s ]
where
— все варианты размещения «шариков» в текущей «коробке»
seqList = filter ( s -> length s <= maxItems )
$ subsequences itemsList
— все варианты размещения «шариков»
— в остальных «коробках» и на «столе»
allTails s = placements ( itemsList \ s ) maxItemsTail

Если вам попадалось готовое решение, поделитесь, пожалуйста, ссылкой.

2. Настройка unbound

Поднятие локального DNS сервера может быть целесообразным по крайней мере в двух случаях. Первый — когда вам хочется ускорить загрузку веб-страниц за счет кэширования ответов DNS сервера провайдера. Если у провайдера тормозной DNS, прирост скорости весьма ощутим. Второй случай — когда часть доменных имен вы хотите резолвить на одних DNS серверах, а часть — на других, например, если вы работаете дома через VPN.

Для этих целей идеально подходит DNS сервер unbound:

pkg_add -r unbound

После установки пишем в /usr/local/etc/unbound/unbound.conf что-то вроде:

server:
# принимаем пакеты только с локалхоста
interface: 127.0.0.1
access-control: 127.0.0.0/8 allow
# минимальный и максимальный TTL
cache-min-ttl: 21600
cache-max-ttl: 86400

forward-zone:
# за адресами доменов компании ходим по VPN
name: «company.example.ru.»
forward-addr: 33.33.33.1
forward-addr: 33.33.33.2

forward-zone:
# остальные домены резолвим у провайдера
name: «.»
forward-addr: 192.168.0.1

В /etc/rc.conf прописываем:

unbound_enalbe=»YES»

Запускаем:

/ usr / local / etc / rc.d / unbound start

Проверяем:

tcpdump -i tun0 udp port 53
dig @ 127.0.0.1 intra.company.example.ru

В /etc/resolv.conf прописываем:

nameserver 127.0.0.1

Чтобы resolv.conf не перезаписывался благодаря DHCP провайдера, в /etc/dhclient.conf пишем:

interface «rl0» {
supersede domain-name-servers 127.0.0.1;
}

Некоторые приложения понадобится перезапустить, иначе они не увидят новых настроек.

3. Использование разных ssh-ключей для разных серверов

Что делать, если требуется получить доступ к N серверам с одной машины, используя различные identity file для каждого сервера?

Копируем закрытый ключ для i-го сервера, например, в ~/.ssh/id_rsa.i-server (также копируем открытый ключ в id_rsa.pub.i-server — чтобы не потерять), меняем права доступа на 600, а затем пишем в ~/.ssh/config :

Host *.i-server.example.ru
IdentityFile ~/.ssh/id_rsa.i-server
User myusername

Повторяем описанные действия для i от 1 до N.

4. Настройка pptp под FreeBSD

Устанавливаем pptpclient:

pkg_add -r pptpclient

Правим /etc/ppp/ppp.conf:

company:
set authname mylogin
set authkey mypassword
set timeout 0
set ifaddr 0 0
# весь трафик — через VPN!
# add default HISADDR
# через VPN ходим только в заданную подсеть
set 123.45.67.0/24 HISADDR
# … и к заданному хосту
set 45.67.89.10 HISADDR

Указываем, через какой шлюз гнать трафик к VPN серверу:

route add -host 33.33.33.1 192.168.0.1

Проверяем:

pptp 33.33.33.1 company

Варнинги типа «/bin/ip: not found» игнорируем, логи смотрим в /var/log/ppp.log. По умолчанию в ppp.conf прописано «enable dns», что приводит к перезаписи resolv.conf. Если вы оставили эту опцию, то после разрыва соединения с VPN сервером должны вручную восстановить resolv.conf:

nameserver 192.168.0.1

Также после разрыва соединения понадобится восстановить шлюз по умолчанию:

route add default 192.168.0.1

Напоминаю, что посмотреть все роуты можно командой «netstat -nr».

5. Создание мгновенного снимка ФС во FreeBSD

Снапшоты файловой системы во FreeBSD можно создать несколькими способами. Наиболее простым, по моим представлениям, является следующий:

# pkg_add -r freebsd-snapshot
$ echo «1111» > test.txt
# snapshot make -g4 /usr:backup

Здесь флаг -g задает максимальное количество снапшотов. Если превысить это число, происходит автоматическая ротация.

# snapshot list /usr
Filesystem          User   User%     Snap   Snap%  Snapshot
/usr               146GB   25.8%    346MB    0.1%  backup.0

# mkdir /mnt/backup
# snapshot mount /usr:backup.0 /mnt/backup
# cat /mnt/backup/home/eax/test.txt
1111
$ echo «2222» > test.txt
# cat /mnt/backup/home/eax/test.txt
1111
# snapshot umount /mnt/backup
# ls -la /usr/.snap/
total 357652
drwxrwxr-x   2 root  operator           512  4 май 11:40 .
drwxr-xr-x  17 root  wheel              512 14 окт 21:59 ..
-r———   1 root  operator  627341157960  4 май 12:12 backup.0
# snapshot make -g0 /usr:backup

Мгновенные снимки часто используются при резервном копировании. Например, если на сервере крутится некая СУБД, мы можем останавливаем ее (или временно запретить запись и скинуть все данные на диск), создать снапшот файловой системы, после чего снова запускаем СУБД (разрешить запись) и сделать резервную копию из снапшота.

В результате сервер не простаивает, а мы получаем резервную копию данных в непротиворечивом состоянии. За счет использования механизма copy-on-write создание мгновенного снимка происходит очень быстро (на то он и мгновенный), а место на диске расходуется с умом.

6. Полуавтоматическая поисковая оптимизации заголовков

Дан список URL и поисковых запросов, по которым продвигаются соответствующие страницы. Следующий скрипт проверяет, заголовки каких страниц следует оптимизировать:

#!/usr/bin/perl

# check-header.pl v 0.1
# (c) Alexandr A Alexeev 2012 | http://remontka.com/

use strict ;
use warnings ;
use utf8 ;

use Mojo :: UserAgent ;

my $ua = Mojo :: UserAgent -> new ( ) ;

while ( my $line = <> ) {
chomp ( $line ) ;
my ( $url , $query ) = split /t/ , $line ;
utf8 :: decode ( $query ) ;
my $title ;
eval {
$title = $ua -> get ( $url )
-> res -> dom -> html -> head -> title -> text ;
} ;
if ( $@ ) {
print «ERROR: t $url n » ;
next ;
}

if ( titleMatch ( $title , $query ) ) {
print «OK: t $url n » ;
} else {
utf8 :: encode ( $query ) ;
print «FIXME: t $url t $query n » ;
}
}

sub titleMatch {
my ( $title , $query ) = @_ ;
$title = lc $title ;
$query = lc $query ;
my @tmp = split /s+/ , $query ;
for my $q ( @tmp ) {
return 0 if ( index ( $title , $q ) < 0 ) ;
}
return 1 ;
}

Проверка довольно топорная — если страница продвигается по запросу «купить яблоки», то в title должны содержаться слова «купить» и «яблоки». Этот скрипт удобно использовать со скриптом из десятого пункта предыдущего выпуска мини-заметок .

7. Как скопировать музыку с CD под UNIX

В портах FreeBSD есть такая замечательная утилита audio/ripit, предназначенная для конвертирования музыки с CD дисков в MP3. Устанавливаем, немного правим /usr/local/bin/ripit.pl:

my $cddev = «/dev/cd0» ;
my $outputdir = «/home/user/cdrip» ;

Затем просто вставляем диск в CD привод и говорим из под рута «ripit». Музыка в формате MP3 магическим образом окажется в директории $outputdir.

8. Удобные сочетания клавиш в bash

Недавно коллега показал мне два очень удобных сочетания клавиш в bash. До этого я умел пользоваться только стрелочками Вверх и Вниз, а также клавишей Tab.

Сочетание Ctr+R позволяет быстро выполнять команды, набранные ранее. Жмем Ctr+R и вводим часть команды. Если bash предложил то, что мы хотели, жмем Enter. Если снова нажать Ctr+R , будет предложена другая команда. Нажатие Escape возвращает нас в нормальный режим.

Сочетание Alt+точка подставляет в вводимую команду последний использованный аргумент. Например, если выполнить команду «ls -la» , затем набрать «cat » и нажать Alt+точка , команда превратиться в «cat -la» . Повторное нажатие Alt+точка подставляет другие аргументы, используемые ранее. Это сочетание особенно удобно при выполнении нескольких команд над файлами, к которым мы обращаемся по абсолютным или длинным относительным путям.

Может, есть еще какие-то сочетания клавиш, которые мне давно следовало бы держать на вооружении?

9. Утилита sloth

Если какой-то фоновый процесс съедает много ресурсов, а (re)nice не помогает, попробуйте утилиту sloth:

pkg_add -r sloth

Эта программа бомбит процесс сигналами SIGSTOP и SIGCONT, что существенно замедляет его выполнение:

$ time md5 PCBSD9.0-x86-DVD.iso
MD5 (PCBSD9.0-x86-DVD.iso) = 805eebb4d24e2ada0466d5baa1997b45

real  1m46.598s
user  0m17.914s
sys 0m7.744s

$ time sloth 5000 md5 PCBSD9.0-x86-DVD.iso
MD5 (PCBSD9.0-x86-DVD.iso) = 805eebb4d24e2ada0466d5baa1997b45

real  7m16.996s
user  0m18.523s
sys 0m7.713s

Если для вашей системы не оказалось готового пакета, вы можете собрать sloth из исходников . Последние представляют собой сотню строк на языке Си.

10. Исправление кодировки без использования iconv

Недавно мне попался дамп базы данных с испорченной кодировкой. Декодер студии Артемия Лебедева определил, что исправить кодировку можно путем перекодирования текста из cp1252 в cp1251. Но ни enconv, ни iconv никак не могли справиться этой, казалось бы, элементарнейшей задачей. В итоге пришлось написать такой скрипт:

#!/usr/bin/perl

# decoder.pl v 0.2
# (c) Alexandr A Alexeev 2012 | http://remontka.com/

use strict ;
use warnings ;
use utf8 ;
use List :: MoreUtils qw/uniq/ ;

# http://www.artlebedev.ru/tools/decoder/advanced/
my @bad = split //,
‘??????????????????????????????????????????????????????????????????’ ;
my @good = split //,
‘абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ’ ;

my % map ;
$map { $_ } = shift @good for ( @bad ) ;

while ( my $line = <> ) {
utf8 :: decode ( $line ) ;
$line = join » , (
map { defined $map { $_ } ? $map { $_ } : $_ } ( split //, $line )
) ;
utf8 :: encode ( $line ) ;
print $line ;
}

Как обычно, я буду несказанно рад вашим вопросам и дополнениям. Также мне было бы интересно узнать, какие пункты этого выпуска мини-заметок больше всего вам понравились и почему.

Дополнение: Мини заметки — выпуск 7

admin

Share
Published by
admin

Recent Posts

vim-commands/

Самое главное — побороть боязнь белого листа. Я всегда говорю это себе, когда нужно начать…

1 месяц ago

firefox-thunderbird-en-ru-dict/

По не вполне ясным причинам, Firefox умеет проверять орфографию либо только в русских, либо только…

1 месяц ago

perl-hacks/

Около месяца собирал разные «хаки» на языке программирования Perl. Эта подборка наглядно демонстрирует, как в…

1 месяц ago

perl-cy-check/

C недавних пор я стал увлекаться SEO. Порой передо мной встает задача быстро проверить индекс…

1 месяц ago

which-cms-perl/

Недавно написал несколько скриптов, позволяющих автоматически определять, какая CMS (Content Management System, система управления контентом)…

1 месяц ago

smtp-descr/

Я так подозреваю, что среди вас найдется те, кто скажет, что этот пост боян и…

1 месяц ago