重力に縋るな

千種夜羽です

技術同人誌を作ったり頒布したりしている話

技術同人誌というものを作っているので,ちょっとその話をしておこうと思います. 要はOtakuAssemblyの話です.今更ですけどね.

あ,この話はOtakuAssemblyをやることになった経緯とか執筆環境の話なので, そういう話が気になる人は読んで下さい.

そういうのいいから技術の話しろよというそこのアナタ!

COVID-19騒動で家で暇してるそこのアナタ!

アナタにピッタリの技術同人誌がなんと通販で買えちゃうんです!(ダイマ) otakuassembly.booth.pm

電子版も完備!汚染されていない生のPDFが手に入ります!

あなたとOtakuAssembly,
今すぐダウンロー
*1

※Vol.2の物理本は現在入荷待ちなのでしばらくお待ち下さい(3/17現在)

OtakuAssemblyとは

2019年の5月頃にできた技術同人誌サークルです. たしか第15回自作OSもくもく会にいた大学1年生のオタク3人(@sksat_tty,@PG_MANA_,@Cra2yPierr0t)が完全にその場のノリと勢いでやるぞと言って気が付いたらやることになっていた,みたいな経緯だったと思います.たぶん.

まあ実はそれより前に@PG_MANA_に「一緒に技術同人誌書かないか...?」と誘われていたんですが, その時は僕も書いてみたいと思ってるけれどネタも微妙だしノウハウもないし金もかかるし何も考えずに特攻するのは無理があるだろみたいな話をどっかのフードコートと改札前で延々と終電ギリギリまで話した覚えがあります. 結局,実際はあんまり何も考えずに特攻したのでなんとも言えないんですけどね. とはいえあれでやろう!となっても長続きしなかったんじゃないかなあとも思います.

じゃあなんで自作OSもくもく会で急にやろう!となったかというと, 久しぶりに会ったからこの話の続きみたいなことをしてたんですよねたぶん. ただ,この時は近くにいた@Mopp_jpさんが「"書いてみたい"って言ってる奴は書かないんですよ〜」と煽ってくれたんですよね. @Mopp_jpさんは技術書典5,6,7で個人出展している強い人で,これにはめちゃくちゃ説得力がありました. そして,いつもTwitterで「これやりたい」「やりてー」とか言ってロクに成したことが無い僕にはとても刺さりました. 今書いてても刺さりますね.やっていきたい.

ということで「とりあえずやってみよう!」という気持ちになり,@PG_MANA_とたまたまその場にいた@Cra2yPierr0tを捕まえて引き入れて「やるぞ!」ということになりました. 完全にノリと勢いです.

ここらへんの話は@PG_MANA_氏もブログに書いてますね. pg-mana.net

ノリと勢いってやつは凄くて,翌日にこんな募集ツイートをしてしまうんですよね.

このツイートが界隈内でまあまあ伸びたんですよね. 金銭面や合同誌のボリューム的に,1~3人増えたらうれしいな. あわよくば経験者が来てくれるとうれしいな,と思ってこんなツイートをしたんですが, 何がオタクに刺さったのか数時間でオタクが10人くらい集まりました.は?

実際は消失したり原稿を落としたりするオタクがいたんですが(これは予想通り*2 ), それでも8人残りました.は?

そんなこんなでなんとか技術書典7に初参加し,『OtakuAssembly Vol.1』を無事頒布することができました. その後も技術書典8に参加し,イベント自体は中止になってしまったものの『OtakuAssembly Vol.2』を作ることができました(BOOTHで売ってるので皆さん買って下さい.頼ムッ).

OtakuAssemblyを支える技術

さて,技術同人誌を作るとなると,執筆環境が重要になってきます(要出典).

OtakuAssemblyでは大体以下のようになっています.

Re:VIEWについて

Re:VIEWを使っているのは主に次のような理由からです. あと僕の趣味*3

  • 原稿・設定ファイルがテキストファイル → Gitで管理できる
  • Docker Imageがある → CIが回せる
  • 技術同人誌を作ることを考えて作られている
  • 学習コストが低い
  • (あんまりやりたくないけど)いざとなればLaTeXを弄ってどうとでもできる

特に最初の2つは大人数のオタクの原稿を管理するにあたってはマストだと思っています. 別に1人で作るならどうとでもできますし,そういう場合はどんなツールを使ってもいいと思います. WordでもAdobe系のツールでもいいでしょう. 執筆時点で体裁とかをあまり気にしないとかなら,Google Documentとかでもいいのかもしれません. 某satさんとかはそんなかんじでやってると聞いたことがあるような気がします.

しかし,OtakuAssemblyは執筆者2ケタの大規模サークル(?)です*4. そして執筆者が全員プログラマーでオタクなので, Wordじゃないと呼吸困難になって死ぬということも無いですし, Gitは使えると思っていいですし,Markdownなどにも慣れているでしょう. このような前提のもとでは,原稿をGitで管理することができるかというのはとても大きな利点となります.

まず,適当なリモートリポジトリを用意して,各自執筆したらcommitしてpushする,ということをするだけで,各位の進捗状況が簡単に確認できます. また,みんなcommitしとる,原稿書いとらんのお前だけができます.僕のことですが... あと,これは個人的にかなり重要だと思っているんですが,「家では書いたんすけど〜w」とか「PCが壊れちゃって〜w」が防止できます. まあ中高の部活の部誌と違ってOtakuAssemblyは原稿を書きたくて集まっている人たちなのでそんなことは無いと思いますけどね!(無いよね?) 「push忘れてた」はやめてください.自信無くていいからpushはしてくれ.

あとdiffを確認できるのがめちゃめちゃ良いです. 自分で書いていて確認できるのもそうですが,執筆用のブランチを切って編集用のブランチに適宜MRを出す,ということをやっていたので,校正・校閲がやりやすくて良いです. まあGitというよりはGitLabの良さかもですけどね.

さらに,そもそもRe:VIEWが技術同人誌を書くために作られたものであるというのも大きいです. 何も考えずにやっても標準でトンボ出してくれたりしますしね. ビルドして出てきたPDFも大体そのまま印刷所に投げつけられます入稿できます. 設定もyamlファイルでできるので,オラッA4にするぞみたいなcommitして,あとで「やっぱA4はアカンわ.revertしたろ.」みたいなことも簡単にできます. というか実際やった.

Docker Imageがあるのもとても良いです. LaTeXの環境構築してないPCでも作業できる,というのもありますが一番大きいのはCIで回せることです. 詳しくは後述しますがCIでPDFをビルドするのはいいぞ.

さて,これらの理由を見ると「LaTeXじゃあかんの?」と思う人もいるかもしれません. もちろん,Re:VIEWでもPDFを作るなら結局LaTeXを吐くわけですし,デザインや文字の配置に拘りたいならLaTeXと真剣に向き合った方が良いですし,それなら直接LaTeXを書いた方がいいかもしれません. ですが,OtakuAssemblyでは執筆者全員が生のLaTeXを書くようになることは無いと思っています.

何故かというと,意味分からんエラーメッセージを見たくないからです. あと意味分からんエラーメッセージを見たくないです(大事なことなので2回言った). 何を言いたいかというと,他の人が書いた原稿をpullしてきてビルドしたら意味分からんエラーメッセージがターミナルを埋め尽くした......みたいな事象を許容できるか?ということです. 僕は許容できません*5. また,執筆者に執筆に集中してほしいということがあります. 原稿を書け. 文章を思いついたらVimで自分の原稿のファイルを開いて書くだけ,という環境を用意しておくのはとても大事だと思っています. 原稿を書け.

このことから,Re:VIEWの記法がとてもシンプルなのも重要だと思っています. まあまあMarkdownっぽいので,普段Markdownを書いている人なら,Re:VIEW フォーマットガイドを読めば難なく書くことができるでしょう. どうしても慣れなかったらある程度はMarkdownで書いてもらって(ただし派生記法をできるだけ使わず),md2reviewで変換する,といったこともできるでしょう. 実際何度かMarkdownで書かれた文書をRe:VIEWに変換してPDFにする,というようなことをやっていますが,変な記法を使ってなければそこまで大きな問題は起きないです. 正直#を=に変えるだけでも大体どうにかなると言っても過言ではありまs...流石に過言か.

記法のシンプルさだけで考えれば,原稿をMarkdownで書いてどうにかこうにかして*6PDFを作るのもアリだと思っています. ただ,Markdownは多くのオタクが普段から書き慣れているという利点はあるものの, その「書き慣れている」記法は得てして任意 flavored Markdownなので,「は?俺の知ってるMarkdownと違うんだが...」が発生するのではないかと思っています. もちろん凝ったことをしなければ何の問題も無いだろうとも思いますが. hikaliumさんがやっていたMarkdownで書いてSATySFiでビルド,とかは今後検討してみたいです.

GitLabを使った運用

リモートリポジトリにはGitLabを使っています. GitHubではなくGitLabなのは,organizationでもprivateリポジトリを作ることができる上, GitLab CIで簡単にCIを導入できるからです. 今ならGitHub Actionsがあるので,GitHubを使う選択肢もあると思います.

GitLabに"OtakuAssembly"というorganizationを作って,そこにprivate repositoryを生やしているだけです. 新規参入者には持っていなければGitLabのアカウントを作ってもらい,organizationにinviteした上で,執筆ネタが決まったら対象となるリポジトリでDeveloper権限を付与する,というようなことをしています.

また,主に編集作業の効率化のために,Git flow的なワークフローを採用しています.

具体的には,masterブランチは常に「リリース(=入稿)」できるもの,developブランチでは編集作業や設定の調整を行う,draftブランチでは各自が執筆する,というやり方をとっています. draftブランチは各自のIDに合わせてdraft/sksatみたいなかんじにしています. あと印刷所から怒られが発生するとhotfixブランチが生えます.わあい(白目).

なんでGitHub flowじゃないの?と思う人もいるかもしれませんが,「リリース作業」が行われることが数えるほどしか無いし,rebaseを行う必要性が微塵もないのでこれでええやろと思ってます. まあVol.1の時に僕がこれくらいしか知らなかったというのもありますが. とはいえこれでかなり上手く行っていますし多分Vol.3が出ることがあってもこれで行くんじゃないかと思います. あとmasterにマージした時のdiffのウオー俺達こんなに書いてたんだ感がいい.

なので,基本的には執筆者は自分のdraftブランチで執筆を行うだけです. そして,執筆に一区切りついたり*7,執筆が完了したりしたらdevelopブランチに対してMerge Requestを飛ばしてもらいます. MRの内容確認やマージは編集担当(基本的には僕)が行います. developブランチでは原稿を統合した時に不具合が起こっていないかチェックしたり,「今こんなかんじか〜」ってなったりします.

GitLab CIによるPDFのビルド

文書作成におけるCI,めっちゃくちゃ重要だと思っています*8. もうCIの無い文書作成はあんまり考えたくないぐらいです. いやもちろんある程度の規模の文書ならってことですけどね. でも,「今のうちに卒論で困らないように執筆環境とCI整備しておこうかなあ」と思うくらいには重要視してます. 常にビルドが通るように気をつける,ビルドが落ちるようになったらすぐに知ることができる,というのも重要ですが, それにより常に標準的な環境でビルドされたPDFを手に入れることができる,ということが大きいと思っています.

Re:VIEWで書こうが最終的にPDFを作るのはLaTeXの仕事なので,出力されるPDFは割とビルド環境にインストールされているLaTeX環境に左右されます. 特にフォントとかね.あとまあバージョンも人によって結構違うことがあると思います. そのような差異を考えなくてよくなるのは結構大きなメリットです. さらに,今外出してて環境構築したPC持ってないんだよ,みたいな時にもスマホからGitLabにログインすれば校正・校閲が可能!!!!!*9 あと,「今tag付けたやつのビルド結果を入稿して!」ができます.これも大きい. 「このcommitのビルド結果を手が空いてる人でチェックして!!」とかもね.

GitLab CIではDocker Imageを簡単に突っ込めるのもとても良いです. Docker Imageには超有名なvvakame/reviewを用いています.

github.com

Re:VIEWのバージョン指定が簡単にできて良いんですよね. ちなみにOtakuAssemblyではVol.1ではversion 3.0,Vol.2ではversion 4.0のRe:VIEWを使っています. 新しいもの好きなので.

ただ,Vol.2の割と後半の方で「siunitxが欲しいんだが......」というオタクがいたので,急遽超虚無Docker Imageを作って差し替えました. まあマジでtexlive-scienceをインストールしてるだけですけどね. github.com

Docker Hubとか使ったこと無くて焦りましたね. でもこれ作ってDocker Image差し替えたら上手く行ったのでやっぱりDockerとGitLab CIは偉大ですね.

あと,Vol.1の時はGitLabのPDFビューアがなんかバグッててページの順番がぶっ壊れたかんじの表示になっていて, Web上でPDF見て校閲したい時かなり厳しい気持ちになっていたんですが,Vol.2の時にはこの問題は修正されていたみたいです. ありがとうGitLab!!!一生付いていきます!!!!!(普段はソースコードGitHubに上げながら).

Slackへの通知

OtakuAssemblyでは,連絡には主にSlackを用いています. というかSlackしか使ってません. なんなら執筆者のほとんどとはTwitterとこのSlackでしか繋がりがありません. 最近流行りのSNS採用・リモートワークってやつですね(?)*10

なので,各位のcommit状況の確認やCIの状況の確認のため,GitLabからSlackにwebhookで通知を飛ばすようにしています. f:id:sksat:20200318021011p:plain

こういうスクショ出すとたまに「スッコココすき」って言われてふふってなります. 名付け親なので(?). スッコココくん,CIをfailさせると顔真っ赤にして怒ってくるんですよ.かわいいですね. f:id:sksat:20200318022229p:plain

あと,Vol.2の執筆中の一時期Issueとかの通知を#vol2(Vol2全般のチャンネル)に飛ばすようにしてみたんですが, Issue上でメモとかするとそれも全部通知が行くのでちょっとウザかったのでやめてしまいましたね. open/closeだけ選別して送れたら良さそうなんですけど.

編集作業について

査読があると......うれしい!!!!うれしくないですか?僕はうれしいです. ということでOtakuAssemblyでも一応それっぽい活動をしています. 最近知ったんですが,僕は編集長だったらしいです.

前述したように,校正・校閲はMRが出たら編集担当が行います. 誤字脱字の指摘や表現の修正の提案はdiffを見てMR上のコメントとして行います. まあ編集担当も執筆者の一人であるというバグがある上に僕の執筆速度が大体一番遅いので終盤になってくると頼む〜〜〜〜手が空いたオタク誤字脱字チェックやってくれ〜〜〜〜となるんですけどね(オイ).

なんで進捗ヤバい時期って重なるんですかね.不思議ですね.

あと,Vol.1の時は誤字脱字もコメントで飛ばしてたんですけど, Vol.2では明らかな誤字脱字はわざわざコメント飛ばさず編集担当がdraftブランチにcommitしちゃっていいかと思うようになりました. しょうもないtypoの指摘に文意の確認とかが埋もれても嫌ですからね. そうじゃないんやってことだったらrevertすればいいですし. まあ適宜pullしてもらう必要がありますが.

ちなみにVol.1ではめっちゃギリギリまで原稿の調整や修正をしたり*11,手の空いた人間全員で読み直しや誤字脱字チェックしたりしてVol.1は〆切45分前入稿という偉業(偉くない)を達成しました.

そしてVol.2は〆切15分前を達成しました!(は?)

あと直前の誤字脱字チェックの時マジで@hsjoihs氏が有能of the humanでした. ありがとうございました. Vol.2では@hsjoihs氏の章が無いのに「監修」になっているのはそういうわけです.

また,Vol.2では新規参加の@coord_e氏がバチクソ誤字脱字や違和感のある文章の指摘・修正活動を行ってくれてとてもありがたかったです. やっぱり文章のクオリティを上げたいと思ってくれる人間がいるととても良いですね.

その一方で,技術同人誌における文章のクオリティってどうやって担保・向上させたらいいんだろうなあという気持ちに最近なっています. エディタースクールとか,そこらへんが出してる本とかもあるみたいなので,そういう分野も個人的に学んでみたいですね.

一応,最低限の注意事項はREADMEに書いていたんですが,執筆者のオタクのうちどれくらいがこれを気に留めて書いてくれていたんですかね.

あと,中高の部活での部誌とか,OtakuAssembly Vol.1, Vol2でそこそこ他人が書いた文章をチェックしたことから思うのは,「人々,他人に読ませることを意識して文章書かないがちでは?」ということです. これはもちろん自戒も込めての思いですけどね.

良い文章が書けない.なんとかしたいですよね.貴重な時間と精神力をたくさん使うのは惜しいですが,2人とも仲良しです.きっと成功しますよ.

技術書典7

こんなこと言ってたけど売れるかめちゃくちゃ不安でした.

当日の売り子は@PG_MANA_と僕で申請して,疲れたら適宜他のオタクと交代するか〜,と思っていました. ずっと売り子するのは疲れる,というのもありますが,そもそもこちらが自分でも技術同人誌を作りたいと思う程度には技術同人誌というものが好きなので,他のサークルの本も買いに行きたいんですよね. 交代ができるのは人数が多いサークルの利点ですね.

さて,そんなこんなで準備をして会場に向かったんですが,現地納品にしていたので物理本がどんな出来なのかは誰にも分かりませんでした. 会場に入り,OtakuAssemblyが配置された机を発見し,そこにある段ボール箱を開けると...

マジで「本じゃん」って思いましたね.本じゃん.

その後アワアワしながら初めての設営をしました. 設営後はこんなかんじになりました.

どのように設営を行うかはかなり悩みました. 何しろほぼ全員同人誌即売会での出展経験皆無でしたからね. まあ大体僕が勝手にやったんですが. 設営に関しては主にコミケとか例大祭とかのオタクのブログを参考にしました. たまに技術書典のオタクも書いていたりしますが,割とちょろっとしか書いてないことが多い気がします.

あとは,これまで技術書典4,5,6に「買う側」として参加していたのですが, その中でやや不満に思っていたことなどを踏まえて,できるだけ「買う側」の人が困らないように, 且つ,近くを通った時に目に留まるように,ということを意識していました.

「おしながき」とかんたん後払いのQRコードを上に吊る,というのもその1つです. 売る側は大体座ってるか中腰かが多いと思うんですが,買いに来る人たちは全員立って歩いてるんですよね. しかも技術書典はめちゃくちゃ込む(午前中は特に)ので,行く前から目を付けているサークルでもなければ,結構素通りしてしまいます. 僕は個人的にはできるだけ全部のサークルを見ようと思って周るようにしているんですが,それでもパッと見て内容が分かる情報が無いと後回しにしてしまうんですよね.

あと,「かんたん後払い」は人々がウカツに予定外の本を買う悪魔の最高のサービスなので, これを使わない理由はありません. ここで使うQRコードは事前に運営からデータを貰える他,小さめの紙に印刷されたものとそれを立てるためのなんか食玩とかにありそうな組み立て式の厚紙でできた台が当日配られます. もちろん配ってくれるのは親切だなあと思うんですが,正直あれは小さいし台も微妙だと思っていました. ちょっと改善したような気はしますが前をよく覚えていないので比較ができない.

実際やってみたところ,そこそこの人が吊った方のQRコードを使ってくれていたように思います. ただ,「アレッかんたん後払いのQRコードどれですか?」と何度か聞かれたので, QRコードもう少し小さくして「かんたん後払いはこちら」の文字をもう少しデカくした方が良かったかなという反省もありました.

これらの準備は以下のようなIssueを立ててやったりしました. f:id:sksat:20200317222732p:plain

ただ,当日朝バタバタしながらスマホからGitLabのIssueをポチポチするのは厳しさがあったので, 持ち物リストは紙とかにしておいた方が良さそうです.

そして一般参加者の入場が始まり,大量の人間が入ってきて「あ〜これで同人誌即売会あるあるの近くのサークルだけ売れてくやつが見られるのかな」とか, 100部は刷りすぎたかなあ......とか思っていました. でもポツポツ売れていくんですよね.めっちゃ嬉しい.嬉しいな.あれ......なんかめっちゃ売れるんだが......?

気が付いたら100部あった『OtakuAssembly Vol.1』は18部になっていました. 元々10部くらい売れたら頒布状況ツイートをしようと思っていたんですが,そんなことをする暇は全くありませんでした.やべえな. 本は何箱かの段ボール箱に入っていて,それぞれの本は5冊ごとくらいに紙テープでまとまって入っていました. なので,常に大体10部くらいが机の上に載っている状態を維持していたのですが,あまりにも売れ行きが良いので, 隣にいた@PG_MANA_に「オイ早く次の束くれ」「次の箱開けといて」「一々出してたら間に合わないから次机に載せるやつ椅子に置いておいて」とか言ってました. ツイートなんかできるわけねえ.

そしてゼエゼエしながらツイートした5分後には9冊に......

んでもってその6分後には物理本完売です.どうなってるんだ. あまりにも早く売れていったので,事前にオタクから頼まれていた取り置きを完全に忘却したり*12,予備分として付いてきた4冊も売ったり,後で執筆者の分ねえじゃん!となったりしました.

その後は電子版のダウンロードカードを配ったり,なんか急に生えてきた『The Zen Book』を展示したりしてました.

金が生えると→→→うれしい!!!!!!!

国会図書館への納本

技術書典7では物理本があまりに早く売り切れてしまったため,その後割とすぐ『OtakuAssembly Vol.1』を増刷しました*13. 増刷分はBoothで売りました. この増刷によってようやく執筆者が自分が書いた本を手に入れることができました(ウケる).

ということで余剰在庫が発生したので,前々からやりたいと思っていた(そして売る時完全に忘れていた)国会図書館への納本をすることにしました.

なんと自分で作った同人誌を国会図書館に納本するとなんと国民の税金を使って半永久的に黒歴史を保存してくれるんですよね.すごい.

というか,そもそも義務なんですよ.

納本制度」とは、図書等の出版物をその国の責任ある公的機関に納入することを発行者等に義務づける制度のことです。わが国では、国立国会図書館法(昭和23年法律第5号)により、国内で発行されたすべての出版物を、国立国会図書館に納入することが義務づけられています。

納本された出版物は、現在と未来の読者のために、国民共有の文化的資産として永く保存され、日本国民の知的活動の記録として後世に継承されます。

www.ndl.go.jp

みんなも出版した黒歴史を現在と未来の読者のために,国民共有の文化的資産として永く保存し,日本国民の知的活動の記録として後世に継承しよう!!!!!!!!!!

納本はとても簡単にすることができました. それまで国会図書館を使ったことがなかったのでその場でIDを発行してもらい, 荷物をロッカーに突っ込んでビニール袋に『OtakuAssembly Vol.1』を入れて*14中に入りました. 中はいいかんじの県立図書館をめちゃくちゃパワーアップした,みたいなかんじでした. あと入館とか検索用端末使うのとかに貰ったIDカード使うのオタク心が擽られてとても良いですね.

ああ納本の話するの忘れてましたね. 館内を見回しても特に納本の案内などは見当たらなかったので,先人のブログ記事に従い,受付で「すみません,技術同人誌の納本をしたいのですがどのようにしたらよいでしょうか?」と聞いてみました. そしたらちょっとびっくりした顔してから「少々お待ち下さい」って言われて,受付の代わりをする人が来てその人に「こちらです」って言われて付いていったら明らかに立ち入り禁止エリアっぽいところに行くんですよね. めっちゃいい. かなり日本国民としてのユーザーエクスペリエンスが良いので日本国民の皆さんにはぜひ同人誌を出版して国会図書館に納本して頂きたいですね. あ,あと立ち入り禁止エリアから出る時は一人だったので「勝手に立ち入り禁止区域に入ってこっそり出てきた一般人」ごっこができます. 誰かに咎められたらどうしようとか思った.

納本自体はとても簡単で本を渡して書類1枚書くだけです.

その後,こんなものが届きました.

それからしばらくするとNDLに『OtakuAssembly Vol.1』が掲載されました. やったぜ.

id.ndl.go.jp

新刊の『OtakuAssembly Vol.2』も近いうちに納本しに行きます. 国民共有の文化的資産ですからね(?).

あと,国会図書館とは関係ないですがOtakuAssembly Vol.1,Vol.2共にISDN: 国際標準同人誌番号というものを登録しています. これはまあISBNのパロディなのですが,結構ちゃんと運営されていて登録もスムーズにできますし,オプションを選択するとそれっぽいバーコードも出力してくれます. Vol.1の時はへ〜こんなものがあるのかと思って刷った後に登録してみたんですが,バーコードが出ると知ってVol.2では絶対にこのバーコードを入れて「「「本」」」にしてやろうと思っていたんですよね. まあ結局入稿数時間前まで忘れてたんですけど. でも印刷所からの怒られ後に表紙の再入稿ができたのでちゃんと裏表紙にこのバーコードを突っ込むことができました. 気になった君はOtakuAssembly Vol.2の物理本を手に入れて裏表紙を見てみよう!本だぞ!!!*15

isdn.jp isdn.jp

技術書典8

はい.中止になってしまいました.残念ですね. まあ仕方ない.仕方なくはあるんですがもう刷ってしまったのでオタクの財布が大変です!!!買ってくれ!!!!!

通販

今買うって言った?なんと通販で買えます.皆さんもウカツに買ってください.

techbookfest.org

otakuassembly.booth.pm

※Vol.2の物理本は現在入荷待ちなのでしばらくお待ち下さい(3/17現在)

おまけ:限界commit log selection

*1:これをやりたかっただけです

*2:オタクは信用できないので

*3:実はAC入試の自己推薦書はRe:VIEWで書きました

*4:こういう書き方するとヤバいな...

*5:もちろん,LaTeXを生で使う場合でも,適切にブランチを切りCIを回しておけば流石にこんなことは起きないと思います.たぶんね.でもマージした途端に大崩壊,みたいな可能性は否定できないと思うんですよね.特に各々が好き勝手にパッケージ導入とかやっちゃうと.まあこれも適切な運用をすれば大丈夫でしょうが,オタクは信用なりませんし,オタクは信用なりませんし,オタクは信用なりませんし,何より「気をつけて運用する」ということは精神的にまあまあ大きなコストです.

*6:pandocとかで

*7:これが難しいんですけどね...

*8:AC入試の自己推薦書でももちろんCI回してましたよ!!!!!面接はfailしましたけどね!!!!(溢れ出る学歴?コンプ)

*9:社畜か?

*10:でも,そういう考え方するとGitLabのム〜ブが参考になったりするのかな?とか思ったりしますね.知らんけど.

*11:直前に300pに抑えないといけなくなったりしたのは辛かった......

*12:このオタクには見本誌を渡してgot kotonakiしました

*13:儲かったので

*14:国会図書館内には基本的に物の持ち込みはできません.どうしても持ち込みたい物はその場に用意されているビニール袋に入れて持ち込む必要があります.

*15:まあ僕もまだ現物は見てないんですけど......

OpenSKを使ってみた

Twitter見てたらこんな記事が流れてきました.

gigazine.net

エッマジかよ. しかもRustなのかよ.すごいな.

security.googleblog.com

"fully open-source security key implementation" っょぃなあ...と思って読んでみたらなんとこれTock OSのアプリケーションとして実装されてるんですね. 俄然気になってきた.

Tockは前にも少し紹介したRust製の組込みOSです.

sksat.hatenablog.com

ということでOpenSKのrepoはここ.

github.com

READMEによると,nRF52840-DKとnRF52840-dongleに対応しているようです. なるほど〜たしかにdongleなら殻付ければセキュリティキーになるよなあ.

USBメモリっぽい形のマイコンってBad USB以外何になるんだろうみたいな偏見があったんですが,セキュリティキーはなるほどというかんじです. まあ僕はBad USBもセキュリティキーも大好きなんですが.

ということでnRF52840-dongleが欲しくなってきたのですが, せっかくnRF52840-DK持ってるので試してみたいですね.試します.

全部READMEに書いてあるのでその通りにやればよいです. 打つコマンドは以下. 書き込みに必要なのでJLinkは入れておいて下さい. あと多分tockloaderも入れておいた方がいいのかな?

$ git clone https://github.com/google/OpenSK
$ cd OpenSK
$ ./setup.sh
$ board=nrf52840dk ./deploy.sh os app
$ sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/ &&
$ sudo udevadm control --reload

これだけでOKです(でした).

あとは,USB peripheralの方にもUSBケーブルを刺してPCと接続しましょう. これでOpenSKのnRF52840-DKへのインストールと,OpenSKをセキュリティキーとして使うための準備が出来ました. さあ,見せて貰おうか.お前の"力"を...

といってもどうやって試したもんですかね. もしかしてこれめちゃくちゃデバッグが大変だったりするのでは? なんかテストツールとかあるんですかね.

まあ今回はめんどくさかったので一瞬だけGoogleへのログイン用のセキュリティキーとして使ってみることにしました.

f:id:sksat:20200201021338p:plain
セキュリティキーの登録

この状態で少し待つとLEDがピカピカ光ります. どうやら点滅する時としない時がある気がするけど何の違いだろう. LEDが光ったら,適当にボタンを押すと登録できます.

f:id:sksat:20200201022102p:plain
登録完了

できました.

f:id:sksat:20200201022131p:plain

では使ってみましょう.

f:id:sksat:20200201022426p:plain
オラッッッ

ここでまたLEDが光るのでボタンポチー.

すると...

f:id:sksat:20200201022501p:plain

ウオオオオオログインできたあああああああ. すごい.まあ登録ができてるんだからいけるのはそれはそう. でもすごいですね.ちゃんと使える. まあ今回は実験なので一瞬で登録解除しましたが.

ということで,オープンソースのセキュリティキー実装のOpenSKを使ってみました. YubiKey大好きマンですし(あんまりちゃんと使えてないけど),オープンソースも大好きなのでもしかしたらそのうち移行するかもしれないまである.

実装も超気になるので時間のある時に読んでみたいですね. とりあえず,近いうちにnRF52840-dongleを買ってケースを3Dプリントしようと思います.

ブラウザをVivaldiからFirefoxに乗り換えられるか試してみる

Vivaldi

中高生の頃はブラウザはずっとFirefoxを使っていました. 中古ノートPCだけですべてをやりくりしていたので, Chromeなんてすぐメモリを食べまくって使い物になりませんでしたからね. ほんの一時期だけOpera使ってたこともあるけど,昔は自分のパソコン持ってなかったのもあって, 色々カスタマイズしたところで同じ作業を何度もやるのダルいしな...とか思って結局Firefoxでいいやってなった. あと火×狐ってなんか厨ニ病っぽくて好き.

そんな僕でしたが,オタクからメモリを貰ったり(何?),大学入学を期にThinkPad X1 CarbonがメインPCになったりしてメモリ容量が割と潤沢になってきました*1

で,ツイのオタクが激推ししていて前から気になっていたVivaldiなるブラウザに乗り換えてみたんですよね. それが過去の僕のツイートから2019年4月2日のことっぽい.

それ以降も結構Vivaldi気に入ったのでずっと使い続けてました. stable版とsnapshot版で使い分けたりとかはしてたけど.

10月くらいにデスクトップマシンを組んだ時も,選ばれたのはVivaldiでした. もちろんディストリはArch LinuxだしWMはi3.

ただ,このVivaldi,なんかどうもたまによく死ぬ(急に落ちる)んですよね. なんかやたら死ぬ日みたいなのがある気がする.

デスクトップマシンで使ったらほとんど落ちなかったので,マシンの問題かもだけど. その他に発生した問題としては,いくつかのWebサービスで"そのブラウザは非推奨です"って言われることですかね. 非推奨なブラウザであることは事実なので仕方ないけども.

まあ,非推奨ですよ〜って言われるぐらいはいいんですよ. でもBANしてくるのはどうなんだ.

Webサービス運営者の気持ちになってみれば,まあ標準的なブラウザ以外サポートしたくなんてないし(特にIE),非推奨ブラウザでアクセスしてきておいてクレームつけられたらたまったものじゃないだろうし,正しい判断なんだろうな〜とは思うんですけどね. 思うけど,「でも中身Blinkだし許してくんねえかな」ってなりますね.なりました.

あと,僕にとって致命的だったのはTweetDeckがゴミクズみたいに使えなくなってきたことです. 入力はバグるしそもそも全体が固まることも多くなってきたし. なんなんですかねあれ.FAKE野郎なので全然原因究明してませんが. まあそもそもDeckとibusやらmozcやらの相性が激悪な気もしているし, 一概にVivaldiが悪いとは言えないとは思うんですが, Firefoxだとそこまでひどい現象は見られないので,はいってかんじですね. web panelでDeck表示しながらブラウジングしたり作業したりするの大好きなんだけどなあ...

なので,最近はAmazon MusicとTweetDeckのためだけにVivaldiの横でFirefoxを開く芸をやっていました. まあタイル型WM使いなのでちょうどいい位置にFirefoxを配置する苦しみみたいなのはあんまりないし, デスクトップマシンだとメモリ容量余裕あるからVivaldiFirefox両方同時に使ってもそんなに問題無い. とはいえ,普通のブラウジングVivaldiで横に常にAmazon MusicとTweetDeckだけ開いたFirefoxを忍ばせておく運用はなんというか精神がすり減るような感覚があります.

ということがあり,ブラウザをVivaldiから他のものに乗り換える...かは分からないですが, 乗り換えられる状況を作っておくのは悪くないだろう,と思ったというわけです. どうせVivaldiの横でFirefox開いてたらそっちも使っちゃうし...

じゃあどんなブラウザ使おうかねと思ったんですが,ちょっと考えたけどFirefoxでいいかってなりましたね. いいじゃん,Rustだし(?). あと脱Googleみたいなのにも興味があるような人間なのでそれでChromeはウーンというかんじでナシ. 別にChrome拡張もそんなに使ってない.いや使ってるけれど,同じものがFirefoxのアドオンにもあるものがほとんどなんですよね.

あとなんか知らんうちにFirefoxにもpicture in picture来てたしね.

それじゃあFirefoxアドオンマシマシにしたらVivaldi置き換えできるか気になるじゃないですか. Firefox Quantumで各種便利アドオンが殲滅されたみたいな話があるのでそこらへんは気をつける必要がありますが.

マウスジェスチャー

Vivaldiで僕が気に入っている機能の1つがマウスジェスチャーです. マウスの動きを登録しておいて特定の動作をさせるやつ. 新しいタブ開くとか今のタブ閉じるとか,そういうやつ.

Firefoxだとマウスジェスチャーできるようにするアドオンあるのかな〜と思ってみたら,いくつかあるみたいですね. でも,Firefox Quantumでかなり滅びたとか. ということで今回使ってみたのはGesturefyです. これが中々使いやすそうで良かった.

f:id:sksat:20200118230950p:plain
Gesturefyへのジェスチャーの登録

あと,デフォルトだと新しいタブが5億光年先で開くじゃないですか(タブは5億個開くので). なので,どうにかならんかな〜と思って見てみたら,Edit Gesture -> Command -> New Tab -> New tab positionを"after"にしたら望むものになりました.やったぜ.

web panelの再現

次はweb panelの再現です. web panelというのは,VivaldiブラウジングをしながらTweetDeckを使うための機能です(真顔). URLを事前に設定しておくとボタンポチーで画面の左半分とかにそのサイトを表示してくれるってやつです. 超べんり.これが無いとツイッターが出来ない体にされた. 僕の場合はDeckの他にはMastodonの一番よくいるインスタンスGoogle CalendarGoogle Translateを入れています.

さて,今回はFirefoxでこれと同じことをやりたいわけです. まあタイル型WM使いなので横にもう1つウィンドウ置けばいいだけといえばそうなんですが, その状態でターミナルのウィンドウとか開いたら好みの場所に設定しなおすのにまた手間がかかるので, ブラウザを1つのウィンドウだけでいいかんじにできれば良いにこしたことはありません.

で,問題はFirefoxにweb panel相当のものがあるかどうかなんですが, Bitwardenのアドオンをインストールした時になんか横にそれっぽいのが生えてたのは知っていました. Firefoxではside barというものだそうです. Vivaldiとは違ってデフォルトではここでWebサイトを開く手段は無さそうですけどね.

でも,side barがアドオンから弄ることが領域であるということは,絶対ここでWebサイトを開くかんじのアドオンがあるはずです. オタクくんそういうの好きでしょ.俺は詳しいんだ.

ということで調べてみると,まさにそういうかんじのアドオンが2つ見つかりました.

あと,もう少し調べてみたら,「side barで表示したいWebサイトをブックマークして,ブックマークのプロパティで"load this bookmark in the sidebar"というチェックボックスにチェックすればいけるで〜」という記事を見つけました. これでいいじゃん!と思ったのですがそんなチェックボックスはありませんでした. なぜ?と思ったらこの機能はFirefox 63で削除されたみたいです. ざんねん.

ということで,Webpage SidebarとSide Viewをそれぞれ使ってみました. まず,Webpage Sidebarはシンプルながら必要なものを抑えてるな〜と思いました.

f:id:sksat:20200118164933p:plain
Webpage Sidebar

クリックするとこんなかんじのシンプルなポップアップが出てきて, ここにside barで表示したいWebサイトのリンクを入れておけばそれ以降はここをポチっなとするだけでside barに表示してくれます.

f:id:sksat:20200118165409p:plain
Vivaldi web panel

できればVivaldiのこのボタンポチーで行けるようにしたいですけどね〜.まあ多くは望まない方がいいでしょう.

次はSide Viewです. これはWebpage SidebarよりもUIがなんというかキラキラしていますね(生htmlってかんじのじゃないねの意です). こちらの特徴としては,なんも考えずに今開いているページをside barに表示できるというのがありますね. これは便利だ.便利なんですが,特に開きたいやつを登録しておく,みたいなことができない. そこについてはWebpage Sidebarの方が「俺はこれとこれとこれをside barで開くんや」という気概があっていいかもしれないですね. とはいえRecent領域があるのでそんなに軽率に開かなければそんなに困らないかな...

f:id:sksat:20200118170649p:plain
Side View

あと,こっちはデスクトップ向け表示させるかモバイル向け表示させるかを選択できます. ちょっとVivaldiっぽい.

どちらを使うかは悩ましいです. でも開くサイトはほぼ決まってるし,サイトのアイコンを一緒に表示してくれればWebpage Sidebarがいいかなあ...と思っています. アイコンでものを判断しているので*2. そんなにコード長くないし,contributeしてみるのもありかもしれないですね?Webなんもわからんが...

さて,これで勝った...と思ったのですが,ダメでした. なんとこのside barさん広げられるサイズに上限がある...

オイ!!!!!!これだと通知が見えにくいやろが!!!!!! この問題はアドオンというか力とパワーで殴らないと解決できませんでした.

まず,これはuserChrome.cssというファイルに

#sidebar {
  max-width: none !important;
  min-width: 0px !important;
}

と書くと好きなだけ幅が変えられます. 変えられるのですが,例によってQuantumからuserChrome.cssが使えなくなったらしいです.oh じゃあどうするのかというと,about:configからtoolkit.legacyUserProfileCustomizations.stylesheetsを選んでtrueにします. で,このuserChrome.cssなるファイルはどこに置くのかというと,config:profilesからprofileのディレクトリを確認して, そのディレクトリ内にchrome/userChrome.cssを書けば良いみたいです.

というかユーザープロファイルって何?

www.clear-code.com

へーそういうかんじの概念か.

タブ管理

あれっ,タブスタックってそういやVivaldiの機能か...って言いながらFirefoxでタブの上にタブ重ねてうーんうーんってやるやつやってました. あと,タブバーを右側に置きたい.

とりあえず,Tree Style Tabなるものを使ってみたんですが, 残念ながらこれはside barを使うアドオンなんですよね.むむう.

他に良いもの無いかな?と思ったものの,やっぱりここらへんもQuantum以降めっちゃ難しくなったっぽいんですよね.

ツリー型タブのWebExtensionsへの移行のおはなし - Qiita

ひえー大変そう.

web panel問題 再来

縦タブ使いたいなあ,どうしたものかなあと思っていたら,TSTの作者の方からこんな情報が...

確かに,Side ViewとかでTweetDeck開くと微妙に表示がおかしいことがありますね...使えないほどではないけれど.

ということで教えてもらったのがこちら.

これをどう使うかというと,TSTとこのアドオンを入れた状態で,Firefoxのウィンドウを2つ開き, 片方でTweetDeck(web panel的に開きたいやつ)を開き,左側に配置します. そうしたら,もう片方のウィンドウで普通にブラウジングします(そして,こっちではTSTを使ってタブ管理します). こうすると,普通のブラウジングは縦タブで優勝しつつTweetDeckで人権が得られます. また,Deckの方で面白そうなリンクが流れてきても,普通に開くとそのタブがぐわーっと左のウィンドウに移動してくれます.なるほどね.

f:id:sksat:20200122181918p:plain
使用感

実際に使ってみるとこんなかんじ. 慣れるまで少し時間かかったけど,慣れたらまあまあ使いやすいですね.

しかし,ここで以下の問題が発生します.

  • 毎回ウィンドウを丁寧に左右に配置するのめんどくない
  • TweetDeck以外左で開けないやんけ

まず,1つ目に関しては,タイル型WMを使いましょう.i3使いましょう. タイル型WM使ってないんですか? ププーッ,ウィンドウが浮いているのが許されるのは小学生まででしょw(?) ということです.よろしくお願いします.

次に,2つ目についてですが,これは結局先程のweb panelもどきアドオンを使うことにしました. ちょっと表示おかしかったりはするけど,使えないってほどじゃないですからね. これがどういうことかというと,こういうことです.

f:id:sksat:20200122184540p:plain

一番見るのはTweetDeckですからね.まあいいでしょう. TwitterやめてMastodonに完全移行してもメインが変わるだけです.

ちなみに,この用途であればSide ViewよりもWebpage Sidebarの方が使いやすかったです.

おわり

ということで,VivaldiからFirefoxに乗り換えられるかなチャレンジをやってみました. とはいえ,やっぱりFirefoxだとアドオンマシマシにしないとできない(&してもできないことがある)ので,そういう機能がデフォルトで付いてる上に設定も弄りやすいVivaldiは良いですねという気持ちになりました. あと,僕がまだ使いこなせていないだけでVivaldiにはもっと色々カスタマイズできるところがありますしね.

でも,本当の意味で縦タブ(タブバーが縦)ができれば,僕にとっては随分状況が違う気もしますね.どうなんだろ.

まあしばらくFirefoxVivaldi両方使ってみようとは思います. Firefoxも好きだし.

*1:といっても,16GBとかですが

*2:ツイのオタクもアイコンで判断しているし,当然web panelのサイトもアイコンで判断している

Rust製の組み込みOS『Tock』について調べてみた

これは 自作OS Advent Calendar 2019 の9日目の記事です.

はじめに

最近大人気ですよね,Rust. 全人類Rust書いとる...俺は... システムプログラミング言語ですし,LLVMを使っているので色々なアーキテクチャ向けにコンパイルできますし, 安全性を重視しているので,RustでOSが書けるようになると色々と面白そうです.

とはいえ,なんだかんだでちゃんと使ってみようという気になれず,まだあまり書いたことがありません. そこで,今回はRustで書かれたOSであるTockを使って,モダンな言語でのOSの作り方やRustそのものについて調べてみようと思います.

Tockとは

TockはRustで書かれたCortex-MやRISC-Vで動く組み込みOSです.

https://github.com/tock/tock

最近はSTM32でも動くらしいですね.

https://garasubo.github.io/hexo/2019/02/18/tockapp.html

とりあえず動かしてみる

何はともあれ,まずは動かしてみましょう. Getting Started Guideに従います.

まずはRustの環境構築と,tockloaderのインストールです. 実はここでrustupで指定されたバージョンのRustを入れるだけのはずなのにnightlyだとclippyが云々とか言われて激しく躓いたんですが,rustupってそういうもんなんですかね...? よく分からないけど,もうちょっとどうにかならないんだろうか(割と公式っぽいところの記述通りにやってもだめだったりするの初心者殺しでは?).

次に,カーネルコンパイルします. カーネルコンパイルはボード毎のディレクトリで行うようです.

$ cd boards/nucleo_f446re/
$ make -n
RUSTFLAGS="-C link-arg=-Tlayout.ld -C linker=rust-lld -C linker-flavor=ld.lld -C relocation-model=dynamic-no-pic -C link-arg=-zmax-page-size=512" cargo build --target=thumbv7em-none-eabi  --release
"/home/sksat/.rustup/toolchains/nightly-2019-10-17-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm"-size target/thumbv7em-none-eabi/release/nucleo_f446re
cp target/thumbv7em-none-eabi/release/nucleo_f446re target/thumbv7em-none-eabi/release/nucleo_f446re.elf
"/home/sksat/.rustup/toolchains/nightly-2019-10-17-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm"-objcopy --output-target=binary target/thumbv7em-none-eabi/release/nucleo_f446re.elf target/thumbv7em-none-eabi/release/nucleo_f446re.bin
$ make
   Compiling tock-registers v0.3.0 (/home/sksat/github/tock/libraries/tock-register-interface)
   Compiling tock-cells v0.1.0 (/home/sksat/github/tock/libraries/tock-cells)
   Compiling enum_primitive v0.1.0 (/home/sksat/github/tock/libraries/enum_primitive)
   Compiling nucleo_f446re v0.1.0 (/home/sksat/github/tock/boards/nucleo_f446re)
   Compiling tock_rt0 v0.1.0 (/home/sksat/github/tock/libraries/tock-rt0)
   Compiling kernel v0.1.0 (/home/sksat/github/tock/kernel)
   Compiling cortexm v0.1.0 (/home/sksat/github/tock/arch/cortex-m)
   Compiling capsules v0.1.0 (/home/sksat/github/tock/capsules)
   Compiling cortexm4 v0.1.0 (/home/sksat/github/tock/arch/cortex-m4)
   Compiling stm32f4xx v0.1.0 (/home/sksat/github/tock/chips/stm32f4xx)
    Finished release [optimized + debuginfo] target(s) in 6.91s
   text    data     bss     dec     hex filename
  55809       2180      71548     129537      1fa01 target/thumbv7em-none-eabi/release/nucleo_f446re

最近はxargo?とかいうのを使わずともcargoで行けるんですね. ようするにcargoでターゲットを指定してビルドして,生成されたELFファイルをllvm-objcopyで素のバイナリにしているだけですね. また,cargoの出力からアーキテクチャ依存部分,ボードやSoC,ランタイム,Capsuleカーネル本体がRustのライブラリとして実装されていることも分かりました.

コンパイルができたので,まずはこのカーネルを手持ちのボードに書き込んでみます. 今回はSTM32F446を使いました(買ってくれた@tnishinagaさんありがとうございます). ...と思ったのですが,何故か書き込みができなくなってしまった(昨日はできたんだけどなあ...)ので, これ以降はnRF52840-DKを使います.申し訳...

(挙動からしてケーブルの接触不良感がするんですが諸事情により今使えるUSB mini Bなケーブルが1本しかないんですよね.マイコン弄りには致命的です.)

$ make flash
    Finished release [optimized + debuginfo] target(s) in 0.00s
   text    data     bss     dec     hex filename
  94208       2464     259680     356352      57000    target/thumbv7em-none-eabi/release/nrf52840dk
tockloader  flash --address 0x00000 --jlink --board nrf52dk target/thumbv7em-none-eabi/release/nrf52840dk.bin
Flashing binar(y|ies) to board...
Using known arch and jtag-device for known board nrf52dk
Finished in 0.560 seconds

書き込めたようです.

カーネルが書き込めたので,次はアプリケーションを動かしてみましょう(Tockではカーネルとアプリケーションは別に突っ込むみたいです). アプリケーションの書き込みには,専用ツールのtockloaderを使います. tockloaderはPython3で書かれています. 3で良かった...こういうのがPython2なのってたまによくあるけどめっちゃイラッとするんですよね.2019年も終わりますからね. Python2は速やかに滅ぼしましょう.

まずは対応しているボードを確認します.

$ tockloader list-known-boards
Known boards: hail, imix, nrf51dk, nrf52dk, launchxl-cc26x2r1, ek-tm4c1294xl

あれ?もしかして結局STM32使えなかったオチ? まあ割と最近追加されたターゲットらしいですし,そのうち実装されるでしょう.

ということで,最初はblinkというアプリケーションを書き込んでみます.

$ tockloader install --port /dev/ttyACM0 --board nrf52dk --jlink blink
Could not find TAB named "blink" locally.

[0]    No
[1]    Yes

Would you like to check the online TAB repository for that app?[0] 1
Installing apps on the board...
Using known arch and jtag-device for known board nrf52dk
Finished in 2.497 seconds

どうやら,アプリケーションはTABという単位で管理されており,オンラインのTABリポジトリに登録されているexampleなどはダウンロードして使えるようです.

めっちゃ光ります.

アプリケーションを見てみる

アプリケーションの実装例はC/C++のものRustのものがあるようです. 正確には,これらはC/C++とRust向けのユーザランドライブラリ群で,examplesにそれを使ったサンプルがあるかんじです. newlibとかluaとか使えるみたいですね.良さそう.

Rustはまだあんまり分かっていないので,ここではlibtock-cを見てみます. まずはblinkです.

#include <led.h>
#include <timer.h>

int main(void) {
  int num_leds = led_count();

  for (int count = 0; ; count++) {
    for (int i = 0; i < num_leds; i++) {
      if (count & (1 << i)) {
        led_on(i);
      } else {
        led_off(i);
      }
    }

    delay_ms(250);
  }
}

とりあえずこれもコンパイルして書き込んでみましょう.

$ git clone https://github.com/tock/libtock-c
$ cd libtock-c
$ cd examples/blink
$ make
~~~libtockのビルド~~~
Application size report for architecture cortex-m0:
   text    data     bss     dec     hex filename
   1240        188        352       1780        6f4 build/cortex-m0/cortex-m0.elf
Application size report for architecture cortex-m3:
   text    data     bss     dec     hex filename
    992        188        352       1532        5fc build/cortex-m3/cortex-m3.elf
Application size report for architecture cortex-m4:
   text    data     bss     dec     hex filename
    992        188        352       1532        5fc build/cortex-m4/cortex-m4.elf
$ tockloader install --port /dev/ttyACM0 --board nrf52dk --jlink build/blink.tab 
Installing apps on the board...
Using known arch and jtag-device for known board nrf52dk
Finished in 2.916 seconds

最初と同じように光ったので,delayの時間を少し変えてコンパイルし直してみます.

チカチカの間隔が長くなりましたね.ちゃんとビルド・書き込みができているようです.

さて,ここで気になるのがこのアプリケーションがどのようにビルドされているのかということです. ビルド時にアーキテクチャやボードは指定していないですし,make時のログを見る限りどうもCortex-M0,3,4向けにそれぞれビルドしているみたいです. ということでbuild/とtabファイルを見てみます.

$ ls build
blink.tab  cortex-m0/  cortex-m3/  cortex-m4/
$ file build/blink.tab
build/blink.tab: POSIX tar archive (GNU)
$ tar xvf build/blink.tab
metadata.toml
cortex-m0.tbf
cortex-m0.bin
cortex-m3.tbf
cortex-m3.bin
cortex-m4.tbf
cortex-m4.bin
$ cat metadata.toml 
tab-version = 1
name = "blink"
only-for-boards = ""
build-date = 2019-12-09T10:00:29Z

あっそういうことなの... とりあえず全部ビルドしてtarに突っ込んでるんですね. TABってtar archiveだったのか... つまり,書き込み時にtockloaderがtarを展開してmetadata.tomlを見ていいかんじに察して対応するアプリケーションのバイナリイメージだけを書き込んでいるということです. まあ,カーネルとアプリケーションが分離されているし基本的なアプリケーションを作る時にはアーキテクチャ毎にビルドしちゃって良いというのは分からないでもないんですが, 必要なやつだけビルドしたいなあ感が否めないですね.

さて,次に気になるのはled.hです. どのようにアプリケーションからカーネルを叩いているのかです.

libtock/led.cを見てみると,led_on()はこんなかんじになっていました.

~~~

int led_count(void) {
  return command(DRIVER_NUM_LEDS, 0, 0, 0);
}

int led_on(int led_num) {
  return command(DRIVER_NUM_LEDS, 1, led_num, 0);
}

~~~

どうやらcommand()システムコールラッパー的なやつで,LEDに関する操作は第一引数をDRIVER_NUM_LEDSにするとよいっぽいですね.

command()libtock/tock.cで実装されていました.

int command(uint32_t driver, uint32_t command, int data, int arg2) {
  register uint32_t r0 asm ("r0") = driver;
  register uint32_t r1 asm ("r1") = command;
  register uint32_t r2 asm ("r2") = data;
  register uint32_t r3 asm ("r3") = arg2;
  register int ret asm ("r0");
  asm volatile (
    "svc 2"
    : "=r" (ret)  
    : "r" (r0), "r" (r1), "r" (r2), "r" (r3)
    : "memory"
    ); 
  return ret;
}

SVC命令で割り込みを発生させてカーネルを呼んでいるみたいですね. r0のdriverがLEDとかButtunとかの大雑把なドライバ(Capusle毎とかなのかな?)の指定に使われていて, そのドライバに対してコマンドと2つの引数を指定できるようです.

ドライバ番号は以下のようになっていました. 結構色々ありますね.

DRIVER_NUM_ALARM 0x0
DRIVER_NUM_CONSOLE 0x1
DRIVER_NUM_LEDS 0x00000002
DRIVER_NUM_BUTTON 0x3
DRIVER_NUM_ADC 0x5
DRIVER_NUM_DAC 0x6
DRIVER_NUM_ANALOG_COMPARATOR 0x7
DRIVER_NUM_SPI 0x20001
DRIVER_NUM_USB 0x20005
DRIVER_NUM_RNG 0x40001
DRIVER_NUM_CRC 0x40002
DRIVER_NUM_APP_FLASH 0x50000
DRIVER_NUM_NONVOLATILE_STORAGE 0x50001
DRIVER_NUM_SDCARD 0x50002
DRIVER_NUM_TEMPERATURE 0x60000
DRIVER_NUM_HUMIDITY 0x60001
DRIVER_NUM_AMBIENT_LIGHT 0x60002
DRIVER_NUM_NINEDOF 0x60004
DRIVER_NUM_TSL2561 0x70000
DRIVER_NUM_TMP006 0x70001
DRIVER_NUM_LPS25HB 0x70004
DRIVER_NUM_LTC294X 0x80000
DRIVER_NUM_MAX17205 0x80001
DRIVER_NUM_PCA9544A 0x80002
DRIVER_NUM_GPIO_ASYNC 0x80003
DRIVER_NUM_NRF_SERIALIZATION 0x80004
DRIVER_NUM_I2CMASTERSLAVE 0x80020006

次に,せっかくなのでlibtock-rsの方も見てみました. 時間がありませんでした.

ブートシーケンスとアプリケーションの実行

さて,一通り使ってみたところで,Tockがどのように起動するのか調べてみましょう. とはいっても,大体はTock Startupに書いてある通りです.

まず,Tockには.vectors.irqsの2つのテーブルがあります. Cortex-Mはベクタテーブルのリセットハンドラに関数ポインタを突っ込んでおくだけで,起動(リセット)後即その関数に飛んでくれるお手軽アーキテクチャなので, この中にあるtock_kernel_reset_handlerが最初に呼ばれる関数というわけです.

また,Rustでは#[link_section=".vectors"]のように書いておけば変数が置かれるセクションを指定できるようです.素晴らしい. #[used]で最適化で消されないようにもできるんですね.

ここで指定されているリセットハンドラはboards/<board>/src/main.rsにあるようです.ボード毎に実装されているわけですね. リセットハンドラは以下のような実装になっていました.

#[no_mangle]   // これでマングリングしないようにできるっぽい
pub unsafe fn reset_handler() {
    stm32f4xx::init();   // ボード毎の初期化処理

    // ペリフェラルとか諸々の初期化

    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES));

    let chip = static_init!(
        stm32f4xx::chip::Stm32f4xx,
        stm32f4xx::chip::Stm32f4xx::new()
    );

    // Console, LED, Buttunなどのcapsuleの生成

    // ボードの構造体
    let nucleo_f446re = NucleoF446RE {
        console: console,
        ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
        led: led,
        button: button,
        alarm: alarm,
    };

    debug!("Initialization complete. Entering main loop");

    extern "C" {
        static _sapps: u8;
    }

    kernel::procs::load_processes(
        board_kernel,
        chip,
        &_sapps as *const u8,
        &mut APP_MEMORY,
        &mut PROCESSES,
        FAULT_RESPONSE,
        &process_management_capability,
    );

    board_kernel.kernel_loop(
        &nucleo_f446re,
        chip,
        Some(&nucleo_f446re.ipc),
        &main_loop_capability,
    );
}

最初にボード毎の初期化やペリフェラルの初期化をしていますね. その後,board_kernelという変数を定義しています. これがこのボードにおけるカーネルを表現するための構造体か何かっぽいです. static_init!()が何をするマクロなのかは分かりませんが,多分kernel::Kernelの型の変数なのでしょう.

その後に定義しているchipはどうやらSoCに載っている諸々が実装されたものっぽいですね. これはボードとは別にtock/chips/以下に実装されています.GPIOのレジスタとか,そういうやつです.

その後は,console, led, buttunなどの抽象化されたデバイスが定義されています. どうやらこれらの構造体はTockではCapsuleと呼ばれているようです.

https://raw.githubusercontent.com/tock/tock/master/doc/architecture.png

TockのArchitectureを見てみると,カーネルがCore KernelとCapsuleに別れていることが分かります. Core Kernelはできるだけ小さくして,実際のハードウェアアクセスはCapsuleでやる,というかんじなんですかね. また,CapsuleはRustの構造体として実装され,明示的に指定されたリソースにのみアクセスできるので安全!とのことです.

Capsuleを作ったら,ボードの構造体にCapsuleを突っ込んで初期化は終わりです.

初期化が終わったら,kernel::procs::load_processesでプロセスをロードします. _sappsはアプリケーションのバイナリイメージを含むROMの領域のアドレスです.boards/kernel_layout.ldで定義されています. kernel::procs::load_processesの実装を読んでみると,PROCESSESの数だけProcess::create()でプロセスを生成しているようでした. あと,多値返却とかもできるんですねRust. ちなみに,APP_MEMORYstatic mut APP_MEMORY: [u8; 65536] = [0; 65536];となっていたので,アプリケーションは最大64KiBのメモリを使うことができるようです.

これでプロセスができたので,後はboard_kernel.kernel_loop()でメインループに入っています. このメインループはtock/kernel/src/sched.rsで実装されており, プロセスはスケジューラによってスケジューリングされつつ,process::State::Runningの時に実行されるようです.

おわりに

実はこの記事は2,3日で急いで書いたので今回はここまでとします. ちなみに書いてる途中に良さげな似たような記事を見つけて焦って内容を増やしました. でも,あんまり「Rustでどういうところがうれしいのか」みたいなところまで調べられませんでした. そもそも僕自身ほとんどRust書いたことがなくてなんもわかっとらんというのもあります.

とはいえ,最近はxv6とかLinuxとかのソースコードしか読んでなかったので,「おお〜モダンな言語っぽい書き方だなあ」という気持ちになりました. ボードとかSoCとかもちゃんと分けられていますしね. インターン先でZenで書いてるOSと似たものを感じました.

でも,チラッと見た限りですがポインタ操作とかちょっとめんどくさそうだな〜という気持ちにもなりました. もちろんユーザーアプリケーションを書く時にはあんまりポインタ使うべきではない/使うとしても安全に使えるようにすべき,というのは分かるんですが, ベアメタル環境で動くプログラムだとそうもいかないですよね.ペリフェラル弄ったりとか. 個人的にはそこらへんはZenの方が楽かな,と思いました(別にステマとかじゃないですよ).

あと,色々読んでみてRust結構良い言語だな〜となるやつ(N回目)をやったので, 少しずつRustでプログラム書いていきたいですね. やっていくぞ.

夏休みにconnectFreeのインターンに行った話

3週間京都でインターンしてた

ブログ書くのめっちゃ久しぶりですね.sksatです.

ちなみに大学生になりました. 大学受験のこととか,大学生活のこととかはそのうちなんか書こうと思います.

で,まあなんだかんだあったとはいえ大学生という身分を利用して最近色々やってます. 研究室入ったり,ロケット打ったりとかね.

あと,長い夏休みを利用して3週間ほどconnectFreeという会社にインターンに行ったりしてました.今回はその話です.

経緯

一般的なインターンって,会社が募集して学生が申し込んで,なんかしらの選考を受けて...とかやるらしいんですが, 今回は全然そんなかんじじゃなくて,行きたいな〜と思っていたらスッと決まっていました.すげえ.

多分最初にconnectFreeに興味を持ったのはLDScellさんのブログ記事だったと思います.

「アホだから,やるんだよ!」,なんでもかんでも自分で車輪の再発明しちゃいたいオタクっぽくてめちゃめちゃ好き. 低レイヤで面白いことやってる企業ってだけでもう興味しかないですね. その後,鮟鱇さんのツイートを見て更に興味が湧きました.

僕は計算機弄りが大好きで,大学も計算機弄るために進学したようなものです. なので,バイトとかやるとしても計算機弄りがいいなあと思っていました(まあ,他が無理というのもあります). でも,計算機弄ってたらお金が貰えるようなものって大体Web〜,とかスマホアプリ〜,とかばっかりじゃないですか(偏見). そもそも僕が計算機弄りを初めたきっかけは中学生の時に『30日でできる!OS自作入門』に何故か出会ってしまったからで, それからも低めのレイヤでわちゃわちゃするか数値計算っぽいことをやるかぐらいしかしてませんでした. ゲーム自作とかもほとんどやったことないですし.

もちろん,組み込み系のところを探せば低レイヤでわちゃわちゃすることもできると思うんですが, あんまりこのご時世に責任が発生するものをCでゴリゴリと書きたくはないですね... 贅沢かもしれないですがせめてC++(11,14,17)は使いたいですし,ナウでホットなRustとか使ってたらめっちゃ良いですよね. Rustあんまり書いたことないけど.

そんなことを思いながらなんとなくバイトを探すなどしていたんですが, そこでこんなものを見たらエーッッッこれ面白そう!!!ってなっちゃうわけです.

そんなこんなでconnectFree面白そうだな〜と思ってツイッターをしていたらなんか見学させてもらえることになったので見学させてもらいました.

見学では,

  • EVER/IPのデモ
  • Zen言語
  • NETBOY

などを軽く見せてもらいました.

EVER/IPはL3のセキュアなプロトコルで, アドレスなどがIPv6互換になっているため,上のレイヤのソフトウェアを書き換えることなく導入が可能になっています. 実際に,connectFreeのGitLabはEVER/IPを使って運用されていて,「自社プロダクトで開発環境が運用されてるのめちゃめちゃ良いな...」と思いました.

ZenはconnectFreeが独自開発しているシステムプログラミング言語で,Zigという言語をforkしたものです. ベアメタル環境などで使われることをとても意識した言語で,標準ライブラリも多くのものがベアメタル環境でも使うことができるようになっています. その上,パターンマッチなどのモダンな言語機能や,メモリアクセスの範囲チェックをコンパイル時に行ってくれたりします.

NETBOYは独自のボードで,もちろんこれの上で動くOSもZenで書くとの話でした.

気持ちになりました.はい.

めちゃめちゃ良さそうだったので,帰り際にぜひバイトとかしてみたいですね〜みたいなことを話しました.

その後,第15回Kernel/VM探検隊に行ったらconnectFreeのCEOが発表してたので, 直接会って話したら,「来たらええやん!」と言われてなんか京都に行くことになっていました.ウケる.

経緯としてはこんなかんじです. そんなわけで9/2〜9/20の間京都に行ってじっくりインターンをやらせてもらいました. ちなみに,京都までの交通費はもちろん,インターンの間住む所の手配とかも全部総務の人がやってくれました.

やったこと

Zen言語の学習

connectFreeでは色々なソフトウェアがZenで書かれているため, 最初の数日はZen言語の学習をしていました. @LDScellさんが作っていた色々なドキュメント(zenbeddedとか)を見ながら色々書いてはコンパイラに怒らていました. ちゃんと怒ってくれるコンパイラも,ベアメタルでも使える色々な標準ライブラリも,諸々のモダンな文法もすげえ...ってなってました.

現在は基本文法・標準ライブラリのドキュメントが公開されているので,興味がある人は見てみてください. Public Beta版のコンパイラも公開されているので,ぜひ遊んでみてください!

個人的には,u1,u2みたいなビット数を指定した変数を作ることができるとことか, comptimeでコンパイル時計算がゴリゴリできるところとか, interfaceとか,UEFIプロトコルが標準ライブラリにあるところとかが好きです.

Zenを使った(組み込み)OS開発

Zenを一通り学んだ後,Zenで組み込みOSを作っていました.やったぜ. 独自のプログラミング言語で独自のOSをフルスクラッチできるインターンとか最高すぎるし他では(多分)絶対できないんだよなあ...ありがてえ...

どのZenの機能をどう使ったら綺麗に実装できるかな〜と考えてコンパイラに怒られるのは楽しかったです. また,途中からこのOSは複数人で開発することになったのですが,今まで複数人での開発というものをやったことが無かったので色々と新鮮でした.

あと,インターン中にもZenコンパイラはゴリゴリと実装が進められていくので, それを眺めるのも,出社即git pullしてmakeするのも,「エーッ先週CEOと話してたことが新機能として生え初めてる!?」ってなるのも楽しかったです.

その後

インターン中に弄っていた開発ボードを貰うなど.中々高機能なので弄り甲斐があるボードです.

そして,お賃金の方も結構いただけたので,思い切って人生初の「自作PC」ってやつをやりました. まあ自作といっても本当に買ってきたパーツを組み上げるだけでしたが.

あとなんかアキバでオタクに煽られて光るメモリにしました. メモリが光ると何がうれしいのかよく分かりませんが,なんとメモリが光るんですよね.

あと調子に乗ってNVMeにしました.速くてうれしい.

もちろんArch Linuxを入れました.

また,インターンが終わった後もリモートでちょいちょい働かせてもらえることになりました. というかしてます.やったね! 多分また長期休暇期間に京都行って集中的にやりたいなーとも思ってます.

あと,僕はどうやらconnectFree初のインターン生だったみたいなのですが, 技術書執筆サークルの強いオタクがconnectFreeに興味を持っていたので社の人に紹介したらちょうど僕と入れ替わりぐらいのタイミングで京都に吸い込まれていきました.

元気にZenを書いているみたいで何よりです. 僕も元気にZenを書いていきたいですね. そのうちロケットの電装に使いたいなあ...

技術書典4に行ってきた

行ってきた. あ,ちなみにこれからはなんかイベントとか行ったら雑でもなんか書くことにしました. あとはパソコンカタカタのシンチョクをにょろ〜んと書いていければ最高ですね.

技術書典,何

一言で言うと技術書版のコミケ.たぶんそれで大体あってる. 技術書,と言っても大半は個人/団体の同人誌ですが.

詳しくは公式サイトを見てくだしあ.まあ正直ここだけ見てもなんもわからんが.

前日

9時に集合=それより前に起きる=無理では? となった

エラいので寝た.

天才なので8時台に起きた.

出発したのが9時半.何故? その衝撃的な理由は↓

しかし技術書典は待ってくれない.

て,ておくれてないし...

なんか釣り堀っぽいやつ見かけた.たのしそう.

着いた. 人間が多すぎて整理券もらうのにすごく並んだ.

技術書典では一意な囚人番号が割り当てられます.

囚人が大量輸送されてた(整理券配布列).

「奴」がいた(もちろん買った).

人間がいすぎて全くツイートができなかった. 気がついたら金を失い謎の紙束を所持していた.

どうもsatさんが学ランネタを気に入ったらしい.

satさんのMeltdown本が欲しかったが,まだ紙になったものが届いていなくて,それが1時くらいにくるらしいとのことだったのでとりあえずオタクで集まって飯を喰った.

「ラ!」と叫ぶと替え玉が無料で降ってくるのでつい喰いまくってしまった.2回替え玉した.

午後

というわけで戻ってきてMeltdownした. この時点でもまだ整理券配布の列はかなり長くて,入場できるのが2700番までとかだった.

すぐこういうことする. こういうことしてるから後ろから近づいてきたオタクにこっそりカバンにメモリ入れられそうになるんですよ. というのはネタで,ThinkPadでRAM4GBでがんばっていたらすぐメモリがオワオワリするのでTLに念を送ったらフォロワーからメモリが生えてきたのでした.感謝!!!!! ちなみに今まで4GB以上の環境を使ったことがない.

計画性が皆無なのでZIPを完全理解しそこねた.

Meltdownは...ありまーす!!

ここらへんで,やることが大体終わったので適当に存在しているオタクとオタクをしていたんですが解散の流れになり,megumishさんがTothenewfutureさんとエンカしそうな雰囲気を醸し出していたので適当に尾行したら結局UDXに戻ってきた&オタク音信不通になったのでmegumishさんと適当にダベってた.

ダベっていたらエモになった. 計画性が本当に皆無なので道端にいたフクロウカフェの宣伝の人とフクロウにつられて気がついたらフクロウカフェにいた. カフェというよりエモ空間だったが...

エモ空間

フクロウカフェ,鶏が一番自由を謳歌していましたね.

みられてる

これすき

あと,技術書典は気がついたらすごいことになってた

Tothenewfutureさんとも会えたので戦果を報告しました.

買ったもの

買いすぎでは...

本当に面白そうなものが色々あったので気がついたら買ってましたね. レイヤーが低めのものが割とあったのも良かったです.

次は売る側で参加してみたいなあ(などと).

カーネル/VMキャンプ #7 に行ってきた

行ってきました.

最近ブログ書いてなかったのでちょっと書く.<- 書いたらTogetterか?みたいなかんじになった

なんやねんそれ

kernelvm.connpass.com

これですね. ハッカソンみたいなやつ(?)です.

まあ多分だいたい「山でオタクで集まってパソコンカタカタすると→タノシイ!」という感情が具現化したみたいなかんじ. ゆるキャン△はいいぞ.

今まで何度か探検隊とかキャンプの様子をTwitterやらYouTubeのLive中継とかで見てたんですが,「これ絶対タノシイな...」と思ったので衝動的に参加してみました. レイヤーが低めな人の界隈なのも良さがある.

1日目

1日目といいつつ,僕は土曜日も登校なので学校帰りにそのまま現地に向かいました.

おなかすいてた. 立川のかにチャーハンの店おいしいよね. 何度か青梅特快乗ってるのにホーム間違えて危なかった. ここらへんに来たのは久しぶりでした.登山部も引退?したし.

この後はバスでロッジの最寄り(2km)のバス停まで行きました. 普段は最後の方までガッと乗っていく藤倉行きを途中で降りるの新鮮だった.

2kmだし歩くか〜wって思ってたら車で迎えに来てもらえました.感謝

そんなかんじでロッジに着きました.

屋根があるのすごくない?2階まであったし(今まで山奥に来たら大抵△だったので感動した). 大型キャビン | ロッヂ神戸岩 東京都檜原村にあるキャンプ場 パワースポット神戸岩に一番近い 秋川渓谷 BBQ コテージ バンガロー テントサイト 日帰り デイキャンプ 水洗トイレ完備

着いた時は♨に行っている人などがいたので少し人数は少なかったのですが, パソコンカタカタしてるオタクや転がって寝をしているオタクなどが散乱していて「ここには...『自由』があるんか...!?」とか思いました.

あとあの小屋,トラフィック最上川は無いのは当然としても電力最上川あるのは最高でしたね. まあ無いとオタクが生きていけませんが.タコ足配線の「強さ」を感じましたね.

あとなんかかなり強いアニメ上映環境が用意されてて,割と早い段階でアニメが流れ初めてた.

焼き

オタクなので△グッズを持っていったら好評だったので良かった

アニメ

放課後のプレアデス

魔法のステッキが「キキーッ」とか「ブロロロ...」とか鳴るの本当にエモい. 天文オタク的にもエモが詰まってたんですが,おるみんさんが「ここNAOJ監修」とか言っててウオオというかんじでしたね. 土星の輪のとことか4D2Uみあった.

プリンセス・プリンシパル

百合最高ですね.

クオリディアコード

クオリディアコードの円盤を買ったもののBD再生環境が無く中身を見ていなかったので見ました. 千種夜羽が出てくる11・12話しか買っていないので当然11話から流すことになり,視聴済のおるみんさん以外「?」となっていたのがチョットアレでしたね.金があれば...(とはいえ金があったら揃えるかというとウーンというかんじになる). いやでも千種夜羽最高なんですよ.

「修正」,っょぃ.

あと,隣で人狼やってる中,オーディオコメンタリーを聞くためだけに2.5周したのは我ながら限界だったっぽい

2日目

なんかクオリディアコード終わってしばらくパソコンカタカタしてたら外が明るくなってきてて,ついでにねむかったので何も考えずにオフトンインしてた

起きたらこんなかんじで最高だった.

この日は適当にごはん食べに行って,

ついでに滝を見に行きました.

で,おうちにかえってきました.

何故か再上映されるプリプリ.百合は脳に良いんですよ.

アンジェさん,「歯止めが効かなくなる」じゃあないんですよ.最高か?いいぞもっとやれ.

色々な妖怪

妖怪は...います!

妖怪めしさらい

エビデンス

現代社

シンチョク

sprintf関数内で無限ループになってSEGVして落ちる,みたいなバグがあって,今回のキャンプではsprintfのアセンブリ読んでこれを解決するぞ!って思ってました. で,golibcの実装読んでsprintf内のラベルのアドレス調べてそこが実行されたらダンプする,とかやってたんですがどうもアドレスが違いそうな雰囲気. で,https://github.com/HariboteOS/tolset の中にいたgolibc.libを自分でビルドしたgolibc.libに置き換えて実行してみたら完全に動作してしまった,という. まあ動いたのは良かったんですが,元々のgolibc.libでビルドしたはりぼてOSはQEMUでは動いてくれるので,バグがあるのは事実っぽいので今度原因を探りたいですね. ただ,元々のgolibc.libはfileコマンド打ってもdataって表示されるのは一体...(tek圧縮でもされてるのだろうか?

花粉が無料で手に入る檜原村

謎の要望

感想

クソ楽しかったです.

ムラに帰りたい...

これは事実