謹賀新年/2017目標
あけましておめでとうございます
昨年度仲良くして下さった皆様、ありがとうございました。
本年もよろしくお願いします。
昨年の良かったこと
- プログラミング方面
- 暮らし
- 引越し先候補を幾つか下見できた事。
- 荷物減らしが進んで、部屋のレイアウトを変更できた事。
- (人生3度めにしてやっと)メガネからコンタクトへの移行が出来た事。
昨年の反省点
- 俺々言語の実験成果を公開できるレベルにまとめられなかった事。 普通の lisp を作るだけならそう難しくないが、 そこから離れた独自の意味論を作る所をどう実験していくかが今の課題。
- 結局、引越し先を決めるに至らなかった事。(探す方向性を変える必要があると気付けたのは収穫)
要するに 昨年の目標 と見比べて ほぼ進展が無いこと(><
今年の目標
- 引っ越ししたい
- 俺々言語に進捗を
- fsharp 勉強しなきゃ… docker もそろそろ…
- 彼女(嫁)探しを諦めない…
Smalltalk の勉強会に参加してきました(ハッカソン編)
私にとって Smalltalk は学生時代から憧れの言語で、にもかかわらず何度挑戦しても (Emacs keybind が使えないがゆえに) 挫折を繰り返していた言語です。何とか突破口を開けられないかと参加させてもらいました。
以下、教えて頂いたこと・調べたことの備忘録です。間違いなど有るかもしれませんのでツッコミ歓迎です。
ハッカソン(午前)
私は Smalltalk 初心者なので、Pharo5 のキーボード・マッピング周りの仕組みを調べて学ぶことにしました。
途中、梅澤さん mumez (Masashi Umezawa) · GitHub に Pharo のショートカット周りのクラスやそのオーバーライド方法、 クラスブラウザの操作方法を色々教えて頂きました。
PharoShortcuts current
で取り出されるインスタンスを通して、ショートカットが設定されているらしいので、ここをオーバーライドすれば出来そう、とのこと。(ただ、そのために PharoShortcuts クラス自体もいじらなければならない。)- この使用箇所を探すとき、クラスブラウザ上でクラスを選んで右クリック→
Analyze
→Class refs...
が役に立つことを見せて頂きました。 - インスタンス変数は大文字はじまり、と。
- この使用箇所を探すとき、クラスブラウザ上でクラスを選んで右クリック→
- (Web ブラウザの開発ツールに有るような) マウスで画面要素を直接指して中身を Inspect したい時は、
Shift + Mouse Middle
で Halo を呼びだせば良いそう。
雑談
お昼ごはんの時にも雑談で色々教えて頂きました。
- イベントループはどこに有るの? →
WorldState
にあるよ - Pharo にも Object Table は有るの? → ある。 Newspeak, Pharo, Squeak は VM (の設計?) が同じ
allInstance
の逆はあるの? →allOwners
というのがある。(Morph のみ?)- バージョン管理機能があると聞いたけど、 CompiledMethod はイメージ内に複数持つの?一つだけ? → 一つだけ。
あと、皆さん pharo を一番使ってたのが印象的でした。 pharo のコア開発者はフランス inria 繋がりの人が多いとか…
<keymap>
は Pragma だった!
以前の挫折ポイントの一つが、この↓ <keymap>
TxTextEditorMorph>>#buildTextEditorKeymapsOn: aBuilder <keymap> { Character home. #moveToLineStart. Character home shift. #selectToLineStart. ...
これは Pharo の Pragma 構文で、所謂 コード注記 と同じ役割を果たしているそうです。 (メソッドに属性としてぶら下がる)。 Pharo は Pragma を色々活用しているとのこと。
ハッカソン (午後)
ところが PharoShortcuts
の中身をよく見たところ、肝心のカーソル移動が定義されていないことに気づきました。
これでは Emacs 風のカーソル移動は定義できません。
そこで方針を変えて、そもそもキーマップ機能と、イベントループ周りがどんな仕組みになっているのかを調べることにしました。
キーマップ関連
TxTextEditorMorph>>#initializeShortcuts: aKMDispatcher aKMDispatcher attachCategory: #TxTextEditorMorph
KMDispatcher というのが関係が深そう…
クラスのコメントを順々に抜き書きしてみます。
KMDispatch
I'm an object that saves a buffer of keyevents for the morph I'm attached. I am the one that dispatches the single and multiple shortcuts. If the morph has a keymap that matches the keyboard event, I tell the keymap event to execute with the morph I'm attached.
KMRepository
I have a singleton instance which can be accessed by executing the following: "self default" I am currently a god object to be refactored =D.
KMRepository>>#reset World setProperty: #kmDispatcher toValue: nil. self default: self new. KMCategory allSubclasses select: [ :c | c is GlobalCategory ] thenDo: [ :c | c new installAsGlobalCategory ]. KMPragmaKeymapBuilder uniqueInstance reset.
KMPragmaKeymapBuilder
I am a singleton object, subscribed to system events, to listen to the creation of methods marked with the <keymap> and keymap:> pragmas. When I listen one of those events, I reinitialize the KMRepository default instance and reload it with all declared keymaps.
う〜ん、らちがあかない…
イベントループ
下から追うのが難しそうなので、今度はイベントループを調べてみます。
教えて頂いた WorldState
と、グローバル変数 World
(こちらは WorldMorph
のインスタンス) が関係が深そう。
WorldMorph>>#doOneCycle worldState doOneCycleFor: self. WorldState>>#doOneCycleFor: aWorld self interCyclePause: MinCycleLapse. self doOneCycleNowFor: aWorld.
WorldState>>#doOneCycleNowFor: aWorld "Immediately do one cycle of the interaction loop. This should not be called directly, but only via doOneCycleFor:" DisplayScreen checkForNewScreenSize. "process user input events" LastCycleTime := Time millisecondClockValue. self handsDo: [:h | ActiveHand := h. h processEvents. "…ここが肝ぽい…" ActiveHand := nil ]. "the default is the primary hand" ActiveHand := self hands first. aWorld runStepMethods. "there are currently some variations here" self displayWorldSafely: aWorld.
displayWorldSafely: aWorld "Update this world's display and keep track of errors during draw methods." [aWorld displayWorld] ifError: [:err :rcvr | "Handle a drawing error" | errCtx errMorph | errCtx := thisContext. [ errCtx := errCtx sender. .... "If the morph causing the problem has already the #drawError flag set, then search for the next morph above in the caller chain." errMorph hasProperty: #errorOnDraw ] whileTrue. errMorph setProperty: #errorOnDraw toValue: true. "Install the old error handler, so we can re-raise the error" rcvr error: err. ].
↑今読み返すと WorldState>>#doOneCycleNowFor: aWorld
の中の ActiveHand processEvent
が鍵ぽいのですが、
この時点では読み取れませんでした。
キー入力周り
再び下から、でも目線を変えてキー入力に関係するコードを探してみようと考えました。
Smalltalk なので、メタキーを扱うコードが有るはず… #meta
の sender を見る…
→ SimulateKeystrokesSpecification>>#testSimulateCmdKeystroke
の中に self simulateKeyStrokes: ...
というコードを発見。
Morph>>#simulateKeyStroke: aCharacter |event| event := KeyboardEvent new setType: #keystroke buttons: 0 position: 0@0 keyValue: aCharacter charCode charCode: aCharacter charCode hand: ActiveHand stamp: 0. self keyStroke: event
KeyboardEvent
クラス! この Class ref から、 HandMorph>>#generateKeyboardEvent
を見つけました。
後はこれの sender を探すのみ。
HandMorph>>#processEvents "Process user input events from the local input devices." | evt evtBuf type hadAny | [(evtBuf := Sensor nextEvent) isNil] whileFalse: [evt := nil. "for unknown event types" type := evtBuf first. type = EventTypeMouse ifTrue: [recentModifiers := evtBuf sixth. evt := self generateMouseEvent: evtBuf]. type = EventTypeKeyboard ifTrue: [recentModifiers := evtBuf fifth. evt := self generateKeyboardEvent: evtBuf]. type = EventTypeDragDropFiles ifTrue: [evt := self generateDropFilesEvent: evtBuf]. type = EventTypeWindow ifTrue: [evt := self generateWindowEvent: evtBuf]. "All other events are ignored" (type ~= EventTypeDragDropFiles and: [evt isNil]) ifTrue: [^self]. evt isNil ifFalse: ["Finally, handle it" self handleEvent: evt. "多分ここで、 HandMorph>>#handleEvent:evt が呼ばれる" hadAny := true. ...]]. ...
そして HandMorph>>#handleEvent:anEvent
が呼ばれる、のではないか…
今日たどり着いたのはここまで!
(でもキーマッピングの話はまだ遠いにょ…)
おしまい
これからビールを飲みながら勉強会です。
zparseopts で posix style long option と一文字オプションを両立させる
Zsh の zparseopts を使って
-t TYPE
--type TYPE
--type=TYPE
全部の書き方をサポートしたい場合にどう書くか。 (代入先の配列名を同じにするだけ、だけど)
値の取り出しの書き方を忘れがちなので、メモ。
(我流なので、ツッコミ歓迎です)
zparseopts がどう働くか
% set -- -t foo % zparseopts -D -K h=o_help t:=o_type % typeset o_type o_type=( -t foo ) %
% set -- --type foobar % zparseopts -D -K h=o_help t:=o_type -type:=o_type % typeset o_type o_type=( --type foobar ) %
% set -- --type=foobar % zparseopts -D -K h=o_help t:=o_type -type:=o_type % typeset o_type o_type=( --type '=foobar' ) %
オプションの検査
配列のサイズを見るのが、良いのではないかと…
if (($#o_type)); then # …オプションが指定されている時の処理… fi
値の取り出し
値の先頭が = で始まる =なんとか
みたいな文字列を渡すことを諦めれば
↓この書き方で行ける。
% print -- $o_type[2] =foobar % print -- ${${o_type[2]}#=} foobar %
.oO(…もっと短く覚えやすい書き方があれば、是非教えて下さい…)
YAP(achimon)C::Asia Hachioji 2016 にボランティア参加してきました
yapcasia8oji-2016mid.hachiojipm.org
最初は予定が合わなくて諦めてたけれど、自分の予定が変わったタイミングで ボランティア足りないって話を聞いたので、思い切ってお手伝いさせてもらいました。
担当は A部屋の第3の司会(交代制)でした。とはいえ喉の調子が悪かったので、 二日目は部屋内遊撃みたいな役目にさせてもらってました。
(…失礼がなかったか、内心ドキドキしています…)
全体感想
開催中にスタッフのある人が『yapc は良いよな、ここで笑いが出るもの…他だと笑ってくんないんだぜ…(意訳)』 と言っていたのが、私にも同感で…この陽気さ・笑いで解決する文化というか、血脈みたいなものこそが、 yapc が培ってきてここに受け継がれたものなんだろうな、などと思いました。
それにしてもよい会場でした… Microsoft さん、ありがとうございました。
トーク感想
どのトークも面白かったのですが、全部は書けそうにないので、3つだけ…発表順で。
pastak さん
Browser 拡張は私もいつか再挑戦したくて…現在の状況がよく分かって、とても有益でした。
ytnobodyさん
http://blog.ytnobody.net/entry/2016-07-04-10-33-02.htmlblog.ytnobody.net
チーム作りと、経営層の巻き込み方の所が、凄いなぁと脱帽しました。 (野村再生工場を連想したり…)
どの項目もサラッと書いてましたけど、実行するのは大変だったはず…
しんぺい a.k.a. 猫型蓄音機さん
MVC 的なものづくり、私も悩んできたし、悩みすぎて テンプレートエンジン+Webフレームワークを作っちゃう タイプなので、 非常に勉強になりました。 『Presentation とそれ以外を分けることこそが肝心なんだ!(意訳)』 って主張とか、 『Model の小分けの仕方はケースバイケース!(意訳)』 って話は、とても納得が行きました。 (とはいえ私の書いてるコードがしんぺいさんの考える適切さの範囲に該当するのかは、なんともですが…><)
最後に
楽しかった!
とある方のブログでみたスクリプトが、なぜ暴走したのかについて
Twitter で流れてきたリンクで、Perl を勉強中の方のブログが目に止まりました。
読んでいて気付いた点があったので、それについて書いてみます。 (最初はコメントで書いていたら文字数制限で途切れてしまったので… 途切れるなら字数制限の警告が欲しい…)
id:note103 様、はじめまして
id:note103 様、はじめまして、興味深く読ませて頂きました。
上記の現象のうち、 Perl 関連の部分について、多分こうではないか?と気付いた所があるので書かせて下さい。
なぜこのスクリプトは暴走したのか
第一に、 Sample.pm の中に間違って init();
が書かれた状態で何が起きるかです。
この場合、 単に use や require で他のスクリプトから読み込んだだけで Sample::init() の実行が始まる
ことになります。
このことは以下のようにして確認できます。
perl -e 'require Sample'
第二に、状況からの推測ですが、 MacVim の syntastic (perl の構文間違いの自動検査) が呼び出した perl -wc main.pl
の中で Sample.pm が読み込まれるので、そこで Sample::init() が呼ばれて入力待ちが発生。 syntastic が応答しない→ MacVim も固まる、となったのではないかと。
ここから先は、ご自身で書いておられる通り、 "具体的には最後のelse文の中で同じサブルーチンを呼び出しているのが悪手" となり、無限に再帰呼出しを行う状況だったのではないかと。
試しに
perl -we 'use Sample' </dev/null
と端末で打ってみると、無限ループが再現できるはずです。
(端末からなら ^C
で停止させることが出来ます。)
あと、この Sample::init で使っている
chomp($bar = <STDIN>);
は、perl の普通の入力待ちループ
while ($bar = <STDIN>) {...}
と違って defined 検査が足りていないため、 eof が来ても停止しない、という点も、無限ループになった要因の一つですね。
ではこの辺りで失礼します〜
実験: SQLite の `in (...)` 句を *雑に* zsh の配列展開で生成してみる
はじめに
値に single quote (') が入らない保証が有る場合
% values=( foo bar baz ) % print " in (${(j/,/)"${(@qq)values}"})" in ('foo','bar','baz') %
こっちは割と、仕事で使ってます。
解説
- ここでは配列変数 values に値を格納
@qq
は配列の要素ごとに qq (single quote で囲む) を適用- それを一旦 " " で囲むことで、
"$@"
と同じ効果を出す
- それを一旦 " " で囲むことで、
j/,/
は配列を,
で join.
値に single quote も入る可能性が有る場合
qq フラグで自動 quote させる場合、文字列中の single quote は '\''
という文字列に置換される
% foo="Foo's Bar" % print -r ${(qq)foo} 'Foo'\''s Bar' %
これを ''
に置き換えれば行けるのではないか…
% values=(foo bar "Foo's Bar") % print -r "in (${${(j/, /)${(@qq)values}}//'\''/''})" in ('foo', 'bar', 'Foo''s Bar') %
出来た気がする…
追記2018-05-08+:配列じゃなくてスカラーの場合の書き方、コピペ用
実務でよく使うようになったので、これも。
% foo="Foo's Bar" % print -r "${${(qq)foo}//'\''/''}" 'Foo''s Bar' %
関数にまとめるとこうかしら?
function zqsql { local val=$1 print -nr "${${(qq)val}//'\''/''}" }
[linux]作業メモ:luks で暗号化した EFI ベースの notepc で HDD を換装した際の作業記録
単なる自分メモ。
1. GParted で GPT で partitioning
- EFI System Parition を作る。 (sdb1)
- サイズは 384MB にしてみた
- format 実行するまでは boot フラグが立てられなかった? 気のせい?
- フラグを立てる画面に esp フラグもあるので、これを立てる
- /boot も作る (sdb2)
- 最後の一つを unformated で確保 (sdb3)
2. /boot/efi をベタコピー
mount /dev/sdb1 /mnt/tmp
cp -va /boot/efi/* /mnt/tmp
umount /mnt/tmp
3. /boot をベタコピー
mount /dev/sdb2 /mnt/tmp rsync -av -x -A -X /boot/ /mnt/tmp umount
- pax -r -w -X -pe だと何かエラー出た。 selinux?
4. luks
cryptsetup luksFormat /dev/sdb3
cryptsetup luksOpen /dev/sdb3 newsecure
pvcreate /dev/mapper/newsecure
vgcreate vghk16 /dev/mapper/newsecure
vgchange -ay vghk16
5. (今回は lv の統合も行う)
mkdir /mnt/srcimg lv=/dev/vghk15/root snap=snap-$lv:t lvcreate --snapshot --name $snap -L2G $lv mount -r /dev/vghk15/$snap /mnt/srcimg function lvsnap {lv=$1; snap=snap-$lv:t; lvcreate --snapshot --name $snap -L2G $lv} lvsnap /dev/vghk15/var mount -r /dev/vghk15/$snap /mnt/srcimg/var lvsnap /dev/vghk15/libvirt_images mount -r /dev/vghk15/$snap /mnt/srcimg/var/lib/libvirt/images mkdir /mnt/destimg mkfs.ext4 -m 1 /dev/vghk16/root mount /dev/vghk16/root /mnt/destimg lvcreate --name var.log --size 8G /dev/vghk16 mkfs.ext4 -m 1 /dev/vghk16/var.log mkdir -p /mnt/destimg/var/log mount /dev/vghk16/var.log /mnt/destimg/var/log time rsync -a -A -X /mnt/srcimg/ /mnt/destimg umount /dev/vghk15/snap-libvirt_images /dev/vghk15/snap-var /dev/vghk15/snap-root lvremove -f /dev/vghk15/snap-libvirt_images /dev/vghk15/snap-var /dev/vghk15/snap-root time hktools/sysadm/lvsnapbackup.zsh /dev/vghk16/ /dev/vghk15/home /dev/vghk15/*.hkoba
… snapshot 作成と mount は一つの関数にまとめるべきだった…読みづらい…
6. lvm vg name と luks の uuid 更新.
前回のメモ>
fedora のディスク暗号化をやり直す場合のメモ。
— hkoba (@hkoba) August 25, 2014
lv を restore したら /etc/crypttab と /etc/default/grub の luks 行を書き換えて、 grub2-mkconfig で grub.cfg を作り直す
今回も grub2-mkconfig 使うべき所を変に気を回して失敗した。
以下は本来こうすべきだったはず!という事後の想像>
volume group 名の変化への対処
HDD 引越しで Fedora が起動しなくなるのは大抵 fstab の書き損じ。
- 最後に chroot して mount -a 通るまで確認するべきだった。
- lv を削ったので fstab 編集は必須
/boot
と/boot/efi
については/dev/sda1
とかに書き換える方法だと chroot からの mount -a での確認が出来ない (この時点では sdb1 とかだから)。 だから真面目に uuid の置き換えをやるべきだった。
- 一度やり直しが発生したせいで、fstab の確認が甘くなった。 (こういう再演をもっと確実にこなすには…?)
files=(/etc/fstab /etc/default/grub) sed -i -e "s/vghk15/vghk16/g" /mnt/destimg$^files vim /mnt/destimg/etc/fstab
luks uuid の変化への対処
files=(/etc/crypttab /etc/default/grub) read vol olduuid rest < /etc/crypttab newuuid=$(cryptsetup luksUUID /dev/sdb3) sed -i -e "s/$olduuid[6,-1]/$newuuid/g" /mnt/destimg$^files
7. chroot して、 dracut
mount -t proc none /mnt/destimg/proc mount -t sysfs none /mnt/destimg/sys mount -t devtmpfs none /mnt/destimg/dev chroot /mnt/destimg
chroot 内での作業
mount -a が上手く行くか確認し、大丈夫なら initramfs と grub2-efi.cfg を生成し直す。
mount -a dracut --force # 確認 lsinitrd -f etc/crypttab grub2-mkconfig -o /etc/grub2-efi.cfg exit
…余談…
この時作った chroot 空間の中で zsh の行編集の一部 (Ctrl キーと alphabet の組み合わせだけ)が 無効になってて…これは何が原因なのか、どなたかご存知でしたら是非ツッコんで下され〜
8. umount
umount /mnt/destimg/boot/efi /mnt/destimg/boot umount /mnt/destimg/{proc,sys,dev} umount /mnt/destimg grep sdb /proc/mounts
で、後は物理交換して再起動するだけ(のはずだった…次こそは一発でやりとげたいなぁ…)
結末
よし、新 HDD で desktop までたどり着いた!
— hkoba (@hkoba) April 10, 2016
% sudo vgs
— hkoba (@hkoba) April 10, 2016
VG #PV #LV #SN Attr VSize VFree
vghk16 1 10 0 wz--n- 930.13g 624.13g
%
ディスクにも余裕出来たし、めでたし。
.oO(…いっそ systemd が top 的な物まで取り込んでくれたら、心穏やかに boot を見守れるようになるのかもしれん…)
— hkoba (@hkoba) April 10, 2016
@hkoba はじめての systemctl enable debug-shell .
— hkoba (@hkoba) April 10, 2016
起動時に top 取れて幸せ。
なんだ setfiles(8) くんが時間掛かってたのか~(白目
追記. 更に後日談
/var/log
を新たに lv として分けてあったのに、 fstab に書き忘れてて全然活かせてなかったと後で気付いた。
これも最初は正しいつもりの fstab を書き上げた後で、手戻りが発生したことで抜けになったケース。
そう言えば、増やした lv の fstab への書き忘れは mount -a でも検出できないなぁ…
折角 /etc を git で管理してあるのだから、一旦 git diff
で変更を保存しておいて、
後で git apply
すれば良かったと、今更ながら思う。