<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4154333943174084921</id><updated>2026-07-24T08:54:24.109+03:00</updated><category term="linux"/><category term="утилиты"/><category term="python"/><category term="звук"/><category term="Programming Praxis"/><category term="jabber"/><category term="scheme"/><category term="программирование"/><category term="сеть"/><category term="C++"/><category term="GNOME"/><category term="консоль"/><category term="математика"/><category term="регулярные выражения"/><title type='text'>Всё чудесатее и чудесатее</title><subtitle type='html'>Блог о разных интересностях, чаще компьютерных, но не без исключений</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-229757851018959860</id><published>2010-06-14T17:30:00.005+03:00</published><updated>2010-06-14T18:29:41.815+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="звук"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>И снова о разрезании lossless-аудио (ape, flac, wv, wav) по файлу cue</title><content type='html'>&lt;a href=&quot;http://strange-to-say.blogspot.com/2009/10/lossless-ape-flac-wv-wav-cue.html&quot;&gt;Ранее&lt;/a&gt; я выкладывал перевод одной заметки о том, как разрезать lossless-аудио на отдельные треки. Однако, в комментариях мне подсказали более простой способ.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;Для этого понадибится утилита shntool (в Debian и Ubuntu живёт в одноимённом пакете). Вообще, это настоящий швейцарский армейский нож в области работы со звуковыми файлами (в том числе и сжатыми), в чём можно убедиться, открыв соответствующий man:&lt;br /&gt;&lt;pre&gt;man shntool&lt;/pre&gt;Вот перечень некоторых команд, которые эта утилита поддерживает:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;len — отображает продолжительность, размер и свойства звуковых данных&lt;/li&gt;&lt;li&gt; join — объединяет несколько файлов в один&lt;/li&gt;&lt;li&gt;split — разбивает звуковой файл на несколько отдельных файлов&lt;/li&gt;&lt;li&gt;cue — генерирует файл CUE или список точек разбиения по набору файлов&lt;/li&gt;&lt;li&gt;conv — преобразует из одного формата в другой&lt;/li&gt;&lt;li&gt;trim — удаляет тишину по краям записи&lt;/li&gt;&lt;/ul&gt;Список поддерживаемых форматов тоже немал: wav (RIFF WAVE), aiff (Audio Interchange File Format), shn (Shorten low complexity waveform coder), flac (Free Lossless Audio Codec), ape (Monkey&#39;s Audio Compressor), ofr (OptimFROG Lossless WAVE), lpac (Lossless Predictive Audio Compression), wv (WavPack Hybrid Lossless Audio Compression), alac (Apple Lossless Audio Codec) и другие, менее распространённые.&lt;br /&gt;&lt;br /&gt;Естественно, для поддержки форматов нужно доустанавливать соответствующие утилиты. Для flac, ape и wv:&lt;br /&gt;&lt;pre&gt;sudo apt-get install flac wavpack monkeys-audio&lt;/pre&gt;Собственно команда для разрезания будет иметь вид:&lt;br /&gt;Эта команда не только разобьёт исходный flac-файл, но и переименует каждый трек в соответствии с форматом:&lt;br /&gt;&lt;br /&gt;Исполнитель (Альбом) - Номер - Название&lt;br /&gt;&lt;br /&gt;Естественно, можно указать и другой формат, задав свою строку и используя постановочные символы %p, %a, %n, %t.&lt;br /&gt;&lt;br /&gt;Если файлы Music.flac и Music.cue расположены в одной папке, имеют одинаковое имя, как в данном случае и других подобных файлов нет, то можно использовать следующий скрипт:&lt;br /&gt;&lt;pre   style=&quot;color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);font-family:&#39;Courier New&#39;;font-size:10pt;&quot;&gt;&lt;span style=&quot;color: rgb(131, 129, 131); font-style: italic;&quot;&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;f&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;`ls *.cue`&lt;/span&gt;&lt;br /&gt;f&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color: rgb(1, 1, 129);&quot;&gt;${f%.cue}&lt;/span&gt;&lt;br /&gt;shntool &lt;span style=&quot;color: rgb(0, 0, 0); font-weight: bold;&quot;&gt;split&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;-&lt;/span&gt;f &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&quot;$f.cue&quot;&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;-&lt;/span&gt;o flac &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&quot;$f.flac&quot;&lt;/span&gt; &lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;-&lt;/span&gt;t &lt;span style=&quot;color: rgb(255, 0, 0);&quot;&gt;&quot;%p (%a) - %n - %t&quot;&lt;/span&gt;&lt;/pre&gt;Я его назвал split_flac и поместил в ~/bin. Чтобы им воспользоваться достаточно зайти в директорию с разрезаемыми файлами и выполнить всего одну команду:&lt;br /&gt;&lt;pre&gt;split_flac&lt;/pre&gt;Аналогичный скрипт можно написать и для формата APE. А можно сделать один большой интеллектуальный скрипт, если не лень.&lt;br /&gt;&lt;br /&gt;Чтобы не было закорючек в именах, нужно следить, чтобы файл cue был в той же кодировке, что и текущая локаль (обычно, UTF-8).&lt;br /&gt;&lt;br /&gt;Единственный минус — теги будут пустыми, но их можно заполнить командой cuetag или какой-то специализированной утилитой наподобие EasyTAG.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/229757851018959860/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/lossless-ape-flac-wv-wav-cue.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/229757851018959860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/229757851018959860'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/lossless-ape-flac-wv-wav-cue.html' title='И снова о разрезании lossless-аудио (ape, flac, wv, wav) по файлу cue'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-3044499393359486348</id><published>2010-06-08T21:05:00.005+03:00</published><updated>2010-06-09T15:48:20.475+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Programming Praxis"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="scheme"/><title type='text'>Решето Эратосфена / Sieve of Eratosthenes</title><content type='html'>&lt;a href=&quot;http://programmingpraxis.com/2009/02/19/sieve-of-eratosthenes/&quot;&gt;Programming Praxis, 19.02.2009&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Более двух тысяч лет назад Эратосфен, который вычислил окружность Земли, расстояние до Солнца и наклон земной оси, изобрёл широту и долготу, а также придумал високосный день, создал систематический метод перечисления всех простых числе, который используется и по сей день.&lt;br /&gt;Эратосфен родился в Кирене (на территории современной Ливии) и жил с 276 г. до н. э. по 194 до н. э. Он провёл большую часть своей жизни в Александрии (Египет), где был вторым главой Великой библиотеки перед &lt;a href=&quot;http://ru.wikipedia.org/wiki/%D0%90%D0%BF%D0%BE%D0%BB%D0%BB%D0%BE%D0%BD%D0%B8%D0%B9_%D0%A0%D0%BE%D0%B4%D0%BE%D1%81%D1%81%D0%BA%D0%B8%D0%B9&quot;&gt;Аполлонием Родосским&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Решето Эратосфена начинается с создания списка натуральных чисел до желаемого предела; проиллюстрируем метод, вычислив простые числа до тридцати:&lt;br /&gt;&lt;br /&gt;2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30&lt;br /&gt;&lt;br /&gt;Теперь возьмём первое число в списке — 2 — и вычеркнем каждое второе число:&lt;br /&gt;&lt;br /&gt;2 3 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;4&lt;/span&gt; 5 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;6&lt;/span&gt; 7 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;8&lt;/span&gt; 9 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;10&lt;/span&gt; 11 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;12&lt;/span&gt; 13 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;14&lt;/span&gt; 15 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;16&lt;/span&gt; 17 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;18&lt;/span&gt; 19 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;20&lt;/span&gt; 21 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;22&lt;/span&gt; 23 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;24&lt;/span&gt; 25 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;26&lt;/span&gt; 27 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;28&lt;/span&gt; 29 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;30&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Затем берём следующее невычеркнутое число в списке — 3 — и вычёркиваем каждое третье число; некоторые из них окажутся уже вычеркнутыми:&lt;br /&gt;&lt;br /&gt;2 3 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;4&lt;/span&gt; 5 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;6&lt;/span&gt; 7 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;8&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;9&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;10&lt;/span&gt; 11 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;12&lt;/span&gt; 13 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;15&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;16&lt;/span&gt; 17 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;18&lt;/span&gt; 19 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;20&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;21&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;22&lt;/span&gt; 23 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;24&lt;/span&gt; 25 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;26&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;27&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;28&lt;/span&gt; 29 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;30&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;повторяем последний шаг для следующего невычеркнутого числа — 5:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2 3 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;4&lt;/span&gt; 5 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;6&lt;/span&gt; 7 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;8&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;9&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;10&lt;/span&gt; 11 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;12&lt;/span&gt; 13 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;14&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;15&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;16&lt;/span&gt; 17 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;18&lt;/span&gt; 19 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;20&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;21&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;22&lt;/span&gt; 23 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;24&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;25&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;26&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;27&lt;/span&gt; &lt;span style=&quot;text-decoration: line-through;&quot;&gt;28&lt;/span&gt; 29 &lt;span style=&quot;text-decoration: line-through;&quot;&gt;30&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;И так далее, каждый раз вычёркивая все числа, кратные следующему невычеркнутому числу в списке. Все невычеркнутые числа к концу процедуры будут простыми:&lt;br /&gt;&lt;br /&gt;2 3 5 7 11 13 17 19 23 29&lt;br /&gt;&lt;br /&gt;Этот метод называется решетом, потому что он просеивает весь исходный диапазон чисел в поисках простых чисел.&lt;br /&gt;&lt;br /&gt;Решето допускает некоторые оптимизации.&lt;br /&gt;&lt;br /&gt;Во-первых, нужно рассматривать только нечётные числа, так как первый проход вычеркнет все чётные за исключением 2, которое можно рассматривать отдельно. &lt;br /&gt;&lt;br /&gt;Во-вторых, вычёркивание нужно начинать с квадрата числа, которое рассматривается в данный момент, так как все меньшие составные числа уже были вычеркнуты на предыдущих шагах; например, рассматривая 3, вычёркивание нужно начинать с 9, так как 6 было вычеркнуто, когда рассматривали 2.&lt;br /&gt;&lt;br /&gt;В третьих, процедура останавливается на квадратном корне из максимального числа, так как все простые числа, большие него уже будут вычеркнуты к этому моменту. Так, в рассмотренном выше примере не было необходимости проверять числа, большие либо равные 7, так как квадрат 7 больше 30 — наибольшего числа в списке.&lt;br /&gt;&lt;br /&gt;Напишите функцию, которая принимает один аргумент n и возвращает список простых чисел, меньших либо равных n используя оптимизированный алгоритм, описанный выше. Примените эту функцию к 15485863 и посчитайте количество полученных простых чисел. &lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Решение.&lt;/span&gt;&lt;br /&gt;Jos Koot написал следующую версию решета Эратосфена:&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;scheme&quot;&gt;&lt;br /&gt;(define (primes n)&lt;br /&gt;  (let* ((max-index (quotient (- n 3) 2))&lt;br /&gt;         (v (make-vector (+ 1 max-index) #t)))&lt;br /&gt;    (let loop ((i 0) (ps &#39;(2)))&lt;br /&gt;      (let ((p (+ i i 3)) (startj (+ (* 2 i i) (* 6 i) 3)))&lt;br /&gt;        (cond ((&amp;gt;= (* p p) n)&lt;br /&gt;               (let loop ((j i) (ps ps))&lt;br /&gt;                  (cond ((&amp;gt; j max-index) (reverse ps))&lt;br /&gt;                        ((vector-ref v j)&lt;br /&gt;                          (loop (+ j 1) (cons (+ j j 3) ps)))&lt;br /&gt;                        (else (loop (+ j 1) ps)))))&lt;br /&gt;              ((vector-ref v i)&lt;br /&gt;                (let loop ((j startj))&lt;br /&gt;                  (if (&amp;lt;= j max-index)&lt;br /&gt;                      (begin (vector-set! v j #f)&lt;br /&gt;                             (loop (+ j p)))))&lt;br /&gt;                      (loop (+ 1 i) (cons p ps)))&lt;br /&gt;              (else (loop (+ 1 i) ps)))))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Существует миллион простых числе, меньших, либо равных 15485863:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;gt; (length (primes 15485863))&lt;br /&gt;1000000&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Моё решение.&lt;/span&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;&lt;br /&gt;from math import sqrt&lt;br /&gt;&lt;br /&gt;def sieve(n):&lt;br /&gt;    l = range(3,n+1,2)&lt;br /&gt;    i = 0&lt;br /&gt;    while 2*i+3 &lt;= sqrt(n):&lt;br /&gt;        k = l[i]&lt;br /&gt;        l[(k**2-3)/2:(n-1)/2:k] = [0] * ((n-k**2+1)/(2*k)+1)&lt;br /&gt;        i += 1&lt;br /&gt;        while l[i] == 0:&lt;br /&gt;            i += 1&lt;br /&gt;    return [2] + filter(lambda x: x != 0, l)&lt;br /&gt;&lt;br /&gt;print len(sieve(15485863))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Казалось бы, использование сечений — не самый оптимальный способ присвоить значение сразу многим элементам списка, но при замене страшной строчки «l[(k**2-3)/2:(n-1)/2:k] = [0] * ((n-k**2+1)/(2*k)+1)» на цикл программ стала завершать работу не за 3.172 с, а за 5,056 с.&lt;br /&gt;&lt;br /&gt;Всего же для просеивания 15485863 числе программе потребовалось 545 итераций. Из упомянутых трёх секунд только полторы уходило на собственно просеивание. Остальное время программа отфильтровывала вычеркнутые элементы.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/3044499393359486348/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/sieve-of-eratosthenes.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3044499393359486348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3044499393359486348'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/sieve-of-eratosthenes.html' title='Решето Эратосфена / Sieve of Eratosthenes'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-8726720007189103968</id><published>2010-06-07T00:45:00.011+03:00</published><updated>2010-06-09T10:37:32.196+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Programming Praxis"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="scheme"/><title type='text'>Обратный польский калькулятор / RPN Calculator</title><content type='html'>&lt;span style=&quot;font-style:italic;font-size:75%;&quot;&gt;Дисклеймер. Хотелось бы поделиться с людьми, которые не особо знают английский, задачками с довольно интересного сайта &lt;a href=&quot;http://programmingpraxis.com/2009/02/19/rpn-calculator/&quot;&gt;Programming Praxis&lt;/a&gt;. Готовых переводов задач я не нашёл, а потому буду потихоньку сам их тут выкладывать. Задачки простые, но для того, чтобы не терять навыки программирования — самое то.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://programmingpraxis.com/2009/02/19/rpn-calculator/&quot;&gt;Programming Praxis, 19.02.2009&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Реализовать обратный польский калькулятор, принимающий выражения вида «19 2.14 + 4.5 2 4.3 / - *», которое обычно вычисляется как «(19 + 2.14) * (4.5 - 2 / 4.3)» и соответствует 85.2974. Программа должна читать выражение со стандартного входа и выводить вершину стека с символом конца строки в стандартный вывод. Программа должна сохранять состояние стека операндов между выражениями.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Решение.&lt;/span&gt;&lt;br /&gt;Единственная сложность заключается в обработке новой строки, которая в Scheme трактуется как пробел. Функция (op token) преобразует знак, из символа, полученного со входа, в оператор, который может быть использован для вычислений. Формат первой строки программы специфичен для Chez Scheme, но большинство реализаций Scheme предоставляют что-то подобное.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;lisp&quot;&gt;&lt;br /&gt;#! /usr/bin/scheme –script&lt;br /&gt;(define (next)&lt;br /&gt;  (cond ((eof-object? (peek-char)) (exit))&lt;br /&gt;        ((char=? (peek-char) #\space) (read-char) (next))&lt;br /&gt;        ((char=? (peek-char) #\newline) (read-char) ‘nl)&lt;br /&gt;        (else (read))))&lt;br /&gt;&lt;br /&gt;(define (op token) (case token ((+) +) ((-) -) ((*) *) ((/) /)))&lt;br /&gt;&lt;br /&gt;(let rpn ((token (next)) (stack ‘()))&lt;br /&gt;  (cond ((eq? ‘nl token) (display (car stack)) (newline) (rpn (next) (cdr stack)))&lt;br /&gt;        ((number? token) (rpn (next) (cons token stack)))&lt;br /&gt;        (else (rpn (next) (cons ((op token) (cadr stack) (car stack)) (cddr stack))))))&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Моё решение.&lt;/span&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;python&quot;&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;#-*- coding:utf-8 -*-&lt;br /&gt;&lt;br /&gt;from sys import stdin, stdout&lt;br /&gt;&lt;br /&gt;def calc():&lt;br /&gt;    stack = []&lt;br /&gt;    result = None&lt;br /&gt;    while True:&lt;br /&gt;        line = yield result&lt;br /&gt;        for token in line.split():&lt;br /&gt;            try:&lt;br /&gt;                number = float(token)&lt;br /&gt;                stack[:0] = [number]&lt;br /&gt;                result = number&lt;br /&gt;            except ValueError:&lt;br /&gt;                try:&lt;br /&gt;                    result = {&lt;br /&gt;                        &#39;+&#39;: lambda x, y: x + y,&lt;br /&gt;                        &#39;-&#39;: lambda x, y: x - y,&lt;br /&gt;                        &#39;*&#39;: lambda x, y: x * y,&lt;br /&gt;                        &#39;/&#39;: lambda x, y: x / y&lt;br /&gt;                    }[token](stack[1], stack[0])&lt;br /&gt;                    stack[0:2] = [result]&lt;br /&gt;                except IndexError:&lt;br /&gt;                    raise ValueError, &#39;Stack is empty&#39;&lt;br /&gt;                except KeyError:&lt;br /&gt;                    raise ValueError, &#39;Unknown operation&#39;&lt;br /&gt;c = calc()&lt;br /&gt;c.next()&lt;br /&gt;&lt;br /&gt;for line in stdin.xreadlines():&lt;br /&gt;    print &amp;gt;&amp;gt; stdout, c.send(line)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Тут есть несколько необычных для новичка моментов.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;line = yield result&lt;/pre&gt; — это «вывернутый наизнанку» вызов функции, который позволяет разбить цикл обработки на две части: работу со стеком и получение строк со стандартного ввода. Команда yield возвращает значение подобно return, но функция при этом не завершается и будет продолжена при вызове метода send снаружи. причём, аргумент send будет передан через yield внутрь функции. Звучит запутанно, но &lt;a href=&quot;http://www.ibm.com/developerworks/ru/library/l-pycon/index.html&quot;&gt;генераторы&lt;/a&gt; — это действительно очень мощная и гибкая штука.&lt;br /&gt;&lt;br /&gt;Другая необычность — использование индексирования словаря. Это позволяет ввести конструкцию, аналогичную, например, switch в C, без использования if—elif. Так код выглядит чище, хотя, конечно, тратятся ресурсы на создание анонимного словаря и поиск ключа в нём.&lt;br /&gt;&lt;br /&gt;Странные индексы списка stack с двоеточиями — это сечения (slices). Тоже довольно удобная штука. Они есть также в MatLab и Fortran, где без них программирование заметно усложнилось бы.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/8726720007189103968/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/rpn-calculator.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/8726720007189103968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/8726720007189103968'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2010/06/rpn-calculator.html' title='Обратный польский калькулятор / RPN Calculator'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-1365350861693218235</id><published>2009-11-05T19:29:00.012+02:00</published><updated>2009-11-06T01:03:06.137+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Как сделать deb-пакет со своими скриптами</title><content type='html'>Рано или поздно у продвинутого пользователя линукса накапливается набор собственных скриптов, хранящихся где-то в «~/bin». Но каталог с программами не так красиво смотрится в домашнем каталоге, да и потом если делиться с друзьями, то приходится отправлять в архиве, говорить куда что копировать, убеждать их, что загромождение домашнего каталога — неизбежное зло. Можно, конечно и куда-то в «/usr/local/bin» их поместить, но можно потратить десять минут и собрать пакет, который потом легко устанавливается (и удаляется) штатными средствами. Причём туда, куда надо.&lt;br /&gt;&lt;br /&gt;Посмотрим, как это делается.&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;В качестве примера скриптов возьмем, например следующие два.&lt;br /&gt;&lt;br /&gt;Первый загружает цитаты с &lt;a href=&quot;http://lorquotes.ru&quot;&gt;lorquotes.ru&lt;/a&gt;.&lt;br /&gt;&lt;pre name=&#39;code&#39; class=&#39;bash&#39;&gt;#!/bin/sh&lt;br /&gt;[ -x ~/.lor ] || mkdir ~/.lor&lt;br /&gt;wget http://lorquotes.ru/fortraw.php -O -| iconv -f koi8-r -o ~/.lor/lor&lt;br /&gt;strfile ~/.lor/lor ~/.lor/lor.dat&lt;br /&gt;&lt;/pre&gt;А второй — выводит и при помощи утилиты fortune.&lt;br /&gt;&lt;pre name=&#39;code&#39; class=&#39;bash&#39;&gt;#!/bin/sh&lt;br /&gt;fortune ~/.lor&lt;/pre&gt;Назовем их соответственно «lor-update» и «lor».&lt;br /&gt;&lt;br /&gt;Сохраним их в отдельный каталог, который при сборке пакета должен иметь имя вида «пакет-версия». В нашем случае это будет «lorquotes-0.1».&lt;br /&gt;&lt;br /&gt;Теперь создадим заготовку пакета при помощи команды dh_make (есть в репозитории под именем — сюрприз! — «dh-make»). Для этого в нашем каталоге выполним следующую команду:&lt;br /&gt;&lt;pre&gt;dh_make --createorig -c gpl3 -e user@example.com -i -p lorquotes_0.1&lt;/pre&gt;Довольно длинно, не так ли? Разберём по порядку:&lt;br /&gt;--createorig — создать отдельную папку с исходниками, это будет нужно при создании пакета;&lt;br /&gt;-c gpl3 — указать в качестве лицензии GPL3 (какие ещё есть лицензии ,можно посмотреть в man-страничке утилиты dh_make);&lt;br /&gt;-e user@example.com — электронная почта собравшего пакет (то есть ваш);&lt;br /&gt;-i — говорим, что пакет не зависит от платформы (bash-скрипты везде одинаковы ведь);&lt;br /&gt;-p lorquotes_0.1 — указываем имя пакета (вообще, необязательно).&lt;br /&gt;&lt;br /&gt;Утилита спросит, всё ли она правильно поняла, на что мы честно соглашаемся и заходим в папку.&lt;br /&gt;&lt;br /&gt;Как видим, старое содержимое скопировалось в каталог «lorquotes-0.1.orig» (спасибо опции --createorig), а в «lorquotes-0.1» появился каталог «debian» с кучей файликов непонятного назначения. Собственно, содержимое этого каталога и определяет как будет вести себя пакет при установке и что он будет содержать.&lt;br /&gt;&lt;br /&gt;Но сперва нужно создать мейкфайл. Это специальный файл, имеющий имя Makefile и говорящий сборщику пакета, как скомпилировать исходнуе тексты и куда устанавливать его содержимое. Структура нашего мейкфайла очень проста:&lt;br /&gt;&lt;pre&gt;DESTDIR =&lt;br /&gt;BIN = $(DESTDIR)/usr/bin&lt;br /&gt;&lt;br /&gt;build:&lt;br /&gt; true&lt;br /&gt;&lt;br /&gt;install:&lt;br /&gt; install -d $(BIN)&lt;br /&gt; install -m755 lor $(BIN)&lt;br /&gt; install -m755 lor-update $(BIN)&lt;/pre&gt;Заметьте, что некоторые строки набраны с отступом при помощи табуляции. Именно так и нужно набирать. Это важно!&lt;br /&gt;&lt;br /&gt;Мейкфайл — это просто предписание команде «make» выполнить определенный набор действий.&lt;br /&gt;&lt;br /&gt;В строке 1 определены специальные переменные: DESTDIR — каталог, в который будет устанавливаться наш пакет. Эта переменная обязательно должна быть в мейкфайле, так как черех неё потом сборщик пакета указывает каталог назначения.&lt;br /&gt;&lt;br /&gt;В строке 2 указан каталог, куда будут установлены наши скрипты. Без этой переменной уже можно было обойтись, так как она пользовательская и введена для удобства.&lt;br /&gt;&lt;br /&gt;Строка с «build» — это одна из целей, которых должен достичь make. После двоеточия можно было указать список целей, от которых цель «build» зависит, но у нас и компилировать-то нечего, потому ничего и не указано. После цели идут команды (внимание, с отступом!), которые необходимо выполнить для достижения этой цели. Так как ничего выполнять не надо, то там стоит команда true, которая ничего не делает (такая у неё работа).&lt;br /&gt;&lt;br /&gt;Аналогично описана цель «install». Но тут уже нужны действия: а именно создание каталога назначения и копирование в него с соответствующими правами наших скриптов. Вместо обычных команд создания и копирования используется утилита install, которая более интеллектуальна и специально для этих целей предназначена.&lt;br /&gt;&lt;br /&gt;Итак, создаем в папке со скриптами (не в debian) мейкфайл под именем Makefile. Теперь мы можем при помощи команд «make» (ничего не делает, т.к выполнится первая цель в файле, т.е. «build») и «sudo make install» (копирует скрипты куда надо) собрать и установить вручную наши скрипты. Но вручную нам не нужно, мы ведь пакет хотим собрать. Поэтому переходим к следующему этапу.&lt;br /&gt;&lt;br /&gt;Настроим свойства нашего пакета. Перейдём в каталог «debian» и откроем файл «control». Он содержит информацию о пакете, его зависимостях и так далее. Заполним его как анкету.&lt;br /&gt;&lt;br /&gt;Source — название того, что мы сейчас собираем,&lt;br /&gt;Section — в какую секцию дерева репозитория поместить наш пакет,&lt;br /&gt;Priority — важность пакета,&lt;br /&gt;Maintainer — сборщик,&lt;br /&gt;Build-Depends — какие программы нужны для сборки пакета,&lt;br /&gt;Standards-Version — версия стандарта, описывающего сборку пакетов,&lt;br /&gt;Homepage — домашняя страничка (если есть),&lt;br /&gt;Package — имя собственно deb-пакета,&lt;br /&gt;Architecture — архитектура, под которую он собирается (i386, amd64 и иже с ними),&lt;br /&gt;Depends — от каких пакетом наш зависит,&lt;br /&gt;Description — описание, короткое в той же строке и длинное ниже (обратите внимание на пробел в начале строки с длинным описанием).&lt;br /&gt;&lt;br /&gt;Я для примера сделал такой файл:&lt;br /&gt;&lt;pre&gt;Source: lorquotes&lt;br /&gt;Section: misc&lt;br /&gt;Priority: optional&lt;br /&gt;Maintainer: Vasiliy Pupkin &lt;vasiliy@example.com&gt;&lt;br /&gt;Build-Depends: debhelper (&gt;= 7)&lt;br /&gt;Standards-Version: 3.8.3&lt;br /&gt;Homepage: http://pupkin.example.com/lorquotes/&lt;br /&gt;&lt;br /&gt;Package: lorquotes&lt;br /&gt;Architecture: all&lt;br /&gt;Depends: wget,fortunes&lt;br /&gt;Description: Small LOR quotes utility&lt;br /&gt; Shows you random quote from lorquotes.ru.&lt;/pre&gt;Думаю, указывать в зависимостях шелл и libc6 смысла нет. Они точно есть в любой системе (или нет?).&lt;br /&gt;&lt;br /&gt;Теперь подправим файл «changelog». Он содержит историю версия нашего пакета. Во время правки не забывайте, что он тоже имеет строгий формат и не добавляйте лишние отступы и строки.&lt;br /&gt;&lt;br /&gt;Вот мой вариант:&lt;br /&gt;&lt;pre&gt;lorquotes (0.1-1) unstable; urgency=low&lt;br /&gt;&lt;br /&gt;  * Initial release&lt;br /&gt;&lt;br /&gt; -- Vasiliy Pupkin &lt;vasiliy@example.com&gt;  Thu, 05 Nov 2009 19:53:58 +0200&lt;/pre&gt;unstable — это имя ветки дистрибутива, для которой готовится пакет, а urgency — это приоритет.&lt;br /&gt;&lt;br /&gt;В том же каталоге есть файл «rules». Это обычный мекфайл, который и отвечает за конфигурирование и сборку пакета. Но так как мы ничего экстраординарного не делали, оставим всё как есть.&lt;br /&gt;&lt;br /&gt;В файле «copyright» находится лицензия. Мы лицензию сразу указали, так что и этот файл трогать не будем.&lt;br /&gt;&lt;br /&gt;Итак, остались ещё следующие важные для нас файлы.&lt;br /&gt;&lt;br /&gt;«cron.d.ex». Переименовываем его в «cron.d». Он содержит информацию о регулярных действиях, которые будет выполнять установленная программа. В нашем случае — ежедневное обновление базы цитат в полдень:&lt;pre&gt;#&lt;br /&gt;# Regular cron jobs for the lorquotes package&lt;br /&gt;#&lt;br /&gt;0 12 * * * root [ -x /usr/bin/lor-update ] &amp;&amp; /usr/bin/lor-update&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;«postrm.ez». Переименовываем в «postrm». Это скрипт, запускаемый после удаления пакета. Заставим его очищать нашу базу цитат, хранящуюся в «~/.lor». Хотя хранить базу в домашнем каталоге не совсем верно идеологически. Но, думаю, после этого поста читатель и сам исправит эту неточность. Итак, мой «postrm»:&lt;pre&gt;#!/bin/sh&lt;br /&gt;# postrm script for lorquotes&lt;br /&gt;#&lt;br /&gt;# see: dh_installdeb(1)&lt;br /&gt;&lt;br /&gt;set -e&lt;br /&gt;&lt;br /&gt;case &quot;$1&quot; in&lt;br /&gt;    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)&lt;br /&gt;    rm -rf ~/.lor&lt;br /&gt;    ;;&lt;br /&gt;&lt;br /&gt;    *)&lt;br /&gt;        echo &quot;postrm called with unknown argument \`$1&#39;&quot; &gt;&amp;2&lt;br /&gt;        exit 1&lt;br /&gt;    ;;&lt;br /&gt;esac&lt;br /&gt;&lt;br /&gt;# dh_installdeb will replace this with shell code automatically&lt;br /&gt;# generated by other debhelper scripts.&lt;br /&gt;&lt;br /&gt;#DEBHELPER#&lt;br /&gt;&lt;br /&gt;exit 0&lt;/pre&gt;Остальные файлы нам не нужны и смело их удаляем. Это разные заготовки. Например, для man-страниц.&lt;br /&gt;&lt;br /&gt;Переходим теперь в каталог со скриптами (т.е. на уровень выше) и даём команду на сбору пакета:&lt;br /&gt;&lt;pre&gt;debuild&lt;/pre&gt;Она собирает пакет, проверяет на ошибки, а потом пробует его подписать вашим GPG-ключом. Но даже если ей подписать не удастся, пакет будет собран. Найти его можно будет в каталоге уровнем выше. Там же будет архив с исходниками и вспомогательные файлы, нужные, если вы хотите создать свой репозиторий или загрузить пакет в уже существующий.&lt;br /&gt;&lt;br /&gt;Конечно, при сборке пакета будут предупреждения. Но мы ведь не закачивать его в дебиановский репозиторий будем, а для себя собираем. Так что устранение причин предупреждений остаётся в качестве домашнего задания читателю. (Кстати, это несложно.)&lt;br /&gt;&lt;br /&gt;Вот и всё! Осталось только установить пакет. :)&lt;br /&gt;&lt;br /&gt;Как видите, ничего сложного. Если интересуют подробности или захотелось собрать пакет позаковыристее, милости просим на &lt;a href=&quot;http://www.debian.org/doc/manuals/maint-guide/index.ru.html&quot;&gt;соответствующую страничку&lt;/a&gt; дебиановской документации.&lt;br /&gt;&lt;br /&gt;А вот &lt;a href=&quot;http://narod.ru/disk/14807417000/lorquotes_0.1.zip.html&quot;&gt;архив&lt;/a&gt; с исходниками и пакетом.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/1365350861693218235/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/deb.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/1365350861693218235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/1365350861693218235'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/deb.html' title='Как сделать deb-пакет со своими скриптами'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-3151807369865007716</id><published>2009-11-02T12:05:00.006+02:00</published><updated>2009-11-02T19:11:45.260+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="сеть"/><title type='text'>Отправка email из командной строки</title><content type='html'>О том &lt;a href=&quot;http://strange-to-say.blogspot.com/2009/11/jabber.html&quot;&gt;как отправлять сообщения через jabber&lt;/a&gt;, я уже написал. А вот сегодня мне захотелось написать утилитку, которая бы делала то же самое и с теми же (примерно) параметрами командной строки, но для электронной почты. Конечно, в линуксе полно консольных почтовых программ (я в курсе, что есть команда mail), но мне не нужны все их возможности, а кроме того, хотелось бы ещё и кроссплатформенности (я в курсе, что в Windows есть утилита blat) и возможности быстро самому что-то дописать. Вот, что получилось. &lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;Не буду тянуть, сразу приведу код скрипта.&lt;br /&gt;&lt;pre  name=&#39;code&#39; class=&#39;python&#39;&gt;#!/usr/bin/env python&lt;br /&gt;import smtplib, ConfigParser, email.mime.text, getopt, os, sys, locale&lt;br /&gt;&lt;br /&gt;name = os.path.basename(sys.argv[0])&lt;br /&gt;&lt;br /&gt;optlist, args = getopt.getopt(sys.argv[1:], &#39;s:f:&#39;)&lt;br /&gt;if len(args) &lt; 2:&lt;br /&gt;    print &quot;Send a message via email&quot;&lt;br /&gt;    print&lt;br /&gt;    print &quot;Syntax:&quot;, name, &quot;[-f from] [-s subject] email text&quot;&lt;br /&gt;    print &quot;email\trecipient&#39;s e-mail address&quot;&lt;br /&gt;    print &quot;from\tsender&#39;s email&quot;&lt;br /&gt;    print &quot;subject\tmessage subject&quot;&lt;br /&gt;    print &quot;text\tmessage, use &#39;-&#39; for stdin&quot;&lt;br /&gt;    sys.exit(0)&lt;br /&gt;&lt;br /&gt;configFile = os.path.join(os.environ[&#39;HOME&#39;], &#39;.&#39; + name)&lt;br /&gt;config = ConfigParser.RawConfigParser()&lt;br /&gt;try:&lt;br /&gt;    config.read(configFile)&lt;br /&gt;    fromEmail = config.get(&#39;From&#39;, &#39;E-mail&#39;)&lt;br /&gt;    smtpServer = config.get(&#39;SMTP&#39;, &#39;Server&#39;)&lt;br /&gt;    smtpLogin = config.get(&#39;SMTP&#39;, &#39;Login&#39;)&lt;br /&gt;    smtpPassword = config.get(&#39;SMTP&#39;, &#39;Password&#39;)&lt;br /&gt;except:&lt;br /&gt;    print &quot;Default configuration was written to&quot;, configFile&lt;br /&gt;    config.add_section(&#39;From&#39;)&lt;br /&gt;    config.set(&#39;From&#39;, &#39;E-mail&#39;, &#39;user@example.com&#39;)&lt;br /&gt;    config.add_section(&#39;SMTP&#39;)&lt;br /&gt;    config.set(&#39;SMTP&#39;, &#39;Server&#39;, &#39;smtp.example.com&#39;)&lt;br /&gt;    config.set(&#39;SMTP&#39;, &#39;Login&#39;, &#39;user&#39;)&lt;br /&gt;    config.set(&#39;SMTP&#39;, &#39;Password&#39;, &#39;********&#39;)&lt;br /&gt;    f = file(configFile, &#39;w&#39;)&lt;br /&gt;    config.write(f)&lt;br /&gt;    f.close()&lt;br /&gt;    sys.exit(0)&lt;br /&gt;&lt;br /&gt;toEmail = args[0]&lt;br /&gt;subject = &#39;&#39;&lt;br /&gt;for option, value in optlist:&lt;br /&gt;    if option == &#39;-s&#39;:&lt;br /&gt;        subject = value&lt;br /&gt;    elif option == &#39;-f&#39;:&lt;br /&gt;        fromEmail = value&lt;br /&gt;&lt;br /&gt;encoding = locale.getpreferredencoding()&lt;br /&gt;if args[1] == &#39;-&#39;:&lt;br /&gt;    message = email.mime.text.MIMEText(sys.stdin.read(), &#39;plain&#39;, encoding)&lt;br /&gt;else:&lt;br /&gt;    message = email.mime.text.MIMEText(&#39; &#39;.join(args[1:]), &#39;plain&#39;, encoding)&lt;br /&gt;&lt;br /&gt;message[&#39;Subject&#39;] = subject&lt;br /&gt;message[&#39;From&#39;] = fromEmail&lt;br /&gt;message[&#39;To&#39;] = toEmail&lt;br /&gt;&lt;br /&gt;server = smtplib.SMTP(smtpServer)&lt;br /&gt;server.login(smtpLogin, smtpPassword)&lt;br /&gt;server.sendmail(message[&#39;From&#39;], message[&#39;To&#39;], message.as_string())&lt;br /&gt;server.quit()&lt;/pre&gt;Всё это сохраняем в файл с именем, например, «mailto» и даём права на выполнение:&lt;br /&gt;&lt;pre&gt;chmod +x mailto&lt;/pre&gt;После первого создаётся файл с настройками подключения. По умолчанию это файл «.mailto» (если скрипт называется «mailto», конечно) в домашнем каталоге. В нём нужно указать адрес отправителя и настройки smtp-сервера.&lt;br /&gt;&lt;br /&gt;Параметров у скрипта минимум, только то, что нужно. Есть два опциональных для указания темы сообщения и адреса отправителя (по умолчанию берётся из файла с настройками). Для них используются ключи «-s» и «-f» соответственно (от слов «From» и «Subject»).&lt;br /&gt;&lt;br /&gt;Обязательных параметров всего два и они без ключей. Это адрес получателя собственно текст сообщения. Если вместо текста поставить «-», то текст будет браться из стандартного входа, что удобно для отправки результатов вывода какой-то программы.&lt;br /&gt;&lt;br /&gt;Использовать программу можно для чего угодно. Например, чтобы отправить список пользователей себе на ящик можно воспользоваться командой:&lt;br /&gt;&lt;pre&gt;who | mailto user@example.com -&lt;/pre&gt;Я, например, использую этот скрипт, чтобы автоматически в определённое время слать себе СМС с напоминанием о чём-либо через гейт «email—SMS» моего мобильного оператора. Получилось удобно.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/3151807369865007716/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/email.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3151807369865007716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3151807369865007716'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/email.html' title='Отправка email из командной строки'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-7675900553010352787</id><published>2009-11-01T00:44:00.016+02:00</published><updated>2009-11-03T01:06:14.874+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jabber"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="консоль"/><category scheme="http://www.blogger.com/atom/ns#" term="сеть"/><title type='text'>Отправка jabber-сообщений из командной строки</title><content type='html'>О том, как отправить jabber-сообщение из консоли при помощи клиента Gajim, я уже писал &lt;a href=&quot;http://strange-to-say.blogspot.com/2009/07/gajim.html&quot;&gt;ранее&lt;/a&gt;. Тем не менее, использование gajim-remote имеет ряд недостатков: нужно установить сам Gajim и запустить его. Это может вызвать некоторые затруднения, например, на сервере, где вовсе может не быть графического интерфейса. Однако, проблема имеет и более простое решение.&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;Сделаем скрипт, которому бы в качестве параметров передавались данные учётной записи jabber, JID отправителя и текст сообщения. В качестве основы возьмём питоновскую библиотеку &lt;a href=&quot;http://xmpppy.sourceforge.net/&quot;&gt;xmpppy&lt;/a&gt;. В частности, рассмотрим повнимательнее один из примеров, входящих в её комплект, который (сюрприз!) как раз и предназначен для отправки сообщений из консоли. Остаётся только его чуть-чуть «допилить» по вкусу.&lt;br /&gt;&lt;br /&gt;Итак, нам потребуется библиотека. Они есть в репозиториях Debian (да и других популярных дистрибутивов), поэтому устанавливаем как обычно:&lt;br /&gt;&lt;pre&gt;sudo aptitude install python-xmpp python-dnspython&lt;/pre&gt;Без python-dnspython работать тоже будет, кстати. Но лучше поставить, так как в этом случае придётся вводить точное имя узла, на котором располагается сервер.&lt;br /&gt;&lt;br /&gt;А вот и сам скрипт:&lt;br /&gt;&lt;pre name=&#39;code&#39; class=&#39;python&#39;&gt;#!/usr/bin/env python&lt;br /&gt;import sys,os,xmpp,time,ConfigParser&lt;br /&gt;&lt;br /&gt;name = os.path.basename(sys.argv[0])&lt;br /&gt;&lt;br /&gt;if len(sys.argv) &lt; 2:&lt;br /&gt;    print &quot;Send a message via Jabber (XMPP)&quot;&lt;br /&gt;    print &quot;Syntax:&quot;, name, &quot;JID text&quot;&lt;br /&gt;    print &quot;JID\trecipient&#39;s Jabber ID&quot;&lt;br /&gt;    print &quot;text\tmessage, use &#39;-&#39; for stdin&quot;&lt;br /&gt;    sys.exit(0)&lt;br /&gt;&lt;br /&gt;toJID = sys.argv[1]&lt;br /&gt;if sys.argv[2] == &#39;-&#39;:&lt;br /&gt;    text = sys.stdin.read()&lt;br /&gt;else:&lt;br /&gt;    text = &#39; &#39;.join(sys.argv[2:])&lt;br /&gt;&lt;br /&gt;configFile = os.path.join(os.environ[&#39;HOME&#39;], &#39;.&#39; + name)&lt;br /&gt;config = ConfigParser.RawConfigParser()&lt;br /&gt;&lt;br /&gt;try:&lt;br /&gt;    config.read(configFile)&lt;br /&gt;    fromJID = config.get(&#39;Connection&#39;, &#39;JID&#39;)&lt;br /&gt;    password = config.get(&#39;Connection&#39;, &#39;Password&#39;)&lt;br /&gt;except:&lt;br /&gt;    print &quot;Default configuration was written to&quot;, configFile&lt;br /&gt;    config.add_section(&#39;Connection&#39;)&lt;br /&gt;    config.set(&#39;Connection&#39;, &#39;JID&#39;, &#39;user@example.com/home&#39;)&lt;br /&gt;    config.set(&#39;Connection&#39;, &#39;Password&#39;, &#39;********&#39;)&lt;br /&gt;    f = file(configFile, &#39;w&#39;)&lt;br /&gt;    config.write(f)&lt;br /&gt;    f.close()&lt;br /&gt;    sys.exit(0)&lt;br /&gt;&lt;br /&gt;fromJID = xmpp.protocol.JID(fromJID)&lt;br /&gt;client = xmpp.Client(fromJID.getDomain(),debug=[])&lt;br /&gt;&lt;br /&gt;conn = client.connect()&lt;br /&gt;if not conn:&lt;br /&gt;    print &#39;Could not connect!&#39;&lt;br /&gt;    sys.exit(1)&lt;br /&gt;print &#39;Connected with&#39;, conn&lt;br /&gt;&lt;br /&gt;auth = client.auth(fromJID.getNode(), password, resource=fromJID.getResource())&lt;br /&gt;if not auth:&lt;br /&gt;    print &#39;Could not authenticate!&#39;&lt;br /&gt;    sys.exit(1)&lt;br /&gt;print &#39;Authenticated using&#39;, auth&lt;br /&gt;&lt;br /&gt;messageID = client.send(xmpp.protocol.Message(toJID, text))&lt;br /&gt;print &#39;Message was sent&#39;&lt;br /&gt;&lt;br /&gt;time.sleep(1)&lt;br /&gt;client.disconnect()&lt;br /&gt;&lt;/pre&gt;Скрипт довольно простой, так что разбирать его работу не буду.&lt;br /&gt;&lt;br /&gt;Всё это сохраняем в каталог «~/bin» под именем, например, «jsend». Имя и каталог значения не имеют, просто «~/bin» удобен для хранения пользовательских скриптов, так как он входит в переменную PATH и для запуска скритов из него достаточно указать их имена. В любом случае нужно разрешить выполнение нашей программки:&lt;br /&gt;&lt;pre&gt;chmod +x jsend&lt;/pre&gt;Рассмотрим её работу. После первого запуска утилита создаёт в домашнем каталоге файл с JID и паролем отправителя. Это удобнее, чем вводить пароль в качестве параметра командной строки, так как в этом случае никто не сможет его подсмотреть. Да и доступ к файлу можно будет закрыть. Файл поличит имя, совпадающее с именем скрипта, но с точкой впереди, чтобы не отображаться лишний раз в списке файлов. В моём случае имя будет «~/.jsend». Естественно, файл после первого запуска нужно будет открыть и впесать свои JID и пароль.&lt;br /&gt;&lt;br /&gt;Формат запуска скрипта:&lt;br /&gt;&lt;pre&gt;jsend JID text&lt;/pre&gt;JID — это идентификатор получателя сообщения, а text — это собственно текст, который нужно отправить.&lt;br /&gt;&lt;br /&gt;Если текста много или нужно отправить вывод какой-либо команды, то вместо text можно поставить «-». Например, команда&lt;br /&gt;&lt;pre&gt;df | jsend user@example.com -&lt;/pre&gt;отправит информацию о заполненности разделов на дисках пользователю user@example.com.&lt;br /&gt;&lt;br /&gt;Также можно настроить отправку сообщений в определённое время при помощи команды at, что тоже иногда оказывается удобным.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/7675900553010352787/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/jabber.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7675900553010352787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7675900553010352787'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/11/jabber.html' title='Отправка jabber-сообщений из командной строки'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-8426104388925106253</id><published>2009-10-27T21:16:00.013+02:00</published><updated>2010-06-14T18:10:52.314+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="звук"/><title type='text'>Разрезаем lossless-аудио (ape, flac, wv, wav) по файлу cue</title><content type='html'>Понимаю, что теме этого поста наверняка написано огромное количество статей, мануалов и прочих ЧаВо. Но каждый раз искать лень, проще один раз сделать узелок на память в блоге.&lt;br /&gt;&lt;br /&gt;(Это перевод англоязычной заметки. См. также &lt;a href=&quot;http://strange-to-say.blogspot.com/2010/06/lossless-ape-flac-wv-wav-cue.html&quot;&gt;описание более простого способа&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Итак, задача такова: дана пара файлов, предположим sample.cue и sample.flac, с каким-либо альбомом. Требуется получить треки альбома в отдельных flac-файлах.Если у вас linux, то делается это в два счёта. Ниже следует перевод одной довольно неплохой статьи с решением проблемы.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;Файлы с lossless-аудио могут быть разрезаны по cue-файлу при помощи утилиты «shnsplit» (входит в пакет «shntool»). Также потребуется утилита «cuebreakpoints» (из пакета «cuetools»). Чтобы установить их, откройте терминал и введите следующее (&lt;span style=&quot;font-style:italic;&quot;&gt;эти пакеты есть в Ubuntu и Debian&lt;/span&gt;):&lt;br /&gt;&lt;pre&gt;sudo apt-get install cuetools shntool&lt;/pre&gt;&lt;br /&gt;Кроме этого потребуются приложения для работы с выбранным форматом. Для Monkey’s Audio нужна будет утилита «mac» (&lt;span style=&quot;font-style:italic;&quot;&gt;в Debian есть пакет «monkeys-audio»&lt;/span&gt;). Для FLAC и WavePack потребуется установить соответственно «flac» и «wavpack»:&lt;br /&gt;&lt;pre&gt;sudo apt-get install flac wavpack&lt;/pre&gt;&lt;br /&gt;Утилите shnsplit требуется для работы список точек, в которых нужно делить звуковой файл. Очень кстати тут оказывается утилита cuebreakpoints, которая печатает список таких точек по cue- или toc-файлу в формате, используемом в shnsplit. Можно создать конвейер между cuebreakpoints и shnsplit следующим образом:&lt;br /&gt;&lt;pre&gt;cuebreakpoints sample.cue | shnsplit -o flac sample.flac&lt;/pre&gt;&lt;br /&gt;В этом примере flac-файл с именем «sample.flac» разрезается по точкам, содержащимся в «sample.cue» и результат выводится в формате FLAC.&lt;br /&gt;&lt;br /&gt;Выходной формат задаётся параметром «-o». Если не указать формат, то файлы будут сохрняться в формате по умолчанию, то есть в виде wav-файлов.&lt;br /&gt;&lt;br /&gt;Чтобы разрезать файл в формате Monkey’s Audio и сохраниеть результаты в формате FLAC, нужно выполнить следующую команду:&lt;br /&gt;&lt;pre&gt;cuebreakpoints sample.cue | shnsplit -o flac sample.ape&lt;/pre&gt;&lt;br /&gt;По умолчанию для выходных файлов используется префикс «split-track» (то есть по умолчанию файлы будут иметь имена: split-track01, split-track02, split-track03,…). Можно задать собственный префикс при помощи опции «-a».&lt;br /&gt;&lt;br /&gt;Чтобы посмотреть список всех параметров наберите «shntool split -h» или «shnsplit -h».&lt;br /&gt;&lt;br /&gt;В звуковые файлах, полученных с помощью shnsplit не будут записаны данные об исполнителе, альбоме и так далее. Однако, можно воспользоваться скриптом cuetag (также входящим в пакет cuetools) для того, чтобы перенести данные из cue-файла в отдельные дорожки. Можно указать отдельные файлы, соответствующие дорожкам, содержащимся в cue-файле:&lt;br /&gt;&lt;pre&gt;cuetag sample.cue split-track01.flac split-track02.flac split-track03.flac split-track04.flac&lt;/pre&gt;&lt;br /&gt;Эта команда перенесёт теги, содержащиеся в файле «sample.cue» в файлы с дорожками: «split-track01.flac», «split-track02.flac», «split-track03.flac» and «split-track04.flac».&lt;br /&gt;Можно записать теги сразу во все полученные файлы:&lt;br /&gt;&lt;pre&gt;cuetag sample.cue split-track*.flac&lt;/pre&gt;&lt;br /&gt;Утилита cuetag работает с форматами FLAC, Ogg и mp3.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://aidanjm.wordpress.com/2007/02/15/split-lossless-audio-ape-flac-wv-wav-by-cue-file/&quot;&gt;Источник&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/8426104388925106253/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/10/lossless-ape-flac-wv-wav-cue.html#comment-form' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/8426104388925106253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/8426104388925106253'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/10/lossless-ape-flac-wv-wav-cue.html' title='Разрезаем lossless-аудио (ape, flac, wv, wav) по файлу cue'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-6648849086084415891</id><published>2009-07-27T20:45:00.005+03:00</published><updated>2009-07-27T21:54:52.590+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="jabber"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>Управляем Gajim из командной строки</title><content type='html'>Gajim — это популярный и активно развивающийся Jabber-клиент, написанный на Python. К слову, он обладает очень неплохой поддержкой всевозможных вкусностей и полезностей Jabber по сравнению со многими другими клиентами. Одной из таких полезностей является возможность управления им из командной строки при помощи &lt;a href=&quot;http://ru.wikipedia.org/wiki/D-Bus&quot;&gt;D-Bus&lt;/a&gt; — системы межпроцессного взаимодействия.&lt;br /&gt;&lt;br /&gt;Управление из командной строки не означает, что Gajim имеет консольный интерфейс. Он по-прежнему будет располагаться на рабочем столе в виде окошка. Просто из консоли можно будет отправлять ему какие-либо команды. Собственно, команд поддерживается немного, но для каких-то простейших действий должно хватить.&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;В состав пакета с Gajim входит консольная утилитка gajim-remote, которая как раз и предназначена для отправки команд основной программе. Если вызвать её без параметров, она покажет список поддерживаемых действий. Вот наиболее интересные:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;check_gajim_running — проверить, запущен ли Gajim (результат — True или False),&lt;/li&gt;&lt;li&gt;list_accounts — список учётных записей,&lt;/li&gt;&lt;li&gt;list_contacts [учётные записи] — список контактов в учётных записях,&lt;/li&gt;&lt;li&gt;contact_info &amp;lt;jid&amp;gt; — информация о пользователе с указанным JID,&lt;/li&gt;&lt;li&gt;account_info &lt;учётная запись&gt; — показать информацию об одной из учётных записей Gajim,&lt;/li&gt;&lt;li&gt; add_contact &amp;lt;jid&amp;gt; [учётные записи] — добавить контакт в ростер,&lt;/li&gt;&lt;li&gt;remove_contact &amp;lt;jid&amp;gt; [учётные записи] — удалить учётную запись из ростера,&lt;/li&gt;&lt;li&gt;change_status &amp;lt;статус&amp;gt; [сообщение] [учётные записи] — изменить статус с возможностью указания сообщения и учётной записи (если не указать — будет изменен статус всех учётных записей),&lt;/li&gt;&lt;li&gt;get_status [учётные записи] — получить статус указанных учётных записей,&lt;/li&gt;&lt;li&gt;get_status_message [учётные записи] — получить сообщение статуса указанных учётных записей,&lt;/li&gt;&lt;li&gt;get_unread_msgs_number — количество непрочитанных сообщений,&lt;/li&gt;&lt;li&gt;handle_uri &amp;lt;uri&amp;gt; [учётные записи] — обработать ссылку вида «xmpp://»,&lt;/li&gt;&lt;li&gt;join_room &lt;комната&gt; [ник] [пароль:] [учётные записи] — присоединиться к конференции,&lt;/li&gt;&lt;li&gt;send_chat_message &amp;lt;jid&amp;gt; &amp;lt;сообщение&amp;gt; [PGP-ключ] [учётные записи] — отправить сообщение в чат,&lt;/li&gt;&lt;li&gt;send_file &amp;lt;файл&amp;gt; &amp;lt;jid&amp;gt; [учётные записи] — отправить файл,&lt;/li&gt;&lt;li&gt;send_groupchat_message &amp;lt;jid&amp;gt; &amp;lt;сообщение&amp;gt; [учётные записи] — отправить сообщение в конференцию,&lt;/li&gt;&lt;li&gt;send_single_message &amp;lt;jid&amp;gt; &amp;lt;тема&amp;gt; &amp;lt;сообщение&amp;gt; [PGP-ключ] [учётные записи] — отправить одиночное сообщение,&lt;/li&gt;&lt;li&gt;open_chat &amp;lt;jid&amp;gt; [учётные записи] — открыть чат с указанным контактом,&lt;/li&gt;&lt;li&gt;start_chat &amp;lt;учётные записи&amp;gt; — открыть чат для заданной учётной записи (появится окно ввода JID),&lt;/li&gt;&lt;li&gt;toggle_roster_appearance — показать/скрыть окошко ростера.&lt;/li&gt;&lt;/ul&gt;Попробуем теперь применить это на практике. Напишем скрипт, меняющий сообщение статуса на случайную цитату из fortunes. (Для тех, кто ещё не знает, fortunes — это консольная программа, выдающая случайную цитату из довольно объемной базы.)&lt;br /&gt;&lt;br /&gt;Для этого в бесконечном цикле будем вызывать gajim-remote, передавая ему при помощи обратных кавычек результат выполнения команды fortunes. Между вызовами поставим паузу 5 минут (5×60=300 с).&lt;br /&gt;&lt;pre&gt;while true; do gajim-remote change_status &quot;online&quot; &quot;`fortune`&quot;; sleep 300; done&lt;/pre&gt;У этой команды есть небольшой недостаток — нужно всё время держать терминал открытым. Для того, чтобы решить эту проблему, можно просто записать команду в текстовый файл, а потом запустить следующим образом:&lt;br /&gt;&lt;pre&gt;bash changestatus.sh &amp;amp;&lt;/pre&gt;Амперсанд в конце запустит выполнение скрипта в фоне. Можно также создать правило для cron — тогда вообще не придется что-либо запускать.&lt;br /&gt;&lt;br /&gt;Другое возможное применение — отправка кому-то сообщения по расписанию. Например, при помощи такой команды:&lt;br /&gt;&lt;pre&gt;echo &quot;gajim-remote send_chat_message user@example.com &#39;Hello&#39;&quot; | at 10:00&lt;/pre&gt;Ровно в 10:00 пользователю будет отправлено сообщение «Hello» (если, конечно, Gajim будет в этот момент запущен).&lt;br /&gt;&lt;br /&gt;Итак, даже этот небольшой набор команд в сочетании с инструментами командной строки позволяет сделать что-то полезное.&lt;br /&gt;&lt;br /&gt;Если работа gajim-remote покажется слишком медленной, можно воспользоваться, например, командой dbus-send или qdbus для отправки сообщения напрямую через D-Bus.&lt;br /&gt;&lt;br /&gt;Список предоставляемых функций можно посмотреть при помощи команды&lt;br /&gt;&lt;pre&gt;qdbus org.gajim.dbus /org/gajim/dbus/RemoteObject&lt;/pre&gt;Вызвать же функцию можно так:&lt;br /&gt;&lt;pre&gt;qdbus org.gajim.dbus /org/gajim/dbus/RemoteObject toggle_roster_appearance&lt;/pre&gt;Работает намного быстрее gajim-remote, но приходится явно указывать, кому мы шлём команды.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/6648849086084415891/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/gajim.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/6648849086084415891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/6648849086084415891'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/gajim.html' title='Управляем Gajim из командной строки'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-7584374994125762711</id><published>2009-07-20T18:49:00.019+03:00</published><updated>2010-06-07T02:43:45.514+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="математика"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>Построение графиков с помощью PyXPlot</title><content type='html'>Утилит, позволяющих построить на компьютере график какой-то функции, превеликое множество. Но не каждая способна создать график в достойном качестве, и с соответствующим оформлением. Многие из них интерактивны, но часто это мешает, когда нужно менять много параметров графика. Поэтому при активной работе с графиками часто применяются командные «графопостроители» — фактически маленькие языки программирования.&lt;br /&gt;&lt;br /&gt;Среди программ таких можно отметить, например, asymptote, популярный gnuplot, metapost и другие. Достойное место в этом ряду занимает &lt;a href=&quot;http://www.pyxplot.org.uk/&quot;&gt;PyXPlot&lt;/a&gt; (её команды, кстати, во многом совпадают с командами gnuplot, так что изучив одну из этих программ, легко разобраться в другой). Отличительными особенностями программы являются простота и высокое качество результата. Ей и посвящен этот обзор.&lt;br /&gt;&lt;span class=&#39;fullpost&#39;&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Запуск программы&lt;/span&gt;&lt;br /&gt;PyXPlot есть в дистрибутиве Ubuntu и Debian, так что установка должна пройти без проблем. В крайнем случае, всегда можно скачать программу с родного сайта.&lt;br /&gt;&lt;br /&gt;Сразу нужно отметить, что PyXPlot — программа чисто консольная. Работать с ней можно как интерактивно, вводя команду за командой, так и в скриптовом режиме. В последнем случае команды записываются в отдельный файл, который затем «скармливается» PyXPlot.&lt;br /&gt;&lt;br /&gt;Запускается PyXPlot как обычно:&lt;br /&gt;&lt;pre&gt;pyxplot СКРИПТЫ&lt;/pre&gt;&lt;br /&gt;Если вместо списка файлов поставить дефис, то программа будет читать команды со стандартного ввода, что очень удобно при автоматизации. Например, так можно нарисовать синусоиду:&lt;br /&gt;&lt;pre&gt;echo &#39;plot sin(x)&#39; | pyxplot -&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYk6GbpfW8jEMAtKufjHeyCbdZJtqs5LXSl5mk4am58mboLvRR-NvSuUoV-p7GTv6tGAcUO0bcnMBADLp7yr0vxsSntm78rP0-LhzCqAQXjBgCLpovY7SkJ4Ny2gcuzyQd6c3UKwYyoOQ/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 274px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYk6GbpfW8jEMAtKufjHeyCbdZJtqs5LXSl5mk4am58mboLvRR-NvSuUoV-p7GTv6tGAcUO0bcnMBADLp7yr0vxsSntm78rP0-LhzCqAQXjBgCLpovY7SkJ4Ny2gcuzyQd6c3UKwYyoOQ/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360598395205363682&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Простейшие операции&lt;/span&gt;&lt;br /&gt;Главная команда для рисования графиков — plot. Она позволяет не только рисовать графики функции, но и строить «по точкам» графики данных, записанных в файл.&lt;br /&gt;&lt;br /&gt;Чтобы построить данные из файла, нужно просто указать его имя в апострофах или двойных кавычках после команды plot. Данные в файле должны быть обычным текстом с одним или несколькими столбцами чисел, разделенных пробелами или запятыми. Если имя заканчивается на «.gz», он будет автоматически распакован перед построением.&lt;br /&gt;&lt;pre&gt;plot &#39;data.gz&#39;&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO0R22X5Jwb8vht8toR-IFDuur-shvFNQK36RtkfPfCxix1YzL2qeHbArrBsOZB_p_T98G_DX-jush_dK5zTSNTldgOOIQsbobrOcu3FoLGaTI7TpKl44_oVvMuHXxwui7TBlP63i3SdU/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 256px; height: 173px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjO0R22X5Jwb8vht8toR-IFDuur-shvFNQK36RtkfPfCxix1YzL2qeHbArrBsOZB_p_T98G_DX-jush_dK5zTSNTldgOOIQsbobrOcu3FoLGaTI7TpKl44_oVvMuHXxwui7TBlP63i3SdU/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360617297312899538&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Так как в файле указаны отдельные значения, то и отображаются они по отдельности, маркерами.&lt;br /&gt;&lt;br /&gt;По умолчанию результаты сохраняются в файл «pyxplot.eps».&lt;br /&gt;&lt;br /&gt;Построения графика функции полностью аналогична. Нужно просто записать её после команды plot. В качестве аргумента нужно использовать x.&lt;br /&gt;&lt;pre&gt;plot sin(x)/x&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijrcJOUQ0FG68VABnKGj6v96sMnW6eQsqMMFxZ5I22A2rJNNs5A2IpbpEPX8B8oyP8mI_5VLoqMnM9lKGqtxLYrd-u4XiPPnz48rf-ncALlvd9KnqDOkUL232RK0noqEOeG1n-E7MCaRw/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 274px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijrcJOUQ0FG68VABnKGj6v96sMnW6eQsqMMFxZ5I22A2rJNNs5A2IpbpEPX8B8oyP8mI_5VLoqMnM9lKGqtxLYrd-u4XiPPnz48rf-ncALlvd9KnqDOkUL232RK0noqEOeG1n-E7MCaRw/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360619123543535506&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Можно построить сразу несколько графиков в одной системе координат, просто перечислив функции (или имена файлов) через запятую.&lt;br /&gt;&lt;pre&gt;plot sin(x)/x, sin(x)&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxwmJMOg7kvSYBr0G_oZHwrDdaB1fPjqCWqjoD6KO4KLGcszdHqLXXCLkHgvGDcTqjwz51pbnK7UNL9Fymt7T5CzxvNWfKUHDCpICYOLwD24-u09oYfIrzdNIBgH6ep6OBu9D2Q_A7bVo/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 274px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxwmJMOg7kvSYBr0G_oZHwrDdaB1fPjqCWqjoD6KO4KLGcszdHqLXXCLkHgvGDcTqjwz51pbnK7UNL9Fymt7T5CzxvNWfKUHDCpICYOLwD24-u09oYfIrzdNIBgH6ep6OBu9D2Q_A7bVo/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360621039882398626&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Переменные и функции&lt;/span&gt;&lt;br /&gt;В теле файла с командами можно объявить переменные и пользовательские функции при помощи операции «=». Всё достаточно интуитивно:&lt;br /&gt;&lt;pre&gt;a = 2&lt;br /&gt;b = 3&lt;br /&gt;plot sqrt(a*pow(x,2) + b)&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_niKuxaSm7m6J60ycl2LrEsBSjYFLQM9sytKsp-sCsuSOQtB27wnLvBJOOYW7KrZ65Qd2ttB7OYlViMPZB1BORQYrhh0S-zJFY-gfn-57i7S2jfbNINk1zhk9O_cV0vyNftxfiwOUxSg/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 264px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_niKuxaSm7m6J60ycl2LrEsBSjYFLQM9sytKsp-sCsuSOQtB27wnLvBJOOYW7KrZ65Qd2ttB7OYlViMPZB1BORQYrhh0S-zJFY-gfn-57i7S2jfbNINk1zhk9O_cV0vyNftxfiwOUxSg/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360622178989618194&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;В PyXPlot встроены самые распространенные математические функции, такие как: sin, cos, tan, exp, min, log, acos, asin, atan, sqrt, pow и т. д.&lt;br /&gt;&lt;pre&gt;f(x) = sqrt(x)*sin(x)&lt;br /&gt;plot f(x)&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIqbLE86y0ZpAtAbBwfEnDnZfxlh1yEWby9dZFU1K0ot_kdKev18jcyhhPipvKMzo97sOYFikjlPXm7_y_D4_YLvurK4e-hwKEd8xD_Iy71A8Ee0WD6AI4TwmipKJ5tyJODVTZeBHhLVQ/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 263px; height: 173px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIqbLE86y0ZpAtAbBwfEnDnZfxlh1yEWby9dZFU1K0ot_kdKev18jcyhhPipvKMzo97sOYFikjlPXm7_y_D4_YLvurK4e-hwKEd8xD_Iy71A8Ee0WD6AI4TwmipKJ5tyJODVTZeBHhLVQ/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360623616096789826&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Настройки графика&lt;/span&gt;&lt;br /&gt;При помощи команды set можно задать дополнительные параметры графика, такие как подписи осей (x label и ylabel) и заголовок графика (title). В подписях можно использовать формат формулы в формате TeX (их нужно обязательно заключить в знаки «$»). Использование TeX делает график намного симпатичнее и презентабельнее.&lt;br /&gt;&lt;br /&gt;Пример:&lt;br /&gt;&lt;pre&gt;set xlabel &#39;$x$&#39;&lt;br /&gt;set ylabel &#39;$y$&#39;&lt;br /&gt;set title &#39;Plot of $\sin(x)\over x$&#39;&lt;br /&gt;plot sin(x)/x&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyeRHAjy5EpnOfBsVSByO6DguHJcU4g-fRP9DwKmaGoFzk5HVEiQ8qnlG9G7m9mHVZQ1k108y6zH3XmDMUFRgaRKm0S_3JeKAuul8UdKc4Upljaq1CG6LoEejf9z71Oa7MLAYgsPqrSxc/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 278px; height: 194px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyeRHAjy5EpnOfBsVSByO6DguHJcU4g-fRP9DwKmaGoFzk5HVEiQ8qnlG9G7m9mHVZQ1k108y6zH3XmDMUFRgaRKm0S_3JeKAuul8UdKc4Upljaq1CG6LoEejf9z71Oa7MLAYgsPqrSxc/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360627550120497890&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;Можно также задать имя выходного файла (set output) и формат выходных данных (set terminal). Поддерживаются распространённые форматы: postscript, pdf, png, jpeg.&lt;br /&gt;&lt;br /&gt;Пример:&lt;br /&gt;&lt;pre&gt;set terminal png&lt;br /&gt;set output &#39;plot.png&#39;&lt;br /&gt;plot cos(x)*exp(x)&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHFX-DzxNTx5JfAknA9TccWLGBQxsxchNhRF37TLEcgJ4Q0WPSxDt3Di4bcZ8qTo-c64iMB9heK-t5vp6yiJ8UGH3sHx_TjE-dNgu7zlkcW5zLThREz0sTXrpUXpWuaUyzCzW_vNb3UGA/s1600-h/plot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 191px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHFX-DzxNTx5JfAknA9TccWLGBQxsxchNhRF37TLEcgJ4Q0WPSxDt3Di4bcZ8qTo-c64iMB9heK-t5vp6yiJ8UGH3sHx_TjE-dNgu7zlkcW5zLThREz0sTXrpUXpWuaUyzCzW_vNb3UGA/s320/plot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360629346087418786&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Работа с файлами данных&lt;/span&gt;&lt;br /&gt;Данные в файле можно использовать как независимые координаты при построении. Для этого нужно добавить парметр using к команде plot.&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;plot &#39;data.gz&#39; using 1:2&lt;/pre&gt;строит график, используя первый столбец как координату x точек, а второй — как координату y.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Стили графика&lt;/span&gt;&lt;br /&gt;Стиль построения графика настраивается при помощи параметра with.&lt;br /&gt;&lt;br /&gt;Команда&lt;br /&gt;&lt;pre&gt;plot &#39;data.gz&#39; with points&lt;/pre&gt;строит точечный график, а команда&lt;br /&gt;&lt;pre&gt;plot &#39;data.gz&#39; with lines&lt;/pre&gt;соединяет точки отрезками.&lt;br /&gt;&lt;br /&gt;Можно также откладывать ошибку на графике (with yerrorbars), но для этого потребуется третий столбец.&lt;br /&gt;&lt;br /&gt;Тип маркеров и линий также настраивается при помощи модификаторов pointtype и linetype. Подробности — в документации.&lt;br /&gt;&lt;pre&gt;plot sin(x) with lines linetype 3&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Qo56oNCcFkbpd2jdczSsOQY4CG-0RBFTM9W0Xo6_EsvC-FmOnTJyhZIPpOiTRBBKv8zFKNdtAZm7WYTqMcbVozB1zrPWRA2c963Yci6H1dmPDTQOjA-CIlhBy22BQ0RtnLG4-kgHS6M/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 274px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6Qo56oNCcFkbpd2jdczSsOQY4CG-0RBFTM9W0Xo6_EsvC-FmOnTJyhZIPpOiTRBBKv8zFKNdtAZm7WYTqMcbVozB1zrPWRA2c963Yci6H1dmPDTQOjA-CIlhBy22BQ0RtnLG4-kgHS6M/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360634467091365762&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Диапазоны по осям&lt;/span&gt;&lt;br /&gt;При построении можно указать размеры осей. Для этого нужно указать минимально и максимальное значения по каждой из осей в квадратных скобках через двоеточие. Если нужно указать параметры только для одной оси, то для другой просто записсывается «[:]» без чисел. Пример:&lt;br /&gt;&lt;pre&gt;plot [-1:1][-1:1] sin(x)&lt;/pre&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEMaavVNTpjZXLU44A3MrG0hmM_CIi0K4BcQJ7Ge6vnaNLYf5xsvDUCu0utd_kmi6uxEjdZjWibFBBILChy_toXTgP5Rvu5dWCt4TwcHFTbLUFP10Ck45h6VIOp9J8_STqS2xUeF-4zoU/s1600-h/pyxplot.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 272px; height: 174px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEMaavVNTpjZXLU44A3MrG0hmM_CIi0K4BcQJ7Ge6vnaNLYf5xsvDUCu0utd_kmi6uxEjdZjWibFBBILChy_toXTgP5Rvu5dWCt4TwcHFTbLUFP10Ck45h6VIOp9J8_STqS2xUeF-4zoU/s320/pyxplot.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5360636746864905314&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Заключение&lt;/span&gt;&lt;br /&gt;Разумеется, возможности программы не исчерпываются только перечисленными командами. Утилита имеет ещё очень много разных возможностей: от аппроксимации данных из файла до построения графиков векторных полей.&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://pyxplot.org.uk/examples/04mc/02fft/output.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 648px; height: 333px;&quot; src=&quot;http://pyxplot.org.uk/examples/04mc/02fft/output.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://pyxplot.org.uk/examples/01pf/05vortex/output.png&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 390px; height: 255px;&quot; src=&quot;http://pyxplot.org.uk/examples/01pf/05vortex/output.png&quot; alt=&quot;&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/7584374994125762711/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/pyxplot.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7584374994125762711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7584374994125762711'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/pyxplot.html' title='Построение графиков с помощью PyXPlot'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYk6GbpfW8jEMAtKufjHeyCbdZJtqs5LXSl5mk4am58mboLvRR-NvSuUoV-p7GTv6tGAcUO0bcnMBADLp7yr0vxsSntm78rP0-LhzCqAQXjBgCLpovY7SkJ4Ny2gcuzyQd6c3UKwYyoOQ/s72-c/pyxplot.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-3666012915388885249</id><published>2009-07-20T11:53:00.014+03:00</published><updated>2009-08-22T22:41:43.427+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="регулярные выражения"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>Массовое переименование файлов</title><content type='html'>Наверное, каждый сталкивался с ситуацией, когда нужно переименовать по какому-то шаблону огромное количество файлов. Например, поменять в названиях песен имя исполнителя и заголовок. Или вставить определенную дату в название группы фотографий.&lt;br /&gt;&lt;br /&gt;В этих случаях на помощь приходят регулярные выражения и специальные утилиты для массового переименования.&lt;br /&gt;&lt;span class=&quot;fullpost&quot;&gt;&lt;br /&gt;Для меня наиболее удобна консольная утилита prename (или rename), входящая в состав пакета perl. Но кому-то больше по душе, наверное, придутся программы с графическим интерфейсом. Могу посоветовать программы krename или gprename. Однако, в большинстве случаев вполне хватит и prename.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Введение&lt;/span&gt;&lt;br /&gt;Синтаксис команды выглядит очень просто:&lt;br /&gt;&lt;pre&gt;prename ШАБЛОН ФАЙЛЫ&lt;/pre&gt;&lt;br /&gt;Но за этой простотой скрывается огромная мощь. Дело в том, что в качестве шаблона используются &lt;a rel=&quot;nofollow&quot; href=&quot;http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%D0%B3%D1%83%D0%BB%D1%8F%D1%80%D0%BD%D1%8B%D0%B5_%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F&quot;&gt;регулярные выражения&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Параметр ФАЙЛЫ может быть как списком файлов, так и шаблоном в стиле bash, использующим «*» для любой последовательности символов и «?» для одиночного символа. Например, «*.txt» — это все файлы с раширением «txt».&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Регулярные выражения&lt;/span&gt;&lt;br /&gt;Остановимся поподробнее на регулярных выражениях. Это настолько обширная тема, что о них пишутся целые книги. И настолько сложная, что большую популярность получила известная шутка: «Некоторые люди, когда сталкиваются с какой-то проблемой, думают: “Думаю, я применю регулярные выражения.” Теперь у них две проблемы.» (Jamie Zawinski) Однако, в простых случаях регулярные выражения просты и удобны. Разве что выглядят непривычно. (Честно говоря, иногда они выглядят так, будто по клавиатуре пробежала кошка.)&lt;br /&gt;&lt;br /&gt;В утилите prename регулярные выражения обычно имеют следующий вид:&lt;br /&gt;&lt;pre&gt;s/ИСХОДНЫЙ/КОНЕЧНЫЙ/&lt;/pre&gt;ИСХОДНЫЙ и КОНЕЧНЫЙ — это шаблоны. Первый задает подстроку, которую нужно найти в имени, а второй — на что эту подстроку заменить.&lt;br /&gt;&lt;br /&gt;В простейшем случае это могут быть обычные слова. Команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/Алиса/Боб/&#39; *.txt&lt;/pre&gt;заменит во всех файлах с расширением «txt» слово «Алиса» на слово «Боб».&lt;br /&gt;&lt;br /&gt;Нужно заметить, что шаблон применяется к каждому имени файла только один раз. То есть файл с именем «Эх, Алиса, Алиса.txt» будет заменен на «Эх, Боб, Алиса.txt». Чтобы шаблон примянялся столько, сколько нужно, необходимо добавить параметр g к регулярному выражению:&lt;br /&gt;&lt;pre&gt;prename &#39;s/Алиса/Боб/g&#39; *.txt&lt;/pre&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Подстановки&lt;/span&gt;&lt;br /&gt;Кроме собственно слов можно использовать специальные подстановочные символы:&lt;br /&gt;«&lt;b&gt;.&lt;/b&gt;» — любой одиночный символ,&lt;br /&gt;«&lt;b&gt;\d&lt;/b&gt;» — цифра,&lt;br /&gt;«&lt;b&gt;\D&lt;/b&gt;» — любой символ кроме цифры,&lt;br /&gt;«&lt;b&gt;\w&lt;/b&gt;» — буква, цифра или знак подчёркивания,&lt;br /&gt;«&lt;b&gt;\W&lt;/b&gt;» — всё, кроме букв, цифр и знака подчёркивания,&lt;br /&gt;«&lt;b&gt;\s&lt;/b&gt;» — любой пробельный символ,&lt;br /&gt;«&lt;b&gt;\S&lt;/b&gt;» — любой непробельный символ.&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/\s/_/g&#39; *.txt&lt;/pre&gt;заменит пробелы на знаки подчёркивания. Несколько идущих подряд пробелов будут заменены на несколько подчёркиваний.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Начало и конец&lt;/span&gt;&lt;br /&gt;Есть также специальные псевдосиволы:&lt;br /&gt;«&lt;b&gt;^&lt;/b&gt;» — обозначает начало слова,&lt;br /&gt;«&lt;b&gt;$&lt;/b&gt;» — обозначает конец слова.&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/a$/b/&#39; *.txt&lt;/pre&gt;заменит «a» на «b» только если «a» — последний символ имени файла.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Экранирование&lt;/span&gt;&lt;br /&gt;Если же какой-то из специальных символов нужно использовать в шаблоне как символ обычный, его нужно экранировать обратным слэшем. Например, «.» — одиночный символ, «\.» — просто точка.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Повторы&lt;/span&gt;&lt;br /&gt;После любой части регулярного выражения можно поставить количество его повторов:&lt;br /&gt;«&lt;b&gt;?&lt;/b&gt;» — ноль или один,&lt;br /&gt;«&lt;b&gt;*&lt;/b&gt;» — ноль и более,&lt;br /&gt;«&lt;b&gt;+&lt;/b&gt;» — один и более,&lt;br /&gt;«&lt;b&gt;{n}&lt;/b&gt;» — ровно n&lt;br /&gt;«&lt;b&gt;{m,n}&lt;/b&gt;» — от m до n,&lt;br /&gt;«&lt;b&gt;{m,}&lt;/b&gt;» — от m и более,&lt;br /&gt;«&lt;b&gt;{,n}&lt;/b&gt;» — от нуля до n.&lt;br /&gt;&lt;br /&gt;Символы «?», «+» и «*» по умолчанию являются «жадными», то есть пытаются отхватить как можно большую часть выражения, попадающую под шаблон.&lt;br /&gt;&lt;br /&gt;Команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/\s+/_/g&#39; *.txt&lt;/pre&gt;заменит пробелы на знаки подчёркивания. Несколько идущих подряд пробелов будут заменены на одно подчёркивание.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Группировка и ссылки&lt;/span&gt;&lt;br /&gt;Части выражения можно группировать при помощи круглых скобок. Также можно ссылаться на скобки при помощи выражения вида «$номер». Здесь — номер — это номер пары скобок в порядке их вхождения в выражение.&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/(\d)+/$1/g&#39; *.txt&lt;/pre&gt;заменит несколько подряд идущих одинаковых цифр в имени на одну (эту же!) цифру. То есть файл с именем «11122233333.txt» будет переименован в «123.txt».&lt;br /&gt;&lt;br /&gt;А команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/(.*) - (.*)\.mp3/$2 - $1\.mp3/&#39; *.mp3&lt;/pre&gt;переименует файл «Ария Филиппа - Шаляпин.mp3» в «Шаляпин - Ария Филиппа.mp3».&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Что за там, за горизонтом?&lt;/span&gt;&lt;br /&gt;Есть также полезная возможность заглянуть вперед или назад, но не включая определенную часть шаблона в найденное:&lt;br /&gt;«&lt;b&gt;(?=ШАБЛОН)&lt;/b&gt;» — просмотр вперёд,&lt;br /&gt;«&lt;b&gt;(?!ШАБЛОН)&lt;/b&gt;» — просмотр вперёд (с отрицанием),&lt;br /&gt;«&lt;b&gt;(?&amp;lt;=ШАБЛОН)&lt;/b&gt;» — просмотр назад,&lt;br /&gt;«&lt;b&gt;(?&amp;lt;!ШАБЛОН)&lt;/b&gt;» — просмотр назад (с отрицанием).&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/(?&amp;lt;!x)a/b/g&#39; *.txt&lt;/pre&gt;заменит «a» на «b» в файлах с раширением «txt» только если «a» не идёт после x.&lt;br /&gt;&lt;br /&gt;А команда&lt;br /&gt;&lt;pre&gt;prename &#39;s/a(?!x)/b/g&#39; *.txt&lt;/pre&gt;заменит «a» на «b» в файлах с раширением «txt» только если «a» не идёт перед x.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Заключение&lt;/span&gt;&lt;br /&gt;Регулярные выражения имеют огромную область применения. Естественно, в этом посте перечислены далеко не все их возможности. Например, не сказано про транслитерацию или диапазоны символов.&lt;br /&gt;&lt;br /&gt;В качестве неплохого руководства по ним могу порекомендовать книгу Дж. Фридла «Регулярные выражения».&lt;br /&gt;&lt;br /&gt;У утилиты, конечно, есть и недостатки. Главный очевиден — нужно знать регулярные выражения. Есть и другие. Например, с помощью prename нельзя пронумеровать файлы.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/3666012915388885249/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/blog-post_20.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3666012915388885249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/3666012915388885249'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/blog-post_20.html' title='Массовое переименование файлов'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-4709925307621607577</id><published>2009-07-17T13:20:00.008+03:00</published><updated>2009-11-01T12:59:15.981+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GNOME"/><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Идеи для GNOME Shell</title><content type='html'>Как известно, сейчас полным ходом идет работа над GNOME 3, в котором привычный интерфейс будет заменен на GNOME Shell. И хотя последний будет включен в GNOME 2.28, работа сейчас находится на достаточно ранней стадии. В связи с этим разработчики предлагают каждому предложить свою идею, каким должен быть интерфейс нового GNOME. Сбор идей производится на &lt;a href=&quot;http://live.gnome.org/GnomeShell/DesignerPlayground&quot;&gt;сайте проекта&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Вот, некоторые из предложений, представленных на сайте, которые мне показались достаточно любопытными (подробности — на сайте GNOME).&lt;br /&gt;&lt;br /&gt;&lt;span class=fullpost&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Расширенный вид меню&lt;/span&gt;&lt;br /&gt;Máirín Duffy предлагает сделать возможность отображения в меню Activities не только приложений, но и связаной с ними информации. Например, недавно открытых файлов.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18981/appmenu_app_with_currently_open_windows_9zP1Iw.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18981/appmenu_app_with_currently_open_windows_9zP1Iw.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/18982/appmenu_chat_app_recent_convos_4ZLMhb.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18982/appmenu_chat_app_recent_convos_4ZLMhb.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18984/appmenu_creativeapp_recent_files_GO0Jjo.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18984/appmenu_creativeapp_recent_files_GO0Jjo.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/18985/appmenu_creativeapps_flatlist_Ebzv21.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18985/appmenu_creativeapps_flatlist_Ebzv21.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Мини-терминал&lt;/span&gt;&lt;br /&gt;Предлагается также сделать небольшое поле для ввода команд. Может быть полезным, если приложению требуются какие-то параметры для запуска.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18987/overlay_mode_mini_terminal_view_modes_0daQjc.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18987/overlay_mode_mini_terminal_view_modes_0daQjc.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Полка для окон&lt;/span&gt;&lt;br /&gt;Довольно интересной представляется возможность складывать неиспользуемые окна на «полку». Особенно удобно это будет с устройствами, оборудованными тачскринами. Тогда окна можно будет просто выделить при помощи «лассо» и свернуть, чтобы не занимали место.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18988/3450460435_53ec08c9ed_o_T06mA1.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18988/3450460435_53ec08c9ed_o_T06mA1.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;«Связывание» окон&lt;/span&gt;&lt;br /&gt;Если эта возможность будет реализована, то пользователь сможет «связывать» два окна, после чего они будут отображаться как единое целое. Шаг в сторону тайловых оконных менеджеров.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18989/3450460435_53ec08c9ed_o_X474d7.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18989/3450460435_53ec08c9ed_o_X474d7.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Отображение приложений справа&lt;/span&gt;&lt;br /&gt;Некоторые пользователи считают, что список приложений лучше выводить справа от миниатюр рабочих столов. Выглядит достаточно непривычно.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18990/3450460435_53ec08c9ed_o_1r491w.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18990/3450460435_53ec08c9ed_o_1r491w.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Цепочка последних действий&lt;/span&gt;&lt;br /&gt;Очень удобным мне показалось отображение последних открытых документов и приложений рядом с меню Activities.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18992/3450460435_53ec08c9ed_o_wZ1kBM.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18992/3450460435_53ec08c9ed_o_wZ1kBM.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/18994/shell_mockup_sanderqd_20090413_02_JuKy3Y.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18994/shell_mockup_sanderqd_20090413_02_JuKy3Y.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18993/drop_down_menu_20090504_rXUJsZ.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18993/drop_down_menu_20090504_rXUJsZ.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Заголовки окон вместо панели&lt;/span&gt;&lt;br /&gt;Не знаю, насколько это удобно, но есть предложение отказаться от панели, где отображались бы запущенные приложения. Вместо этого можно было бы использовать заголовки окон.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18995/windowtraysmockup_2GSX2g.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18995/windowtraysmockup_2GSX2g.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Умные окна&lt;/span&gt;&lt;br /&gt;Предлагается позволить окнам самим мледить за тем, кто из них на переднем плане. Возможно,что это позволит переключаться между ними, затрачивая меньше времени. Хотя выглядит тоже очень очень непривычно. По-моему, окнам лучше быть просто окнами.&lt;br /&gt;&lt;br /&gt;&lt;object height=&quot;385&quot; width=&quot;480&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/lsZvwyxJ9vk&amp;amp;hl=ru&amp;amp;fs=1&amp;amp;&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://www.youtube.com/v/lsZvwyxJ9vk&amp;amp;hl=ru&amp;amp;fs=1&amp;amp;&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; height=&quot;385&quot; width=&quot;480&quot;&gt;&lt;/embed&gt;&lt;a class=&quot;hlregmasowpqcxeiygjc&quot; href=&quot;http://www.youtube.com/v/lsZvwyxJ9vk&amp;amp;hl=ru&amp;amp;fs=1&amp;amp;&quot;&gt;&lt;/a&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Категории в меню&lt;/span&gt;&lt;br /&gt;Некоторые идеи выглядят очень инновационо. Например, отображение всех приложений и документов в одном меню. Поэтому появилось предложение сделать возможность выбора между новым и старым стилем представления.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18997/overlay_flat_list_mockup_48Epqo.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18997/overlay_flat_list_mockup_48Epqo.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/18998/overlay_categories_mockup_LO6KQ2.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18998/overlay_categories_mockup_LO6KQ2.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Выпадающий список приложений&lt;/span&gt;&lt;br /&gt;В то время как одни хотят избавиться от панели задач, другие предлагают менее радикальное решение — представить запущенные приложения в виде списка.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18999/windows_needing_attention_concept_19A7VT.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18999/windows_needing_attention_concept_19A7VT.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/19000/2_NwhLLu.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/19000/2_NwhLLu.jpg&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Отказ от списка приложений&lt;/span&gt;&lt;br /&gt;Есть также идея вообще отказаться от списка приложений в пользу списка контактов и документов (организованного, например, при помощи Zeitgeist). В целом, довольно здравая мысль, так как всё равно люди часто используют приложения только для обработки документов или для свзяи с кем-то.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/19003/documents2_TgK7Cc.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/19003/documents2_TgK7Cc.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt; &lt;a href=&quot;http://www.ubuntu-pics.de/bild/19004/people2_0j1uqU.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/19004/people2_0j1uqU.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;Контакты в Activities&lt;/span&gt;&lt;br /&gt;Также кроме простого отображения списка контактов можно выводить и дополнительную информацию, получая более тесную интеграцию окружения рабочего стола с мессенджерами.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/19005/gnome_shell_people_overlay_mockup_t7rZVK.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/19005/gnome_shell_people_overlay_mockup_t7rZVK.png&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Вот, вкратце, наиболее инновационные предложения. Есть какая-то идея? Присоединяйтесь и вы!&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/4709925307621607577/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/gnome-shell.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/4709925307621607577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/4709925307621607577'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/gnome-shell.html' title='Идеи для GNOME Shell'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-7911511324542384039</id><published>2009-07-16T20:58:00.008+03:00</published><updated>2009-07-20T11:52:45.546+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="python"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>Информация о медиафайлах</title><content type='html'>В недавнем посте об отображении тегов mp3-файлов рассказывалось об утилите mp3info. К сожалению, она обладает существенными недостатками: не понимает ID3v2 и работает, как следует из названия, только с mp3-файлам.&lt;br /&gt;&lt;br /&gt;Однако, сама по себе утилитка довольно удобна. Поэтому я решил написать небольшой скрипт, предоставляющий похожий интерфейс, но понимающий большее количество медиаформатов.&lt;br /&gt;&lt;span class=fullpost&gt;&lt;br /&gt;Естественно, писал я его не на пустом месте. Для работы скрипта потребуется библиотека &lt;a rel=&quot;nofollow&quot; href=&quot;http://doc.freevo.org/2.0/SourceDoc/KaaMetadata&quot;&gt;Kaa.Metadata&lt;/a&gt;:&lt;br /&gt;&lt;pre&gt;sudo aptitude install python-kaa-metadata&lt;/pre&gt;&lt;br /&gt;Параметров у скрипта всего два (для простоты): форматная строка и файл (или несколько файлов через пробел):&lt;br /&gt;&lt;pre&gt;mediainfo.py ФОРМАТ файл(ы)&lt;/pre&gt;&lt;br /&gt;При указании файла можно использовать стандартные шаблоны. Так что вполне допустимо имя вида «*.mp3». Можно использовать и более сложные шаблоны: «~/Музыка/*/*.mp3».&lt;br /&gt;&lt;br /&gt;Скрипт не умеет рекурсивно обходить каталоги, но это ему и не нужно. Обход можно реализовать, например, средствами bash.&lt;br /&gt;&lt;br /&gt;Подробнее о форматной строке. В ней можно использовать следующие шаблоны:&lt;br /&gt;%t — название,&lt;br /&gt;%a — исполнитель,&lt;br /&gt;%r — частота дискретизации,&lt;br /&gt;%l — продолжительность,&lt;br /&gt;%m — продолжительность (только минуты),&lt;br /&gt;%s — продолжительность (только секунды)&lt;br /&gt;%c — кодек,&lt;br /&gt;%b — битрейт,&lt;br /&gt;%n — номер трека,&lt;br /&gt;%A — альбом,&lt;br /&gt;%g — жанр,&lt;br /&gt;%% — символ %.&lt;br /&gt;&lt;br /&gt;В ней также можно использовать обычные питоновские экранированные последовательности: \n, \t и т. д.&lt;br /&gt;&lt;br /&gt;Вставлять \n в конце форматной строки не нужно, это делается автоматически. Кроме того, вывод скрипта автоматически переконвертируется в кодировку текущей локали.&lt;br /&gt;&lt;br /&gt;Если теги файла записаны в однобайтовой кодировке и формат тегов не предусматривает указания кодировки, то скорее всего вместо ожидаемой cp1251 будет latin-1. Впрочем, ответственность за это лежит на библиотеке. Может, это можно настроить, я глубоко не вникал. Во всяком случае, это еще один повод перевести все теги в utf-8.&lt;br /&gt;&lt;br /&gt;Утилиту можно использовать как саму по себе, так и в конвейере:&lt;br /&gt;&lt;pre&gt;mediainfo.py &#39;%l&#39; ~/Музыка/*/* | awk &#39;{s += $1} END {print &quot;≈&quot;,int(s/3600),&quot;hour(s)&quot;}&#39;&lt;/pre&gt;&lt;br /&gt;А вот, собственно, исходный текст скрипта:&lt;br /&gt;&lt;pre name=&#39;code&#39; class=&#39;python&#39;&gt;#!/usr/bin/env python&lt;br /&gt;#-*- coding:utf-8 -*-&lt;br /&gt;&lt;br /&gt;# Disable all warnings&lt;br /&gt;import warnings&lt;br /&gt;warnings.filterwarnings(&#39;ignore&#39;)&lt;br /&gt;&lt;br /&gt;# Disable log messages&lt;br /&gt;#import logging&lt;br /&gt;#logger = logging.getLogger(&#39;metadata&#39;)&lt;br /&gt;#logger.setLevel(logging.CRITICAL)&lt;br /&gt;&lt;br /&gt;# Get locale encoding&lt;br /&gt;import locale&lt;br /&gt;encoding = locale.getdefaultlocale()[1]&lt;br /&gt;&lt;br /&gt;import os&lt;br /&gt;import sys&lt;br /&gt;import glob&lt;br /&gt;import string&lt;br /&gt;import kaa.metadata&lt;br /&gt;&lt;br /&gt;class MyTemplate(string.Template): delimiter = &#39;%&#39;&lt;br /&gt;&lt;br /&gt;def addItem(infolist, info):&lt;br /&gt;    item = {}&lt;br /&gt;    item[&#39;t&#39;] = info.title                      # Title&lt;br /&gt;    item[&#39;a&#39;] = info.artist                     # Artist&lt;br /&gt;    item[&#39;r&#39;] = info.samplerate                 # Samplerate&lt;br /&gt;    item[&#39;l&#39;] = int(info.length)                # Length (seconds)&lt;br /&gt;    item[&#39;m&#39;] = int(item[&#39;l&#39;] / 60) % 60        # Length (minutes only)&lt;br /&gt;    item[&#39;s&#39;] = format(item[&#39;l&#39;] % 60, &#39;02d&#39;)   # Length (seconds only)&lt;br /&gt;    item[&#39;c&#39;] = info.codec                      # Codec&lt;br /&gt;    item[&#39;b&#39;] = info.bitrate                    # Bitrate&lt;br /&gt;    item[&#39;n&#39;] = info.trackno                    # Track number&lt;br /&gt;    item[&#39;A&#39;] = info.album                      # Album title&lt;br /&gt;    item[&#39;g&#39;] = info.genre                      # Genre&lt;br /&gt;    infolist.append(item)&lt;br /&gt;&lt;br /&gt;def process(path):&lt;br /&gt;    infolist = []&lt;br /&gt;    path = os.path.normpath(path)&lt;br /&gt;    for f in glob.glob(os.path.expanduser(path)):&lt;br /&gt;        if os.path.isdir(f):&lt;br /&gt;            continue&lt;br /&gt;        try:&lt;br /&gt;            info = kaa.metadata.parse(f)&lt;br /&gt;        except:&lt;br /&gt;            info = None&lt;br /&gt;        if info != None:&lt;br /&gt;            addItem(infolist, info)&lt;br /&gt;    return infolist&lt;br /&gt;&lt;br /&gt;if len(sys.argv) &lt; 3:&lt;br /&gt;    print &#39;Usage:&#39;&lt;br /&gt;    print os.path.split(sys.argv[0])[1], &#39;FORMAT file(s)&#39;&lt;br /&gt;    exit(0)    &lt;br /&gt;for f in sys.argv[2:]:&lt;br /&gt;    infolist = process(f)        &lt;br /&gt;    for item in infolist:&lt;br /&gt;        sys.stdout.write(MyTemplate(sys.argv[1]).safe_substitute(item).encode(encoding) + &#39;\n&#39;)&lt;/pre&gt;&lt;br /&gt;Не забываем разрешить его выполнение:&lt;br /&gt;&lt;pre&gt;chmod +x mediainfo.py&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/7911511324542384039/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/mp3-mp3info.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7911511324542384039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/7911511324542384039'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/mp3-mp3info.html' title='Информация о медиафайлах'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-2531429219684325114</id><published>2009-07-15T15:47:00.010+03:00</published><updated>2009-07-20T11:52:15.902+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><category scheme="http://www.blogger.com/atom/ns#" term="утилиты"/><title type='text'>Информация об mp3-файлах</title><content type='html'>Иногда, когда залезаешь в свою коллекцию музыки, возникает необходимость составить список песен с продолжительностью. Например, для того, чтобы распечатать и приложить к диску.&lt;br /&gt;&lt;br /&gt;Для того, чтобы получить названия песен можно использовать ls, но не всегда название файла соответствует содержимому. И ещё реже в названии указана продолжительность.&lt;br /&gt;&lt;br /&gt;В этом случае на помощь приходит пакет mp3info.&lt;br /&gt;&lt;span class=fullpost&gt;&lt;br /&gt;В Ubuntu устанавливается как обычно:&lt;br /&gt;&lt;pre name=&#39;code&#39; class=&#39;bash&#39;&gt;&lt;br /&gt;sudo aptitude install mp3info&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;У него довольно много возможностей по редактированию и отображению тегов. Подробности можно узнать в man. Для того, чтобы получить список песен в альбоме можно воспользоваться следующей командой:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;mp3info -p &#39;ФОРМАТ&#39; *.mp3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Она выведет данные об mp3-файлах в текущем каталоге в соответствии со строкой ФОРМАТ.&lt;br /&gt;&lt;br /&gt;В форматной строке можно использовать как обычные символы (они выведутся как есть), так и специальные шаблоны. Вот список некоторых из них:&lt;br /&gt;%f — имя файла без пути,&lt;br /&gt;%F — имя файла с путём,&lt;br /&gt;%k — размер файла в килобайтах,&lt;br /&gt;%a — исполнитель,&lt;br /&gt;%g — жанр,&lt;br /&gt;%l — альбом,&lt;br /&gt;%n — номер трека,&lt;br /&gt;%t — название трека,&lt;br /&gt;%y — год,&lt;br /&gt;%q — частота сэмплирования (в кГц),&lt;br /&gt;%r — битрейт,&lt;br /&gt;%m — продолжительность (только минуты),&lt;br /&gt;%s — продолжительность (только секунды),&lt;br /&gt;%% — знак процента,&lt;br /&gt;\n — перевод строки,&lt;br /&gt;\t — горизонтальная табуляция,&lt;br /&gt;\\ — обратный слэш.&lt;br /&gt;&lt;br /&gt;Например, команда&lt;br /&gt;&lt;pre&gt;mp3info -p &#39;%n. %a - %t (%m:%s)\n&#39; *.mp3&lt;/pre&gt;&lt;br /&gt;выведет на экран что-то вроде:&lt;br /&gt;&lt;blockquote&gt;01. Allison Crowe - It Came Upon the Midnight Clea (0:42) &lt;br /&gt;02. Allison Crowe - Silent Night (4:2) &lt;br /&gt;03. Allison Crowe - In the Bleak Midwinter (4:3) &lt;br /&gt;04. Allison Crowe - What Child Is This (4:4) &lt;br /&gt;05. Allison Crowe - The First Noel (5:34) &lt;br /&gt;06. Allison Crowe - O Holy Night (4:16) &lt;/blockquote&gt;&lt;br /&gt;При работе с файлами, содержащими теги на русском языке могут возникнуть проблемы. Дело в том, что в них данные очень часто записываются в виндососвской кодировке cp1251. Решить проблему можно перекодировав вывод команды при помощи утилиты iconv:&lt;br /&gt;&lt;br /&gt;Просто по старой виндузячьей традиции теги хранятся в кодировке cp1251. Я все перекодирую при помощи easytag, но если файлик с такими тегами попался, то можно использовать iconv. Например, так:&lt;br /&gt;&lt;pre&gt;mp3info -p &#39;%a - %t \n&#39;  *.mp3 |iconv -f cp1251&lt;/pre&gt;&lt;br /&gt;Следует помнить, что mp3info работает только с тегами ID3v1.1.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/2531429219684325114/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/mp3.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/2531429219684325114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/2531429219684325114'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/mp3.html' title='Информация об mp3-файлах'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-6371896629128644776</id><published>2009-07-13T09:10:00.034+03:00</published><updated>2009-07-18T23:37:49.379+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="звук"/><category scheme="http://www.blogger.com/atom/ns#" term="программирование"/><title type='text'>Пишем пищалку для будильника</title><content type='html'>Часто мне не хватает удобного и простого будильника под Linux. Органайзеры со всплывающими окошками и проигрыванием заданной мелодии явно избыточны для того, чтобы просто не забыть про чайник. А старый добрый beep я использовать не могу по причине отсутствия PC-Speaker. Можно бы, конечно, поискать подходящую программу, но проще написать её самому. Тем более, программирование звука — это просто!&lt;br /&gt;&lt;span class=fullpost&gt;&lt;br /&gt;Итак, что должна уметь делать программа? Во-первых, издавать какой-то звук. Причем используя для этого звуковую карту. А во-вторых, должна быть консольной с возможностью указания времени звучания в командной строке.&lt;br /&gt;&lt;br /&gt;Чтобы проигать какой-то звук я решил использовать библиотеку &lt;a href=&quot;http://xiph.org/ao/&quot;&gt;libao&lt;/a&gt; — очень простую в использовании и удобную. При этом ещё и кроссплатформенную. К слову, она поддерживает ALSA, ESD, OSS, Pulse, чего должно хватить с головой.&lt;br /&gt;&lt;br /&gt;На родном сайте есть ссылки для скачивания и подробная документация. Пользователи Debian/Ubuntu могут установить библиотеку обычным способом&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;bash&quot;&gt;&lt;br /&gt;sudo aptitude install libao2&lt;br /&gt;sudo aptitude install libao-dev&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Пакет libao2 — это сама библиотека, он нужен будет для работы программы, а libao-dev — это заголовочные файлы.&lt;br /&gt;&lt;br /&gt;Библиотека написана на чистом C, поэтому для удобства можно обернуть все необходимые функции в класс¸ а потом, если потребуется, выделить в отдельную библиотеку. Удобство может показаться сомнительным, но лично мне в основной программе не хочется вводить посторонние переменные и писать функции для открытия/закрытия устройства. Да и забыть могу. А так всё, что нужно, прописано в конструкторе и деструкторе, а значит вызывается само собой.&lt;br /&gt;&lt;br /&gt;Работу с библиотекой можно разбить на три этапа:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;инициализация, настройка формата вывода, открытие устройства;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;воспроизведение звука;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;закрытие устройства и завершение работы с библиотекой.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;Класс можно написать, например, такой:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;class Beeper {&lt;br /&gt;  private:&lt;br /&gt;  ao_device *device;&lt;br /&gt;  int driver;&lt;br /&gt;  ao_sample_format format;&lt;br /&gt;&lt;br /&gt;  public:&lt;br /&gt;  Beeper();&lt;br /&gt;  void operator() (double freq, double time, double volume = 0.75);&lt;br /&gt;  ~Beeper();&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;С конструктором и деструктором всё понятно, а вот перегруженная операция вызова функции — это и есть метод класса, который издает звуки. Ему передается всего три параметра: freq — частота звучания в герцах, time — время звучания в секундах, volume — громкость (от 0.0 до 1.0).&lt;br /&gt;&lt;br /&gt;Про инициализацию и завершение работы с библиотекой можно почитать в документации. Скажу лишь про то, как, собственно, издавать звуки. Тут потребуется вспомнить школьный курс физики, в котором говориться, что звук — это просто колебания воздуха.&lt;br /&gt;&lt;br /&gt;Можно взять синусоиду, тогда мы получим чистый тон. Частота колебаний определяет высоту звука, а амплитуда — громкость. Тут всё просто. На практике же мы сталкиваемся со следующей проблемой: компьютер-то работает не с математическими формулами, а с числами.&lt;br /&gt;&lt;br /&gt;Но и тут проблема легко решается. Звуковая карта получает на вход последовательность чисел, задающих амплитуду через некоторые малые промежутки времени. Количество таких отсчетов амплитуды в секунду называется частотой дискретизации. Типичное значение — это 44100 Гц. Почему именно такое число? Дело в том, что человек может слышать звуки с частотой не выше ≈20000 Гц. А по теореме Котельникова, чтобы точно передать сигнал с какой-то частотой, нужна минимум в два раза большая частота дискретизации. Хотя, для низких звуков такая высокая частота — излишество.&lt;br /&gt;&lt;br /&gt;Другие важные параметры — это разрядность и количество каналов (моно, стерео).&lt;br /&gt;&lt;br /&gt;Разрядность говорит, сколько бит тратится на один отсчет амплитуды. Чем больше разрядность, тем точнее передается звук. Но для обычных нужд хватит и 16 бит, то бишь двух байт. Тут возникает такой вопрос: а как хранить эти два байта? Сначала старший или младший? Это &lt;a href=&quot;http://ru.wikipedia.org/wiki/%C3%90%C2%9F%C3%90%C2%BE%C3%91%C2%80%C3%91%C2%8F%C3%90%C2%B4%C3%90%C2%BE%C3%90%C2%BA_%C3%90%C2%B1%C3%90%C2%B0%C3%90%C2%B9%C3%91%C2%82%C3%90%C2%BE%C3%90%C2%B2&quot;&gt;старая компьютерная проблема&lt;/a&gt;. Я же решил не заморачиваться и сначала помещаю младший байт, а потом старший (так называемый little-endian порядок байтов). Для указания, что используется именно такой параметр, соответствующему полю структуры, отвечающей за формат сигнала присваивается значение AO_FMT_LITTLE.&lt;br /&gt;&lt;br /&gt;Разбить двубайтовой целое на два однобайтовых легко. Для этого можно использовать побитовое И с числом 0xFF. Это даст младщий байт, так как старшие биты будут умножены на 0. А потом можно сдвинуть все старшие биты в исходном числе на 8 бит влево и повторить процедуру.&lt;br /&gt;&lt;br /&gt;Для 16 битного звука значения амплитуды должны быть в диапазоне от -32768 до 32767. Эти крайние величины соответствуют максимальной громкости. Если нужен звук потише, то амплитуду можно уменьшить. Амплитуда, равная 0 — это тишина.&lt;br /&gt;&lt;br /&gt;Если мы хотим выводить звук в несколько каналов, то значения амплитуды для каждого из них чередуются.&lt;br /&gt;&lt;br /&gt;Итак, как издать звук. Для этого в памяти создается буфер, чтоб не отправлять каждый байт поодиночке. Буфер должен иметь размер t×F×b, где t — это время звучания, F — частота дискретизации, а b — разрядность в байтах. Потом мы в цикле записываем значения синусоиды с нужной частотой и амплитудой. А затем всё это дело выводится на устройство. Подробности можно посмотреть в коде программы.&lt;br /&gt;&lt;br /&gt;Когда класс готов, можно заняться самой пищалкой. В ней просто несколько раз повторяется звук  с частотой 880 Гц (это ля второй октавы) и длительностью 0,3 с. Пауза между звукам — 0,2 с. По умолчанию сигнал повторяется 20 раз (то есть 20/(0,3+0,2)=10 с), но можно передать нужную дительность как параметр командной строки.&lt;br /&gt;&lt;br /&gt;Как видно, работа с классом очень проста и функция main выглядит ясной и чистой.&lt;br /&gt;&lt;br /&gt;После того, как программа скомпилирована, её можно поместить, например, в /usr/local/bin или создать deb-пакет, чтоб потом можно было поделиться с друзьями.&lt;br /&gt;&lt;br /&gt;Использовать её просто. Например, нужно подать сигнал в 12:30, а исполняемый файл называется beep. Тогда пишем следующее:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;echo &quot;beep&quot; | at 12:30&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Если beep лежит в домашней папке, то не забываем указать путь:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;echo &quot;~/beep&quot; | at 12:30&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;У at очень гибкий формат указания времени исполнения, так что рекомендую заглянуть в man.&lt;br /&gt;&lt;br /&gt;Можно также всё это оформить в виде скрипта:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;echo &quot;~/beep&quot; | at $@&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;$@ — это специальная переменная, хранящая параметры, переданные скрипту. Так что можно будет просто написать, например:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;alarm.sh 12:30&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;А вот вся программа в одном файле.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#include &amp;lt;ao/ao.h&amp;gt;&lt;br /&gt;#include &amp;lt;cmath&amp;gt;&lt;br /&gt;#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;&lt;br /&gt;#define BITS       16&lt;br /&gt;#define CHANNELS   1&lt;br /&gt;#define RATE       22050&lt;br /&gt;&lt;br /&gt;class Beeper {&lt;br /&gt;private:&lt;br /&gt;ao_device *device;&lt;br /&gt;int driver;&lt;br /&gt;ao_sample_format format;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;Beeper() {&lt;br /&gt; ao_initialize();&lt;br /&gt; this-&amp;gt;driver = ao_default_driver_id();&lt;br /&gt;&lt;br /&gt; this-&amp;gt;format.bits = BITS;&lt;br /&gt; this-&amp;gt;format.channels = CHANNELS;&lt;br /&gt; this-&amp;gt;format.rate = RATE;&lt;br /&gt; this-&amp;gt;format.byte_format = AO_FMT_LITTLE;&lt;br /&gt;&lt;br /&gt; this-&amp;gt;device = ao_open_live(driver, &amp;amp;format, NULL);&lt;br /&gt; if (this-&amp;gt;device == NULL)&lt;br /&gt;     exit(1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void operator() (double freq, double time, double volume = 0.75) {&lt;br /&gt; int buf_size = static_cast&amp;lt;int&amp;gt;(this-&amp;gt;format.bits/8 * this-&amp;gt;format.channels * this-&amp;gt;format.rate * time);&lt;br /&gt; char *buffer = new char[buf_size];&lt;br /&gt; int sample;&lt;br /&gt;&lt;br /&gt; for (int i = 0; i &amp;lt; this-&amp;gt;format.rate * time; i++) {&lt;br /&gt;     for (int c = 0; c &amp;lt; this-&amp;gt;format.channels; c++) {&lt;br /&gt;         sample = static_cast&amp;lt;int&amp;gt;(volume * (1&amp;lt;&amp;lt;(this-&amp;gt;format.bits - 1)) * sin(2 * M_PI * freq * ((float) i/format.rate)));&lt;br /&gt;         for (int j = 0; j &amp;lt; this-&amp;gt;format.bits/8; j++) {&lt;br /&gt;             buffer[this-&amp;gt;format.bits/8*i*this-&amp;gt;format.channels + this-&amp;gt;format.channels*c + j] = sample &amp;amp; 0xff;&lt;br /&gt;             sample &amp;gt;&amp;gt;= 8;&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt; ao_play(device, buffer, buf_size);&lt;br /&gt; delete[] buffer;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;~Beeper() {&lt;br /&gt; ao_close(device);&lt;br /&gt; ao_shutdown();&lt;br /&gt;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt;Beeper b;&lt;br /&gt;&lt;br /&gt;int count = (argc == 1) ? 20 : atoi(argv[1]);&lt;br /&gt;&lt;br /&gt;for (int i=0; i &amp;lt; count*2; i++){&lt;br /&gt; b(880.0, 0.3);&lt;br /&gt; b(0.0, 0.2);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Компилируется командой&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;g++ -lao -o beep beep.cpp&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вот, вкратце всё. Не забываем покритиковать! ;)&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/6371896629128644776/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/blog-post.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/6371896629128644776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/6371896629128644776'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/07/blog-post.html' title='Пишем пищалку для будильника'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4154333943174084921.post-2575905393194774640</id><published>2009-05-06T00:07:00.007+03:00</published><updated>2009-07-18T23:38:20.295+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="linux"/><title type='text'>Ввод специальных символов или «типографские раскладки»</title><content type='html'>Наверняка многие пользователи хотели бы вводить различные специальные символы вроде кавычек-ёлочек («») или длинного тире (—) простыми сочетаниями клавиш, но не знают как. И остается им облизываться на &lt;a rel=&quot;nofollow&quot; href=&quot;http://ilyabirman.ru/typography-layout/&quot;&gt;раскладку Бирмана&lt;/a&gt;, для которой в Windows есть удобный установочный пакет. Либо копаться по форумам и выполнять загадочные действия: что-то скачивать, что-то где-то править в здоровенном xml-файле. А то и вовсе использовать старую добрую таблицу символов.&lt;br /&gt;&lt;br /&gt;Однако, всё что нужно, уже может быть в вашем дистрибутиве!&lt;br /&gt;&lt;span class=fullpost&gt;&lt;br /&gt;Дело в том, что существуют специальные клавиатурные раскладки, позволяющие вводить спецсимволы при помощи нажатия особой клавиши одновременно с какой-то из обычных клавиш клавиатуры. Например, после нажатия правого Alt и &gt; получается знак ». Всё просто и легко запоминается (» похожа на &gt;). Такие раскладки и называются типографскими.&lt;br /&gt;&lt;br /&gt;К сожалению, я сейчас использую только Ubuntu 9.04 и не могу сказать, верно ли сказанное в других дистрибутивах.&lt;br /&gt;&lt;br /&gt;В старых версиях для того, чтобы использовать все возможности и удобства расширенной раскладки, мне пришлось (по совету с какого-то сайта) править несколько файлов со списками раскладок, что неудобно, да и неправильно, так как эти файлы принадлежали пакету xkb-data.&lt;br /&gt;&lt;br /&gt;После установки Ubuntu 9.04, я хотел было уже опять искать в сети способ включить типографскую раскладку, но тут случайно обнаружил, что всё уже есть в самой системе. Достаточно лишь зайти в настройки клавиатуры («Система» → «Параметры» → «Клавиатура» → вкладка «Раскладки» → «Параметры раскладки») и включить соответствующую галочку.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18877/screenshot_001_wkviec_i6Jecr.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18877/screenshot_001_wkviec_i6Jecr.png&quot; border=&quot;0&quot; alt=&quot;Настройка раскладки&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Теперь пару слов о том, как же теперь эти символы вводить. В качестве «волшебной клавиши» для ввода по умолчанию используется правый Alt, но это можно изменить в том же окне в разделе «Key to choose 3rd level».&lt;br /&gt;&lt;br /&gt;Раскладка, конечно не такая богатая, как некоторые другие, но всё, что нужно позволяет легко вводить. Вот несколько полезных сочетаний:&lt;br /&gt;&lt;br /&gt;Alt-&gt; »&lt;br /&gt;Alt-&lt; «&lt;br /&gt;Alt-- —&lt;br /&gt;Alt-. …&lt;br /&gt;&lt;br /&gt;Остальные можно посмотреть, распечатав раскладку в том же окне настроек клавиатуры.&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18878/screenshot002x_2Nl6Qp.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18878/screenshot002x_2Nl6Qp.png&quot; border=&quot;0&quot; alt=&quot;Русская раскладка со спецсимволами&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Несколько слов для тех, кто не хочет или не может пользоваться гномовским клавиатурным настройщиком. Активировать расширенные раскладки можно командой setxbmap. Пример того, как это сделать, я подсмотрел на сайте Сергея Столярова.&lt;br /&gt;&lt;pre&gt;setxkbmap -option grp:caps_toggle -option grp_led:caps -layout us+typo,ru:2+typo&lt;/pre&gt;&lt;br /&gt;Эта команда задаёт способ переключения (grp:capstoggle, т.е. клавишей Caps Lock), индикатор, используемый для отображения раскладки (grpled:caps, т.е. индикатор Caps Lock), а также непосредственно раскладки (us+typo и ru:2+typo). Как можно заметить, слой с дополнительными символами добавляется к обеим раскладкам (us и ru).&lt;br /&gt;&lt;br /&gt;Если вы используете другой способ настройки XKB, то вы должны там заменить us на us+typo и ru на ru:2+typo.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Upd.&lt;/b&gt; Я забыл упомянуть (спасибо пользователю &lt;a rel=&quot;nofollow&quot; href=&quot;http://welinux.ru/user/konkere&quot;&gt;konkere&lt;/a&gt; за подсказку) о другом, даже более мощном штатном способе ввода спецсимволов — &lt;a rel=&quot;nofollow&quot; href=&quot;http://ru.wikipedia.org/wiki/Compose&quot;&gt;клавише Compose&lt;/a&gt;. О нём довольно много написано в интернете, поэтому отсылаю читателя к википедии и гуглу. Скажу лишь о некоторых недостатках этого способа.&lt;br /&gt;&lt;br /&gt;Чтобы ввести сочетание Compose + &gt; + &gt; нужно переключаться в английскую раскладку, так как в русской нет символа &gt;. (Имеется в виду обычная русская раскладка, которую можно видеть на клавиатуре. Расширенная русская позволяет вводить как &lt; и &gt; — Alt-Shift-б и Alt-Shift-б — так и квадратные и круглые скобки без дополнительных переключений.) Можно, конечно, использовать ~/.XCompose, что было бы очень удобно, так как позволяет создавать свои раскладки, но в гномовских приложениях используется другой метод ввода и файл с настройками просто проигнорируется.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Upd. 2&lt;/b&gt; Ещё рекомендую включить опцию «Unicode additions».&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.ubuntu-pics.de/bild/18879/screenshot_001_r4v2nv_nOg5yA.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;http://www.ubuntu-pics.de/thumb/18879/screenshot_001_r4v2nv_nOg5yA.png&quot; border=&quot;0&quot; alt=&quot;Включение Unicode additions&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Тогда можно будет указанным выше способом вводить при помощи цифровой клавиатуры стрелки (←→⇐⇒) и некоторые математические операторы (⋅×÷).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Upd. 3&lt;/b&gt; Пользователь &lt;a rel=&quot;nofollow&quot; href=&quot;http://welinux.ru/user/pluton&quot;&gt;pluton&lt;/a&gt; натолкнул меня на мысль об еще одном способе ввода символов — по их коду в Unicode. Для этого нужно нажать Ctrl-Shift-U. Появится маленькая подчеркнутая буква &lt;u&gt;u&lt;/u&gt;, после которой нужно ввести 16-ричный код символа и нажать пробел. К сожалению, использовать этот способ для ввода текстов в Firefox не получится, так как там это сочетание клавиш, по-видимому, уже используется для отображения исходного кода посещённой страницы. Но в текстовых редакторах (например в gedit) этот способ может пригодиться (если, конечно, вы помните все коды Unicode ;)).&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://strange-to-say.blogspot.com/feeds/2575905393194774640/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://strange-to-say.blogspot.com/2009/05/blog-post.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/2575905393194774640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4154333943174084921/posts/default/2575905393194774640'/><link rel='alternate' type='text/html' href='http://strange-to-say.blogspot.com/2009/05/blog-post.html' title='Ввод специальных символов или «типографские раскладки»'/><author><name>Вадим</name><uri>http://www.blogger.com/profile/03928284652612977325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='30' height='32' src='http://1.bp.blogspot.com/_hRyhd7EUrGc/Sk5VleynHlI/AAAAAAAAAfE/ucW5wDwhBPw/S220/my_avatar.gif'/></author><thr:total>1</thr:total></entry></feed>