Про странные вещи в мире программирования.

Пока сам с таким не столкнешься, глазам своим не поверишь. Такой баг сразу и не найдешь.

Многие базы данных корректно работают с датами. Если взять дату — 31.12.2017, и отнять от нее один месяц, то должна получиться дата — 30.11.2017:

db=# select '2017-12-31'::timestamp - interval '1 month' new_date;
      new_date       
---------------------
 2017-11-30 00:00:00
(1 строка)
MariaDB [(none)]> select '2017-12-31' - interval 1 month new_date;
+------------+
| new_date   |
+------------+
| 2017-11-30 |
+------------+
1 row in set (0.00 sec)

Но php почему-то считает иначе:

$dt = date_create("2017-12-31");
$dt->modify("-1 month");
echo $dt->format('Y-m-d')."\n";

2017-12-01

Интересно то, что разработчики php не считают такое поведение багом, а особенностью реализации алгоритма работы с датами.

Синхронизация времени на разных серверах

Самый правильный способ синхронизации часов на серверах — это использовать какой-нибудь общий тайм сервер, и синхронизироваться с ним с помощью ntpd или ntpdate. Однако иногда возникают ситуации, когда таймсервер в локальной сети не настроен или недоступен, а выход во внешнюю сеть закрыт.

Первый вариант решения проблемы — использование какого-нибудь локального HTTP-сервера в качестве тайм-сервера. На все http-запросы сервер должен отвечать, и в заголовке ответа будет присутствовать параметр Date, то есть примерно так:

telnet 10.11.12.105 80
Trying 127.0.0.1...
Connected to 10.11.12.105.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.0 200 OK
Date: Mon, 14 Sep 2017 19:43:59 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Length: 1496
….

Само тело ответа нас не интересует, нам достаточно знать время. Его можно распарсить и при наличии рутовых прав можно установить локально часы в полученное значение времени. Команда выглядит так:

root# date -s "$(curl -sD - 10.11.12.105 | grep -E '^[[:space:]]*[dD]ate:' | sed 's/^[[:space:]]*[dD]ate:[[:space:]]*//' | head -1l | awk '{print $1, $3, $2,  $5 ,"GMT", $4 }' | sed 's/,//')"

Второй вариант — можно считать время одного из серверов эталонным, и запуская скрипты по расписанию на нем, корректировать время на остальных серверах при помощи входа по ssh и удаленного выполнения команд. Примерно так:

ssh root@10.11.12.102 date --utc $(date --utc "+%m%d%H%M%Y.%S")

Тут разница по времени будет чуть больше, поскольку авторизация по ключам RSA занимает чуть больше времени, чем получение ответа от веб сервера без авторизации. Способ тоже рабочий.

Новый сервис: онлайн форматирование JSON

Давненько я не писал что-нибудь общественно-полезного. А тут как раз пришлось писать очердной вебсервис с блэкджеком и шлюхами, который должен выплевывать неотформатированный JSON, и в целях отладки мне пришлось его форматировать скриптами.

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

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

В качестве теста можно использовать строку JSON, например, такую:

{"data":[{"t1":"John","t2":"Doe"},{"t1":"Anna","t2":"Smith" },{"t1":"Peter" ,"t2":"Jones"}]}

На выходе будет удобно читаемый JSON:

{
   "data" : [
      {
         "t2" : "Doe",
         "t1" : "John"
      },
      {
         "t2" : "Smith",
         "t1" : "Anna"
      },
      {
         "t2" : "Jones",
         "t1" : "Peter"
      }
   ]
}

Обычным людям такой сервис вряд ли будет не нужен, но программистам – пригодится.

OpenSuSe 13.1, ноутбук с видеокартой Nvidia и старые игры в wine

Так получилось, что ранее я ругал карты ATI Radeon здесь, тут и там. И для разнообразия у меня появился ноутбук Lenovo Z560 с карточкой Nvidia на борту. Пропиетарные дрова с сайта Nvidia ставятся без проблем, все работает хорошо — за исключением одного маленького нюанса.

Почему-то разработчики драйверов перешли на новую версию протокола randr, и теперь в системе для экрана ноутбука определяется только одно единственное разрешение экрана:

> xrandr -q
Screen 0: minimum 8 x 8, current 1366 x 768, maximum 8192 x 8192
VGA-0 disconnected (normal left inverted right x axis y axis)
LVDS-0 connected primary 1366x768+0+0 (normal left inverted right x axis y axis) 344mm x 194mm
   1366x768       60.0*+   50.0  
HDMI-0 disconnected (normal left inverted right x axis y axis)

В старой версии протокола разрешений экрана можно было получить гораздо больше:

> xrandr --q1
 SZ:    Pixels          Physical       Refresh
*0   1366 x 768    ( 340mm x 191mm )  *50   51  
 1   1280 x 720    ( 318mm x 179mm )   52  
 2   1024 x 768    ( 254mm x 191mm )   53  
 3    800 x 600    ( 199mm x 149mm )   54  
 4    640 x 480    ( 159mm x 119mm )   55  
Current rotation - normal
Current reflection - none
Rotations possible - normal left inverted right 
Reflections possible - X Axis Y Axis

Если надо кодить, или править документ какой-нибудь, то проблемы это не вызывает. Но если решил порубиться в старую игрушку с древним разрешением экрана (например, 640×480), то игра вполне себе может ругаться на разрешение экрана. Например, у меня fallout не запускался, и появлялось сообщение Error initializing video mode 640×480, и в консоли при этом был виден текст ошибки такого вот содержания:

err:x11settings:X11DRV_ChangeDisplaySettingsEx No matching mode found 640x480x8 @0! (XRandR 1.2)

Оказывается, проблему победить можно. Надо лишь наваять 2 скрипта и поместить их куда-нибудь в пути. Первый скрипт позволяет менять разрешение экрана из командной строки:

> cat setres.sh
#!/bin/bash
RESOLUTION=$1
nvidia-settings --assign CurrentMetaMode="LVDS-0: nvidia-auto-select @$RESOLUTION +0 +0 {ViewPortIn=$RESOLUTION, ViewPortOut=$RESOLUTION}"

Второй скрипт собственно меняет разрешение экрана на правильное, запускает fallout в десктопе со «правильным» разрешением экрана, ну и возвращает настройки разрешения обратно по завершении игры:

> cat fallout1.sh
#!/bin/sh
cd /home/username/.wine/drive_c/Program Files/GOG.com/Fallout
/usr/local/bin/setres.sh 640x480
wine explorer /desktop=foo,640x480 falloutw.exe
/usr/local/bin/setres.sh 1366x768
cd $HOME

Смена разрешения на 640×480 — необязательный шаг, и если его не сделать, можно играть в оконном режиме. А вот для полноэкранного режима без смены разрешения не обойтись.

Про письма счастья и личный кабинет налогоплательщика. Подробная инструкция о том, как не надо делать сервис для людей.

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

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

Так получилось, что рядом с домом у нас есть офис налоговой, который относится к другому району. А офис нашей налоговой находится дальше раз в 20. Покумекав немного, я решил пойти в ближайшую налоговую в гости, благо при регистрации было четко сказано — пароль в личный кабинет можно получить в любом отделении ФНС (кроме некоторых). Зашел туда, и там случился фейл номер 2 — оказывается, у налоговых органов нет единой базы, и им пришлось вручную вбивать мою заявку на доступ в личный кабинет. Что в общем-то вызвала некую бурю относительно праведного гнева со стороны местных сотрудников ФНС. Но с горем пополам они все же доступ мне сделали.

Окрыленный успехом, я добежал до компьютера и залогинился в личный кабинет. Но не тут-то было — он оказался ПУСТОЙ, с нулем ценной для меня информации. Личный кабинет формируется в течение 3-х РАБОЧИХ дней, и судя по скорости внесения данных туда, они попадают в личный кабинет путем ручного вноса доблестных сотрудников ФНС.

Надо отдать им должное, в течение заявленного срока информация в личном кабинете появилась, и я узнал, сколько я должен родному государству. Сумма была точна, тут претензий нет. И я уж грешным делом подумал — неужели счастье-то наступило? Дай-ка я заплачу все онлайн, но… Третий, и самый ужасный фейл заключается вот в чем.

Онлайн оплата налогов в настоящий момент лишь обладателям счетов в одном из 15 банков, среди которых я знаю только Сбер. Но так как с филиалом ада на земле я сотрудничать отказался, и этот чудный инструмент по онлайн оплате налогов для меня оказался БЕСПОЛЕЗЕН.

Еще один непонятный момент мне не понравился. Оказывается, мне нельзя заплатить налоги за супругу или за кого-то еще. Этот запрет явным образом прописан в личном кабинете (в виде вот такого текста): «При списании денежных средств с Вашего счета в банке в уплату налогов, сборов за других физических лиц их обязанность не будет признана исполненной!». Просто все для людей сделано, и для их удобства — просто нет слов.

Других столь бездарно сделанных личных кабинетов я больше не видел нигде.

Вышла OpenSuSe 13.1

Логотип OpenSuSe

И вот черт меня дернул попробовать совсем уж новый дистрибутив. Обычно я не ставлю первые версии дистрибувов, т. к. они скорее всего будут сырыми и необкатанными, но в этот раз что-то меня переклинило и я поставил OpenSuSe 13.1 x86_64.

В Gnome 3 работать невозможно, но об этой проблеме известно уже давно. Все их увещевания о том, что новый дизайн гнома является совершенством — мне очень напоминает историю про Windows 8 и кнопку «Пуск». Но в отличие от Microsoft, разработчикам Gnome было начхать на мнение пользователей, и к стилю проверенного временем Gnome 2 они возвращаться не хотят. Ну что ж, такова жизнь — прощай, Gnome 3.

От KDE 4 я тоже не в восторге, уж больно он тяжелый. В OpenSuSe 12.2 я пару дней потратил на то, чтобы его допилить до удобного мне вида, но в этот раз даже заморачиваться не стал и решил поставить что-то другое. IceWM конечно очень легкий, но уж слишком он убого выглядит. Поэтому в этот раз в качестве оконного менеджера я выбрал Xfce, и в общем, остался доволен.

Самое первое, что надо сделать — это поставить пропиетарные дрова на видеокарты ATI Radeon. К великому сожалению, опенсорсный аналог для этого драйвера не умеет пробуждаться после перехода в спящий режим. И тут дело даже не в дистрибутиве, дело в самом драйвере. С похожей проблемой столкнулись и убунтоводы с Хабра.

Мне очень не понравилась настройка раскладок клавиатуры. Как ее не настравивай, после перезагрузки системы настройки слетали нафиг, и язык оставался только тот, что стоял по умолчанию. Проблему удалось решить вот как. Ставится пакет fsKbsettings вот отсюда, создаются для каждого пользователя директории /home/username/.config/autostart и с помощью этой утилиты под индивидуальные нужды легко и непринужденно настраивается раскладка клавиатуры.

Вторая серьезная проблема — скайп сразу не заработал. Версия, скачанная с skype.com для SuSe, была 32-битной, и предназначалась для OpenSuSe 12.1. Она без проблем ставилась на 12.2, но отказывалась устанавливаться на 13.1, и выглядело это так:

# rpm -ivh skype-4.2.0.11-suse.i586.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:skype-4.2.0.11-suse121           ################################# [100%]
error: unpacking of archive failed on file /usr/bin/skype;528dc292: cpio: read failed - No such file or directory
error: skype-4.2.0.11-suse121.i586: install failed

Но если скачать версию dynamic, раскидать иконки, звуки, аватарки и файлы lang в /usr/share/skype — скайп запускается, но голосовые звонки в нем не работают. Да и звук вообще не работает, тут требуется кое-что допилить.

Во-первых, эта версия skype не там ищет некоторые библиотеки. Я сделал симлинк на новую директорию со старым названием:

# ln -s /usr/lib/alsa-lib /usr/lib64/alsa-lib

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

$ cat start_skype.sh
#!/bin/sh                                                                         
PULSE_LATENCY_MSEC=60 /usr/local/bin/skype

Вот теперь скайп работает так, как и ожидалось.

Но в целом, дистрибутив мне понравился. Косяки со скайпом — это скорее проблема Microsoft, которая не успевает релизить свои версии программ под новые дистрибутивы.

И тем не менее, мораль сей басни такова. Если не хотите стать добровольным бета-тестером, никогда не ставьте дистрибутивы первых версий. Времени на допиливание уйдет довльно много, и далеко не факт, что все заработает как надо.

Просмотр RTMP-потока на телевизорах Samsung

Мой телевизор Samsung UE46C5000QW не умеет просматривать видео, транслируемое в UDP или в RTMP. Зато он умеет смотреть фильмы по сети с использованием DLNA, поэтому я решил попробовать настроить связку телевизора UE46C5000QW и роутера D-Link DIR 300 Rev b для просмотра IPTV без использования компьютера — это не так уж и сложно.

Родная прошивка DIR 300 вполне справлялась с UDP потоками, но преобразовать UDP поток в DLNA-совместимый HTTP поток ей не по зубам. Пришлось сменить прошивку роутера на DD-WRT v24-sp2 (build 14896). Прошивка хороша тем, что под нее можно собирать много линуксовых приложений, загружать их при необходимости и использовать по прямому назначению. Под прошивку были найдены udpxy (преобразователь udp потока в tcp), и upnpd — маленький демон, который публикует плейлисты в DLNA-совместимом формате. Информации о том, как это можно сделать, в сети навалом; так же как и сборок этих приложений под большинство роутеров, работающих под DD WRT или OpenWRT.

Все бы хорошо, но вот потоки RTMP по-прежнему смотреть на телевизоре было невозможно. Для преобразования RTMP в HTTP был давным-давно написан пакет rtmpdump, в составе которого есть маленький прокси — rtmpgw, который в теории должен справляться с задачей.

Но тут есть три проблемы. Во-первых, чистый rtmpgw не добавляет правильные заголовки в http-поток, в результате чего телевизор разрывает соединение и ругается на неподдерживаемый формат файла (даже если видео и аудио кодеки абсолютно точно поддерживаются им). Любой расово правильный медиаплеер (mplayer, vlc) показывают такие потоки, но не телевизоры Samsung.

Во вторых, из-за одной довольно криво написанной функции оригинальный rtmpgw очень нехило кушает CPU, что не есть хорошо.

В-третьих, я так и не нашел готовой сборки rtmpgw для dd-wrt своего роутера. Поэтому пришлось качать исходники, ковыряться в исходном коде и собирать свой вариант rtmpgw. И в результате у меня получился вот такой бинарник rtmpgw (mipsel, не путать с mips — он не совместим) — качайте на здоровье и можете ставить его в свой роутер.

Использовать его можно примерно так. На роутере сохраняются команды, выполняемые при каждой загрузке:

cd /tmp
wget http://www.bloged.org/downloads/rtmpgw
chmod +x rtmpgw
/tmp/rtmpgw --buffer 120000 -v -g 8082 -D 192.168.1.1 >/dev/null 2>/dev/null &

где 192.168.1.1 — внутренний IP роутера

Если запуск прошел успешно, то по адресу http://192.168.1.1:8082 будет транслироваться RTMP поток, который можно передать в качестве параметра. Проверить работоспособность можно из локальной сети за роутером:

vlc "http://192.168.1.1:8082/?r=rtmp:%2F%2Fvipwowza.yacast.net%2Ffrance24_live_en&s=http:%2F%2Fwww.france24.com%2Fen%2Fsites%2Fall%2Fmodules%2Fmaison%2Faef_player%2Fflash%2Fplayer_new.swf&t=rtmp:%2F%2Fvipwowza.yacast.net%2Ffrance24_live_en&p=http:%2F%2Fwww.france24.com&y=f24_liveen.stream"

VLC покажет англоязычную трансляцию France 24, если мой бинарник совместим с вашей прошивкой и вы все сделали правильно. К сожалению, транслировать такое в телевизор Cамсунг не получится — конкретно в этом потоке он не поймет кодеки (по крайней мере мой телевизор ругается на них). Тут нужен транскодинг, но это уже совсем другая тема для разговора.

Остальные каналы, которые я нашел с кодеками H264 – MPEG-4 AVC / Mpeg Audio Layer (mpga), транслируются без проблем.

Заметил одну особенность в некоторых трансляциях. Часть из них транслируются нормально, у другой части наблюдается прогрессирующее отставание звука от картинки на телевизорах Samsung. Убогий самсунговский плеер почему-то не может синхронизировать видео и звук при длительной работе на таких потоках. Причем если поток сохранить в файл и открыть его через DLNA, отставания нет даже в телевизоре; оно наблюдается только при онлайн трансляции. А в vlc или mplayer такая проблема не наблюдается вообще, они умеют синхронизировать картинку со звуком, даже если в потоке есть потери фреймов.

OpenSuse и интернет через Bluetooth

Nokia E5

Я уже писал про использование телефона Nokia E5 в качестве модема, и даже приводил настройки интернета для черногорского оператора M-tel. Все это работает отлично, если бы не одно НО. Длинна USB кабеля для Nokia E5 меньше 10 сантиметров, и уж очень неудобно его крепить к ноутбуку. Телефон постоянно свешивается, дергается; связь может теряться в зоне неуверенного приема. И я решил попробовать использовать телефон в качестве модема при соединении через Bluetooth.

Оказалось, все делается очень просто. Сначала надо сделать так, чтобы телефон и ноутбук снюхались по Bluetooth. Это делается очень просто — на телефоне разрешается соединение Bluetooth для всех, и с помощью апплета gnome-bluetooth находится телефон среди доступных. Далее следует обмен пин-кодами и вуаля, две железки снюхались.

Затем надо посмотреть, какой канал модема используется в телефоне. Ищем адрес телефона:

notebook:~ # hcitool scan
Scanning ...
        04:A8:2A:93:CE:48       Nokia E5

Далее выясняем номер канала модема:

# sdptool browse 04:A8:2A:93:CE:48
…
Service Name: Dial-Up Networking
Service RecHandle: 0x10009
Service Class ID List:
  "Dialup Networking" (0x1103)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 5
Language Base Attr List:
  code_ISO639: 0x454e
  encoding:    0x6a
  base_offset: 0x100
Profile Descriptor List:
  "Dialup Networking" (0x1103)
    Version: 0x0100
…

В моем случае это Channel 5. Теперь надо настроить модем:

# cat /etc/bluetooth/rfcomm.conf
#
# RFCOMM configuration file.
#

rfcomm0 {
        # Automatically bind the device at startup
        bind yes;

        # Bluetooth address of the device
        device 04:A8:2A:93:CE:48;

        # RFCOMM channel for the connection
        channel 5;

        # Description of the connection
        comment "Nokia E5 Bluetooth Modem";
}

Номер канала в настройках модема должен совпадать с номером обнаруженного канала, иначе модем работать не будет. После этого надо создать конфигурационный файл для «звонилки». Привожу свой конфиг для черногорского оператора T-mobile:

# cat /etc/wvdial.conf
[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,"IP","tmcg-wnw"
Modem = /dev/rfcomm0
Phone = *99#
Idle Seconds = 30000
Modem Type = USB Modem
Stupid Mode = 1
Compuserve = 0
Baud = 460800
Auto DNS = on
New PPPD = Yes
Dial Command = ATDT
Ask Password = 0
ISDN = 0
Password = 38167
Username = 38167

Ну и последний скрипт запуска «звонилки»:

# cat start_internet_via_bluetooth.sh
#!/bin/sh
rfcomm release 0 # разрываем текущую связь устройства с модемом
rfcomm bind 0 04:A8:2A:93:CE:48 5  # привязываем модем телефона на 5-м канале к устройству rfcomm0
wvdial # набираем номер и подключаемся к интернету

Вот теперь телефону не обязательно находиться рядом с ноутбуком. Его можно держать, например, на балконе (где уровень сигнала выше чем в помещении). Главное, чтобы ноутбук видел телефон, а телефон видел сеть. Скорости передачи данных более чем достаточно для голосовой связи по SIP или Skype.

Про перемотку, DLNA и телевизор Samsung.

Смеркалось. KTorrent докачивал очередной фильм в FullHD, и в мою не совсем трезвую голову пришла шальная мысль: а почему бы и не посмотреть это кино на телевизоре вместо монитора? А что, кабель HDMI — есть, на видеокарте выход HDMI — есть, на телевизоре разьем HDMI тоже имеется. Соединить одно с другим несложно и этот вариант 100% рабочий. Но мы не ищем легких путей, ибо телевизоров дома может быть несколько и вдруг мне приспичит посмотреть на каждом ящике свой фильм — одного кабеля HDMI будет маловато.

Так что созрел у меня коварный план — поднять у себя DLNA-сервер и раздавать фильмы в локальной сети. С OpenSuSe 12.2 поставить miniDLNA вообще не проблема, но сложности начались там, где я их не ожидал. Телевизор Samsung UE46C5000QWX прекрасно воспроизводит фильмы через DLNA, но отказывается их перематывать. Однако у меня были подозрения, что телевизор все-таки перематывать умеет, т. к. при выключении фильма и повторном его запуске он предлагал продолжить воспроизведение с места остановки. Если внимательно вчитаться в инструкцию к телевизору, то там будет написано — перемотка не поддерживается при просмотре видео через DLNA; и это касается многих моделей Samsung TV.

Однако методом научного тыка и просмотра камментов к багам miniDLNA таки были обнаружены кнопки на пульте, которые перематывают видео. Они оказались нестандартные, вместо кнопок перемотки надо было нажимать на кнопки навигации по меню (вправо и влево) — и перемотка стала работать как надо.

Правда, есть один нюанс, перемотка срабатывает не всегда. Например, файлы flv скачанные с youtube почему-то не перематваются. Но это уже не проблема, т. к. перекодировать flv в avi (который легко перематывается) совсем не сложно:

mencoder -oac mp3lame -ovc lavc -o file.avi file.flv

Вообще, телевизоры Samsung производят приятное впечатление по качеству железа, и отвратительное по качеству софта/прошивок. Непонятная ситуация с перемоткой может расцениваться как бага или как недокументированная фича; а вот отсутствие возможности отключения экрана при проигрывании музыки — это уже серьезная недоработка, которую Samsung и не думает исправлять.

Новый сервис – Аудиоредактор

Я тут новый сервис наваял — Аудиоредактор. Он позволяет загружать аудио файлы на сервер, конвертировать их в AAC, M4R, MP3, OGG или WAV, а также вырезать выбранный интервал из трэка. Также можно добавить эффект приглушения звука в начале и в конце трэка (эффект fade), загружать аудио по прямым ссылкам.

Есть и экспериментальная фича, можно вырезать звук из ролика в Youtube. Только честно скажу, это срабатывает не всегда: иногда youtube банит айпишник за слишком частое скачивание; иногда ругается на то, что в стране сервера просмотр ролика невозможен из-за ограничения авторских прав; могут быть и другие причины.

Но в целом все работает, может кому-то будет интересно.