пятница, 22 января 2016 г.

мало ли, вдруг пригодится...

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

- И какой же? - с интересом спросил Оруженосец.

Рыцарь немного помолчал.

- Он передаётся из поколения в поколение. Я его услышал от своего отца, тому рассказал мой дед, и так далее. Если у дракона количество голов больше количества лап, то это - неправильный дракон. Он с лёгкостью отдаст нам принцессу - а, может даже, и не одну, и будет отдавать их до тех пор, пока не станет правильным драконом. Каждый раз, когда такой дракон выпускает принцессу, число его голов уменьшается на количество его лап. Такая вот интересная закономерность.

- То есть, - оживился Оруженосец, - если мы встретим, например, шестиглавого четырехлапого дракона, то... м-м-м, получим одну принцессу, а дракон станет двуглавым?

- Совершенно верно.

- А если дракон будет тринадцатиглавым и трёхлапым, то мы обзаведёмся гаремом из четырех принцесс, а одноглавый дракон станет правильным? Вот это чудеса!

- Да, если папа не врал. А у меня нет причин ему не верить. По крайней мере, мама и тётя Марта всегда подтверждали его слова.

- Хм-м, постойте, господин, а вдруг дракон окажется, скажем, десятиглавым и пятилапым?

Рыцарь задумался.

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

- О-чу-меть! Надо же, какая загадочная зверюга. Прожорливая, небось?

- Ужасно прожорливая. Хорошо, что травоядная. Пощиплет травку, смотришь - а число голов удвоилось, ну и лап тоже. Только что бегал по лужайке на семи ногах и жрал одуванчики в одну пасть, а тут, глядь: уже лап четырнадцать и две башки поглощают флору гораздо шустрее. Или три головы на двадцати одной лапе... Зависит, в общем, от объёма переваренного силоса.

- И что же, никак его не убить?

- Никак. Разве что сократить, да и то не всех.

- Не понял, господин. Это как "сократить"?

- Ну, сам я не пробовал. Но Жан - ты знаешь его, он живёт во дворце на Серых Холмах - рассказывал, что однажды на него напал огромный двуглавый двенадцатилапый дракон. И что делать - непонятно. Убить нельзя, убежать - тоже како-то несолидно. Тогда Жан достаёт свой меч-кладенец, посильнее размахивается, и р-р-аз! отполовинивает число голов. Тут же каким-то чудом число ног тоже уменьшается в два раза, и чудовище, ставшее одноглавым шестилапым - не больше таракана - шустро исчезает в ближайших кустах.

- И это у всех так?

- Да, во сколько раз уменьшается число голов, во столько раз становится меньше число ног.

... Будильник трещал не переставая. Иванов с трудом оторвал чугунную голову от подушки, оказавшейся учебником математики за 6-й класс, но ещё не до конца понимая, откуда в его спальне парты, и почему он в школе, и куда все подевались. Будильник постепенно превратился в школьный звонок и заткнулся. Иванов протёр глаза, сладко потянулся и понял, что за окном вечер и пора идти домой. В пустой башке продолжали ворочаться рыцари и какие-то неправильные сократимые драконы. Иванов подхватил портфель. сунул в него свою "подушку" и, продолжая думать над тайнами высшей математики, вышел из класса.

понедельник, 18 января 2016 г.

MS Excel - посчитать разность дат

Ексель полон сюрпризов. Помнится, то ли в 2000, то ли в 2003 там в качестве пасхалки присутствовали даже гоночки. А теперь это.

Потребовалось рассчитать возраст человека на определенную дату. На первый взгляд, подходящей функции в екселе нет. Однако, оказывается, это не так:
=РАЗНДАТ(B1;A1;"y") - количество полных лет
=РАЗНДАТ(B1;A1;"ym") - количество полных месяцев свыше полных лет
=РАЗНДАТ(B1;A1;"md") - количество дней свыше полных месяцев

Подсмотрел тут:
http://www.planetaexcel.ru/techniques/6/105/
http://www.excel-office.ru/formulivexcel/schitaemvosrastvexcel

воскресенье, 20 декабря 2015 г.

Linux: перекодировать файл из win-1251+CRLF в utf-8+LF

cat Файл-win1251.txt | iconv -f windows-1251 -t utf-8 | tr -d '\r' > Файл-utf8.txt

вторник, 24 ноября 2015 г.

Windows XP: FireFox и аппаратное ускорение

Допустим, есть компьютер под управлением Windows XP с графической системой Intel Q45/Q43 Express на борту, и есть браузер Mozilla FireFox, в котором галочка "Use hardware acceleration when available" вроде как стоит. При этом информация "about:support" показывает "GPU Accelerated Windows: 0/1 Basic". А хочется 1/1.

Помогло следующее:

1) Обновил драйверы видео до последней версии

2) В настройках браузера (about:config) поставил две опции:
gfx.direct2d.force-enabled=true
layers.acceleration.force-enabled=true

3) Перезапустил FireFox.

Источники:
Force Enable Hardware Acceleration in Firefox
Blocklisting/Blocked Graphics Drivers

Slackware: dot и graphviz

Начитался тут баша и открыл для себя язык описания графов по имени dot. Соответственно, возникло непреодолимое желание этот самый dot пощупать. Решил взгромоздить на свой Slackware некий софт graphviz v2.38, собрав его из исходников. Дальше начались чудеса.

Во-первых, заглючила команда make, вывалившись с сообщением error: 'tsrm_ls' undeclared. Решение нашлось, но, по-моему, на китайском языке. К счастью, буквы, которые надо вводить в компьютер, остались английскими, так что сориентироваться можно. В общем, надо отредактировать файл tclpkg/gv/gv_php_init.c, добавив в пару функций по строчке:
static size_t gv_string_writer (GVJ_t *job, const char *s, size_t len)
{
    TSRMLS_FETCH(); // <- добавили
    return PHPWRITE(s, len);
}
 
static size_t gv_channel_writer (GVJ_t *job, const char *s, size_t len)
{
    TSRMLS_FETCH(); // <- добавили
    return PHPWRITE(s, len);
}


На этом приключение не закончилось. Впервые на моей памяти заглючила также команда make install. На этот раз ошибка выглядела примерно так: fatal error: QtGui/qwidget.h: No such file or directory. Оказывается, требуется поправить файл /cmd/gvedit/Makefile: найти там строку примерно такого вида:
INCPATH       = -I/usr/lib64/qt/mkspecs/linux-g++ -I. -I/usr/lib64/qt/include/QtCore -I/usr/lib64/qt/include/QtGui -I/usr/lib64/qt/include -I../../lib/gvc -I../../lib/common -I../../lib/pathplan -I../../lib/cgraph -I../../lib/cdt -I../.. -I.
и вымарать из неё пару опций:
INCPATH       = -I/usr/lib64/qt/mkspecs/linux-g++ -I. -I/usr/lib64/qt/include -I../../lib/gvc -I../../lib/common -I../../lib/pathplan -I../../lib/cgraph -I../../lib/cdt -I../.. -I.
После этого всё, наконец, установилось.

Штука оказалась довольно прикольной. Например, можно создать вот такой текстовый файл sample.gv:
digraph myFirstGraph {
    edge [color=blue]
    a;
    b [shape=box label="Ку-ку"];
    c;
    d;
    a -> b [label="некая связь"];
    subgraph g1 {
        edge [dir=none]
        b -> c;
        b -> d;
    }
}
натравить на него команду:
dot -Tpng -osample.png sample.gv
и получить симпатичную картинку:
Ну не чудо ли!

четверг, 19 ноября 2015 г.

Slackware: загадочный VirtualBox

Сегодня как-то нехорошо себя повёл VirtualBox. При попытке запустить виртуальную машину командой:
virtualbox --startvm WinXP
он тяжело и надолго задумался, а потом закрылся с сообщением:
ICE default IO error handler doing an exit(), pid = 12345, errno = 32
Проверка диска при помощи fsck ничего интересного не дала.
Почему-то помогла очистка папки ~/VirtualBox VMs/WinXP/Logs

понедельник, 26 октября 2015 г.

Linux: PostgreSQL 9.x и сертификаты

Захотелось тут, чтобы определенный пользователь при авторизации в СУБД был избавлен от необходимости ввода пароля. Можно было бы указать, что соединения от имени этого пользователя - доверенные, но я почему-то предпочёл другой путь: авторизацию с использованием сертификата. Наверно, в последнее время слишком часто приходилось иметь с этими штуками дело, вот и решил пойти проторенной дорожкой.

Как я понял, PostgreSQL использует сертификаты в двух случаях: для установления защищенного соединения и для проверки подлинности пользователя. В любом случае используется информация:

1) адрес или имя сервера баз данных, по которому будет стучаться клиент, например, myserver

2) имя системного пользователя, который пытается авторизоваться, например, sysUser

3) имя пользователя базы данных, под которым пытается авторизоваться системный пользователь, например, pgUser

При этом затрагиваются следующие каталоги и файлы конфигурации:

1) На стороне сервера: файлы postgresql.conf, pg_hba.conf и pg_ident.conf. Эти файлы в зависимости от сборки могут располагаться в разных местах. Например, на дебиане они обнаружились в каталоге /etc/postgresql, а на слакваре при установке из исходных кодов обосновались в рабочем каталоге /usr/local/pgsql/data

2) На стороне клиента: каталог ~/.postgresql/, в который должна быть положена пара ключ-сертификат, использующаяся для проверки подлинности пользователя.

Итак, настраиваем все эти сертификаты. Так как я - по натуре нищеброд, то сертификаты у меня будут самоподписанные, а создавать их буду бесплатной утилитой openssl.

Сначала генерируем корневой сертификат, которым будем подписывать сертификаты сервера и клиента:
# генерируем приватный ключ
openssl genrsa -out root.key 1024

# создаем самоподписанный корневой сертификат
openssl req -new -x509 -days 1826 -key root.key -out root.crt
При этом будут заданы всякие вопросы, от ответов, я так понял, мало что зависит.

Затем при помощи этого корневого сертификата создаем сертификат сервера:
# генерируем приватный ключ
openssl genrsa -out server.key 1024

# создаем запрос сертификата
# тут надо внимательно отнестись к заполнению полей:
# в поле Common Name (CN) надо указать адрес или имя сервера баз данных
# (например, myserver)
openssl req -new -utf8 -key server.key -out server.csr

# из запроса создаём сертификат сервера, подписанный корневым сертификатом
openssl x509 -req -days 730 -in server.csr -CA root.crt -CAkey root.key -out server.crt

У нас получилось три ценных файла: root.crt, server.key, server.crt. Их нужно запихнуть в рабочий каталог postgresql (тот самый что-то-там/data, в котором при установке СУБД делалась команда initdb). При этом на файл server.key налагаются суровые ограничения по безопасности: он должен иметь владельцем пользователя, под которым работает СУБД, и уровень доступа -rw-------.

Теперь сгенерируем сертификат для клиента:
# генерируем приватный ключ
openssl genrsa -out postgresql.key 1024

# создаем запрос сертификата
# тут тоже надо внимательно отнестись к заполнению полей:
# в поле Common Name (CN) следует указать имя системного пользователя,
# для которого создаётся сертификат
# (например, sysUser)
openssl req -new -utf8 -key postgresql.key -out postgresql.csr

# из запроса создаём сертификат клиента, подписанный корневым сертификатом
openssl x509 -req -days 730 -in postgresql.csr -CA root.crt -CAkey root.key -out postgresql.crt -CAcreateserial

После этой процедуры два файла, postgresql.key и postgresql.crt, закидываем клиенту в папку ~/.postgresql/ и у файла postgresql.key опять-таки выставляем правильного владельца и права -rw-------.

Стоит отметить, что содержимое получившихся сертификатов, в частности, заполнение поля CN можно всегда посмотреть командой:
openssl x509 -in postgresql.crt -text -noout -nameopt oneline,-esc_msb,utf8

Так или иначе, осталось написать правильные настройки сервера баз данных:

1) в файле postgresql.conf проверяем, что включена опция ssl = on

2) прописываем в pg_hba.conf строку:
#TYPE    DATABASE  USER    ADDRESS   METHOD
hostssl  all       pgUser  myserver  cert clientcert=1 map=myMap
Тут мы указали, что соединение должно быть защищено ssl, для авторизации следует использовать сертификат клиента и при сопоставлении системного имени и имени пользователя баз данных будет использоваться запись с меткой myMap из файла pg_ident.conf

3) в файле pg_ident.conf прописываем строку:
#MAPNAME  SYSTEM-USERNAME  PG-USERNAME
myMap     sysUser          pgUser
На самом деле, как я понял, этот файл содержит довольно простую информацию: какому системному пользователю под каким именем СУБД разрешается подключаться к серверу. То есть, если пользователю позволено подключаться под разными именами, pg_ident.conf будет выглядеть так:
#MAPNAME  SYSTEM-USERNAME  PG-USERNAME
myMap     sysUser          pgUser1
myMap     sysUser          pgUser2

4) перезапускаем сервер PostgreSQL.

Процесс авторизации по этой схеме выглядит, насколько я понял, так:

1) Устанавливается защищенное соединение при помощи сертификатов server.key + server.crt

2) От клиента сервер получает сертификат postgresql.crt, из которого выясняет системное имя пользователя. Имя пользователя базы данных, под которым хочет зайти системный пользователь, указывается явно в строке подключения.

3) По имени пользователя базы данных, имени сервера и режиму соединения (hostssl) определяется строка в файле pg_hba.conf, из которой выясняется имя метки в файле pg_ident.conf.

4) По метке в файле pg_ident.conf устанавливается, может ли данный системный пользователь авторизоваться в СУБД под данным пользователем баз данных.

Вообще говоря, требование размещения клиентских сертификатов в каталоге ~/.postgresql/ не является таким уж обязательным. Просто их там по умолчанию ищет библиотека libpq. В произвольных же скриптах можно указывать явно, какие файлы использовать в качестве пары ключ-сертификат. Вот, например, скрипт на Python-е:
import psycopg2

connString = "host=myserver"             + \
             " user=pgUser"              + \
             " dbname=postgres"          + \
             " sslcert=./postgresql.crt" + \
             " sslkey=./postgresql.key"

conn = psycopg2.connect(connString)