Tkで発覚した衝撃の事実

最近のスクリプト言語PerlRubyPythonなど)はGUIを簡単に作れるよう標準でTkを搭載していることが多い。このTkというやつ、元はTclという言語のものだったということは広く知られている。だからTkってのはTclのいちライブラリであって、それを他のスクリプト言語に移植したもの、みたいな感じなんだろうなと自分はずっと思っていた。しかし実際は違った。これらはTclという言語も含めて導入されている。Tkを使ってGUIを作ろうとするとTclのコードが実行されてGUIが作られる。だから以下のようにTkを使わずTclの機能だけを使うこともできる。

# Python 3.2.2
import tkinter
t = tkinter.Tcl()
t.eval('puts {hello world}')
t.eval('set x 2')
t.eval('set x [expr $x + 3]')
t.eval('puts "2 足す 3 は $x です。"')

これを踏まえてTkinterのソースを読むと、Tkinterが抱えている色々な制限や奇妙な動作が少しは納得できる。

MyDefragがクラッシュ

System Disk Daily をやると途中で必ずクラッシュするようになってしまった。

エラー メッセージに書いてあるURLのページを見るとデバッグ版をインスコして詳細なレポートを採取し送れと書いてある。とりあえず手順に従ってみると MyDefrag.debuglog に詳細なログが出力されるようになった。しかしログを眺めて見ても何が悪いのかさっぱりわからん。関係ありそうな部分を適当にググってみると、なんか“Program hints”クラッシュなんじゃねとか言ってる。紹介先に書いてあることを試してみるとクラッシュしなくなった。このバグは次のバージョンで修正される予定らしいが、MyDefragはもう2年弱くらいバージョンアップが滞ってるよな。

追記(2012年12月1日)

よくわからんというコメントがあったので、当該部分を適当に翻訳しておいた。

プリフェッチファイルが古くなっていますね(program hints)。

しかしクラッシュはまずいです。このバグは既に把握済みで、次のバージョンで修正される予定です。


1. Windows\Prefetchフォルダーの中にあるファイルを全て削除してください。


2. おそらくタスクスケジューラーが無効になっているので、こうなってしまったのでしょう。タスクスケジューラーを有効にしてから、次のコマンドを管理者権限で実行してください。


rundll32 advapi32,ProcessIdleTasks


3. VistaWindows7を使っている場合は、Windowsを5回再起動します。するとブートトレースが作成されます。これらのOSでない場合は必要ありません。


4. MyDefragがクラッシュしなくなります。作成されたlayout.iniファイルとprogram hintsを使って、Windowsとアプリケーションが素早く起動するようファイルを並び替えられるようになります。

“Pythonはじめたんだがprint が失敗するんだが”って人へ

print が最初から使えなくなって困ってる人が多いようなので。

>>> print "hello world"
File "", line 1
print "hello world"
^
SyntaxError: invalid syntax

Python はバージョン 3.0 で後方互換性を切りました。これは Python の開発が始まって以来、初めてのことで初学者の間に多少混乱があるようです。

文法に互換性がないってことは、つまり 2.x 系統と 3.x 系統のどちらかを選ぶ必要があるってことです。

Python 2.x 時代の本やサイトを参考にしている人は 2.x を使う必要があります。Python 3.x に対応してる本は、たいてい Python 3 対応と書いてあります。

ちなみに 3.0 で導入された機能は互換性を破壊しない範囲で 2.6 にも導入されています。同様に 3.1 で導入された機能は 2.7 にも導入されています。しかし、2.8 はありません。2.x 系統は 2.7 で開発終了です。ただしバグの修正は続けられます。

結構重要なライブラリが未だに 3.x に対応してなくて困るってことが結構あるわけで、まだ両方使えたほうが捗ることは確か。違いは大したことないから心配すんな。

shopped とは

4chan で時々 “not shopped ○○” みたいな言葉を見かける。辞書を引いても検索してもそれらしい訳語が出てこなないので長い間「?」状態だったけだが、先ほどはたと気付いた。

Photoshop のことじゃないか。

つまり “not shopped ○○” は「Photoshop で修正されていない○○」って意味だ。名詞を動詞的に使っている。

少し違うが日本でも Photoshop のことを写真屋って言うしな。俗語はほんと難しい。

xyzzy のエンコーディング名指定は?

ここを参考に xyzzy のデフォルト エンコーディングを変更しようと思ったのだが BOM 付きの UTF-16 にするにはどうしたらいいのか書いてないな。

色々検索してみたがわからん。やっぱりコード関連で迷ったら grep (findstr) するのが手っ取り早いな。

D:\>cd \hoge\xyzzy

D:\hoge\xyzzy>findstr /s "*encoding-utf16" *.l
lisp\encoding.l:          *encoding-windows-turkish* *encoding-windows-baltic* *encoding-utf16*
lisp\encoding.l:          *encoding-utf16* *encoding-utf16le-bom* *encoding-utf16be-bom*
lisp\encoding.l:          *encoding-utf16le* *encoding-utf16be* *encoding-utf8* *encoding-utf8n*
(以下略)

この結果からエンコーディングは list\encoding.l で定義されていること、また BOM 付きの UTF-16 にするには *encoding-utf16le-bom* か *encoding-utf16be-bom* を指定すればいいことがわかった。

(setq *default-fileio-encoding* *encoding-utf16le-bom*)

エンディアンはメモ帳とおなじリトルエンディアンにしておいた。BOM 付いてるからどっちでもいいんだろうけど。

icmp.lib はなくなりました

http://www.geekpage.jp/programming/iphlpapi/send-icmp.php を参考に ping を送信するプログラムを書いてみたが、コンパイルできん。

foo.obj : error LNK2019: 未解決の外部シンボル _IcmpCloseHandle@4 が関数 _main で参照されました。
foo.obj : error LNK2019: 未解決の外部シンボル _IcmpSendEcho@32 が関数 _main で参照されました。
foo.obj : error LNK2019: 未解決の外部シンボル __imp__inet_addr@4 が関数 _main で参照されました。
foo.obj : error LNK2019: 未解決の外部シンボル _IcmpCreateFile@0 が関数 _main で参照されました。
foo.exe : fatal error LNK1120: 外部参照 4 が未解決です。

よく見ると icmp.lib をリンクするのを忘れていた。だが pragma を追加すると今度は別のエラー。

LINK : fatal error LNK1104: ファイル 'icmp.lib' を開くことができません。

icmp.lib でググると、もう必要がなくなったみたいなこと言ってる。

ひょっとして集録されている場所が変わったのかと思い、_IcmpCloseHandle でググると、やっぱり変更されてたわ。

Icmp.lib is no longer distributed since its contents have been included in iphlpapi.lib

http://www.codeguru.com/forum/showthread.php?t=241151

Icmp.lib はもう集録されてない。というのも、その内容は iphlpapi.lib に含まれているから。

iphlpapi.lib をリンクすればおk。

ブックマークの整理が終わった

溜まりに溜まったブックマークの整理が一段落した。

Firefox の場合、以下の場所に過去のブックマークが自動でバックアップされているようなので、どれくらい減ったのか調べてみた。

%AppData%\Mozilla\Firefox\Profiles\xxxxxxxx.default\bookmarkbackups

バックアップのファイル形式は JSON で、中身はフォルダの情報とブックマークの情報がごっちゃになっているが、基本的にはこんな感じ。さすがに適当すぎるか?

とりあえず object.type の種類だけ調べてカウントするコードを Python で書いた。

# Python 3.2.2
import sys
import json
import collections

def count(obj, table):
    table[obj['type']] += 1
    if 'children' in obj:
        for subobj in obj['children']:
            count(subobj, table)

def main():
    tree = json.load(open(sys.argv[1], encoding='utf-8'))
    table = collections.Counter()
    count(tree, table)

    for key in table:
        print(table[key], key)

if __name__ == '__main__':
    main()

結果こう↓だったのが、

7387 text/x-moz-place
104 text/x-moz-place-container

こう↓なった

4090 text/x-moz-place
70 text/x-moz-place-container

思ったより減ってないか。

そもそも何でブックマークを整理しようと思ったかというと、Firefox が重過ぎるからだ。Firefox はブックマークを溜めすぎるとブックマークの移動や削除にすごい時間がかかるようになる。その間 CPU はずっと 100% なので他の作業もできない。さすがにこれはまずいので整理することにした。少し前に Firefox は大量のタブを開いても重くならないように改修されたようだが、こっちの方も何とかしてくれないかな。

追記(2012-02-06)

よく考えたら CheckPlaces でも同じ情報が取れるので、わざわざコードを書く必要はなかったなな。

追記(2012-02-11)

よく考えたらアドオンいれなくても places.sqlite を叩けば取れるな。

SELECT
  CASE type
      WHEN 1 THEN "ブックマーク"
      WHEN 2 THEN "フォルダー"
      ELSE "その他" END AS type,
  count(*) AS count
FROM
  moz_bookmarks
GROUP BY
  type;
追記(2013-08-23)

Firefox 21 から about:healthreport で見れるようになったみたい。