2019年2月11日月曜日

循環リストの応用例その2(Luhnアルゴリズム)

Luhnアルゴリズム(Luhn algorithm)は、
様々な識別番号の認証に使われている単純なチェックサム方式。
たとえば、クレジットカード番号にもこの方式が使われている。
詳細は wikipeida参照。

このLuhnアルゴリズムのさまざな言語での実装が、
Implementation in 88 languages on the Rosetta Code project
に載っているので、そちらを見ていただいても構わない。

で、先日ISBNのコードを書いている途中、
たまたまLuhnアルゴリズムに出くわしたので、
「関数の循環リスト」を使った、schemeでの実装を書いてみた。
なお、入力は文字列として受け取る。
(define (check-luhn num-string)
  (define luhn-digit
    (circular-list (lambda (x) x)
                   (lambda (x) (vector-ref #(0 2 4 6 8 1 3 5 7 9) x))))
  (zero? (remainder (fold + 0 (map (lambda (f x) (f x))
                                   luhn-digit
                                   (reverse (map digit->integer (string->list num-string)))))
                    10)))
;; (check-luhn "1234567812345678")

なんというか、schemeならではの素敵なコードになったと思うので、
ここに記録しておく。

以上

2019年2月2日土曜日

ISBNチェッカー(循環リストの応用例)

循環リストの応用例

最近、ISBNの入力ミスを発見するためのスクリプトを書いた。
循環リストを使った美しいコードだと思う。

だけど、「循環リスト(Circular list)なんて観念で、
(理論の)完全性のために存在しているだけ」と言われることがある。
また、Googleで「循環リスト」を検索すると
関連検索として「循環リスト 応用例」を提案してくる。

でも、循環リストを使わないと実現しにくいアルゴリズムもあるし、
循環リストはSchemeの楽しさを高めている思っている。
そして私はこよなくschemeを愛している。
だから、ここに実用的な「循環リストの応用例」として
ISBNチェッカーを公開する。

ISBNチェッカー

ISBNは書籍を一意に示すための番号である。
ISBN-13の最後の1桁はチェックデジットであり、以下のように計算される。
----- -----
現行規格のISBN (ISBN-13) のチェックディジットは、JANコードと同じく、「モジュラス10 ウェイト3・1(モジュラス10 ウェイト3)」という計算法にて算出される。(チェックディジットを除いた一番左側の桁から順に1、3、1、3…を掛けてそれらの和を取る。和を10で割って出た余りを10から引く。ただし、10で割って出た余りの下1桁が0の場合はチェック数字を0とする。)
----- -----
「ISBN」(2018年12月21日 (金) 08:59UTCの版)『ウィキペディア日本語版』より引用[注1]

これを実装すると以下のようになる。ただし、入力は文字列として受け取る。
(use srfi-1)
(define (check-isbn13 num)
  (define weight (circular-list 1 3))
  (zero? (remainder (fold + 0 (map (lambda (x y) (* x y))
                   weight
                   (map digit->integer (string->list num))))
            10)))
「一番左側の桁から順に1、3、1、3…を掛け」るところに循環リストを使っている ((circular-list 1 3)は'(1 3 1 3 ...)となる循環リストを返す。)。
左から1桁ずつループして拾っているのだけど、
掛ける数が1と3で交互なので、
(1 3 1 3 ...)となっている循環リストに対して、
carで先頭を拾って使い、cdrして残りを次のiterationに渡している。
場合分けとかフラグとかを使っていないところが美しいでしょう?

うさぎとかめのアルゴリズム

ところで、あるリストを与えられた時、それが循環リストになっているかをチェックする コードが以下にある。
大変美しく、ぜひご覧いただきたいので、ここで勝手に紹介する。

以上

2019年1月26日土曜日

ふわっとした情報から一次ソースまでたどり着く方法(RFC編)

0. 要旨

「メールアドレスのドットの連続はRFC違反」みたいな ふわっとした情報があって興味をもったとき、 技術屋なら 「どのRFCのどのセクションにどのように記述されているか」 みたいな一次ソースを当然確認したくなるでしょう?
今回、メールアドレスのルールが気になって調べたのでここに記録しておく。

1. 一次ソースまでの道のり

1.1. Wikipedia日本語版「メールアドレス」

ざっと説明を読む。ふむふむ。 RFC 5321とRFC 5322への参照がある。 取り合えずリンクを開く。
(今回は、Wikipedia日本語版に参照先まで書いてあってラッキーなパターン。 日本語版に参照がなくても英語版を眺めると参照先が見つかることもあるし、 さらにインターネットをさすらう場合もある。)

1.2. RFCを眺める

タイトルは
RFC 5321:Simple Mail Transfer Protocol
RFC 5322:Internet Message Format
で、どちらもボリュームがある。
RFC 5321から読むことにする。

1.3. RFC 5321を眺める

まず左上にObsoleted byがないことを確認する。
(もしObsoleteになっているなら、 Obsoleted by: XXXXのXXXXを読むべきだから。)
長いのでさらさらスクロールしてみる。
中程でバッカス・ナウア記法(BNF)的な 表記を見つけて手を止める。その節は 「4.1.2.  Command Argument Syntax」。
読んでみるが、いまいち解決しない。
@の左側はLocal-partと呼び、それはDot-stringであって、、、 と書いてあるが、atext以降が解決していない! そしてこの文書にはatextはこの1個しかない!

1.4. RFC 5322を眺める

気を取り直して、RFC 5322を開き「atext」を検索する。 3個めのatextでBNF的な表記に出くわす。その節は「3.2.3.  Atom」。 atextが定義されている。なんだatextは普通の文字 (アルファベットと数字といくつかの記号)のことか。

1.5. RFC 5321に戻る

ここで、RFC 5321 4.1.2に戻る。
----------------------------------------------
(前略)
   Dot-string     = Atom *("."  Atom)
   Atom           = 1*atext
(後略)
----------------------------------------------
たしかに、Local-partは確かにドットは連続しないわ、と納得する。

<読み方>
読み方は人によるところが大きい。
私はボトムアップが一番理解しやすいので、 最下層(定義に近いもの)から順番に組み立てるように理解する。
「Atomは任意個の普通の文字。
Dot-stringは先頭にAtomあって、その後に任意個の{.(ドット) とAtomの連結}が続く。
ということは.(ドット)は連続で現れないし、先頭にも最後尾(@の直前)にも現れない!」

1.5. RFC 5321とRFC 5322

だけど、RFC 5321の途中からRFC 5322の定義を読むのでよいのか、 と我に返る。
RFC 5321で5322を検索すると 「1.2.  History and Context for This Document」に 「RFC 5322はcompanion documentだよ」と書いてあるので、 よいことにする。

2. おまけ

2.1. ITEFのRFCのページ

ITEFのRFCのページは便利。
https://tools.ietf.org/html/rfc5321
Obsoleteになっているもの、updateがあるものは 最上部で分かるし、 他のRFCへの参照はハイパーテキストリンクになっている。

2.2. バッカス・ナウア記法(Backus-Naur form)

BNFは学部3年のときに情報学科の講義で勉強して、 なるほどすごい、と思った。
でも、いつもギリシャのお酒の好きな神様を思い浮かべてしまう。 (綴りはちょっと違う)

2.3. Request For Comment

RFCに「違反」という言葉は似合わないと思っている。
「法令」ではない、ただの「Standard」なのだから、 「準拠していない」くらいが適切と思う。

以上

2018年2月4日日曜日

[FreeBSD] uim-anthyは動きます(FreeBSD 11.1、 2018年2月)

0. 要旨

2018年2月、FreeBSD環境で、portupgradeからpoudriereに乗り換えてportsを全体的に入れ直したら、日本語が入力ができなくなった。
MATEのStartup ApplicationsとしてiBusが立たないようにして、
# uim-module-manager --register anthy
して、
$ uim-pref-gtk
で設定を直したら、また日本語が入力できるようになった。

1. 環境

OS:FreeBSD 11.1-STABLE
PackageとPorts: portupgradeからpoudriereに乗り換えた
input method: uim※

※uimは昔から使っている。
~/.xsessionに以下を書いている。
export GTK_IM_MODULE=uim
export XMODIFIERS=@im=uim
uim-xim &
~/.uimに以下を書いている。
(define default-im-name 'anthy)

2. 状況と検索と試行錯誤

FreeBSD環境で、portupgradeからpoudriereに乗り換えてportsを全体的に入れ直したら、日本語が入力ができなくなった。

2.0 設定の上書き?

設定が上書きされた可能性があるので、確認する。
(System->Preferences->Personal->Input Methodで、uim-pref-gtkというuim設定用のAplicationが立ち上がる。)
Hotkeyが変わっている気がしたので直したが、解決しない。

2.1 iBus

こういうときはiBusがhotkeyを食べている可能性がある。
$ ps -aux |grep ibus
したらibus daemonがいる。ibus daemonはいらないので、killする。
それからMATEのStartup Apllicationsを確認したらそこにもいたので、削除する。
(System->Preferences->Personal->Startup Applicationsで、MATEが立ち上がった時に立ち上げるデーモン類を設定する)

2.2 状況調査

  • atril(MATEのpdf/ps viewer、gnomeのevinceにあたる、いつの間にかgtk3に依存するようになっている)の検索窓にも入力できない。
    ということは、2017年5月とは違いgtk3まわりの問題ではなさそうだ。
  • よく見ると
    uim-pref-gtk
    のGlobal SettingでAnthyが選べない。
    Canna, SKK, Ajaxとかあるのに、Anthyがない。
  • いろいろ検索していると、ある nakagami の日記 で~/.uimに
    (require-module "anthy")
    という見慣れない記述を見つける。これは何だ?
  • さらに色々検索していると、
    CustomizeUim で~/.uim.d/custom/というディレクトリが出てくる。
    ls ~/.uim.d/custom/
    すると
    custom-skk-keys1.scm
    ...
    custom-tutcode-keys1.scm
    とかあるのに、
    custom-anthy-*.scm
    は1つもない。
  • 何の気はなしに、
    $ uim-
    でタブを押してどんなコマンドがあるかなと見ていたら uim-module-managerというコマンドを発見する。
    $ uim-module-manager
    Usage:
      uim-module-manager [options]

    Options:
      --register <modules>   Register the modules
      --unregister <modules> Unregister the modules
      --path <path>          Target path where installed-modules.scm
                             and loader.scm to be installed
      --unregister-all       Unregister all modules

    Example:
      uim-module-manager --register anthy skk
      uim-module-manager --register prime --path /usr/local/share/uim
      uim-module-manager --register personal-module --path ~/.uim.d/plugin

    Note:
      Registeration and unregistration cannot be done simultaneously.

    やってみる。
    $ uim-module-manager --register anthy
    ファイルのパーミッションがないと言われた。

3 解決

$ sudo -s
# uim-module-manager --register anthy
をする。

~/.uim.d/custom/
の下に
custom-anthy-*.scm
が一式できた。(他のcustom-skk-*.scmなどの一式も更新された)

$ uim-pref-gtk
左側にAnthyが登場した。
Enabled input methodsには並んでいないが、 Editを押すと、disableにAnthyが登場していた。
Anthyをenableに、それ以外をDisableに移動した。 他のセッティングも下の画像のとおりに直した。



これで、元のように日本語が入力できるようになった。
めでたしめでたし。

2017年7月9日日曜日

といだ後の米の重さ

食事の用意をしているときに、ふと気づくと「今日はお米を何合といだっけ」と 分からなくなることがありますね?
「といだ後の米の重さ」で検索したけれど、根拠のある数字が見つからなかったので、 自分で測定しました。
(追記:今、この記事を書きながら「米 吸水」で画像検索すると、いくつかのウェブページが見つかりました。でも実験したので公開します。)
もちろん、米の品種、とぎ方、水温、浸水時間などたくさんのパラメータがありますので、 参考値としてご利用ください。

実験条件

米の品種:ゆめぴりか
米の量:計量カップで1.5合はかりとる
(確認のため、1合の重さを測定したら、148gだったので、実際は1.5合強である)
季節:6月〜7月
※食べるために炊くついでに測定しているので、データはそれぞれ違う日に測定している。

実験方法

1. 計量カップで米1.5合はかりとり、重さをはかる(乾燥重量)。
2. とぐ。
3. ざるにあげて、軽く水を切って重さをはかる(といだ直後の重量)。

4. 水に30分つける。(余裕があれば水温を測定する)
5. ざるにあげて、軽く水を切って重さをはかる(吸水後の重量)。
6. 炊いて、食べる。

実験結果

乾燥重量(A)[g]といだ直後の重量(B)[g] B/A吸水後の重量(C)[g] C/A 吸水開始時の水温[℃] 吸水終了時の水温[℃]
225.5252.51.120290.01.28622.722.9
230.0257.51.120294.51.28025.325.3
230.0256.51.115299.01.30025.225.4
228.0255.51.121290.01.272
230.5258.51.121300.01.302
228.5256.01.120300.51.31525.825.9
229.0256.51.120298.51.30325.325.5
228.0256.01.123296.51.300


結論

米の乾燥重量は、1合約148gである。
米をといだ直後の重量は、乾燥重量の約1.1倍になっている。
米をといで30分浸水後の重量は、乾燥重量の約1.3倍になっている。

補足

データをプロットしてみると、嫌な感じにバラつく。
コントロールできていない変数がありそうな、ちゃんとできていない実験のようなデータで、論文なら査読を通らなそうだ。
だから、誤差の推計も解釈もしないで、そっと「約1.X倍」とだけ言って、この記事は終わりにする。

以上

2017年5月27日土曜日

[FreeBSD] firefox 53.0.3とuimとgtk3

0. 要旨

2017年5月、Freebsd環境で、firefoxを53.0.3にportupgradeしたら、日本語が入力ができなくなった。
pkgsrcめも - isihara@るるる.おーぐのぺーじ
「uimにgtk3オプションを入れてmakeし直すと、入力できる。(デフォルトでは入っていない。)」
の記述をヒントに、
portupgrade -N textproc/uim-gtk3
したら日本語入力できるようになった。

1. 環境

OS:FreeBSD 11.1-PRERELEASE #2
Firefox: 53.0.3にversion upした。(穴はさっさと塞ぐべし。)
input method: uim※

※uimは昔から使っている。
~/.xsessionに以下を書いている。
export GTK_IM_MODULE=uim
export XMODIFIERS=@im=uim
uim-xim &

2. 状況と検索と試行錯誤

Firefoxのバージョンを上げたら、日本語が入力できなくなった。
atril(mateのpdf/ps viewer、gnomeのevinceにあたる)の検索窓には日本語を入力できる。
ということは、input method側の話ではないのかもしれない。

検索ワードを変えて、色々googleで検索する。
"firefox 53 日本語";それらしいものはみつからない。
"firefox nihongo";日本語が入らない人のために、"nihongo"が入るようにしているページを期待したが、とくにない。
"firefox input method":add-onの話ではないのだよ。
"firefox uim": FreeBSD + uim-anthy + Firefox | どうでもいいブログ - TeaCup
その情報、重要で記録に残していただいてありがたいのだけれど、その部分はすでに正しくなっている。

"firefox gtk_im_module":似た状況の人はいないようだ。それにしても、最近はuimはトレンディでないのかしら。

"firefox uim",1か月以内: pkgsrcめも - isihara@るるる.おーぐのぺーじ
 www/firefoxでuimで日本語入力できない [2017/5/6]
uimにgtk3オプションを入れてmakeし直すと、入力できる。(デフォルトでは入っていない。)
という記述がある。

BSDの話だし、時期も近いし、やってみようと思ってportsを見ると
textproc/uim-gtk
textproc/uim-gtk3
と2つある。何だこれは!uim-gtkしか入っていないぞ!と textproc/uim-gtk3もportsからインストールする。

rebootしたらfirefoxで日本語入力できるようになった。
めでたしめでたし。

先達のたった2行で解決できたことに感謝し、私も記録を残すこととする。

3. 推測

firefoxはしばらく前から、gtk2とgtk3の両方に依存しているようだが、
Input Methodまわりがgtk2からgtk3に変わったのかな。
(/usr/ports/graphics/atril/Makefileを見ると、atrilはgtk2に依存しているようだ。)

2016年12月10日土曜日

Canon PIXUS iP2700をFreeBSDからLPDで使う

0. 前置き

最近、うちのプリンタ(Canon BJ S500、2001年発売。2008年頃ヘッドを交換した)の調子が悪かった。

LEDで「サービスが必要なエラー」だと訴えかけてきて、バキバキと異音を発していたのだ。結局、分解して歯車を手で回したりしたら生き返ったのだが、治るまでの間に、後継機種がFreeBSDで使えるかを検討したので、その記録をここに公開する。

注意!!!実機では試していないので、本当に印刷できるかは確認していません!!!

1. 機種の選定

うちのプリンタは、
 出かけるときに地図を印刷する。
 論文等をちょっと印刷する。
 航空券などのeチケットを印刷する。
ような感じで、使っている。BJ S500で何も不満はない。

また、手元のFreeBSDビギナーズバイブル(改訂第2版、2005/09)[1]に記載されている非ポストスクリプトプリンタは、CanonのPIXUS 2機種である(なお、PIXUSは、Wonder BJシリーズの後継である)。これらの理由から、CanonのPIXUSを第1候補に考えた。

次に、Canonの「PIXUS選べるガイド」ページに行く。http://cweb.canon.jp/pixus/special/room/index.html?id=pix1 (公式サイトのPIXUSのトップhttp://cweb.canon.jp/pixus/からタイミング良くクリックするべし。)
「くらべてわかる早見表」から、iP2700で十分と思った。
価格.comを見ると、3000円代であり、これにしようと考えた。

[1] 後藤大地著、FreeBSDビギナーズバイブル、ISBN978-4839918941、http://www.amazon.co.jp/FreeBSDビギナーズバイブル-MYCOM-UNIX-Books-後藤/dp/4839918945

2. CUPS

FreeBSDでの印刷は、「CUPSプリンタドライバを使い、CUPSで印刷する方法」「LPD用のフィルタを使い、LPDで印刷する方法」の2つに大別される。

今のBJ S500はquantumの記録:FreeBSDからCanon BJ S500で印刷できた で書いたようにLPDで使っている。

前述したような用途で使っているので、pdfをatril経由で印刷するか、firefoxからpdfに保存して、atril経由で印刷することがほとんどである。したがって、CUPSはいらなくて、LPDで動けば十分である。(なお、ヘッドの位置合わせやスリープ設定等は、windows機でやればいいと割りきっている。)

一方、CUPSは色々できるが、構成が大きくて、動作させるまでもっていくのが大変そうである。(そもそもLinux用ドライバをFreeBSDで動かすのだ、困難は少ない方がいい。)

これらの理由から、iP2700のLPDでの動作確認をすることとした。

3. 予習

ビギナーズバイブルにはPIXUS iP4100が載っている。
「ip4100 linux」でググって、「Canon Bubble Jet Print Filter Ver 2.50 for Linux」のダウンロードページに行く。
共通パッケージ、機種別パッケージ、LPRng追加パッケージがダウンロードできるようになっていて、それぞれ、rpmがダウンロードされる。
tar xvf *.rpm で展開すると、usrディレクトリができる。(5年前から知っているけど、tarでrpmも展開できる)
ビギナーズバイブルを見ると必要なファイルは usr/local/bin/bjfilterpixusip4100 (あえて相対パスで書いた)で、それもusrディレクトリの下にできる。これはフィルタである。

4. iP2700のドライバを試す

前提条件

マシンはFreeBSD 11.0-stable #3。Linux互換も動くように設定してある。現在BJ S500が使えていて、使えるようにしたときの記録は、quantumの記録:FreeBSDからCanon BJ S500で印刷できた に公開している。
この記事の後、linux-baseをf10からc6に変更した。また、graphics/linux-f10-png10に穴が開いていて、portsで追いかけるのがしんどくなったので、必要なライブラリを確保して、パッケージをアンインストールしたあと、BJ S500のために必要最低限のライブラリだけを/compat/linux/usr/lib/に書き戻す作業もしている。(ノートに記録はあるのだが、blogでの公開はしていない。)
なお、前述のようにプリンタ本体はないので、印刷できるかまでは試していない。

4.0 ダウンロードする

「ip2700 linux」でググって、「IJ Printer Driver Ver.3.30 for Linux」のダウンロードページに行く。rpm版をダウンロードする。以下/tmp/にcnijfilter-ip2700series-3.30-1-i386-rpm.tar.gzをダウンロードしたとする。

4.1 展開する

まず展開する。
$ cd /tmp/
$ tar xvf cnijfilter-ip2700series-3.30-1-i386-rpm.tar.gz
/tmp/cnijfilter-ip2700series-3.30-1-i386-rpm/ ディレクトリができる。
その下に、install.sh、packages、resourcesがあって、packagesの下には、2つのrpmがあるので、とりあえず展開する。
$ cd cnijfilter-ip2700series-3.30-1-i386-rpm/packages
$ tar xvf cnijfilter-ip2700series-3.30-1.i386.rpm
$ tar xvf cnijfilter-common-3.30-1.i386.rpm
usr/ディレクトリができる。usr/local/bin/下にいくつかファイルがある。どれかがフィルタだとうれしい。どれだろう。lddしてみる。
$ ldd usr/local/bin/* |less
ここで、予習で用意したbjfilterpixusip4100のlddの出力と比較すると、usr/local/bin/cifip2700がフィルタのようだ。

4.2 動作させる

動作確認する。
Linuxバイナリのライブラリパスの設定とかやや面倒だから、/compat/の下に置いてしまう。
# cp usr/local/bin/cifip2700 /compat/linux/usr/local/bin/
動作確認には、今使ってる(/etc/printcapでif設定されている)/usr/local/libexec/canonを流用する。コピーして(canon_ip2700と名前を変えた)、フィルタ名を書き換えたものを次に示す。

#!/bin/sh

/usr/local/bin/gs \
    -q -r600 -dNOPROMPT -dSAFER -sPAPERSIZE=a4 -sDEVICE=ppmraw \
    -sOutputFile=- - quit.ps | \
    /compat/linux/usr/local/bin/cifip2700 --full --imageres 600 --lgmon

exit 0

おもむろに実行する
$ ./canon_ip2700
とライブラリ libcnbpcmcm364.soが足りないと言われる。
$ ls usr/lib/*
すると、libcnbpcmcm364.so.8.0.1と長いファイル名で、一式ライブラリファイルがあるが、短いファイル名のシンボリックリンクはない。tarなら、シンボリックリンク普通に使えるのになぜに?と思いながら作る。
$ cd usr/lib
$ for i in *.so do ln -s $i ${i%%.so.*}.so
/compat/の下にコピーする。
# cd ../../
# cp usr/lib/*.so* /compat/linux/usr/local/bin/

再挑戦する。
$ ./canon_ip2700
とライブラリ libpng12.so.0が足りないと言われる。portsから入れられそう。
$ ls -ld /usr/ports/*/*png*
すると、/usr/ports/graphics/の下に、linux-c6-png、linux-c7-png、linux-f10-pngがある。どれを使えばいいのだ?
$ pkg info -xI linux_base
linux_base-c6-6.8_6が現在のうちのマシンのlinux-base。5年前はf10だが変えたのだな。
# cd /usr/ports/
# portupgrade -N graphics/linux-c6-png

再挑戦する。
$ ./canon_ip2700
--lgmon: unknown optionと出た。ライブラリは揃って動き出したようだ。./canon_ip2700スクリプトから --lgmonを削除する。

再挑戦する。
<?xml version="1.0" encoding="utf-8" ?> (snip) </cmd>□□BJLSTART
ControlMode=Common
SetTime=2016 (snip)
BJLEND□

と出力始めるので、Ctrl-Cで止める。この出力は、今の/usr/local/libexec/canonとよく似ているので、とりあえず良さそうだ。

5. 補足

iP4100をLinux+lpdで使う場合にも、この記事は参考になるであろう。/compat/linux/を/(すらるーと)に読み替えて、portsの代わりにrpmなりを使えばよろしい。