советы.блогспот.ком

GNU/Linux, Vim, LaTeX, полезные скрипты, визуализация данных, численные расчёты

20090701

Сортировка фото по дате EXIF

На днях и я, и virens почти синхронно написали две заметки об EXIF: как исправить дату EXIF в фото и как добавлять пользовательские теги в raw-файлы. Раз уж тема начата, то поделюсь ещё одним приёмом.

Фотографии я храню, группируя каталоги по годам и по датам съёмки (указывая дату в формате ISO), то есть в архиве путь к альбому у меня примерно такой: photos/2009/20090628 - название альбома/. Очень удобно, потому что обычно один день — одна тема, и даже при алфавитной сортировке каталога альбомы упорядочены хронологически. И такая организация не зависит ни от операционной системы, ни от конкретной программы-каталогизатора.

Однако если на карточке фотографии разных дней — раскидывать их по альбомам вручную утомительно. Поэтому у меня есть ещё и скрипт-сортировщик для внесения фото в архив. Он смотрит на дату в EXIF, создаёт нужные каталоги и помещает в них фото:
#!/bin/sh

ARCHIVE=$HOME/photos

for f in "$@"; do
DT=$(exiftool -s -DateTimeOriginal "$f")
YEAR=$(echo $DT|awk '{print $3;}'|awk -F: '{print $1;}')
ISODAY=$(echo $DT|awk '{print $3;}'|sed 's/://g')
TARGET="$ARCHIVE/$YEAR/$ISODAY"
install -d "$TARGET" && \
install "$f" "$TARGET"
echo "$f -> $TARGET"
done


Запускаю из каталога с фотокарточки:
$ import-photos *

Так можно импортировать и JPEG-и, и RAW. И там, и там EXIF обычно есть.

Как ускорить Firefox на eeePC 901

На моём eeePC 901 Firefox часто подтормаживал, и это явно совпадало с работой диска. Объяснение нашлось здесь.

Дело в том, что в eeePC 901 два флэш-диска, маленький на 4 ГБ и большой 16 ГБ, и этот большой флэш-диск — медленный. Домашний же раздел /home у меня, естественно, на большом, и там же профиль Firefox-а. Браузер же по-умолчанию сохраняет в него текущую сессию каждые 10 секунд и туда же пытается писать кэш. Пишет он синхронно (то есть ждёт, пока не запишется), поэтому и замирает на секунду при каждом чихе.

Народная медицина в этом случае рекомендует пойти в about:config и там

1) создать ключ toolkit.storage.synchronous с целым значением 0 (запись на диск вести асинхронно, то есть не ждать, пока, например, состояние сессии действительно запишется)

2) создать или изменить ключ browser.cache.disk.parent_directory, его строковое значение установить в /dev/shm/firefox-username (сохранять кэш в памяти, а не писать на диск; кэш, конечно, будет утерян при перезагрузке, и памяти потребуется больше, но зато и работать будет быстрее)

Дополнительно я увеличил промежуток времени между записями состояния сессии (списка открытых вкладок):

3) в browser.sessionstore.interval поставил 60000 (60 секунд), вместо 10000 (10 секунд).

Я попробовал — так явно лучше (iceweasel 3.0.6). Возможно, с кэшем есть и более красивые решения (сделать внутри профиля символическую ссылку куда-нибудь на быстрый диск, или какими-то другими ключами отключить дисковый кэш, увеличив кэш в памяти...). Можете оставлять в комментариях ссылки и рецепты.

Советы, полагаю, применимы не только к eeePC, но и к другим нетбукам с SSD (флэш-дисками).

В предыдущей заметке можно прочитать, как мы ставили и настраивали Debian на eeePC.

20090629

Как исправить дату EXIF в фото

Иногда, отфотографировав день-два-три можно обнаружить, что всё это время в камере стояла неправильная дата. Я тут как раз ошибся: на один год (вперёд), 12 часов (a.m./p.m, эх) и один часовой пояс.

Дело поправимое. Поможет exiftool. Чтобы откатить дату на один год и 12+1 (13) часов, поступаем так:
$ exiftool "-DateTimeOriginal-=1:0:0 13:00:00" *.jpg

Смотрим, что получилось, и если что-то не так, то возвращаемся к оригиналам (exiftool их услужливо сохранит):
$ for f in *_original ; do mv $f ${f%_original} ; done

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

20090625

Metacity: сочетания клавиш, чтобы прижимать окна к краю

При всей любви и уважении к мозаичным оконным менеджерам, я пользуюсь традиционными перекрывающимися окошками. С мозаичными менеджерами на маленьком ноутбучном экране у меня обычно всё складывалось примерно так:

Первый экран — терминал во всю стену. Второй экран — браузер на 80% ширины, IM на 20% ширины. Остальные экраны — для остальных приложений (отдельный для Gimp, отдельный для полноэкранного плеера, и т.д.).

Итак, я на практике понял, что в основных рабочих приложениях удобно работать или в полноэкранном режиме, или поместив рядом два приложения. В двух этих случаях, кстати, мозаичность удобна. В остальных случаях, мозаичность иногда даже мешает. Однако для терминала во весь экран никакой мозаичности не нужно. Достаточно нажать F11 в Гноме (аналогичное сочетание клавиши где угодно). Остаётся случай «два окна рядом», одно справа, другое слева. Раз в день разложить так окна руками, конечно, можно.

Однако удобнее, когда есть клавиатурные сочетания. Во-первых, нужна максимизация по горизонтали и особенно по вертикали. Тогда окно сразу займёт всю ширину (или высоту) экрана, а для другого окна рядом останется место. Во-вторых, очень полезны сочетания, позволяющие подвинуть окно к краю экрана. С парой окон на экране и такими сочетаниями можно наслаждаться мозаичностью в любом оконном менеджере. В Openbox такие сочетания легко настраиваются, а вот в конфигураторе для Metacity (Gnome) — команд, чтобы прижать окно к краю, нет.

Так я думал и продолжал передвигать окна ручками. Одно влево, другое вправо. А сегодня узнал, что команды такие в Metacity есть. И сочетания клавиш к ним привязать можно в gconf-editor. Запускаем, идём в /apps/metacity/window_keybinding и там для команд move_to_side_x (где x — n, e, s, w) прописываем сочетания клавиш (строковое значение вида <Shift><Control>Up). Всё сразу работает.

сочетания клавиш для того, чтобы прижимать окна Metacity к краю экрана

С моим настройками я нажимаю Ctrl+Shift+F11, и окно вытягивается на всю высоту экрана. Нажимаю Ctrl+Shift+, и окно прижимается к правому краю. Другое окно вытягиваю и прижимаю к левому краю. На другом экране я запускаю терминал и нажимаю F11 (полный экран). Всё остальное, что собираюсь держать открытым дольше минуты (читалку PDF, плеер, и т.п.) запускаю на других экранах.

Кстати, полноэкранный терминал (без заголовков окон, без полосы прокрутки) — по-моему, ещё и идеальный полноэкранный редактор, то есть такая среда для работы с текстом, в которой ничего не отвлекает. То, что людям такая среда нужна — доказывает обилие специальных полноэкранных редакторов. А ничего специального не нужно: достаточно полноэкранного терминала и vi (или emacs). Вообще, полноэкранный режим чрезвычайно удобен, не только для терминала, но и для некоторых других приложений.

20090611

Debian Lenny на Samsung X22

Мой новый рабочий ноутбук — Samsung X22. Черновой отчёт об установке и настройке Debian здесь (по-английски).

Когда разрешу оставшиеся вопросы, перепишу по-русски и помещу здесь. Пока очень кратко.

WiFi нормально работает после установки firmware-iwlwifi.

Комбинации клавиш Fn+... работают не все. Из коробки работают «кнопка сна» и регулировка громкости. Оказалось, не страшно. Простейший патч к hal-info, починяющий кнопки, разработчикам отправлен.

Видео-драйвер radeon работает, но не летает. Версия в Lenny недостаточно свежая и XVideo не поддерживает. Буду разбираться. fglrx вроде работает.
Дополнение 2009-07-01: fglrx который в Lenny, работает без нареканий, а вот с Xorg из unstable мне завести fglrx не удалось. Зато в Xorg из unstable драйвер radeon — уже 6.12.2. А именно в 6.12 появилась поддержка ускорения EXA и XVideo для чипов серии R6xx. Чтобы заработало, нужно также либо ядро 2.6.30 или новее, либо пересобрать модули radeon.ko и drm.ko для старых ядер. Как это сделать — написано в X.org вики (это минутное дело). Да, если ядро Debian — нужно ещё доустановить пакет firmware-linux (то, что выкинули из дебиановского ядра). И действительно — после этого новый свободный драйвер radeon работает. Видео высокого разрешения играется, по-моему, даже лучше и ровнее, чем с fglrx. 3D, правда, пока в свободном драйвере нет, только в fglrx. В общем, сейчас есть выбор: жить с Xorg из stable и проприетарным fglrx, или с Xorg из unstable и со свободным radeon (видео лучше, нет 3D).


Звук играет и с драйвером из Lenny, но, чтобы заработал микрофон, нужна свежая ALSA и в /etc/modprobe.d/alsa-base пришлось добавить
options snd-hda-intel model=ultra
По нажатию на Fn+Esc машина и с самого начала засыпала хорошо, но после просыпания экран не включался. Установил, что работают:
s2ram -f -a 2
и
pm-suspend --quirk-s3-mode
Соответственно в /usr/share/hal/fdi/information/10freedesktop/20-video-quirk-pm-samsung.fdi переделал так:
     <!-- this does not work for my SX22S! -->
<match key="system.hardware.product" string_outof="R40/R41;CoronaR">
<merge key="power_management.quirk.vbestate_restore" type="bool">true</merge>
</match>
<!-- I use this one: -->
<match key="system.hardware.product" string="SX22S">
<merge key="power_management.quirk.s3_mode" type="bool">true</merge>
</match>
После этого и спим хорошо, и просыпаемся.

Вебкамера, кардридер (xD/SD/MS) работают отлично. Оптический привод, вроде, тоже. Bluetooth пока не пробовал, а вот ExpressCard и HDMI проверять просто не на чем.

20090526

Twtrize — сократитель речи

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

Люди иногда сознательно сокращают слова, набирая SMS или твиты — чтобы потратить меньше денег или укоротить сообщение.

Идея возникла, когда на одном из многочисленных «сократителей URL» я увидел надпись «Shrink text». И мне пришло в голову, что вот он возьмёт, и сократит сам текст: выдаст что-нибудь вроде «shrnk txt». Конечно, сервис всего лишь заменял в тексте URL, но я подумал, что можно было бы сокращать и сам текст.

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

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

Зависимости


Программа написана на Literate Haskell (это значит, что то, что, вы сейчас читаете, и есть программа!). Используются следующие модули:
> import System.IO.UTF8 as U
> import Data.Char (toLower)
> import Text.Regex.Posix ((=~))
> import Data.Char (isPunctuation)

TODO: Я использую старый способ работать с UTF-8 (utf8-string), надо переделать под новую библиотеку text.

Алгоритм


Данная программа «сжимает» русский текст так:
I. Из слов убираются (почти) все гласные и мягкие знаки,
> filterVowels = filter (`notElem` (aVowels ++ jVowels))

Неприкосновенны гласные, которые:
I.a. являютя частью приставки «не-»
> rmVowels = map wordFilter
> where
> wordFilter ('н':'е':cs) = "не" ++ wordFilter cs

I.b. стоят в трёх- и менее -буквенных словах
>    wordFilter w = if length w <= 3
> then w

I.c. стоят в начале или конце слова
>                    else
> let (prefix,inner,ending) = splitWord w
> in prefix ++ (ajaFilter inner) ++ ending

>    splitWord s  = let p = takeWhile dontRemove s
> r = drop (length p) s
> e = reverse $ takeWhile dontRemove $ reverse r
> m = take ((length r) - (length e)) r
> dontRemove c = c `elem` vowels || isPunctuation c
> in (p,m,e)

I.d. являются комбинациями со звуком «й»: «-ою-», «-ая—» и проч.
>    ajaFilter [] = []
> ajaFilter s = let (b,m,a) = s =~ diftPat :: (String,String,String)
> diftPat = "[" ++ vowels ++ "][" ++ jVowels ++ "]"
> in (sameConsFilter b) ++ m ++ (ajaFilter a)

I.e. стоят меж двух одинаковых согласных
>    sameConsFilter [] = []
> sameConsFilter s =
> let (b,m,a) = s =~ sameConsPat :: (String,String,String)
> sameConsPat = "(["++consonants++"])[" ++ vowels ++ "]\\1"
> in (filterVowels b) ++ m ++ (sameConsFilter a)

Программа использует такой список гласных:
> vowels = aVowels ++ jVowels

где есть и простые гласные (к ним же причислен и мягкий знак)
> aVowels = "аиоуыэь"

и дифтонгообразующие (не знаю правильного термина — в общем, дающие звук «й»),
к ним же причислена и буква «й»:
> jVowels = "яйёюе"

Для некоторых правил требуется также список русских согласных:
> consonants = "бвгджзклмнпрстфхцчшщ"

II. из предложений убираются знаки препинания, кроме точек, вопросительных и восклицательных знаков
> rmSomePunctuation = filter (not . null) . map rmTrailing
> where rmTrailing = reverse . rmHead . reverse
> rmHead [] = []
> rmHead s@(c:cs) = case c `elem` rmlist of
> True -> rmHead cs
> False -> s

Список подлежащих удалению знаков препинания:
>         rmlist = ",;-—:–"

III. из текста удаляются некоторые предлоги (в телеграфном стиле)
> rmPrepositions = filter (`notElem` preps) . words
> where preps = [ "в", "во", "на", "над", "к", "от", "из"
> , "по", "под", "через" ]

IV. для пущей стилизации текст пишется в нижнем регистре
> tolower = map toLower


Использование программы


Программу можно использовать как простой unix-фильтр: он читает текст из потока stdin и печает «сжатый» текст в стандартный вывод (stdout).
> main = U.interact $ (++ "\n") . twtrize

> twtrize = unwords . filter ( not . null ) .
> rmVowels . rmSomePunctuation . rmPrepositions . tolower

Пример:
    $ printf "Гласные, а также некоторые предлоги — как, например, «на», — из \
текста удаляются, но какие-то остаются.\n" | runhaskell twtrize.lhs

глсные а ткже нектрые прдлги как нпрмр «на» ткста удляются но какие-то
остаются.


Последняя версия: исходник здесь. Лицензия: BSD-3.

20090515

Ledger — бухучёт в командной строке

Решил, что надо наводить порядок в своей жизни и деньги считать. В общем, вести домашнюю бухгалтерию. Познания в бухучёте у меня очень скромные (хотя когда-то и прослушал вводный курс), помню только, что такое двойная запись, и дебет/кредит. Когда-то, правда, пользовался GNUcash.

Кроме GNUcash в линуксе есть ещё несколько программ для учёта личных финансов: KMyMoney и Grisbi. Программы красивые, удобные, наглядные. Однако меня впечалил и заинтересовал ledger. Это бухучёт в стиле unix. В общем, для фанатов.

Идея проста: записываем все расходы/доходы в текстовый файл (файл редактируем сами, программа его не трогает), а программа всегда поможет проверить баланс и составить отчёт о текущем состоянии или по периоду. Что может быть естественней, проще, надёжней? Полный простор в организации учёта.

Отмечу, что вначале я нашёл не сам ledger, а его клон hledger, написанный на Haskell. Есть ещё и вариант написанный на Python — beancount. Какую программу выбрать — дело вкуса. Формат файла, к счастью, у них (почти) одинаковый. «Старший» ledger уже есть в репозиториях Ubuntu и Debian, но мне пока больше понравился вариант на Haskell (исходники короче и понятнее), про него и буду рассказывать.

Хотя сложного в использовании ledger вроде ничего нет, трудно начать, потому что все примеры в сети на английском и используют английскую бухгалтерскую терминологию. Для меня, чтобы разобраться, было важно понять формат в котором вести записи. Итак, файл состоит из записей, формат каждой записи
ДАТА[=ФАКТИЧЕСКАЯ ДАТА] [*|!] [(КОД)] [ОПИСАНИЕ] [ ; КОММЕНТАРИЙ ]
отступ НАЗВАНИЕ СЧЕТА хотя бы два пробела СУММА [ ; КОММЕНТАРИЙ ]
отступ НАЗВАНИЕ ДРУГОГО СЧЕТА [ хотя бы два пробела СУММА ] [ ; КОММЕНТАРИЙ ]
[другие счета, если необходимо]
Каждая запись начинается с цифры, то есть даты. Даты пишем в формате ISO, ГГГГ-ММ-ДД. Для краткости можем указать в файле
Y2009
и все последующие записи без указания года будут относится к 2009-му году.

Описание проводки может быть любым. Номера квитанций, счетов и тому подобные коды можно вписывать в поле (КОД) (указывать перед описанием в скобках).

СУММЫ можно писать так, как удобно, «13», «$42», «17 EUR», «121 Kb», «9 L». Ledger понимает, что разные единицы измерения нужно считать отдельно. Единицы можно указывать любые, те, которые нужно учитывать. В том числе и неденежные (и программа умеет их правильно пересчитывать, если ей дать файл с историей цен).

В каждой записи обычно два или три счета, но указывать сумму для одного из них необязательно, понятно, что изменение будет равно сумме всех других, но с противоположенным знаком:
2009-05-14
расходы:обед 123 RUB
актив:наличные ; понятно, что здесь должно быть -123 RUB
Счета можно называть как угодно. В том числе и по-русски. Можно делать подсчета, используя двоеточие в названии счёта, например, «расходы:услуги:интернет». Видимо, необходимо иметь счета как минимум пяти категорий: актив, долги, доходы, расходы и какой-то счёт для уравнивания балансов. Я назвал его «собственные», в англоязычных примерах его обычно называют «equity».

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

Составим такой файл со счетами, для начала. Пусть у нас есть текущий счёт в банке, на котором лежит 1001 рубль (единицы не будем указывать для краткости), есть что-то в кошельке, скажем 150 рублей. Пишем файл:
Y2009

05-14 начальное состояние счета в банке
актив:банк 1001
собственные:начало

05-14 начальное содержимое кошелька
актив:наличные 150
собственные:начало
Сохраняем в файл, например ~/.ledger (там его по-умолчанию ищет hledger). Смотрим, что получилось:
~$ hledger
1151 актив
1001 банк
150 наличные
-1151 собственные:начало
Программа сама догадалась подсчитать баланс виртуального счёта «актив». Всё сходится: всё, что было списано со счёта «собственные:начало» оказалось в «активе». Если что-то не сходится, программа будет страшно ругаться.

Как записывать расход-приход — см пример записи выше. Допустим, мы что-то купили и что-то получили в подарок:
05-15 * подарок
актив:наличные 100
доходы:подарки
05-15 * яблоко
расходы:покупки 9
актив:наличные
Я добавил звёздочку перед описнием проводок. Как её интерпретировать — дело хозяйское. Я помечаю ей те операции, которые уже завершены (а восклицательным знаком — те, которые запланированы). Программа потом позволяет легко отбирать проводки со звёздочкой и без.

Предположим, например, что на завтра я запланировал ответный подарок, но ещё его не сделал:
05-16 ! ответный подарок
расходы:подарки 90
актив:наличные
Теперь, если посмотреть баланс с ключиком -C, увидим только то, что завершено:
$ hledger -C bal
91 актив:наличные
-100 доходы:подарки
9 расходы:покупки
Чтобы посмотреть не баланс, а список проводок, есть команда register:
~$ hledger reg
2009/05/14 начальное состояни.. актив:банк 1001 1001
собственные:начало -1001 0
2009/05/14 начальное содержим.. актив:наличные 150 150
собственные:начало -150 0
2009/05/15 подарок актив:наличные 100 100
доходы:подарки -100 0
2009/05/15 яблоко расходы:покупки 9 9
актив:наличные -9 0
2009/05/16 ! ответный подарок расходы:подарки 90 90
актив:наличные -90 0
Отмечу, что в «сишной» версии ledger колонки здесь разъедутся. А вот в hledger-0.5 уже всё в порядке (и для 0.4 я тоже сделал патчик).

В общем, баланс (balance) и проводки (register) — два главных отчёта. Можно ограничивать отчёты по диапазону дат или периодам. Или по названиям счетов. Так, чтобы выбрать все счета со словом «подарки» в названии, используем регулярное выражение:
$ hledger reg .*подарки.*
2009/05/15 подарок доходы:подарки -100 -100
2009/05/16 ! ответный подарок расходы:подарки 90 -10
Чтобы выбрать записи по описанию, поступаем так:
$ hledger reg desc:яблоко
2009/05/15 яблоко расходы:покупки 9 9
актив:наличные -9 0
В общем, идея понятна. Для отчётов по неделям и по месяцам есть ключики -W и -M.

Бывают ещё периодические записи, но только в ledger, в hledger их пока нет. Они не означают, что со счёта что-то автоматически списывается. Проводку нужно всё равно вносить вручную, но периодические записи позволяют рассчитывать прогноз бюджета. В ledger также можно делать виртуальные записи, ими можно автоматически учитывать разные комиссии или проценты.

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

Вот пример ledger-файла.