2015年 10月 14日

リファレンスマニュアルをインクリメンタル検索するやつを Electron で実装した

https://github.com/cho45/Chemrtron

機能

  • インデックス用のクローラ
  • 作ったインデックスのインクリメンタル検索と表示

できるだけ雑にインデックス作成用のクローラを実装できるようにしたかったので、そのようになっている。

オフライン閲覧はあんまり考慮してないが、file:// でインデックス登録すればオフラインでも使えると思う (ネットワークよりもディスクサイズのほうが厳しいのでオフラインにあまり興味がない…)

動かしかた

レポジトリをクローンする場合 electron-prebuilt が必要。

npm -g install electron-prebuilt
git clone https://github.com/cho45/Chemrtron.git
cd Chemrtron
electron .

または https://github.com/cho45/Chemrtron/releases のページから .dmg を落としてくる。うまく動くかわからないが、こちらはランタイムを全て含むので electron-prebuilt や npm などは不要。

インデクサの選択

歯車アイコンまたはメニューの Preferences… から設定画面を開くと選択できる。

まだ並べかえを実装していないので、オンにした順に並ぶ。

インデクサの実装

マニュアル単位でインデクサを実装する必要がある。主要なものは実装済みでレポジトリに入れてあるが不完全かもしれない。対応済みの一覧

だいたいの場合 HTML で全メソッド/クラスへのリンクが張ってあるページがマニュアルに存在しているので、そのページをとってきて querySelectorAll とかで雑にリンク抽出すれば十分なインデックスをつくれる。

インデクサのコードは非表示の別ウィンドウで実行されるので、ある程度重い処理でブロックしても問題ない。

インデックスの内容

インデックスといっても転置インデックスではなく、検索対象文字列の一覧を正規表現でマッチをかけているだけである。

リファレンスマニュアルのようなものの検索の場合フルテキストサーチよりも、ある程度一貫性のある文字列を検索させたほうが余計なものがヒットしないので気持ちがいいと思う。

例えば Array.prototype.slice みたいなページを表示したいとき、arr sli とかだけでいいようにしたい。既に行きたいページが明確なので雑なクエリで確実に辿りつきたい。

インデクサの書きかた

https://github.com/cho45/Chemrtron/blob/master/indexers/nodejs.js

あたりを参考にして雑に書くと動く。もし動かない場合、View → Toggle Developer Tools とするか、設定から Developer Mode をオンにすると console と、インデクサ用のウィンドウが表示させるのでデバッグ可能になる。

~/.chemr/indexers/ に置いても読むようになっている。

おすすめのインデックス

MDN (Mozilla Developer Network) は HTML, CSS, JavaScript を横断して検索でき、ブラウザごとの互換情報とか、ポリフィル方法 (実装概略) とかも載っていて、とりあえずウェブ系ならこれを検索しとけば良い感じで便利。

で、Dash で良くない?

クローラを内蔵していて、雑にインデックスを作るのが楽という方向性を目指しています。

今後

せっかくなので Windows 版を作ろうとしたがうまくいってない。

バックグラウンドで自動更新するようにしたい。

経緯

昔 Chemr というリファレンスマニュアルをインクリメンタルサーチするアプリケーションを書いていた。最初の Chemr は HTML Help を読め RubyCocoa で実装していた。次はFirefox + Greasemonkey 上で動くユーザスクリプトとして実装した。そして Electron が流行ってきたので Electron 上で動くように実装しなおした。

2015年 10月 12日

諏訪大社

なんとなく行きたくなったので、諏訪大社にいってきた。諏訪大社は2社4宮に分かれて点在していて、それぞれが結構離れている。上社と下社は電車で、ほかは徒歩で移動したがかなり疲れた。

上社 前宮






道中

上社 本宮




下社 秋宮




道中

かなり高低差がある。この神社は上から見たのみで行かず

春宮と秋宮で建築技術を競ったらしいので名残りかな?



下社 春宮



仁科神明宮

諏訪大社に続き、仁科神明宮にも行ってきた。諏訪からは同じ長野県内ではあるがかなり離れており、駅からも30分ぐらい歩く。

現存する神明造社殿では最古で、本殿が国宝に指定されている。

神社はどの神社も式年遷宮で造りなおされる傾向があり古いものがそのまま残っているケースが少ない。この神社も300年前までは建て替えをしていたみたいだけど、その後は修繕をやって残っているらしい。

ちなみに神明造りに限らなければ、現存最古の神社は京都の宇治上神社で、こちらも国宝になっている (なおかつ京都の世界遺産を構成する1つ)。宇治上神社は5年前に行った











2015年 10月 08日

もう僕らは OpenGL ライブラリにリンクするビルドに悩むことはない

WebGL があるからね。ブラウザが業を背負ってくれるのだよ。

https://github.com/cho45/go-KX3-panadapter

KX3 (無線機) 用の panadapter (広域スペクトラムスコープ) の実装を WebGL でレンダリングするように変えた。

経緯

これまで go-gl を使って頑張っていたが、いつのまにか go-gl の構成が変更され、ビルドができなくなってしまった。

go には依存パッケージのバージョン指定を行う方法がないので (ないよね?) 最新に追従する以外の選択がないのだが、いきなりビルドが通らなくなるみたいな事態がおこるともうやる気がしない。

継続的にメンテするほどの変更は入れてないが「ときどき実用しているアプリケーション」が割とどうでもいい理由で壊れるととにかくやる気が失せる。なので、できるだけ壊れなそうなものに依存するようにしたい。

その点ウェブ技術に依存しておけば、あまりひどい非互換は入らないことが期待できるし、最悪壊れてもググれば非互換情報が見つかりやすく、対処しやすい。そしてそもそも JS で書くのでビルドできないような事態にはならない。

構成の変更

前のバージョンでは go-gl を使い、go で書いたプロセスで直接ウィンドウを作ってレンダリングしていたが、構成の変更により、go で書く部分は portaudio を使って任意のサンプリング周波数で信号のFFTを行い、WebSocket からストリームで投げ続けるというシンプルな動作を行うようになった。(44.1kHz 固定なら WebAudio + WebWorker でできそうだが、すくなくとも 96kHz サンプリングはしたいので WebAudio はつかってない)

ブラウザ側のJavaScriptでgoプロセスへ WebSocket の接続を行い、データを受信し次第 WebGL を使ってレンダリングを行う。

これにより go の部分の cgo 依存は portaudio のみになった。portaudio は非常に薄いラッパーなので将来非互換が入るような余地がほぼないと思われる。安心

備考

別に go に限ったはなしではなく、ビルドができるできないとか依存がどうとか、とにかくダルイ。やらなくてすむことはやらないようにしよう。

2015年 10月 06日

拡張子のないファイルに一括で拡張子を付与する

rename コマンドで可能だぞ。rename コマンドは Perl の式でファイル名を置換可能だ!

「拡張子のないファイル」にマッチするシェルのglob表現は簡単ではないし、シェルスクリプトの for 文の文法はだいたいいつも忘れている。rename コマンドは Perl の正規表現という大変慣れたものを使え、sed や awk などと比べても安心感がある。

rename -v -n 's/^([^.]+)$/$1.txt/' *

置換が行われなかった場合リネームは行われない。-n はドライランなので実際に実行するときは外す。-v は verbose オプションで、つけておいたほうがいい。

この正規表現では . を含まないファイル名にマッチさせ、.txt をファイル名にあとに追加している。

備考

Ubuntu の wiki によると

UNIXにこのコマンドがないこともあって余り知られていませんが、どのLinuxにも含まれています。

https://wiki.ubuntulinux.jp/UbuntuTips/FileHandling/RenameCommand

らしいが、本当のところどうなのかよくわからないぞ! すくなくとも Ubuntu では使用可能だ! なお OS X には含まれていない。

OS X では brew install rename で入るが、これは Ubuntu のパッケージのものとはまた別のバージョンである。ただし高機能版であり、-v -n オプションは互換性がある (-n の longname は Ubuntu 版では no-act だが、homebrew で入るものは --dry-run または --just-print となっている)。

copyright

ライセンスはどちらも This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself. となっており Perl と同一 (Artistic License) のようだ。原版と同じ名称を使ってはいけないライセンスだった気がするが……

Ubuntu 版

# This script was developed by Robin Barker (Robin.Barker@npl.co.uk),
# from Larry Wall's original script eg/rename from the perl source.

homebrew 版

AUTHORS
Aristotle Pagaltzis

Idea, inspiration and original code from Larry Wall and Robin Barker.

となっており、Larry Wall (Original?) → Robin Barker (Ubuntu版) → Aristotle Pagaltzis (homebrew版) という感じで進化している雰囲気がある

2015年 10月 05日

2D 描画でも WebGL を使うべきか? スペクトラムウォーターフォール最速決定戦

上のように、スペクトラムのウォーターフォール表示ではよく下に1行追記して全体を上にスクロールさせていくみたいな見せかたをするが、全体の再描画が必須なため、かなり描画負荷が高い処理となる。

いくつか実装を書いてどのぐらい差がでるかを検証してみた。

毎回 canvas の内容を全部描く

http://cho45.stfuawsc.com/spectrum-performance/canvas-redraw-whole/

		ctx.putImageData(
			ctx.getImageData(0, 1, canvas.width, canvas.height - 1),
			0, 0
		);

上のようなコードで canvas 全体を 1px ずらして、最後の一行に新しいデータによる putImageData() をさらに行う。

ピクセルデータを直接シフトさせるやりかただと、一番ナイーブで実装が簡単だが実際のところかなり遅い。

35ms/render ぐらい。

2枚の canvas とっかえひっかえ追記で塗りつつ、DOM 的にエレメントを移動する

http://cho45.stfuawsc.com/spectrum-performance/canvas-double-dom/

canvas の 描画自体は1px * width だけを常に上書きする形で行い、全体のスクロールは DOM でずらす (ブラウザに再描画をやらせる)

わかりにくいので動画にするとこんな感じで、2枚の canvas 要素を margin で使って動かして、親要素で表示領域を制限 (overflow: hidden) してる。

4ms/render

WebGL でテクスチャ2枚をとっかえひっかえし、シェーダーでスクロールする

http://cho45.stfuawsc.com/spectrum-performance/webgl-double-textures/

2枚 canvas とやっていることはほぼ同じだが、canvas の代わりに WebGL のテクスチャを2枚定義し、DOM の代わりにシェーダーを使う。

0.6ms/render

毎回 canvas の内容を全部描く (drawImage)


と言われて、drawImage! そういえばそんなのも! という感じだったので試したらこれは十分高速だった。

0.6ms/render で WebGL でやるのと変わらないぐらい。

肌感覚

canvas へ広範囲に putImageData の繰替えしをするより DOM で移動させたほうが圧倒的に早いのがおもしろかった。

WebGL は面倒くさい分たしかに高速で、2D でも可能な限り使ったほうがよさそうだけど、直接文字のレンダリングができないとか (canvas に書いてからテクスチャとして転送する必要がある)、API 的に面倒とか、GLSL というシェーダー言語を覚える必要があるとか、難点もある。

とはいえ、面倒なぶん自力でチューニング可能なポイントが多いのでおもしろい。

備考

もっと早くなる方法がありそうなら是非お知らせください。

https://github.com/cho45/spectrum-performance

CNC フライス制御用インターフェイス GrblServer の紹介動画

だいたい作ってやる気がなくなってきたので動画にいちおうまとめた。

2015年 10月 04日

CSS Animation Sine Wave

http://cho45.stfuawsc.com/misc/css3-sine-wave.html

CSS 自体では自由な曲線は描くことができないが、CSS animation では、animation-timing-function で cubic-bezier() を使い定義したベジェ曲線に従ってプロパティーの変化量を決めることができる。

なので、複数の animation する要素を組合せることで、全体としてサイン波を描くことができる。

ポイントは animation-timing-function はキーフレーム間 (1回のアニメーション全体ではない) に適用される点で、勘違いしているとひたすらハマる。


上記の例ではアニメーションさせたままだが、animation-delay に負の値を指定して animation-play-state: paused; を指定すれば止めた状態にもできる。

http://cho45.stfuawsc.com/misc/css3-sine-wave2.html

DOM の KeyBoardEvent の e.keyCode とか e.which とかを文字列としてとりたいやつ

昔 keyString.js という KeyBoardEvent からなんとなく押されたキーの文字列表記になおすやつを書いたことがある。

しかしこれは実装が不完全で一部のキーがちゃんと判定されなかったりした。が、マルチプラットフォーム・マルチブラウザで検証するような気力はないし、そんなことしても無駄になるのは目に見えているのでやる気はおきない。

KeyBoardEvent.key

KeyBoardEvent に key というプロパティが DOM Level 3 Events ではできることになっていて、これは Enter キーの場合 "Enter" という文字列が入り、物理的なキー位置(ということになっている謎の数値)ではなく、論理的なキーを表現するということになっている。が、全てのブラウザで同じように実装されているとはいえない。

ということで KeyBoardEvent.key には polyfill をつかおう。

https://github.com/inexorabletash/polyfill/blob/master/keyboard.js

を読みこむだけでいい。完璧ではないがおそらく現時点で一番まともだと思う。このファイルにはライセンスが書いてないが polyfill 全体で Public Domain となっており適当に扱っても問題ない。

KeyBoardEvent.key を直接判定に利用するには問題がある

KeyBoardEvent.key は modifierKey (シフトキーとか) の状態は当然含んでいないので、単に

if (e.key === 'Enter') {
}

で判定してしまうと、Shift+Enter や Alt+Enter なども同じもの扱いになってしまう。かといって

if (e.shiftKey && e.key === 'Enter') {
} else
if (e.altKey && e.key === 'Enter') {
} else
if (!e.shiftKey && !e.altKey && e.key === 'Enter') {
}

とか全部書くのは見通しが悪い。

ということでしかたなしに

var key = (e.altKey?"Alt-":"")+(e.ctrlKey?"Control-":"")+(e.metaKey?"Meta-":"")+(e.shiftKey?"Shift-":"")+e.key;   

みたいなのを1行書いて modifier key のプリフィックスをつけておくとやはり楽になる

if (key === 'Shift-Enter') {
} else
if (key === 'Alt-Enter') {
} else
if (key === 'Enter') {
}