博多電光

技術ブログ

Firefoxにパイプライン演算子を実装した

主に大学とバイトで忙しくオープンソース的な活動がしばらくできていない@hakatashiだが、大学の実験でSpiderMonkeyの開発に参加し、なおかつ本家にマージされるという貴重な経験を得たので、これまでの経緯とかをまとめておく。

かつ、本実験では実験レポート代わりにブログ記事を1つ書くことになっている (すごい) ので、そちらのレポートも兼ねている。

相方のブログエントリはこちら:

siquare.hatenablog.com

SpiderMonkeyとは

SpiderMonkeyとは、JavaScriptの処理系の一つである。フロントエンドエンジニアならばまず知らない人はいない。主にMozillaが保守・開発を行っており、Firefoxブラウザに標準で搭載されている。あまり知られてないが当初は Netscape Browser に搭載するために実装されたJSエンジンであり、同時に世界で初めてブラウザに実装されたJSエンジンでもある。

SpiderMonkeyの処理系としての大きな特徴は、JavaScriptコードを実行する際に、一度中間言語であるバイトコードに変換してからインタプリタに通すという点である。この点で、直接マシンコードに落とし込んで実行するV8などの他のJSエンジンとは大きく異なる。これはある意味プラットフォームに応じた最適化がやりづらいとも言えるが、一方でコンパイラのコードがフロントエンドとバックエンドにはっきりと分離できるため、可搬性が高く、開発にかかるコストが低いのも特徴である。今回SpiderMonkeyに新しい機能を実装する際にも、この構成に大いに助けられた。

実装までの経緯

本来ならば、こんな大規模プロジェクトに、しがないフロントエンドエンジニアであるところの僕が関わる機会はまず無いのだが、どういうわけかガッツリと関わりを持ってしまった。これもいろんな偶然と人との出会いがあった故である。

僕が通っている電気系の学科で行われる実験の一つに、「大規模ソフトウェアを手探る」というタイトルのものがある。これは一言で言うと「大規模なOSSプロジェクトを一つ選び、何かコントリビュートする」という実験 (?) で、シンプルながら非常に意欲的な内容である。オープンソース主義者であるところの僕も当然ワクワクする実験だったのだが、さらに驚くべきはこの実験を担当するTAの一人がMozillaのコミッターであり、Firefoxリポジトリに日常的にパッチを投げ続ける、まさに「JavaScriptのプロ」であったという点である。実験中にもレクチャーがあったが、実験課題としてSpiderMonkeyを選択した場合、なんとその場で彼がコードレビューして、本体にマージすることも可能であるとのこと。

実験を通して@siquareとペアを組んだ僕は、2人で相談して「SpiderMonkeyに新しい言語機能を追加する」という課題に取り組むことに決めた。お互いJSエンジンへのコントリビュート経験もなくやや敷居の高そうな内容だったが、TAの一人がMozillaのコミッターであること、2人ともJavaScriptには日常的に世話になっていること、そしてこんな機会はめったに巡ってこないであろうことを考えて、すこし背伸びをしてみることにした。

タイムライン

実験に割り当てられた時間は10日間あった。タイムラインは以下のような感じである。

  • 1日目: 実験に関する大まかなレクチャー。
  • 2日目: 実験で苦楽を共にするペアを組む。取り組む課題を決める。環境構築。パイプライン演算子のドラフトを読む。
  • 3日目: 環境構築。トークナイザの修正。
    • この時点で@siquareがすでにトークナイザを完成させてASTを吐けるようになっていた。はっやーい。
    • そのころ@hakatashiはいまだに環境構築をしていた。
  • 4日目: バイトコードエミッタの修正。
    • ASTをバイトコードに変換する処理。ソースコードで言うところのBytecodeEmitter.cppに相当する。
    • 既存の関数呼び出しのバイトコードを吐いてる所を流用して書いたら、一応それっぽいものが動いた。
      • 提案書に書いてあるサンプルコードとかもちゃんと正しく動いたので、この時点でもう勝った気になっていた。
  • 5日目: 演算子の優先順位の修正。テストの記述。
    • 演算子の優先順位をより仕様に沿った形に修正。および仕様へのフィードバック (後述)。
      • この作業にだいぶ詰まって時間を溶かす。
    • テストは書き慣れたJavaScriptで記述する。楽しい!!
  • 6日目: テストを完成させる。優先順位問題の解決。評価順問題について検討。
    • 一応リグレッションがないように他のテストも全て走らせたところEC2の4コアマシンで8時間程度かかった。世の中のFirefox開発者の開発用マシンはどうなっているのだろうか。
  • 7日目: 評価順問題の解決。Reflect.parse API の実装。Bugzillaにパッチを投げる。
    • Reflect.parseは、SpiderMonkeyのJS部分から利用できるAPIで、JSコードの文字列をパースしてASTをJSオブジェクトとして取得できる関数である。
      • これのデバッグ自体にパイプライン演算子を使ったら、とてつもなく便利だった。誰だこれ実装したの。
      • 例: '10 |> parseInt' |> Reflect.parse |> (_ => JSON.stringify(_, null, ' ')) |> print
    • 実際に投げたパッチはこれ 1405943 - Implement Pipeline Operator |>
  • 8日目: コードレビュー (1回目)。
    • ありがたいことに翌日にはBugzilla上でTAからコードレビューを受けることができたが、不真面目な学生なので実験当日まで放置していた。
    • TA以外からもコメントを受け、configure flag の下にコードを隠すようにしたのもこのタイミング。
    • 2人がかりで修正し、再度パッチを投げる。
  • 9日目: コードレビュー (2回目)。
    • 本家masterへのrebase作業や、パッチ分割作業など。
    • 再度修正し、パッチを投げる。
  • 10日目: 最終発表
    • ⋯⋯があったらしいが、@hakatashiは今年最大級の絶起をキメてしまったため痛恨の欠席。
    • https://pbs.twimg.com/profile_images/3422504765/31886cb104d4d32f9a8e5110dba047eb.png

パイプライン演算子とは

JavaScriptは現在、仕様に関する議論が最も盛んな言語である。新しい機能や構文を追加するためのドラフトが日夜更新され、それを正式な仕様に組み込むための議論や実装が日々進められている。僕らが今回実装した「パイプライン演算子」も、そうしたドラフトの仕様の一つである。

「パイプライン演算子」は、関数呼び出しの新しい文法を定義する演算子で、執筆時点ではstage-1の提案である。

通常、JavaScriptの関数呼び出しは以下のように記述される。

print('hoge');

なんのことはない、他の言語でも見慣れた、丸括弧を用いた記法である。この文法の問題点は、関数呼び出しの多重ネストを行った時にコードの可読性が大きく下がるというものだ。例えば、

print(Boolean(parseInt(getChars(100))));

という感じである。処理の順番としては getCharsparseIntBooleanprint となるはずなのに、コード上では記述する順番が逆転してしまう。これは見方にもよるだろうが、確かに読みづらいかもしれない。

これを解決するために提案されているのが、パイプライン演算子である。上のコードをパイプライン演算子で記述すると、以下のようになる。

100 |> getChars |> parseInt |> Boolean |> print;

見ての通り、関数と引数の順番が逆転している。これにより関数呼び出しを「実際に処理される順番に」記述することができ、コードの可読性が上がる⋯⋯というのがこの演算子が提案された所以である。

関数呼び出しというプログラムの根幹に関わる変更で、個人的に言わせてもらえばヤバい文法といった印象だが、実はこのパイプライン演算子は他の言語でも意外と実装されている。有名どころで言うと Julia, OCaml, F#, Elixir, さらにはLiveScriptやElmといったAltJS系の言語でもこの演算子は実装されている。こうした背景にはLiveScriptやElmのようにJavaScript関数型言語化を推し進めようという流れがあり、pappの陽な仕様を提案しているコミュニティと深いつながりがあったりなかったりするのだが⋯⋯ともかく、関数呼び出しを便利に書ける演算子だということが一番重要なポイントである。

詳しい話は以下あたりの記事が詳しい。

qiita.com

abouthiroppy.hatenablog.jp

今回、SpiderMonkeyに実装する新機能として、このパイプライン演算子の先行実装を選択した。理由はいくつかあるが、主なものは、

  1. 「新しい演算子」という、ユーザーの目に見える部分の実装で、個人的にモチベーションが高かったため
  2. SpiderMonkey (や、その他ブラウザ) で、既に提出されているパッチや実装がなかったため
  3. 関数呼び出しという、既に存在する機能に対する文法なので、バイトコードから先の実装は変更しなくてよく、実装が軽そうに見えたため
  4. この仕様を先行実装するBabelプラグインが存在し、実装も数十行程度とシンプルだったため

という感じである。

開発

実際の開発は、相方の@siquareと協力して淡々と進めていった。最終的に本家に送信したパッチは、実装部分が@siquare, テスト部分が僕という分割がされているが、実際には特にどちらがどちらを担当したということはなく、お互いが実装とテストを行ったり来たりしながら開発を進めていった。

実装に関して、細かい話は@siquareのブログエントリに書いてあるので省略するが、特に難しかったというか、意外なつまづきポイントだったのが「関数と引数の評価順の問題」だった。

例えば、以下のコード

print(hoge);

と、

hoge |> print;

は、ほぼ同じ動作をするが、厳密には等価ではない。これは実装している最中にパイプライン演算子のドラフト仕様を読んでいて発見したことだが、通常の関数呼び出しでは「関数」→「引数」という順番 (printhoge) で評価が行われるのに対し、パイプライン演算子では「引数」→「関数」という順番 (hogeprint) で評価が行われることになっている。要するにコードに記述した順番に評価が行われるのだ。

確かにコードを書く側からすればそっちのほうが直感的かもしれない。しれないが実装する側からするとこれは少し考えものである。というのも僕らの実装ではSpiderMonkey中間言語であるバイトコード自体には手を付けず、パイプライン演算子を既存の関数呼び出しのバイトコードに変換するという手法を取っていた。それなのに厳密には直接の関数呼び出しとは違うとなるとだいぶ困ってしまう。これを厳密に「仕様に忠実に」実装するために大いに悩んだが、最終的にはpickというバイトコードの命令を用いて、「引数」→「関数」の順番でスタックに積んだあと、スタックを回転してから関数呼び出しの命令を実行することで解決した。

仕様へのフィードバック

今回開発を進める上で僕が特に注力したのは、実際のパイプライン演算子の実装というよりもむしろ、社会的な活動のほうだった。実験中にTAも仰っていたとおり、まだ仕様として固まっていないドラフトをJSエンジンに先行実装する意義とは、実際に実装を行ってみて得られた経験や、ユーザーが新しい仕様を使った時の知見を、フィードバックとして仕様に還元することにある。パイプライン演算子に関する議論はおもにGitHubで今も激しく行われているが、実際にJSエンジンに実装してみたのは (おそらく) 僕らが最初ということもあって、実際に実装して初めて得られた疑問や知見などを積極的に仕様にフィードバックしていこうと考えていた。

パイプライン演算子の優先順位問題

そんな中で特に難しい問題だったのは、演算子の優先順位の問題である。

パイプライン演算子の優先順位をどのように定義するかに関して、執筆時点ではまだ仕様が確定していないが、なるべく優先度を低くするという点で見解は概ね一致しているようである。というのも、パイプライン演算子は複数連ねて書くので他の演算子と組み合わせた時に括弧無しで書けるのが望ましく、また見た目にも「大きい」演算子なので、優先順位が低いほうが直感的であるというのが主な理由である。

このような流れもあって、当初はこの意向に従い、「あらゆる演算子の中で最も優先順位が低い」という実装を行う予定だった。しかし実際に実装してみると、思わぬ壁にぶちあたった。

今回はじめて知ったことだが、実はJavaScriptの演算子の優先順位は、「単項演算子」→「二項演算子」→「三項演算子」という順番で並んでいる。ふだんJavaScriptを書いていて意識したことはなかったが、言われてみればたしかにそうである。SpiderMonkeyではこの仕様を受けて、演算子が取る引数の数を最初に見て、まずはその順に優先順位を確定させてしまうという実装になっていた。

今回僕らは三項演算子 (?:) よりもパイプライン演算子の優先順位を低く設定しようとしたため、SpiderMonkeyのコードに大きな変更を加えなければいけないことに気がついた。これには多大な労力を伴う上に、「単項演算子」→「二項演算子」→「三項演算子」というJavaScript演算子の優先順位のルールを崩すことになってしまう。果たして本当にパイプライン演算子の優先順位は「全ての演算子の一番下」であるべきかと疑問に思った僕らは、パイプライン演算子の提案に対してその旨フィードバックし、実装は「二項演算子の一番下」で行うことにした。

(なお、ドラフトの仕様では最初から「二項演算子の一番下」という優先順位になっている。)

スプレッド演算子との組み合わせ

もう一つ、関数呼び出しのコードを手探っていて気になったのは、スプレッド演算子に対する対応である。

ES2015で定義された比較的新しい関数呼び出しの文法に、スプレッド演算子が存在する。例えば、以下のコード

const array = [1, 2, 3];
print(...array);

は、

print(1, 2, 3);

とほぼ等価である。

これをパイプライン演算子に応用するとどうなるのかを考えたところ、以下のような文法が考えられるのではないかと考えた。

...array |> print;

ヤバいを通り越してバイオハザードのコードだが、いちおう論理的には辻褄が合っている⋯⋯かもしれない。

こういった応用手法に関して突っ込んだ議論は見られなかったので、実装していて考えたことをいくつかまとめて、新たにIssueを立てた。さすがにあまりポジティブな反応は得られなかったが、パイプライン演算子の提案を前に進めるためにいちおう一定の貢献はできたのではないかと考えている。

本家コードへのマージ

そんなこんなで紆余曲折を経て、SpiderMonkeyに仕様どおりのパイプライン演算子を実装することができた。

stage-1の提案というかなり実験的な機能だということもあって、当初は本家のコードへのマージは現実的でないと考えていたが、TAの尽力もあって、configure flag 付きという条件のもとで本家ブランチへのマージができるようになった。要するに現時点では配布版のFirefoxのビルドには含まれないし、この演算子を試すにはソースからビルドし直さないといけないけれど、ソースコードには残して貰えるということである。

2回のコードレビューを経て、約束通り本家ブランチにマージして頂き、コミット履歴に僕と@siquareの名前を残すことができた。我々エンジニアにとってはこれ以上ない栄誉である。

hg.mozilla.org上のコミット:

GitHub上のコミット:

というわけで、僕も@siquareも、今では立派な (?) Firefoxコントリビューターである。

今回実装したパイプライン演算子を今すぐ試したい場合は、このページの手順に従ってSpiderMonkeyをビルドする必要がある。その際、./configureのフラグに、--enable-pipeline-operatorをつけるのをお忘れなく。

全体を通しての感想

まず何よりも、本実験を統括してくださった田浦先生、ならびに実験を通して非常にお世話になったTAの藤澤さんに深い感謝を。ありがとうございます。お世辞抜きで最高の実験でした。最終日は本当に申し訳ありませんでした。

加えて、実験ペアの@siquareにも大きな感謝を。最初から最後まで迷惑かけっぱなしで、最終発表に加えてこの実験レポートの執筆も遅れに遅れてしまったので本当に反省したい。謝謝。

そして何度でも書くが、今回の実験でSpiderMonkeyにコントリビュートするという貴重な経験を得ることができて、感激の至りである。やっぱり普段の活動ではこういったプロダクションレベルの大規模OSSに関わるチャンスは少なく、特にSpiderMonkeyのような基盤的なソフトウェアには逆に苦手意識すらあったので、これを機に他のOSSにも手を出していけたらと思っている。

実験全体を通して、レポート代わりのブログ記事や、毎回の進捗発表の時間など、先進的な取り組みを多く取り入れていて、参加して非常に楽しい実験だった。EEICの名物実験と銘打ってもいいくらいだと思う。もしこの記事を読んで実験に興味を持った東大生がいたら、ぜひ電気系に進学してほしい。というわけで、#進振りはEEICへ

祖母が他界しました

さる9月9日、母方の祖母が他界した。

穏やかな往生だった、と聞いている。かねてより病状の芳しくなかった祖母は市の療養所で長いあいだ治療を受けていたが、9月の初めごろから体調が急変、幽明の境を彷徨った。危篤の報を受けた母は直ちに実家に戻り、祖母を見舞った。一時は持ち直したものの、結局は看病の甲斐なく、9月9日の未明、祖母は2人の娘に見守られながら息を引き取った。享年81歳。

僕にとっては、人生で初めて経験した近しい親族の死だった。

盆に実家に帰った時に祖母を見舞ったばかりだった。その時の祖母はたどたどしくも会話ができ、食事に同席することもできた。ふくよかになった孫の姿を見て朗らかに笑っても見せた。が、祖母は傍目に見ても明らかに衰弱している様子だった。骨ばった手からは死相が透けて見えるようだった。病室を退去するとき、これが今生の別れかもしれないと思って祖母の手を握った。だからと言ってはなんだが、僕は祖母の死に関して思い残すことはなかった。祖母の凶報に接した際にも、どこか冷静でいられた。

祖母が息を引き取ったとき、僕はサークルの合宿で一宮に逗留していた。間が悪く連絡手段を喪失していたこともあって、僕がその訃報を受け取ったのは9日の夜になってからだった。父母と相談の上、翌晩に合宿を切り上げて葬儀と告別式に出席することになった。

ひとり帰路についた夜の10時半、僕以外に乗客のいない外房線の電車の中で、僕はおそらく初めて死について本気で考えた。明かりの少ない真っ黒な車窓と、親しかった肉親が失われたという事実は、これまでずっと目を逸らしてきた死という現実を、今まで接してきたどんな人物の死よりもリアルに突きつけてきた。

臨終の瞬間、祖母は何を考えていたのだろうか? 祖母以外の人間がそれを知ることは、絶対にできない。観測できないなら、存在しないのと一緒だ。それなら一体、なんの意味がある?

それまでに経験した記憶も感情も、死という圧倒的な一瞬によって強制的に断ち切られる。酒に酔って正体を無くしたり、寝ぼけて上の空になるのとは根本的に違う。酒に酔った人間は「今の自分は正常じゃない」と認識することができる。少なくともその余地がある。だが死はそうではない。「おらは死んじまった」などと、死を俯瞰するメタな視点を持った自分自身が存在しない。「存在しない」が存在するのではなく、「存在しない」も存在しない。虚無ではない。虚空ではない。まるで事象の地平面のように、僕の世界は死より手前までしか存在しない。宇宙の外側が真空なのではなく空間そのものが存在しないように、精神世界の観測は生と死に区切られた有限区間の中でしか成立しない。そんな絶対のボーダーライン、超えられないはずの彼我の境界面を、死はたやすく突き抜けていく。駅のホームで少し体重を傾けるだけで超えていく。それだけではない。日常生活においてすら、僕らの生命は完全に僕らの手中にあるわけじゃない。人間の命は常に誰かの手に握られている。飛行機の操縦士に。エレベーター技師に。天災に。人災に。誰かの悪意に。

怖かった。22歳の最後の夜、僕は本気で死を恐れていた。

死とはなんだ。死んだら僕の意識はどこへ行く。死んだら何もかもなくなるなら、それまでの人生になんの意味がある。今この瞬間、意識するいとまもなく刹那に僕の脳が吹き飛んだら、僕の主観はどうなるのか。その時未来は存在するのか。すでに通過し克服したと思っていた数多のドグマが僕を責め立てる。

死を連続する意識の終端と捉えるなら、死は眠りに落ちる瞬間と何も変わらない。僕らは毎夜々々死んでいる。そんなことはもちろん知っている。だったらどうして僕はこんなに動揺しているのか。眠りに落ちたあとの人生が存在しないことに、どうして震え上がるほどの恐怖を抱いているのか。それは純粋に本能ゆえか、それとも⋯⋯。

外房線ロングシートで揺られながら、僕はこれまでの人生で感じたことのない孤独と不安で気が狂いそうだった。科学に縋った弱い現代人は、宗教という心のシェルターから永遠に追放される。死への恐怖は、合理化し続ける社会が残した、人類への最後の呪いだ。

仮にジャネーの法則を信じるならば、僕は既に人生の半分以上を体感で過ごしたことになる。だけど足りない。僕はまだ全然生き足りない。こんな僕がもし天寿を全うしたとしても、死に臨み、「もう十分生きた。もう飽きてしまった」と本気で思えるのか、相当に疑わしい。

翌朝、黒いスーツに着替え、新幹線で神戸に向かい、親族と合流した。この日は奇しくも僕の誕生日だった。葬儀、告別式、読経、献花、出棺、火葬、骨上げ、繰り上げ法要、何から何まで初めてのことばかりで、ちゃんと祖母を見送ってあげられたか自信がなかった。僕は死化粧をした祖母の顔を直視することができなかった。棺に花を添えるとき、皆がそうするように祖母の顔を撫でるのが怖かった。骨上げのとき、ひび割れた肩甲骨を拾う箸が震えた。

告別式で、喪主である祖父が挨拶を述べた。20代で結婚し、苦楽を共にし、人生を分かち合った二人が、艱難辛苦を乗り越え、ついに添い遂げた瞬間だった。常に飄々とし、芸術と神戸を愛し、そして何よりも祖母を愛していた祖父の、耳慣れない嗄れ声を、僕はその時初めて聞いた。

「ついに、この日がやって参りました。妻との思い出は、思い出せば、限りがありません。ですが、それを語ることは、もう、できません。さようなら。さようなら。」

祖父が口にした、およそ挨拶らしからぬこの最後の別れの言葉が、今もショッキングに僕の耳にリフレインしている。きっと一生、それこそ、この身がああして焼かれるまで忘れられないだろう。

人事は棺を蓋いて定まる。

いつかこの長い昼が閉じ、僕の棺が永遠の闇に覆われるとき、はたして僕の人事は平穏に定まっているだろうか。祖母の霊柩が閉じられたとき、そんなことを考えていた。

僕は、ついに祖母の遺体に触れることができなかった。

人生を有意義に生きることは難しい。そもそも意義なんてないかもしれない。それでも前を向いて生きよう、なんて、今の僕には言えない。ただ、生きている僕らには容赦なく朝がやってくる。この世界には大切なものが多すぎる。僕はまだ死ねない。死にたくない。たとえ臨終の時まであと半分しか残されていなくても、たとえ意味はなくても、生きることをやめることはできない。宇宙の全てが決定論に支配されていたとしても、現在という時間的特異点に存在する僕の思惟だけは、決して泡沫じゃない。そう信じて今日を生きた。明日も生きるだろう。死ぬまでそんな調子かもしれない。


最後に。

祖母の訃報に際し、忌引などでご迷惑をかけた皆様、慰めの言葉をかけてくださった皆様に深く感謝申し上げます。祖母は浄土真宗に帰依していたため忌中・喪中はありませんが、個人的心情により四十九日の間は喪に服し、慶事・祭事の類はお断りさせていただこうと思います。よろしくお願いします。

パズルゲーム「MNEMO」を製作しました

この記事は TSG Advent Calendar の13日目の記事です。

f:id:hakatashi:20161213205431p:plain

こんにちは、博多市です。今日はサークルTSGが製作するゲーム、「MNEMO(ニーモ)」の紹介をします。

MNEMOは、パズルゲームです。プログラミングを意識した内容になっており、算数を習いたての小学生からガチのプログラマーまで、広い世代の方に楽しんで頂けるゲームになっています。

百聞は一見にしかず。MNEMOはズバリこんな感じにパーツを組み合わせて、条件を満たす回路を組み立てるゲームです。

試行錯誤を繰り返して目的の回路を組み上げたり⋯⋯。

後半になるとこんな複雑な回路を作ったり⋯⋯?

とにかく楽しいゲームです! ブラウザゲームなのですぐ開いて気軽に遊べます。ランキングもあります。

みなさんもhttps://mnemo.pro/からぜひ遊んでみてください!

あ、できれば Google Chrome でプレイしてください。Safariでもそれなりに動くと思います。それからスマホでも一応遊べますがまだちゃんと対応してないのでできればPCからお願いします。

MNEMO製作記

はい、では一通り宣伝をしたところで、MNEMO開発に至るまでの経緯についてお話します。

まず、TSGとは、東京大学のサークルであり、主にコンピューター系の活動を行っています。僕も(なぜか)4年ほど在籍しています。

TSGの晴れ舞台は、年に1回開催される東京大学の学園祭、駒場祭です。部員はこの日に向けて、各々が持つ技術と誇りを賭けて、来場者向けの展示物を作る⋯⋯はずだったのですが、今年は少し違いました。

今年8月、東京大学工学部丁友会主催の科学イベント、TechnoEdgeの第3回が開催されました。東大に興味を持つ学生が「工学に親しむ」ためのイベントなのですが、今年はこれにTSGも声をかけていただいたので、喜び勇んで出展することになりました。そして本番に先駆けて、TSGでは恒例の夏合宿を行い、内部イベントとしてミニハッカソンを開催しました。この時にTechnoEdgeに出展するための企画案として製作されたのが、MNEMOです。

当初はプロトタイプということで、現在よりもだいぶ簡素なデザインでしたが、ゲームの構想やルール自体は今とほとんど変わっておらず、この時点でも遊んでいてかなり楽しいものでした。*1

f:id:hakatashi:20161213232250p:plain

MNEMOという名前もこの時つけられました。名前の由来は、アセンブリ言語で用いられる「ニーモニック(mnemonic)」の頭の部分です。簡単な命令を組み合わせて複雑な回路を作るというアイデアが低級言語を彷彿とさせたので、こう名付けました。命名者は僕です。

なので読み方は「ニーモ」です。一部で「エムネモ」と呼ばれており部内でも浸透していますが正式には「ニーモ」です。「ニーモ」なのです。

そして迎えたTechnoEdge当日、無事MNEMOを見せられるレベルまで完成させ、来場者からそれなりに好評を得ることができました。MNEMOのライブパフォーマンスも行われました。

本来はこのTechnoEdgeのためだけに製作されたゲームだったのですが、MNEMOのパズルゲームとしての単純さと奥深さにポテンシャルの高さを感じ、そのままTSGの部内プロジェクトとして開発を進めていくことになりました。その後の地道な開発や駒場祭における展示を経て、本日パブリックリリースと相成りました。

そんなこんなで、TSGメンバーがそれなりに頑張って作ったゲームです。ぜひぜひ楽しく遊んであげてください。よろしくお願いします。

また、MNEMOはオープンソースプロジェクトです。改善してほしい点や追加したいステージなどありましたらぜひGitHubまでお寄せください。

最後に、以下は2016年12月現在のMNEMOのContributor一覧です。ありがとう!

f:id:hakatashi:20161213234912p:plain

*1:ちなみに、TechnoEdge前日までこのデザインのままでした。

EEICの過酷な課題生活を支える(願望)技術

この記事は eeic Advent Calendar 2016 その2 の3日目の記事です。

qiita.com

←2日目: Android アプリ解析基礎 その2 -PC編- 4日目: チノちゃんと寝る


博多市は、東京大学の2016年度進学選択で、工学部電気電子工学科に内定しました。内定に至るまでの経緯についてはこの Advent Calendar の22日目でもう少し語ろうと思うので、今回は割愛します。

工学部電気電子工学科は、隣接学科でありほぼ同じカリキュラムが適用される工学部電子情報工学と合わせて、EEICと略されます。名前の通り電気と電子を扱う学科であり、量子力学から論理回路、高級プログラミング言語に至るまで、電子技術を支えるあらゆる学問について手広く扱う学科です。

そんなEEICは、工学部の中でも指折りのスパルタな学科であると(少なくとも学科内では)言われています*1。かくいう僕も、EEIC内定から3ヶ月の間に随分思い知らされました。

まあ大体こんな感じです。

さて、そんなEEICで、博多市はWeb長*2を引き受けています。EEICにおいてはサーバー管理やNASの管理、ウェブサイトの管理、Slackの管理など仕事の多いWeb長ですが、相互扶助の精神が育まれるEEICにおいて僕も何かWeb長として人々に貢献できる仕事がないかと探した結果、eeic2017botというslackbotを制作することにしました。

EEIC2017のSlackについて

EEICでは学年内での連絡やコミュニケーションにSlackを用いています。今年度の内定生はなんと学科ガイダンスが行われる以前から自主的にSlackチームが組織されており、ガイダンス時点ですでに半分が加入している状態でした。現在の学年Slackは僕がこれを引き継ぐ形で受け取ったもので、チームとしてはガイダンス以前に組織されたものがそのまま使われています。

例えば、以下のようなチャンネルが存在します。

  • #general: 真面目な話をする部屋
  • #random: 真面目じゃない話をする部屋
  • #assignment: 課題について相談する部屋
  • #programming: プログラミングについて質問する部屋
  • #competitive-prog: 競技プログラミング勉強会の話をする部屋
  • #examination: 試験中(!)に使われる部屋
  • #party: コンパや懇親会の連絡をする部屋

このうち、EEIC生にとって生命線となるのは #general#assignment です。#general には休講情報や落とし物情報などが流れ、#assignment ではシケ対が解いたレポートの解答や課題の解き方について流れてきます。

eeic2017botは、そんな #assignment チャンネルでEEIC生に日々課される課題をお知らせする仕事をしています。

eeic2017botのおしごと

f:id:hakatashi:20161202023039p:plain

これがeeic2017botです。

ひと目見て分かる通り、カオスです。「EEICたん」は僕がeeic2017botに勝手に付けた名前、アイコンは電気系の民なら誰でも知っているルートヴィッヒ・ボルツマンの肖像です。気がついたら誰かが設定してました。きっと課題のやり過ぎで精神を病んだEEIC生の仕業に違いありません。

EEICたんは、先ほどの画像のようにEEIC生の誰かが登録した課題情報をお知らせしたり、

f:id:hakatashi:20161202024449p:plain

週の初めにその週に提出する課題の一覧をお知らせしたり、

f:id:hakatashi:20161202024457p:plain

前日まで課題をやらないうっかりさん*3のために課題締切前日にお知らせを流したりしてくれます。

eeic2017botの仕組み

eeic2017botのソースコードGitHub一般に公開しています。オープンソース最高。

eeic2017botがお知らせする課題の一覧は、EEICのWikiの「課題一覧」というページを参照しています。WikiはEEIC生なら誰でも編集できるので、課題情報の更新が誰か一人に頼り切りにならなくて運用が楽です。

f:id:hakatashi:20161202025145p:plain

一番最初に引用したツイートで呟かれている「EEICで1ヶ月のうちに課された課題の一覧」は、実はこのページの目次を参照しています。

そして、BOTのプログラムはHeroku上で動いています。Heroku Scheduler で動かせば、BOTが眠ることもないし消費するDynoも低く抑えられるので楽ちんです。11月の消費Dynoは10.8時間でした。

プログラムはNode.jsで書かれており、Heroku Scheduler で10分おきに実行されるごとにEEICのMediaWikiにアクセスし、APIを叩きます。ページを取得するとそれを気合でパースし*4、登録されている課題の一覧を取得します。

取得した課題はRedis上にキャッシュされ、新しく追加された場合はSlackに通知、そして指定時刻になったら該当する課題を引いてきてSlackに通知します。新しく追加された課題を検索するとき、RedisのSDIFFを使うと高速で便利です。

ちなみに、このプログラムはコミットログを見るとわかりますが電気回路理論の授業中に作成され、その日のうちに運用開始しました。課題を通知するために課題がおろそかになるとは皮肉なものです(適当)。

EEIC生を支えるその他の技術

EEIC生の過酷な課題生活を支えるのはeeic2017botだけではありません。

EEIC2017のシケ長は専用のTwitterアカウントを持っており、課題や試験の情報を逐次お知らせしてくれています。

twitter.com

それから、EEICの試験問題やシケプリは過去のものも含めてすべて専用のWebDAVサーバーに蓄積されています。こちらはEEIC全学年共用のストレージになっており、ブラウザ上でアクセスできるフロントとしてPydioを採用しています。

f:id:hakatashi:20161202173101p:plain

まとめ

というわけで、EEICのB2の課題生活とそれを支える技術について紹介しました。EEICに内定してから3ヶ月、学科生専用のサーバーがすでに構築されていたり、レポートが出されたその日のうちにシケ対がレポートの解答をSlackに上げたりと、EEICの学生の真面目さ(とクソ真面目さ)には驚くばかりです。

みなさん、#進振りはEEICへ

明日は@Ishotihadusさんの「チノちゃんと寝る」です。お楽しみに。

*1:しかし、東大には2年冬から授業が全て本郷で行われる学科や、一度でも授業を欠席すると留年が確定する学科があったりするので侮れない。

*2:東大用語。主にクラス/学科のメーリングリストやウェブサイトの管理などを行う役職。

*3:つまり僕

*4:MediaWikiにはaction=parseというAPIがあるようなのですが、使用したAPIラッパーが非対応みたいなので使えていません。いつかラッパーを捨てて対応したい⋯⋯。

6月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160705005359p:plain

コミット数が単調増加の傾向にある。どういうことなの……

今月は技術書典があり、執筆も全てGitHub上で行ったためコミット数が大幅に増えた。あと Google Summer of Code への取り組みで多少コミット数を稼いだ。

主な成果

awesome-prml-jaを作成

サークル活動でPRML勉強会に参加しているのだが、インターネット上に散逸する過去のPRML勉強会の資料をまとめたサイトがないので、少し前に流行ったawesomeの体裁でGitHubリポジトリを作った。作ってみて思ったが資料多すぎである。正直本買わなくてもこれだけで独学できてしまうのではないだろうか。

awesomeの統括リポジトリに登録申請するか迷ったが、日本語だし適切にフォーマットされてないのでやめた。

slack-ikkuを作成

アルバイト先のSlackで遊ぶために一晩で作ったどうしようもないネタBOT。後ほどブログを書く予定。

general-category 1.5.0 をリリース

ファイルサイズがさらに小さくなった。それからREADMEのサンプルコードを自動でテストするようにした。

あと1.4.0で使用したファイルサイズを小さくする技術について社内LTで発表した。各方面の技術を結集した謎スライド。

HakataFeedをQiitaとGithubに対応

個人的に使用している、WebサイトをスクレイピングしてAtomフィードに変換するやつ。もとはpixivの新着フィードを変換するためだけに動いていたが、様々なサイトを統一的に扱うためにクラス継承の仕組みをちゃんと整えた。あと取得したCookieファイルシステム上に永続するようにした。疲れた……。

LINE for Node.js

ネタで作ろうかと思ったが--line--というモジュール名が取得できなかったので諦めた。仕様だけ書いてある。

5月のコミットまとめ

hakatashi (Koki Takahashi) · GitHub

f:id:hakatashi:20160603043015p:plain

かなりcontributionしたと思った先月を軽く超えていてビビる。

Privateなcontribution数もプロフィールに表示できるようになったので、なかなか彩り豊かになって幸せである。

主な成果

mochify--browser-fieldオプションを実装

この画像には見えないが、mochifyに--browser-fieldなるオプションを実装したプルリクがマージされたのが一番の成果と思われる。他人のリポジトリにマージされたプルリクとしては、規模的にも自分史上最大のものになった。しばらく放置されていたので不安だったが、マージされた時は軽く小躍りしてしまった。

いまはGSoCの真っ最中である。自分の仕事がちゃんとマージされるようにがんばらなくては。

Sugoi Converter をアップデート

1.7.2 から 1.8.16 になった。新機能は以下のとおり。

  • Quoted-Printable の変換を実装
  • 各種依存パッケージのアップデート
  • 各種deprecatedパッケージの駆逐
    • JadeをPugに
    • ついでにGulpをベータバージョンの4にアップデート
  • Google Analytics を導入

npmモジュール general-category をアップデート

npmモジュール asianbreak のテストフレームワークをmochaからInternに変更

はい、GSoCの課題の一つです。

ついでにカバレッジも取れるようになって最高。

takuboku-project

おや、どうしたんだろう?

シンタックス・ハイライト機能で対応してほしい言語

お題「シンタックス・ハイライト機能で対応してほしい言語」

LiveScriptをリクエストするしかない。

require! 'prelude-ls': {unfoldr, map, concat}

export integer-array-to-buffer = ->
  it |> map ->
    it |> (+ 1) |> unfoldr ->
      if it is 0 then null
      else
        modulo = it %% 128
        base = it .>>. 7
        modulo .|.= 2~1000_0000 if base is 0

        [modulo, base]
    |> map (.^. 0xFF)
  |> concat
  |> buffer-from

general-category/util.ls at 4e494d9347d95471cce63d10a8c2dbdf0775beb9 · hakatashi/general-category · GitHub

HaskellにもCoffeeScriptにもなれなかった悲しい言語。