〜2014年6月中旬〜
dcだよなと思ったが、seqで攻めた。最初は
read n;seq $n $[n+9]
としていたが、苦肉の策で1バイト縮めた。
seq $[{n=`dd`,n+9}]
これはzshで動かない。bashは先に{}を展開するがzshはどうも展開しないようで。
つまりbashでは
seq $[n=`dd`] $[n+9]
と書いたのと同じ。一見
seq $[`dd`{,+9}]
でいいんじゃないかと思えるが、これは
seq $[`dd`] $[`dd`+9]
と展開されるのでだめ。``の評価のほうが後になる。
% echo 1 | bash -c 'seq $[{n=`dd`,n+9}]' 0+1 records in 0+1 records out 2 bytes (2 B) copied, 0.000137874 s, 14.5 kB/s 1 2 3 4 5 6 7 8 9 10 % echo 1 | zsh -c 'seq $[{n=`dd`,n+9}]' 0+1 records in 0+1 records out 2 bytes (2 B) copied, 0.000134562 s, 14.9 kB/s zsh:1: bad math expression: illegal character: {
というわけで、zshのほうが1バイト多い。
dcを使っても?をquoteしなきゃいけなくて1バイト差が出てるのが面白い。
よく見かけるchopとflip flopの組み合わせ。
-chop ${LEFT}x${TOP} -flip -flop \ -chop ${RIGHT}x${BOTTOM} -flip -flop \
同じ-chopなのにこれはどういうことなのか。
flip flopってなんだっけと調べたらflipが上下反転、flopが左右反転。
% convert label:abc -flip x: % convert label:abc -flop x:
とすると確認できる。つまり意味的には
-chop ${LEFT}x${TOP} \ -flip -flop -chop ${RIGHT}x${BOTTOM} -flip -flop \
なんだな。上下左右を反転させることで左上と右下が入れ替わる。
だから左上しか指定できない-chopが使えると。ということは180度回転でもいいわけだ。
-chop ${LEFT}x${TOP} \ -rotate 180 -chop ${RIGHT}x${BOTTOM} -rotate 180 \
kindlizeは-gravityを使ってるようだ。賢い。
-chop #{LEFT}x#{TOP} \ -gravity SouthEast -chop #{RIGHT}x#{BOTTOM}\ -gravity NorthWest
convertした結果をそのままpipeでoptipngに渡したいなんてことを考えてみたが受けつけてくれない。
むりやり/dev/stdinを使っても
% convert in.jpg png8:- | optipng -out out.png /dev/stdin ** Processing: /dev/stdin Error: Can't ftell in input file stream ** Status report 1 file(s) have been processed. 1 error(s) have been encountered.
と言われてしまう。<()を使っても同じだ。
% optipng -out out.png <(convert in.jpg png8:-) ** Processing: /proc/self/fd/11 Error: Can't ftell in input file stream ** Status report 1 file(s) have been processed. 1 error(s) have been encountered.
どっちしてもseekできないとだめってことなので、ファイルにせざるを得ない。
zshなら=()にすればいける。
% optipng -out out.png =(convert in.jpg png8:-) ** Processing: /tmp/zsh1oY1na 200x200 pixels, 8 bits/pixel, 182 colors in palette Reducing image to 8 bits/pixel, grayscale Input IDAT size = 2110 bytes Input file size = 2938 bytes Trying: zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 1804 zc = 9 zm = 8 zs = 1 f = 0 IDAT size = 1723 Selecting parameters: zc = 9 zm = 8 zs = 1 f = 0 IDAT size = 1723 Output file: out.png Output IDAT size = 1723 bytes (387 bytes decrease) Output file size = 1994 bytes (944 bytes = 32.13% decrease)
/tmp/zsh1oY1naと表示されているように一時ファイルを作ってくれる。
=()って何のためにあるのかと思ったが、こういうときのためにあるんだな。
ipv6がどうのこうの。
% zsh -c 'printf "%04s\n" "ab"' ab % bash -c 'printf "%04s\n" "ab"' ab % /usr/bin/printf "%04s\n" "ab" /usr/bin/printf: %04s: 無効な変換指定です zsh: exit 1 /usr/bin/printf "%04s\n" "ab" % ruby -e 'printf("%04s\n", "ab")' ab % ruby -e 'printf("%04s\n", "ab")' ab % awk 'BEGIN{printf("%04s\n", "ab")}' ab % python -c 'print "%04s" % "ab"' ab % perl -e 'printf("%04s\n", "ab")' 00ab
Perlだけ気が利いている。Rubyなら
% ruby -e 'puts "ab".rjust(4, "0")' 00ab
という手もあるが。
chopを2回しなくてもshaveなんてオプションがあった。
しかしこれは左と右、上と下は同じ量だけ削られる。別々に指定できない。
-shave 20x10と書いた場合、左右は両方とも20、上下は両方とも10削られる。
スキャンした結果だとそんな都合よく対称にはならないのでなかなか使いづらそう。
sqliteのダウンロードページに行っても3.7あたりの古いソースはもう見当たらない。
以前は http://www.sqlite.org/sqlite-3.7.2.tar.gz とすごいところに置いてあったので、
直接指定してみたらまだあった。3.6.23もあった。
以前横向きでスキャンした画像を
90度回転して元に戻す処理を書いた。
シェルスクリプトなのでwindowsだと使えないが、
convertにはfxがあるのでその処理を吐かせればいいんだと気づいた。
% convert 00?.png -format "convert %f -rotate %[fx:t%2?90:-90] -verbose /tmp/%f" info: convert 001.png -rotate -90 -verbose /tmp/001.png convert 002.png -rotate 90 -verbose /tmp/002.png convert 003.png -rotate -90 -verbose /tmp/003.png convert 004.png -rotate 90 -verbose /tmp/004.png convert 005.png -rotate -90 -verbose /tmp/005.png convert 006.png -rotate 90 -verbose /tmp/006.png convert 007.png -rotate -90 -verbose /tmp/007.png convert 008.png -rotate 90 -verbose /tmp/008.png convert 009.png -rotate -90 -verbose /tmp/009.png
fx内のtは画像リストのインデックス(0から)になっている。
Cでお馴染の?:も使えるので偶数奇数で-90度/90度と回転させればいい。
これをリダイレクトしてバッチにすればwindowsでも実行可能だ。
Linuxでもこのままshに食わせてもいいが、parallelに食わせると時短になる。
% convert 00?.png -format "convert %f -rotate %[fx:t%2?90:-90] -verbose /tmp/%f" info: | parallel 002.png=>/tmp/002.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit DirectClass 41KB 0.090u 0:00.100 003.png=>/tmp/003.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 90.1KB 0.110u 0:00.119 004.png=>/tmp/004.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 41KB 0.170u 0:00.169 005.png=>/tmp/005.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 32.8KB 0.080u 0:00.079 007.png=>/tmp/007.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 41KB 0.090u 0:00.079 006.png=>/tmp/006.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 45.1KB 0.190u 0:00.190 001.png=>/tmp/001.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit DirectClass 1.38MB 0.330u 0:00.339 009.png=>/tmp/009.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 45.1KB 0.080u 0:00.070 008.png=>/tmp/008.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 32.8KB 0.170u 0:00.179
xargsは引数を省略すると/bin/echoを呼ぶが、parallelは実行する。ここが大きな違い。
% convert 00?.png -format "convert %f -rotate %[fx:t%2?90:-90] -verbose /tmp/%f" info: | xargs -P5 -I@ sh -c @ 003.png=>/tmp/003.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 90.1KB 0.110u 0:00.150 005.png=>/tmp/005.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 32.8KB 0.080u 0:00.169 002.png=>/tmp/002.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit DirectClass 41KB 0.080u 0:00.159 007.png=>/tmp/007.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 41KB 0.090u 0:00.080 006.png=>/tmp/006.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 45.1KB 0.180u 0:00.219 004.png=>/tmp/004.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 41KB 0.170u 0:00.449 009.png=>/tmp/009.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 45.1KB 0.090u 0:00.119 008.png=>/tmp/008.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit PseudoClass 255c 32.8KB 0.170u 0:00.260 001.png=>/tmp/001.png PNG 1081x714=>714x1081 714x1081+0+0 8-bit DirectClass 1.38MB 0.310u 0:00.519
とすればxargsでもパラで実行可能。
使い始めたはいいが、local mailが届かなくなって困った。
SMTP clientなんだから当たり前なんだけど、
そのためにlocalでSMTP server立てるんじゃ意味ないしねえ。
local mailと言ってもcronの結果ぐらいでいいんだけど。
しかたないので~/.msmtprcで
aliases ~/etc/aliases
として、~/etc/aliasesで
eban: gmailアドレス
とした。crontabでなにか吐かれるとそっちに飛ぶ。
Rainlendarがicsを読み込んでくれるので、
これをタスクスケジューラで30分おきに動かすといい感じ同期できる。
ただ、場所情報がないのが痛い。これだけのためにoutlookを起動しないといけない。
AppointmentItem Members (Outlook)を見るとLocationで取れそうだし、他にも情報を入れられそう。
ただVBSだけにちょっといじりにくい。
Rubyのwin32oleでいけるのか?
結局Rubyで書いた。
#! /usr/bin/ruby # -*- coding: utf-8 -*- require 'win32ole' require 'date' olFolderCalendar = 9 WIN32OLE.codepage = WIN32OLE::CP_UTF8 ol = begin WIN32OLE.connect("Outlook.Application") rescue WIN32OLE.new("Outlook.Application") end items = ol.Session.GetDefaultFolder(olFolderCalendar).Items items.Sort "[Start]" items.IncludeRecurrences = true now = Time.now seven = now + 7 * 24 * 60 * 60 body = <<'EOT' BEGIN:VCALENDAR BEGIN:VTIMEZONE TZID:Asia/Tokyo BEGIN:STANDARD TZOFFSETFROM:+0900 TZOFFSETTO:+0900 TZNAME:JST DTSTART:19700101T000000 END:STANDARD END:VTIMEZONE EOT count = 0 STATUS_VALUES = ["CANCELLED", "TENTATIVE", "CONFIRMED"] filter = "[Start] >= '#{now.strftime("%Y/%m/%d %H:%M")}'" + " AND [End] <= '#{seven.strftime("%Y/%m/%d")}'" + " AND [BusyStatus] > 0" e = items.Find(filter) while e valarm = 1 < e.BusyStatus && now < e.Start ? <<'EOT' : "" BEGIN:VALARM ACTION:DISPLAY TRIGGER;VALUE=DURATION:-PT5M END:VALARM EOT body << <<"EOT" BEGIN:VEVENT UID:#{count+=1} SUMMARY:#{e.Subject} [#{STATUS_VALUES[e.BusyStatus][0,2]}] DTSTART;TZID=Asia/Tokyo:#{e.Start.strftime("%Y%m%dT%H%M%S")} DTEND;TZID=Asia/Tokyo:#{e.End.strftime("%Y%m%dT%H%M%S")} LOCATION:#{e.Location} STATUS:#{STATUS_VALUES[e.BusyStatus]} #{valarm}END:VEVENT EOT e = items.FindNext end body << "END:VCALENDAR\n" ARGV[0] ? IO.write(ARGV[0], body) : puts(body)
最初はicalendar gemを使ったけど、やたらと遅いのでもう直接展開することにした。
WIN32OLE.codepage = WIN32OLE::CP_UTF8とするとutf-8で処理できる。
これはfilterの中身とかもutf-8で書けるので便利。
" AND [Subject] <> '昼休み'" +
のようにすれば表示したくない処理も簡単に追加できる。
" AND [BusyStatus] > 0"
はキャンセルした予定はうっとしいので表示しないという意味。
あと一律5分前にアラーム設定。これで結構いい感じで使えるようになった。