2020-09-17

gem installでnokogiriとrmagickが失敗する場合

なぜ失敗するかというと、nokogiriとrmagickはシステムに特定のソフトウェアやライブラリが入っていることに依存しているからだ。依存しているソフトウェアやライブラリをPATHの通った場所に用意してやらなければビルドができない。

nokogiriで問題になるのは主にlibxml2だ。nokogiriは独自のパッチをあてたlibxml2をビルドして使う。libxml2のビルドに必要になるソフトウェアとライブラリがある。

具体的な方法は公式ドキュメントに情報がある。

Installing Nokogiri - Nokogiri

特に入っていない可能性が高いのはzlibとliblzmaだ。Debian系ならば以下のようにパッケージをインストールする必要がある。


apt install build-essential patch ruby-dev zlib1g-dev liblzma-dev

rmagicはImageMagickのRuby bindingだが、システムにImageMagickがインストールされていなければならない。またインスールされているヘッダーファイルやオブジェクトファイルを発見するためにpkg-configも必要だ。

GitHub - rmagick/rmagick: Ruby bindings for ImageMagick

Debian系では以下のように依存パッケージをインストールする


apt install build-essential pkg-config libmagicwand-dev

2020-09-05

C++20の標準規格が承認された

C++20の標準規格がC++標準化委員会で承認されたそうだ。

残念ながら私の今の仕事がC++ではなくなってしまったので、C++の参考書を執筆する時間を捻出することはできないし、C++20に追加された一部の機能に懐疑的な立場であるので、喜ぶべきなのかどうかよくわからない。

一時期、C++の参考書執筆を続けるべく、C++の教育に価値を見出しそうな転職先を探したこともあったが、どうやら国内ではC++の最新規格の教育にそれほど価値がないらしく、結局今は普通のプログラマーにpivotしつつある。

普通のプログラマーはC++教育者とはだいぶ特性が異なる。C++の規格は一個の人間が全容を理解できる程度の小さな問題であり、完全に理解して解説するだけであった。しかし、現実のソフトウェアは一個の人間が理解できる規模を遥かに超えている問題であり、自分の担当の範囲外について理解しようとする無駄な努力をやめなければならない。自分が入社する前から開発されていた数千万行のコードをすべて理解するのは不毛だし、したところで仕事ができるようにはならない。使うプログラミング言語やソフトウェアも多岐にわたるため、すべてを理解するのは一個の人間の時間では足りない。普通のプログラマーは巨人の肩の上に乗っているが、その巨人について理解しようとしてはならないのだ。

C++は私のフルタイムの時間と趣味の時間をどちらも投じて全容を理解できる規模の問題だったが、今は仕事ではなくなり、また趣味も健康面を考慮して運動に切り替えた今、C++に割くための時間が足りない。C++20の参考書は暇な時間にたまに執筆しているが、おそらく完成することはないだろう。

2020-08-31

360度カメラの残念な現状

冬のスノーボードのために動画撮影用のカメラを買おうと思っている。今の所、GoProの次のモデルが発表されたら買うのを検討しようかと思っているのだが、360度カメラという選択肢も出てきた。しかし調べたところ、360度カメラの現状はあまりよろしくない。

360度カメラではカメラを中心に全周囲を撮影できる。これによって追い撮りするときに撮影対象を収めそこねたという問題を回避できるし、自分も周囲も同時に撮影できる。私の目的は思い出を記録しておくことだから、360度カメラはとてもいい選択肢のように思える。

360度カメラは2つ以上のレンズを使って撮影した複数の映像をつなぎ合わせることで実現されている。一般的な製品では半球レンズを2つ使って2つの動画を撮影してつなぎ合わせている。

撮影した生の映像は、半球レンズによって著しく歪んだ2つの動画にすぎない。このままでは見るに耐えないので、視点を固定し、その視点に合わせた現実的な狭い視野を模した動画の一部のみを再生することになる。そのための処理として、製品ごとに異なる独自のプロプライエタリなソフトウェアが必要になる。

まずstitchingを行う。撮影した複数の動画は境目となる部分を単に重ねただけでは継ぎ目が明らかになってしまう。撮影部分がオーバーラップしたり、撮影方向の違いによって当たる光の関係で映像の色温度が変わってくる。これをごまかすために、オーバーラップ部分を認識したり、継ぎ目をぼかしたり、色温度を調整したりといった処理が必要になる。複数の独立したカメラを使って手動で360度動画を作るならこれはすべて手動でやらなければならない。360度カメラのようにあらかじめカメラ特性が分かっているのであれば自動化も可能になる。そのためのソフトウェアはカメラベンダーが提供するプロプライエタリなソフトウェアとなる。GoPro MAXではstitchingはカメラ内で撮影時に行われる。

次にprojectionが必要になる。我々の視野は360度ではない。そのため視聴環境に合わせて動画を変形させなければならない。視聴環境が平面ディスプレイせよ、VRディスプレイにせよ、必要だ。この処理も事前にカメラ特性がわかっていれば自動化できるが、そのためのソフトウェアもカメラベンダーが提供するプロプライエタリなものになる。

360度動画に必要なものは規格化であるように思われる。stitchingはカメラ内で行えるが、projectionは処理量的にカメラ内ではやりにくい。その方法もまだ発展段階にあり混沌としている。projectionを規格化することによってカメラベンダーごとのプロプライエタリなソフトウェアの必要をなくしてほしい。

なぜこれを問題視しているかと言うと、プロプライエタリなソフトウェアが10年後に動作する保証はどこにもないからだ。しかも360度動画のprojection処理はGPUを使うのでなおさらだ。

2020-08-15

LinuxカーネルにおけるGPLコンドーム問題への対処パッチ

最近、Linuxカーネルで話題になっていることに、GPLコンドーム問題がある。

Kernel Developers Work To Block NVIDIA "GPL Condom" Effort Around New NetGPU Code - Phoronix

発端はNetGPUと呼ばれる機能をLinuxカーネルへ追加するパッチだ。これはNICとGPUの間のデータ転送にDMA zero-copyにしてNICとGPUが直接やり取りできるようにしつつ、プロトコル処理自体はCPUに処理させるという機能で、GPGPUがますます汎用化してくるなかでGPUから直接ネットワーク越しにデータを転送する事ができるようになる。

ところが、NetGPUをNVIDIAドライバーに対応させるパッチとやら出てきて物議を醸している。NVIDIAのドライバーはプロプライエタリであり、LinuxカーネルのGPLシンボルを使うことができない。そこでLinuxカーネルとNVIDIAのプロプライエタリドライバーをつなぐ目的のためだけの薄いshimコードをGPLと称する手口が流行っている。これがGPLコンドームと呼ばれる問題だ。NetGPUがプロプライエタリなNVIDIAだけを利するものであれば、そもそもLinux上流に取り入れる意味がない。

その流れを受けて、GPLコンドーム問題に対処するパッチが出てきた。

Linux 5.9 Brings Safeguard Following NVIDIA's Recent "GPL Condom" Incident - Phoronix

これはGPLを称しながらプロプライエタリなシンボルを使うカーネルモジュールに対してもTAINT_PROPRIETARY_MODULE taintを付加するものだ。

2020-08-05

GDBがeBPFのデバッグをサポートした

GDBがeBPFのデバッグをサポートした。

GNU Debugger Adding eBPF Debugging Support - Phoronix

eBPFというのはLinuxカーネル内の仮想マシンだ。

もともと、BPF(Barkley Packet Filter)という仮想マシンがあった。これはネットワークのパケットフィルタリングをするための仮想マシンで、レジスターベースのRISCプロセッサーを模した命令セットになっている。

カーネル内で安全にユーザーコードを実行するというのは需要があるので、BPFをより汎用的に使いたいという声は多かったのだが、何分BPFは設計が古い。レジスタは2個で32bit、命令セットはatomic compare exchangeのようなモダンなプロセッサーに搭載されている命令がない。

そのためeBPF(extended BPF)が設計された。レジスタは10個で64bit、命令セットもモダンなプロセッサーにマッピングできるように見直された。

2020-08-02

キャスターボード

かねてから気になっていたキャスターボードを買った。今回買ったのはRipStik Air Proだ。

キャスターボードは一見するとスケートボードに似ているが、スケートボードではない。スケートボードは板の下に二輪ずつのウィールが前後に付いているものをいう。キャスターボードは、前後に1輪づつしかついていない。しかもウィールはキャスターにつながっていて、回転する。このキャスターは水平に対して30度ほど傾けて取り付けてある。

キャスターボードの元祖は韓国で発売されたEssBoardであるといわれている。その後、アメリカでRazorがRipStikという製品を出してから有名になった。オリジナルのRipStikは板が2枚あり、その間をトーションバーでつないでいる。その後、一枚の板でトーションもきく製品が発売された。今回買ったRipStik Air Proは1枚板の製品だ。

さっそく乗ってみたが、意外と簡単だった。スノーボードの経験が効いているものと見える。筋肉の疲労具合もスノーボードと似ている。スノーボードのオフシーズンのトレーニングに丁度いい。

キャスターボードはトーションをきかせつつ前後の足を互い違いに動かすことで進むことができる。また、腰のツイスト運動で進むこともできる。どちらもひねり運動の一部を前進運動に変換しているようで、スケートボードのキックターンと同じだ。ただ、ひねり運動から前進運動への変換には極めて低い上限があるらしく、ある速度を超えるとひねり運動が過剰になるだけで前進速度は少しも上がらなくなる。

運動負荷も高い。私は片足スクワットができる上に9kmのジョギングもできるし毎日6kmほどキックスクーターで移動している。それでもキャスターボードでは数百メートルも進むと後ろ足がパンプする。キャスターボードを始めてから一ヶ月ほどすると、筋持久力は上がってきたのだが、今度はヒザに違和感が出てきた。痛みと言うほどではないがかゆみがある。そのためヒザの調子を見つつトレーニングしている。できれば週に2回はトレーニングしたいのだが、ヒザの回復を待つために週に1回ぐらいしかできていない。

キャスターボードの構造上、スイッチができない。動画ではウイリーやオーリー、360といったトリックができるようだが、とてもできるようには思えない。

最近は板から降りずにレギュラーとグーフィーの両方で1km進むことができるようになった。

キャスターボードは後輪ウィールの消耗が激しい。RipStick Air Proには76mmのウィールがついているようで、インラインスケート用のウィールと同じものなので硬度の高いウィールを注文した。ベアリングも安いものを注文したが、いずれスケートボード用のオイルベアリングを試してみてもいいかも知れない。

2020-07-17

GitHubのArctic Vault Contributerになった

以下のような企画がある。

GitHub Archive Program | The GitHub Archive Program will safely story every public GitHub repo for 1,000 years in the Arctic World Archive in Svalbard, Norway.

1000年後に情報を残すために、GitHubの一部の注目を集めたパブリックレポジトリをフィルムに転写したものが北極海の地下シェルターのなかに収められた。その中に私の貢献したレポジトリーも含まれていた。

まず私が書いた参考書のC++11/14コア言語の原稿だ。

EzoeRyou/cpp-book: C++11 textbook

これは主に私が書き、多数の人間がPRで修正をした参考書の原稿だ。

つぎに、CPUを使ってラジオを鳴らそうというコードだ。

fulldecent/system-bus-radio: Transmits AM radio on computers without radio transmitting hardware.

sleepを挟んで1秒間に1000回CPUに負荷をかけると、周囲に1000Hzで電磁波ノイズが飛ぶ。これはAMラジオで拾えるぐらいのノイズになる。つまりCPUを使って特定の周波数のノイズを表現でき、周波数を適切に選べば音階も表現できるので、音楽を発信できるのではという雑な考えで書かれたコードが、実際に動いてしまった。私はコードをC++11に移植した。またスレッドも使うようにしてよりCPUに負荷をかけ、ノイズも強くした。

最後に私も貢献したことになっているのだが、ちょっとよく覚えていないのがこれだ。

cplusplus/draft: C++ standards drafts

これはC++標準規格のソースコードだ。おそらく私も何らかの修正をしてPRがマージされたから参照されているのだと思うが、よく覚えていない。調べれば分かると思うのだが面倒なので調べていない。

2020-07-05

スノーボード用の別荘を検討している

COVID-19によりリモートワークが長引いている。ここまでリモートワークが長引くのであれば、いっそのこと冬はスキー場近くに別荘を用意して滑りながら仕事をするのはどうか。これを真面目に検討してみた。

別荘を手に入れるためには購入するか賃貸しなければならない。購入するのは簡単だ。バブル期に立てたリゾートマンションが腐るほどある。現金が数百万もあればよい。中には取引額が負数の不動産さえある始末。問題は維持費だ。固定資産税がかかるし管理費、修繕積立金もかかる。そして日本では不動産を放棄することができないので、バブル崩壊後のリゾートマンションはババ抜きとなっている。

引退後にその地方に移住するならば購入はありだが、運動強度の高いスノーボードを老後も続けられるかどうかはわからない。

賃貸はどうかというと、これがまたスキー場近くの不動産の購入に価値がないと思わせるほど賃料が安い。月3万も出せばワンルームから2DKぐらいの部屋が借りられてしまう。問題は冬の間4ヶ月だけ借りて最低限住めるだけの環境を整え、シーズンが終わったら撤退する手間は面倒だ。通年で借りれば毎年賃貸契約と解約をする手間は省けるが、特に登山趣味もないので夏の間の価値はほとんどない。

手間もさることながら、場所の問題もある。

越後湯沢駅の徒歩4分のところに、月1.6万円のワンルームと3.2万円の少し広いワンルームがある。駅からバスで各スキー場に行くことができる。東京-越後湯沢が2時間、越後湯沢駅から各スキー場まで20-40分といったところだ。月1.6万円は極めて安く、通年借りたとしてもそれほどの負担ではない。問題は、越後湯沢周辺のスキー場は雪質はそれほどでもないということだ。東京からの交通の便がよいために栄えている場所だ。駅前の土地勘はそれほどないが、車なしで数ヶ月滞在することぐらいはできるだろう。

白馬駅から800mのところに月4.8万円の2DKがある。白馬村は前シーズンに2週間滞在したことがあり土地勘がある。白馬駅からバスや電車で各スキー場に行くことができる。スキー場までは1時間弱といったところだろう。付近には温泉もスーパーもある上、好日山荘に小さなクライミングウォールがある。東京からバスと電車の連絡にもよるが4時間ぐらいだ。

妙高市の新井駅の近くに、月3万ぐらいで1Kから2DKぐらいの賃貸がある。問題は土地勘が一切ない。地図を見る限り駅前は車なしでも数ヶ月滞在できそうな気はする。近所にボルダリングジムがある上、トップロープまでできる場所もあるようだ。問題はスキー場なのだが、新井駅から電車で26分かけて妙高高原駅に行き、そこからバスで赤倉温泉、赤倉観光、池の平、杉ノ原といった各スキー場に移動するか、関山駅に行ってバスでロッテアライリゾートと関山温泉スキー場に行くことができるようだ。新井駅からスキー場まで1時間以上かかるだろう。東京からは4,5時間ぐらいだ。

賃貸を借りるならいい加減に不動産屋に連絡を入れないといけないが、何分遠方の物件なので手間がかかるし踏ん切りがつかない。

2020-06-30

職質裁判、上告不受理で終了

職質裁判は上告不受理で終了した。

calling-110-is-suspicious/20200626_zyoukoku_huzyuri.pdf at master · EzoeRyou/calling-110-is-suspicious

経緯はこうだ。3年前にひどい職務質問を受けた。

警察官に職務質問をされた話

警察官職務執行法に規定されている通り、職務質問をするためには職務質問を受ける人物について犯罪を犯した、あるいはこれから犯罪を侵すと疑うに足る相当な理由が必要だ。それに職務質問で規定されているのは質問であって、開口一番にリュックの中身を見せろと発言するのはもはや質問ではない。そして警察官2人がかりで路上に羽交い締めにされたり、多数の警察官によって私有地の駐車場に監禁され、何の法的根拠もない手荷物検査に応じるまで解放しない。これは説得でありお願いであるので法的根拠は必要ないと2時間拘束されたわけだ。職務質問において私が警察官職務執行法に規定する相当な理由について質問したところ、警察官が答えたのは、「帽子を目深にかぶっていた」、「うつむいて下を向いて歩いていた」ということだけで、特に「うつむいて下を向いて歩いている」者は「薬物中毒者である可能性が高い」と言われた。

これに対して東京都を相手に裁判をしていたのだが、一審では不審事由がなくても声をかけることは違法ではなく、110番通報を要請することは不審事由に当たるのでその後の職務質問は正当であるという判決が出された。裁判では、東京都は本当に謎の主張をしてきだ。私が手を小刻みに震わせているという職質当時は一切指摘されなかった主張をしたり、警察はパトカーから私とすれ違ったが、そのとき私は顔を伏せてパトカーから逃げ去ったという主張だ。私には手を震わせる持病はないし、ましてや東京都の主張する私とパトカーがすれ違いざまに走り去ったという地点から10m先の自動販売機で、私はのんびりと飲み物を購入しているわけだ。私は走っていないし、走り去ったとしたらなぜ10m先の自動販売機でのんびり飲み物を購入しているというのか。そして目の前の警察官があまりにも法律を無視しているので110番通報を要請したところ、目の前の警察官は110番通報を阻止したのだ。そして裁判では110番通報の要請は不審事由に当たるとされた。

二審では110番通報の要請は怪しいという部分は削られた。しかし結論は変わらず、不審事由がないにもかかわらず職務質問は妥当であるという結論は変わらなかった。

判決で参照されている判例は、車を運転中に物損事故を起こした上で呼気検査を拒否したとか、検問での呼気検査に引っかかったが検問が違法なので違法な証拠収集であるという、もともと無理筋の裁判で、この判例を歩道を歩いている何の違法行為も事前に認められない人間を相手に適用すべきかということで上告したが、結果は上告不受理であった。

この結果から何の教訓を引き出せばいいのかわからない。一番の敗因は110番通報を妨害され失敗したことであるように思われる。110番通報の通話記録は確実に残り強い証拠として使えるので、今回東京都が主張してきた様々な嘘が嘘であるという証拠になる。当時私は録音録画する装置を持ち合わせておらず、またプライバシーを優先して携帯電話も持たない主義なのでその場で110番通報できなかったのだ。

これからは自衛のために常日頃からボディカメラを装着して持ち歩くべきだろう。常時録音録画しておき記録に残すのだ。

警察の偽証から自衛せねばならぬとは嫌な世の中になったものだ。

2020-06-21

バックトゥザフューチャーのタイムライン

話題になっていたので映画バックトゥザフューチャーのタイムラインについてまとめてみた。タイムトラベルが行われるたびに新しいタイムラインが生成される。これは映画三部作だけを参考にしており、テレビ放送アニメ、コミック・ブック、小説、ビデオゲームについては考慮していない。

T0: タイムトラベルの発生しないオリジナルのタイムライン。アインシュタインは1分後にタイムトラベルしない。地名は二本松モール。ドクはリビヤ人テロリストによって射殺される。マーティの父親は弱気でビフにゆすられている。

T1: アインシュタインが1分後にタイムトラベルする。オリジナルのT0とほとんど変化はないと思われる。

T2: マーティが1985年から1955年にタイムトラベル。木を一本車で引き倒したために地名が孤独松モールに変わる。ドクは防弾チョッキを着ていたので生存。父ジョージが自信家になりビフは真面目になる。マーティのその後の消息は不明。

T3: マーティが1955年から1985年にタイムトラベル。マーティはジェニファーとドライブデート中に腰抜け(Chiken)と煽られ交通事故を起こし障害者になる。マーティの息子がそそのかされて犯罪を起こし、マクフライ家は崩壊。

Ta: ドクがa回のタイムトラベルをしたことによりn個の世界線が発生する。aの数は不明。デロリアンにMr. Fusionが搭載され、家庭ごみを燃料に駆動するようになる。空も飛べるようになった。

T4: ドク、マーティ、ジェニファーが2015年にタイムトラベル。マーティの息子に将来降りかかる危難をなかったことにする。その後のドクとマーティとジェニファーの消息は不明。

T5: ビフが2015年から1955年にタイムトラベル。2015年に入手したスポーツ年鑑を1955年に使い博打で大儲けした結果、ビフが大金持ちになる。周辺の治安は悪化。マクフライ家は崩壊、父ジョージはビフに殺され、母ロレインはビフと再婚。ドクは精神病院に入院。没案では1985年以降にロレインはビフを射殺。

T6: ドク、マーティ、ジェニファーが2015年から1985年にタイムトラベル。T5の世界線を観測する。

Tb?: ドクがビルの屋上に追い詰められたマーティを助けるタイミングの都合が良すぎるので、ドクは何度かタイムトラベルした可能性がある。

T7: 1955年に戻りビフからスポーツ年鑑を奪う。T3の世界線に戻る。

Tc?: ドクがマーティをトンネルで助けるタイミングの都合が良すぎるので、ドクは何度かタイムトラベルした可能性がある。

T8: ドクの乗るデロリアンが雷に撃たれて1955年から1885年にタイムトラベル。マーティは郵便配達人から100年前の手紙を受け取る。ドクは手紙を書いて程なくしてビフの先祖であるビュフォード・タネンに射殺される。

T9: マーティが1955年から1885年にタイムトラベル。クララが生存。マーティがビュフォード・タネンに射殺される。

T10: マーティが1885年から1955年にタイムトラベル。ショナシュ峡谷がイーストウッド峡谷に変わる。マーティは腰抜け(chiken)と煽られても交通事故を起こさない。

Td: ドクがd回のタイムトラベル。

2020-06-13

キックスクーター

キックスクーターに乗り始めて早2年、いろいろと分かってきたので書き出しておく。

最初に買ったキックスクーターは1万円ほどの安物で、これは悪くはなかったが、もう少しいいものがほしいので人に売り払った。

次に買ったのはMicro MobilityのCity BMW Scooterだ。これはBMWとの公式コラボ製品で、日本で正規の購入代理店がいて手軽に買える中では最も高い製品だ。

- micro-mobility.com

しばらく使った感想としては、ソリッドタイヤでは快適に走れる道がかなり限られるということだ。大通りの道の舗装はかなり荒いアスファルトになっているので快適ではない。大通りからそれた路地がおすすめだ。またどうもこの製品はフットブレーキの作りがあまりよくない。すぐに壊れてしまった。

COVID-19の影響もあって電車に乗りたくないので、エアタイヤのキックスクーターを買ってみることにした。前輪が230mm、後輪が205mmのエアタイヤになっている。

FR230P | Frenzy Scooters

しかし、これがまたかなりひどい欠陥品だった。届いた製品の後輪のタイヤが分厚すぎてフレームに干渉してしまう。販売店に相談して純正品の交換パーツを送ってもらったが、これまた同じ欠陥を抱えている。返品を考えたが、物自体はそれほど悪くはないので、アマゾンで中華製の8インチのエアタイヤを買ってみた。これがなかなか悪くなく細めにできていて70PSIも入る。これでようやく快適になった。これで荒いアスファルトも石畳も怖くない。ただ、ソリッドタイヤに比べてほんのわずかに速度で劣る気がする。ベアリングの質の問題ではないはずなので、運動エネルギーの一部が減衰性のある素材のせいで熱に変わっているせいだろうか。

結論から言うと、おそらく前輪後輪とも205mmのキックスクーターでよかったのではないかと思う。というのも230mmエアタイヤというのは珍しすぎて交換品がない。タイヤチューブはあるのだが、ベアリングホイールとタイヤの交換品がみあたらない。205mmはチューブ、ベアリングホイール、タイヤとも豊富に互換品が存在する。

2020-06-01

パブリックドメインの漫画が出てくるのは2050年代から、アニメは2030年代から

Redditでパブリックドメインな漫画は存在するのかと質問されていたので考えてみた。

Are any manga in the PUBLIC DOMAIN? : japan

2018年に改正された日本の著作権法では、個人の著作権の保護期間は死後70年を原則として、映画、無名、周知されていない著作物は公開から70年となっている。改正時にすでに著作権条保護されていない作品について保護期間が延長されることはないので、1967年に著作者の死亡した作品の著作権の保護期間は満了しているが、1968年に著作者の死亡した作品の著作権は2038年まで存続する。

それを踏まえて日本の漫画の歴史を紐解くと、1930年代には、現代風の漫画が公開されている。このときの漫画家達は1970年から1980年頃まで生きているので、著作権の保護期間が満了してパブリックドメイン漫画が出てくるのは、1950年代以降ということになる。

もちろん例外はある、1967年までに死んだ漫画家の著作物はすでにパブリックドメインになっている。ただし、それほど多くはないだろう。

アニメは法律上映画になるので、アニメの著作権は漫画より早く消失する。日本のアニメは1960年代から発表されているので、2030年代にはパブリックドメインのアニメが出てくることになる。

判例を考えると、映像表現をともなうビデオゲームは映画の著作物になる。任天堂のファミコンは1983年に販売されている。したがって2054年以降から、パブリックドメインのファミコンのゲームが出てくることになる。

2020-05-03

マッスルアップができない

クライミングジムがのきなみ営業自粛してしまってからしばらくたつ。その間に筋力だけでも落とさないようにと公園の鉄棒でトレーニングをしているのだが、クライミングとは違う身体の動きを要求される。

最初はなかなかできなかったうんていだが、最近はラクラクとこなせるようになった。これは筋力が発達したのではなく、効率的な身体の動かし方を学んだのだろう。垂直な鉄の棒を腕だけで登ることもできるようになったし、落差50cmぐらいの棒から棒に飛び移ることもできるようになった。

クライマーからすると、鉄棒はガバすぎて指に対する負荷が足りなすぎるので、ロックリングスを買ってみた。ふしぎなことに単に鉄棒で懸垂するより指3本を第一関節だけかけるロックリングスのほうが懸垂がやりやすい気がする。クライミングはするが鉄棒での懸垂はほとんどしてこなかったことが影響しているのだろう。またローリーバーも買った。クライミングジムでたまに触るのとちがって、自分で所有して本格的に30分ほど取り組むと、だいぶ手首に負担がかかることが分かった。ローリーバーはそれほど長時間するものではない。

現在の目標は鉄棒でマッスルアップができるようになることだ。マッスルアップをするための筋力はすでに十分に備わっているはずなのだが、マッスルアップができない。マッスルアップのうち、プルアップはできるが、そこから身体を持ち上げることができない。なので最近はディップスのトレーニングをしている。クライミングジムが再開したらマントル返しやプッシュに向上につながることを期待している。

ところで、電車に乗ることを避けるためにエアタイヤのキックスクーターを新しく購入した。FrenzyのFR230で、前輪が230mm、後輪が205mm。両方共エアタイヤだ。届いた当初、常にブレーキがかかったような感覚を覚えると思ったら、後輪のタイヤがフレームに干渉していた。初期不良を訴えて交換してもらったのだが、交換してから20日で今度は後輪がパンクした。どうもこの製品、製造上の欠陥がある気がしてならない。タイヤというのは荷重するとわずかにたわんで幅が広がる。Frenzyの後輪のフレーム部分の幅が狭すぎ、たわんだ際に干渉する問題があるのではないかと思っている。

とりあえず古いキックスクーターから205mmのソリッドタイヤを移植したが、一度だけ自転車屋にタイヤをパンク修理で持ち込んで見ようと思う。しかし、新品が20日でパンクした以上、あまり期待はしていないのだが。

2020-04-17

検出不可能なゲームのチートが発表、今後のオンラインゲームのデザインはこのチートを前提に設計しなければならない

PCILeechというソフトウェアスタックがある。

ufrisk/pcileech: Direct Memory Access (DMA) Attack Software

これはPICeデバイスを使ってターゲットコンピューターのメモリをDMAで読み取るためのPCIeデバイスのFPGAの実装とその操作のための一連のソフトウェア群だ。

原理は簡単だ。ターゲットコンピューターのPCIeスロットにつないだPCIeデバイスからDMAをするだけ。これによりターゲットコンピューターのメモリ領域を読み取ることができる上、ターゲットコンピューターからは検出不可能だ。なぜならばDMAはCPUを介さずに行われる上、ターゲットコンピューターにカーネルスペース/ユーザースペースともに追加のコード実行を必要としないからだ。

PCILeechを作って作られたゲームのチートに、CSL:GOのチートがある。これはマップ上のどこにプレイヤーがいるかを表示するチートだ。

pcileech-webradar/readme.md at master · EngineOwningSoftware/pcileech-webradar

原理上、このチートはターゲットコンピューターからは検出不可能だ。したがっていかなるDRMであろうとも役に立たない。難読化をして多少チートの開発を嫌がらせすることはできるかもしれないが、所詮その程度だ。もはやゲームにおいてメモリは常に読まれるものと考えなければならない。

このチートに抗うのは無意味だ。したがってこれからのオンラインゲームはローカル環境でのメモリが読まれることを前提に設計しなければならない。CS:GOのようなオンラインFPSゲームでは、全プレイヤーの位置は公開すべきだろう。すなわちこのようなチートの意味をなくすのだ。オンラインポーカーのようなゲームでは、ローカルに秘密情報を保持しない実装にしなければならない。秘密情報については中央の権威サーバーのみが処理するか、メンタルポーカーのアルゴリズムを使う。オンラインFPSも中央の権威サーバーによる実装もできるが、それはGoogle Stadiaのような入力をサーバーに送信して映像をストリーミング再生するだけのような実装になるだろう。

この仕組みを使ってメモリに書き込む場合は検出可能だろう。というのも連続していない任意箇所のメモリに対してアトミックに書き込むことはできないので、ゲーム状態を重複して複数のメモリ箇所に保持したり常時チェックサム計算などの対策で、メモリ改変を検出できるはずだ。

また、自分のプログラムが全メモリアクセスを専有している場合は、メモリ帯域を常時使い切ることにより、メモリ帯域に変化が生じればそれはDMAアクセスが行われたと考えていいだろう。問題はPCILeech以外の各種デバイスかもしれず、またIntel MEやAMD PSPのような邪悪で不自由なバイナリブロブのファームウェアによるものかもしれないので、切り分けができない。そして全メモリアクセスを専有する状態ではもはやPCゲームは実装できない。

世の中から無意味で邪悪で人道上の罪であるDRMは滅ぼさなければならない。

2020-04-16

Error handling in Erlang

Last time, I wrote about how to write a hello world HTTP server by using Erlang, Cowboy and Rebar3.

Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

Today, I'm going to write about the error handling in Erlang.

The error handling in Erlang is easy if we can ignore the error. That is, we don't expect the error. In the event of unlikely failure, we immediately abandon any computation we were doing and start over. The OTP and other famous frameworks were written by following Erlang culture of error handling so it will handle it well. If, on the ohter hand, the errors are expected to happen, so we have to explicitly deal with it. Erlang is suddenly reared its ugly head.

How a function notify it's caller the failure? In other languages, like Haskell, there is a Maybe type which may or may not contains the value. Erlang is not staticaly strong typed language so the Erlang version of the Maybe is tagged tuple. We return ok or {ok, State} upon success and we return any other value otherwise. It may be {error, Reason}, empty list [], or simply an atom like error, false, undefined whatever.

The user of such functions must match the returned value with ok tagged tuple,

do_something( State ) ->
    {ok, State_1} = f( State ),
    do_normal_things.

If the function f return anything other than {ok, any()}, match failed and throw an exception of error:{badmatch, V}. So hopefully, the higher framework catch these exceptions and restart the process.

But what if the caller want to deal with the error? We have to use the patter match for the conditional execution. It can be done by case expression or function.

case expression:

do_something( State ) ->
    case f( State ) of
        { ok, State_1 } -> do_normal_things ;
        { error, Reason } -> do_error_handling
    end.

function :

do_something( State ) ->
    do_something_1( f( State ) ) .

do_something_1( { ok, State } ) -> do_normal_things ;
do_something_1( {error, Reason} ) -> do_error_handling .

Whichever you use, it became quite verbose and boilar-plate.

Erlang has exception like many other langauges. But I feel some oddities on Erlang's exception and that is the concept of class.

The Erlang has three class of exception: error, exit, and throw. These are thrown by calling function error/1,2, exit/1, and throw/1 respectively.

If you don't care about exception, you need to do nothing. But if you care, that is, you want to run some code on the condition of exception, things get verbose.

Let's suppose that previous function f/1 return { ok, State } on success, but throw some exceptions otherwise and you want to deal with it because you expect it to happen. You can use try expression or catch expression

try expression is strightforward, if you ignore the awkward Erlang grammer that is.

try Exprs
    catch Class1:Pattern1 -> Body1 ;
    catch Class2:Pattern2 -> Body2
end

The class is either error, exit, or throw, pattern may vary. If you were to catch the exception thrown by error class's badmatch(1 = 2), it looks like this.

try 1 = 2
    catch error:{ badmatch, V } -> its_bad_man
end

Now, how to do_normal_thing and do_error_handling depending on the presense of exception? try expression can have of section and it will be evaluated only on no exception in Exprs.

try f( State ) of
    { ok, State_1 } -> do_normal_thing ;
catch
    throw:something_went_bad -> do_error_handling
end

Now how to deal with the situation where the error will be reported in either by value or exception? Use try expression's of section to pattern match the error value.

try f( State ) of
    { ok, State_1 } -> do_normal_thing ;
    { error, Reason } -> do_error_handling
catch
    throw:something_went_bad -> do_error_handling
end

There is another way to deal with the exception. The catch expression.

catch Exprs

catch expression evaluate Exprs and return its value on no exception. In case of exception, the value will be either

For exceptions of class error, that is, run-time errors, {'EXIT',{Reason,Stack}} is returned.

For exceptions of class exit, that is, the code called exit(Term), {'EXIT',Term} is returned.

For exceptions of class throw, that is the code called throw(Term), Term is returned.

Erlang -- Expressions

If it's by throw({error, Reason}), the code will be clean.

case catch Exprs of
    { ok, Value } -> do_normal_thing ;
    { error, Reason } -> do_error_handling
end

But if it's error class, the code is too ulgy to read.

case catch 1 = 2 of
    { 'EXIT', { {badmatch, _} }, _ } -> do_error_handling
end

Perhaps, error and exit class were not meant to be handled by catch expression, but some library use these even for the predictable situations. like list_to_integer, binary_to_integer. My guess is to keep the backward compatibility.

Putting it all togather, it's very verbose to handle errors in Erlang.

Let's quickly borrow a code from the hello world HTTP server I explained in the previous article. Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

Instead of returning the hello world, we're going to return the sum of two query parameter a, b.

$ curl "http://localhost:8080/?a=1&b=2"
3
$ curl "http://localhost:8080/?a=1&b=-100"
-99

All we need to do is modify the cowboy_handler. The simplest code that assume no error will be like this.

init( Req, State ) ->
    P = cowboy_req:parse_qs(Req),
    { _, A } = lists:keyfind(<<"a">>, 1, P ),
    { _, B } = lists:keyfind(<<"b">>, 1, P ),
    Sum = integer_to_binary( binary_to_integer(A) + binary_to_integer(B) ),
    Req_1 = cowboy_req:reply( 200,
        #{<<"content-type">> => <<"text/plain">>},
        Sum, Req ),
    {ok, Req_1, State ).

Well, it's not bad. But I want to deal the the error.

Suppose, the users forget the query parameters.


$ curl "http://localhost:8080/"
$ curl "http://localhost:8080/?a=1"
$ curl "http://localhost:8080/?b=1"

If this happend, our code failed the pattern match because lists:keyfind returns false.


{ _, A } = false,

In such cases, I want to reply with the helpful error messages like this.


$ curl "http://localhost:8080/"
Error: missing query parameter a, b.
$ curl "http://localhost:8080/?a=1"
Error: missing query parameter b.
$ curl "http://localhost:8080/?b=1"
Error: missing query parameter a.

We can do condional branching with either case expression or function pattern match.

Another type of error is although the query paramters are present, it has a string that cannot be parsed as an integer.


$ curl "http://localhost:8080/?a=abc&b=123"

I would like to reply with helpful error messages in this case too.

After consdering the various code, I come up with this code. It's too verbose and ugly but I think alternatives are worse.

init( Req, State ) ->
    P = cowboy_req:parse_qs(Req),
    A = lists:keyfind( <<"a">>, 1, P ),
    B = lists:keyfind( <<"b">, 1, P ),
    { Http_status_code, Answer } = process( A, B ),

    Req_1 = cowboy_req:reply( Http_status_code,
        #{&lt;&lt;"content-type"&gt;&gt; =&gt; &lt;&lt;"text/plain"&gt;&gt;},
        Answer, Req ),
    { ok, Req_1, State }.

process/2 is set of function that ultimately returns { integer(), iodata() }. Here is the verbose code.

%% for missing query parameters.
process( false, false )     -> { 400, <<"Error: missing query parameter a, b.\n">> } ;
process( false, _ )         -> { 400, <<"Error: missing query parameter a.\n">> } ;
process( _, false )         -> { 400, <<"Error: missing query parameter b.\n">> } ;
%% for invalid query parameters
process( badarg, bardarg)   -> { 400, <<"Error: invalid query parameter a, b.\n">> } ;
process( badarg, _ )        -> { 400, <<"Error: invalid query parameter a.\n">> } ;
process( _, bardarg)        -> { 400, <<"Error: invalid query parameter b.\n">> } ;
% lists:keyfind succeeded.
process( { _, A }, { _, B } ) ->
    process(
        try binary_to_integer( A ) catch error:badarg -> badarg end,
        try binary_to_integer( B ) catch error:badarg -> badarg end
    ) ;
% no invalid query parameter. return the result.
process( A, B ) ->
    { 200, { integer_to_binary( A + B ), <<"\n">> } } .

The -spec attribute for this process/2 is abomination.

-spec process(
    { bitstring(), bitstring() } | false | badarg | integer(),
    { bitstring(), bitstring() } | false | badarg | integer()
)  -> { integer(), iodata() }.

Well, at least, I understand the error handling of Erlang.

2020-04-13

Erlang, Cowboy, Rebar3によるHello World HTTPサーバーのチュートリアル

本記事では、Erlang, Cowboy, Rebar3によるHello worldを出力するHTTPサーバーの実装方法を解説する。

目的は、このプログラムを実行中に、以下のような挙動になることだ。

$ curl "htttp://localhost:8080/"
hello,world

ErlangもCowboyもRebar3も、情報が極めて少ない。しかも公式ドキュメントすら間違っている。公式ドキュメントすら間違っているのには理由があり、実際の実装とドキュメントに差がでているのだ。Erlangは変化の少ない言語ではあるが、それでもOTP17からmapが追加されたりと言語的に少し変わっているし、mapの追加により、cowboyも以前ならproplistsを使っていた部分でmapを使うようになり、しかも2.0でAPIかなり破壊的な変更が入り、2.5からはモジュールの構成も少し変わってしまった。Rebar3は本当にひどい。名前が示すように、すでに破壊的な変更を2回経ている。そして技術的負債の塊だ。

この記事で解説する程度の知識を得るのに私は公式ドキュメントと何ヶ月も格闘するはめになった。公式ドキュメントですらこうなのだから、非公式なドキュメントは本当に参考にならない。ここに書いてあることは2020年の時点では正しいが、来年はわからない。

準備

Erlang実装とRebar3が必要だ。CowboyについてはRebar3がダウンロードしてくれるので考えなくてよい。

Debian系のディストロでErlangをインストールする。

$ apt install erlang

GNU/Linuxでrebar3をインストールする最も信頼できる方法は、自前でビルドすることだろう。

$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap

これで"rebar3"というファイルができるので、このファイルをPATHの通ったディレクトリにコピーするかシンボリックリンクをはればよい。

ln -s rebar3 /usr/local/bin

これで準備が完了した。

プロジェクト作成

まずrebar3を使ってプロジェクトを作成する。名前を"hello_server"としよう。

$ rebar3 new release hello_server
$ cd hello_server

このコマンドで"hello_server"というディレクトリが作成される。その中にはテンプレート生成されたファイルがいくつかある。重要なものだけ説明する。

"hello_server/rebar.config"は設定ファイルで、cowboyの依存を追加するために編集する。

"hello_server/apps"ディレクトリにはアプリケーションが配置される。rebar3のreleaseプロジェクトはumbrella projectと呼ばれていて、複数のアプリケーションを持つことができる。

"hello_server/apps/hello_server"はrebar3がテンプレートから生成したアプリケーションだ。このディレクトリ内には"src"ディレクトリがあり、3つのファイルが作成されている。"hello_server_app.erl", "hello_server_sup.erl", "hello_server.app.src"だ。

"hello_server_app.erl"はapplication behaviourを実装するソースファイルだ。

"hello_server_sup.erl"はsupervisor behaviourを実装する。今回は編集しない。

"hello_server.app.src"はapplication resource fileを生成するためのソースファイルだ。Erlang VMをどのように実行するかということを設定するためのファイルだ。rebar3はこのファイルから実際のapplication resource fileを生成する。このファイルも編集する。

Cowboyを依存に追加

Cowboyを依存に追加してrebar3にダウンロードしてもらう。そのために"hello_server/rebar.config"を編集する。

$ vim rebar.config

最初の数行は以下のようになっている。

[erl_opts, [debug_info]}.
{deps, []}.

[relx, [{release, {hello_server, "0.1.0"},
...

今回編集するのは2行目、つまり"{deps,[]}."という部分だ。このlistのなかに依存を記述していく。記述のフォーマットは様々だが、すべて"{ package_name, ...}"という形のtupleになっている。このチュートリアルではパッケージをhex.pmからダウンロードしてくるので、フォーマットは"{ package_name, "version number"}"になる。本チュートリアルを執筆時点で、最新の安定版のcowboyのバージョンは2.7.0だ。


{deps, [
    {cowboy, "2.7.0"}
]}.

rebar3は依存ライブラリが必要になった時に自動的にダウンロードするが、今回は正しく記述できていることを確認するために明示的にダウンロードしてみよう。

$ rebar3 upgrade

次に、アプリケーションリソースファイルを編集して、cowboyを先にスタートさせるようにする。今実装しているアプリケーションはcowboyを使っているので、cowboyを先にスタートさせておかなければならない。その設定方法として、"hello_server.app.src"を編集する。

$ vim apps/hello_server/src/hello_server.app.src

このファイルの中身を抜粋すると以下のようになっている。


{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib
    ]},
  ...
  ]}.

applicationsのtagged tupleの中のlistに"cowboy"を追加する。

{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib,    % カンマを忘れないこと
     cowboy     % この行を追加
    ]},
  ...
  ]}.

これはErlangのlistなのでカンマを忘れないようにすること。

HTTPサーバーの始動

容易が全て整ったので、HTTPサーバーを開始する。まず"apps/hello_server/src/hello_server_app.erl"を編集する。

vim apps/hello_server/src/hello_server_app.erl

このソースコードはrebar3によって生成されたapplication behaviourを実装するためのモジュールだ。start/2を変更して、HTTPサーバーを開始する。

start(_StartType, _StartArgs) ->
    hello_server_sup:start_link().

HTTPサーバーを開始してコネクションをlistenするには、まずcowboy用語でルートと呼ばれているものを設定する。これは特定のリモートホストやパスをcowboy_handlerに関連付けるための設定だ。ルートを設定するにはcowboy_router:compile/1を使う。この関数は引数としてcowoy_router:routes()型を取る。型は"[{Host, Pathlist}]"となっている。PathList型を展開すると、"[{Host, [{Path, Handler, InitialState}]}"となる。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { Host, [{Path, Handler, InitialState}]}
    ]),
    hello_server_sup:start_link().

ホストとして'_'を指定すると、任意のホストからのコネクションを受けつける。ホストを制限したい場合、例えばlocalhostからの接続しか受け付けたくない場合は、<<"localhost">>を指定する。

今回の場合、Pathは<<"/">>だ。今回は"http://localhost/aa/bb/cc"のようなPathは受け付けないのでこれでいい。

Handlerにはhello_handlerというatomを指定する。これは後でcowboy_handler behaviourを実装するモジュールとして実装する。

特に状態は持たないので、InitialStateは空のlistを使う。

すべてまとめると、以下のようなコードになる。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, [] }]
    ]),
    hello_server_sup:start_link().

ルートが準備できたので、HTTPリスナーを開始する。ここでは素のHTTPを使うので、cowboy:start_cear/3を使う。引数はstart_claer( Name, TransportOpts, ProtocolOpts )だ。

NameはこのHTTPリスナーを識別するための名前で、ErlangのTermであればなんでもよい。通常はatomが使われる。ここでは"hello_listener"を使う。

TransportOptsには様々なオプションがあるが、このチュートリアルではlistenするポートを指定するだけだ。今回はHTTPサーバーのポートはは通常80だが、今回は8080を使うので、"{{port, 8080}}"となる。

ProtocolOptsでは先程設定したrouteを指定する。ProtocolOptsの型はmapで、envというキーがあり、値はdispatch型だ。ここに先程束縛したDispatch変数を指定する。

成功した場合、start_clear/2は{ok, pid}を返す。okのtagged tupleに束縛することで失敗時のことはapplication behaviourにまかせよう。

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, []}] }
    ]),
    {ok, _} = cowboy:start_clear(
        ello_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch}}
    ),
    hello_server_sup:start_link().

接続の処理

HTTP listenerの用意が出来たので、やってきた接続要求を処理していく。そのためにはさきほどのhello_handlerを実装しなければならない。これはcowboy_handler behaviourとして実装する。まず新しいソースファイルを作成する。

$ vim apps/hello_server/src/hello_handler.erl

まず基本的なところを埋めていこう。

-module(hello_handler).
-behaviour(cowboy_handler).
-export([init/2]).

init( Req, State ) ->
    {ok, Req, State}.

Reqはリクエストとレスポンスを保持している。Stateは好きに使える状態だが今回は使わないので空のlistとする。

やるべきことは、HTTPステータスコードとして200を返し、ヘッダーのcontent-typeとしてはtext/plainを指定し、コンテンツは"hello,world"とするだけだ。これにはcowboy_req:reply/4を使う。引数の型は"reply(Status, Headers, Body, Req)"だ。

StatusはHTTPステータスコードで型はnon_reg_integer()もしくはbinary()だ。今回は200を指定する。

HeaderはHTTP headerをmap()で指定する。今回は"content-type"を"text/plain"にする。

Bodyには<<"hello,world">>を指定する。

Reqは現在のReqオブジェクトだ。

replyは新しいReqオブジェクトを返す。これ以降Reqオブジェクトを使う際には、この新しいReqオブジェクトを使わなければならない。

init/2のコードは以下のようになる。

init( Req, State ) ->
    Req_1 = cowboy_req:reply(
        200,
        #{<<"content-type">> => <<"text/plain">>},
        <<"hello,world">>,
        Req
    ),
    {ok, Req, State}.

プログラムの実行

$ rebar shell

確認しよう。

$ curl "http://localhost:8080/"
hello,world

次はErlangのエラー処理について書こうと思う。Erlangのエラー処理はその場で処理を中断して無視していい場合は簡単だが、エラーに明示的な対処が必要だととたんに面倒になる。

2020-04-07

Walkthrough of hello world HTTP server with Erlang, Cowboy, and Rebar3

This is the quick walkthrough of implementing and executing a HTTP server that just return hello world by using Erlang, Cowboy and rebar3.

The goal is, while executing this problem, the following happens.

$ curl "htttp://localhost:8080/"
hello,world

Erlang and Cowboy is easier compared to the god-forsaken rebar3. Rebar3, as its name indicates, had major backward incompatible breaking changes twice, and it still has many technical debt piled up on it. Even the official documentation is unhelpful at this time. I wasated months just figuring out the basics and I write it down here so you don't have to.

Prerequisites

You need Erlang implementation, rebar3. The cowboy can be fetched by rebar3.

To install erlang on debian-based distro:

$ apt install erlang

To install rebar3 in most GNU/Linux distros, you should built it yourself.

$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap

This create a file "rebar3". You can copy this file to somewhere in the PATH or symlink it.

ln -s rebar3 /usr/local/bin

Now you're ready to start using the rebar3.

Creating a new project.

First, you must create a new rebar3 project. Let's call it "hello_server".

$ rebar3 new release hello_server
$ cd hello_server

This command create a directory "hello_server" and bunch of template files in that directory. I don't explain everything in details, but just for the important bits.

"hello_server/rebar.config" is a config file we have to modify to add cowboy as an dependency.

"hello_server/apps" directory contains apps. rebar3's release project is called "umbrella project", it can contains multiple "apps".

"hello_server/apps/hello_server" is the default apps the rebar3 generated from the template. Inside that directory, there is a "src" directory which contains three template files. "hello_server_app.erl", "hello_server_sup.erl" and "hello_server.app.src".

"hello_server_app.erl" is a source file we modify.

"hello_server_sup.erl" is for implementing supervisor behaviour. We don't modify this file in this walkthrough.

"hello_server.app.src" is a source file for application resource file. It tell the Erlang VM how to start the application. Rebar3 just copy it to the appropriate place so you don't have to. We modify this file too.

Adding cowboy as an dependency

Next, we need to add cowboy as an dependency so the rebar3 can fetch it. To do so, open the "hello_server/rebar.config".

$ vim rebar.config

The first few lines are like these.

[erl_opts, [debug_info]}.
{deps, []}.

[relx, [{release, {hello_server, "0.1.0"},
...

We need to modify the second line, that is "{deps, []}.". You can add dependencies in the list. There are many formats for that but every thing is tuple of "{ package_name, ... }". In this walkthrough, we fetch the package from hex.pm. So the format shall be "{ package_name, "version number"}". As of this writing, the latest stable version of cowboy is 2.7.0.


{deps, [
    {cowboy, "2.7.0"}
]}.

rebar3 fetch the necessary dependency automatically when it is needed, but let's just fetch it explicitly to make sure we wrote it correctly.

$ rebar3 upgrade

Also, we need to modify the application resource file to start cowboy before our application. Since our application requires cowboy, the cowboy application must be started before our application. To do so, modify the "hello_server.app.src"

$ vim apps/hello_server/src/hello_server.app.src

The part of the content of this file should looks like this.


{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib
    ]},
  ...
  ]}.

We add "cowboy" to the list.

{application, hello_server,
  [...
  {applications
    [kernel,
     stdlib,    % don't forget comma
     cowboy     % add this line
    ]},
  ...
  ]}.

As you see, this is Erlang's list so don't forget the comma before cowboy.

Fire up the HTTP server

Now we're going to start the HTTP server. First, we modify the "apps/hello_server/src/hello_server_app.erl".

vim apps/hello_server/src/hello_server_app.erl

This source code is generated by rebar3 to implement the application behaviour. We are going to modify the start/2 to fire up the HTTP server.

start(_StartType, _StartArgs) ->
    hello_server_sup:start_link().

In order to start the HTTP server listening the incoming connection, we first need to set what cowboy call it "route". It's a mapping of the connection from some remote hosts, path to cowboy_handler. To do that, we use cowboy_router:compile/1 which take a parameter of type cowboy_router:routes(). The type is "[{Host, PathList}]", if you expand the PathList type, it'll be "[Host [{Path, Handler, InitialState}]]".

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { Host, [{Path, Handler, InitialState}]
    ]),
    hello_server_sup:start_link().

The Host can be '_' which means we allow the connections from any hosts. If you are to allow connection from anywhere, use '_', if on the other hand, you want to restrict the access only from, say, localhost, it would be <<"localhost">>.

The Path in our case is <<"/">>. Since we don't support path like "http://localhost/aa/bb/cc".

For Handler, we specify "hello_hander" atom which we have to implement it as a cowboy_handler behaviour later.

We don't use state so the IinitialState be emply list.

Putting all togather so far, the code looks like this.

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, [] }]
    ]),
    hello_server_sup:start_link().

Now we prepared the route, we're going to fire up the HTTP listener. We are going to use good old plaintext HTTP by cowboy:start_clear/3. The three parameters are "start_clear(Name, TransportOpts, ProtocolOpts)".

Name can be any Erlang term to refer this listener, but atom used used most of the time. Let's use "hello_listener".

TransportOpts has many options, but for this walkthrough, we only need to set the port to listen to. We going to listen port 8080 so it would be "[{port, 8080}]".

In ProtocolOpts, we use the route we made earler. The type of ProtocolOpts is a map which as a key env whose value is also a map which has a key dispatch. We pass Dispatch for the value of this key.

If succeeded, start_claer/2 return "{ok, pid}". Let's make sure it returns ok and fail otherwise.

start(_StartType, _StartArgs) ->
    Dispatch = cowboy_router:compile([
        { <<"localhost">>, [{<<"/">>, hello_handler, []}] }
    ]),
    {ok, _} = cowboy:start_clear(
        ello_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch}}
    ),
    hello_server_sup:start_link().

Handling the incoming connections.

Now the HTTP listners are up and running, we need to implement the hander for the incoming connections. For that, we need to implement the hello_handler we specified earlier by following the cowboy_hander behaviour. Create a new source file .

$ vim apps/hello_server/src/hello_handler.erl

Let's write the basics.

-module(hello_handler).
-behaviour(cowboy_handler).
-export([init/2]).

init( Req, State ) ->
    {ok, Req, State}.

Req represents requests and response. We don't use State really. It's just an empty list.

All we need to do is return a HTTP status code 200, the content-type is text/plain, it's content is "hello,world". We can do that by cowboy_req:reply/4. The parameters are "reply(Status, Headers, Body, Req)".

Status is a HTTP status code in non_neg_integer() or binary(). In this case, it's 200.

Header is a map() to specify HTTP header. we set it's "content-type" to be "text/plain".

For the Body, we return "hello,world".

Req is a current Req object.

reply return a new Req object which we must use it instead of old Req objects after the call.

And now, the init/2 code.

init( Req, State ) ->
    Req_1 = cowboy_req:reply(
        200,
        #{<<"content-type">> => <<"text/plain">>},
        <<"hello,world">>,
        Req
    ),
    {ok, Req, State}.

To run the program

$ rebar shell

Now to confirm it.

$ curl "http://localhost:8080/"
hello,world

If I have in the mood, I'll write the error handling next. The reality is more verbose than textbook.

2020-04-04

2019-2020シーズンに行ったスキー場の感想

2019-2020シーズンは腕も上達したし雪が少なかったこともあって普段は行かない様々なスキー場に行った。ここにその感想を簡潔にまとめておこうと思う。

まずは白馬にあるスキー場からだ。2月上旬というハイシーズンに行ったはずなのに、あいにくとほとんどの日は雪質がわるかった。

栂池高原スキー場は白馬にあるスキー場だ。白馬駅からバスで行ける。特徴はゴンドラでふもとから山頂まで一気に上がって長距離を滑ることができる点だ。とはいってもあいにくの暖冬でふもとは雪質が悪かったので、ゴンドラの中間駅まで滑ってゴンドラを往復していた。

白馬コルチナスキー場は白馬にあるスキー場だ。朝早くの行きは白馬駅から電車とバスで、帰りはバスになる。白馬はパウダーキチガイのオーストラリア人で占拠されているので、開き直ってコース外のほとんどを自己責任で滑走可能なエリアとして解放してしまったスキー場だ。コースのどこからコース外に出てもふもとの同じ場所に帰ってくることができるので、コース外を滑るには適しているスキー場と言えるだろう。白馬コルチナスキー上の横には白馬乗鞍温泉スキー場があり、共通リフト券が買えるのだが白馬コルチナスキー場からは接続が悪かったので買う価値はわからなかった。

白馬五竜とHAKUBA 47は2つのスキー場が併設されているがリフト券も共通なので実質一つのスキー場だ。白馬五竜のほうはなだらかで広いゲレンデがあり雪質の悪さと相まって面白さがわからなかったが、HAKUBA 47はなかなか面白かった。

次に赤倉温泉のスキー場だ。周辺にはもっとスキー場があるのだが、今回は2つしかいかなかった。この暖冬の3月上旬にもかかわらず雪が豊富にあった。もっとも、例年はもっと雪が多いらしいのだが。

赤倉温泉スキー場は赤倉温泉の宿が密集する場所の近くにある。スキー場としては初心者向けでほとんどなだらかなコースしかない。一箇所だけ急なコースがあるのだが、そこに上がるリフトが今にも壊れそうでとても怖い。あまりにも簡単すぎるスキー場だったので、初日の足慣らしや最終日の疲れた足でのんびり滑る分にはいいが、連日でいく価値は見いだせなかった。

赤倉観光リゾートスキー場は赤倉温泉スキー場のとなりにあり、相互に連絡できるが、リフト券は別だ。こちらはとても面白いスキー場で難しいコースもあり、連日行く価値があった。ゴンドラで上がって4km滑ることができるのもよい。

これで今シーズンは滑り納めにしようと思っていたのだが、3月24日に越後湯沢にそれなりの雪が降ったので、25日に急遽日帰りで向かった。今年のかぐらは周りのスキー場が雪不足に悩む中、標高が高くて雪があるということで大勢の客がいる上、ゲレンデまでロープウェイで上がらなければならない。しかも2019年の大型台風19号の影響で下山コースが破壊されており、帰りもロープウェイに乗らなければならない。待ち時間が数時間にもなるおそれがあり、行きたくない。ちょうどコロナウイルスが騒がれていた頃でもあったので、人が密集するロープウェイも避けたい。

そこで、神立スノーリゾートに行った。このスキー場、去年までは神立高原スキー場という名前だったはずなのだが、なぜか名前を変えている。別にリゾートと言うほどの規模のスキー場ではない気がするし、周辺にホテルが密集しているわけでもない。

スキー場自体の作りは小さいながらもよい。リフトに一本乗って2km弱ぐらいのなだらかなコースを滑ることができるし、非圧雪もあるし、きれいに形成されたコブ斜面もあり、万人の需要を満たす作りになっている。

2020-03-29

村上原野(ボレロ村上)の思い出

村上原野(ボレロ村上)の思い出を色褪せないうちに書いておこうと思う。

村上原野の父親であり師匠であった猪風来は縄文土器による芸術家である。縄文土器の制作方法を復元した人物だ。

猪風来プロフィール | 美術館の紹介 | 猪風来美術館

縄文土器は窯を使わずに野焼きで焼き上げる。野焼きで窯ほど燃焼温度が上がらないので、低温でも焼き上がるような粘土を使わなければならない。その製法は再発見され、村上原野が縄文土器作成を学ぶ頃には、一通り完成していた。製法を復元した上で、その製法を使って芸術品を作るというのだ。

聞いた話では、猪風来は極めて形から入る芸術肌の人間で、縄文人の心を理解するために、北海道に竪穴式住居をこしらえて家族で住んでいた。つまり、村上原野の父親と母親と本人は中学生か高校生ぐらいまで北海道の竪穴式住居に住んでいたのだ。

竪穴式住居とは歴史の教科書にも出てくる様式の原始的な家だ。地面を掘り下げ、その上に屋根を設営する家だ。竪穴式住居は全国にあるのだが、北海道のような寒い地方では、寒さ対策のために地面をかなり深く掘り下げる。猪風来がかつて展示会で語っていた話では、竪穴式住居の中で座ると、ちょうど目の高さが地面すれすれになるほどだという。そうして猪風来は縄文人の心を会得した。

その後、村上原野の一家は岡山の廃校に引っ越す。廃校を作品制作の作業場と作品の保管所と美術館として利用している。

村上原野はそのような特殊な家庭環境にもかかわらず、当初は高専を卒業し、確か本人の話では製図技師か何かで数年、民間で働いていたそうだ。ただし本人曰く「やはり土をいじっている方が楽しい」ということで仕事をやめ、家業をつぐことにしたのだという。

村上原野のいでたちは、かなりガッシリとした体格で、よく日焼けしていて、母親の作った作務衣を着ている。どこから見ても偉丈夫であり、刺しても死なないほどの健康な見た目であった。

このブログの読者が知る村上原野は、ボレロ村上、もしくは中3女子という名前で知っている人物で、C++プログラマーだ。

https://github.com/bolero-MURAKAMI/Sprout

Sproutは村上原野によるC++ライブラリであり、C++におけるコンパイル時計算用のフレームワークを提供している。

このSproutを使った村上原野の作品としては、コンパイル時レイトレーシングがある。

constexpr レイトレーシング - ボレロ村上 - ENiyGmaA Code

当時の純粋なテンプレートメタプログラミングのみのレイトレーシングや、あるいはC++11時代のまだ本体はreturn文ひとつしか書けなかった頃のconstexpr関数を使ったレイトレーシングがある。

あるいは、コンパイル時音声生成がある。

constexpr で音階生成&シンセサイザー&音声合成 - ボレロ村上 - ENiyGmaA Code

生前の村上原野に、C++によるこの作品は芸術なのかと聞いてみたことがあるが、彼にとってこれらは芸術ではないらしい。

村上原野 aka ボレロ村上, 中3女子 逝去

ボレロ村上、中3女子ことC++プログラマーで陶芸家の村上原野の訃報が流れている。それによるとどうやら、2月16日未明に、陶芸作品を製作中に倒れ、翌朝に発見されたようだ。

2月15日の21時51分のtweetに体調の変化を示唆する書き込みがある。倒れたのが16日の未明とあるので、そこから6時間後ということになる。

この書き込みから急な脳梗塞ではないかと思われる。体調の変化を感じたら病院に行くべきなのだろう。

大一報はおそらく猪風来美術館のFacebookで、これは20日に公開されたとのことだが、我々プログラマーの界隈に知られるまでに9日間を要したようだ。

岡山にある猪風来美術館は村上原野とその両親が経営している廃校を利用した美術館と製作所のはずで、すぐにでも岡山に行きたい気持ちがあるのだが、あいにくと世間にはコロナウイルスが流行している。行けば至近距離で会話をしたくなるだろうから、東京に住んでいる身としては軽々と訪れることができない。早くコロナウイルスが収束してほしい。

ゲンヤよ!

2020年2月16日未明、おまえは32歳という若さでこの世を去った。最後の作品を制作中、倒れる直前粘土をひと掻きした跡そのままに、手に竹べらをもったまま息絶えた。きらめく魂、やさしい魂、躍動する魂よ、おまえのすべての命が燃え尽きたのだ。 力いっぱい、こんなに精一杯生きて、表現して、苦悩し、愛して、未来へ、新しい地平へ翔けていくはずだったおまえは、今力を尽くして、生命を生き切って、美しい魂の宿る作品を私たちに託して旅立っていった。

おまえの大きな縄文の渦はここから湧きあがり、おまえはその渦に乗りここから翔けあがり、おまえの愛した山や海や大地をめぐり、生まれ育ったアイヌモシリや遥かなアメリカの大地をめぐる。おまえの渦はしなやかに美しく螺旋を描き、無数の夢を乗せて伸びやかに繋がっていく。おまえが見た精霊たちは、今おまえの後を追って螺旋の渦をなし、ひきもきらさず列をなしている。

そして渦に乗ったおまえは何度もなんどもこの地に戻ってくるだろう。まわりの森の木々を震わし、みんなで協力して建てた竪穴住居の茅屋根を撫で、野焼きの野炉の灰を散らし、おまえやほかの人の作った縄文作品を愛で、いつも、どこでも残った私たちにおまえの記憶を喚起させるだろう。おまえの成し遂げた仕事、思索、大きな夢、愛する人たち、すべてがここにあったのだから。

おまえはここで新しいおまえの地平を切り開き生きていくはずだった。縄文のスピリットに惹かれ、現代に生きる己の感性で縄文の新時代の美を求めてひたすらに挑戦を続け、その手でやり遂げていく意欲に溢れていた。私たちは底のない悲しみの中、その夢を引き継ぎ繋いでいかなければと、今祈るような気持ちで歩み始めようと思う。

生前、村上原野を支え、愛し、共に力を携えて活動してくださった方々に感謝の思いでいっぱいです。これから私たちは心を寄せる人たちと共に彼の魂の宿る最後の作品を無事焼き上げます。そして彼の残した作品を新しい縄文芸術として世に提示していきたいと思っています。彼の縄文の渦はまだ終わっていないのですから。どうぞこれからもよろしくお願いいたします。

(猪風来・むらかみよしこ)

猪風来美術館 - ゲンヤよ!... | Facebook

2020-03-08

赤倉温泉スキー場に来ている

2月に白馬に2週間滞在してスノーボードと温泉三昧だった。白馬に2週間も滞在することになったのには長い話があるのだがまたの機会に書くとして、結果として、長期滞在して温泉に浸かりスノーボードをしてリモートワークをする価値に目覚めてしまった。3月も同じことをしたいと思ったので、人を誘って再び一週間の長期滞在をしてきた。

滞在先は赤倉温泉だ。詳しくは知らないが、この暖冬にもかかわらず全国のスキー場の積雪ランキング上位にあるスキー場だ。予約時に300cmの積雪があったので、これならば雪はあるだろうと宿を予約した。赤倉ホテルという宿だ。さぞ予約は取りづらいだろうと思っていたが、あっさりと予約を取ることができた。

宿はなかなかよかった。食事は悪くなく、宿の建物内に温泉が3箇所あり、しかも2箇所は24時間入り放題。そしてもう一つ露天風呂があり、これがやや特殊な完全な外に設置されている露天風呂で、涼しくて湯温も高く最高だった。この露天風呂、変わったことに混浴でかつ周りから丸見えなのだが、そもそもホテルにはほとんど客がいないので気兼ねする必要はなかった。ただし、例年では雪が高くつもり、完全に周囲から隠れてしまうそうで、本来は女性客も入りやすいそうだ。

肝心のスキー場だが、宿の目の前に赤倉温泉スキー場がある。当初、このスキー場にのみ行くだろうと思って、あらかじめリフト券を4日分手配しておいた。しかし、これは間違いだった。赤倉温泉の近くには赤倉温泉スキー場、赤倉観光リゾートスキー場、杉ノ原スキー場、池ノ平スキー場、関温泉スキー場がある。特に赤倉温泉と赤倉観光は隣り合ってつながったスキー場で、赤倉温泉スキー場は広くて簡単でつまらないコースばかりだが、赤倉観光リゾートスキー場の方は難しくて面白いコースが多かった。

まず移動日は滑らず、初日は赤倉温泉スキー場で足慣らし、白馬で2週間、1日滑って2日休むという筋肉を鍛えるのに理想的な頻度で滑っていたので、体には余裕があった。2日目に赤倉観光リゾートスキー場に行ったが、これまた前日の疲れがまったく気にならないほどの余裕があった。3日目は流石に連続しては辛いだろうと赤倉温泉スキー場でのんびりと滑ったが、これまた余裕があった。4日目は再びリゾートに行った。5日目は念の為に休みを入れた。膝は多少痛むが、危険な痛みではない。

これを書いている時点では土曜日だが、明日の日曜日に1日滑り、月曜日は余力があれば午前中に滑って帰ってこようと思っている。こんなにも膝と脚に余裕ができているほど体が鍛えられているとは自分でも驚いている。しかも、スノーボードの腕も上達している。白馬でスイッチができるようになったが、さらに滑走が安定した。

白馬での目的はスイッチだったが、今回の目的はGoProを持っている友人と一緒に言ったので、追い撮りと自撮りの上達を目標にした。そのために自撮り棒を購入した。結果は大成功だった。もっと難しいものだと思っていたのだが、自撮り棒を持っての滑走はほとんど滑走に影響を与えない。簡単であることがわかったので、GoProの来年のモデルが販売されたら購入を検討しようと思う。

今回使ったGoProはHERO 7だが、使う上での注意点がいくつかあった。まずGoProはバッテリーが持たない。リフト営業開始から終了までの丸一日の全滑走を撮影したいというのであれば、4K解像度や120FPS撮影は諦めた上で、予備のバッテリーを2つ以上持っていくのがよいだろう。逆に、事前に危惧していたSDカードの容量は全く問題がないことがわかった。今は512GBや1TBのSSDカードが数万円で売られている。動画のビットレートが90Mbpsであったとして、512GBあれば12時間は撮影できる計算になる。そしてGoProのバッテリーは1時間持たない。

GoProを撮影した後の注意点もある。GoProはSDカードのフォーマットにexFATを使っている。exFATのfuseではないマウントにはLinux kernel 5.4が必要だ。Ubuntu 19.10は5.3、Ubuntu 20.04が5.4になる予定となっている。

GoProが使う動画フォーマットはh.265(HEVC)の10bitプロファイルを使用している。この動画のリアルタイムデコードはとても重い。筆者はここ10年ぐらいCPUのパフォーマンスは十分すぎるぐらい向上したので、いまだにSkyLake世代のIntel CPUを積んだラップトップを今回の旅行に持参した。ところが、H.265 10bitのデコードのハードウェア支援はSkyLakeの次の世代のKirbyLakeが必要だ。KirbyLakeもそうだが、AMDやNvidiaのGPUのハードウェアデコード支援も、h.265 10bitに対応したのは2016年に販売された製品からだ。今回の撮影は2.7k 60fpsで行ったが、筆者のPCではリアルタイムデコードできなかった。前のフレームからの差分で表現するIフレームや、前後のフレームからの差分で表現するBフレームを多用するh.265の再生は、リアルタイムデコードが出来ない場合破綻する。そのために当初は単に映像を確認するためだけにffmpegでh.264にエンコードしていたが、いろいろと試した結果、ブラウザーを実行しない状態でmpvを使うとややフレームレートに違和感はあるものの、再生できることがわかった。

2.7k 60fpsでこの負荷なので、4K 60fpsはもっと負荷が高いのだろう。GoProで撮影した動画を編集するには最新の高スペックなコンピューターを容易すべきだ。最も筆者はffmpegのフィルターでできる以上の編集をするつもりはないのであまり気にしていない。今のところ考えている編集は動画の切り出しと連結、あとは別音声のmuxぐらいだ。今回撮影した自撮りと追い撮りはすぐにでも動画サイトにアップロードしたいのだが、現在滞在している宿のWiFiの帯域は20Mbps程度で2割程度のパケットロスが発生するという基本的人権がないほど貧弱な環境なので、自宅に帰ってからアップロードする予定だ。

追い撮りと自撮りについてだが、まず自撮りについては特に難しいことはなかった。単に自撮り棒をもって滑るだけだ。スノーボードは両手が自由なので様々な持ち方ができる。360度カメラではない自撮り棒に固定したカメラの場合、後ろ手で持って山側から谷側への撮影、前の手で持って谷側から自分を含む山側を撮影、前の手で持って谷側を撮影という方法が考えられる。全て試してみたが、どれも特性の違う動画ができあがる。

追い撮りは難しい。単に追いかけて被写体をフレーム内に納めるだけならそれほど難しくはないのだが、問題は距離だ。GoProは画角が広い。これは被写体をフレーム内に維持するという点ではいいのだが、実際の距離以上に被写体との距離感が出てしまう。被写体を大きく移すには近づく必要があるのだが、これも難しい。被写体は自分ではないので滑走の速度があわない。直滑走すると追い越してしまうし、丁度いい速度を保つのが難しい。撮影中、離されたので直滑走して追いつき、そして抜きそうになったので減速してまた離されることがたびたびあった。これは自分のショートターンの腕前を上げるほか、被写体と無線で連絡を取り、離されすぎた場合減速してもらうなどの連携が必要だろう。

もう一つ難しいのが、実際に見たとおりに撮影できないということだ。雪面は日光の反射で白飛びしてしまい、起伏が目立たなくなってしまう。かなり深いコブ斜面でもまるで圧雪されているかのようになだらかに見えてしまう。そして、傾斜も実際より浅く見える。これはカメラ自体が傾斜にそっているために仕方がないことではある。カメラを水平にすると撮影できるのはほとんど空だけだ。速度感も乏しい。カメラを高い位置で保持すると全く速度感がない。それなりの傾斜のある斜面を直滑走しても、雪面が白飛びすることと画角の広さのせいで、全然速度が出ているように見えない。速度感を出したければカメラを低い位置に置かなければならない。

また、今回は追われ撮りもためしてみた。これはカメラを後方に向けて滑り、被写体に追いかけてもらうことで、被写体を全面から撮影しようという試みだ。これはある程度はうまくいったが、なかなか難しい。減速やターンをするたびにカメラを左右に降ってしまうので、被写体はフレームに入るためにかなり努力して滑らなけれならない。直滑走すると被写体と撮影者の道具と技量と体重差によって速度差が出てしまうので破綻する。今回、私はスノーボードで友人はスキーだったが、私は毎回ホットワックスをしているが友人はスプレーワックスで済ませるズボラな人間であるのと、私が友人より20kg重いために、直滑走すると友人よりかなり相対速度が開いてしまう。それに、被写体一人だけで同じ姿勢を維持して直滑走し続ける動画はそれほど映像映えしないという問題もある。複数人でのレースのような面白さを追加する要素が必要だ。

手ブレ補正も一長一短がある。GoProの手ブレ補正はなかなかに優秀ではあるのだが、手ブレ補正をかけると滑走のダイナミックな動きが消えてしまう短所もある。

友人はスキーヤーなので、スキーでの自撮りや追い撮りを模索していたが、自撮りについては圧倒的にスノーボードのほうが楽だ。追い撮りもスキーでは細かい調整が聞かずに難しい。ヘッドマウントではカメラ位置が固定されてしまい、自撮り棒を動かすというダイナミックな撮影ができない。スキーで自撮り棒をもつと滑走が難しくなる。スノーボードでは手を固定して滑ることもできるが、スキーは手を動かしてバランスを取りたい特性があるようだ。

今回、自分の滑りを追い撮りしてもらう機会にも恵まれたが、やはり滑走中にバランスを取るために上半身をリーンする癖が抜けない。下半身の屈伸だけで十分にバランスをとれるところでは積極的に下半身を意識して使っていきたいところだ。

2020-02-16

C++20標準規格がほぼ固まった

2020年2月10日から15日までプラハで行われた会議により、C++20のDIS(Draft Intarnational Standard)が可決された。これはC++20となる標準規格と同じ文面であり、もうこれ以上変更はない。今後、このドラフト案に対して各NBによって可否の投票が行われる。何事もなければこのまま可決されてC++20が制定されるだろう。

今回残念なのはstd::formatだ。これはpythonにあるようなテキスト整形ライブラリだ。ただしロケールに依存している。std::formatのロケールを引数に取らないコンストラクターはグローバルなlocaleオブジェクトに依存する。今の所ロケールの影響を受けるのはtype specifier nで、数値を桁区切りにして出力する機能だ。

std::formatがlocale汚染されたことにより、std::formatは危なくて使えないライブラリになったし、ローカライゼーションの妨げになるので使ってはならないライブラリとなった。

10年前、char8_tの必要性を標準化委員会に説いたときはchar型は生のバイト列を表現するのに最適な型だなどととんでもない話を持ち出されて一笑に付されたが、その後にchar8_tの必要性は認識され、かつcharが生のバイト列を表現するのに不適切な型であることが認識され、std::byteが入った。

コルーチンも問題が多い。C++20に入ったコルーチンとはその名前で連想するようなユーザーモード実装の軽量スレッドではない。C++20のコルーチンとは3種類のキーワード、co_await/co_yeild/co_returnを使った関数をコルーチン関数と認識し、その関数に対してあらかじめ定められた変形を行い、最終的にユーザー定義のクラスの特定のシグネチャーのメンバー関数を呼び出す単なるシンタックスシュガーだ。変形ルールを考慮した上で自力でライブラリを実装すれば、例えばユーザーモード実装の軽量スレッドやジェネレーターやメソッドチェインやステートマシンや非同期I/Oといった機能を実現できる。ただし、コルーチンをサポートした標準ライブラリは存在しないので自力で実装する必要がある。そして自力で実装するのは極めてだるい。

コルーチンのためだけにコア言語にここまでユーザー定義クラスの特定のシグネチャが存在することを前提とした文法を入れるのは汚い。コルーチンのような機能は、静的リフレクションで実現すべきだ。

今現在、環境の変化でC++に時間を割くことができていないし、C++20本は出せるかどうかわからない。

2020-01-18

Erlangについて思うところ

職場の今までいた部署が潰れてしまったので、新しい部署で仕事のためにErlangを学んでいる。基礎的な文法については学び終わったので、現時点でのErlangについての雑感を書いておこうと思う。

Erlangは多数派のプログラミング言語とはだいぶ違う文法を持っている。終端記号がドットであることもそうだが、比較演算子もだいぶ違っている。多くの言語が!=を使うなか、Erlangは/=を使っている。Less than or equal toが=<であるのも多数派とは異なっている。ただし、Greater than or equal toは>=だ。一貫性がない。

終端文字はドットだが、関数の中には一つの式しか書くことができない。式はカンマで区切ることができるので、以下のようになる。

func() ->
    expr1 , % カンマ
    expr2 , % カンマ
    expr3 . % ドット

このような文法はリファクタリングの時に問題になる。というのも、例えば関数の戻り値をexpr3の評価結果に依存した別のものにしたくなったとき、

func() ->
    expr1 , % カンマ
    expr2 , % カンマ
    expr3 . % エラー
    expr4 .

うっかりドットをカンマに修正するのを忘れるとエラーになる。

そもそも関数の文法も問題だ。関数は同名の関数群をセミコロンで区切って一度に定義する文法になっている。

Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr . 

関数群の最後はドットで終端するが、途中の関数はすべてセミコロンで区切る。これは関数を定義する順番を変えたときに、手でセミコロンとドットを修正しなければならない。

Name( P1 ) when ... ->
    expr ;
Name( P1 ) when ... ->
    expr . % エラー、リファクタリング中の修正漏れ
Name( P1 ) when ... ->
    expr ; 

変数が再束縛できないのもコードを汚くする。というのは、結局現実のコードでは式を評価した結果を元に更に計算を行い、その結果を束縛し、途中の結果については参照しないコードがある。


R1 = expr1 ,
R2 = Do_something(R1) ,
R3 = Do_something2(R2) .

もちろん、途中の評価結果を変数に束縛する必要はないのだが、あまりにも式が長い場合は可読性のために途中でわかりやすい名前をつけたくなる。しかし、変数の再束縛が許されていないために、変数名に意味のある単語を使わない文化圏の怠惰な数学者がよく使うX'や、gitを使えないバカがよく使う2020-01-18プロジェクト企画書(最新)(第二項)(承認待ち).zipのようなひどい変数名を作り散らかす原因になる。

他にもガードにBIFしか使えないとか型がないとか型がないとか特に型がないとかいろいろといいたいことはあるし、ErlangはHaskellの爪の垢を煎じて飲んでほしいのだが、汎用プログラミング言語としてみたErlangは貧弱で、主要なプログラミング言語とは違う文法を採用し、しかも融通がきかない不自然な文法で、まことにつまらない言語だ。まるでGOやJavaのような言語と言える。

ただ、言語としてはそれほど難しい概念もないので、習得は容易だろう。

ただし、あらゆる点で言語としておそまつな点が目につく。最初はクソ言語と思っていたが、途中からこれはBrainfuckと同じエソテリック言語の仲間だと思えてきた。

そして基礎的な文法を一通り学び終えた今では、ついにあるひとつの結論に達した。Erlangは分散コンピューティング用のDSLなのだ。SQLとかシェルスクリプトと同じであって、汎用プログラミング言語として考えるからクソ言語だと思うのであって、特定の分野専門のDSLだと考えれば悪い言語ではない。汎用プログラミング言語として考えたとき、SQLやシェルスクリプトはいかにもクソ言語というしかない。しかし、SQLやシェルスクリプトの価値はそこにあるのではない。Erlangも同様に、たまたま汎用プログラミング言語としての機能を備えてしまっただけで、本来は単なるDSLであり、ツールでしかない。1980年台にネットワーク越しのリモートコンピューター群をあたかも一つのコンピューターを扱っているかのように扱えるようなツールを実現したという点で価値がある。

さて、Erlangの基礎的な文法は一通り理解したのだが、まだこれでErlangの習得が終わったわけではない。これからErlangのプロセスやメッセージパッシングなどを学ばなければならない。まだもう少し時間がかかりそうだ。

膝の痛みがなかなか治らない

スノーボードによる膝の痛みがなかなか治らない。

30を超えてから新しい運動を始めると悩まされるのが靭帯と腱の損傷だ。筋肉痛というのは数日で回復するが、靭帯と腱の回復には数ヶ月かかる。これまでにボルダリング、ダンス、スノーボードと新しい運動に挑戦し続けているが、そのたびに靭帯と腱を損傷している。

残念ながら今の日本語圏のインターネットにはまともな情報がないので、せめて自分の怪我の状況と回復時の自覚症状ぐらいは書き残しておこうと思う。

ボルダリングでは指の腱を損傷した。原因は単純で、足を滑らせて指だけで極端な荷重変化を支えてしまったのが原因だ。指の腱を損傷すると、指の曲げ伸ばしと手首、手首の下辺りに違和感を感じる。回復の自覚症状はかなり急峻だ。病院に行ったところ、抗炎症作用のある塗り薬を処方された。塗るとわずかに痛みが減る。最初の一ヶ月ぐらいはほとんど回復が見られず絶望的になるが、ある日を境に1日単位で違和感が減っていく不思議な自覚症状の変化が現れた。

ダンスでは足首が痛くなった。つま先を上げる方向に足を動かすと、足首が痛くなる。医師の診断によるとアキレス腱を痛めたそうだ。一ヶ月ほどダンスを中断して、痛みがやや収まったものの、依然として残るので病院に行ったところ、処方はロキソニンテープとジクロフェナクNa(鎮痛抗炎症剤)とレバミピド(胃薬)とアセトアミノフェン(解熱鎮痛剤)であった。薬の鎮痛効果により痛み自体は軽減されるのだが、痛みがなくなるわけではなく、回復して痛みが減ったのか、単なる鎮痛効果で痛みがわかりにくくなっているだけなのか判断に困る。そのまま更に1ヶ月ほどは自覚症状は変わらなかったが、ある時を境に急激に1日単位で症状が軽くなっていった。

そして今悩まされているのが膝だ。原因はスノーボードだと思われる。ダンスで膝を痛めなかったのはよくわからない。いかにも膝に負担の掛かりそうな動きもしたのだがダンスでは問題がなく、スノーボードに1日行っただけで極端に膝を痛めてしまった。

当初は右膝の内側に痛みがあったのだが、今は左膝も少し痛み、かつ膝の外側にも痛みがある。膝の内側の痛みしか自覚症状がなかったときに医者にかかったところ、膝関節内側側副靱帯(MCL)を痛めたのだろうということだ。処方は足首と同じだ。

肝心の治療経過だが、一ヶ月経過した今、まだはかばかしくない。未だに痛みが残っている。当初は階段を上がるととても大きな痛みがあったが、今は階段を上がるぐらいでは痛みはでない。当初は膝に負荷をかける動きをすると痛みが出ただけで、安静にしていれば痛みはなかったのだが、今は膝に負荷をかけても痛みはそれほどないが、常に膝に違和感を感じている。この安静時の違和感は安定せず、痛みがないときもあれば、痛むときもある。自覚できる痛みがないからとうっかりと地下鉄の階段を上がってしまった翌日は痛みが出ている気がするので、膝への負荷に遅延して安静時の痛みが生じているのかもしれない。

靭帯と腱の回復には2ヶ月かかるという個人的な経験則からすると、回復にはまだ一ヶ月かかる計算になる。スノーボードのシーズンは短い。特に今年は雪が少なく例年より短くなるだろう。

この記事をここまで書いてから2日立った。たまたま膝の調子が良かったのでボルダリングに行ったところ、回復の兆しを感じた。翌日も痛みがあまり膝に残らない。

改めて考えてみると、今まで靭帯や腱を痛めたときの痛みの自覚症状は、いつも同じような状況だ。まず受傷直後はそれほど痛くない。翌日から数日も痛みはあるもののそれほど痛くはない。ただし、少しでも負荷がかかったならば危険な痛みを感じるので運動はできない。その後一ヶ月以上、運動を完全に控えても痛みが収まらない状態が続く。多少の負荷をかけても当初感じた危険な痛みはないのだが、やはり痛みはあるので運動はできない。このような状態が一ヶ月以上続いて絶望するが、ある時急に回復の兆しを感じる。そうすると少しぐらいは負荷を書けても痛みは感じなくなり、運動も様子を見ながら再開できる。そして、不思議なことに運動をすると回復が早まる。

2月にはスノーボードに復帰できるかもしれない。

2020-01-05

2020年の日本には2020年にふさわしい日本語の掲示板がない

情報の流通において最も効率的なのはテキストだ。テキストを効率よく流通させる方法として、古典的なインターネットにはメール、チャット、掲示板があった。

このうち、メールは古典的なEメールがまだ生き残っている他、現代的なSNSがメールの機能を代替し始めてきた。日本では今の所LINEが最も普及しているようだ。

チャットもそうだ。古典的なIRCはまだ生き残っている。しかし現代的なSNSや、Slackのようなサービスが代替し始めてきている。

では掲示板は? 現代の日本には現代的な掲示板サービスが欠けている。

もちろん、掲示板機能を提供するWebサービスはたくさんある。しかし、日本語圏でWebサービスを提供しているものは、いずれもかなり限定的な目的に特化したものだ。例えばユーザー同士で質問と回答をしあうサービス(Yahoo知恵袋など)とか、ソーシャルニュースアグリゲーション(はてなブックマーク)のようなサービスはある。しかしテキストの流通機能としては貧弱であり掲示板ではない。

2ch/5chのような古典的な掲示板はある。しかし見たところ技術的負債と開発リソースの不足により、ほとんど当時のまま運用されているようだ。2020年に使いやすい作りではない。

私の考える2020年の品質の掲示板とは、RedditやHacker NewsのようなWebサービスだ。どちらもソーシャルニュースアグリゲーションだ。そういう意味でははてなブックマークはとてもいい線を行っている。しかしはてなブックマークは掲示板ではない。単に1行コメントが書けるだけで、他人のコメントを参照してテキストを積み重ねることができない。はてなブックマークはソーシャルニュースアグリゲーションというよりはオンラインブックマークとして設計されているので、結果として掲示板にはならなかった。

結果として、日本には2020年にふさわしい現代的な掲示板がない。ないということはどこかが作れば儲かるのではないかと思う。誰かがやってほしい。

Arch Linuxがパッケージ圧縮フォーマットをxzからzstdに変更

Arch Linux - News: Now using Zstandard instead of xz for package compression

Arch Linuxがパッケージの圧縮に使うフォーマットをxzからzstdに変更した。

Archでは圧縮レベル20を使うことにより、xzにくらべて0.8%サイズが増加するが、デコード速度が1300%向上するという。

CanonicalによるUbuntuは2018年にzstdに移行するテストをしていて、その結果による、圧縮レベル19を使うことにより6%のサイズ増加だったということだ。

zstdとはFacebookのYann Colletが2016年に発表した圧縮フォーマットとそのリファレンス実装のことだ。軽く調べてみたところ、メモリ使用量が多く並列実行に力を入れている設計と実装のようで、現代のコンピューター向けという感じがする。

2020-01-04

未来のタクシーはネットカフェになる

深夜にのんびりとRedditを眺めていたところ、以下のような1年前の記事が話題になっていた。

Mean streets: Self-driving cars will "cruise" to avoid paying to park

内容はこうだ。自動運転が実用化されたならば、車は駐車せずに自動運転で周辺を運転するようになる。なぜならば、燃料費と摩耗費よりも駐車料金のほうが高くつくからだ。

たしかに一理ある。都市部の駐車料金は高い。なぜなら土地が高いからだ。自動運転により人件費がなくなれば、後は「車の燃料費と摩耗費<駐車料金」であるならば車を運転し続けたほうが安い。

この考えを推し進めると、将来、タクシーはネットカフェになる。

ネットカフェは簡易的な個室とインターネット、マンガや映画を提供している。貧乏人はネットカフェを簡易宿として利用している。これらネットカフェの機能は、自動運転による無人タクシーで代替できる。

つまりこうだ。都市部を自動運転による無人タクシーが流している。客はこのタクシーを呼び止め中に乗る。中にはフラットに倒すことのできる椅子とコンピューターと携帯電話網によるインターネットが提供されている。またマンガや映画のストリーミングサービスも提供されている。客がネットカフェ機能を利用している間、この無人タクシーは周辺、あるいは指定した目的地まで運転する。この無人タクシーは簡易宿としても利用できる。客は椅子をフラットに倒して寝ることができる。その間もタクシーは周辺を運転する。

荒唐無稽だとも思えない。現実のネットカフェは、土地と建物を用意するのに大掛かりな費用がかかる。しかも場所は固定で、車のように柔軟ではない。

どの程度現実的なのだろうか。車の摩耗費、メンテナンス費用、通信費用、コンテンツ契約費は償却して無視するとしよう。後に残るのは燃料費だ。現在、日本のガソリン価格はレギュラーが146円/Lだ。最新のハイブリット車は20km/Lを上回る燃費を持っている。

ただ、このネットカフェとしての無人タクシーにおいて、燃費というのは「距離/燃料」ではない。本当の燃費は「時間/燃料」だ。このネットカフェとしてのタクシーは走行をしなくても常時電力が必要なので、停止していても燃料を消費する。運転は燃料消費を最小にするが、走行距離を最大にする必要はない。たとえ信号や渋滞や燃料補給によって都合よく停止している時間が長くても、燃料消費が少なければ問題はない。

もしガソリン1リットルで1時間の燃費(時間/燃料)があるのだとしたら、1時間あたり146円の費用がかかる。

あるいは、蓄電池を搭載した完全電動車とすることもできる。この場合、無人タクシーは充電拠点の周辺を運転することになる。

都心部のネットカフェの料金と比較してみよう。都心部のネットカフェの相場は、30分で300円、3時間で千円、6時間で2千円、12時間で3千円程度だ。自動運転による運転手の人件費のかからない無人タクシーとしてのネットカフェは物理ネットカフェと同じ料金で利益を出せそうだ。

では肝心の駐車場の料金はどうだろう。都心部の駐車場の料金はまちまちだが、無人タクシーは場所の利便性を考えなくてもよい。利便性の悪い場所にある駐車場は、都心部であっても夜中は500円といった安いところもある。長時間利用する客を乗せた無人タクシーは、安い駐車場が空いているのならば駐車場を使い、そうでなければ道路を燃費(時間/燃料)のよい運転で流すのがよいだろう。

高度な自動運転が実用化され、このようなネットカフェとしての無人タクシーが大量に公道を流すようになると、公道が渋滞して社会問題になるはずだ。しかし法改正は技術開発よりも時間がかかるはずで、このような未来はありうるのではないか。