カスタムキャストでキャストデータを移行する

アプリとしての出来が悪いままのカスタムキャスト

ドワンゴのVTuber戦略は相当不調らしい。 まぁ、「当然だな」という越えがおおかったりもするのだが、登場当初は非常によく遊ばれ、期待も大きかったカスタムキャストがいまひとつ普及していないのも、その現れなのかもしれない。

カスタムキャストは元はアダルトゲームのカスタムメイドがベースになっている。 あれは、エディット機能自体は優秀なものの、DMM版含め出来がよくないという評判がもっぱらなので、必然なのかもしれない。 ありとあらゆる面でいまひとつであり、そのひとつとして「引き継ぎ機能がない」というのが挙げられていた。

やがて引き継ぎ機能が実装されたのだが、著しい「コレジャナイ感」が漂っている。

ほとんどの人は引き継ぎたいのはキャストデータだと思うのだが、キャストデータは対象外、というか引き継げるデータはほとんどない。 キャストデータを作るのは結構時間もかかるし、再現するのは困難なので、キャストデータが引き継げないとそもそも使い物にならないと思うのだが。

データをコピーすればOK

説明にある通り、キャストデータは端末に保存されている。 保存場所はAndroid/data/jp.customcast.cc2/以下である。つまり、このフォルダ以下をコピーすれば良い。 幸いにも現在データチェックは甘く、キャストデータをピンポイントに上書きしなくても、必要なデータを再ダウンロードする形で通してくれる。

ただ、私が試した限りだとgvfs MTPの制限なのか、このフォルダ以下にコピーすること自体ができなかった。 ただし、ファイルの作成や上書きはできるため、

のようなシェルスクリプト(これはサブフォルダ用)で処理できた。 これ以上深いディレクトリの中身は放置して良いし、cache以下は気にしなくて良い。

Windowsユーザーはどうすればいいか、という話は私が取り扱うべき話ではないから、 このフォルダをコピーすればいいよ、という情報を元にがんばっていただく方向で。

「ZshからRubyにしたら速くなる」 その理由とテクニック

現在取り組んでいるプロジェクトで、パフォーマンスチューニングの一環として当初Zshで書かれていたスクリプトをRubyで書き直すことによって、60倍程度の高速化を実現した。 もちろん、単純に書き換えただけではなく、可能な限りfork/execをしないようにしたり、コストがかかる処理を最小にするなどの工夫を伴って手に入れた結果だが、「ZshでしていたことをRubyに書き換えた」だけでも相当な効果があった。

このパフォーマンスチューニングは単にプログラムを書くだけの人には生まれにくい発想である。 Unix、そしてLinuxのシステムや、プログラミング言語処理系に関する知識がないと考えられない要素が多いのだ。

そこで、この話を解説する。

「ZshよりRubyが速い」そのわけ

根本的な話として、Zshはそもそも遅い処理系だ。 「Zshが遅い」という話はZshのメーリングリストでもちらほら話をされる。 別にBashと比べて遅いということではないのだが(Bashもまた非常に遅い処理系だからだ)、状況によっては速度が問題になる程度に遅い。

Rubyも相当に遅い処理系であると言われていたし、実際かなり遅かったのは事実だ。 それでもZshに比べれば随分早かったのだが。

だが、それ以降、Rubyは高速化に取り組み続けている。対して、Zshはあまり高速化には取り組んでいない。だから、差が開いている。

しかし、理由がそれだけというわけではない。

Zshは純粋なインタープリタである。対して、Rubyはスクリプト言語ではあるがバイトコードインタプリタ型である。 この違いは、syntax errorが起きるタイミングが、Rubyがスクリプトを実行しようとしたタイミングであるのに対し、Zshはその行に到達したときであることからもわかる。

インタープリタ型であれコンパイラ型であれ、ソースコードを機械語に変換しなければならない、という点は変わらない。 その違いは方法とタイミングである。

インタープリタ型言語の場合、「1行ずつ(1コマンドずつ)変換する」のである。 その変換方法はもちろん処理系によって異なるのだが、Zshの場合、complex commandでも複数の文をまとめて変換することはしないし、ループによって繰り返される場合でも一度変換したものを使いまわしたりはしない。

対してRubyは、最初にコード全体を構文木に変換する。 RUby 1.8までは構文木インタープリタによってこれを実行していたが、Ruby 1.9以降はこれをさらにバイトコードに変換し、バイトコードインタープリタ(VM)によって実行するようになった。 バイトコードはRuby専用の機械語のようなもので、VMによって非常に小さなコストで実行できる。 Ruby 2.6からはJITコンパイラも追加され、部分的にCコードを生成し、これをネイティブコンパイラ(例えばgcc)によってバイナリコードに変換する(こともできる)。

これで1行だけのようなコードだとあまり差は出ないし、Zshでは1行だけどRubyでは何十行という可能性もあるので、このようなケースではRuby有利というわけではなくなる。 だが、ループで何度も同じコードを実行するような場合には非常に大きな差になってくる。 今回の場合、テスト段階で500回のループであったことから、大きな差になったということである。 だからループ回数が増えると倍率的にも速度差はさらに開く。

fork/execとコンパイルにかかる時間

Unix関連に少し知識がある人であれば、「forkはコストが重く遅い」というのを聞いたことがあると思う。

だが、この認識にはちょっと注意が必要だ。 というのも、C言語の速度から見た時に「forkする時間があればどれだけ実行できるか」という点を考えるとsystemで外部コマンドを呼び出すとそこだけ局所的に時間がかかる、という状況が発生する。

だが、実際にはfork(2)しても1000分の数秒にすぎない。 どちらかといえばそれよりもexec(2)のほうが重いのだが、それでもせいぜい100分の1秒程度だ。 だから、C言語で書いている場合ですらそれなりに長くなる場合はむしろ実行コストを省略できてコマンドを呼び出すほうが速かったりする。

昔のUnixではfork(2)はもっともっと遅かった。 現在のLinuxにおいてfork(2)が速くなったのはコピーオンライト形式であることの恩恵が大きい。 古典的なUnixではfork(2)は呼び出した時点でプロセスのメモリをコピーしていた。直後にexec(2)する場合はコピーしたメモリの内容は全く使わないのでかなりの無駄だ。

ところが、現在のLinuxにおいてはfork(2)によってメモリはコピーされない。共有されるのである。 そしてforkされたプロセスが共有されているメモリに対して書き込みを行った時に別に領域を確保してそれを変更する仕組みだ。

結果的にfork自体は一瞬に近くなっている。

そして、もうひとつ重要なのが「コンパイル時間」だ。 Rubyは起動時に対象スクリプトの変換を行う。 だが、この変換コストは速くなるに従って増加している。以前は構文木に変換するだけだったのが、1.9からはさらにバイトコードに変換する時間が必要になったし、2.6でJITを使うとさらにCコードを生成してそれをコンパイルする時間まで必要になっている。 つまり、Rubyはだんだん「実行は速くなっているが、実行に着手するまでは時間がかかるようになっている」のである。

これは、例えばechoであれば

% time /bin/echo > /dev/null
/bin/echo > /dev/null  0.00s user 0.00s system 79% cpu 0.001 total

ということになるのだが、Rubyだと空っぽに近くても

% time ruby -e 'nil'         
ruby -e 'nil'  0.04s user 0.02s system 59% cpu 0.089 total

結構時間がかかる。 つまり、一瞬で実行が終わるRubyスクリプトを何度も何度も繰り返して呼び出すと、トータルではかなり時間がかかるわけだ。 もともとのスクリプトは本体はRubyで、呼び出しがZshだったので、20並列で各500回、Rubyによるコンパイルがかかっていた。だから、かなりの時間がかかっていたのだ。

だが、「Linuxのforkはメモリが共有され、ほとんど一瞬で終わる」という点を利用すると改善の余地がある。 それは、実行可能なRubyスクリプトをライブラリ化する、という方法だ。

ZshからRubyを呼び出す場合、どうしてもRubyを呼び出すたびにRubyによるコンパイルをかけざるをえない。 当初は10000回コンパイルされていたのだが、500回のループをZshではなくRubyで行うようにすれば20回で済むようになる。だが、それでも20回のコンパイルが必要だ。

しかし、呼び出すスクリプト自体をRubyに変えてしまえば、実行しようとするスクリプトをライブラリとしてロードするという方法がとれるようになる。 ライブラリとしてロードすると、そのコンパイルは呼び出し元スクリプトをロードしたときに行われる。 もちろん、呼び出しの目的は呼び出すだけであり、直接そのライブラリの機能を使うわけではない。だが、この状態からforkすると、「コンパイル済みコードがメモリ上にあるRubyプロセス」が出来上がる。

この時点でスクリプトを実行する方法は「メソッドを呼び出す」(あるいは、その機能を果たすオブジェクトを作ってメソッドを呼び出す)だけである。 繰り返し呼び出すループを書くのも、単にRubyのループを書いて、そこで繰り返しメソッドを呼び出すなりオブジェクトを作るなりすれば良い。 呼び出し元スクリプト側では並列分だけforkしたあと、Process.waitallでもしていればいいわけだ。

これはZshに対して、「Rubyスクリプトのコンパイルが1度だけでいい」「execする必要がない」というメリットをもたらしている。 どちらも結構コストの高い処理であるから、繰り返し実行する場合は非常に大きなコストになり速度を低下させる。「処理自体は軽いのだが果てしなくループする」タイプのスクリプトに対してこの方法は本当に効く。 なぜならば、そのようなスクリプトに対してはコストの高い呼び出しをしているとコストのほとんどは呼び出しで占められ、実行コストは小さいためにスクリプト自体を高速化しようとがんばったところでほとんど無意味だし、逆に呼び出しコストを軽くすると劇的に速くなるからだ。

Powerlevel9k * モリサワフォント

Zsh * Powerlevel9k を使っていて、なおかつモリサワパスポートユーザーである人なんて多分この世に数えるほどしかいないと思うので、需要は限りなく0に近い記事を書かせてもらうことにする。

Powerlevel9kで使われるU+F015(ホームマーク)やU+F17C(Linuxマーク)はPrivate Use(外字)領域であり、 文字として定義されていない。 そして、モリサワフォントはこの領域を使用しており、U+F015は「言信」という文字(実際は一文字)に割り当てられており、 モリサワフォントを導入するとAwesomeフォント(Nerd font)に優先されてしまうため、有効に機能せず、文字化けしてしまう。

解決方法は結構シンプルで、FontConfigで

のようにしてNerd fontをprependするだけである。

この問題のハマりポイントは、「Nerd fontのグリフを持っているCicaを指定したときにNerd fontグリフ部分を使ってもらえない」ことである。 だから、Cica一本に頼っていた場合はNerd Fontを別途導入する必要がある。

Zshでの連続的呼び出しに環境変数を使ってみる (Zshのガベージコレクション)

Zshは極めて強力なシェルだが、大規模プログラミングにおいて使われることは少ない。 だが、Orbital designにおいてはシェルスクリプトは強力な武器だ。できれば積極的に活用していきたい。 そうなると、Zshにおいて明らかでない、あるいは公知ではないことと付き合っていかなければならない。

単純に言えば今回は

のような処理を行うスクリプトを、invoke_workerがファイルを読み込むのではなく、事前に読み込んでおくことでワーカーの処理時間を短縮したいということだ。

のようにしたいということだ。

だが、問題は「これがメモリを食いつぶさないか」ということである。

意図と効果

普通のスクリプトの場合、この方法はほとんど効果をもたらさない。もしかしたらマイナスになるかもしれない。

そもそもこれらの情報が「単純にファイルとして読み込むだけ」の設計になっているところも工夫のなせる技なのだが、必ずしもそのようにできるわけではない。 特にクラスタ仕様になっているとファイルアクセスが遅いかもしれないし、その違いを吸収するためにさらに別の方法をとるかもしれないのだ。

ワーカーは起動数も多く、当然ながら処理としては重い。 逐次実行されるワーカー部分であまりその処理を担わせたくない。 特に設定のほうは起動される全てのワーカーにとって共通である。 これを環境変数にするメリットは大きい。

Linuxのfork(2)はコピーオンライトだ。 configは文字列であり、起動されるワーカーではその文字列をパースすることになるから、この$config環境変数が変更されることはない。 つまり、この環境変数は実体はひとつであり、常に同一の実体が参照される。コピーされることもないので速度が上がる。ディスクIOとメモリへのコピーが2回目以降省略できるのだ。

ただし、環境変数で渡す文字列は「システムコールがCライブラリである」ためにC文字列(の配列)であり、\000が含まれていると文字列がそこで終わってしまう。 私は勘違いと慎重さを欠いたことから赤っ恥をやらかしてしまった。

データのほうは、ほぼ単純に、ワーカー実行中に時間がかかる(かもしれない)データの取得を裏でやっておきたい、ということである。 これも環境変数にしてしまえばワーカーはリード時間をとられない。所要時間の総量は変わらないが、裏でやることで逐次実行部分に含めることを避けるということである。

問題と検証

だが、これは

というのが100万回実行されるということだ。 しかも、これはループのたびに異なる値になる。

もしZshにガベージコレクタがなければ100万件のデータを抱えてしまうことになり、これはメモリ消費量的にまずい。

というわけで、「Zshは変数を上書きしたらメモリを開放してくれる(ガベージコレクションしてくれる)のか?」という疑問を解き明かす必要ができた。

この調査は割と簡単で

とし、

のようにしてメモリ消費量を監視すれば良い。

ちなみに、100Mを指定しているが、/dev/urandomは一度に読めるのは32MiBまでである。

80340
215640
80332
80332
80348
43344
80340
80340
80332
80332
215636
80340
80332

だいたい2倍程度と見ていいと思うのだが、ときどき3.5倍程度まで増加する。 ただ、だいたい2倍ということはかなり迅速にメモリを回収してくれている印象だ。

しかし、実際のワーカーはこんなに長時間実行はしないので、実際のワーカーの実行時間に近い感じにしてみよう。

108932
80340
195300
80340
215628
80340
211472
111616
80332
178644
43344
215644

回収しきれないタイミングが増えてメモリ使用量にばらつきは生じているが、回収ペースを上回ってメモリ消費量が果てしなく増えていくようなことはないようだ。

結論

  • Zshにはガベージコレクタがある
  • Zshでパラメータを上書きすると、ローカル変数か環境変数かによらず迅速にメモリは解放される
  • IOコストが高いなどで逐次的に実行するコストを削減したい場合、コントローラで環境変数にする作戦はなかなか有効

追加の注意点

フルスケールするように設計されているワーカーの場合、CPUコア数を使い切るだけワーカーを起動していると、結果的に裏で色々するためのコンテキストスイッチコストが高くついて全体では遅くなる可能性もある。 というか、ワーカーの実行がそれほど時間のかからないものであるならばwaitの時間は短くなり、waitの時間が短くなるほどスケール阻害要素としては大きくなる。

ウェブサイト全文検索システムの開発

開発経緯

NamazuやGroongaも試したのだが、いまひとつ望むものにはならなかったので、シンプルで美しい全文検索システムを書くことにした。

これは、第一にはGoogle検索に依存しているMimir Yokhamaの検索機能を自前で持つこと、 第二にはChienomiを含むWordPressのシステムの置換えである。

検索システムの開発自体はそれほど難しくないと思うのだが、どのように動作するのが望ましいかということを考えると非常に難しい。 Googleの検索システムは非常に高度なので、それに匹敵するものを作るのは難しいのだ。

だが、ここはPureBuilder Simplyにふさわしいシンプルなものを目指すことにする。

設計その1

とりあえず、grepを使えば話が早いのだが、HTMLだと余計な要素を含んだ検索になってしまう。 HTMLからタグを除去するのは難しくないが、どういうポリシーで除去するのか、いつどうやって除去するのか、などが難しい。

PureBuilder Simplyの構成から言えば、生成時に、Pandocで生成するのが望ましい。

$ pandoc index.md -t plain index.txt

だが、生成時に生成を全く無視してインデックスを生成するのはどうだろうか? そもそもPre pluginsはソースファイルを、Post Pluginsは生成したHTMLファイルを加工するものであるため、本来の目的から逸脱してしまう。 例えばPre Pluginsを使って

とかもできる。

ただ、今のところ検索対象になるようなソースファイルを加工するようなPre plguinsを使っていないため、別にこのようにする必要性はない。

設計その2

あとから処理するためのもの。 .indexes.rbm に基づいて処理を行う方式。

検索

いずれにせよここまでやってしまえば検索は簡単。 grepで検索できる状態なので、シンプルに検索可能。

AND検索の要領としては

ものすごく検索対象が多い場合は、検索対象そのものを絞り込んでいくほうがいいだろう。 だが、プロセス起動回数が増えることを考えると、そのような場合は自前実装のほうが良い可能性が高い。

OR検索はもっと簡単で

スペースの取り扱い方とか、case問題とか考え始めると難しい。 ただ、世の中そんな複雑な検索をしている検索エンジンはあまりないし、多分ローカルにそんなもの作ったところで報われないのでこれくらいでいいような気もする。

ANDまたはORではなく自由にANDとORを結合できるようにした場合は、expr自体に評価できるメソッドを追加すると良い。例えば

といった感じである。

あとがき

検索機能の実装自体は難しくないのだが、ChienomiをPureBuilder Simply化するという話になると結構難しい。

既にかなりの記事があり、検索からの流入も多いため、どうしても全記事に対してマップせざるをえない。 これもなかなか面倒だ。

だが、もっと問題Chienomiの記事は書き方が一定でない、ということだ。

Chienomiの記述形式はPOD, RDoc, ACCS2, PureDoc, PureDoc2, PureDoc2::Markdown, Pandoc Markdownがある。 PureBuilder SimplyはPandocでの処理を前提としているため、なんとかしないといけない。

過去記事については諦める方針ならばHTMLとして抜き出すという方法もあるのだが(Mimir Yokohamaでウェブサイトのサルベージでよく使う方法だ)、 できれば避けたいというのもある。

また、タグとカテゴリのつけ方が一定ではないため、これを処理しなければならない。

さらに厄介なのがメディアファイルだ。 WordPressはメディアファイルの使い方が独特だし、そのためにメディアファイルについてはWordPress上で追加する方法をとっていた。 さらにサイト移行時にメディアファイルを紛失したこともあって、結構大規模な作業になると思う。

そのことを考えると一筋縄ではいかない。

それはともかくとして、サイトの検索で非常に複雑な演算子を使いたがる人はまずいない、 どころかサイト内検索なんてほぼ使われていないに等しいので、基本的な検索機能で十分だと思うのだが、それであればこの通り実装はとても簡単だ(例によって設計で稼いだ感があるが)。

というわけでちょっとした実装例、そしてシェルスクリプトサンプルとして役立てば幸いである。

Linux zsh/デュプレクサ/ssh設定の勘所

ここのところ大作をいくつも書いているため、忙しさも手伝ってなかなかアップロードできない。 この話もLinuxを使えるようセットアップする話をまとめようと思っていたのだが、それはあまりに時間がかかってしまうので、かいつまんで解説しようと思う。

世の中にはLinuxをインストールだけ繰り返すという人もいるのだが、だいたいそういう人はセットアップをしない。

1台だけのコンピュータを使う人、というのも、実はLinux手練(というよりも達人)の中でも結構多いのだが、1台だけ使っているうちにはその中で順次セットアップを煮詰めていけば良いのだが、Linuxは複数台使ってこそその真価を発揮するし、そうなると素早く適切にセットアップすることが求められる。 特にConoHaでインスタンスを立てたり閉じたりする場合にはなかなか重要だ。

ここでは頻繁にセットアップを行うがまだ手順を確立していない人、あるいはセットアップ自体確立していない人のために私のコツをご紹介しよう。

なお、ここでは前提としてManjaro Linuxあるいは(サーバーにおいては)Arch Linuxをセットアップする前提にあり、その中で極力少ない労力でセットアップしようとしている。 基本的な方針は他のディストリビューションでも応用できるはずだが、労力の多寡に関してはこの限りではない。

また、シェルはZshを使っていることを前提としている。 Bashを使っている人はZshに乗り換えてしまえば良いと思うが、Fishを使っている人に関しては私はわからないので留意していただきたい。

初期セットアップに関して

とりあえずアップデートして再起動

# pacman -Syu
# reboot

vimがないと設定に困るのでvimを用意する。 viも別パッケージであるのだが、むしろ不便なのでシンボリックリンクにする。 vim-pluginsが入っていればだいたい良いので、一緒にいれておく。これでvimで苦痛を感じることなく使うことができるようになる。 (デスクトップではvimではなくgvimを入れる。そうするとXセレクションを扱えるようになる)

# pacman -S vim vim-plugins
# (cd /bin; ln -s vim vi)

設定ファイルをViなんかで書けるか! Emacsにしろ! という人はEmacsも入れる。 私はEmacsを使わないのであまり詳しくない。 こちらもデスクトップではemacsパッケージを入れる。

# pacman -S emacs-nox

ここで一般ユーザーを作っておく。もちろん、Manjaroでは必要のない作業。 Manjaroでは一般的なデスクトップユーザーに追加すべきグループが多いので留意する必要がある。

# useradd -m -U -c "First User" -s /bin/zsh -G wheel,storage,sys,network luser
# passwd luser

wheelグループにsudoを許すようにする。 $wheelの行のコメントアウトを外す。NOPASSWDになっている行ではないほうが良いだろう。

# visudo

Zshをログインシェルにしたが、まだ設定していないのでbashで入る。

# sudo -u luser bash -l

AURを扱うのであればとりあえずyayを入れるのがお勧め。 Archでも2パッケージで済むからだ。それにタイプ数も少ない

$ sudo pacman -S go
$ git clone 'https://aur.archlinux.org/yay.git
$ cd yay
$ makepkg
$ sudo pacman -U yay*.pkg.tar.xz

あとはほしければTrizenでも入れておけば良い。 yaourtとpacaurは「安全ではないソフトウェア」になりつつあるらしいので、とりあえずお勧めはしない。

$ yay -S trizen

w3mとlvがあればとりあえず文書を読むのは楽になる。 コンソール作業する場合は必須

$ yay -S w3m lv

ターミナルマルチプレクサを入れる。Powerlevel9kはGNU Screenで位置がバグる問題があるので、ここでtmuxを入れておく。 一応、screenも入れておく。

$ yay -S screen tmux

Moshは便利だと思うけれど、私はUDPを透過するファイアウォール設定をしたくないため、ここではMoshの話はしない。

Zshとターミナルマルチプレクサ

とりあえず

私が新インスタンスに対して最初にすることは、Zshを導入しセットアップすることである。

ZshからFishに変えた、あるいはZshが使えなくてBashがいいという人の多くはZshのセットアップができていない。 ディストリビューションに良いZshの設定が含まれていることは稀だし、Zshの設定は非常に多くて難しい。 マニュアルを読んで設定を作り上げてこそなのだが、それをしない人が圧倒的に多い。 (似たようなことはVimにも言えるが、Vimの場合はそれが気になるケースは少ないかもしれない)

実は話は実に簡単で

$ sudo pacman -S grml-zsh-config zsh-completions

これで再ログインすれば立派に使えるZshが出来上がっている。

grmlの設定は非常に練られていて、多くの場合これで十分だろう。 (場合によっては調整がいるかもしれない)

なお、Archのgrml-zsh-configはskelが含まれているのだが、Manjaroは含まれていない。 skelのほうは便利ツールがコメントアウトされているものなので、別になくても構わない。

なお、Zshの設定ファイルに日本語を使うとサーバーではトラブルのもとになるので注意してほしい。

オプション

だが、もう少し練ることにしよう。 まず、grmlの設定ではAUTO_CONTINUEが有効ではないので、間違ってフォアグラウンドで起動してdisownしたあとSIGCONTをわざわざ送る必要がある(実際はこのケースではbgしてからdisownするほうが良い)。

重複する部分が多いが、重要なオプションは設定しておこう。

私は次も設定しているが、多分いらない。(RC_EXPAND_PARAMはgrmlではオフかも)

シンタックスハイライト

プラグインの中では便利なもの。 ただし、いくつかのオプションが制限される。

% sudo pacman -S zsh-syntax-highlighting

履歴の機能を拡張

grmlの履歴機能はhistory-beginning-{for,back}ward-endを採用している。 これは、「コマンド部分は途中ならその位置、コマンド部分が入力されていればその部分を維持し、カーソル位置を末尾としてヒストリをたどる」というものだ。

だが、個人的にはオプションも含めてカーソル位置まで維持してくれるほうが好きだ。 全面的に書き換えるのではなく、PgUp/PgDown時はカーソル位置を維持してヒストリをたどるようにする。

本来は記述が足りていないが、この内容はgrmlを前提としている。

履歴を残す量も設定しておこう。 HISTSIZEは検索で辿れる量、SAVEHISTはファイルに残す量だ。

viモード

私はviモード使いなので、設定しておく。

なお、逆にEmacsキーバインドで使いたい人で、EDITORvivimnvimにしている人はちゃんと設定する必要がある。

ターミナルマルチプレクサ

SSHの場合は切れないとか、セッション増やしたいとかだいたい起きるので、使用させることにする。

なお、これでtmuxの設定で

set -g default-terminal "xterm-256color"

とかすると地獄をみるので絶対にしてはいけない。 必ず

set -g default-terminal "screen.xterm-256color"

または

set -g default-terminal "screen-256color"

とすること。

なお、私はGNU Screen使いなので、tmuxのキーバインドはscreen互換にしてある。

プロンプトとテーマモード

私は普段はgrmlプロンプトテーマを使っているが、SSHではPowerlevel9kを使っている。 これは、見やすく、わかりやすいため。普段から使わないのはプロンプトが戻るのがちょっと遅いからだ。

% sudo pacman -S zsh-theme-powerlevel9k awesome-terminal-fonts powerline-fonts

私はテーマ読み込みにこんなことをしている。

前述の$_DEFAULT_SHELLMODEはこのためのものだ。 だが、常にPowerlevel9kで良いのなら、別にロード部分を直接書いてもいい。

grmlと競合してしまうので、prompt offすること。

私の設定はこんな感じ。

このあたりは好みなのだが、実はPowerlevel9kの公式マニュアルにはあるが動かないものというのが結構合ったりする。 典型的には$POWERLEVEL9K_SHORTEN_STRATEGYは多くがうまく動かない。

ポイントになるのが、プロンプトにcontextを使わずuser hostと分けた上でホストのREMOTEのみ色を設定していること。

基本的には「ローカルの場合はどのマシンでも同じ色でいいが、リモートの場合はどのマシンか判別できたほうがよい」と思う。 別にこれ以外のプロンプトテーマでもホスト名は出しているのだが、現在作業中のホストを勘違いしてやっちまった、ということはしょっちゅうある。

まずホスト名に一貫性があってわかりやすい名前をつけることが大切だ。

% sudo hostnamectl set-hostname thinkpad-x1

私の場合は花の名前をつけることにしている。 実はこれは1993年の出来事に由来しており、運用は1998年から、と私としてはとても歴史がある。

さらにメリットとして花なので、色が連想できる。私は$POWERLEVEL9K_HOST_REMOTE_{FORE,BACK}GROUNDはその花の代表的な色をモチーフにした色使いにしている。 それぞれのマシンでイメージが離れた花の名前をつけているため、色被りも少ない。

簡単でわかりやすいのは、機種名とケースの色だろうか。VPSは難しい。

なお、

vi_modeを正しく表示するために必要な部分。

SSH

基本的なSSH

とりあえずroot鍵を登録してパスワード認証は閉じる。

まずはログインするほうでssh-keygen -f <file>によって生成した.pubのほうのファイルを ログインされるほうの~root/.ssh/authorized_keysにコピーする。

なお、.sshはパーミッション0600であること。

このroot鍵を登録するステップはサーバーに対するもので、直接ログインできるのであればスキップすべき作業である。

そして/etc/ssh/sshd_config (ssh_configではない!)を

PasswordAuthentication no

としておく。 この時点で一旦リロード

% sudo systemctl reload sshd

同じ要領でユーザー鍵を登録する。 鍵そのものも分けたほうがいい。

% ssh-keygen -f server-luser_rsa
% rsync -e "ssh -i server-root_rsa" server-luser_rsa.pub root@server:/home/luser/.ssh/authorized_keys
% ssh -i server-root_rsa root@server "chown luser:luser -R /home/luser

以降のために~/.ssh/configに設定しておく。

Host server-luser
  User luser
  Port 22
  HostName server.example.org
  IdentityFile ~/.ssh/server-luser_rsa

これでssh server-luserとして入れるようになる。

なお、HostNameだが、LANで同じセグメント内にいるのであればZeroconfによる.localを使えばいいだろう。 あるいは、各マシンを固定アドレスとして/etc/hostsに書いておくというのも手。 /etc/hosts上の名前は1マシン1つではなく、役割ごとに名前をつけておくと、その役割が他のマシンに移ったときにあまり苦労しなくて済む。dnsmasqで配るという方法もある。

SSHに関する話は以前にしたので、応用技としてはそのあたりを参考にしてくれると良い。

いざというときのための暗号化経路

なにかのときのため、ネットワークごとに1台は透過的にアクセスできると良いだろう。 これはいくつかの方法がある。

最も簡単なのは、Socksプロキシを使うことだ。

% ssh -TND 4711 -o ServerAliveInterval 10 -o ServerAliveCountMax 3 luser@server

これでlocalhost:4711をSOCKS5プロキシとして使用すればSSHサーバーを経由してアクセスすることが可能になる。 これは、ウェブブラウザやメールクライアントで有用である。これは公衆Wi-Fiからアクセスする程度の場合に有効だ。

もうひとつは、SSH経由の環境から利用できるようにしておくことだ。 w3mやMutt, Vim, Emacs, lvなど端末から利用できるアプリケーションを一通り揃えておけば、GUIは使えなくてもひととおりの作業が可能だろう。

本当にそのネットワークを通じてアクセスする必要が生じた場合はどうだろうか? 私はそんなサバイバルな経験を何度かしているが、普通の人はあまりない。 常時必要とするのであればVPNを用意しておけば良いのたでが、緊急避難的に使用できるようにしておくと何かと便利だ。

まずは双方にpppをインストールしておく。

% sudo pacman -S ppp

ログインするサーバーに対してはパスワードをかけたコマンド用rootキーを使うのが最も確実で安全。

command="/usr/sbin/pppd nodetach notty noauth",pty,no-X11-forwarding,no-port-forwarding,no-agent-forwarding ssh-rsa ...

さらに実際に使うときにログインした上でフォワーディングを許す。

# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

そしてつなぐ。

% sudo pppd updetach noauth silent nodeflate pty "sudo -u luser ssh server-ssh-ppp" ipparam vpn 192.168.32.1:192.168.32.2

192.168.64.0/24に対してアクセスできるようにしたい場合:

% sudo ip route add 192.168.64.0/24 via 192.168.32.1

すべての未知のホストにこの経路でアクセスしたい場合。サーバーのアドレスは10.0.8.1、現在のデフォルトゲートウェイは192.168.1.1だとすると:

% sudo ip route add 10.0.8.1 via 192.168.1.1
% sudo ip route replace default via 192.168.32.1 proto static metric 101

シェルスクリプトで並列処理

なんだか検索件数が多いので、シェルスクリプトによるコンカレンシーのお話をしよう。

ただし、bad design (変数を書き換えるとか、相互にやりとりするとか)は除外する。

また、Zshを前提とする。

投げっぱなし

まず基本。投げっぱなしはとても簡単。

シェルスクリプトではジョブコントロールは無効になっているので、SIGHUPの送信はなされないので、さっさと終了してしまっても大丈夫。

処理の終了を待ちたい場合はwait

flock

flockを使う方法は簡単でシンプル。 ロックファイルを使ってファイルデスクリプタを開きっぱなしにし、そのファイルデスクリプタを指定してロックする。

まずファイルデスクリプタ9.lockファイルをライトモードでオープンする場合

そしてファイルデスクリプタ9を閉じる場合

これを利用するとこんな感じ。

ロックしている間に共有しているリソースの読み込み/変更を行い、ファイルデスクリプタを閉じる。

リソースを読むより簡単な方法は、ひとつのストリームを共有したファイルデスクリプタとして開き、 ロックを中に読むことである。

ワーカーを生成するサブシェルの標準入力はqueueファイルにリダイレクトされている。 そのため、ファイルデスクリプタ0queueファイルなのだが、そのサブシェルの子プロセスであるワーカープロセスはリダイレクトしていないため、このファイルデスクリプタが共有される。 結果、全てのワーカーはqueueファイルを標準入力とするのだが、ストリーム自体を共有しているため、どのワーカーが一行読んだとしてもストリームの位置が変更され、次に読み込む位置は他のワーカーにとっても変更される。実際

WORKER 1: foo
WORKER 2: bar
WORKER 3: baz

となる。

producer-consumer キュー

もっと凝ったことがしたいのであればUNIXドメインソケットを使ってproducer部分をシングルスレッド化することができる。

zsocket -lのタイミングで接続を受け付けているのだが、zsocket -lしていないタイミングでは接続しようとするプロセスをブロックするため、producer側の処理は直列に行われる。

双方向性があるときはproducerと直接やりとりできるのはメリット。

Orbit designの場合

私が採用しているOrbit designはレギュレーターはZshスクリプトなので、基本的にこのような並列化手順をとっている。 とはいえ、ものによっては直列(serial)になっていたりする。

ただ、並列化されているものが多い。ワーカープロセスは最も多いもので5。

基本的にワーカースクリプトが受け取るのは処理対象ID(ほとんどの場合ファイルパス)だけである。 それ以外の情報はスクリプト側で生成するか、別途取得するかする。

Mimir Yokohamaに「いいね機能」「コメント機能」を追加

概要

Weekly 10000PVを達成して機能強化に力の入っているMimir Yokohamaのウェブサイト。

連続の機能強化でついに「いいね機能」と「コメント機能」が追加された。

実は先日の「お問い合わせフォームの実装」は単にその機能を実装する最小限ではなく、簡単なアプリケーションを実装できるプラットフォームになっており、 アプリケーションを追加する条件が整っていたのだ。 また、そのためのテストもしてあった。

そのため、実は今回コード追加はわずかで、両方合わせても23行ほどにとどまる。 ごく簡単だが、確証が持てないためにテストと本番環境のための修正を行ったりして結構な時間がかかった。

これに関してはみるべきところはあまりない。 受け取ったパラメータをファイルに書き込めば良いだけだからだ。

ちなみに、連打しやすいアプリケーションを入れるために連打の対策もサーバーにしてあった。 実は先のパフォーマンスチューニングはこの対策によってパフォーマンスが低下してしまったため、これをカバーするついでに行ったものだった。

いいね機能の設計

いいね機能はごくシンプルだ。

Pandocテンプレートを使ってページタイトルを埋め込むことができるので、これだけ使うのであれば単にテンプレートの中にフォームを書けばいいだけ、ということになる。

実際はリファラ(Rack::Request#referer)及びユーザーエージェント(Rack::Request#user_agent), IPアドレス(Rack::Request#ip)も特定に使用している。

ポイントは「一度送信したら表示を変更、送信を無効化する」ということだ。

inputタグのdisabled属性を使うことで送信ボタンを無効化している。

そう、この機能はHTML上でインラインで書かれているのだ。 このような書き方はW3C的には推奨されないのだが、Googleは推奨している。 実際、これだけのためにJavaScriptファイルをロードさせることをしたくなかったので、インラインにした。

ポイントは

  • Legacy DOMにおいてフォーム部品は連想配列のようにアクセスできるようになっている
  • submitボタンのラベルはvalueである
  • disabledによってフォーム部品を無効化できる

である。

これらの処理は送信の「前に」行われる。 これは正しいことではないが、問題はない。 なぜならば

  • 送信できなかったからといってユーザーが修正するなどの手を入れる余地はない
  • 特に返信を必要とするものでもないので、送信失敗はクリティカルな問題でもない
  • サーバーエラーなどは表示されるようになっている

からだ。

また、画面変遷せずに送るだけ…というと、Ajaxで非同期に送るしかないように考えるかもしれないが、 実際は現代のブラウザは基本的に2XXステータスで空コンテンツを返すとページ変遷しないようになっている。

このような用途のために204(No Content)が用意されているため、204を返す仕様だ。 できるだけブラウザの標準機能に頼るようにしている。

このボタン、めっちゃgooglebotが押してくる…

コメント機能の設計

公開されるものではなく、sanitizeしなくても問題が発生しない設計になっている(単に文字列として扱う以上の取り扱いがなされる条件で使用しない)ため、非常に楽だ。

難しく考えるよりも、シンプルで挙動をちゃんと把握できていて、余計なことをしない方法をとるのが最も楽に、確実に、バグなく設計できる。

ただ、この機能に関しては「コメントフォームの表示」などが必要になり、JavaScriptが必要になった。 また、コメントするというあまりとらない行為のための部品であり、常にロードすることは非常に好ましくない。

そこでとった方法は「JavaScriptの遅延ロード」であり、「クリック時にelementを追加してJavaScriptを読み込む」という方法だ。

これでscript要素を追加している。

では呼び出されたあとどうしているのか…というと、こんな感じだ。

そう、コメントフォームは標準でHTMLに含まれていない。

パフォーマンス的にみても親切機能のためにもう重くなりつつあるドキュメントをこれ以上重くしたくないので、 「フォーム部分はJavaScriptがロードされたときにinnerHTMLで書く、という方法をとっている。

「クリックされたときにはじめて必要とされるのでドキュメントノードを追加してロードする」という手法は稀に使われるが、さすがにそれでHTMLドキュメントそのものを生成するというのはまず見ない手法になっている。

連打されたときのことを考えて、clickイベントを発生する値に特殊なプロパティを埋め込み、何度も実行されないようにしている。 なお、これは本当に連打したときだけ機能するもので、JavaScriptシングルスレッドなので一回このスクリプトに入っていまえばこのスクリプト中に割り込まれることはない。 だが、連打されるとイベントがキューに入ってしまうので何度も実行されてしまうことから、そうしたことがないようにしている。 シングルスレッドなので、このスクリプトが実行されているのにプロパティが設定されないうちにまた実行されるということはない。

元になるフォーム自体は存在していて、submitボタンを配置すればフォームの送信は可能だ。 そのため、submitイベントに対するイベントリスナーを設定するものはHTML上に静的に存在している。

その上で「フォームはやっぱり閉じられたほうがいいな」ということでボタンクリックに対するイベントの変更、及びボタンラベルの変更を行っている。

送信を行った場合はもうコメントフォームは使わないので、コメントフォームは非表示にして(削除はしていない)ラベルを変更している。

ラベル変更だが、input部品とは違ってbutton要素は子要素テキストノードがラベルになっているので、dataプロパティの書き換えによって変更している。

もともとHTML上でLevel0 DOMイベントを使っているので、スクリプト上でもLevel0 DOMによってイベントを変更している。 いつもaddEventListenerを使っていたので、珍しい。 イベントの削除はイベントにnullを代入するだけだ。

なお、HTMLで全て含めてしまえばJavaScriptは排除できるのだが、これ以上余計な要素を組み込むことはできれば避けたいためこのような仕様になっている。既にDOMコンパイルは割と重い。

また、デザインポリシーからいって、多くの場合余計なコメントフォームを常に表示させておくというのは美しくないとも思っている。 JavaScriptを使わずCSSでオンオフするようにもできるが、そうすると今度はボタンのテキストを変更するのが難しいし、連打や再送信を防ぐのも難しい。

このことから、なにがなんでもJavaScriptを使わないのが正義、ということでなければ、 このような付加コンテンツはユーザービリティの点からも素直に使うべきだと思う。

こちらもいいね機能同様、送信する前に状態を変更してしまい、成功すれば204を返す仕様。

Legacy DOM と DOM Level0 Eventに関して

Legacy DOMやDOM Level0 Eventについて意見をもとめられることがたまにあるのだが、私としてはあまり勧められないと考えている。

非常に簡単なので学習にはいいが、Legacy DOMはHTMLの構造に依存する。例えば

として、

とかやってしまうと、ドキュメントの構造が変わるたびに修正だ。

だが、「フォームにのみnameで使い」「フォームはW3C DOMで特定する」のであれば悪くない。

DOM Level0 Eventはイベントリスナーが1つしか登録できないためモジュール設計になっている場合や、なんらかのライブラリを使っている場合は使ってはいけない。 イベントを「追加」する場合はLevel2で、イベントを「設定」する場合はLevel0という使い分けも考えられる。 HTMLに直接書く場合はLevel0しか書けないので、その部品の基本的な動作と定義されているならLevel0でもいい。

ただし、その場合でもできればLevel2 Eventを「後から追加する」のが適切なので、DOM Level0 Eventの使いどころは今回のようなものが唯一だと思う。

先のシェルスクリプトを形にしました

一時キーボード無効

Temporary Disable Keyboard @GitHub

Xinputを使用してデバイスを無効/有効にするためのもの。

主な変更点は次の通り

  • 無効化を「時間制」「ダイアログ」「無限」から選択できるようにした
  • Zenityダイアログを若干調整
  • ランチャー用の.desktopファイルを追加

Zshスクリプトだが、case内で非常に珍しい;&(フォールスルーする)を使用している。

ターミナルエミュレータ選択機能

Terminal Selector @GitHub

主な変更点は次の通り

  • ランチャー用の.desktopファイルを追加
  • KDE Service用の.desktopファイルを追加
  • Nemo用の.nemo_actionファイルを追加
  • 対応する端末を大幅に増加
  • 利用できない端末を選択肢から除外するように変更
  • Zenityダイアログを調整
  • 柔軟に端末を追加できるようにファイルマネージャでの起動用の引数対応が連想配列で使用できるように変更

連想配列を使用するための方式は次のようなものだ。

わざわざ連想配列をテンプレート文字列とし、そこから配列に変換している理由は

  • 連想配列に格納できるのは文字列のみ
  • 置き換えしてからではDIRがIFSを含む可能性がある

【検索ワードに応えて】 ThinkPad X1 Carbon (2017, シルバー) のお話, Linux関連, その他

久しぶりの検索ワード反応企画。 ThinkPad X1 Carbon関連の検索が多かったので、併用されたワードに従ってコメントさせていただくことにする。

なお、ThinkPad X1 CarbonについてはYouTube (はるかみ☆ チャンネル)で開封動画を掲載させていただいているので、よかったらそちらもどうぞ。

また、そのほかLinux関連の検索にも回答させていただく。

ThinkPad X1関連

基本的なレビュー

ラップトップをガリガリ使うモバイラーなら持たない理由が見つからない。

XPS13のような13.3インチの中でも小型のものを除けばボディは13.3インチと変わりないサイズだ。 しかし14インチの画面は明らかに見やすく、作業もしやすいし、人に画面を見せるときにも良い。

そして非常に軽量でバッテリーマイレージも素晴らしい。 もちろん、キーボードはあらゆる現行ラップトップの中で最高だと思う。

唯一欠点としては天板の外板が弱い。 既に凹み、割れがある。それほど目立たないし、動作には問題ないのだが、ちょっとカナシイ。

買い時について

「高性能」「最先端」などを意識したい場合はリリース間もない頃が良い。

リリース直後は割引はなく、およそ半年程度で30%程度の割引になる。モデル末期は40%を越える程度の割引だ。

基本的にはThinkPadの場合30%程度割り引いた状態で競争力のある通常価格で、割引のない最初期というのはフリーク向けと考えられる。 なので買い時を気にするような人なら直後はないだろう。

春頃には30%前後の割引になっていたりするから(現時点でサイト公式のクーポンが28%、恐らくメルマガや店頭クーポンならもう少し行くだろう)、それぐらいが買い時ではなかろうか。

少しでも安く買いたい人は、翌年モデルが発表されてから決めるといい。 その頃にはかなり安くなっているし、在庫が残っていれば翌年モデルが出てからでも安く買える。 翌年モデルを待つべきかどうかの判断も出来てお得だ。

2017と2018に関しては、X1 Carbonとしての進化は微々たるものだったけれど、第8世代プロセッサになったという点がとても大きい。 ただ、私はかなり安く買えたので、そのタイミングでよかったと思う。

シルバーのThinkPadについて

良いと思う。

ThinkPadらしくないという批判はあるだろうけれども、マットだけれども黒のピーチスキンよりもサラッとした手触りで汚れもつきにくく目立たない。

シルバーのラップトップはそれなりに存在するので目立たないということは言えるけれども、「Hacker’s itemたるThinkPad」と「美しくおしゃれな高級ラップトップ」を両立させる意図は十分に達成できている。

控え目にいっても最高にかっこいい。

国産と中国産について

何も違わないから安心してほしい。 400万円するようなP920でも中国産だ。

なお、納期はかかる。X1は予定納期よりも遅かったという人が珍しくないようなので注意してほしい。

その他の検索ワード回答

シェルスクリプトの並列実行

基本的な形式は次のとおり

シェルスクリプトの並列実行は待ち合わせず投げっぱなしにするのが基本。

ただし、どうしても待ち合わたい場合はwaitを使う方法もある。

とした時、$!でサブシェルのPIDが取れるので、

としておけば待ち合わせる必要があるタイミングで

とすることができる。これはBashでもZshでも共通。

入出力をやりとりするのであれば、下流のパイプに流すべきで、親プロセスが出力を披露ようなことは考えないほうがよい。

どうしてもであればファイルに書いてwaitするか、もしくはZshならProccess Substitutionを使用する。

あるいは大量の処理があり、複数のワーカーを走らせたい場合はflockを使うのが無難だろう。 例えば以下のようにする。

要点は以下の通りだ。

  • 関数workerが各ワーカーが実行する内容
  • これをサブシェル内でworker nの形で実行する
  • ファイルデスクリプタはクローンされるので、標準入力から読んだ場合、親シェルもサブシェルも同じものを読み進めるし、位置も同時に変化する
  • しかし、もし同時に読んでしまうとおかしなことになるので、読んでいる間は他のシェルに読んでもらっては困る
  • そこでロックファイルを作り、これをロックすることで排他制御する。いわゆるドットロック。
  • exec 9>| .lockでファイルデスクリプタ9番をロック用に確保
  • 開きっぱなしになるので、flockでこのファイルをロック
  • ロックを獲得できたら標準入力から読む
  • 読み終わったらファイルデスクリプタを閉じてロックも解放
  • これでキューから1行読めたので、処理を進める
  • 「1行では足りないよ!」という場合、エントリをファイルに書いておいてディレクトリにまとめ、キューはファイル名にするとかすれば良い

AMD APU (Godavari/Kaveri) と Linux

特に問題はない。

以前はCatalystドライバのおかげでずいぶん苦労させられたけれども、 AMDGPUになって以来目立った問題は発生していない。

割と電気を食うけれど性能は微妙なので嬉しくはないと思う。 コストパフォーマンス的にみれば、これくらいの性能がおいしいという人は多いと思う。 ビデオ関連も充実しているし、Killerシリーズなんかは機能も充実しているしね。

XMPP

ちょっと話題が広すぎて何を求めているのかがわからない。ごめんよ。

DPI

これかなり広い。

LinuxでのHi-DPIの話なら/etc/X11/xorg.conf.d/以下にモニターの設定ファイルを書く。 40-monitor.confとかで。

Section "Monitor"
    Identifier             "<default monitor>"
    DisplaySize            286 179    # In millimeters
EndSection

で、KDE Plasmaを使うといい感じになる。 Plasmaを使わない場合については、Qtアプリケーションについてはなんとかなるけれど、GTKに関してはうまいことスケールしない。

LightDMに関してはGreeterの設定ファイルにxft-dpi=と書きましょう。

Hi-DPIはLinuxでは結構苦手にしている感じ。

フォントの設定はまた別。

某人物について

コメントする気はありません。

VP9のハードウェアエンコード

  • Intel QSVを使ってください
  • LinuxならVA-API経由ffmpegが良いよ
  • ただし画質は絶望的だったとは言っておく

Intel QSV * H.265

  • LinuxならVA-API経由ffmpeg
  • 速度はそこそこ。X.265とは雲泥の差。CPU負荷は0ではないというか、普通に40%くらいはいく
  • ちゃんとVA-APIドライバ入れようね

scale_vaapi

VA-APIを使用する場合の出力画面サイズ指定。 変更しない場合は省略して大丈夫。

AMD VCE / NVIDIA NVENC

VCEはLinux的にはVA-API経由。なのでQSVと一緒。

ただし、AMDのビデオドライバはVA-APIだけじゃなくVDPAUも使える。 ところがVA-APIがエンコード/デコードなのに対してVDPAUはデコードのみ。

VA-APIをVDPAUに転送するドライバ(libva-vdpau-driver)と、VDPAUをVA-APIに転送するドライバ(libvdpau-va-gl)があり、 VDPAUを有効にして、VA-APIに転送するドライバを使ってしまうと(Nvidiaの場合はVA-APIが使えないのでこうする)デコードのみになってしまって使えない。

ちゃんとlibva-mesa-driverを使いましょう。

Nvidiaの場合はVA-APIをサポートしておらず、VDPAUはエンコードができないので、 NVENCは専用のインターフェイスになっている。

どっちが優れているというのは難しいけれど、Nvidiaのほうが対応フォーマットは多い。

DiscordとSlack

基本的にはDiscordがいいと思うし、最近はSlackも微妙だと思うのだけれども、「両方あると嬉しい」という面もある。

Discordの場合「ユーザーという概念がある」ということが大きい。

Discrodでつながると、どのようなつながりであれ、「その人」というのが見えてしまう。 Discordは通知をカスタマイズできないため、「通知をオンにしている全ての人からの通知が一律に行われる」ということになる。 棲み分けをする方法がない。

これはLINEと同様の問題である。 恋人だろうが、ゲーム仲間だろうが、仕事の人間だろうが、区別する方法がないのだ。 アカウントの切り替えは難しいためアカウントで分けるのも現実的ではないし、アカウントで認識されているから一時的な連絡先にもしにくい。

Slackの場合はやりとりもつながりもあくまでそのチーム内でのことなので、仕事の関係などであればSlackのほうが便利だ。

自前メールサーバーからのメールをGMailが受け取らない

主にはホスト認証の関係。

GMailは送られてきたメールサーバーが、本当にそのメールを送る資格があるかをチェックする。

設定方法はいくつかあるけれど、SPFレコードを書くのが楽。 「メール SPF」で検索すると色々出てくる。

LinuxとRealTek ネットワークカード (RTL8152ほか)

ASIXよりはマシだけれど安定して苦しめてくれるRealTekのネットワークカード。

Linuxではネットワークアダプタは

Intel > Atheros (Killer) > Broadcom > RealTek > Asix

だからね。

RealTekのWiFiモジュールであるRTL8152のドライバはカーネルモジュールとしてある。 Arch Linuxの場合はDKMSになっていて、AURからインストール可能。 場合によってはRTL8153をブラックリストに入れる必要がある。

インストールしなくても動作はするけれど、うまく交信できなくなったりする。 安定性の面から言えば入れるべきだけれど、入れたところでうまくいかない場合もある。

「うちのディストリビューションにはないよ!!」という方。 Archにおいで。むしろManjaroにおいで。