2020-05-02 ,

JavaScript碁盤

JavaScript碁盤を書きました。

実行
ソースコード
https://github.com/misohena/js_igo

最近囲碁クエストにはまっているのですが、ブラウザ版には終局後の検討機能がありません。検討機能は終局後に巻き戻して途中から自分で好きに石を並べられるモードです。終局後に「あそこは何かあったんじゃないかな」「防ぐ手はなかったかな」などと思うことは良くありますが、ブラウザでプレイするとそれができません。Android版にはちゃんと検討機能がありますし過去の対局を振り返って検討することもできるのですが、デスクで作業しているときにいちいちスマホに手を伸ばしたくありません。

幸い棋譜(SGF)のエクスポート機能(ブラウザのテキスト領域に表示してコピーできる)はあるので、何か適当なソフトで読み込めば検討はできます。CGobanを入れてみたのですが、コピーしたSGFテキストを一度ファイルに保存してから読み込まなければならず面倒です。同じブラウザでSGFをペーストして読み込める碁盤があれば便利だなと思ったので作ることにしました。同じようなものは探せばいくらでもあるみたいですが、探すのも面倒ですし作るのも勉強になりますので。

基本的なロジックは10年以上前に作ったものがあったので流用しつつ現代風にアレンジ&機能追加しました。

盤面のデータ構造はUint32Arrayに1交点2ビットずつ詰め込む形を採用。9路盤を2*9*9=162ビット、162/32=5.0625で6dwords(24バイト)で表現出来ます。最小を目指すなら3(空点、黒、白)の倍数で記録していくべきなのですがさすがにそれはやりすぎかなと。盤外を表す点を用意すべきか等色々トレードオフがあってよく分からないのですが、盤面を沢山複製して保持するときにできるだけ小さい方がいいだろう、ということで。ハッシュも計算しやすそうですし。ただ、今回の用途までならどうやっても問題なし。

画像で表示するのも馬鹿らしいのでSVGで表示。グラデーションと影をつけてまあまあの見た目になりました。

履歴は最初からツリー構造を採用。巻き戻してから他の場所に打ったときは別のノードを作って記録します。分岐はA, B, C,…と盤面に表示できるようにしました。他のツールのようにツリー構造全体を図で表示出来たらかっこよかったのですが、これでも十分実用にはなります。

SGFインポート/エクスポート機能は今回の目的では必須。SGFフォーマットのページを見たらEBNFが書いてあったのでそれを元に手書きで解析器を作成。プロパティは、囲碁クエストのSGFを読むだけならSZ, B, Wくらいに対応すれば十分。後から詰碁を表示したいと思ってPL, AB, AW, AE, C, その他マーク等にも対応しました。

詰碁に対応するためにコメント機能、フリー編集機能、先番設定機能を追加。

一応スマホでも使えるようにタッチイベントに対応。19x19はさすがに小さいですね。ボタン類も一緒に小さくなってしまうので盤面部分だけ拡大縮小出来るようになるとよいのですが……。(→追記:対応しました)

あ、結果の判定機能はありません。死活判定しなければならないので難しいですよね……。死に石を指定出来るようにするとか、純碁みたいに全部打ち切るなら判定出来るのですが……。今後の大きな課題です。

純碁と言えば王銘エン先生の「こんなに面白い 世界の囲碁ルール」は面白かったです。オススメ。

ちなみに囲碁クエストをはじめたのは、知り合いが将棋ウォーズをやっていたからです。将棋は子供の頃に父親にボコボコにされたトラウマがあるのでやらないことにしているのです。なので囲碁ウォーズを試してみたのですが、Android版アプリの出来がすこぶる悪い。何回やっても起動しなくなるのです。時々思い出したようにすんなり起動するのですが、アプリを終了するとまた起動しなくなります。何が原因なのかまったく分かりません。調べてみると囲碁クエストという別のアプリの方が安定しているようなのでそちらをはじめました。

どちらもメインは9路盤のようです。19路のオンライン対局は大変なのでとてもやる気が起きませんが、9路なら短時間でプレイできるのでオススメです。

一問一答! 囲碁・9路盤の手筋 ~基本定石からヨセまで~ (囲碁人ブックス)」という本も買ってみたのですが、これはちょっと難しいですね。難易度が低い問題が分からなくて気を落としていたら難易度が中くらいのものがあっさり分かってしまったり。巻末の引き分け定石は参考になります。手順番号の着いた棋譜を脳内再生するのは苦手なのですが、今回作った碁盤を使って勉強してみようと思います。

Web上も探すと9路の情報が結構ありますね。Youtube動画もあります。

2020-04-22

2020年春の新番組

かぐや様2期くらいかなぁ。

印象 開始日時 チャネル タイトル
03/26(木) Netflix 7SEEDS 第2期
03/27(金) 24:00 TOKYO MX GRANBLUE FANTASY The Animation Season2
03/28(土) 11:00 YouTube アイカツオンパレード!
03/30(月) 18:10 NHK Eテレ 忍たま乱太郎 第28シリーズ
04/01(水) 24:30 TOKYO MX 神之塔 -Tower of God-
04/01(水) 07:30 テレビ東京系 みっちりわんこ!あにめ~しょん
04/01(水) 18:00 NHK Eテレ おじゃる丸 第23シリーズ
04/02(木) 17:20 NHK Eテレ のりものまん
04/02(木) 22:30 TOKYO MX 八男って、それはないでしょう!
× 04/02(木) 23:30 TOKYO MX 球詠
04/02(木) 24:00 TOKYO MX かくしごと
04/03(金) 16:00 公式ポータルサイト ベイブレードバースト スパーキング
04/03(金) 17:00 YouTube(爆丸公式Ch) 爆丸アーマードアライアンス
04/03(金) 18:20 NHK Eテレ あはれ!名作くん シーズン5
× 04/03(金) 22:00 TOKYO MX 新サクラ大戦 the Animation
04/03(金) 25:23 テレビ東京 文豪とアルケミスト
04/03(金) 25:55 TBS LISTENERS リスナーズ
04/03(金) 26:25 TBS 波よ聞いてくれ
04/04(土) 07:30 テレビ東京系 遊☆戯☆王 SEVENS
04/04(土) 09:00 NHK Eテレ おしりたんてい 新シリーズ
04/04(土) 17:35 NHK Eテレ MAJOR 2nd 第2シリーズ
04/04(土) 22:00 TOKYO MX アルテ
04/04(土) 25:00 TOKYO MX ギャルと恐竜
04/04(土) 25:30 TOKYO MX 乙女ゲームの破滅フラグしかない悪役令嬢に転生してしまった…
04/04(土) 25:30 テレビ朝日 イエスタデイをうたって
04/05(日) 07:30 テレビ東京系 ディズニー・サンデー ラプンツェル ザ・シリーズ
04/05(日) 09:00 フジテレビ デジモンアドベンチャー:
× 04/05(日) 09:30 テレビ東京系 トミカ絆合体 アースグランナー
04/05(日) 10:30 テレビ東京系 ミュークルドリーミー
04/05(日) 19:00 NHK Eテレ もっと!まじめにふまじめ かいけつゾロリ
04/05(日) 22:00 TOKYO MX 継つぐもも
04/05(日) 22:30 TOKYO MX アイドリッシュセブン Second BEAT!
04/05(日) 23:30 TOKYO MX グレイプニル
04/05(日) 24:15 NHK総合 キングダム 第3シリーズ
04/05(日) 24:30 TOKYO MX 社長、バトルの時間です!
04/05(日) 25:00 TOKYO MX 俺の指で乱れろ。~閉店後二人きりのサロンで…~
04/06(月) 07:05 テレビ東京系 ガル学。~聖ガールズスクエア学院~
× 04/06(月) 17:55 テレビ東京系 ファンファンキティ!
04/06(月) 22:30 TOKYO MX 白猫プロジェクト ZERO CHRONICLE
04/06(月) 22:50 NHK Eテレ 銀河英雄伝説 Die Neue These(NHK版)
04/06(月) 23:29 BS日テレ ぽっこりーず
04/06(月) 24:30 TOKYO MX プリンセスコネクト!Re:Dive
04/06(月) 25:00 チバテレビ あの世のすべては、おばけぐみ
04/06(月) 25:15 TOKYO MX 邪神ちゃんドロップキック'
04/06(月) 25:30 テレビ東京 フルーツバスケット 新作 2nd season
04/07(火) 07:30 テレビ東京系 おりがみにんじゃ コーヤン
04/07(火) 17:55 テレビ東京系 シャドウバース
04/07(火) 24:30 TOKYO MX 放課後ていぼう日誌
04/07(火) 25:35 TOKYO MX 無限の住人-IMMORTAL-
04/08(水) 07:20頃 テレビ東京系 おばけずかん
04/08(水) 22:00 TOKYO MX 本好きの下剋上 司書になるためには手段を選んでいられません 第2部
04/08(水) 23:29 BS日テレ 困ったじいさん
04/08(水) 24:55 フジテレビ BNA
04/09(木) 25:10 フジテレビ 富豪刑事 Balance:UNLIMITED
04/09(木) 25:28 TBS ノー・ガンズ・ライフ 第2期
04/09(木) 25:58 TBS やはり俺の青春ラブコメはまちがっている。完
  04/10(金) 21:00 YouTube 魔神英雄伝ワタル 七魂の龍神丸
04/10(金) 20:00 ニコニコCh ざしきわらしのタタミちゃん
04/10(金) 22:30 TOKYO MX 天晴爛漫!
04/10(金) 24:30 TOKYO MX 食戟のソーマ 豪の皿
04/10(金) 25:25 TBS系 アルゴナビス from BanG Dream! ANIMATION
04/11(土) 17:30 日本テレビ系 ハクション大魔王2020
04/11(土) 19:00 TOKYO MX ガンダムビルドダイバーズRe:RISE 2nd Season
04/11(土) 23:30 TOKYO MX かぐや様は告らせたい?
04/12(日) 23:00 TOKYO MX ULTRAMAN
04/13(月) 23:00 TOKYO MX 啄木鳥探偵處
04/16(木) 19:53 テレビ東京 テレビ野郎 ナナーナ 怪物クラーケンを追え!
04/20(月) 21:54 TOKYO MX オリンピア・キュクロス
04/23(木) Netflix 攻殻機動隊 SAC_2045
04/25(土) 08:00 テレビ東京系 ヴァンガード 外伝 イフ-if-
04/25(土) 24:00 TOKYO MX ソードアート・オンライン-アリシゼーション- War of Underworld -THE LAST SEASON-
–/–(日) 08:30 テレビ東京系 デュエル・マスターズキング
2020-04-15 ,

org-mode文書をタグなどで検索したときにエントリの中身(本文)を全部表示する(Org 9.3.6)

org-modeで書かれた文書を org-match-sparse-tree を使ってをタグで検索する(Sparse Tree を作る)とマッチしたヘッドラインだけが表示されるのですが、そのとき本文も全て一括で表示して欲しかったのでどうしたらよいのか調べてみました。

例えば DIARY タグで検索して日記を通して読みたいときにいちいち一つ一つのヘッドラインをTABキーで展開してまわるのは面倒です。かといってS-TABだとマッチしていない部分の本文も展開されてしまいます。

マニュアルのSparse Treeの項目を見てもマッチしたエントリを移動する操作くらいしか書いていませんでした。

Sparse Trees (The Org Manual)

しかたがないので org-match-sparse-tree 関数(org.el内)を調べてみることにしました。

org-match-sparse-tree の亜種を作る

org-match-sparse-tree は内部で org-scan-tags を呼んでいます。 org-scan-tags はその名の通りの文書をスキャンしてマッチする部分を巡回する関数です。マッチしたところで何をするかは引数 action で指定することになっていて、 org-match-sparse-tree では 'sparse-tree を渡してマッチした場所をハイライトしたりヘッドラインを表示したりしています。 action には任意の関数も渡せるようになっているので、そこにサブツリーを表示する関数を渡してマッチした部分を子孫も含めて全て表示させることにしました。

org-match-sparse-tree のコードをベースに修正してみます。

;; org-match-sparse-treeをベースに修正
(defun org-match-sparse-tree-show-subtree (&optional todo-only match)
  "Create a sparse tree according to tags string MATCH.

MATCH is a string with match syntax.  It can contain a selection
of tags (\"+work+urgent-boss\"), properties (\"LEVEL>3\"), and
TODO keywords (\"TODO=\\\"WAITING\\\"\") or a combination of
those.  See the manual for details.

If optional argument TODO-ONLY is non-nil, only select lines that
are also TODO tasks."
  (interactive "P")
  (org-agenda-prepare-buffers (list (current-buffer)))
  (let ((org--matcher-tags-todo-only todo-only))

    ;; 修正点ここから
    ;; まずはトップレベル以外は全て非表示にする。ハイライトももしあれば解除する。
    (org-overview)
    (org-remove-occur-highlights)
    ;; 修正点ここまで

    (org-scan-tags
     ;; 修正点ここから
     ;; マッチしたところをハイライトしてからサブツリーを表示する
     (lambda ()
       (and org-highlight-sparse-tree-matches
            (org-get-heading) (match-end 0)
            (org-highlight-new-match
             (match-beginning 1) (match-end 1)))

       (org-show-subtree) )
     ;; 修正点ここまで
     (cdr (org-make-tags-matcher match))
     org--matcher-tags-todo-only)))

元々の (org-scan-tags 'sparse-tree ....) では、マッチした場所で (org-show-context 'tags-tree) を呼び出しており、 (org-show-context)(org-show-set-visibility) を呼び出してその場所を表示状態にします。どのような表示を行うかは org-show-context-detail 変数でカスタマイズできるのですがサブツリー全体を表示するというオプションはありません。 'local が一番近いのですが、なぜか次のエントリーのヘッドラインまで表示してしまいます(ドキュメントにもそう書いてあるので意図した動作のようです)。他のオプションには if point is not on headline, also show entry and all children 等と書いてあり、ヘッドライン外にポイントがないと内容は表示してくれません。しかたがないので (org-show-context) の代わりに直接 (org-show-subtree) を呼ぶようにしてあります。

一時的に org-show-context をオーバーライド

org-match-sparse-tree の実行中、 (org-show-context) を一時的にオーバーライドしても結果は同じです。こちらの方がシンプルでしょうか?

(require 'cl)
(defun org-match-sparse-tree-show-subtree (&optional todo-only match)
  (interactive "P")
  (flet ((org-show-context (&optional key) (org-show-subtree)))
    (org-match-sparse-tree todo-only match)))

fletで一時的にorg-show-contextをオーバーライドしてみました。

マッチしたところだけ後から展開する

これでマッチした全エントリーの中身(サブツリー)を表示出来たのですが通常の動作との使い分けが面倒なことに気がつきました。最初から本文を全部読みたいと思って検索するなら上で定義した (org-match-sparse-tree-show-subtree) を使えば良いのですが「とりあえずタグで検索 → 一覧が出る → 一覧を全部展開」という手順の方が自然な気がします。

本当に欲しかったのはS-TABでマッチした(ハイライトした)エントリだけをvisibility cyclingすることなのではないでしょうか。

マッチした部分は (org-occur-next-match) という関数で巡回出来ます(M-g n や M-g p で移動するときに使われます)。マッチした部分のハイライトは (org-highlight-new-match beg end) で行われています。これは org-occur のためにある関数のようですが指定された範囲にオーバーレイを適用して、オーバーレイを org-occur-highlights リストに追加します。検索後にC-c C-cでハイライトが消えるのは (org-ctrl-c-ctrl-c) 内で org-occur-highlights リストに何か入っているときは (org-remove-occur-highlights) を呼んでいるからだったりします。 (org-occur-next-match) で次のマッチ、前のマッチに移動出来るのはオーバーレイの 'org-type プロパティに値 'org-occur が設定されているからで、その値を検索して移動しているようです。

なので (org-occur-next-match) でハイライト部分を巡回して (org-show-subtree) しまくればマッチしたエントリーの内容をサブツリーを含めて表示出来ます。

(defun org-show-occur-highlights-subtree ()
  (interactive)
  (save-excursion
    (goto-char (point-min))

    (while (ignore-errors (org-occur-next-match 1))
      (org-show-subtree))))

本当は S-TAB をオーバーライドしてハイライトがあるときはハイライトされている部分だけを展開したり折りたたんだりできればいいのですが現在の展開状態を調べる必要があるので面倒そうなので今日はここまでにしておきます。

(2020-04-16追記)S-TABでマッチしたエントリのみを展開したり閉じたりする

ここまでで一応検索結果(Sparse Tree)の本文を一括で表示(展開)できるようになったのですが、やっぱり S-TAB に割り当てて検索結果を開いたり閉じたりしたい! ということで引き続き調べてみました。

まず、既存の S-TAB がどのようになっているのか調べる必要があります。

調べてみた結果、次のようなフローになっていることが分かりました。複雑ですね。

S-TAB => org-shifttab => org-global-cycle => (org-cycle '(4)) => org-cycle-internal-global

C-u 引数によって多少流れが変わることもあるかもしれませんが最終的には org-cycle-internal-global が呼ばれるようです。

org-cycle-internal-global関数は切り替えの処理を行いますが最初はOVERVIEWで表示し、同じコマンドが連続して呼ばれたときに => CONTENTS => ALL => OVERVIEW … の順で表示を切り替える実装になっています。私はこれまで気がついていなかったのですが現在の状態から次の状態へ変わるわけではないんですね。例えば他の作業をした後にS-TABを3回押せばどんな状態からでも必ずALLになるわけです。

実際の表示状態の変更は次の関数が行います。

org-overview
トップレベルのヘッドラインだけ表示
org-content
全てのヘッドラインだけを表示
org-show-all
内容も含めて全て表示(ドロワーなど一部を除く)

ハイライトがあるとき(Sparse Tree表示時)の動作はこれらの関数を修正すべきでしょう。S-TABだけでなくこれらの関数を直接呼び出すこともあるでしょうし。

……と思ったのですが、これらの関数がハイライトがあるときにどのような動作をすべきか考えたのですがなかなか一貫性のある挙動を決めることができませんでした。

org-overview
このまま? ハイライトされている部分だけを表示?(デフォルトの表示って事?)
org-content
ハイライトされているエントリ以下の全てのヘッドラインを表示? org-occurでマッチしたヘッドライン以外の部分はどうする?
org-show-all
ハイライトされているエントリ以下の全てを表示?

org-occurがあるのでハイライトされるのはヘッドラインだけとは限らないところが問題を難しくします。Sparse Treeを表示した直後に1回S-TABを押したときに同じ表示になる(何も変わらない)のも避けたいところです。

仕方が無いので既存の動作との一貫性は脇に置いてSparse Tree表示時の特殊な挙動として仕様を決めることにしました。

org-sparse-tree-show-matched
マッチしたところを表示(デフォルト)
org-sparse-tree-show-all
サブツリーを含めて全て表示

ハイライトがあるときは、この二つと既存の三つをS-TABで切り替えることにします。

OVERVIEW => SPARSE-TREE-SHOW-MATCHED => SPARSE-TREE-SHOW-ALL => CONTENTS => ALL

つまり2回S-TABすればマッチした箇所(タグ検索の場合はヘッドラインのみ)が、3回S-TABすれば本文まで展開してくれるわけです。既存の操作感覚に割と近くなっていると思います。マッチした部分に限定されたくない場合に備えて、4回S-TABすればCONTENTS、5回S-TABすればALLとなるようにしました。

;; org-sparse-tree-cycle.el
;; https://misohena.jp/blog/2020-04-15-show-contents-of-entry-when-sparse-tree-in-org-mode.html
;;

(defun org-sparse-tree-show-all ()
  "マッチした部分をサブツリーを含めて表示します。"
  (interactive)
  (save-excursion
    (org-overview)

    (goto-char (point-min))
    (while (ignore-errors (org-occur-next-match 1))
      (org-show-context 'tags-tree)
      (org-show-subtree))))

(defun org-sparse-tree-show-matched ()
  "マッチした部分を表示します。"
  (interactive)
  (save-excursion
    (org-overview)

    (goto-char (point-min))
    (while (ignore-errors (org-occur-next-match 1))
      (org-show-context 'tags-tree))))

;; この関数は org-cycle-internal-global を元に修正しています。
(defun org-sparse-tree-cycle-internal ()
  "Do the sparse tree cycling action."
  ;; Rotate overview => sparse-tree-show-matched => sparse-tree-show-all => contents => show all

  ;; Hack to avoid display of messages for .org  attachments in Gnus
  (let ((ga (string-match "\\*fontification" (buffer-name))))
    (cond
     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'sparse-tree-show-all))
      ;; We just created the overview - now do table of contents
      ;; This can be slow in very large buffers, so indicate action
      (run-hook-with-args 'org-pre-cycle-hook 'contents)
      (unless ga (org-unlogged-message "CONTENTS..."))
      (org-content)
      (unless ga (org-unlogged-message "CONTENTS...done"))
      (setq org-cycle-global-status 'contents)
      (run-hook-with-args 'org-cycle-hook 'contents))

     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'contents))
      ;; We just showed the table of contents - now show everything
      (run-hook-with-args 'org-pre-cycle-hook 'all)
      (org-show-all '(headings blocks))
      (unless ga (org-unlogged-message "SHOW ALL"))
      (setq org-cycle-global-status 'all)
      (run-hook-with-args 'org-cycle-hook 'all))

     ((and (eq last-command this-command)
      ;; sparse tree show matched
           (eq org-cycle-global-status 'overview))
      (org-sparse-tree-show-matched)
      (setq org-cycle-global-status 'sparse-tree-show-matched))

     ((and (eq last-command this-command)
           (eq org-cycle-global-status 'sparse-tree-show-matched))
      ;; sparse tree show all
      (org-sparse-tree-show-all)
      (setq org-cycle-global-status 'sparse-tree-show-all))

     (t
      ;; overview
      (run-hook-with-args 'org-pre-cycle-hook 'overview)
      (org-overview)
      (unless ga (org-unlogged-message "OVERVIEW"))
      (setq org-cycle-global-status 'overview)
      (run-hook-with-args 'org-cycle-hook 'overview)))))

(defun org-sparse-tree-shifttab-advice (oldfun arg)
  (if org-occur-highlights
      ;; ハイライトがある
      (org-sparse-tree-cycle-internal)
    ;; 元の関数を呼ぶ
    (funcall oldfun arg)))

;; org-shifttabをオーバーライドする
(advice-add 'org-shifttab :around #'org-sparse-tree-shifttab-advice)

うん、これでSparse Treeが大分使いやすくなりました。

2020-04-06

星表を使って星空を描く

ESAのHipparcosGaiaのデータを使用して星空を描いてみました。

  • js_hoshizora:

    JavaScript+WebGLで10万個くらいの星空を描いてみたもの。実行はこちら

  • drawstars:

    Gaiaのデータを使って精巧な天の川まで描いてみたもの。あまりに天体の数が多いのでリアルタイムは不可能。C++でコマンドラインツールに仕立てました。去年の夏に撮影した天の川と比較してみたところほとんど一致しました。

昔から一度星空を描いてみたかったのです。小学生の頃図書館にBASICで書かれたグラフィックスの本があってその中に星空・星座を描くものがあったのですが当時の私にはさっぱり理解出来ませんでした。

天体の位置計算 増補版やWebの情報で勉強してみると精度を求めないのであればそれほど難しくないようでした。基本的に赤経・赤偉で星の位置が与えられているので、それを地球のある地点から見た座標系に変換すればOKです。言葉の定義などをしっかり学んで考えてみれば3Dグラフィックスでおなじみの行列での座標変換でした。

一番困ったのは色の計算。一般に星の観測は複数の異なる帯域(赤とか青とか)に反応するセンサーを用い、色はその差分で表されるのですが、そこから画面のRGB値にするのに苦労しました。今でも適当です。

恒星時の計算もひっかかりました。年々式が変わっているようなのですが原理をあまり理解していないのでよく分かりません。精度を求めないのであれば適当でもなんとか。

歳差やら章動やら天体の固有運動、視差、光行差等はまだろくに学んでいないので考慮していません。色についても赤方偏移や減光など色々な要因で変わるみたいですが後々の課題と言うことで。

正距円筒図法で描かれた天の川
図1: 正距円筒図法で描かれた天の川
テクスチャにして投影した天の川
図2: テクスチャにして投影した天の川
現実の天の川
図3: 現実の天の川
描画された天の川
図4: 描画された天の川
2020-01-23

2020年冬の新番組

今期はどうでしょうね。1話切りを連発したわりには案外残っているような気もします。

あたりですかね。

01/03(金) 22:30~ TOKYO MX 恋する小惑星
× 01/03(金) 24:00~ TOKYO MX ダーウィンズゲーム
01/04(土) 24:00~ TOKYO MX マギアレコード 魔法少女まどか☆マギカ外伝
01/05(日) 21:30~ TOKYO MX りばあす
01/05(日) 24:00~ TOKYO MX ID:INVADED
01/05(日) 24:10~ NHK総合 映像研には手を出すな!
× 01/05(日) 25:00~ TOKYO MX おーばーふろぉ
01/06(月) 21:54~ TOKYO MX へやキャン△
01/06(月) 22:00~ TOKYO MX pet-ペット-
× 01/06(月) 24:30~ TOKYO MX 群れなせ!シートン学園
01/06(月) 25:00~ TOKYO MX 八十亀ちゃんかんさつにっき 2さつめ
01/06(月) 25:35~ TOKYO MX なつなぐ!
01/07(火) 07:30~ テレビ東京系 LALALACOCO
01/07(火) 18:45~ NHK Eテレ ブレーカーズ
01/08(水) 07:30~ テレビ東京系 フライングベイビーズ☆プチ
01/08(水) 22:00~ TOKYO MX 魔術士オーフェンはぐれ旅
× 01/08(水) 22:30~ TOKYO MX number24
01/08(水) 24:55~ フジテレビ 空挺ドラゴンズ
× 01/08(水) 25:05~ TOKYO MX プランダラ
× 01/08(水) 25:35~ TOKYO MX 痛いのは嫌なので防御力に極振りしたいと思います。
01/09(木) 19:30~ BS4K ムーミン谷のなかまたち シーズン2
01/09(木) 22:00~ TOKYO MX ネコぱら
01/09(木) 22:30~ TOKYO MX SHOW BY ROCK!! ましゅまいれっしゅ!!
× 01/09(木) 23:30~ TOKYO MX インフィニット・デンドログラム
01/09(木) 24:00~ TOKYO MX 宝石商リチャード氏の謎鑑定
01/09(木) 24:30~ TOKYO MX ソマリと森の神様
01/09(木) 24:55~ フジテレビ うちタマ?! ~うちのタマ知りませんか?~
× 01/09(木) 25:28~ TBS 推しが武道館いってくれたら死ぬ
01/09(木) 25:58~ TBS 地縛少年 花子くん
01/10(金) 24:30~ TOKYO MX 理系が恋に落ちたので証明してみた。
01/10(金) 25:05~ TOKYO MX とある科学の超電磁砲T
× 01/10(金) 25:23~ テレビ東京 織田シナモン信長
01/10(金) 25:25~ TBS系 ハイキュー!! TO THE TOP
× 01/10(金) 25:35~ TOKYO MX ケンガンアシュラ
× 01/10(金) 26:05~ TOKYO MX はてな☆イリュージョン
× 01/10(金) 26:25~ TBS ランウェイで笑って
× 01/11(土) 23:00~ TOKYO MX 22 / 7
× 01/11(土) 25:30~ TOKYO MX 異種族レビュアーズ
01/11(土) 25:30~ テレビ朝日 虚構推理
01/12(日) 22:00~ TOKYO MX ぼくのとなりに暗黒破壊神がいます。
01/12(日) 24:00~ TOKYO MX ドロヘドロ
× 01/13(月) 23:00~ TOKYO MX ARP Backstage Pass
× 01/13(月) 24:00~ TOKYO MX A3! -SPRING & SUMMER-
× 01/14(火) 23:00~ TOKYO MX 7SEEDS
01/14(火) 24:30~ TOKYO MX 異世界かるてっと 第2期
01/15(水) ~ YouTube ポケットモンスター ソード&シールド「薄明の翼」
01/23(木) 23:00~ TOKYO MX BanG Dream! 3rd Season
01/23(木) ~ Netflix 聖闘士星矢: Knights of the Zodiac パート2

継続:

  • ちはやふる3
  • 耐え子の日常
2019-12-08

Windows用のEmacs26.3をMSYS2でビルドする方法(IMEパッチ、ImageMagick-6)

rzl24ozi’s gistsにIMEパッチが公開されている。README.txtに詳細なビルド方法が書いてあるのでよく読むこと。

1次情報としてはソースコードツリー内の nt/INSTALLnt/INSTALL.W64 にWindowsでのビルド方法が書いてある。

Emacs 26.2以降は最低限のIMEサポートがなされているらしいのでIMEパッチを適用しなくても公式ビルドで十分な場合もある。私の場合、ATOK使用時にCtrl+Nで部分確定した文字が正しく入力されなかった(Ctrl+各確定した文字…と解釈されてそんなキーバインドは無いと言われた)のでIMEパッチを使うことにした。

また、ImageMagickサポートがあると画像の拡大縮小ができて大きな画像も無理なく埋め込み表示出来るのでImageMagickパッチも適用することにした。

作業概要

MSYS2環境を構築(後述)してから、MinGW64のシェルから次の作業を行う。各ステップについての詳細は後述する。

# 作業用ディレクトリを作る
mkdir emacsbuild
cd emacsbuild
WORK_DIR=$(pwd)

# ImageMagickをダウンロードして展開してビルドする
IMAGEMAGICK_VER=ImageMagick-6.9.10-77
wget http://www.imagemagick.org/download/releases/$IMAGEMAGICK_VER.tar.gz
tar xvfz $IMAGEMAGICK_VER.tar.gz

IMAGEMAGICK_DIR=$WORK_DIR/ImageMagick-6
cd $IMAGEMAGICK_VER
./configure --host=x86_64-w64-mingw32 --enable-hdri --with-rsvg --prefix=$IMAGEMAGICK_DIR
make install
cd ..

# Emacsをダウンロードして展開する
EMACS_VER=emacs-26.3
wget http://ftp.gnu.org/gnu/emacs/$EMACS_VER.tar.gz
tar xvfz $EMACS_VER.tar.gz

# IMEパッチを当てる
wget https://gist.githubusercontent.com/rzl24ozi/ee4457df2f54c5f3ca0d02b56e371233/raw/16794e5883211049aed08c681f71240fa32cc28f/emacs-26.1-rc1-w32-ime.diff
patch -p0 -d $EMACS_VER <./emacs-26.1-rc1-w32-ime.diff

# ImageMagickパッチを当てる
wget https://gist.githubusercontent.com/rzl24ozi/2b6dd502f3e0fa5083fb87c808287370/raw/a56d6c576d3f4ca24f87ff7510498f588a67c236/emacs-26.1-rc1-mingw-imagemagick.diff
patch -p0 -d $EMACS_VER <./emacs-26.1-rc1-mingw-imagemagick.diff

# ImageMagick関連dllファイル名をビルドしたバージョンに合わせて書き替える
mv $EMACS_VER/lisp/term/w32-win.el $EMACS_VER/lisp/term/w32-win.el.orig_patched
sed 's/-6\.Q16HDRI-5\.dll/-6.Q16HDRI-6.dll/g; s/-6\.Q16-5\.dll/-6.Q16-6.dll/g;' $EMACS_VER/lisp/term/w32-win.el.orig_patched > $EMACS_VER/lisp/term/w32-win.el

# Emacsをビルドする
EMACS_INSTALL_DIR=/c/app/$EMACS_VER
cd $EMACS_VER
./autogen.sh
PKG_CONFIG_PATH=$IMAGEMAGICK_DIR/lib/pkgconfig:$PKG_CONFIG_PATH ./configure --without-dbus --with-gnutls --prefix=$EMACS_INSTALL_DIR
make -j4
make install-strip
cd ..

# dllをコピーする
cp /mingw64/bin/*.dll $EMACS_INSTALL_DIR/bin
cp $IMAGEMAGICK_DIR/bin/libMagickCore*.dll $EMACS_INSTALL_DIR/bin
cp $IMAGEMAGICK_DIR/bin/libMagickWand*.dll $EMACS_INSTALL_DIR/bin

Cygwin使用者への注意

Cygwinを使用している場合はCygwinの設定がMSYSと混ざらないように注意すること。

  • 環境変数HOMEが指している場所に.bashrcや.bash_profile等の設定ファイルがある場合は、それが読み込まれないようにする。そこにPKG_CONFIGやLIBRARY_PATH等の設定があるとうまくビルド出来ない。
  • PATHがCygwinのツールを参照していると問題を起こす場合がある(特にテキストマウントによる改行コードの問題)ので、PATHからCygwin関連へのパスを外す等する。

環境変数HOMEがCygwinの設定ファイルがあるディレクトリを指している場合、例えば次のようにして対処する。

  • MSYSを使う前に一時的に環境変数HOMEを削除する
  • msys2_shell.cmdの先頭に「set HOME=」を追加する
  • cmd.exeから set "HOME=" && (msysインストール先)\msys2_shell.cmd -mingw64 でMinGW64シェルを起動する
  • .bashrcや.bash_profileにCygwin以外(MSYS等)で実行した場合に対応するコードを追加する。例えば次のコードをファイルの先頭に入れるとCygwin以外は何もせず終了する

    [[ "$OSTYPE" != "cygwin" ]] && return
    

MSYS2環境の準備

MSYS2のインストール

MSYS2 homepageからMSYS2(x86_64)のインストーラをダウンロードして実行しインストールする。

MSYS2シェルの起動

スタートメニューから「MSYS2 MSYS」を選ぶとMSYS2シェルが起動する。

MSYS2の更新

すでにMSYS2をインストール済みの場合、ビルドの前に各種パッケージの更新を行う(古いバージョンのMSYS2の場合は入れ直した方が早いかも)。

スタートメニューから「MSYS2 MSYS」を選んで以下を入力。

pacman -Syuu

warning: terminate MSYS2 without returning to shell and check for updates again warning: for example close your terminal window instead of calling exit

のようなメッセージが出たらAlt+F4で終了してスタートメニューからMSYS2 MSYSを起動して再度 pacman -Syuu を実行する。

何度か繰り返して更新されなくなったらOK。

以前追加したパッケージはここで更新される。

必要なパッケージの追加

必要なパッケージについては nt/INSTALLnt/INSTALL.W64 を参照のこと。

nt/INSTALL.W64では次のパッケージをインストールしている(2019-12-07現在)。

pacman -S --needed base-devel \
  mingw-w64-x86_64-toolchain \
  mingw-w64-x86_64-xpm-nox \
  mingw-w64-x86_64-libtiff \
  mingw-w64-x86_64-giflib \
  mingw-w64-x86_64-libpng \
  mingw-w64-x86_64-libjpeg-turbo \
  mingw-w64-x86_64-librsvg \
  mingw-w64-x86_64-lcms2 \
  mingw-w64-x86_64-jansson \
  mingw-w64-x86_64-libxml2 \
  mingw-w64-x86_64-gnutls \
  mingw-w64-x86_64-zlib

不要なパッケージ(ImageMagick-7)が入っている場合は削除すること。

pacman -Rs mingw-w64-x86_64-imagemagick

MinGW64シェルに移る

スタートメニューから「MSYS2 MinGW 64-bit」を選ぶ。

Cygwinを使用している場合はCygwin使用者への注意を参照のこと。

作業用ディレクトリを用意する

mkdir emacs_build
cd emacs_build
WORK_DIR=$(pwd)

以降作業ディレクトリへのパスを $WORK_DIR とする。

ImageMagickのビルド

ImageMagickのソースコードの取得

http://www.imagemagick.org/download/releases/ から6系の最新のソースコードを取得する。

IMAGEMAGICK_VER=ImageMagick-6.9.10-77
wget http://www.imagemagick.org/download/releases/$IMAGEMAGICK_VER.tar.gz
tar xvfz $IMAGEMAGICK_VER.tar.gz

ImageMagickのビルド

MinGW64シェルから展開したディレクトリへ移動して

IMAGEMAGICK_DIR=$WORK_DIR/ImageMagick-6
cd $IMAGEMAGICK_VER
./configure --host=x86_64-w64-mingw32 --enable-hdri --with-rsvg --prefix=$IMAGEMAGICK_DIR
make install
cd ..

$WORK_DIR/ImageMagick-6 にビルド結果が格納される。そのディレクトリを以降 $IMAGEMAGICK_DIR とする。

Emacsのビルド

Emacsのソースコードの取得

Emacsの公式サイトからソースコードをダウンロードして展開する(Cygwinの場合テキストマウントに注意すること)。

http://ftp.gnu.org/gnu/emacs/

EMACS_VER=emacs-26.3
wget http://ftp.gnu.org/gnu/emacs/$EMACS_VER.tar.gz
tar xvfz $EMACS_VER.tar.gz

Gitで取得することもできる。

which gitしてgitが見えなければgitへのパスを通す(Git for WindowsなどMSYS2の外でインストールしている場合は見えないと思う)。

export PATH="/c/app/dev/Git/cmd":"$PATH"

emacs.git - Emacs source repository より好きなブランチを選んで入手する。

git clone --depth=1 -b $EMACS_VER git://git.savannah.gnu.org/emacs.git --config core.autocrlf=false

改行コードに注意すること。Windowsだとautocrlfで使っている人もいると思うので、改行コードが変換されないようにオプションを付ける。

IMEパッチを適用

rzl24ozi’s gists より最新のものを入手する。

emacs-26.3にはemacs26.1-rc1用のパッチがそのまま適用できた。

wget https://gist.githubusercontent.com/rzl24ozi/ee4457df2f54c5f3ca0d02b56e371233/raw/16794e5883211049aed08c681f71240fa32cc28f/emacs-26.1-rc1-w32-ime.diff
patch -p0 -d $EMACS_VER <./emacs-26.1-rc1-w32-ime.diff

注意: Cygwinをテキストマウントで使っている場合、Cygwinのpatchを使うと改行コードがCR+LFになることがあるので、その場合はMinGWのpatchを使うこと。

(msys2インストール先)/usr/bin/patch -p0 -d $EMACS_VER <./emacs-26.1-rc1-w32-ime.diff

ImageMagickパッチを適用(+一部手動修正)

ImageMagickを使うときは次のパッチを使う。

wget https://gist.githubusercontent.com/rzl24ozi/2b6dd502f3e0fa5083fb87c808287370/raw/a56d6c576d3f4ca24f87ff7510498f588a67c236/emacs-26.1-rc1-mingw-imagemagick.diff
patch -p0 -d $EMACS_VER <./emacs-26.1-rc1-mingw-imagemagick.diff

した上で

lisp/term/w32-win.el 内の次の場所をDLLのファイル名に合わせて変更する。

       '(magickwand "libMagickWand-6.Q16HDRI-5.dll" "libMagickWand-6.Q16-5.dll"
                    "libMagickWand-6.Q16HDRI-2.dll" "libMagickWand-6.Q16-2.dll")
       '(magickcore "libMagickCore-6.Q16HDRI-5.dll" "libMagickCore-6.Q16-5.dll"
                    "libMagickCore-6.Q16HDRI-2.dll" "libMagickCore-6.Q16-2.dll")

例えばImageMagick-6.9.10-77をビルドすると libMagickCore*-6.dll や libMagickWand*-6.dll ができるので、上の-5.dllを-6.dllへ修正する。

mv $EMACS_VER/lisp/term/w32-win.el $EMACS_VER/lisp/term/w32-win.el.orig_patched
sed 's/-6\.Q16HDRI-5\.dll/-6.Q16HDRI-6.dll/g; s/-6\.Q16-5\.dll/-6.Q16-6.dll/g;' $EMACS_VER/lisp/term/w32-win.el.orig_patched > $EMACS_VER/lisp/term/w32-win.el

Emacsのビルド

MinGW64シェルから

EMACS_INSTALL_DIR=/c/app/$EMACS_VER
cd $EMACS_VER
./autogen.sh
PKG_CONFIG_PATH=$IMAGEMAGICK_DIR/lib/pkgconfig:$PKG_CONFIG_PATH ./configure --without-dbus --with-gnutls --prefix=$EMACS_INSTALL_DIR
make -j4 #4コアで
make install-strip
$EMACS_INSTALL_DIR/bin/runemacs.exe -Q

DLLのコピー

msys64/mingw64/bin/*.dll をEmacsのbinディレクトリへコピーする。

cp /mingw64/bin/*.dll $EMACS_INSTALL_DIR/bin

ビルドして生成されたImageMagick用のdllもコピーする。

cp $IMAGEMAGICK_DIR/bin/libMagickCore*.dll $EMACS_INSTALL_DIR/bin
cp $IMAGEMAGICK_DIR/bin/libMagickWand*.dll $EMACS_INSTALL_DIR/bin

その他の注意

MSYS2のライブラリパッケージがバージョンアップするとビルドが通らなくなったり通っても正しく動かなくなったりする場合があります。 emacs-26.2の時はlibgnutlsのバージョンアップに伴いSSL接続が正しく動かなくなった時がありました。 上記手順は2019-12-08にビルドが通ることを確認しました。

2019-11-13

2019年秋の新番組

10/01(火) 07:30~ テレビ東京系 ばなにゃ ふしぎななかまたち
10/02(水) 18:25~ テレビ東京系 あひるの空
10/02(水) 19:25~ NHK Eテレ ラディアン 第2シーズン
× 10/02(水) 21:54~ TOKYO MX 浦島坂田船の日常
10/02(水) 23:30~ TOKYO MX 慎重勇者 ~この勇者が俺TUEEEくせに慎重すぎる~
10/02(水) 24:30~ TOKYO MX 俺を好きなのはお前だけかよ
10/02(水) 25:05~ TOKYO MX 旗揚!けものみち
10/03(木) 17:55~ テレビ東京系 プリスクタイムエッグカー』&『GO!GO!アトム
× 10/03(木) 19:26~ TOKYO MX シルバニアファミリー ミニストーリー -クローバー
10/03(木) 22:30~ TOKYO MX 超人高校生たちは異世界でも 余裕で生き抜くようです!
× 10/03(木) 23:30~ TOKYO MX アズールレーン
10/03(木) 24:30~ TOKYO MX 放課後さいころ倶楽部
10/04(金) 12:00~ ニコニコ動画 ぬるぺた
10/04(金) 17:55~ テレビ東京系 ゾイドワイルド ZERO
× 10/04(金) 22:30~ TOKYO MX 厨病激発ボーイ
10/04(金) 24:00~ TOKYO MX GRANBLUE FANTASY The Animation Season2
× 10/04(金) 25:00~ TOKYO MX どるふろ -癒し編-
10/04(金) 25:05~ TOKYO MX ハイスコアガール 第13話~第15話
10/05(土) 10:30~ テレビ東京系 アイカツオンパレード!
10/05(土) 17:35~ NHK Eテレ 魔入りました!入間くん
10/05(土) 23:30~ TOKYO MX Fate/Grand Order -絶対魔獣戦線 バビロニア-
10/05(土) 24:30~ TOKYO MX ぼくたちは勉強ができない 第2期
10/05(土) 25:00~ TOKYO MX この音とまれ! 第2クール
× 10/05(土) 25:30~ TOKYO MX 戦×恋(ヴァルラヴ)
10/06(日) 22:00~ TOKYO MX トクナナ -警視庁 特務部 特殊凶悪犯対策室 第七課-
10/06(日) 23:30~ TOKYO MX ACTORS -Songs Connection-
10/06(日) 24:00~ TOKYO MX Fairy gone フェアリーゴーン 第2クール
× 10/06(日) 24:30~ TOKYO MX アフリカのサラリーマン
10/06(日) 25:00~ TOKYO MX XL上司。
10/06(日) 深夜~ テレビ東京 フォーカード 新シリーズ
10/07(月) 21:54~ TOKYO MX 兄に付ける薬はない! 第3期
10/07(月) 22:00~ TOKYO MX バビロン
10/07(月) 22:30~ TOKYO MX ファンタシースターオンライン2 エピソード・オラクル
× 10/07(月) 23:00~ TOKYO MX スタンドマイヒーローズ-PIECE OF TRUTH-
10/07(月) 24:00~ TOKYO MX 私、能力は平均値でって言ったよね!
10/07(月) 25:00~ チバテレビ エイリは王さま!
× 10/08(火) 23:00~ TOKYO MX Z/X Code reunion
10/08(火) 24:30~ TOKYO MX 神田川JET GIRLS
10/08(火) 25:00~ TOKYO MX 耐え子の日常
10/09(水) 17:55~ テレビ東京系 七つの大罪 神々の逆鱗
10/09(水) 22:00~ TOKYO MX 本好きの下剋上 司書になるためには手段を選んでいられません
10/09(水) 23:54~ BS11 ポンコツクエスト ~魔王と派遣の魔物たち~ シーズン6
10/09(水) 25:15~ フジテレビ BEASTARS
10/10(木) 20:00~ YouTube ガンダムビルドダイバーズRe:RISE
10/10(木) 24:00~ TOKYO MX アサシンズプライド
10/10(木) 25:28~ TBS ノー・ガンズ・ライフ
10/10(木) 25:58~ TBS 星合の空-ほしあいのそら-
10/10(木) ~ Amazon PV 無限の住人-IMMORTAL-
× 10/11(金) 24:30~ TOKYO MX 食戟のソーマ 第4期
10/11(金) 25:55~ TBS 歌舞伎町シャーロック
10/11(金) 26:25~ TBS 真・中華一番!
10/12(土) 17:30~ 日本テレビ系 僕のヒーローアカデミア 第4期
10/12(土) 24:00~ TOKYO MX ソードアート・オンライン -アリシゼーション- War of Underworld
10/13(日) 22:54~ BS11 天華百剣 ~めいじ館へようこそ!~
10/13(日) 23:00~ TOKYO MX ライフル・イズ・ビューティフル
10/14(月) ~ AbemaTV SUPER SHIRO
10/17(木) 24:55~ フジテレビ PSYCHO-PASS サイコパス 第3期
10/22(火) 25:29~ 日本テレビ ちはやふる 第3期
10/25(金) 25:05~ TOKYO MX ハイスコアガールⅡ (第2期)
2019-07-14

2019年夏の新番組

異世界ものが多いとは聞いていましたが、これはきっついですね。

全体の変数が少ないのでできるだけ1話切りしないで頑張ってみようかなと思ったのですが、早々にくじけそうです。

06/14(金) Netflix アグレッシブ烈子 シーズン2
06/24(月) 27:00頃 読売テレビ あにめたまご2019
06/28(金) Netflix 7SEEDS
07/01(月) 22:00 TOKYO MX スタミュ-高校星歌劇- 第3期
07/01(月) 23:00 TOKYO MX かつて神だった獣たちへ
07/01(月) 25:00 チバテレビ われしょ!~我ら!小動物愛護委員会~
07/02(火) 07:05 テレビ東京系 おどるモワイくん
07/02(火) 23:00 TOKYO MX 手品先輩
07/02(火) 23:15 TOKYO MX ソウナンですか?
07/03(水) 23:30 TOKYO MX ダンベル何キロ持てる?
07/03(水) 24:00 TOKYO MX 魔王様、リトライ!
07/03(水) 25:05 TOKYO MX 彼方のアストラ
07/04(木) 23:30 TOKYO MX うちの娘の為ならば、俺はもしかしたら魔王も倒せるかもしれない。
× 07/05(金) 22:00 TOKYO MX Dr.STONE
07/05(金) 22:30 TOKYO MX 女子高生の無駄づかい
07/05(金) 25:25 TBS系 炎炎ノ消防隊
07/05(金) 25:55 TBS グランベルム
07/05(金) 26:25 TBS 荒ぶる季節の乙女どもよ。
07/06(土) 09:00 NHK Eテレ おしりたんてい 新シリーズ
× 07/06(土) 24:00 TOKYO MX ロード・エルメロイⅡ世の事件簿 -魔眼蒐集列車 Grace note-
07/06(土) 25:00 TOKYO MX 戦姫絶唱シンフォギアXV 第5期
07/07(日) 06:15 KBC 博多明太!ぴりからこちゃん
07/07(日) 22:00 TOKYO MX Re:ステージ! ドリームデイズ
07/07(日) 22:30 TOKYO MX あんさんぶるスターズ!
07/07(日) 23:30 TOKYO MX からかい上手の高木さん 第2期
07/07(日) 24:00 TOKYO MX ビジネスフィッシュ
07/07(日) 24:10 NHK総合 ヴィンランド・サガ
07/07(日) 24:30 TOKYO MX ナカノヒトゲノム【実況中】
07/07(日) 25:00 TOKYO MX 指先から本気の熱情-幼なじみは消防士-
07/07(日) 深夜 テレビ東京 闇芝居 第7期
07/08(月) 22:30 TOKYO MX 胡蝶綺 ~若き信長~
07/08(月) 24:00 TOKYO MX コップクラフト
× 07/08(月) 24:30 TOKYO MX ありふれた職業で世界最強
07/09(火) 24:30 TOKYO MX 可愛ければ変態でも好きになってくれますか?
× 07/10(水) 25:35 TOKYO MX 異世界チート魔術師
07/11(木) 24:55 フジテレビ ギヴン
07/11(木) 25:28 TBS まちカドまぞく
× 07/12(金) 24:00 TOKYO MX 通常攻撃が全体攻撃で二回攻撃のお母さんは好きですか?
× 07/12(金) 24:30 TOKYO MX ダンジョンに出会いを求めるのは間違っているだろうかⅡ
× 07/12(金) 25:05 TOKYO MX とある科学の一方通行
  07/14(日) 25:35 テレビ東京 BEM(妖怪人間ベム)
2019-07-10

はじめてのフォトグラメトリ

TLにフォトグラメトリのやりかたが流れていたので試してみました。 使ったのは3DF Zephyrというソフトです。

吉野家でもらったマグカップ。酷い出来ですw

近くにあったハンバーガーのキーホルダー。左目の下がおかしくなってしまいましたが前のよりはマシになったかも。素材の質感はよく出てますね。

自転車。なかなか厳しいです。公園に行って動画で撮影してそのフレームを元に作成したのですが。

鰻を食べに行く機会があったので撮影。

なかなかうまくモデル化するのは難しいですね。できるだけ前のフレームと沢山重ねて撮影した方が良いとか、同じ場所で向きを変えるよりも平行移動したほうが良さそうとか、後は変換時のオプションでかなり変わったり。コツは色々あるみたいです。

2019-05-01

Emacs + Gnusでメールを読み書きする設定(Gmail、IMAP、POP複数アカウント)

普段Wanderlustを使っているのですが久しぶりにGnusに再挑戦、メールの読み書きが出来るようにしてみました。

環境

GNU Emacs 26.1.92 (build 1, x86_64-w64-mingw32)
 of 2019-03-08
Gnus v5.13

Gnus関連ファイルをひとつのディレクトリにまとめる

デフォルトだと ~/ の下にいろんなファイルを勝手に作るのでそれを ~/gnus/ に変更しました。 既に使っているWanderlustと併用したいので ~/Mail/ は特に困ります。

Gnus用設定ファイルの位置も ~/gnus/.gnus.el に移したいのですが、そこへのパスだけは .emacs や init.el の方に書かないとダメですね。その他の設定は .gnus.el に書くことにします。

  1. .emacs や init.el に (setq gnus-home-directory "~/gnus") を書く
  2. 次のコードを ~/gnus/.gnus.el に書く
;; Move home directory to ~/gnus
;; Write (setq gnus-home-directory "~/gnus") on init.el
(setq message-directory "~/gnus/Mail"
      mail-source-directory "~/gnus/Mail"
      nnfolder-directory "~/gnus/Mail/archive"
      pop3-uidl-file "~/gnus/.pop3-uidl"
      nntp-authinfo-file "~/gnus/.authinfo"
      auth-sources '("~/gnus/.authinfo" "~/gnus/.authinfo.gpg" "~/gnus/.netrc"))

受信設定

設定したメールアカウントは次の4つです。

  • Gmail
  • IMAPで扱う独自のアカウント
  • POPで扱う独自のアカウント(二つ)
;;; ~/gnus/.gnus.el

(require 'nnir)

;; Make Gnus NOT ignore [Gmail] mailboxes
;; Gmailのメールボックス名を無視しないようにする。
;; デフォルトの正規表現だと[Gmail]という名前にマッチしてしまうので。
(setq gnus-ignored-newsgroups "^to\\.\\|^[0-9. ]+\\( \\|$\\)\\|^[\"]\"[#'()]")

;; Use gnus-secondary-select-methods only
;; gnus-select-method は使わず gnus-secondary-select-methods のみを使う。
;; リストだけ使う方が追加・廃止が楽なので。
(setq gnus-select-method '(nnnil))

;; Gmail (IMAP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnimap "gmail"
          (nnimap-address "imap.gmail.com")
          (nnimap-server-port 993)
          (nnimap-stream ssl)
          ;; Search
          (nnir-search-engine imap)))

;; My Email 1 (IMAP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnimap "myaccount1"
          (nnimap-address "myimapserver1.example.jp")
          (nnimap-server-port 993)
          (nnimap-stream ssl)
          ;; Search
          (nnir-search-engine imap)))

;; WanderlustのMH形式フォルダを読み込む。が、起動時に毎回時間がかかるのでコメントアウト。
;; ;; My Old Email Archive (Wanderlust's MH Folders)
;; (add-to-list
;;  'gnus-secondary-select-methods
;;  '(nnmh ""
;;         (nnmh-directory "~/Mail")
;;         (nnmh-get-new-mail nil)))

;; 手元にダウンロードしてくるタイプのPOP、IMAPアカウント。
;; My Email 2,3 (POP)
(add-to-list
 'gnus-secondary-select-methods
 '(nnml ""))

(setq mail-sources
      '((pop :server "mypopserver2.example.jp"
             :port 995
             :user "mypopuser2"
;;             :password "???" ;;=> .authinfo に machine mypopserver2.example.jp login mypopuser2 port 995 password ??? と書いた方が良い。ミニバッファにパスワードを入力しても、POPの場合はなぜか自動で保存してくれないので手動で書き込んだ方が良い。
             :authentication apop
             :stream ssl
             :leave t ;; or N days
             )
        (pop :server "mypopserver3.example.jp"
             :port 995
             :user "mypopuser3"
;;             :password "???"
             :authentication apop
             :stream ssl
             :leave t
             )))

;; ソースによってグループを分ける。
(setq nnmail-split-methods
      '(("myaccount2" "^X-Gnus-Mail-Source: pop:mypopuser2@mypopserver2\\.example\\.jp$")
        ("myaccount3" "^X-Gnus-Mail-Source: pop:mypopuser3@mypopserver3\\.example\\.jp$")
        ("unknown-source" "")))

Gnusでは情報源は gnus-select-methodgnus-secondary-select-methods に設定します。 なぜか同じような機能のものが二つあるのですが、おそらく最初は gnus-select-method だけがあって、後から複数の情報源を設定出来る gnus-secondary-select-methods を追加したのではないでしょうか? 今回はリストで複数設定出来る gnus-secondary-select-methods のみを使います。 gnus-select-method には nnnil を設定して無効化しました。ネットニュースを読むならニュースサーバをここに設定しても良いと思います。

nnimap で指定したIMAPサーバ上のメッセージは、手元にファイルをダウンロードすることなく読むことが出来ます。

nnmlmail-sources で指定したPOPサーバ上のメッセージは、 ~/gnus/Mail/ (デフォルトだと~/Mail/)にダウンロードしてから読むことになります。

mail-sources に複数のアカウントを指定した場合、全アカウントのメールが全て一箇所にまとめられてしまうようでした。なので nnmail-split-methods で振り分けの設定をしています。幸い X-Gnus-Mail-Source というヘッダーがついていたのでそれで振り分けられました。何かもう少しうまい仕組みがあれば良いのですが……。グループパラメータの mail-source が使えるかなとも思ったのですがそちらは試していません。

POPでメールをサーバに残すには :leave t を指定します。これが無いと受信したメールはサーバから削除してしまうので注意してください。整数で日数を指定することも出来るようです。

POPのパスワードは .authinfo(や.authinfo.gpg)にあらかじめ書いておくことをおすすめします。どこにも書かなければアクセス時にミニバッファで聞かれますが、自動的に .authinfo に保存してくれませんでした。 nnimap の場合は保存してくれたのですが。

IMAP(nnimap)のパスワードも .authinfo に保存します。あらかじめ書かなくてもミニバッファで聞かれたときに入力すれば自動的に保存されました(むしろ下手に書いて形式に間違いがあってハマりました)。

Gmailで二段階認証している場合等はアプリパスワードを発行する必要があると思います。

送信設定

複数のアカウントがあるので送信設定も適切に切り替える必要があります。

何を切り替えるべきか:

  • (Fromの)名前
  • (Fromの)メールアドレス
  • 文末の署名
  • 送信したメールをどこに保存するか(Bcc, Gcc)
  • SMTPサーバとの接続情報

切り替える条件案:

  • Fromヘッダー
  • メール作成時のグループ

探してみるとFromによってSMTPを切り替える設定(Multiple SMTPAccounts - Emacs Wiki)を見つけたのですが、色々試してみて最終的に gnus-posting-styles でメール作成時のグループにより適切なヘッダーを設定する方法で落ち着きました。

;;; ~/gnus/.gnus.el

;; デフォルト送信設定
(setq smtpmail-stream-type 'starttls) ;;基本的に全てstarttlsで送る。
(setq smtpmail-smtp-server "mysmtpserver2.example.jp"
      smtpmail-smtp-service 587
      smtpmail-smtp-user "mysmtpuser2") ;;デフォルトのSMTPサーバ
(setq user-full-name "My FullName"
      user-mail-address "myaccount2@example.jp") ;;デフォルトの名前とメールアドレス

;; メール作成時に作用する設定
(setq gnus-posting-styles
      '(
        ;; IMAP
        ("^nnimap\\+gmail:"
         (name "My FullNameG")
         (address "myaccountg@gmail.com")
         (signature "My FullNameG\nmyaccountg@gmail.com")
         (gcc "nnimap+gmail:Sent")
         ("X-Message-SMTP-Method" "smtp smtp.gmail.com 587 myaccountg@gmail.com"))

        ("^nnimap\\+myaccount1:"
         (name "My FullName1")
         (address "myaccount1@example.jp")
         (gcc "nnimap+myaccount1:INBOX")
         ("X-Message-SMTP-Method" "smtp mysmtpserver1.example.jp 587 mysmtpuser1"))

        ;; POP
        ("^nnml:myaccount2\\(\\..*\\)?$"
         (name "My FullName2")
         (address "myaccount2@example.jp")
         ("Bcc" "myaccount2@example.jp")
         ("X-Message-SMTP-Method" "smtp mysmtpserver2.example.jp 587 mysmtpuser2"))

        ("^nnml:myaccount3\\(\\..*\\)?$"
         (name "My FullName3")
         (address "myaccount3@example.jp")
         ("Bcc" "myaccount3@example.jp")
         (signature "** My FullName3 **")
         ("X-Message-SMTP-Method" "smtp mysmtpserver3.example.jp 587 mysmtpuser3"))
        ))

gnus-posting-styles変数を使用すると様々な条件でメールヘッダーや署名等を切り替えることが出来ます。この変数はメール作成を開始する時点で作用するので、本文を書くときに効果を目で確認出来ます。

上の設定ではメール作成時のグループ名を元に、名前、メールアドレス、署名、送信済みメールの送り先、使用するSMTPサーバを切り替えています。

送信したメールの保存先は、私の場合次のようにしました。

  • POPアカウントならBccで自分自身にコピーを送る
  • IMAPアカウントならGccを送信済みフォルダーに設定する

POPでBccしているのは他のPCからでも見られるようにするためですが、それが不要ならばGccをnnml:myaccount2とかにしてローカルに保存するだけでも良さそうです。

X-Message-SMTP-Method というヘッダーを使用すると送信時に使用するSMTPサーバ(ポート、ユーザ名)を指定出来ます。このヘッダーは送信時に削除されて相手には届きませんでした(試した限り)。 この方法だとSSL/TLS暗号化の方式を個別に指定出来ないような気がしますが、私の場合は全てSTARTTLSで問題ありませんでした。デフォルトの設定では、使えるならSTARTTLS、使えなければ暗号なしになるみたいです。

見た目の設定

;;; ~/gnus/.gnus.el

;; Tree view for groups.
;; デフォルトをトピックモードとする。
;; https://www.gnu.org/software/emacs/manual/html_node/gnus/Group-Topics.html
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

;; Referencesヘッダーを元にスレッドを構築する。同じSubjectというだけでスレッドになると困るので。
;; gather threads by References headers (default is by subject)
(setq gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references)

;; Summary Line Format
;; 短い年月日日時(190503T1234)、短いFrom、記事行数不要
(setq gnus-summary-line-format "%U%R%z %&user-date; %I%(%[%-15,15f%]%) %s\n"
      gnus-user-date-format-alist '((t . "%y%m%dT%H%M")))

GnusかWanderlustか

ここまでやってみましたが、結局私は当面Wanderlustを使うと思います。

手元の環境(Windows+自分でビルドしたEmacs)だと数回に一回は送受信時にエラーが発生します。これはGnusでもWanderlustでも起きるのですが未だに原因がつかめていません(SSLでも平文でも起こるのでgnutlsがらみでも無さそう?)。 今回Gnusを試してみたのはこれが解決するかもしれないと思ったのが一番の理由なのですが残念ながら変わりませんでした。

メールソフトとしての使い勝手はWanderlustの方が普通だと思います。カスタマイズを進めていけばGnusでもそれほど悪くないのかもしれませんけれど、デフォルトの状態があまりにも。

Wanderlustはバグが多くそれが一向に解決される気配が無いのも今回Gnusを試した理由の一つなのですが、まぁ、Wanderlustでも一応最低限は使えていますので。

添付ファイルまわりとか日本語まわりとかはまだ試していないので分かりません。Wanderlustだとおかしな挙動をすることが良くあるので、それがGnusで問題なければ良いのですが。