日々のメモ書き
Debian Developerが綴るメモ
ReportLabのPDFの明朝がゴシックで表示される
evinceで日本語の入ったPDFを表示させると明朝がゴシックになるという話があって、それはfont-mangerの設定ファイルを編集しろという話はすぐにみつかって、まあ、dvipdfmxで作ったPDFはそれで表示される。バグ登録もされているようだがなかなか直ってないのはなんでだろうとか思うがまあいい。
がReportaLabで作った場合はCIDフォント(HeiseiMin-W3)を指定しているせいなのかその設定がわからない。Acrobat Readerではきちんと明朝体で表示されるので指定が間違っているわけではない。ごちゃごちゃlocal.confを設定してみたがよくわからない。どうでもいいところで進まねえよ。
Shift JISのHTMLを読む前に
引き続きHXTでスクレイピングの話。対象ファイルがShift JISなのでText Nodeの検索などを考えると素直にはいかない。結局IConvを使って変換することに。以下のようなコードになる。
import Codec.Binary.UTF8.String import Codec.Text.IConv import Data.List import Text.XML.HXT.Core import qualified Data.ByteString.Lazy as BSL main = do cs <- BSL.readFile "shiftjis.html" let u8s = convert "CP932" "UTF-8" cs let html = decode (BSL.unpack u8s) let doc = readString [withParseHTML yes, withWarnings no] html nodes <- runX $ doc //> hasText (isInfixOf "日") mapM_ (putStrLn . show) nodes
GHCのString(=[Char])は内部エンコーディングにUCS-4が使われていらしいがソースコードがutf-8なら認識はしてくれる。
IConvはByteStringを直接扱っているがそのバイト列のエンコーディングをプログラマが意識しなければならない。この点はHaskellの型を使わない実装というのはあまり良くないと思う。UTF-8の入ったByteStringとEUC-JPの入ったByteStringを混ぜることができるなんて恐しい…。
urlopenのバグを追い掛けて
Pythonのurllib.urlopenが一部の HTTPS 接続がタイムアウトする問題を調べていたが、予想していた通りOpenSSLの問題。
openssl s_client -connect sslsite.example.com:443
とエラーが出るサイトがやるとやはり繋がらない。gnutls-cliだと問題なく繋がるからサーバ側の問題ではない。
ごちゃごちゃ探してみたが NetBSD でも同じバグレポートが。TLS1.2をs_clientで無効にするという話が出ている。というかUbuntuでも報告されてパッチ当たってるじゃねえか。Debian側のメンテナがどういう方針かしらんがしばらくすれば直ることは直るんだろう。たしかにopenssl s_client でも -tls1 とか -ssl3 とか付ければ大丈夫な感じだ。でもOpenSSLが直るまでまで自分の開発が止まっちゃうよ。
追記: 当たり前だがRubyのopen-uriでも再現するな。
製品レビュー: サワートレッカー
モンベルの沢靴のサワートレッカーの感想である。買ったのは2011年で去年は使用する機会がなかった。多分あまり2012年もモデルチェンジはしてないと思うのだが一応注意。
今年数回の沢で使ってみた。一応大きな破綻もなく使えている。縫製がいきなりほつれるということもない。ただ靴の幅がひろいのでつま先が下がる場面で親指がつっこんで痛いことがある。これは足型が合わないのでどうしようもない。靴紐をかなりしめても足型の問題でどうにもならない。もっと細い靴をどこか出してくれないかな。
この靴の特徴としてベロの部分が完全に縫い付けられていることが上げられる。足首のホールドまで完全に一体化しているので沢の中を歩いていても靴の中に小石が入ることはほぼ無い。が、着脱がかなり力入れてやらないとできない。そんなことするのは朝晩だけなのであきらめろという話だ。それでも構造的に仕方がないのはわかるけどなんとかならないかと思う。
使用しての1年目としては特に不満もなく使えているというところ。
WordPressをテスト
世間並にWordPressを少しテスト。
Apacheの設定ファイルを設定して、mysqlのデータベースを作成。WordPressの設定ファイルを入れて動かしてみる。まあ動くのはすぐに動く。
問題はプラグインを入れようとしたとき。/var/lib/wordpress/wp-content/plugins に入れているはずなのに表示されない。おかしいなと /usr/share/wordpress/wp-content/plugins に入れたら表示される。WP_CONTENT_DIR の設定が /var/lib/wordpress に向いていない。/usr/share/wordpress/wp-config.php にはきちんと設定されているようなんだが…。また考えよう。
GtkStatusIcon に文字を表示させる
Pythonでやったがどの言語でも似たような話。
GtkStatusIcon に画像は表示できるが直接文字を表示させられない。GtkWidget なら Cairo を使って文字を表示させるが GtkStatusIcon は GtkWidget のサブクラスではない。
ということで貼り付ける画像に文字を書き込んで画像を更新するということになる。ただ GtkStatusIconは Cairo で描いたものを渡すことはできない。受け取るのは Pixbuf。流れとしては背景となるPNGファイルから ImageSurface を作り CairoContext を使って文字を書き込む。そのあと ImageSurface を Pixbuf に変換して GtkStatusIcon に渡す。次のようなコードとなる。
image = cairo.ImageSurface.create_from_png(ICON_PATH) width = pngimage.get_width() height = pngimage.get_height() cr = cairo.Context(image) cr.set_font_size(128) cr.move_to(0,128 ) cr.show_text("1234") cr.move_to(0,256 ) cr.show_text("ABC") pixbuf = Gdk.pixbuf_get_from_surface(pngimage,0,0,width,height) statusicon.set_from_pixbuf(pixbuf)
GtkStatusIcon は直接PNGファイルを渡すことができるので Cairo.ImageSurface.write_to_png ファイルに書き出してできないこともないがそんなことはやりたくなかった。StringIO を使ってできないかと思ったが Gtk.StatusIcon.set_from_file はファイルハンドラは受け取らずパスのみだったのでできず。
queryのparse
Haskellで低レベルなGETによるクエリのパースの処理について。
Network.HTTP.Types にある parseQuery か parseSimpleQuery を使う。この二つの違いは、例えば "?a=b&c"とあったときに parseQueryだと [("a", Just "b"),("c", Nothing)] となるが parseSimpleQuery だと [("a", "b"), ("c","")] となる。ちなちみに両方ともStringではなくてByteStringを受け取るのでpackするなり注意。
必要なパラメータだけ取り出す場合は Data.Map.fromList を使って Map に変換して扱うのががわかりやすいが(追記: Data.List.lookupを使うのもいいが)、同じパラメータ名が二つ以上あったときにどうするかというのがあるなあ…。
HXTでスクレイピング
ほんとはHaskellでスクレイピングを書きたかったので頑張ってみる。TagSoupは使い方がまだよく理解してないのでHXTで。HXTはStringしか受け付けないのが面倒だな。Data.ByteString.Char でファイルを読み込んでからunpackするのが必要だ。
同じくリンク先にfooが含まれるものの一覧を作成する。
import Text.XML.HXT.Core import Data.List import qualified Data.ByteString.Char8 as BSC main = do html <- BSC.readFile "index.html" let doc = readString [withParseHTML yes, withWarnings no] (BSC.unpack html) links <- runX $ doc //> hasName "a" >>> hasAttrValue "href" (isInfixOf "foo") >>> getAttrValue "href"
mapM_ putStrLn links
BeautifulSoupでスクレイピング
少しだけテスト。
from bs4 import BeautifulSoup import re import urlparse soup = BeautifulSoup(file('index.html')) tags_a = soup.findAll('a', href=re.compile('.*foo.*')) for i in tags_a: print i.get('href') print i.get_text().encode('utf-8')
これでURLにfooが含まれるリンク先の取得して一覧にして表示。
ワールドカップ予選突破まで勝ち点はあと何点?
ちょっと怪しいながらもイラクに勝ってほっと安心。前のイラクの試合を見たときはジーコらしいぐだぐだな試合をしていたので楽勝かと思ったらちゃんとしたサッカーになっていたので何が起こったんでしょうか?日本はボランチとCBの補強が課題。今は大丈夫でも2年後を考えるとなんとしても次が来てもらわないと困ります。
さて、いつになったら安心できるのかということでちょっと勝ち点を計算してみました。単純に残りの12試合の全ての勝敗パターン(3^12=531441)を計算してみただけです。3位でもプレーオフはありますが考慮せず、勝敗がランダムに発生し得失点差は日本が不利だと仮定して計算すると日本が勝ち抜けできないパターンは40969パターンあり、つまり7.7%になります。よほどのことがないかぎり問題がないということですね。
あと何勝すれば勝ち抜けなのか?ちなみにオーストラリア残り5連勝などということが起これば勝ち点16でも敗退するパターンが6あります。つまり理論的には勝ち抜けには17点が必要になります。逆に言えば一敗は問題ありません。現実問題として二敗しても大丈夫ということがわかります。
早く確定するといいですね。10/16の試合が終わったらまた計算結果を出します。
あと計算につかったプログラムを残しておきます。
import Control.Monad import Data.List data Country = Japan | Jordan | Australia | Oman | Iraq deriving (Eq,Show) data Result = HomeWin | Draw | AwayWin deriving (Eq,Show) countries = [Japan, Jordan , Australia, Oman, Iraq] countryPriority :: Country -> Int countryPriority x | x == Japan = 0 | otherwise = 5 matchDone = [ ((Japan,3),(Oman,0)) , ((Jordan,1),(Iraq,1)) , ((Japan,3),(Jordan,0)) , ((Oman,1),(Australia,1)) , ((Australia,1),(Japan,1)) , ((Iraq,1),(Oman,1)) , ((Japan,3),(Iraq,0)) , ((Jordan,3),(Australia,0)) ] matchLeft = [ (Oman, Jordan) , (Iraq, Australia) , (Iraq, Jordan) , (Oman, Japan) , (Australia, Oman) , (Jordan, Japan) , (Japan, Australia) , (Oman, Iraq) , (Iraq, Japan) , (Australia, Jordan) , (Jordan, Oman) , (Australia, Iraq) ] leftPattern = replicateM leftMatchNum [HomeWin, Draw, AwayWin] leftMatchNum = length matchLeft resultToPoint :: ((Country, Country), Result) -> ((Country, Int),(Country, Int)) resultToPoint ((x,y), r) | r == HomeWin = ((x,3),(y,0)) | r == AwayWin = ((x,0),(y,3)) | r == Draw = ((x,1),(y,1)) resultToPointPattern :: [Result] -> [((Country, Int), (Country, Int))] resultToPointPattern result= map resultToPoint (zip matchLeft result) calcPoint :: [((Country, Int), (Country, Int))] -> Country -> (Country, Int) calcPoint pp c = (c, sum $ (map (snd . fst) $ filter (\x@(h,a) -> fst h == c ) pp) ++ (map (snd . snd) $ filter (\x@(h,a) -> fst a == c ) pp)) resultCompare :: (Country, Int) -> (Country, Int) -> Ordering resultCompare (c1,r1) (c2,r2) | r1 > r2 = LT | r1 < r2 = GT | r1 == r2 = compare (countryPriority c2) (countryPriority c1) orderByJapan :: [(Country,Int)] -> [(Country,Int)] -> Ordering orderByJapan x y = compare (fmap snd $ find (\a@(c,r) -> c == Japan) x) (fmap snd $ find (\a@(c,r) -> c == Japan) y) main = do let pointPattern = map (\pt -> sortBy resultCompare (map (calcPoint (matchDone ++ (resultToPointPattern pt))) countries) ) leftPattern let lossPattern = filter (\x -> not (elem Japan (map (\y@(c,r)->c) (take 2 x)))) pointPattern mapM_ print $ sortBy orderByJapan lossPattern print $ length lossPattern print $ (3 ^ leftMatchNum) print $ (fromIntegral (length lossPattern))/(3 ^ leftMatchNum)