Linuxで プロセスごとにネットワークを禁止 / インターフェイスを限定

特定のプロセスをオフラインにする

稀にネットワークを禁止した状態で利用したいことがある。 例えば安全性に疑問があるケース、無用な通信が疑われるケース、ファイルをダウンロードできているかの確認などだ。

方法としては

  • cgroupsを使う
  • iptablesを使う (EUID/EGID単位なら制御可能)
  • SELinux + iptables を使う

の3種類。

単純にネットワークを利用できないようにするのはunshare

$ sudo unshare -n w3m /some/text/file

環境変数とかXAuthorityとか面倒なので、Firefoxなどを実行するならsudoでrootにしてsudoで戻すのが勧め。

特定のプロセスを特定のゲートウェイから流す

これだけだと「なんだよ」とか言われてしまうので、もうちょっとまともな話をしよう。

SSH+pppdを使ったVPNは比較的知られているが、VPNはプロキシを通すのに使うか、デフォルトゲートにしてしまうかというのが一般的で、プロセス単位でVPNにルーティングする方法というのはあまり知られていない。

しかしこれもcgroupsを使って実現可能だ。

ここではiptablesによるルーティングを目的とした仮想インターフェイスやブリッジを使うのではなく、あくまで既に割り当てられているインターフェイスを使用させることを目的とする。

まずはトンネルを通しておく。

# pppd updetach noauth silent nodeflate pty "/usr/bin/ssh root@gwhost /usr/sbin/pppd nodetach notty noauth" ipparam vpn 10.0.8.1:10.0.8.2

専用に名前空間を作り、pppデバイスを登録する。

# ip netns add vpnns
# ip link set ppp0 netns vpnns

pppデバイスにアドレスを与える。 pppは/32プレフィックスがつくのだけど、/32だと通信できないので、/24にしておく。

# ip netns exec vpnns ip addr add 10.0.8.1/32 dev ppp0

これで10.0.8.2とは通信できるようになった。 あとはこの状態でシェルを立ち上げ

# ip netns exec vpnns bash -l

お好きにどうぞ。

SSH+pppdのトンネルをデフォルトルートにするのはなかなか苦労がある。 もし単純に物理的なインターフェイスをデフォルトルートとして使わせたいのならDHCPが使えて楽。

# ip netns exec newns dhcpclient eth1
# ip netns exec newns bash -l

もっと簡単な方法

SOCKSを使えばもっと楽にできる。

$ ssh -NCD8080 proxyhost

単純にSOCKS5プロキシとしてlocalhost:8080を指定すればOK。SSH経由で流れてくれる。

SOCKSに対応していないプログラムでも、proxychainsやtsocksを使えばできる場合も多いだろう。

プロセスごとに帯域制限を

cgroupsとtcを使ってください。

現状では理想的に動作しないのでこの話は略。 情報はここらへんにある。

ThinkPad E440がスリープから復帰できない問題 (機種固有)

ThinkPad e440は基本的にLinuxではスリープ/サスペンドからの復帰が全くできない。 スリープに入る段階でフリーズしてしまうため、スリープはできるのだけれども、電源再投入ができなくなる。 ちなみに、Windowsでもやや不安定で復帰できないことがある。

Linuxのスリープというのは結構複雑な問題で難しく、調整が必要なことは珍しくないのだが、それでもなかなかうまくいかず、 しかしe440の出番がそれほど多くないことから放置していた。 そもそも私がスリープをほとんど使わないという理由も大きい。

ただ、最近不便を感じ始めていたので対応することにした。

ArchWikiには機種ごとの情報があったりするので調べてみたところ、e440のページもあった

のでこれに基づきBIOSのアップデートを試みる。 現在の最新バージョンは2018-03-06のv.2.27で、ArchWikiの記述と異なりISO配布されているため特別なツールは必要ない。

アップデートしたところ何の問題もなく復帰できるようになった。 なんのこっちゃ。

今更だけど、mpvがビデオ再生に便利

mpv、ほんとになんでもできるようになってきていて笑いが止まらない。

mpvで自由自在にビデオを見る

mpvの定番の設定になっているようだけれども

ビデオを回転させる:

Alt+RIGHT add video-rotate 90
Alt+LEFT add video-rotate -90

ビデオをズーム/パンする。 これは既にデフォルトの設定として採用されている。

Alt+- add video-zoom -0.25
Alt+= add video-zoom 0.25

ズームしたビデオを移動する。

Alt+j add video-pan-x -0.05
Alt+l add video-pan-x 0.05
Alt+i add video-pan-y 0.05
Alt+k add video-pan-y -0.05

ズーム/パンの設定をリセットする。

Alt+BS set video-zoom 0; set video-pan-x 0; set video-pan-y 0

もちろん、こんなのはほんの一部で様々なことができる。

12はコントラストに割り当てられている。 全体的に画面が暗く、もやもやしてよく見えないときにはコントラストを上げると良い。 逆に色彩鮮やかすぎて目が痛い画面ではコントラストを下げると見やすくなる。 くらい室内の動画や夜間撮影の動画ではコントラスト上げが、明暗差がきつい晴天時のオンボード動画などではコントラスト下げが活躍する。

Ctrl++Ctrl+-はオーディオディレイに対応している。 定量的な音ズレを簡単に補正できる。

*/あるいは9, 0はボリュームコントロールに対応している。 複数のビデオを並行で再生するような環境では1音量を揃えるために活躍してくれる。セッションを越えて保存されないので、一時的な変更には最も手軽だ。

sでスナップショットを取る。非常に手軽だ。

3, 4でブライトネス、5, 6でガンマ、7, 8でサチュレーションを補正する。 私はあまり使わないが画質的に見づらい動画を補正できる。

iでビデオの詳細な情報を表示する。 詳細な上にみやすく、ビデオソースについて知る必要があるときには活躍する。

lでA-Bループになる。lを押すだけの簡単操作で正確なタイミングをつかみやすい。 Lでそのビデオをループする。

aはアスペクト比の強制を行う。 アスペクト比の間違ったビデオを再エンコードせずに視聴できる。

字幕も表示/非表示、タイミングの補正、位置の補正も可能だ。

mで一発ミュート。

[]は再生速度のコントロールになっている。 音楽の練習ではとても重宝する。

Ctrl+LEFTCtrl+RIGHTはちょっとめずらしい、字幕の早送り/巻き戻しに対応している。密度の高い字幕がある場合には結構便利だ。

PgUpPgDownがチャプターに対応しているが、Shift+PgUpShiftPgDownが10分巻に対応しているのも数時間あるようなビデオではポイント高い。

そして、実はXF86メディアキーでの操作も可能。

ほんとなんでもできる。ありとあらゆるビデオを快適に再生し、活用できるようになっている。

mpvについて

mpvはもとはMPlayer2と呼ばれていて、MPlayerからフォークしたものだ。 MPlayer2はあまり人気がなかった気がするけれども、mpvになってからはMPlayerに対する明らかなアドバンテージの数々(例えばVA-API/VDPAUのサポートなど)を武器に今や標準ツールとなりつつある。

MPlayerもそうなのだけど、GUIのないビデオプレイヤーの魅力って、ちょっと理解しにくい。 実際、私も昔はGMPlayer2ばかり使っていた。

ないよりはあったほうがいいじゃないか、と思うかもしれない。 だが、そうではないのだ。

ビデオの場合、視覚的なものである。 コントロールを表示すればその分表示領域が必要になる。 画面の外に表示すればビデオは小さくなるし、重ねれば邪魔になる。必ずしもフルスクリーンで見るわけでもない。フルスクリーンではないけれど取れる範囲で最大限のスペースを使いたいという希望は普通にあるだろう。

また、VLCやSMPlayerだとビデオを開くたびにセッションを開く。 再生が重いというのもあるが、ものすごく単純なこととして、「ファイルを開いたら単純にそのファイルを開いてほしい、それ以外にはなにもしないでほしい」というのがあったりする。

mpvは再生によって何かを保存したり記憶したりしない。 余計なものを開いたりもしない。ファイルブラウザでビデオを開くアプリケーションをmpvにしていれば、ただ単純にダブルクリックするとビデオが再生される。

だが、その場合でもちゃんと視聴に必要な機能は備わっていてほしいはずだ。 mpvには他のプレイヤーにはないような機能まできっちり備わっている。 何かにプレイヤーを内包するような機能はない3が、プレイヤーとしての機能はパーフェクトなはずだ。

写真で考えてみよう。

アルバムアプリを立ち上げ、写真フォルダを探しながら写真をみるときと、ファイルブラウザから写真をダブルクリックするときでは意識に大きな違いがあるはずだ。 そして、ファイルブラウザでダブルクリックしたとき、アルバムアプリが立ち上がり、写真フォルダ一覧が表示されるのはあなたが望むことではないだろう。ファイルブラウザで写真をダブルクリックしたら写真を表示してほしいはずだ。それ以外の余計なものは表示せずに。

mpvはそういうアプリケーションだ。 コントロールはキーボードで行う。一見複雑なようだが、考えてみてほしい。 複雑に様々なコントロールができるとしたら、専用のリモコン、あるいはコントローラがあったほうが便利だろう。

だが、GUIがあったほうが便利なこともある。 例えば全体がどれくらいで、今どれくらいの位置を再生しているのか知りたいときなどだ。 mpvはpseudo-gui/OSDと呼ばれる機能により、oキーと、マウスオーバーによってそれらの情報を表示できる。 しかも表示できるだけではない。なんて操作できる。ビデオスキャンのほか、タイトルクリックでのフルタイトル表示、プレイリストコントロールなどが可能だ。


  1. 多分そんなことをする人はあまりいないのだけれど、私は多用する。

  2. ソフトウェアとしてはMPlayerなのだけれど、gmplayerというコマンドを使用するとGUIつきで起動する。Arch LinuxではMPlayerはgmplayerなしでビルドされている。

  3. いや、実はyoutube-dlを介してURL再生できたりするのだが

SSHのリバースポートフォワーディングの強化

以前かなり入念に設定して外出中もSSHでログインできるようにしたはずだったのだが、実際に試してみるとうまくいかないケースがあった。

もちろん、前回の設定で、SSHが死ねば再度コネクションを貼り直すようにしたし、サーバーから一定時間応答がなければ死んだとみなすようになっていた。 これで万全のはずだった。

ところが、サーバーからPONGは届いているにもかかわらず、ポートフォワーディングは死んでいる…という事態に遭遇したのだ。

これでは困る。 なぜそんなことになるというのか。

しかし発生するものは仕方ない。 実際にログインできない場合には無理やり貼り直すことにしよう。

方法としては割と単純で、自分自身に対するものではあるが、一旦サーバーにSSHで接続し、そこからSSHで手元のコンピュータに対してログインしコマンドを実行する。 これに失敗すればコネクションが切れているとみなす。

ProxyCommandを使う必要はなく、単純にsshのコマンドとしてsshを含めればいい。

新しく鍵を作ってサーバーに登録する。

サーバーで実行するコマンドはsshである。

また、逆にサーバーでも新しい鍵を作って手元コンピュータに登録する。つまり、互いにコマンド実行用の鍵を登録することになる。

サーバー側で結びつけるコマンドはsshである。 このSSHで~/.ssh/configによってターゲットコンピュータに対してログインするホストを指定する。

Host target-pc-connection-check
    User jrh
    Port 2222
    Hostname localhost
    IdentityFile ~/.ssh/target-pc-connection-check_rsa

サーバー側で鍵に結びつけるコマンドはssh target-pc-connection-checkである。

ターゲット側では次のように登録する。

Host target-pc-connection-check-via-server
    User jrh
    Port 22
    Hostname serverhost.example.com
    IdentityFile ~/.ssh/target-pc-connection-check-via-server_rsa

これでターゲットコンピュータがこの鍵でサーバーにログインすると自動的にサーバーはSSHを実行しターゲットコンピュータにSSHポートフォワーディングを介して接続しようとする。 自動化のためそれぞれの鍵にはパスワードはかけない。

ターゲット側で鍵に結びつけるコマンドはtrueでも良いと思うが、echo OKあたりでも良いだろう。

これでターゲット側から

とすれば、コネクションが到達するかどうかをチェックできる。

Systemdユニットに組み込むと面倒なことになるので、システムトレイアプリに組み込む。

ArchLinux * Nginx * php-fpm * MariaDB * WordPress

慣れている人にとっては常識レベルなのだろうけれど、つまずきどころ満載だったので、メモ。

Nginxのインストール

# pacman -S nginx

PHP / php-fpmのインストール

# pacman -S php-fpm

MariaDBのインストール

“MySQL”と認識している人も多いだろうけれども、 現在は圧倒的にMySQLよりMariaDBが一般的である。

MySQL自体は継続しているが、MySQLを提供しているディストリビューションは非常に少なく、 そもそもアプリケーションが想定しているデータベースもMySQLよりMariaDBのほうが一般的だ。

MariaDBはMySQL5.5から派生したコミュニティベースのデータベースである。

# pacman -S mariadb

有効化する前に 初期設定を行う。

# mysql_install_db --user=mysql --basedir=/usr --datadir=/var/lib/mysql

そしてセキュアな設定を行う。 (省略しても構わない)

# mysql_secure_installation

リモートホストからのアクセスを拒絶しておく。 /etc/mysql/my.cnfskip-networkingをアンコメントすればOK。この状態でもローカルホストからは接続できる。

これでMariaDBを起動・有効化できる。

PHPの設定

PHPのモジュールが無効になっているので有効にしておく。 これがなければデータベースに接続できず、500 Internal Server Errorになる。

/etc/php/php.iniを編集する。bz2, mysqli, pdo_mysqlを有効にする必要がある。

これをしていないとWordPressの初期設定でデータベース設定後に500エラーになることになり困惑することになる。

これでphp-fpmを起動・有効化できる。

Nginxの設定

まずはサーバー設定を書いておく。 設定を書かない場合、WordPressにアクセス自体できない。

どこに何を書くかという解説はしない(Nginxについて説明をはじめると長い)ので、それを理解しているという前提で進める。 もしろん、コピペでなく値は合わせること。

最低限だとこんな感じ。

server {
  listen 80;
  listen [::]:80;
  server_name blog.example.com;
  root /srv/http/blog/example.com;

  access_log /var/log/nginx/blog-example.log;

          location / {
               index  index.html index.htm index.php;
          }
          location ~ \.php$ {
               fastcgi_index  index.php;
               include        fastcgi.conf;
          }

}

公式の設定から引用するとこんな感じ。

server {
  listen 80;
  listen [::]:80;
  server_name blog.example.com;
  root /srv/http/blog/example.com;


  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  rewrite /wp-admin$ $scheme://$host$uri/ permanent;

  location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires 24h;
    log_not_found off;
  }

  location ~ \.php$ {
    try_files $uri =404;
    
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    include fastcgi_params;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
#   fastcgi_intercept_errors on;
    fastcgi_pass php;
  }

}

公式の場合サイト別ではなく上流で次のような設定も必要になる。

upstream php {
  server unix:/run/php-fpm/php-fpm.sock;
}

php-fpmのソケットファイルが間違っている場合、502 Bad Gatewayになる。

WordPressのインストール

「公式パッケージはあるけどWordPress公式からインストールしたほうがいいよ」というのがArchの姿勢。

$ cd /srv/http
$ wget https://wordpress.org/latest.tar.gz
$ tar xvzf latest.tar.gz
$ sudo chown -R http:http wordpress
$ mv wordpress blog/example.com

パーミッションが間違っていると403 Forbiddenになる。 これは主に所有者で、Nginxプロセスの所有にする必要がある。 現在のArch LinuxではNginxプロセスはhttp:httpで動作する。

起動と有効化

# systemctl start nginx
# systemctl enable nginx
# systemctl start mariadb
# systemctl enable mariadb
# systemctl start php-fpm
# systemctl enable php-fpm

php-fpmが起動されていない場合は502 Bad Gateway、MariaDBが起動されていない場合は500 Internal Server Errorになる。

別のWordPressから移行する

WordPressのファイル側にもファイルがあるらしい(どうも画像データはこっちらしい)ので、MySQLのエクスポートと同時にファイルもとっておく必要がある。

取得したファイルはWordPressインストールの代わりに展開し、パーミッション(所有者)を変更する。 パーミッションの変更は忘れがち。

SiteGuardでログインアドレスを変更している場合は、この機能がApacheに依存しているためログインできなくなってしまうので、wp_content/plugins/site-guardを削除しておく。あるいは、エクスポート前にこの機能を無効にしておいてもいい。 ログインページをNginx上で変更したい場合は他のプラグインを仕様する必要がある。私の場合は“Login Rebuilder”を利用した。

従来が第三者サービスなどによって提供されていたWordPressで、データベース名やユーザー名が好ましくない場合、あるいは複数サイトをインストールするために指定したい場合はwp_config.phpも編集。

データベースをインポートする前にデータベースを用意しておく。

# mysql
> create database <database_name>
> create user '<username>'@'localhost'
> grant all privileges on <database_name>.* to '<username>'@'localhost' identified by '<password>'
> quit

そしてインポート

# mysql <database_name> < wordpress_database_file.sql

そんなわけでブログ引っ越し完了

ブログはXdomainの付属サービスから自サーバーに移動した。

これによりパフォーマンスが改善し、またスマートフォンでの閲覧において広告がでなくなった。

パフォーマンスは最善ではない。これはこのサーバーでWordPressだけが動いているわけではないため、リソースをWordPressに大量に割くことができないからだ。 必要ならば将来的にWordPressを独立したサーバーにしてパフォーマンスを向上させたり(Kasanagi導入が妥当だろう)、リソースを増強してパフォーマンスチューニングを行うかもしれない。

現状ではこのChienomiのほうのデイリーPVは1500から6000程度である。 特に広告などを出して収益があるわけでもないので、今のところあまり考えていない。 そうね、ヒューマンユニークがデイリー1500を越えるか、月間1000円以上の広告収入が発生するようなことがあれば考えようかな。

いずれ広告を出す可能性があるにせよ、それはChienomi側で選定しコントロールした話であり、プロバイダー広告が出るのは(広告を出さないというポリシーに基づく)ユーザービリティ的にもパフォーマンス的にもデメリットしかないので、Chienomiがそれなりにアクセスがあることを踏まえて対応した。

VPN(リバースフォワーディング)をアイコン操作にしてみる

先日の多段SSHによる外出時のログインだが、外出時にリバースフォワーディングをオンにし、帰ってきたらオフにするのはちょっと面倒だし、忘れそうだ。 そこで私は「システムトレイにアイコン出してもらって、クリックしたら閉じてくれるようにしたらいいじゃない」と考えた。

まず、「Linuxでシステムトレイにアイコン」と考えたらまずYadを考えて良い。 ZenityやKDialogはシステムトレイをサポートしていない。

yad --notification --image=<icon> --title=<title on hover>

の形式でシステムトレイにアイコンを表示できる。 --commandオプションをつかってクリック時の動作を指定することもできるし、--menuオプションで右クリックに対応させることもできる。 --commandオプションを指定した場合は終了するかわりにそのコマンドを実行する。

今回の場合クリックしたら終了を含む動作をさせたいので、特にコマンドは指定しない。 そこでyadプロセスが終了したらクリックした後の動作をさせていけばよいわけだ。

必ずしもこの操作をこのプログラムから行う、という制約はないこと、 そして「トンネルを解除しない」という選択がありえることから、ループとし、当該ユニットが動作中であればアイコンを表示する方式にした。

ひとつめのyadはシステムトレイにアイコンを表示し、クリックされるのを待つものだ。 これでクリックされるまではスクリプトはここでブロックされる。

ふたつ目のyadだが、yadの場合zenityと違い、タイプを指定しないで起動するとシンプルなダイアログになる。 アイコンとボタンのタイプはそれぞれ指定できる仕組みだ。 このため、ZenityやKDialogにあるいくつかの動作オプションがまとめられている。 ここではYes/Noダイアログを表示している。

なお、ボタンはボタンのあとに終了コードを書くようになっており、gtk-cancelも利用可能。それ以外は単にラベルとして使用される。

さらにランチャーで使用するため、.desktopファイルも作っておいた。 右クリックでの開始/停止もサポートしている。

これでわかりやすく、操作しやすくなった。

もちろん、SSHフォワーディングを行うスクリプトに含めるというのも手だが、そうすると他の手段が失われてしまう。 Systemdユニットにした上で追加機能は別のスクリプトにするというのは良いアイディアだと思う。

プレゼントが無駄になったので弟子を募集するよ

プレゼントとして用意していた「ピンクセット」が音信不通により無駄になってしまった、という理由で弟子を募集するよ。

条件は以下

  • 女性であること
  • ピンクが好きであること (ピンクというか、ローズゴールド)
  • 真剣に(労力・熱意・時間を割いて)コンピュータに精通する強い意思があること (現状の能力は不問)
  • エンジニアまたはハッカーの志望者、あるいは新人であること

特典

  • 今回の主題である無駄になったピンクセットのプレゼント
  • 私から教わり放題
  • 場合によってはP720のリソースも利用可能
  • 自分のコンピュータを持っていない人には一時利用向けにコンピュータを貸与

基本的にはコンピュータに精通し、私を超越することを目標とする人に余ってしまったピンクセットをプレゼント、という内容。 条件はおおよそ、音信不通になった人物を踏襲したもの。

正規の弟子募集要項と比べてずいぶんと簡単な動機だけれど、 志望者がいればもちろんきっちりと対応するよ。

PureBuilder Simplyのアップデート (ReST完全対応)

3ヶ月ぶりとなったPureBuilder Simplyのアップデート。

今回はMimir Yokohamaのウェブサイトの新連載(そもそも連載開始にお金かかるので時期未定)でReSTructured Textを使うため、ReSTに完全対応した。

完全対応のポイントは、従来きちんと対応できていなかったdocinfo(Bibliographic Elements)に対応するようにした。

ただし、これは「対応した」という言い方が適切なのかどうかわからない。 ひとつは、自力でdocinfoを解釈する部分が間違っていたのと、仕様の理解自体正しくなかったので適正にした。

File.open([dir, filename].join("/")) do |f|
    l = f.gets
-        if l =~ /:[A-Za-z]+: .*/ #docinfo
-          docinfo_lines = [l.chomp]
+        if l =~ /:([A-Za-z]+): (.*)/ #docinfo
+          frontmatter = { $1 => [$2.chomp] }
+          last_key = $1

        # Read docinfo
        while(l = f.gets)
            break if l =~ /^\s*$/ # End of docinfo
-            if l =~ /^\s+- / && (docinfo_lines.last.kind_of?(Array) || docinfo_lines.last =~ /^:.*?: +-/) # List items
-              if docinfo_lines.last.kind_of?(String)
-                docinfo_lines.last =~ /^:(.*?): +- *(.*)/
-                docinfo_lines[-1] = [ [$1, $2] ]
-              end
-              docinfo_lines.last[1].push(l.sub(/^\s+- +/).chomp)
-            elsif l =~ /^\s+/ # Continuous line
-              docinfo_lines.last << " " + $'.chomp
-            elsif l =~ /^:.*?: +.*/
-              docinfo_lines.push l.chomp
+            if l =~ /^\s+/ # Continuous line
+              docinfo_lines.last.push($'.chomp)
+            elsif l =~ /:([A-Za-z]+): (.*)/
+              frontmatter[$1] = [$2.chomp]
+              last_key = $1
            end
        end

-          # Convert Hash.
-          frontmatter = {}
-          docinfo_lines.each do |i|
-            if i.kind_of?(Array) #list
-              # Array element
-              frontmatter[i[0]] = i[1]
-            elsif i =~ /^:author: .*[,;]/ #author
-              # It work only pandoc style author (not Authors.)
-              author = i.sub(/:author: /, "")
-              if author.include?(";")
-                author = author.split(/ *; */)
-              elsif author.include?(",")
-                author = author.split(/ *, */)
-              end
+          # Treat docinfo lines
+          frontmatter.each do |k,v|
+            v = v.join(" ")
+            if((k == "author" || k == "authors") && v.include?(";")) # Multiple authors.
+              v = v.split(/\s*;\s*/)

-              frontmatter["author"] = author
-            elsif i =~ /^:(.*?): +(\d{4}-\d{2}-\d{2}[T ]\d{2}[0-9: T+-]*)$/ #datetime
-              key = $1
-              time = DateTime.parse($2)
-              frontmatter[key] = time
-            elsif i =~ /^:(.*?): +(\d{4}-\d{2}-\d{2}) *$/ #date
-              key = $1
-              time = Date.parse($2)
-              frontmatter[key] = time
-            elsif i =~ /^:(.*?): +/
-              key = $1
-              value = $'
-              frontmatter[key] = value
+            elsif k == "date" # Date?
+              # Datetime?
+              if v =~ /[0-2][0-9]:[0-6][0-9]/
+                v = DateTime.parse(v)
+              else
+                v = Date.parse(v)
+              end
+            else # Simple String.
+              nil # keep v
            end
+
+            frontmatter[k] = v
        end

    elsif l && l.chomp == ".." #YAML
        # Load ReST YAML that document begins comment and block is yaml.
+          @extra_meta_format = true # ReST + YAML is not supported by Pandoc.
        lines = []

        while(l = f.gets)

考え方自体に大きな変更があったため、変更行数も多い。 ただし、22165f2よりも8f6e453のほうが以前のバージョンとの違いは少なくなっている。

ここでひとつポイントだ。ReSTの仕様上、authorsa,b,cと書かれた場合は3人の著者になる。a,b,c;と書かれた場合は1人の著者になる。 だが、Pandocは;でのみ分割するので、この仕様に従っている。このため非常にシンプルな仕様だ。

基本的にdocinfoの場合、authorsdateのみが特別扱いされる。 Pandoc的にもそのような仕様になっており、authorsauthorの代わりに書ける点も正式な仕様に従っている。 PureBuilderもこれにならって、それ以外のフィールドについては特別扱いしない。 また、Pandocは仕様にない項目を入れてもエラーにしないため、この点も合わせてある。

この上で、メタデータの解釈はPandocに委ねることにした。 従来は-Mオプションを付加して上書きしていたのだが、解釈の違いからバグにもなったし、Pandocのほうが優秀なのでこのような挙動は取りやめた。

ただし、PureBuilder的にはこれではちょっと困る。 サイトの内容に関する情報をメタデータに記述する風習があるため、メタデータに書ける内容が決められてしまうのは困るのだ。

そこで従来サポートされていた「ReSTでも先頭をコメントにした場合はそのあとYAMLメタデータを書くものとする」という仕様も維持している。 この場合、Pandocは解釈できないため、@extra_meta_formatというインスタンス変数を追加し、これが真の場合のみ-Mオプションでのメタデータを使うことにした。

こうしてReSTも完全対応できることとなった。 asciidocも結構人気があるらしいのだけど、Pandocが入力にasciidocをサポートしていないのでサポートすることはできない。 Textileをサポートしてほしい人がいれば対応は考えなくもないけれど、私が知る限りPureBuilderでTextileを使いたい人はいないはずだ。1


  1. 比較的複雑な構造を書けることがPureBuilderの利点であり、また簡易な記述をしたい人にとってもMarkdownが困ることはないはずだからだ。Textileにはコメント機能があるため、サポートすること自体は不可能ではない。

2018年版コミュニケーションメディア 所感

eメール

最近はeメールを使う人は本当に減ってしまったようで、個人的なやりとりに使われることは現状ほぼない。

特段見くびるほどの欠点があるわけではないと思うのだが、実際のところレガシーな使いづらさというのは存在する これはどちらかというとソフトウェア実装上の問題である。

ただし、柔軟性に関しては最も優れている。 オープンで共通の仕様という意味では被験するのはXMPPくらいのもので、 この点を理由にeメールを扱いたい理由はある。

若い人の場合、大学生、あるいは大学卒であればeメールは扱えるが、 そうでない場合は扱えない傾向があるようだ。 また、eメールを扱う場合でも、特定のアプリとアカウントが紐付けられた状態(LINEのような状態)で認識しており、使い方は理解できていないというケースが目立ち始めている。

LINE

依然として日本においてデファクトスタンダードの座を譲らないLINEである。

アプリの使いづらさはある程度改善されつつあるのだが、Windowsアプリ版の使いにくさには批判が多いようだ。 また、アプリの種類によって機能が異なる点は単なる使いづらさになっている。

モバイルアプリ版に関してはヴォイスメッセージ機能が秀逸である。 トーク画面でヴォイスボタンを押している間に発した言葉が送信される。 あまり活用されていないようだが、非常に優れた機能といっていいだろう。(LINEが初なのかはわからないが)

メッセージ消去機能がついたが、Skypeと比べれば証拠消しなどには使いづらく良心的だと言えるだろう。 直前消去だけで良いのではないかという気がするのだが…

通話品質はあまり改善がみられず、非常に切れやすい。

LINEが優れている点はわずかだが、普及とスタンプという蓄積要素があるため、乗り換えも容易ではないところまできたように感じる。

Kakao Talk

混沌の時代に現れ、様々な雑な対応でユーザーを失ったカカオトークだが、 その混沌と荒野、そして雑さをついて出会い系利用に拍車がかかった。

直接的にIDを交換するケースもあるが、他の出会い系メディアからの連絡手段交換として利用されているようだ。 出会い系、というとソフトにきこえるが、ほぼ売春・援助交際目的である。

そして、それ以外の用途というのはあまり利用されていないことから、 「インストールすることでその人の素行品性が問われる」という状況にあるといっていい。

Skype

Microsoftに買収されてから改悪を続けるSkype。 5.4になってからレビューを著しく落としたのは有名な話だが、それ以降さらなる改悪を続けている。

まず、コンタクト機能がなくなった。 電話帳利用を強制しており、利用しない場合はコンタクト機能が存在せず管理不能の状態になる。 チャットした相手は全て自動的にコンタクトがある状態になる、という仕組みだ。 電話知用機能のないLinuxの場合、「チャットをしたことのある相手一覧」という形式になる。

また、ステータス表示機能もなくなった。 これは一旦削除し、激しい批判を浴びて復活させたのだが、完全になくなってしまった。 これは今までは「モバイルアプリ版にはない」だったのだが、ステータス通知APIもろともの削除で、外部アプリを使った場合でもステータスは取得できない。

SkypeのSNS化進行も激しく、だいたいsnapchat化している。 Skypeのコンタクトにはあまり親しくない人も多いことから非常に困ってしまう。

通話品質も低下しつつあり、より通話品質に優れるアプリが登場していることから避けたいメディアになりつつあるようだ。

Telegram

LINEと類似の一通りの機能、無料のステッカー、ステッカー同様にGIFを利用する機能などなかなか魅力的だ。 また、LINEに追加されたヴォイスメッセージに近い機能(もうちょっと慎重)と、同様に利用できるビデオメッセージも利用可能だ。

だが、致命的なのはWhats Appを意識しているのか、「電話番号と本名を前提としている」ということだ。

基本的にユーザー検索時はファーストネームと電話番号が必須である。 裏技として、ユーザーIDだけわかっていればシークレットチャット開始→ID検索ということも可能だが、 検索結果に本名と電話番号が表示される。

検索を防ぐ設定はないので女の人などは非常に不安だろうし、 「電話の代わり」という仕様はWhats App同様いかがなものか。 「日本人は秘密主義すぎる」みたいに言われることがあるのだが、世界的に見てそんなに受け入れられている気はしない。 むしろアメリカ人が個人情報やプライバシーに無頓着すぎると思う。

通話機能はかなり切れやすく、快適ではない。

XMPP

依然としてXEP-180(ビデオ通話)に対応したクライアントがなく、どのアプリも快適にはほど遠い。

期待されていたJitsiに関してはそもそもXMPPをやめてしまったという状況だ。

モバイルアプリは最も有力なのはXabberだが、Xabberにしてもあまりデキはよくない。 重要な相手とのやりとりには使用できないが、あまり密ではない(取りこぼしがあったとしても構わない)ような相手とのやりとりには利用できるだろう。

「XMPPを利用している人は少ない」という前提のもと、「XMPPを利用できないレベルの人にXMPPでやりとりをできるようにする」という作業を行う状況というのが限定的すぎて現実的ではない。

ただし、メリットは全くないわけではない。 XMPPアカウントの取得は比較的容易で、XMPPのウェブクライアントも存在するためだ。

PCの場合はインストールも不要で簡単にXMPPで会話することが可能になる。

現実的にはスマートフォンでインストールもせずにチャットするのはかなり難しい。 だが、そのような人はおそらく会話する意思に著しく乏しいものと思われるので配慮するだけ無駄ではないか。

Jitsi Meet

Jitsi MeetはWebRTCクライアント+WebRTCサービスである。

一応、他のWebRTCサービスも利用できるようだ。

つながっている手段が通話機能を提供していない場合(たとえばTwitterなど)、あるいはその方法が適切ない場合に有効である。 特に個人情報を教えたり登録したりする必要もないのもメリットと言えるだろう。

Discord

Discrodが良いものであることは既に明らかだが、明確な欠点がある。 それは、アカウントの使い分けが困難だということだ。

PCならいくつか方法はあるのだが、Discordは活用ジャンルが非常に広く、通知を分けることもできず、特定のチャンネルに集中することも難しい。 別にDiscordに固有の問題ではないとはいえ、便利だからといってあれもこれも教えていると困ることになってしまう。

方法は色々ある(たとえばInvisibleにするとか)のだが、使い方に配慮が必要なのは確かだ。

通話品質は非常によく、現状ベストな選択肢である。

なお、招待すると「ゲーマー」のところにみんなひっかかるので、そろそろ他のことも書いてくれないか。

Slack

日本語版がリリースされ、CMも打たれたため、名前だけは知っているような状態になっている。

実際一般にそこまでSlackが広まった印象はないが、少なくとも提案したときに受ける抵抗は減ったように思う。

Slackはログを商売にしているが、あまり良い手ではないというのが一般の意見だ。 XMPPサポートをそれを理由に切ったことも批判的に見られている。

Slackは全体的にDiscordに見劣りするが、明確にDiscordより優位な点がある。 それは切り分けが容易なことである。ユーザー単位では認識されないし、チームは分離される。 常に適切なリージョンで分割できるというのはメリットといっていいだろう。

なお、Slack Webはスマートフォンでは利用できない。

Google Hangouts

品質はあまり変わっておらず、少なくともSkypeやLINEよりは良い選択肢といっていいと思う。

しかし、Googleアカウントが特定されてしまうこと、結果としてGMailもわかってしまうこと、Google+をやっている場合は自動的にGoogle+でもつながってしまうことなどFacebook Messanger同様の使いづらさが存在している。

Viber

楽天が取り込んでいるけれども、プライバシー面で改善されたという話は聞かず、 かなり不安な状況のままだ。

まとめ

  • Discordは良いもの
  • 仕事など限定された環境のつながりはDiscordでなくSlackで
  • DiscordとSlackの使い分けは大事
  • LINEやTelegramのようなプライバシーに関わるものをプライベートなつながりでないのに要求する人からは逃げよう
  • 親しい人とLINEを交換するのは妥当。ただし「その人が親しい人でなくなるリスク」とセットで考えないと、ブロック/削除しても可視性が残る
  • Googleアカウントでつながってしまっている人に関してはHangoutsというのも結構妥当
  • 「とりあえずXMPPアカウント交換しておこうかな」というのもまぁ妥当な判断
  • カカオトークはやめましょう。人間性の問題になる。
  • Telegramは現状、電話番号以上のプライバシーの塊なので、本当に親しい人とでないと困難
  • チャット機能に関してはTelegramかなり使い心地いい
  • 妥当というか無難なのはLINE。メッセージ到達性は一番優秀
  • メール侮るべからず
  • 匿名性を保ってつながりたいという人は、XMPPとJitsi Meetを提案するのが多分無難
  • そのうちチャットつくるよ
  • Mimir YokohamaはTelegramが対応済み。XMPPもそのうち対応します