修士論文の合格が明らかになった

読みにくくて恐縮だがそういうことだ。なお「散々自分の修論をクソ呼ばわりしておいて結局優取ってんじゃねえか詐欺師野郎」という批判があるかもしれないが、文学部における優は特に意味を持たない。優上は優秀、優は普通、良は悪い、可はお情けだ。

これを受けて、僕が修了を失敗する残された可能性は

  1. 単位数の計算間違い
  2. 修了前に犯罪等で退学になる

に絞られた。JavaScriptを使ったプログラミングをしているので2が発生する確率は決して低くはないのだが、祈ろう。

カメラを止めるな

テレビで『カメラを止めるな』を放送していたので見た。すごいどんでん返しがあるという評判だったので気になっていたのだが、『ラヂオの時間』の発展系のように見えた。視聴者に見えないところで制作スタッフがリアルタイムに奔走している姿を描くという基本形に、いかにも安っぽいB級ゾンビ映画を一度フルで見せるというアレンジによって謎解きの快楽を付け加え、スタッフたちのドラマの魅力を増すことに成功している。

怪異・妖怪ゼロ食い/fish!!

学部生の授業のために作ったプログラムがどうもおかしいという話なので報告をよーく読んでみたら、0から始まる数列をExcelで読んだときに数値扱いされて左端の0が「食われる」という事件だったようだ。キレそう。Excelを許すな(俺が悪い)。なお検証の過程でJestの使い方を覚えた。でもCDNからモジュールをインポートしていることをJestが気づいてくれなくてエラーが出まくってやっぱりキレそう。

自宅のPCのシェルをfishに変えた。昆虫なので色がきれいなのは好き。欠点はググラビリティ。

TweetDeck魔改造―読み上げ

MutationObserverとSpeechSynthesisを使うシンプルな方法が既に紹介されていたが動作が不安定だったのでChrome拡張として自分で作り直した

SpeechSynthesisに長文を連続で送りつけると読み上げが止まってブラウザの再起動が必要になる。この辺りは中で呼んでいるAPIの仕様の領域なのでまだよくわかっていないが、TLの流速に合わせて調節する必要がありそうだ。

TweetDeckのページ全体がJavaScriptによって動的に生成されているので、ページの読み込みのあとにMutationObserverのターゲットを指定する必要がある。愚直にsetTimeoutを使った。新しいツイートの受信以外にもMutationObserverを発火させる要因がなにかあるようだが、まだわかっていない。

読み上げの内容についても、リプライは読むのか、ハッシュタグは読むのか、URLは読むのか、画像はどうするのかなど使い方に応じて検討すべき点がある。これらは設定で変えられるようにしたい。

Vivaldi復帰断念

なんとなくVivaldiのことを調べたら2.x系列がリリースされていた。デザインや設定の自由度の高さはchromeより好きだし、安定性さえ問題がなければしばらく戻ってみようかと思ってインストールしてセッティングしてみたが、最重要拡張機能であるBetterTweetDeckが動かないので泣く泣く諦めた。

BetterTweetDeckはとにかく優れものなのだが、僕が最もよく使うのはクリップボードからの画像投稿だ。スクリーンショットをクリップボードに保存し、それを直接投稿欄に貼り付けるのは非常に便利だ。

ところで今日は寒い。29日に寒波が来るとのことで、コミケ早朝組の生命が心配だ。寒い日は暖かい部屋にいるに限る。今日はほとんど外出しなかった。

昼食に焼きそばを作った。油が切れていたので新しいのを買ったのだが、これが以前より大きいパッケージで(当然大きい方が割安)自然と油の使用量が増える。すると焼きそばの味がよくなり、焦げ付きも減った。油も洗剤も困ったら増やしてみるといい。

JavaScript+Hyperappで心理学実験プログラムを作った

これです(github)。

僕の学科では学生が実験に参加しつつその実験についてレポートを書くという授業が多く行われている。そこで行う実験は古典的なものが多いのだが、大昔に書かれた実験プログラムがメンテナンスされずに使われ続けているということがある。

今回書いた記憶実験のプログラムもそうで、誰がいつどうやって作ったかわからないexeファイルが受け継がれ使われ続けてきた。しかし内部の処理がわからないので細かい仕様がわからず、いろいろ試してみて推測することしかできない状態だった。さらにいつ動かなくなるかもわからない。

そこでこのプログラムを移植(ソースコードがないので移植と言うかは微妙だが)しようという話になった。当初はPythonが候補に上がっていたが、多数の学生に授業中に同時に行わせるにあたり、Pythonをexeに固めたものは容量が大きくなりすぎダウンロードが長引く懸念があった(経験的には数十MB)。そこでJavaScriptでの制作を提案した。サンプルを作って披露したところゴーサインが出たので制作した。

動作は単純で

  1. x桁のランダム数列を3秒間表示
  2. 数列を消し5秒間待つ
  3. 参加者が数列を思い出して回答する
  4. 正誤を3秒間表示
  5. 桁数を変更し、1に戻る

というものだ。5の桁数変更のアルゴリズムには上下法や恒常法などがある。

上下法は正解すれば次は1段階難しく、不正解なら次は1段階簡単にするというアルゴリズムだ。これによって参加者の正解できる限界の桁数に収束する。メリットは試行数が少なく済むこと。

恒常法は一定の範囲の桁数をランダムな順番で課し、桁数を横軸に、正解率を縦軸にプロットすることで正解率を桁数を結びつける関数を得る。そして正解率50%(任意の値)に相当する桁数をその人の限界とする。メリットは関数そのものが得られるため多様な分析が可能であること。

心理学の実験は基本的にはwebではやらない。それは参加者の環境が統一できないからだ。MATLAB+Psychtoolboxが主流で、Python+Psychopy(pygame)もある。しかしポータビリティは低い。GUIを使うプログラムはDockerで動かすのは不便で、できてもパフォーマンスに不安がある。

そこまで環境にこだわらない実験や、今回のように同じ部屋で多くのPCで実験を行うときにはポータビリティの高いwebプログラミングによる実験は便利だ。そもそもGUIを扱うノウハウやライブラリという点ではJavaScript、というよりブラウザという環境が優れている。

Hyperappでhtml要素の真偽属性を操作する

※この記事は『金麦 RICH MALT』を飲みながら書かれた。

hyperappのviewはh関数で作る。これは公式サイトのサンプルだ。

const view = (state, actions) =>
  h("div", {}, [
    h("h1", {}, state.count),
    h("button", { onclick: () => actions.down(1) }, "-"),
    h("button", { onclick: () => actions.up(1) }, "+")
  ])

h関数は3つの引数をとる。1つ目はタグ名、2つ目は属性を列挙したハッシュ、3つ目は子要素だ。ここで属性はハッシュなので、キーとバリューのペアが必要だ。しかし全ての属性がキーとバリューのセットで用いられるわけではない。たとえばreadonlyは値をセットする必要がなく、存在することによって機能する。

ここでHTML5の真偽属性の仕様を確認する。

checkedおよびdisabledとなるチェックボックスの例を示す。checkedおよびdisabled属性は真偽属性である。

<label><input type=checkbox checked name=cheese disabled> Cheese</label>

これは次に書かれるものと等価であるべきである:

<label><input type=checkbox checked=checked name=cheese disabled=disabled> Cheese</label>

スタイルを混在させることもできる。以下は依然として等価である:

<label><input type='checkbox' checked name=cheese disabled=""> Cheese</label>

どういうことかというと、以下の3つはどれでもいい(参考)。

  • disabled
  • disabled=disabled
  • disabled=””

つまり真偽属性を変化させたいときは以下のように書きわけることができる。

h("input", {readonly=""}, "")
h("input", {not-readonly=""}, "")

これをhyperappの枠組みで考えるとこうなる。

const state = {
  readonly: "readonly"
}

const actions = {
  writable: () => state => ({ readonly: "not-readonly" })
}

const view = state => h("input", { [state.readonly]: "" }, "")

viewのh関数の第2引数のハッシュで、ブラケット記法を用いてキーの方を変更する。バリューはなんでもいい。

Mastodonに自動ハッシュタグ機能をつけた

アニメ実況時は同じハッシュタグで継続的にツイートする。よってハッシュタグを保持し自動的に付加し続けてくれる機能は便利だ。作った。

やたらとトゥートの反映が遅いのはサーバーがイマイチだからかな…

この機能追加はReact+Reduxの処理階層を知っていれば全然難しくない。まずハッシュタグ入力欄と、そこへの入力を処理するaction, reducer, stateを作る(全部compose-formのコピー)。さらにCtrl+Enterによるトゥートを処理するhandleKeyDownにShift+Enterによって発火する別ルートのトゥート投稿処理を追加する。これもトゥートボタンによって発火する処理をほとんどコピー。そのルートの最後にあるのがこれ。

const status = getState().getIn(['compose', 'text'], '') + ' ' + getState().getIn(['compose', 'preservedHashtag']);

これだけが実質的に意味のあるコードだ。興味のある方はコミットログをどうぞ。

1年前のドワンゴインターンではJavaScriptが全然わからず(わからなかったのはJavaScriptだけではないが)チームメンバーに教えてもらっていたが、今では自力で触れるようになった。

over the touge

※この記事は『福島産 あかつき桃直搾り』を飲んで書かれた。

昨夜から今朝にかけて徹夜したので今日は絶対大学に行くまいと思っていたが、いろいろあって行った。今取り組んでる作業はあとちょっと直すだけ。

先週の土日は大学に来ていたので今週はゆっくり休みたい。そういえば台風が来るらしい。休日に家にいるぶんには、天気は荒れてくれたほうがなんとなくワクワクする。

Hyperappでストップウォッチを作りたかったのでググったらこれがヒットしたんだが、app関数にeventsなる引数を渡している。こんなのあったかなと思ったらこのページの公開版では変わっていて

const main = app(state, actions, view, document.body)
setInterval(main.tick, 1000)

となっている。appの戻り値を利用するのはappのactionsを外部から呼び出す正しい方法だ。公式サイトにも書かれている

よく知らないが、昔はHyperappにそういう仕様があったのだろうか。

ニコニコするためにニコニコしてるのでニコニコできないアレはアレしようというアレを作った

niconico-nonpolitical

正味30分くらいで作った。目的と機能は日記タイトルの通り。インターネットにおいて見たくないものを見ないことは重要だ。これが上手くできないと人類は絶滅する。HTMLCollectionを配列に変換して使う(ES2015+)これやろうと思ったんだけどunexpected tokenとか言われてできなかった。なんでだろう。代わりに集合を配列に変換する方法をやった。jQuery使わなかったのはなんとなく、意地で。

今日は3人分実験をした。データは必ずしも予想通りではないが、概ね意図した通りの実験操作は行えているようだ。アドバイスをもらって改善点もはっきりした。調子は悪くない。

未来のミライをもう一度見に行きたい。あと野菜を摂取したい。

be caught in the rain

毎週土曜はコインランドリー、そして日記もいつもコインランドリーのことを書いていてマンネリを感じないでもない。

今日はコインランドリーから帰るときに雨に降られた。といってもコインランドリーは自宅から290m徒歩3分なのでどうということはない。洗濯物も軽く乾燥して自宅で干すので多少濡れても問題ない。

雨に降られて道を走っていると、自分がその場所にいるということを強く感じる。考え事をしながらだとかツイッターを見ながら道を歩いていてもそういうことは感じないのだが、雨に降られていると早く家に帰りたいとか木の下を走ろうとか考えるので、場所や空間のことを強く意識するのだと思う。

僕はときおり、道に寝転がりたいと思う。夏の夜にコンクリートはひんやりして気持ちよさそうだと思ったり、コンクリートはどういう触感なのか気になったり、はたまた単に疲れていたり、いろいろな理由がある。しかし実際にやったことはない。小学生のころは平気で道に座って寝転がったりしただろうが、大学生になってからはない。なんどか本気で試みたのだが、ついにできなかった。誰かが見ているかもしれないとか、道は公共の場所なのでそんなことをすべきでないとか、いろいろと理由をつけてはいるが、事実として僕は道に寝転がることができない。

子供の頃は自分はなんでもわかっているつもりだったし、自分を子供扱いする大人に苛立ったりもした。そして大人になればもっと自由になれると思っていた。しかし法律的・身体的には間違いなく大人になった今、僕は「子供はものをわかっていない」と思っているし、道に寝転がる自由を失った。

ところでHyperappで2つのactionを連鎖的に呼び出したいとき、具体的にはinputへの入力をstate.onePropertyに反映しつつ、さらにその新しいstate.onePropertyに基づいてstate.anotherPropertyを再計算したいとき、どういう風に書くのが美しいのだろうか。

現状こんな風に書いているが、ひとつの関数で2つの作業をしており、美しくない。2つめ(4行目)の操作を他の場所でも使いたいときに、2つの作業を別々の関数にしておいたほうが便利だ。そう素朴に考えたのだが、

これは上手くいかない。値を入力しても即座に元の値に戻ってしまう。多分Hyperappから呼ばれるupdateにはstateが渡されるが、updateから呼ばれるupdateInputやreCalculateにはstateが渡されていない。

こうすると望み通りの動作をするが、actionsの中に形式の違う関数が混ざっていていいのかどうか疑問がある。別の場所にhelperみたいなオブジェクトを作ってそこにしまっておきたい気がする。

Hyperappは書きやすい。楽だ。しかし「どう書くべきか」というノウハウが見つからない。自由は苦痛だ。自由を捨てよ。