2017/10/30

[nodejs][raspi]Raspberry Piにnodejsなどを入れる(2017/10)

Google HomeのためにVirtual Boxで動かしているUbuntuにgoogle-home-notifierをインストールしたのだが、ずっとVMを動かしているわけでもないので、単独で動いてくれる環境もほしくなった。

ああ、だからRaspberry Piでやっている人が多いのか・・・と気付く。
よし、インストールだ。


Raspberry Pi 1を使う。

OSは、2017-09-07-raspbian-stretch-lite。
適当にSDカードに焼いて、起動して、raspi-configでディスク領域を調整したり、SSHを有効にしたり。
aptのupdate/upgradeもやっておく。



noelportugal/google-home-notifier: Send notifications to Google Home
ここにRaspberry Pi用のやり方が書いてあるので、真似する。

真似したのだが・・・ちょっと足りなかった。

$ curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
$ sudo apt install nodejs git-core libnss-mdns libavahi-compat-libdnssd-dev npm build-essential
$ sudo ln -s /usr/bin/nodejs /usr/bin/node

nodeコマンドはそのままではシンボリックリンクされてなかったし、npmも入ってなかった。
build-essentialは、いるのかどうかわからんが、どうせビルドするだろうからやっておいた。

$ git clone https://github.com/hirokuma/google-home-notifier-test.git
$ cd google-home-notifier-test
$ npm install

ここでかなり時間がかかっている。
・・・そして、404エラーが出てしまった。

npm ERR! 404 Not Found
npm ERR! 404
npm ERR! 404 'types/node' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it
npm ERR! 404 It was specified as a dependency of 'ngrok'
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, or http url, or git url.
npm ERR! System Linux 4.9.41+
npm ERR! command "/usr/bin/nodejs" "/usr/bin/npm" "install"
npm ERR! cwd /home/pi/Nodejs/google-home-notifier-test
npm ERR! node -v v4.8.2
npm ERR! npm -v 1.4.21
npm ERR! code E404
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR!     /home/pi/Nodejs/google-home-notifier-test/npm-debug.log
npm ERR! not ok code 0

/home/pi/Nodejsは、こっちで作ったディレクトリだ。

Ubuntuだとv8だったので「setup_8.x」にしてみたが、4.8.2しかインストールされん。
curlでnodesourceから取ってくるときに警告が出ているのだが、Raspberry PiのCPUだとソース提供されていないのかもしれん。


うーん、よくわからんが、デフォルトパラメーターでエラーが出ているようだから、削った。
ついでにexample.jsを削除し、package.jsonからも使わなくなったrequireを減らしていった。
正しいやり方なのかどうかはわからんが、これなら動いた。

https://github.com/hirokuma/google-home-notifier-test/tree/8a4f07c7f6193d129b20132381a5ebf9fba638aa

cloneしたままのexample2.jsだとIPアドレスが入っていないので、そこは自分のGoogle Homeのやつを入れておくれ。

端末の遅さのせいか、実行してから8秒くらいかかって、ようやくしゃべり始める。
そこそこ、端末側にもパワーがいるのだねぇ。

2017/10/29

[googlehome]avahiで名前解決させたい

Google Home miniだが、Androidアプリは自動で探すことができている。
何か名前解決するしくみがあるに違いない。

avahi-discoverというツールで接続されているかどうかは確認出来るらしい。

Discovery Troubleshooting  |  Cast  |  Google Developers

apt installしただけではavahi-daemonの立ち上げができなかった。
何も考えずに、こちらのssh.serviceをそのまま設定ファイルにすると、うまくいった。
avahi-daemonを設定してDNSサーバ運用をやめた - Qiita


image

おお、見えている。
AvahiはAppleのBonjourと同じようなプロトコルなのか、ツール名なのかわからんが、そんな感じのものらしい。
googleのものが2つ出てくるが、_googlecast._tcpの方がそれなのかな。


avahi-resolveでIPアドレスから名前を引けるらしい。
どーでもいい日々: mDNS、Avahi、Bonjour

やってみたのだが、これはavahi-resolveが失敗した。


困ったことに、ごにょごにょやっているうちに、pingが通るようになってしまった・・・。

$ ping xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.local

このxxx...のところは、UUIDっぽい。
Avahi Discoveryで見えるところの、_googlezone._tcpの下に出てくる名前の方でもあるし、_googlecast._tcpの項目にある"Address"でもある。

だから、jsファイルのip()も、その名前を書けばよいことになる。


ただ、デバイス名からアドレスを引っ張ってくる方はダメなようだ。
これはmdns.createBrowser()したインスタンスの中で起きているようだから、うちがnodejsをv8とかにしたせいかもしれん。
まあ、深くは考えまい。


AvahiというかmDNSというか、とにかく機器名からIPアドレスを探すという処理を使わないのであれば、google-home-notifier.jsからmdnsとbrowserは削除することができる。
それ以外で使っているのは、castv2-clientというやつと、google-tts-apiというやつか。

ttsは、Text to Speechの略らしく、文字をしゃべるということになるか。
うーん、これはわからん。。。
ただ、引数でしゃべる速度を変えるくらいだったらできそうだ。

speed()を追加してみた。example2.jsにサンプルを追加した。
デフォルトは1で、0に近づくとゆっくりになるようだ。
引数の説明で"0.24"という数字が出てきたので、それがゆっくりの下限なのかな?
https://github.com/hirokuma/google-home-notifier-test/tree/d75f4f314aa5bdcbd6da2e78d6be776d5d6e6acf

2017/10/28

[nodejs]google-home-notifierのインストール

ミーハーなことに、Google Home miniを買ってしまった。
職場にGoogle Homeを買ったのだけど、案外ものわかりがいいやつだということに気付いてしまったのだ。
それだけだったらまだしも、IFTTTとかでしゃべらせることができるらしい。
ならば、買わねばならぬのぅ。


Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる(ついでにNode.jsやngrokやらも使ってLINEやGoogle Homeに通知する) - Qiita
こちらを読むと、google-home-notifierというやつをインストールするらしい。

https://github.com/noelportugal/google-home-notifier

npmでインストールするらしい。
確か、node.jsとかの関係だよな。

$ npm install google-home-notifier

いろいろ出た後、ERRになった。。。
installだからsudoがいりそうな気もしたのだが、そういうエラーではないように見える。

sudo apt install npm node.js libnss-mdns libavahi-compat-libdnssd-dev

よくわからんが、そのページに書いてあって関係ありそうなものをインストールしたら、google-home-notifierもインストール出来たようだ。
WARNがいくつも出ているが、大丈夫よ・・・ね?


書いてあるサンプルをファイルに保存して実行してみたが、requireが見つからんと言われる。
心配になって、もう一度npm installしてみると、エラーではないもののnodeのバージョンが期待よりも古いといわれているようだ。
aptでは最新なのだけど、世の中の最新は別のところにあるらしい。

Ubuntuに最新のNode.jsを難なくインストールする - Qiita

aptではnodeはv4.2.6が最新だったのだけど、これをやるとv8.8.1になった。
全然違うやん・・・。


フォルダの中のファイルを消して、もう一度npm installしなおした。

npm WARN saveError ENOENT: no such file or directory, open '/home/xxx/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/home/xxx/package.json'

なんかダメそうだ・・・。


npm installはあきらめて、こっちの方法でやることにした。
https://github.com/noelportugal/google-home-notifier#listener

手順の最後でexample.jsを動かすようだが、こちらを見ながらやっても改造がうまくいかん。。。
GoogleHomeスピーカーに外部からプッシュして自発的に話してもらいます - Qiita

もしかしたらRaspberry Pi用の説明なのかもしれんと思い、githubに書いてあった方のサンプルを簡単に改造した。

var googlehome = require('./google-home-notifier');

googlehome.device('地下室');
googlehome.accent('ja');
googlehome.notify('冷たいビールが飲みたい', function(res) {
  console.log(res);
});

このファイルをtest.jsという名前で保存し、

~/xxx/google-home-notifier$ node test.js
*** WARNING *** The program 'node' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node>
*** WARNING *** The program 'node' called 'DNSServiceRegister()' which is not supported (or only supported partially) in the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=node&f=DNSServiceRegister>
Device notified

こんなログは出るものの、ちゃんと日本語でしゃべってくれた。
あ、「地下室」というのは、うちにあるGoogle Home miniにつけた名前だ。
別に地下室じゃないんだけどね。。。


このサンプルは、google-home-notifier.jsを書き換えないと動かないやつになっていた。

var googlehome = require('./google-home-notifier');

googlehome.device('地下室', 'ja');
googlehome.ip('xx.xx.xx.xx');
googlehome.notify('朝ごはんは食べましたか?', function(res) {
  console.log(res);
});

デバイス名で検索出来ていたのかと思ったが、IPアドレスを指定している方が効いているみたいだ。
あるいは、デバイス名が英語だったらいけるのかもしれんと思ったが、ダメだった(abortする)。

device()で'ja'にしないと、notify()で日本語をしゃべってくれない。
つまり、しゃべってほしい言語はここで指定することになるようだ。

2017/10/27

[uml]シーケンス図の方向に悩む

データの流れや処理の流れを考えるために、UMLのシーケンス図を描くことがある。

そのときに悩むのが、方向をどっちにするか、だ。
対等な関係のライフラインが並ぶならそこまで気にしないのだが、だいたいはデータの提供元(input)が出てくるので、片方向の矢印を引くことになる。
それを、右側を提供元にするか、左側を提供元にするか、ということで悩んでしまうのだ。


いや、どっちでもよいのだよ。
全体として、その方向が統一して描かれてさえいれば、右だろうと左だろうと困りはしない。
単に、感覚としてどっちを提供元にした方がわかりやすいか、というだけのことだ。


一応検索して見たところ、左側に提供元を置く場合が多そうだ。
電気回路で電源を左側に置くとか、そんな理由なんだろうか?


では、割込の発生は左側に描くかというと・・・上記ルールにあわせるならば、私だと右側になるだろうな。
データの提供元=外面に近い、ではあるものの、アプリ層・ミドル層・ドライバ層、みたいな分け方になると、外面はアプリ層かな、と感じるからだ。
そういう意味では、アプリの階層でいう上位側が左、下位側が右、というところか。


じゃあ左がユーザに近い側かというと、そうでもなかろう。
ソフトウェアとしては、何らかの接点に一番近いのは階層だからだ。
ボタンなりディスプレイなりは、最後はそこで制御するしね。

image

ただ、そこまで細かいことをシーケンス図だけで表現してしまうと、とてもわかりづらくなりそうだ。
本末転倒になりかねないので、そこら辺は割り切ってしまう必要もあるだろう。
機能ブロックに分けて、ブロック単位で描くとか、細かいところは別の図にするとか、工夫がいりそうだ。

image


設計を図で描いていくと、変に細かいところまで同じ表現方法を使おうとして失敗してしまいがちなので、気をつけたい。
というか、今、気をつけねばならんのだ・・・。

[android][nfc]JPKIのASN.1を読む

OpenSCに入っていた、JPKを読込む部分を参考にして、例のカードの総合認証証明書プロファイルのASN.1ダンプを表示させるアプリをCSharpで作っていたものを、Androidでも動くようにした。

https://github.com/hirokuma/AndroidReadJpk/tree/8b68a801b254368f6a6a884ad843cd965aa5441f


起動させると、アプリのタイトルが「Read JPK PubKey」になっているが、あまり気にしないでおくれ。。。
それと、何が出力されているのかは聞かないでおくれ。。。

内容についてはよく知らんのだ。
暗証番号などを入力せずに読めるから、きっと公開鍵かなんかだろうと思ったんだけど、これはたぶん証明書にあたるものだ。
この中のどこかに、公開鍵が入っているんじゃなかろうかね?


元ネタは、こちらだ。
マイナンバーカードでSSHする - AAA Blog

元ネタの方では、2番目にSELECT FILEするのが0x0018になっているが、暗証番号を打ち込まないと読めないやつは怖いので、認証証明書というやつを読込むことにしたのだった。
データ構造はこれになるのかな?
https://www.jpki.go.jp/ca/pdf/cross_certificate_profile.pdf

このアプリではAPIを使ってダンプさせているため、文字列以外は中身が出てきていないようだ。
応用する方法が思いつけば何か作ろうかと思ったが・・・まあ、そういうのは今回は無しだな。

2017/10/26

[java]ASN.1をデコードするライブラリを探す

急に、AndroidでASN.1をデコードしたくなった。
人生は唐突だ。


OpenSSLのコマンドでダンプ出来た気がするのだが、どうもOpenSSLではASN.1の一部しかサポートしていないらしい。
今回読みたいデータがどうなのかわからないけど、二度手間は避けたいところだ。
https://stackoverflow.com/questions/5964269/asn-1-encoding-decoding

Androidの標準にはないような気がするので、Javaで検索した。
Parsing ASN.1 binary data with Java - Stack Overflow

ASN1InputStreamというclassがあるらしい。
親切にサンプルソースへのリンクも載っていて、org.bouncycastle.asn1たちをimportしている。


ここまでは分かったのだが、Android StudioにASN1InputStreamと書いても、いつものようにAlt+Enterで自動的に対処してくれなかった。
ということは、外部JARなどを追加しないといけないのだろう。

それはわかるのだが、これからどうしたらよいのだろう?


こちらが本家だと思われる。
The Legion of the Bouncy Castle Java Cryptography APIs

latest releasesページにJARファイルがあるので、それを使えばよいのか。


それはそれでよさそうだが、StackOverflowに貼ってあったサンプルソースのリンク先を見てみると、ディレクトリ構造?の先頭が「Maven-Central」になっている。
そういえば、pyCharmなんかでは、ライブラリを検索して追加する機能があったけれども、AndroidStudioにも同じようなものがあるかもしれない。

これか。

image

「bouncycastle」で検索すると、大量に出てきた・・・。
たぶん、mavenのこんなページと同じ感じで出てきているんではなかろうか。
https://mvnrepository.com/artifact/org.bouncycastle

bouncycastleのドキュメントページのこちらにasn.1があったから、今回は「provider」というやつを使えばよいのだろう。
latest releasesでいえばこれか。


ただ、ここまでわかっても、まだDependencyのところで絞り込み方がわからん。。。
「org.bouncycastle:bcprov-jdk15on:1.58」でよい気がするのだが、自信はない。
とりあえず追加してやると、ASN1InputStreamをAlt+Enterでimportしてくれたが、それでも自信が持てない。。。

2017/10/24

[nrf]Embedded Studio用も提供される

Nordicからのメールが来た。

最近、BLE開発から遠のいているのでスルーしようとしたのだが、気になる内容だった。

Nordic SemiconductorのnRF51とnRF52 SoC開発に Embedded Studio IDEのサポートが加わる / Product Related News / ニュース / ニュース / Home - Ultra Low Power Wireless Solutions from NORDIC SEMICONDUCTOR


Embedded Studioは、SEGGER社が提供している統合開発環境だ。
以前、評価用に使ってみたことがある。
hiro99ma blog: [nrf]nRF5 SDK for Eddystoneは動くのか? (9) - SES

これが1年半前のことだ。
このときは、無償で使えるのが評価用というか非商用だったので、評価だけで終わった。
当時は仕事としてもやっていたし、そこにお金を掛けるほどでもなさそうだったのだ。


で、今回の紹介を見ると「商用IDEを無償で利用可能」と書かれている。

NordicがEmbedded Studioのライセンス供与を受けたことにより、nRF5 SDKを使うデベロッパーは、nRF51とnRF52をフルにサポートする商用IDEを無償で利用できるようになりました

KeilでSTM32F1であれば制限なくて使えるように、Embedded Studioもそういう方式が使えるのかもしれない。


EclipseでもSEGGERのプラグインがあるので、無償の環境を作ることはできる。
ただ、やはり環境を一から作るのは面倒だ。
私も一度作った環境は、SDKのバージョンが上がっても使い回している。
Eclipseのバージョンが上がるといろいろやり直しになるので、もうEclipseは困らない限り固定バージョンだったりする。

次回、Nordicのチップを使うことがあれば、最有力候補になるな。


しかしまあ、私もここ1年くらい、あまり組込みっぽいことをやっていない。
FPGAもちょっと触っただけだし、今までやっていたNFCやBLEに至ってはほとんど触っていない。

まずい!
非常にまずい。。。

2017/10/21

[c/c++]URIスキームはラベル扱いになってしまう

お仕事でプログラムを作っている。
まだテスト段階なので仮実装が多く、忘れないように#warningなどで目印にしている。


だから、ビルドするとwarningはたくさん出てしまうのだが、エラーは出ないようにしている。
しかし、ソースを見直しているとこんな行が出てきた。

xxx {
   ...
   for (...) {
      ...
  }http://www.yahoo.co.jp/
}

参照したURLをコメントに書こうとしたのだろうが、間違えてソース中にそのまま貼り付けてしまったようなのだ。

にもかかわらず、エラーになっていない。
なんでだ?


単純なソースファイルにしてみる。

int main(void)
{
    http://www.yahoo.co.jp/
    printf("Hello, World!\n");
    return 0;
}

エラーにならないし、ちゃんと動く。


-Wallをつけてようやく分かったのだが、これは「http」というラベル扱いになったのだ。
こう書くと、printfは実行されずに終了する。

int main(void)
{
    goto http;
    printf("Hello, World!\n");

http://www.yahoo.co.jp/
    return 0;
}


何か使い道はないかと考えたが・・・ないな。
「なんか間違ってるよ」と思われるのがオチなので、やめておこう。

2017/10/19

[git]forkして作業するか、forkせずに作業するか (1)

githubでソース管理することを考えている。
まだ一人なので何とでもなっているのだが、そのせいでチーム開発向けのルールが考えついていないのを、なんとかしようとしているのだ。


いつもは、なるべく作業前にブランチを作って、そこで作業して、終わったらpull requestしてマージしてもらう、というやり方にしている(一人しかいないので、自作自演なんだけどね)。


まず、各作業をする人が同じリポジトリを使った方が良いのか、リポジトリを各人で作ってforkした方が良いのか、というので悩んでいる。

最初は同じリポジトリで試して、今は別アカウントでforkしている。
前者が使えるのは、リポジトリへのアクセス権をもらった場合(organizationに追加してもらうなど)だけのようだから、混ぜてやるなら後者しかないか。

前者の利点は、forkしていないから、git pullなどとすれば最新版がmergeできるというところか。
後者だと、相手のリポジトリにmergeしてもらったあと、fork先からのmergeという手段になってしまうと思うのだ。
GitHubでFork/cloneしたリポジトリを本家リポジトリに追従する - Qiita

今はそれでやっているのだが、けっこうfork先からのmergeを忘れてしまう。。
私が悪いと言えばそれまでなのだが、なまじどちらにも同じ権限を持っているだけに、どっちのリポジトリにマージしたのか忘れてしまうこともあった。

そのちょっと前までは、forkしたリポジトリでブランチを作って、fork先にpull requestしてmergeして、fork先からfork元にpull requestする、という2段階でやっていたのだが、さすがに面倒だったのでやめた。
githubでも、pull requestすると、最初にfork元が候補に出てくるから、直接やる方を推奨しているんじゃないかと思っている。


書いていて気付いたが、組織内であればforkさせる理由はあまりないか。
間違ってmainlineを直接編集してしまうという心配はあるのだが、それを避けたければREAD権限にして...forkしてpull request出すのが安全なのか?
branchにprotectをかけるということができるようだから、mainlineだけ保護してしまえばよいのかな?


しばらく、protectして使ってみて、また考えよう。

2017/10/18

[win]SysinternalsのStrings.exeと他のstringsで結果が違うがわからん

WindowsでSlackアプリを使っている。
未読があると、タスクトレイアイコンに赤か青のドットが表示されるのだが、見逃さないように通知領域に出している。

image

Slackアプリは更新が多く、困ったことに更新されると通知領域に表示させる設定がOFFに戻ってしまうのだ。
デスクトップ版もUWP版も変わらないので、OS側なのかな?


私の心が狭いのか、このOFFに戻ったときがどうにも腹立たしい。
「設定アプリ>個人用設定>タスクバー>タスクバーに表示するアイコンを選択してください」と、たどるのが深いのが、また腹立たしさをいや増す。

タスクバーの設定画面までは通知領域のコンテキストメニュー表示から飛べるのだが、最後の画面にたどりつくには、そこからリンクをクリックせんといかん。
設定画面への直接のURIはいくつかあるのだが、この画面に対しては存在しないようだった。


というのが、前置き。

調べていると、この記事が見つかった。

山市良のうぃんどうず日記(102):Windows 10 Fall Creators Updateで増える「設定」は「ms-settings:URI」で狙い撃ち (2/2) - @IT

この人は、DLLからURIを探し出して、Microsoftのページに書いていない画面も探すことに成功している。
私も同じことをしてみようと、フォルダまで飛んで、cygwinを立ち上げてstringsで文字列を出し、grepでフィルタ挿せた。
が、"ms-settings"が1つも出てこない・・・。

記事の時期のせいかもしれんと思ったが、2017年7月なので、それはなさそうだ。
念のため、Bash on Windows on Ubuntuでもやってみたが、結果は同じ。
むう。

最後に、書いてあるとおりにSysinternalsのStrings.exeでもやってみることにした。
こっちは、出てくる。
結果が全然違うのだ。
なんでー!


あり得るとしたら、Windowsだから2byteのUnicodeを使っていて、Sysinternalsはそれに対応しているから・・・か?
理由はよくわからんものの、Windowsアプリの文字列を取ってくるときにはSysinternalsの方を使うのが無難だということはわかった。

2017/10/17

トラックボールを使ってみる

技術ネタではないのだが、今回はトラックボールに持ち替えて1日目になるので、感想を書いておく。


歳を取ってきて、マウスによる腱鞘炎に悩むことも多くなった。。。
私の場合は、右人差し指の第2関節か、右親指の第2関節がよくやられる。

親指の方はよく理由が分からないのだが、人差し指はホイールを動かす量が多い場合だということがわかっている。
デバッグしていて、ひたすらログを上下に眺める状況が数日続くと、もう危ない。

ロジクールの、ホイールがするする回転するマウスを使うようになって軽減したのだが、限界はある。
中指で代用することもあるのだが、使い勝手が悪い。


マウス以外の選択肢となると、トラックボールかペンタブか。
ペンタブは用途に合わないので、トラックボールか・・・と思ったが、踏ん切りが付かない。

そういうとき、飲み会でトラックボールに変えた人がいたので、思い切ってやってみたというわけだ。


買ったのは、ケンジントンのトラックボール。
ネットで買うともっと安いのだが、ヨドバシでは5,100円だった。

image

前方後円墳みたいな見栄えになっているが、下の方は付属品のパームレストだ。
付けた方がよいのかどうかは、まだ悩んでいるところである。

ボタンは2つしかないが、アプリによって同時押しもカスタマイズできる。
私は中央ボタンに割り当てた。
ブラウザでは「戻る」が使えると便利なのだが・・・と思ったら、アプリ単位での割り当てもできた。

ホイールは、ボタンの周りをくるくる回すことになる。
私は親指と薬指で回している。
これのおかげで、スクロールはかなり楽になった。

ホイールのチルトによる水平スクロールはないし、カスタマイズするアプリにもないのだが、他のアプリでShiftキーを押したままホイール回転させることで代用できるものがあるらしい。
今のところ必要に駆られていないので、そういうときはマウスを使うことにしよう。


肝心の使い勝手だが、まだ思った位置にカーソルを動かすことはできないものの、素早い移動はしやすい。
一番難しいのは、ドラッグだ。
まあ、これもやっていれば慣れるんじゃなかろうか。

期待した方向に動かすことができないというのが、慣れの問題なのか、そうでないのか。。。
上下に動かしているつもりでも、ボールを動かす量が多いとぶれてしまうのだ。
ブラウザのマウスゼスチャーなんかは、あんまりうまくできていない。


このままトラックボールでいくか、マウスに戻るのかはわからないけど、もうしばらく使っていてもよいと思った。
とにかくよいのは、指の関節をあまり使わなくて済むところだ。
うまくいけば腱鞘炎対策になりそうだし、そうでなくても腱鞘炎になったらマウスからトラックボールにする、という選択肢が増える。

2017/10/14

[c/c++]16bit→32bitへの拡張は行われるが、32bit→64bitへの拡張は自動で行われない

ミスった・・・。

Windows 10 64bit(Bash on Ubuntu on Windows)
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5)

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    int32_t  a = -1;
    uint32_t b =  1;
    if (a < b) {
        printf("OK\n");
    } else {
        printf("NG\n");
    }
}


私は、符号違いのために64bitまで自動で拡張されてOKルートを通ると考えていたのだ。
たぶん、過去にも同じような記事を書いていたと思うが、そうではなくNGルートを通った。
変数が32bitではなく、16bitであればOKルートを通る。


『Cクイックリファレンス』のp.48に、同じような例が書かれていた。
まず、-1の方がuint32_tに変換されるのだ。
もちろん、明示的にint64_tに変換すればOKルートを通るのだ。


符号の有無が異なるところは、明示的にキャストした方が無難だな。
昔はコンパイラでwarningが出ていたような気がするけど、-Wallしても出ないんだよなぁ。
-Wだけの方がよいかもしれん。

2017/10/13

[git]間違ってcommitしてpushまでしてしまっても怒らない

ぼーっとしていると、gitの操作を間違うことがある。

昨日は、branchを作るのを忘れたまま作業してしまい、そのままcommitし、pushまでしてしまったのだ。
自分しか使っていないのでなんとでもなるのだが、あまり気持ちがよいものではない。


pushする前であればresetでもやるとよかろうが、pushしてしまうと、できないことはないらしいが、取り消さない方が良いそうだ。
まあ、そういう気はするな。

しかし、それをやってしまうことはあるだろうから、グループ内で運用する場合であっても怒らないような文化にした方がよいだろう。
やってしまいがちな操作を禁止して、やらかしたら怒る、というやり方は萎縮させてしまうだけだと思うので、手順を決めておきたい。


結局、こうやった。

  1. やってしまったcommitをrevertで戻す
  2. その状態でpush
  3. ブランチを新しく作って移動
  4. 1のrevertをrevert
  5. その状態でpush

どうせpushするつもりだったんだから、もうそれでいいや、という運用だ。

commit履歴のコメントが「最初のコメント」「Revert 最初のコメント」「Revert Revert 最初のコメント」と並んでしまうのだが、やらかしたんだな、くらいでスルーしてしまえばよい。


しかし、コメントに「Revert」と入るだけだったら、本当にRevertしたのか、コメントの文字列に書いただけなのか区別できん気がするのだけど、そこまで管理してるのかな?

[btc]bitFlyerのP2WSHアドレス

さっき、bitFlyerからメールが来た。
私はbitFlyerにアカウントを作っているので、アナウンスがあるとメールが送られてくるのだ。


いつも bitFlyer をご利用いただきありがとうございます。 P2WSH 方式の Segwit に対応いたしましたのでお知らせいたします。
 
【P2WSH 方式の Segwit に対応】
お客様が bitFlyer アカウントからビットコインを外部のビットコイン・アドレスへ送付する際のトランザクションを P2WSH(Pay to Witness Script Hash)方式の Segwit に対応しました。当社が世界初*で採用した P2WSH は数ある Segwit の実装方式で安全性及び技術的難易度が高いもので、アドレスが「bc1」で始まることが特徴です。


ほー。


この話は、BIP141と、BIP173に関連したものだ。


まず、「P2WSH方式のSegwit」から。

今のところ、Segwitの表現方法は4つある。
https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#examples

  • P2WPKH
  • P2WPKH nested in BIP16 P2SH
  • P2WSH
  • P2WSH nested in BIP16 P2SH

P2PKHのSegwit版がP2WPKH、P2SHのSegwit版がP2WSHと、名前に「W」が入る。
それに「nested in BIP16 P2SH」が付くかどうかだ。

P2SHというのは、「マルチシグ」が代表格で、複数の人が署名するようなタイプのアドレスだったり、個人じゃなくてスクリプトに署名したり、するタイプのアドレスだ。
個人向けの非SegwitアドレスがP2PKHで、そうじゃなく非SegwitアドレスがP2SHと思っておけばよいかな。


Segwitは、アドレスの方式ではなく、トランザクションの構成などを表すもの。
トランザクションの構成が違うから、アドレスも区別できるようにした、というところかな。

しかし、いきなり「明日からSegwitのアドレスだけにします」と言われても、他のアプリは急に対応できない。
だから、まずは純粋なSegwitのトランザクションではなく、P2SHの皮をかぶせたSegwitトランザクションを作ろう、ということになったんじゃなかろうか。
経緯は知らないが、構成としてはそうなっている。
それが「nested in BIP16 P2SH」とついているタイプのアドレスだ。

アドレスを見ただけでは、それがP2SHなのか、Segwitのnested in BIP16 P2SHなのかは区別が付かない。
区別が付かないから、従来のアプリもP2SHとして処理できる、というわけだ。


ただ、皮をかぶせている分、トランザクションのサイズは大きくなっている。
トランザクションのサイズが大きくなると、手数料に反映されてしまう(基本的に、トランザクションのバイト数で手数料が決まるので)。
だから、どこかでnested inじゃないアドレスを作って普及させねば、という課題があったのだろう。
そこで出てきたのが、BIP173だ。


今までのP2PKHやP2SHのアドレスは、秘密鍵にハッシュ計算を何回か行って作り出すものだ。
BIP173で使うBech32という方式?はそれとは異なる。
どう異なるかは、ここで書くにはとても足りないので、BIPを読んでほしい。
けっして、けっして私が理解できなかったわけではないぞ。。。。

BIPに、アドレスの例が載っている。
https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples

価値がある方のblockchainであるmainnetで使えるアドレスは「bc1」で始まっているのが分かるだろう。
bitFlyerのメールだけでは詳細が書かれていなかったのだが、たぶん、これを指しているのだと思う。

BitcoinのMainnetは「bc」、Testnetは「tb」で始まる。
これが「Human Readable Part」と呼ばれる部分だ。
まあ、直訳すれば、人間が読める部分、だな。

その次の「1」は単なるセパレータで、それから後ろが実際のデータ部になる。


Bech32になると、QRコードなんかで表現しやすいらしい。
だからというわけでもないけど、そのうちアドレスはBech32がメインになっていくのかもしれんね。

私ももうちょっと勉強しよう。
リファレンス実装があったので、仕様をよく読まずにC言語でmainnetとtestnetに限定したバージョンを作ったのだけど、regtestのことは考慮になくてね・・・。

2017/10/12

[btc]systemctlでbitcoindを起動させておく

当たり前だが、bitcoindは起動していない間はblockchainの同期を行ってくれない。
testnetしか使わない私だが、作業するたびに同期時間がかかるのは嫌なので、VMを立ち上げたときは起動したままにしているし、クラウド上のものもそうしている。

ただ、Linux自体を再起動したときに起動し忘れることが多々ある。
うちではUbuntuを使っていて、serviceよりもsystemctlを使うような感じがしたので、メモを残しておく。


Sample init scripts and service configuration for bitcoind

bitcoindのgithubに、簡単な説明が書かれているので、基本的にはこれに従う。


説明では、データを/var/lib/bitcoindに置くようだが、既に運用しているデータフォルダがあるし、ユーザも1人しかいないので、そっちを使い回すことにする。

systemdの場合はここに書いてあったが、Ubuntu16.02には /usr/lib/systemd/system というディレクトリが無かった。
作るほどでもないと思うので、 /etc/systemd/system に bitcoind.serviceというファイルを置いた。
個人のものをsystemd/systemに置くのもどうかと思うが、一人だと迷惑はかからんだろう。


ファイルの中身も、githubにサンプルが上がっている。
bitcoin/bitcoind.service at master · bitcoin/bitcoin

PIDは何番でもいいし、wallet機能はいるし、さっき書いたようにユーザも固定したいのでそこら辺だけ変更している。
UserとGroupが個人のもので、今運用しているのだったら、ExecStartは「/usr/bin/bitcoind -daemon」くらいで済んでしまう。

他の設定は、変更してもよいのだろうけど、このままでも困りそうにないので残した。


あとは、これだけやれば起動した。

$ sudo systemctl enable bitcoind.service
$ sudo systemctl start bitcoind.service

reloadするようなコマンドを打たないとダメだったような気がするのだけど、動いてるな・・・。
まあ、reloadせんといかんときはメッセージが出てきた気がするので、それに従えばいいんじゃなかろうかね。

2017/10/11

[c/c++]gccの-Dオプションで文字列を指定する

以前、INIファイル形式を読込みたいので、ライブラリを使った記事を書いた。

コメントとして「#」を許容させるためにあれこれやっていたのだが、ソースを見ると行頭の「;」と「#」はコメント扱いのようだ。。。
https://github.com/benhoyt/inih/blob/master/ini.c#L125

マクロの「INI_INLINE_COMMENT_PREFIXES」は、インラインだから、行の途中で見つかった場合にコメントとする文字のようだ。


前回はMakefile自体を変更したが、よそのgithubに入っているMakefileを変更するのは避けたい。
そういうときは変数が使えるようになっていると、なんとかできる。
inihでは「EXTRACCFLAGS」が外部用に用意されているようだった。

$ EXTRACCFLAGS="-g -O2 -D'INI_INLINE_COMMENT_PREFIXES=\"#\"' -DINI_STOP_ON_FIRST_ERROR=1" make -f Makefile.static

文字列は、シングルクオーテーションで囲むのがよさそうだった。
Makefile中ではないので、#をエスケープしなくても大丈夫だ。


シングルクオーテーションで囲むのは、-Dで関数マクロ形式を指定する場合の説明に載っていたやり方を真似しただけなので、もしかしたら文字列はもっと簡単なやり方があるのかもしれん。

2017/10/09

[zybo]これまでの復習

久しぶりにZyboを触ろうとしたが、どういうものだったか、何を調べてきたのかすら記憶に残っていないので、復習しておこう。



まず、CPU?として、XilinxのZYNQ-7000シリーズである、Z-7010が搭載されている。
PS部としてARM Cortex-A9(650MHz)が2つ。
PL部として7-series Artix FPGA相当のものが搭載されている。

PS部とPL部は、EMIO, AMBAなどのバスでつながっているようだ。


ARMのA9が載るだけあって、周辺も充実している。
RJ45もあるし、HDMI(I/O)、Dsub9のVGA、MIC IN, LINE, INもあるし、タクトスイッチやスライドスイッチ、GPIOのポート(Pmod)もある。
USBは、Type-Aもあるし、microBを使えばFTDIが載っているのでUSBシリアル変換でコンソールとして使うこともできる。

microSDカードもささり、そこから起動させるようなこともできるのだ。


なかなかよいのだが、発売がもう3年くらい前になるためか、情報があまり更新されていない。
FPGAの勉強用であれば、もうちょっと最近発売されているボードの方がおすすめだと思う。

Xilinxが発売しているボードであれば、Vivadoなどの開発環境で最初から設定が入っていそうだから、本筋にすぐ入っていけるのではなかろうか。
私なんか、おかげで、新しいPetaLinux(Xilinxが提供しているLinux環境)をZyboで動かすために数ヶ月かかってしまったぞ。

まあ、それはそれで勉強になってよいのだけどね。


おかげで、まだVHDLとかVerilogとかにはほとんど手を出していない。


FPGAというと、なんとなく組込みジャンルで考えていたのだが、ZyboみたいにOSが載る環境で使えてしまうと、もっと違う使い方をした方がよいような気がしてくる。

もちろん機器の制御もできるけれども、ハードウェアに近い部分でロジックを作ることもできるのだ。
そうなると、柔軟な並列演算処理装置、という見方もできよう。
GPUで仮想通貨のマイニングしたり、ディープラーニングの演算をさせたりするような、そんなイメージだ。

私はCortex-M系のマイコンを使うことが多かったのだが、A系だと電池で動かすこともないだろうし、動作クロックもそうとう高い。
Linuxを載せたとしたら、デバイスの制御にはデバイスドライバを介することになるだろう。
割り込み処理ですれスケジューリングされてしまうはずだ。


そうなると、少々のことであればPL部を使う必要がないはず。
PS部からGPIOで制御した方が、自由がききやすいと思う。
そうなっていないということは、A9とOSが載った環境ですら難しいことをPL部にやってもらうのがよいのではなかろうか。

ということで、結果的に「FPGAのFPGAっぽい部分をがんばるべし」という結論になった。
何をがんばればよいのかわからんけど、GPIOみたいなものの制御ではなく、並列でロジックを書けるようになるとか、そういう方向がよいのかな?

[xilinx]SDx 2017.2が出ていた

3連休なので、FPGAのことをやることにした。

最後にFPGA関連で更新したのがは、PetaLinuxをPC-Linuxでビルドする話の最終回で、ちょうど1ヶ月前(2017/09/09)だった。
あれからVivadoなども起動せずにいたのだが、今日Xilinx Information Centerを起動すると、SDx 2017.2が出ていた。
リリース日が09/05になっているから、単に私が見逃していただけのようだ。

image

Xilinxのすごいところは、リリースノート(pdf)なんかも日本語版を用意するところだ。
過去の分から作りやすいだけなのかもしれないが、いやいや、すごいもんですよ。


さて、いまSDxをインストールしているのだが、これにはVivado 2017.2も含んでいる。
使ったこと無いけど、Vivado HLSも含んでいる。
リリースノートからすると、XSDKに入っているのと同じARMのToolchainを含んでいるそうだ。
だから、XSDKでできることがSDxでもできるのであれば、SDxだけあればよいはずだ。


SDxがインストールできるのは、Zybo購入時にSDSoCのライセンスを購入しているからだ。
つまり、WebPACKではないので、WebTalkをオフにすることができる。
まあ、仕事で使っているわけでも無いし、変な動作をしないなら気にしないのだけどね。


あとは、私がこれらを使いこなせるかどうかなのだが・・・まだ全然ダメだ。
まずは、LED以外のチュートリアルを動かして遊んでみよう。


SDxでインストールされたVivadoを起動すると、ウィンドウの名前は「Vivado 2017.2_sdx」という名前になっていた。
微妙に違いがあるのかもしれん。

Vivado 2017.2で使ったことのあるプロジェクトがRecentとして出てきたので、そこら辺は共通なのか。
ただ、IPのリビジョンが微妙に上がっていたようで、そこはUpgradeした(プロジェクトをVivado 2017.1で作ったままだったかもしれない)。


Upgradeしたあとは、Bitstreamを作り直す。
プログレスを示すくるくるが出てくるようになった。
できれば、右下に出てくるか、最小化しないようにできるとありがたいのだが、まあぜいたくは言うまい。

いまRunning synth_designが実行されているようなのだが、とても長い。。。
そんなにPCの性能は悪くないと思うのだが、うたた寝しても良いくらいの時間はかかっているだろう。

ようやく終わって、Exportしなおして、Launch SDKすると、SDxが起動した。
以前、XSDKで作っていたプロジェクトが表示されている。


ということは、SDxがインストールされていれば、VivadoとXSDKは個別にインストールしなくてよいということになるな。


ついでに、SDxのチュートリアルをやっておこう。
SDxのリリースノートから、ug1028-sdsoc-intro-tutorial.pdfというSDSoC環境チュートリアルがたどれたのだ。

チュートリアルをやりたいというよりは、SDxでZyboを使ったデバッグができるのかを試したかったので「6.デバッグ」だけにする。


説明はZC702ボードになっているが、Zynq-7000デバイスであればよいらしい。
Zyboはそうなので、動くのだろう。
スタンドアロンアプリケーションをダウンロードして実行するところまで行えるそうだ。

ボードの設定は、SDカードがどうのこうの書かれているが、microUSBで電源とUARTを確保し、起動モードはJTAGにした。
以前System Debugをした感じからすると、他のモードでも動くんじゃないかと思うが、演習に関係するところだけ確認させたいのでそうしているようだ。


次は、スタンドアロンプロジェクトの作成。
書いてあるとおりにやっていくだけだ。
最後に「Build Project」するのだが、これが重くて長い。。。
15分以上やっているが、まだ25%だ。

結局、26分くらいかかりました。

image

すごいスペックというわけではないけど、けっこうよいスペックじゃないかと思うのだが、どうだろうか。
ウイルス対策ソフトがDefenderなので、そこで時間かかったりするのかもしれん。


デバッグは、Eclipseでデバッグするときの要領でよいが、選択するのは「Launch on Hardware(SDSoC Debugger)」だ。
似たような項目がたくさんあるので、赤文字のところを気にしておこう。
選択すると、パースペクティブを変更するか聞いてくるので、Debugに切り替える。
そうすると、mainで止まった状態が表示される。

ZyboのUARTというかシリアルポートというか、それをターミナルにつないでおく。
私はTeraTermにした。


ブレークポイントで止まった状態なので、再開アイコンをクリックする。
そうすると、ターミナルに何か出てきて、SDxの方は_exitで停止した。
ブレークポイント一覧を見ると、mainと_exitに設定されていたので、これでよいようだ。

Testing 1024 iterations of 32x32 inting point mmultadd...
Average number of CPU cycles running mmultadd in software: 1145442
Average number of CPU cycles running mmultadd in hardware: 19192
Speed up: 59.6833
TEST PASSED


何をやったのかはわからんが、行列演算で使いそうな計算をPL側に持っていったことで高速化したとか、そんな感じではなかろうか。
まったくVivadoに触ってないし、FPGA Programなんかもやっていないから、うまいこと使いこなせると私のようなソフト屋さんには便利そうだ。

2017/10/07

jqコマンド

最近、JSON-RPCで指示を出して、その結果を取得するようなプログラムを作った。
ネットでよくある、JSON整形してくれるページで結果を確認したので、まあ間違ってはいないようだ。


JSON形式は、あまりお好きではない。
理由は、コンマだ・・・。

最後のデータにコンマを許可しないというルール故に、出力するときはひどく面倒なのだ。
まず、1行目の先頭にコンマがあってはならないので、1行目は普通に出力する。
2行目があるなら、コンマを出力してから2行目を出力することになる。
そして、それを繰り返していき、最後のデータの場合はコンマ無しで終わらせる。


順番にデータを掃き出すときはそこまで困らないのだが、嫌なのはforなどでぐるぐると掃き出したい場合だ。
コンマを出力する処理を、行の出力を行う前に置くか、後に置くか。。。
前に置くと、1行目だけコンマ出力をスキップする、という処理がいるし、後に置くと「次のデータがあるか」をチェックする処理がいる。
それが嫌だったら、1行目の出力と2行目以降の出力を分け、forですぐにコンマ出力するようにしておけばよいが、コンマのためだけに処理を分けるのも腹立たしい。

最後のデータにコンマを許可するか、あるいはコンマを無くしてしまう構造だったら悩まなくて済むと思うのだ。
まあ、データ構造に文句を言っても仕方ないのだが・・・。


JSON形式で出力するのが面倒であることを書きたいだけの記事なのだが、それだけでは何なのでjqコマンドのことを書こう。

Ubuntuではapt-getでinstallすることになるが、jqというJSON形式のデータを整形したり加工したりできるコマンドがある。
非常に多機能なのだが、自作で掃き出したJSON形式の改行やスペースが見づらかったとしても、引数無しでjqコマンドを通すだけで見やすくなる。

$ ./cli/lightning-cli getinfo
{ "id" : "02d030cf51591116155597cee2cbf8bb432fa01b691c055d329b51c838fd754130", "port" : 9735, "network" : "testnet", "version" : "v0.5.2-2016-11-21-964-geedbd1d", "blockheight" : 1209621 }


$ ./cli/lightning-cli getinfo | jq
{
   "id": "02d030cf51591116155597cee2cbf8bb432fa01b691c055d329b51c838fd754130",
   "port": 9735,
   "network": "testnet",
   "version": "v0.5.2-2016-11-21-964-geedbd1d",
   "blockheight": 1209621
}

ほら、この通り!
カラーが使えるコンソールであれば、パラメータとデータで色分けもしてくれるし、データも数値か文字列かで色が変わってくれるので、見やすい。


いま見ているgithubのサイトで、よくわからない使い方をしているので、なにやっているのか見ておきたい。

https://github.com/ElementsProject/lightning#receiving-and-receiving-payments

route=$(cli/lightning-cli getroute <recipient_id> <amount> 1 | jq --raw-output .route -)

cli/lightning-cliコマンドが何を出力するのかはあまり関係ないのだが、例がないと分かりづらいので載せておこう。

{ "route" :
         [
                 { "id" : "aaa", "channel" : "1207790:27:0", "msatoshi" : 101023561, "delay" : 92 },
                 { "id" : "bbb", "channel" : "1207703:21:0", "msatoshi" : 100511006, "delay" : 56 },
                 { "id" : "ccc", "channel" : "1207785:11:0", "msatoshi" : 100001001, "delay" : 46 },
                 { "id" : "ddd", "channel" : "1207779:2:0", "msatoshi" : 100000000, "delay" : 36 } ] }

コマンドの1行としては、「route=$(中身)」が外側で、その中身がjqの結果になるのだと思う。
では、cli/lightning-cliコマンドが出力した内容をjj.txtというファイルに保存したとすると、こうなるはず。
青文字が結果だ。

$ cat jj.txt | jq --raw-output .route-
[
   {
     "id": "aaa",
     "channel": "1207790:27:0",
     "msatoshi": 101023561,
     "delay": 92
   },
   {
     "id": "bbb",
     "channel": "1207703:21:0",
     "msatoshi": 100511006,
     "delay": 56
   },
   {
     "id": "ccc",
     "channel": "1207785:11:0",
     "msatoshi": 100001001,
     "delay": 46
   },
   {
     "id": "ddd",
     "channel": "1207779:2:0",
     "msatoshi": 100000000,
     "delay": 36
   }
]

「route」要素だけを出力したことになるのかな?
ただ、これを環境変数?に代入して、echoなどで掃き出しても、改行が残らないのだ。

$ route=$(cat jj.txt | jq --raw-output .route -)
$ echo $route
[ { "id": "aaa", "channel": "1207790:27:0", "msatoshi": 101023561, "delay": 92 }, { "id": "bbb", "channel": "1207703:21:0", "msatoshi": 100511006, "delay": 56 }, { "id": "ccc", "channel": "1207785:11:0", "msatoshi": 100001001, "delay": 46 }, { "id": "ddd", "channel": "1207779:2:0", "msatoshi": 100000000, "delay": 36 } ]

最後のハイフンがそういう意味なのかと思ったけど、ハイフンを外しても結果が変わらんかった。
tarコマンドで、標準出力とか標準入力とかを使うときにハイフンを付けるのと同じ意味のように思う。
じゃあ、パイプじゃなくてもいいやん、というか、パイプで書いているからハイフンがなくても動いているのかもしれん。


とにかく、何が言いたかったかというと、バイナリデータ最高!、ということでした。。。

2017/10/06

AzureでVM作った後にNSGを変更する

まったくの個人メモです。

Azureの使い方がよくわかってないけど、がんばってVMをたくさん作った後で、設定するネットワークセキュリティグループを間違えていたのに気付いたときの変更方法。



  1. 変更したいVMをクリック
  2. 左から「ネットワーク」をクリック
  3. 上に出ているネットワークインターフェイスをクリック
  4. 左から「ネットワークセキュリティグループ」をクリック
  5. 上の「編集」をクリック
  6. 現在のネットワークセキュリティグループが表示されるので、クリックし、気に入ったものをクリック
  7. 上の「保存」をクリック


ネットワークインターフェイス名が分かっているなら、リソース一覧から選択した方が早いな。

2017/10/05

[md]markdownで改行しようとスペース2つ付けたらMD009

Visual Studio Codeをしばしば使っている。

markdownに便利なExtensionsもあるので、適当にインストールしているのだが、それからLINTのようなものが働いて動的に指摘が入るようになった。
あまり慣れていないので助かる。

指摘と言っても、エラーになるわけではないから、無視してもよい。
pyCharmでpythonを書いたときに指摘されるような、あんな感じだ。


指摘を見ていると、改行しようとして行末にスペースを2つ入れているところに何か出ていた。

image

スペースをつなげるなって?
でも、markdownの改行は、行末にスペース2つじゃなかったっけ。。。


https://github.com/DavidAnson/markdownlint/blob/master/doc/Rules.md#md009
https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md009---trailing-spaces

改行についてはbr_spacesというオプションで指定することで回避できそうだが、デフォルトは0だし、vscodeのオプションにはそれっぽいものが出てこなかった。
今回は、MD009はfalse設定にすることで、見過ごすことにしよう。。。


デフォルトが0ということは、markdownの改行はあまりやらないのか、他の手段を使っているということなのか。
英語だと、段落になるまでずらずらつなげて書くのかもしれないけど、日本語だと「ここで別の行にしたいが、段落を変えたいわけではない」ということがあると思うので、そういう違いなのかもしれん。

2017/10/02

[c++]boost::tie ?

前にboostを使って最短経路を求める(1,2,3,4,5)というのをやった。
そのときは目的を達成できてよかったのだが、今になってよくわかっていないところがあることに気付いた。

サンプルソースのここで並び替えを行っているのだが、本業ではこの箇所で辺(edge)に載っているデータを使って計算するようにしていた。

bool found;
graph_t::edge_descriptor e; boost::tie(e, found) = edge(v, p[v], g);

これで、foundがtrueになれば、該当するedgeの番号がeに入ったことになるらしい。

しかし、別の箇所では

boost::tie(e1, inserted) = boost::add_edge(v1, v2, graph);

などとしている。

単に戻り値をeやe1に入れるだけなら、boost::tieなどいらないはずだ。
そもそも、boost::tieってなんだ??


http://www.boost.org/doc/libs/1_65_1/libs/tuple/doc/tuple_users_guide.html

tupleは要素数固定のデータ集、でよいのかな?
そして、tieはtupleだけど要素が固定値ではないもの・・・?


std::pairは2つ限定だし、std::tupleはC++11からのようだから、boostにあったtupleがC++11に入ったのかな?
よく見ると、std::tieもC++11にあるそうだ。
boostのtieとstdのtieは同じものだろうか?

いろいろ疑問はあるが、今回はboost::tieの使い方を知りたいだけだ。
消極的だが、やむを得ん。


int i; char c; double d; 
tie(i, c, d) = make_tuple(1,'a', 5.5);

左辺にtieを置いても、ちゃんと使えるようだ。

ということは、最初に挙げた例のfoundやinsertedも、単に変数として使っているだけか。

いや、この引数がboost::tie::inserted、みたいな役割を持っていて、それによって何か結果が変わってくるんじゃないかと心配していたのだ。
自分でbool変数を作っているのだし、それはないか。


これで終わらせようとしたが、さすがにサンプルコードくらいは書かねばなるまい。

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;
    return 0;
}

123, yoshio


まあ、そのまんまですな。。。

なんというか、局所的な構造体っぽい使い方ができるのかな?
ただ、戻り値を構造体にするとなると、構造体を定義して、実装側と使う人がincludeなどで共通の構造体を使わないといかんけど、tieだと型と順番が揃っていればよい。

けど、だったら構造体でもいいんじゃないの、という気がするが、構造体が増えていくのも面倒な気がする。
型は同じだけど用途が異なるので、中身が同じ構造体を別に用意する、みたいなことはしなくてよいか。


なんとなく、gcc -Sでアセンブラ展開すると、700行近くなった。
試しに、2行追加してみる。

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    boost::tie(b, a) = boost::make_tuple("yoshio", 123);
    std::cout << a << ", " << b << std::endl;

    return 0;
}

これをアセンブラ展開すると、1200行ちょっとになる。
順番が違うから、それに応じたコードを生成するしかないのか。


では、同じtieの並びで変数が違ったらどうなる?

/*
 * $ g++ -o tst tietie.cpp
 */
#include <iostream>
#include "boost/tuple/tuple.hpp"

int main(void)
{
    int a;
    std::string b;
    boost::tie(a, b) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    int m;
    std::string n;
    boost::tie(m, n) = boost::make_tuple(123, "yoshio");
    std::cout << a << ", " << b << std::endl;

    return 0;
}

これは、750行程度だった。

変数mを、int型からuint8_t型に変更すると、972行。
uint64_tにしても同じだった。

C++のテンプレートは、基本的にマクロの拡張のようなものだったと思うので、uint8_tはint内に収まるから、途中は全部int型で処理して最後にキャストしてやろう、みたいなことはできないのだろう。

まあ、今回は最適化したわけでもないし、アセンブラにして眺めただけなので、違いは出てくるかもしれんが、コードサイズが大きくなることを心配するのであれば、そこら辺は実装側で気をつけねばならんだろうな。