2020/12/06

[js]Buffer.from()に'hex'を使えるが0xはいらない

いらないというか、付けたらいかん、という話だ。
JavaScriptとしたが、Node.jsだけの話かもしれん(違いがよくわからん)。

 

ハッシュ関数にBufferを引数に使うものがあった。

最初は文字列のハッシュを取っていたのだが、16進数のハッシュを取りたくなった。
あれこれ調べていたのだが、Buffer.from()の第2引数にencodingで'hex'とすればよさそうだ。
かんたんかんたん。

 

と思ったのだが、なんかハッシュ値がサンプルと違う結果になった。
Bufferがおかしい?

01: const value = '0x0000000000000000000000000000000000000000000000000000000000000000';
02: console.log(Buffer.from(value, 'hex'))

$ node buf.js
<Buffer >

あれ?

01: const value = '0000000000000000000000000000000000000000000000000000000000000000';
02: console.log(Buffer.from(value, 'hex'))

$ node buf.js
<Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00>

 

あー、第1引数を"0x"で始めてしまうと16進数ではない文字列ということでエラーにもならず処理してしまうのね・・・。

 

いくつか試してみたが、こんな感じだ。

"123" → 12
"1234jk56" → 12 34
"1y34" → (無し)

雰囲気だけでいえば、こうだ。

  • 先頭から偶数文字数で16進数文字列(0-9, A-F, a-f)だけ処理する
  • 文字列の途中で16進数文字列以外が現れたら、それより前の文字列を有効とする
    • それによって奇数文字数になるなら切り捨てる
  • エラーは出さない

 

Node.jsにも、その辺りのルールは書いてなかったのだが、共通仕様なのだろうか。

Buffer | Node.js v15.3.0 Documentation
https://nodejs.org/api/buffer.html#buffer_static_method_buffer_from_string_encoding

慎重にやるなら第1引数が16進数文字列かつ偶数であることをチェックするのだろうけど、JavaScript界隈の人なら格好良く処理できるのかもしれん。

2020/11/15

[node]バイナリをHEX形式でconsole.logする

まだまだ初心者の域を出ない・・・というか、出るつもりがあまりなさそうなNode.js。
なんとなく書いて、なんとなく動いてしまうので、もういいんじゃないか、と思ってしまってね・・・。
それに、困ったらCやgolangで書きゃいいんじゃないの、と割り切ってしまっているのも原因だろう。
そもそも、必要がない限りNode.js使ってないし。

 

というわけで、今回はバイナリをHEX文字列でダンプしたいことについてだ。
Pythonのときもいろいろやったのだが、文字列ではないデータを扱うことが多いので、16進数を16進数のままコンソールに出力する手段がほしいのだ。


最初に出てきたのが、Bufferを使うやり方。

01: const data = "abc\x12\x34\x56def";
02: const dbuf = Buffer.from(data);
03: console.log(dbuf.toString("hex"));

$ node xx.js
616263123456646566

デバッグのためにBufferオブジェクトを作るのは嫌なのだが、デバッグと割り切ってしまえば良かろう。
デバッグ用の関数にしてしまうとかすれば心も痛むまい。

 

次に、文字列を1つ1つ16進数文字列に置き換える方式を考えたのだけど、こうなった。

01: const data = "abc\x12\x34\x56def";
02: for (let lp = 0; lp < data.length; lp++) {
03:     process.stdout.write(data.charCodeAt(lp).toString(16));
04: }
05: console.log();

$ node xx.js
616263123456646566

これのテストで「data.charCodeAt(lp)」をprocess.stdout.write()で出力させようとしていて、ずっとエラーになっていてね・・・。
consol.log()だと出力されるということに気付くのにかなり時間がかかった。
文字化けしたら考えよう、というやり方はよくないのだろう。

 

けど、「変なデータでも何でもいいから出力しやがれ」とは思ってしまうのだ。
それで動いてしまうと危険だから、ということなんだろうから、まあ文化の違いだろうね。

2020/11/04

[vbox]おそるべしネステッド

数日前、WSL2とVirtualBoxを両方動かすためにネステッドなんとかをオフにした。

これはオンに戻した後の設定だが、この2つ。

image

image

 

ネステッドVT-x/AMD-Vを無効にすると両方とも無効になる。

で、その状態でゲストOS(ホストはWindows10で、ゲストはLubuntu18.04)を起動したのだが、どうにも遅い。
動いている間は気にならないのだが、起動するまでがとても遅い。

ただ、いつも立ち上がるまで他のことをしているので、ネステッドは関係ないかもしれない。

 

というわけで、目視で計測した。

  • ネステッドを両方オフ:2分くらい
  • ネステッドを両方オン:40秒くらい

うん、ここまで違うとは思わんかったよ。

 

ネステッドを一度オフにすると、GUIからはオンにできないようだ。
コンソールからできる。
Windowsだとパスも通ってるし、管理者権限とかもいらん。

virtualization - Virtualbox enable nested vtx/amd-v greyed out - Stack Overflow
https://stackoverflow.com/questions/54251855/virtualbox-enable-nested-vtx-amd-v-greyed-out

2020/11/03

WSL2とVirtualBox 6.1.16(11月あたま)

前回、WSL2とVirtualBoxを試して失敗した。

hiro99ma blog: [wsl]何も考えずにWSL2にしたらVirtualBoxが起動しなくなった
https://hiro99ma.blogspot.com/2020/08/wslwsl2virtualbox.html

あれから2ヶ月ちょっと経ったが、どうなっただろうか?
失敗しても問題ない環境があったので、そこで試そう。

 

image

image

まず、「Windowsの機能の有効化または無効化」

  • Linux用Windowsサブシステム
  • Windowsハイパーバイザープラットフォーム

 

再起動して、まずWSL2をインストールする前にVirtualBoxのゲストOSを起動させる。
・・・エラーダイアログは表示されないが、起動の途中で止まったままになってしまった。

 

ネステッドページングをオフにしたら起動した。
前回もそうだったが、ネステッドVT-x/AMD-Vを有効化しないようになったおかげかもしれない。

そして、立ち上がりはするのだが、ゲストOSの動作が遅く感じる。
気のせいだろうか・・・。


元に戻す気がするので、ベンチマークを測っておこう。
そういえばLinuxでベンチマーク計測を行おうとするのは初めてだな。

CPUやメモリなどのシステム性能を比較するベンチマークツール | さくらのナレッジ
https://knowledge.sakura.ad.jp/1048/

こちらで、UnixBenchというものが紹介されていた。

https://github.com/kdlucas/byte-unixbench

cloneして、cdして、makeしたら"./Run"を走らせるだけで自動的にテストが開始される。

テストしたまま忘れて数時間放置していたが、最後は1218.8というスコアが出ていた。

 

次は、WindowsハイパーバイザープラットフォームだけをOFFにして、ゲストOSのネステッドVT-x/AMD-Vを有効化し、ネステッドページングも有効にした。

OFFにしても再起動を促されなかったが、ゲストOSを起動すると怒られた。
再起動すると起動できたので、まあよかろう。

今度のスコアは1278.4だった。
約60上がったのだが、これは有意な差なのだろうか?

正直なところ、このくらいだとよくわからんな・・・。

[node]base64urlのデコード

データで、base64urlでエンコードされている項目があった。

base64は、主にバイナリを文字列に置き換えたいときに使うものだ。
8bitの3バイトデータを、6bitの4バイトデータにする。同じ24bitだから。
6bitは64個なので、64個の文字列に当てはめる。A~Zとa~zで52個、0~9で10個。あと2個は”+”と”/”。

base64urlは、”+”と”/”を、”-“と”_”にしただけのものだ。
base64も最初からそうしておけば・・・と思わなくもないが、まあ時代的に仕方なかろう。

 

最初、base64urlというライブラリを使っていた。

https://www.npmjs.com/package/base64url

でも、なんか結果がおかしい(使い方が悪かっただけなのだが、このときはわからなかった)。

自信がないので、普通のbase64デコード方法で試そうとBufferを使うことにした。

https://nodejs.org/api/buffer.html#buffer_static_method_buffer_from_string_encoding

Buffer.from()にエンコードとして”base64”を指定すると、うまいことやってくれる。
固定文字列だったので、自分で”-“や”_”を置き換え、4文字ごとになっていなかったので”=”を追加。
そうすると、ちゃんと期待した値になった。

せっかくなので、base64urlの文字列でどういう例外が出るのかを確認しようとしたのだが・・・エラーにならない。
変な値になるわけでもなく、ちゃんとデコードできている。
あれ、そういうものなの??

仕様としてできるのか、偶然できただけなのか、APIの説明では分からんな。。。

 

ちなみに、base64urlライブラリでもちゃんとできた。

Buffer.from(base64url.decode(“base64url文字列”))

のようにやっていたのだが、

base64url.toBuffer(“base64url文字列”)

だけでよかった。

でも、

Buffer.from(“base64url文字列”, "base64")

だけで済むのなら、それに越したことはないな。

 

GitHubを検索したら、base64はURLやファイル名で安全な文字列もいけるようなことが書いてあった。

https://github.com/nodejs/node/pull/5243/files

creatingとかencodingしか書いてないけど、decodeもいけるよね・・・?

探しづらいのだが、Node.jsのページだとここら辺だ。

https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings

 

'base64': Base64 encoding. When creating a Buffer from a string, this encoding will also correctly accept "URL and Filename Safe Alphabet" as specified in RFC 4648, Section 5. Whitespace characters such as spaces, tabs, and new lines contained within the base64-encoded string are ignored.

ここのencodingは、エンコード・デコードの方じゃなくて、いわゆるエンコーディングだろう(そのまんまだが)。
それに、リンクが載っているRFC-4648 section5の表には"-"と"_"の方も載っているから、心配しなくても大丈夫だろう。

2020/11/01

JWT

JWTという形式のデータが現れた。
現れたといっても、仕事の中で言葉が出てきたというだけだが。

JWTのJはJSONのJ、ということがわかって満足していたのだが、どうもちゃんと調べないとダメらしい。
ちっ。


JSON Web Tokenの略で、JWT。

JSON Web Tokens - jwt.io
https://jwt.io/

RFC 7519にもなっているので、私が知らなかっただけで巷では有名なのかもしれん。
AbstractだけDeepLで翻訳しておこう。

JSON Web Token (JWT) は、2 つの当事者間で転送されるクレームを表現するためのコンパクトで URL 安全な手段です。JWTのクレームは、JSON Web Signature(JWS)構造体のペイロードとして、またはJSON Web Encryption(JWE)構造体の平文として使用されるJSONオブジェクトとしてエンコードされ、クレームがデジタル署名されるか、メッセージ認証コード(MAC)で保護されるか、および/または暗号化されることを可能にする。

クレームというと、お店に文句を付けるというネガティブなイメージになるのだが、”claim”という単語としては「主張、要求、権利、資格」のようなもので、苦情っぽい要素はない。
和製英語だったら別に構わないのだけど、日本語で使うときに意味が変わるというのは止めてほしいな・・・。

 

JSON-RPCのリクエストみたいな使い方をするのだろうか?
使い道は後で調べるとして、まずは文法というかフォーマットを知っておきたい。


RFCは長いのでまだ読みたくない・・・ので、導入のドキュメントを見ておく。
無料のEBOOKもあるようなのだが、メールアドレスだけじゃなくてCompanyとかの入力もあったので、面倒なのでやめた。

JSON Web Token Introduction - jwt.io
https://jwt.io/introduction/

Introductionでは署名するタイプのJWTに焦点を当てるそうだ。まあ、単にJSONをJWTのフォーマットにするだけだとありがたみがあまり無いのだろう。

JWTの使いどころは、AuthorizationとInformation Exchange。承認と情報交換。
他にもあるのだろうけど、まあよかろう。

 

そしてフォーマット。

<Header>.<Payload>.<Signature>と、3つの部分をドットで区切ってあるそうだ。

Header

Base64Urlでエンコードされる。
エンコードするのはJSONデータで、JSONのところは署名アルゴリズムとトークンのタイプを載せる想定のようだ。他にitemがあってもよいのだろうが、”alg”と”typ”はたぶん必須だ。

”typ”は”JWT”でよいとして、”alg”は何が使えるかというと、RFC-7518の3.1章にJWSの”alg”ヘッダパラメータの一覧があった。
サンプルは“HS256”となっているが、これはHMAC SHA-256のことのようだ。

https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1

 

そういえばHMACのしくみをよく知らない。
いつも使う署名といえば、署名する人が秘密鍵を持っていて、データをSHA256のようなハッシュ関数でハッシュ値を求め、それに対して署名計算している。データ長を気にせず署名できる計算があるのかどうか知らないが、私が知っているタイプはデータ長が決まっているので事前にハッシュ計算してデータ長を整えるのだ。

 

HMACの場合は共通鍵のようだ。
じゃあ、JWTというかJWSというか、署名がついてHMACの場合には事前に鍵を決めるというシーケンスがいるのだろうか?
それはそれで面倒だ。

ただ、署名は無視することもできる。
送っている方が「俺だよ、おれおれ」っていう証明を付けてきて、確かに俺さんの秘密鍵を持っていないと作ることが難しいデータを付加しているだけなので、その人が受信した人が思っている俺さんかどうかわからないし、そのデータが正常かどうかなどというのはさらに関係が無い。

“HS256”だけはRequiredなので、これだけはどの環境でも使えないとRFC-7518を名乗ることができないはずだ。

 

Payload

ここにはclaimが入っている。claimには3タイプある。

  • Registered claims
  • Public claims
  • Private claims

PayloadもBase64Urlでエンコードされている。

 

 

Signature

HeaderとPayloadをまとめて署名する。
HMAC-SHA256の例が載っているのがわかりやすかろう。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

かなり省略した。。。すまぬ。
HMACのときにどうやって署名検証するかが気になって、残りがどうでも良くなってきたのだ。

JSON Web Token(JWT)の紹介とYahoo! JAPANにおけるJWTの活用 - Yahoo! JAPAN Tech Blog
https://techblog.yahoo.co.jp/advent-calendar-2017/jwt/

ここを読むと、”kid”というところで公開鍵を参照したりするそうだ。
しかし、HMACって共通鍵だから・・・?

 

まあ、今回は概要を知りたかっただけなので、これでよしとしよう。
あとは会社で詳しい人に聞くとするかね。

2020/10/18

[win]回復ドライブが作成できない

まいった。

image

いつか忘れたのだが、USBメモリに回復ドライブを作っているので、以前は作成できていたのだ。
大きめのWindows Updateが行われたときに作成したと思うので、もう昨年のことか。

 

ここを見ながらやってみよう。

https://navigator3.com/windows-re-come-back/

reagentc.exeでdisabledだったので、ここのdiskpartのところをやっている。

回復パーティションは存在している。いるのだが、GUIでは1つなのだが、diskpartを見ると回復パーティションが2つ存在している。900MBくらいのと、1300MBくらいのだ。
GUIで回復パーティションになっているのは900MBの方だ。1300MBの方もGUIで見えているのだが、何にも割り当てられていない。
とりあえず、1300MBの方にvolumeを割り当てて、reagentc.exeしてみる。
うん、disabledのままだ。

 

再起動させると回復ドライブの作成が進むようになった。
いいのか、そんなことで?
reagentc.exeで見てもまだdisabledのままなのに?
というよりも、回復パーティションが複数あるのは変じゃないか??
もう大混乱である。


検索すると、たくさん出てきた。
私のがどれに当たるのか分からないが、複数はいらんだろう。
そして、diskpartで削除する方法が載っている。なんでGUIから削除しないのかと思ったら、実行できないからだった。

回復パーティションを1つも残さないという選択もあるかもしれんが、リスクは減らしたい。この場合のリスクは、回復ディスクも使えないという場合だ。まあ、ネットでCreationToolみたいなものをダウンロードしてやればよさそうなことは書かれているのだが、時間かかるしね。

あれ・・・もしかして回復パーティションが増えたのはXubuntuをインストールするときに削除できずに残っていて、その後にフルリストアしておかしくなっているとか?
Xubuntuのインストーラでは全消しするように頼んだのだけど、Windowsのことだし特殊なパーティションに見せて(いや、隠して)いたのかもしれない。

 

ここを読む限りでは、回復パーティションはオリジナルに戻す機能くらいしかなさそうだ。

Windows 10回復パーティションを総合的に理解
https://www.partitionwizard.jp/partitionmagic/windows-10-recovery-partition.html

だが、ちょっと困ったときにコンソールが使えるだろうし(そういうときはもうどうしようもないかもしれんが)、残しておいても良かろう。
でも、回復ディスクの場合は16GB以上のUSBメモリがいるのよね・・・。サイズ的に納得がいかん。

 

ともかく、今は回復ディスクの作成中だ。
かなり時間がかかるので、寝る前に仕掛ける、くらいでいいのかもしれん。そこまではなくても、1時間以上はかかると考えておいた方が良かろう。

 

 

文章が滅裂な感じになっていて申し訳ないのだが、正直なところどれが正しくてどれが間違いなのかよくわからないのだ。
回復ディスクの作成が始まらなかったのは間違いなく、それについて調べていって試したのも間違いないのだが、どれによって作成が開始されるようになったのかが分からない。
disabledがenabledになったのであればdiskpartで行った処理がよかったのだと思えたのだろうが、disabledのままで動くようになってしまった。
そうなると、それより前に行ったことがリセットによって今回反映されたのかも?とか、USBメモリを一度抜いたのが良かったのでは?とか、いろいろ考えてしまうのだ。 でも、リセットはそれまでに何度もやってるし、USBメモリを探すのはエラーダイアログが出るよりも後の処理だったから関係ないと思うのだが、とか。

 

そういうわけで、今の私の気持ちとしては、全部忘れてWindows10をインストールし直したい。
インストールし直すことによってすっきりするのと、インストールし直し自体の時間と精神的な負担を比べると、まだ負担の方に軍配が上がっているという状況だ。
これが逆転するのは、システムの動作自体が不安だと感じたときだろう。ネットワークが数日つながらなかったくらいでは、まだまだだ。

変なアプリが動くことによってネットがつながらなくなったという考えもできるのだが、私がそういうアプリを作る立場であれば変な動作を起こさないように最善を尽くすだろう。泥棒されたことに気付かないというのが最善なのだ。自分のPC管理に自信を持っているわけではないのだが、DropBoxなりGoogleドライブなりに置いている時点でもうダメだし、SlackやZoomなんかで打ち合わせしているのはもっとダメダメだろう。

嫌だけど、今のところ信用するしかない、という状況だ。

[win10]なぜかネットにつながらなくなった話

先週、急にノートPCがネットにつながらなくなった。
最初に書いておくが、技術的な話は何もないし、何かしたから直ったわけでもないし、そもそも今も解決したかどうか分からない。

 

うちにはデスクトップPCとノートPCがあり、リモートワークで会社から持ち帰ったノートPCもある。
そして、ノートPCたちだけがネットにつながらなくなった。
初日はルータ(うちはauひかりなので、ホームゲートウェイという)にpingがほぼ通らなかった。「ほぼ」で、たまーに通ることがある、という程度。
WiFiのせいかと思ったが、有線にしても同じ。

あれこれ試していると有線ではつながったようだった。
もう夜中だったので、その日は電源を落として寝た。

 

翌朝はつながった。
よかったよかったと思ったのだが・・・昼に見てみるとまたつながらなくなっていた。
私はほとんどの作業をデスクトップPCで行うので、なかなか気付かないのだ。

さすがにまずいので、Windows10のネットワークをリセット。直らない。
データを残しての初期化。直らない。
データを削除しての初期化。直った・・・? なんか微妙な感じがする。
なんか、pingは通るのだけど、一部のサイトだけしかつながらない。Googleとかauとかdocomoとか。Yahoo!なんかはダメだし、Dropboxなんかもダメだ(そもそもネットにつながらないと気付いたのはDropboxのアプリがグレーになってたから)。
DNSの問題っぽいけど、それならもっとつながらないはずだし。
WiFiのUSBドングルを試したが、変わらず。ノートPCのネットワークはIntelのチップセットで有線も無線もやってるので疑ったのだが、そこではなさそうだ。

VirtualBoxでXubuntuを立ち上げると、なんとそこからはブラウザで普通にアクセスできる。
ということは、問題は外部ではなくOS側にあるはずだ。
念のためUSB起動でXubuntuを立ち上げる。問題なし。
さらに念のためXubuntuをインストールして立ち上げ。問題なし。
じゃあ、なんでWindows10を初期化してもダメなんだ??

 

そんなことをしている間に、もう1台のノートPCの方はつながっていた。
昨日ダメだったのに。今日は何もしてないのに。さっきダメだったのに。
有線でも無線でも大丈夫なのだ。
訳がわからんね。

いじくっていた方のノートPCも全リストアして元に戻した。ネットもつながった。
疲れた・・・。


メモを残しておく。

  • 全バックアップは大切。各アプリの再インストールとかしたくなければ、だが。データはほとんどクラウドにあるのだけど、アプリのインストールは憂鬱だ。chocolateyの設定をバックアップしておけばもう少し楽なんだろうか?
  • Windows10の回復ディスクは大切。全リストアした後、Windowsが立ち上がらなくてね・・・。たぶんXubuntuをインストールしてMBRみたいなものが書き換わったせいだと思う。回復ディスクからコマンドプロンプトを立ち上げてなんかネットを見ながらコマンドを打つと直った。これが今回の騒動で一番面倒くさいところだった。
  • 全リストアの準備も大切。バックアップはするけど、リストアはなかなかしないからねー。Paragon 17のFree版を使っていたのだけど、リカバリー用の起動ディスクを作ってなくてね。ディスクを作るために初期化したWindowsにFree版をインストールして、ADKとかあれこれインストールしたのだけど、どうも作成に失敗した。ネットを参考にしてParagon 16を使うと作成できた。今回の騒動で2番目に面倒だったのがこれだった。
  • BitLockerを使っている場合は、回復キーを残しておくのを忘れぬよう。どこでか忘れたけど、今回の作業で使うことになったのだ。

 

データはなんとかなることが多いのだけど、元の環境に戻すコストが高いので、そこをどうするかという課題が残るのだ。
まあ、新規でインストールするのが一番だし、そうすると環境もすっきりするのだけど、なかなかねぇ。。。
全部ストアアプリになればまた違うのだろうけど、そんなことにはならないし。

 

そして、最初に書いたとおり、何かして直ったというわけではない。
あのまま放置していても直っていたんじゃないかと思う。
また起きそうな気がするので、心配だ。

2020/08/26

Windows10とVT-x有効化

前回の続き。

VT-xが有効に戻ったので、もう一度やってみよう。
T460sでどうやるとVT-xが無効になるか、だ。

 

「Linux用Windowsサブシステム」「仮想マシンプラットフォーム」をONにして再起動。

image

VT-x関係が無効になった。
念のため電源OFFして3分おいてみたが、同じ結果になった。

image

 

この状態で、以前動いていたゲストOSを起動するとこうなる。
まあ、確かにVT-xは有効になってないね。

image


なんか情報ないかと検索すると、いいのがあった。

WSL2とHyper-Vの関係 - Qiita
https://qiita.com/matarillo/items/ca1eecf8f9a3cd76f9ce#%E3%81%A7%E3%81%AA%E3%82%93%E3%81%A7wsl2%E3%81%AFvm%E3%81%98%E3%82%83%E3%81%AA%E3%81%8F%E3%81%A6%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%83%BC%E3%81%AA%E3%81%AE

どうやら「Windowsハイパーバイザープラットフォーム」も有効にするらしい。

有効にしてみたが、それだけではWindows再起動は不要だった。
だが、Intelのツールで見てもVT-xは無効なままだった。
再起動、いや電源OFFだ。

image

ツールによる結果は変わらずでした。

VirtualBoxの方は期待したけど、こちらも同じエラーでダメ。まあVT-xは有効になってないしね。
元に戻していこう。


この設定でも、まだVT-xは無効のままだ。
再起動しかしていないので、電源OFFを試してみるか。。。

...

......

結局、全部OFFにして再起動したらVT-xも有効になったし、VirtualBoxのゲストOSも起動するようになった。

image

 

 

VirtualBoxのバージョンが関係しているかもしれないので、載せておこう。
v6.1.12 r139181だ。

image 

2020/08/25

Intel VT-xがなかなか有効にならなかった

まだWSL2とVirtualBoxの件を引きずっている。

私はThinkPad T460sを使っているのだが、それ以外にもデスクトップPCを使っている。
そして会社から持って帰っているT460sもあるので、3台似たようなPCがある。

先週末にWSL2を有効にする設定をしてしまい、VirtualBoxが起動しなくなっていた。
WSL2の方をあきらめて元に戻すことにした。なんか最初は「仮想マシンプラットフォーム」をオフにしただけではだめだったので、「Linux用Windowsサブシステム」もオフにした。
今はこうなっている。

image

 

で、この設定でデスクトップPCと会社から持ち帰ったT460sはVirtualBoxが起動するようになった。
デスクトップPCで動かしているゲストOSは、VT-xを無効にすると動かなかったので元に戻した、というのは前回のブログ記事になる。

 

そしてもう1台のT460sだが、これはWSL2を使うように設定したままなのを忘れてゲストOSが動かなくなったと悩んでいた。
その時のVirtualBoxが出したエラーメッセージが、文言は忘れたのだがVT-xが有効になっていない、みたいなことを書いていたのだ。

そんなことはなかろう、とBIOS設定を見たが、有効になっている。
念のためIntelのツールをインストールして確認したところ、確かに無効だと出てくる。
(下の赤で囲んだところが無効になっていた)

image

 

試しにWindows10でHyper-Vを有効にしたり無効にしたりしたけど変わらない。

 

なんでじゃー、と会社T460sとBIOS設定から比較していったところ・・・何もせずに有効になっていた。
BIOS設定を見るときに、それまでは再起動していたのを電源OFFしたからよかったとか?

直ったポイントがさっぱり分からなくて、モヤモヤする。。。
これは怒りにまかせて、また「仮想マシンプラットフォーム」をONにするところからやってみるしかないのか。

2020/08/22

[wsl]何も考えずにWSL2にしたらVirtualBoxが起動しなくなった

しまった・・・何も考えてなかった・・・。

 

きっかけは、こちらの記事。

「WSL 2」が「Windows 10 バージョン 1903/1909」でも利用可能に ~Microsoftが旧OSに移植 - 窓の杜
https://forest.watch.impress.co.jp/docs/news/1272017.html

インストールはうまくいったのだが、VirtualBoxのゲストOSを起動したらこうなった。

image

 

Windows10のバージョンは1909だ。

image

さて、どうしよう。


FAQ

WSL 2 についてよく寄せられる質問 | Microsoft Docs
https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-faq

VirutualBox6だとサポートしていそうなことが書いてある。

 

そういえば、ダイアログも「ダメだー」ではなく、nested VT-x/AMD-Vはnested-pagingとunrestricted guest executionなしだと有効にできない、みたいなメッセージだった。

が、WSL2環境を2マシンで作ったので、まず1台は元に戻す。
ただ・・・試しにゲストOSの「ネステッドVT-x/AMD-Vを有効化」のチェックを外したところ、項目がグレーアウトして元に戻らなくなってしまった。
その状態だとWSL環境を戻してもゲストOSは起動しない。
Linuxサブシステムもアンインストールしたが、ダメ。そういう問題ではなさそうだ。

virtualization - Virtualbox enable nested vtx/amd-v greyed out - Stack Overflow
https://stackoverflow.com/questions/54251855/virtualbox-enable-nested-vtx-amd-v-greyed-out

コマンドラインからならできるそうで、実際できた。
助かった!


そしてもう1台の方は、ゲストOSが起動できた。
なんでかと思ったら、ネステッドVT-x/AMD-Vを元々有効にしていなかった。
VM作成時にネステッドVT-x/AMD-Vを有効にしていると、後から取り外すとうまく行かないのか?

 

まずは、ネステッドVT-x/AMD-Vの有効化は何をしているのか?からだ。

VirtualBox で仮想マシンが入れ子 (Nested Virtualization) できるようになった - CUBE SUGAR CONTAINER
https://blog.amedama.jp/entry/virtualbox-nested-virtualization

こちらは2020/02/02の記事で、VirtualBox v6.1になったときの話だ。
この方は、ホストOSがMacで、VirtualBoxのゲストOSにUbuntu、その中でさらにVagrantでCentOSを動かすようなことをされている。
Vagrantは知らなかったのだが、仮想化ソフトウェアの運用をサポートするツールらしい。ということは、仮想かはVagrant自身は行わないのかな?

 

ということは、私が使いそうなところだと、ホストOSがWindowsで、VirtualBoxのゲストOSがUbuntu、その中でdockerを使っう、というのはネステッドにしていないとできないのだろうか?
docker使うからVirtualBox使うか、くらいの気持ちでいたのだが、それが間違っていたのだろうか。。。

動いている環境で試してみよう。

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:7f0a9f93b4aa3022c3a4c147a449bf11e0941a1fd0bf4a8e6c9408b2600777c5
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
....

うーん、動いていると思うのだが。


CPUに依存するという情報もあった。

VirtualBox 6.0 から Hyper-V と共存できるはず - Qiita
https://qiita.com/takotakot/items/94d3218cf8de5b2c1da8

さっきdockerも動いたと書いた方は、Intelのi5-6200Uだ。
それより前に動かなかったと書いた方は、Intelのi5-6500だ。

 

などとのんびりしていたのだが、元に戻した方の環境でVirtualBoxのゲストOSの動きがおかしくなった。
Xubuntu20.04を使っているのだが、なんというか、おかしい、くらいの表現しかできない。ログインするとCrash Reportのダイアログが出てくるのはまあいいとして、ウィンドウマネージャーがあまり動かない。ツールバーにランチャーでコンソールが起動できるようにしているのだが、立ち上げると他のクリックができなくなってしまうし、ウィンドウの移動も拡大縮小もできない。ゲストOSのウィンドウもダメなので、なんかよろしくないことになっているようだ。

 

ちょっとWSL2を触ってみたかっただけなのに、なんか大ごとになってしまった。。。
ゲストOSの件は、VirtualBoxのインストールを修復したら直ったような気がする。

2020/08/21

[lmdb][win10]もう少しlmdbがうまく動作しない件をWSL2で調査

Windows10がversion 2020でなくてもWSL2が使えるという情報が!

WindowsUpdateと再起動を何回か繰り返し、たぶんWSL2になった。
見た目が変わらないので確信が得られないのだが。

 

WSL2になって確認したかったのは、これ。

hiro99ma blog: [lmdb][win10]もう少しlmdbがうまく動作しない件を調査
https://hiro99ma.blogspot.com/2018/06/lmdbwin10lmdb.html

LMDB以外のDBでも似たようなissueが上がっていたので、ファイルシステムが原因だろう。
そしてWSL2になって改善されたということでさっそく動作確認した。

 

記憶がおぼろげなのだが、1回目の実行はDBファイルを新規作成するので成功。
2回目からがエラーになって、最初の起動から5~10秒くらい経過すると成功する、とかだったか。

やってみると・・・・エラーにならない!
WSL2で解決されたんだ!!

胸のつかえが下りましたな。

2020/08/18

[js]npm install -gしていいのはツール類だけ?

前回、TypeScriptでprocessを使うのに@types/nodeをインストールしたけど-gを付けていたのでダメだった、という話をした。

そういえば・・・nodeのライブラリ検索は常に"node_modules"というディレクトリ名で、それをカレントからルートまで順にたどっていくというやり方だったと思う。

ならば、ツールのように実行するものは-gでインストールして動くが、ライブラリは-gだとダメなんじゃなかろうか?

 

いや・・・しかし importも requireもないのに検索するのだろうか?

コンパイルして生成したファイルには、node.d.tsのような記載はない。というか、ほとんどtsファイルと同じだ。
package.jsonの"dependencies"に"@types/node"が追加されたので見に行っているのかと思ったが、外しても動作した。

ということは、Node.jsか?
でも、Node.jsが処理するなら declareは使えないんじゃないだろうか。
あれ、そういえば declareは TypeScript専用なのだろうか? Mozilla.orgでは出てこなかったのだが。もし TypeScriptの予約語なら Node.jsでは解釈できないと思うのだ。

しかし、 node_modules/@types/node には tsファイルしかない。まあ、拡張子が tsでも Node.jsは気にしないだろうが、TypeScriptにしかないキーワードが出てくれば処理できないだろう。
それに、node_modules/@types/node/process.tsをリネームしてみたが、関係なくコンパイルも実行もできた。node_modules を削除しても実行できるので、 process.exit()を tscするときに使うのだな。


関係ないけど、インストールするときに"--save-dev"と書いてあるのが気になった。
どういう意味なのか?

common options: [-P|--save-prod|-D|--save-dev|-O|--save-optional] [-E|--save-exact] [-B|--save-bundle] [--no-save] [--dry-run]

他にもsaveのオプションがあるのか。

* `-P, --save-prod`: Package will appear in your `dependencies`. This is the
                     default unless `-D` or `-O` are present.

* `-D, --save-dev`: Package will appear in your `devDependencies`.

* `-O, --save-optional`: Package will appear in your `optionalDependencies`.

何も付けない場合は "--save-prod" と同じ扱いで "dependencies"に追加される。

製品版と開発版とか、そういうのをきっちり分けるときに使い分けるのだろうか?
ここら辺はそのうち調べよう。

2020/08/17

[js][ts]node.d.tsはローカルにインストールした場合だけなのか

TypeScriptの勉強中で、tscでコンパイルするのと、型がある、くらいのところまで把握した。

 

今日は、これ。

グローバル変数の宣言 - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/type-system/intro/variables

ここに、node.d.tsがあればprocessを使うのに何もしなくていい、みたいなことが書かれている。
なので私はこうしていた。

npm i @types/node -g

プロジェクト作成のところにも書いてあったし、tscは勉強中はグローバルにインストールしておいた方がわかりやすかったので、@types/nodeも-gでインストールしたのだ。

 

しかし、これだとprocessが見えなくてね。
なにかimportみたいなことがいるのかと思って調べたのだが、node.d.tsをどうやって使うのか見つけられなかった。

そういえば、以前グローバルにインストールすると使えないものがあったことを思いだし、-gなしでインストールした。
うん、そうするとコードとしては何も書かずにprocessが使えるようになった。

 

こういうのが、まだよくわかってないのだな。。

2020/08/15

[js]typescript (3)

さて、夏休みのTypeScript勉強の3回目だ。

 


プロジェクトの環境設定

プロジェクトの環境設定
https://typescript-jp.gitbook.io/deep-dive/project

宣言空間

TypeScriptには型宣言空間(type declaration space)と変数宣言空間(variable declaration space)がある、と。

「型アノテーションとして使用できるものが含まれている」と書いてあるのだが、そもそも型アノテーションがわからん。
調べた感じからすると、変数宣言で型指定するあれのことをそう呼んでいるようである。TypeScriptだと変数宣言の後ろにコロンと型名を書くやつだ。
あってもなくても動作するからアノテーションなのかな?

 

型はまあいいとして、変数の方がよくわからん。
変数の宣言は、まあいい。型宣言したものも全部ではないが変数として扱えるらしい。たぶん右辺値だけだとは思うが。。。どうだろう。。。

varだけ書いてあるが、letやconstも変数宣言空間にいるんだろうか?
いてほしいな。

 

モジュール

オリジナルだと”Modules”で、項目も”Global Module”と”File Module”だった。後からオリジナルが更新されたのかもしれん。

ともかく、ファイルの中に普通に宣言するとグローバル扱いになって、別ファイルだろうと名前が衝突する可能性がある。importとかしなくてもいいのか?

ともかく、極力ファイルモジュールにしましょう、ということだった。
external moduleとも呼ぶそうだ。

そのファイルモジュールだが、TypeScriptファイルにimportかexportがあるだけでローカルスコープになると書いてある。
本当か?

 

いろいろ疑わしくなったので試そう。

まず、mod1.tsにfooを、mod2.tsにfooを代入するbarを用意し、tscしてnodeでmod2.tsを実行。
・・・うん、bar is not definedでエラーになるね。

そういえば、そもそもグローバルにいるとかいっていても、mod1.tsとmod2.tsをコンパイルしてリンクするわけでもないので、何かしらプロジェクトみたいな概念があるはずだ。

先にそっちを整えないとTypeScriptの勉強にならんな。
3回目にしてようやくそういう課題が見つかるとは。。。


Node.js & TypeScriptのプロジェクト作成

Node.js & TypeScriptのプロジェクト作成 - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/nodejs

npmを使うようだ。どこかでnpmは略語じゃないと書いてあったが、ここには関係ない話だ。

tscはプロジェクトでインストールするようだ。まあ、これは-gでもよかろうが、バージョンで挙動が変わるかもしれんので安全に行くならローカルか。
そのうち、nvmみたいにバージョン管理されるようになるんだろうか。

@types/nodeというのもインストールする。これは知らなかった。
node.d.tsらしいが、importして使うのだろうか?

そしてtsconfig.jsonももちろんいる。
パラメータを見ると、srcとlibになっている。ここら辺はNodeのお作法なのかな。

package.json の”scripts”にコマンドを書いておくと、 npm runでコマンドが実行できるようだ。
npm のお作法なんだろうけど、そういうのを私は知らんのだ。
取りあえず”build”に”tsc –p .”を書いておくと、npm run buildでビルドできる。


モジュール再び

さて、これでビルドはできるようになったが、今は他のモジュールも使っていないので手動でコンパイルするのとほとんど変わらん。

Node.jsには globalというオブジェクトもあるらしい。

https://nodejs.org/docs/latest-v12.x/api/globals.html#globals_global

Node.jsではそのモジュール内でのローカルになると書いてあるので、他のファイルにあってもグローバルだから見える、というのはブラウザでの話だろうか?

global.fooなどとしても globalは見つからないと言われるから、うん、そういうものだと思い込もう。

 

コンパイルしてリンクする言語じゃないから、1ファイル内で完結しないといかんのかな。
1ファイルといっても、そこからimportしていくだけだろうけど。

 

ファイルモジュールの詳細

ファイルモジュールの詳細 - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/project/modules/external-modules

公開する方は、 exportを付けておけばよい。
その付け方がいくつかあるので混乱してしまうのだが、どれか1種類だけ覚えておいて、自分が使うときはそれを、他の人が違うのを使っていたらツールに任せる、くらいでいいか。

問題はimportだ。
なんかいろいろ書き方があるのだが、これからやるんだったらES module syntaxというやつだけにしましょう、ということか。

ES module syntaxは、exportされたものをimportするときに fromを使うやつだと思っている。
そうじゃないやつはCommonJS syntaxとかいう呼び方で、exportされたものをimportするときにrequire()を使う。
require()の方が良く使われていたし、使い方もシンプルだったのでそうしていたのだが、どうも時代はfromを使うタイプのようだ。

試しにNode.jsでfromを使ってみたらエラーになって、そういえば拡張子を.mjsにしないと動かないんだった、というのを思い出した。


 

力尽きました・・・。

さすがに3回でたどり着くのは無理でした。
まあ、環境の作り方が分かったのと、前提となるJavaScriptの知識が足りてないのがわかったから、じわじわやりますかね。

2020/08/14

[js] typescript (2)

では、2回目はJavaScriptについてだ。
TypeScriptというタイトルなのに・・・なのだけど、TypeScript全開で書いたコードはNode.jsでは動かせないけれども、JavaScript全開で書いたものはTypeScriptでも有効なのだから、まずはJavaScriptのところを見ておかねばなるまい。

といっても、JavaScriptを全部やるわけではなく、TypeScriptとの比較という意味でそういう章立てになってるのだろう。


JavaScript

JavaScript - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/recap

等価演算子の同一

null/undefinedチェック以外は===使っておけ、ということか。
自動型変換は気付きにくいのでやっかいだな。

 

Object型については、===で比較できるのは同一のアドレスを指しているかどうかだけのようだ。
むかしC言語の話で「C言語には値渡ししかない」と説明されて、ポインタもアドレス値を渡しているだけだから値渡ししかないのだ、と納得したのだが、そんな感じだな(なにがだ)。

 

nullとundefined

nullとundefinedについては、基本的に==でnullをチェックすれば良い。
==nullだと==undefinedもチェックできるからだ。
ただし、その変数がそもそも定義されていないという場合には、nullだろうとundefinedだろうと比較したら例外が発生するので、もしそんなことをしたいならtypeofを使う。

むしろ、じゃあどこでundefinedを気にする使い方をするのかというと、構造体とか戻り値とかだそうだ。
戻り値でundefinedを使うくらいなら、golangのようにerrを使うのがよいのか。型アノテーションというのがそういうやつなのかな。

 

JSONのシリアライズは、JSON仕様にnullはあるけどundefinedはないので、nullだったらメンバになるけどundefinedは除外されるらしい。ほほぅ。

まとめとして、TypeScriptのコーディングガイドラインとしてはnullを使わずundefinedだけにするのが推奨らしい。
まあ、変数定義後のデフォルト値がundefinedだから、わざわざnullを突っ込む必要はなかろうということか。
ともかく、==nullでチェックしてる分にはいいんじゃないの、ということだった。

 

クロージャ

聞くね、クロージャという言葉。いくつかの言語で出てきたと思う。

クロージャ - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures

「クロージャは、関数と、その関数が宣言されたレキシカル環境の組み合わせです」。既に意味が分からん。

うーん・・・C++のtemplateみたいな使い方ができる?というほどtemplateにも詳しくないのだが、可変にできそうなところを可変のままにして関数の枠を作っておき、そこに値を与えて新たな関数として使えるようにしてしまう、という感じなんじゃなかろうか。新たな関数にするのも1段だけじゃなく、その新しい関数にパラメータを与えてさらに新しい関数を作る、みたいなこともできるようだ。

まあ・・・使い道が思いつくまでは放置だな。

 

 

Number型

この前かった「開眼!JavaScript」にも書いてあったが、JavaScriptにはネイティブなオブジェクトもあるし、プリミティブ型ももちろんあるのだった。
数値に関してはNumberしかない。

で、Numberっていったいどういうものかと思っていたのだが、倍精度の64bitらしい。double相当か。
最近の言語だからか、2進数による誤差や64bitを超える値を扱うことが考慮されているようで、big.jsというものがあるそうだ。golangのbigみたいなもんか。C言語にはなかったのだけど、最近の動向は調べてないなぁ。

あとは、NaN、無限大、無限小の定義があるらしい。
NaNは、他の言語だとエラーだったり例外だったりするやつか。例では√-1が挙げられていた。
無限大と無限小は、この範囲を超えたら無限になるという閾値ね。外れるとInfinity(あるいは-Infinity)になる。

 

Truthy

「Trueと評価される値」だそうな。反対語はfalsyね。
ちょっとC言語っぽく、0以外がtruthyだ。空文字列でなければtruthyだし、nullやundefinedでなければtruthy。

でもやっぱりbooleanっぽいのがいいよねー、という場合は、これもCっぽく!!が使えるそうだ。
まあ、!が使えるなら!!も使えるわな。
個人的には!を使う時点でtruthyを認めてるんだから!!しなくていいんじゃないの、とも思うのだけど、全体的にそうコーディングしておくと静的解析ツールなんかで間違いを検出しやすいんじゃなかろうか。最初booleanだったものがnumberに変更になったのを忘れてたとか。


モダンなJavaScriptの機能

モダンなJavaScriptの機能 - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/future-javascript

 

classes

確かに本で出てこなかったな、class。
JavaScriptのObjectでも同じようなことはできた・・・というか、できないとTypeScriptでも実現できないんだった。

 

アロー関数

アロー関数はthisの束縛だっけ、あれがコールバックと違うということだったと思うのだが、今やサポートしていないのはIEだけらしいから全環境で使えるという扱いでいいのかな。

あまり理解はできていないのだが、実際にアロー関数じゃないとダメだった場合に遭遇してしまったので、嫌でも覚えないといかんだろうという気がしている。

 

let, const

varじゃなくてlet使っておけばいいと思う。
constも使える。
ブロックスコープじゃないのがあるというのは思ってもなかった。

 

分割代入, スプレッド演算子

困るのがこういうやつなのよ。。。
こういう記法があるんだろうということはコードを読んでいてわかるのだけど、キーワードが分からなくて検索できないのだ。

「スプレッド演算子」といっても、そういう演算子があるわけでもなさそうだし。
検索すると「スプレッド構文」が出てくるのだが、ここではSpread Operatorになっているから誤訳ではなさそうだ。

 

for...of

golangだとrange戻り値の1番目がindex、2番目が要素だったっけ。
for...inがindexを返すやつで、for...ofが要素を返すやつ、ということか。

最近、forでぐるぐる回すのを書いた気がするが、for...ofを知っていればすっきりしただろうに。というか、知ってる人がコード見たら「この人for...of知らんのか」って思うんだろうな。

 

テンプレートリテラル

知ってしまえば「文字列をシングルやダブルで囲む代わりにバッククォートで囲むやつ」なのだけど、あの書き方とこの名前は結びつかないな。今も出てこない。

まあ、便利になるだけで、今の書き方でもなんとかなるから、思い出せたら使うくらいでいいだろう。

 

Promise

わしの若い頃はPromiseがなくてのぅ、と言いたくなったが、単に知らんかっただけだろう。
最近はPromiseを使うところではasync-awaitで事足りることが多かったのだが、あれはあれでPromiseの違う運用みたいなものだったと思う。

ともかく、ここの例になっている非同期とtry-catchのところを読んだだけでも、自分で正しく実装できる自信がない。

 

ジェネレータ

これもコードを見ても名前が思いつかないパターンだ。幸い「function*」が検索できるのでセーフだが。

イテレータの作成をするもので、関数ポインタではない。


 

疲れた・・・。

TypeScriptだったら、みたいなのがほとんど出てこなかった。
3回だけブログにするつもりだったので、あと1回なのだが、はてさて何をやるべきかね。

[js] typescript (1)

やはり TypeScript は避けられなさそうだ。
勉強するしかあるまい。

ブログにでもしないと続かないので、3回くらいやろう。


ここを見ながら。

TypeScript Deep Dive 日本語版について - TypeScript Deep Dive 日本語版
https://typescript-jp.gitbook.io/deep-dive/

JavaScriptについても書いてあるので助かる。

 

tsc 自体は JavaScriptへのコンパイラというかプリプロセッサとか、とにかくそういうものだという認識だ。
TypeScript で書かれたファイルを tscで JavaScriptに変換する。

TypeScript の特徴は型システムの追加で、これは JavaScriptにはないもののようだ。
なので、型システムを使って TypeScriptを書くと Node.jsなんかでは実行できなくなる。あるいはこういう言い方もできよう。型システムを使わずに TypeScriptで書けば Node.jsでもそのまま動かせる、と。


TypeScript といえば Microsoft。
Microsoft といえば Visual Studio Code。
というわけで、 Visual Studio Code を使えば TypeScript開発は楽なはずだ。

TypeScript tutorial with Visual Studio Code
https://code.visualstudio.com/docs/typescript/typescript-tutorial

バージョンが毎月上がるツールは変化が激しいからなぁ。
これを書いている時点では Version 1.48.0だ。

 

いくら Visual Studio Code とはいえ、デフォルトのままで TypeScript は扱えないようだ。

  • tsc のインストール
  • tsconfig.json を作る
  • コンパイル

tscのインストールは npm install –g typescriptでいける。

tsconfig.jsonは、tsc --initでいける。
そのあと、ちょちょっと変更するとよさそう。

  • “sourceMap”をtrueにする。そうせんとデバッガが使えんらしい。
  • “outDir”でコンパイルで生成されたjsファイルの置き場所を指定。ここは個人の好みだろう。

“outDir”は、tscコマンドで単体のtsファイルを指定したときには効果が無いようだ。tsc、だけで実行すると指定したディレクトリ内にjsファイルが生成されていた。

 

コンパイルはコマンドラインから打っても良いが、Ctrl+Shift+Bでもうまいことビルドしてくれるようだ。
プロジェクトがまだ簡単だからそれでいけるのかな?
Visual Studio Code はショートカットキーもカスタマイズできて、私が結構いじるので、人によっては違うキーかもしれん。

 

デバッガを動かしたが、これはtsファイルの方でブレークポイントが止まってくれた。
mapファイルがうまいことやってくれてるのだろう。

このくらいであれば、.vscode/launch.jsonや.vscode/tasks.jsonなどがなくても使えるようだ。


最初はこのくらいで良かろう。
・・・あと2回でどこまでいくのやら。

2020/07/24

[js]JavaScriptとtsc

最近、組み込みのことをやっていないので記事を書くのに熱心ではなくなってしまった。
それでも世の中は進んでいるし、開発もまた止まることがない。。。

 

前回の記事から1ヶ月くらい経ったが、面倒なところは慣れている人にやってもらって、その人が慣れてないところを私がやるなどしてバランスを取ることにした。
まあ、その人が慣れていないのかどうかは知らんがね。

で、お任せしていたらTypeScriptのフレームワークを持ってきてくださった。
「JavaScriptだとちょっとねー」ということだったのだが・・・そういうものなのか!

そんなわけで、よくわからずにTypeScriptにも触れることになってしまった。


そうはいっても、やっている作業が「既存の置き換え」で、サンプルまで作ってもらっていたので力業でやるだけの作業であった。
あまり考えなくて良いのは助かった。

 

幸い、localhostでできる作業だったので、visual studio codeでブレークポイントを張りながらデバッグすることもできた。まあ、面倒だからconsole.log()デバッグが大半にはなってしまったのだが。

それはともかく、初のTypeScriptでいくつかわかったことがある。

  • tscコマンドにPATHが通ってないといかん
  • tscでコンパイルされるとJavaScriptファイルになる
  • 動くのはJavaScriptファイル

tscはJavaScriptへのコンパイラらしい。C++をCに変換するc frontだっけ、ああいう立ち位置かもしれん(私の時代にはC++コンパイラがあったので、よく知らない)。

 

いま検索すると、Visual Stduio CodeでTypeScriptにブレークポイントを張ってやることもできるようだった。しかし・・私がデバッグしたかったのはnode_modulesの下にあるファイル立ちだった。結局、console.log()をJavaScriptファイルに埋め込んで眺めることにした。

いや、node_modulesの下でもブレークポイントは張れるのだが、TypeScriptもわかってないし、JavaScriptもそこまでわかっていないので、関数の呼び出しなどのように変換していることがはっきりわかるところじゃないと対処できないのだ。

はあ。。。


もちろん個人で開発するのであれば、なんでもやって、なんでもやれるのであれば問題ないのだろうが、チームでやるのであれば得意な方面を進めていった方がよいだろう。

あるいは、TypeScriptをやるよりもgolangとかrustをやりたい、と言い換えても良かろう。
なんか今までrustをやろうとするたびにgolangを調べないといけない作業が発生していたのだよ。ようやく最近になってgolangに対する手の抜き方を覚えてきたので、そろそろいける・・・か?

 

まあ、忘れていく一方なので、覚える方についてはネタが尽きんだろう。

2020/06/28

[js]マルチスレッドしたい

JavaScriptはシングルスレッドだったよな、と思っていたのだが、Node.jsではworker_threadsなるものが使えるそうだ。
バックグラウンドで結果を待ち続けつつも表での処理は続けたかったので、2つjsファイルを起動しないといけないのか悩んでいたのだった。


Worker Threads | Node.js v12.18.1 Documentation
https://nodejs.org/docs/latest-v12.x/api/worker_threads.html

私が見たときはNode v14.4.0だったのだが、動かしているのはNode v12.18.1だ。

 

とりあえず、一番上にあったコードを動かしてみよう。
・・・何も起きない。。。
__filenameは実ファイルに置き換えないといけないのかと思ったが、そういうわけでもない。
ログを埋め込んで、isMainThreadで分岐してmain threadと認識しているところまでは分かった。

 

そういえば、module.exportsは外部に提供する場合だったような。。。
今さらだが、module.exports に関数を代入する書き方をした場合、それをrequire()すると関数本体だけが渡されたことになる。
だから、require()した変数に()を付けるだけで実行できる。

 

などと勉強しながらやっていったのだが、たぶんこの例は単独で動かすことはできない。
だって、mainじゃない方の分岐ではrequire()でパースするライブラリを必要としているし。

よし、このサンプルは忘れよう。


次はここだ。

worker_threadsを使ったNode.js マルチスレッドプログラミング - kakts-log
https://kakts-tec.hatenablog.com/entry/2018/12/14/005316

いきなりAPI仕様を見ても分からんので、使い方をある程度見てからにする。
worker.workerDataのサンプルが動いた。

  1. new Worker()でworker thread生成。__filenameは__FILE__みたいなものか。workDataでworkerに値を与えられる。
  2. 起動したworker threadはコンソールログを出してmain threadにスレッドIDをpostMessageする
  3. main threadではEmit Eventで”message”を待ち受けていて、postされたメッセージをコンソールログに出す

main threadでもworkerにpostMessageしているが、これは使っていないようだ。

 

workerDataに関数は指定できるのだろうか?

const {Worker, isMainThread, workerData, parentPort, threadId} = require('worker_threads');

function yoshio(name) {
  console.log(`yoshio=${name}`);
}

if (isMainThread) {
  // mainスレッド
  console.log(`Main Thread!!! isMainThread: ${isMainThread}, threadId: ${threadId}`);

  // 4つ作成する
  for (let i = 0; i < 4; i++) {
    const worker = new Worker(__filename, { workerData: yoshio });
    worker.on('message', (message) => {
      console.log(`[main] message got from worker : ${message}`);
    });

    worker.postMessage("from tokyo")

  }
} else {
  // workerスレッド
  console.log(`[worker] workerData: ${workerData} isMainThread: ${isMainThread}`)
  parentPort.postMessage(`ThreadId: ${threadId}`)
}

ダメだった。

$ node main.js
Main Thread!!! isMainThread: true, threadId: 0
internal/worker.js:194
    this[kPort].postMessage({
                 ^

DOMException [DataCloneError]: function yoshio(name) {
  console.log(`yoshio=${name}`);
} could not be cloned.
    at new Worker (internal/worker.js:194:17)
    ........


classにしたら渡せるのかと思ったのだが、エラーにはならないものの、プロパティしか渡されなかった。JSON.stringify()で見たところ値まで一緒に出てきた、し関数も出てこないし、classが渡されたというよりはコピーしてプロパティだけが残された、ということか。

 

うーん、pthreadみたいにvoid*で大元から渡せると楽なのだけど、同期とか考えると参照渡しはできないということか。。。

試しに、new Worker()の前にインスタンスを作って、スレッド分岐後のmain thread側で書き換えてみたのだが、反対側のthreadには反映されなかった。
アドレス値が表示できればもう少し自信が持てるのだが、まだJavaScript慣れしていないので実装がうまくないだけかもしれん。。。

 

Node.jsのworker_threadsに何を渡すべきか - Qiita
https://qiita.com/ayatty/items/1f5dde995251ac5800ad

共有メモリ方式なのかな?

ただ、私がやりたかったのはメソッドを含めたオブジェクトの共有なのだ。
そういうことは、おそらくできないような気がする。

オブジェクトは1つのスレッドにまとめて、その結果だけをコピーできる形でもらうような設計にする方が無難な気がしてきた。

2020/06/21

[sol]Solidityのこと

なぜ日本語には、「以上」「以下」は対であるのに「未満」の対はないのだろうか・・・。
あったとしても私は聞いたことがないので、あまり普及はしていないだろう。

 

と、本題とはまったく関係ない文章から始まってしまったが、今日はSolidityの学習だ。
細かいところは全部省略する。


Solidity v0.6.10を見る。

Solidity — Solidity 0.6.10 documentation
https://solidity.readthedocs.io/en/v0.6.10/index.html

 

1行目

SPDXを何かしら指定する。

// SPDX-License-Identifier: UNLICENSED

 

2行目

pragmaで対応solcバージョンを指定する。

 

範囲指定

pragma solidity >=0.4.21 <0.7.0;

指定バージョン以上、次バージョン未満(メジャーバージョンやマイナーバージョンの変更がある手前まで?)

pragma solidity ^0.6.11;

 

他にも、構造体を戻り値にしたいpragmaなどある。

 

import

使いたい外部パッケージなど。
残念ながらrequire()はない。
truffle compileなどを使っているとパスの指定はそこまで考えなくて良くなるので助かる。OpenZeppelinとか。

 

本体

これ以降が本体。

 

コメント

//と/* */が使える。
doxygenと同じ感じで、///や/** */もある。
コマンドはdoxygenではなくNatSpecフォーマットというもののようだ。
コンパイル時にうまいことドキュメントにしてくれたりするので、独自でやるよりは従った方が良かろう。


contract, interface, libraryのどれか。
ブロックチェーンに上げられたものは全部見えるので、publicとかprivateとかはない。
変数や関数になるとそういうのが出てくるが、あくまで言語的なアクセスについてだけで、ブロックチェーン的に隠したりとかはチェーンにそういう機能がない限りできない。

 

contractは、他の言語で言うところのclassっぽいもの。
継承もできる。
デプロイがインスタンスを作る作業で、コントラクトアドレスがインスタンスのアドレスと思っておけばいいだろう。

 

abstract contract、というものもあるようだ。
interfaceもあるのだから、どっちかいらないんじゃないかという気もするのだが、作りたいものによっては便利なのかもしれない。

 

libraryはcontractと同じようにデプロイできるのだが、単なる関数の集まりみたいなもので、コンテキストは呼び出し元に依存する。
それだけならよかったのだが、どうもthisが使えるらしいし、呼び出し元のコントラクトのストレージにも触れるようだ。

やらかしてしまいそうなのであまり使いたくないのだが、使いたくなるシーンが出てくるのだろう。
ここら辺は要勉強だ。

2020/06/20

[js]requireとimport

今まで読んでいたJavaScriptのサンプルコードでは、外部モジュール(npmでインストールしたものなど)を使いたいときにはrequire()が使われていた。
なので、C言語で言うところのincludeみたいなものだろうと解釈していた。

 

require()ってどういうパスの解釈をするのだろう、と調べようとしたのだが、なんだかimportというものが出てきた。
時代の流れで変わってしまったとかだろうか?


一番わかりやすいのがここだった。

export / import と exports / require - Qiita
https://qiita.com/kumagaias/items/c8e87bbea496a5351234

なるほど、require()はNode.jsなのか。
だからそれしか見たことが無かったのかもしれない(ブラウザのことを考えていないので)。

Node.js v12.18.1で動かしてみる。

 

 

expo84.js

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.js

import { Expo, ExpoFunc } from './expo84.js'

console.log(Expo);
console.log(ExpoFunc(10));

$ node expo_use.js
(node:24541) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
/home/ueno/Prog/expo_use.js:1
import { Expo, ExpoFunc } from './expo84.js'
^^^^^^

SyntaxError: Cannot use import statement outside a module
  ...

 

モジュールとわからせないといけない?
あるいは拡張子が.mjsならよい?

 

expo84.mjs

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.js

import { Expo, ExpoFunc } from './expo84.mjs'

console.log(Expo);
console.log(ExpoFunc(10));

 

あれ、これでもダメ??

 

 

expo84.mjs

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

export { Expo, ExpoFunc }

 

expo_use.mjs

import { Expo, ExpoFunc } from './expo84.mjs'

console.log(Expo);
console.log(ExpoFunc(10));

$ node expo_use.mjs
(node:24577) ExperimentalWarning: The ESM module loader is experimental.
84
94

 

expo84.jsに戻すとそれはそれでエラーになったので、拡張子を変える場合は呼ばれる方も呼ぶ方も.mjsでないとダメとか?

 

require()を使うなら、こういう感じか。

 

expo84.js

let Expo = 84;

function ExpoFunc(val) {
    return val + 84;
}

module.exports = { Expo, ExpoFunc }

 

expo_use.js

const myexpo = require('./expo84.js');

console.log(myexpo.Expo);
console.log(myexpo.ExpoFunc(10));

$ node expo_use.js
84
94

 

うん、もうrequire()でいいや。。。

[vscode]自動でSuggestions候補を出したくない

Visual Studio Code v1.46.1を使ってJavaScriptを書いているのだが、ドット(.)を打ち込むと自動的に候補が出てくるのに困っていた。

出てくれるとありがたい場合もあるのだが、候補一覧が邪魔してコードが見えなくなることもある。
表示するまでの時間を延ばしてみたのだが、ドットだけ打って、変更する前にちょっと動かしてみようとターミナルにフォーカスを移動してごにょごにょコマンドを入力している間に一覧が表示されたりして、あまり精神的によろしくなかったのだ。

 

設定がいろいろあるので、やり方は違うかもしれんが、私の場合はこれが向いていた。

"editor.suggestOnTriggerCharacters": false

トリガになる文字を打ってもSuggestionしなければいいだけだ。Suggestion自体はやってほしいので、それは別のキーに割り当てておけば良い。

 

vscodeは設定が多くて、どれがいいのかわからないのが困るのよねぇ。ぜいたくな悩みだ。

2020/06/13

[js]classがあるのか

JavaScriptのオブジェクトはプロパティが入っているだけだから恐るるに足らず!と思っていたのだが、classなんてものがあることに気付いた。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/class

ECMAScript2015で導入されたらしいので、サポートしていないエンジンだと使えないのだろう。
Node.jsはだいたい対応しているようだから、気にしなくてよいか。
まあ、私がclassを使うかどうかもわからんがね。


class Person {
    living;
    age;
    gender;

    constructor(living, age, gender) {
        this.living = living;
        this.age = age;
        this.gender = gender;
        this.getGender = function() { return this.gender; };
    }
}

var cody = new Person(true, 33, 'male');
console.log(cody);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }

 

うーん、これでは違いがよくわからん。。。
GUIの部品とオブジェクト指向は相性がいいような話を聞くので、使いやすいシーンがあるのだろう。


前回のように、コンストラクタを置き換えてみる。

class Person {
    living;
    age;
    gender;

    constructor(living, age, gender) {
        this.living = living;
        this.age = age;
        this.gender = gender;
        this.getGender = function() { return this.gender; };
    }
}

var cody = new Person(true, 33, 'male');
console.log(cody);

cody.constructor = function Yoshio(){};
console.log(cody);

Person.constructor = function(banana) {
    this.banana = banana;
};
var cody2 = new Person('great banana');
console.log(cody2);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
Yoshio {
  living: true,
  age: 33,
  gender: 'male',
  getGender: [Function],
  constructor: [Function: Yoshio]
}
Person {
  living: 'great banana',
  age: undefined,
  gender: undefined,
  getGender: [Function]
}

 

ほう! これは予想外の結果だ。
constructorの置き換えで”Yoshio”になるのは分かるのだが、わからんのはbananaだ。
予想では、bananaというプロパティを追加するのだろうと思っていたのだが、結果としてはlivingが代用されている。というか、bananaのコンストラクタ置き換えができていないように思う。

「オブジェクト」と「インスタンス」で用語を分けるなら、インスタンスのコンストラクタは置き換えられるが、オブジェクトのコンストラクタは変更できないということだろう。

インスタンスになってしまえば、コンストラクタの置き換えもできるし、プロパティ(フィールド?)の追加もできる。
JavaScriptというだけで何でも変更できてしまうという心配をしていたのだが、型になる部分の変更は簡単にはできないということだろう。

[js]コンテナの表示名

前回、こういうコードを書いた。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
console.log(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }

 

codyの方は”Person”と表示されるが、bobの方は何も表示されない。
bobは”Object”と表示されてもいいんじゃないだろうか?
あるいは、何かが足りないから表示されないのだろうか。

本では、実行環境によってオブジェクト型の表示が変わるとは書いてあるのだが、何を見て表示しているのかは書いていない。


ありそうなのは、コンストラクタだろう。
cody.constructorとbob.constructorをconsole.log()してみよう。

[Function: Person]
[Function: Object]

Objectの場合は表示しない、というルールかもしれない。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
bob.constructor = cody.constructor;
console.log(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
Person {
  gender: 'zombie',
  age: '153',
  getLiving: [Function],
  living: false,
  constructor: [Function: Person]
}

うむ、予想したとおりだ。

 

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;

cody.constructor = function Yoshio(){};
console.log(cody);
console.log(bob);

$ node prop.js
Yoshio {
  living: true,
  age: 33,
  gender: 'male',
  getGender: [Function],
  constructor: [Function: Yoshio]
}
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }

関数を設定すると、関数名がそのまま出力されるようだ。

 

まあ、コンストラクタは最初しか使われないはずだから、どうでもよいのかもしれん。

2020/06/07

[js]オブジェクト

JavaScriptがわからないと困ることが多くなってきた。
golangの勉強もまだまだなのだが、平行してやらないと。

ネットで検索しながら勉強しているとよくわからなくなってきたので、本を買った。

O'Reilly Japan - 開眼! JavaScript
https://www.oreilly.co.jp/books/9784873116211/

さあ、私も開眼できるのだろうか?


こんなことが書いてあった。

オブジェクトはプロパティの集合体を格納するコンテナです。

メソッドも含めてプロパティなのだそうだ。

 

そりゃそうだろう、と思っていたのだが、JavaScriptのオブジェクトはC++やJavaよりも柔軟というか、golangに近いようだ。

時系列的にはgolangの方が後から出た言語なので、逆だろう、といわれそうだが、私が勉強した順だから仕方ない。

 

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.living = false;
bob.gender = 'zombie';
bob.age = 153;
console.log(bob);

function print(aaa) {
    'use strict';
    console.log(aaa.age);
}

print(cody);
print(bob);

 

codyはPersonはコンストラクタで作ったインスタンスで、bobはObjectをnewして作ったインスタンスだ。
しかし、関数(オブジェクトに紐付いてなくてもメソッドなのかな?)のprint()で引数としてはどちらでも受け入れるし、出力も期待通りになった。

Javaはすべてのclassはjava.lang.Objectの派生だったと思うが、JavaScriptはそういう継承とか何とかいう概念ではなく、プロパティの名前が一致していれば「そういうプロパティがある」ということを受け入れてくれるのだ。

 

これは、bobのプロパティを設定する順番を変更し、ageを文字列にして、getLiving()というメソッドを追加したのだが、それでも実行時エラーにならない。
print()なんか、演算までしているのに、だ。

var Person = function(living, age, gender) {
    'use strict';
    this.living = living;
    this.age = age;
    this.gender = gender;
    this.getGender = function() { return this.gender; };
};

var cody = new Person(true, 33, 'male');
console.log(cody);

var bob = new Object();
bob.gender = 'zombie';
bob.age = '153';
bob.getLiving = function() {
    return this.living;
};
bob.living = false;
console.log(bob);

function print(aaa) {
    'use strict';
    console.log(aaa.age + 3);
}

print(cody);
print(bob);

$ node prop.js
Person { living: true, age: 33, gender: 'male', getGender: [Function] }
{ gender: 'zombie', age: '153', getLiving: [Function], living: false }
36
1533

codyのageは数字だったので3を足し、bobのageは文字列だったので’3’が末尾に追加された。

 

一番最後にこういうのを追加しても、それでも動く。

cody.age = '99';
print(cody);

993

 

この辺が、C++やJavaのような言語と違うところだろう。
最初に決めた型が絶対ではないのだ。C++で同じことをしようとしたら、void*と型を示す変数を追加するとかになるのか?

 

ともかく、オブジェクトは単なる入れ物だ、ということだ。
そしてこの自由さが私にとってはすごくやりづらいところでもある。慣れるしかないのだが。。。

2020/05/15

[golang]go getとgo.mod

go getするとき、pkgに落ちることもあれば、srcに落ちることもある。
ルールがよくわからんなー、と思っていたのだが、もしかしてgo.modによるのか?

[golang]selectとchan

golangで、chanの受信をしているコードがあった。
普通に?1行で受信しているのではなく、selectのcaseで受信していたのだ。
しかも複数chan!
受信って、バッファがあるときはどうだったか忘れたけど、ブロッキングになってるんじゃなかったっけ?


そうでもないらしい。

Go言語でチャネルとselect - Qiita
https://qiita.com/najeira/items/71a0bcd079c9066347b4#select

selectだからというわけでもないだろうが、selectシステムコールのように複数の待ち受けができるらしい。

もしselectがなかったら、どうするんだろう? 非同期はgoroutineで対処するものなのだろうから、どうしようもないのかな。。。

2020/05/04

[golang]手軽そうなkey value storeタイプのDB

golangの勉強をしているが、ちょっとしたデータ保存をしたいと思った。
大げさに言えばデータの永続化だが、プロセスを終了させてもデータが残っているようにしたいだけだ。

 

SQLiteを考えたが、大して検索などしないならkey value storeタイプでもよいだろう。
Cでlmdbを使っていたので、その辺で探してみた。

 

なんとなく手軽そうなので、bboltを使ってみよう。
boltdb/boltというリポジトリがオリジナルだったようだが、そちらはarchiveになっていた。


ちょっとチュートリアルをやって終わろうと思ったが・・・説明が長い!
DBだし、lmdbをベースにしているとなるとマルチプロセスやらマルチスレッドやらgoroutineやらあるので、ちゃんと説明がいるのだろう(読んでないけど)。

 

クロージャーとかいうものを使っているらしい。
他の言語でも聞いたことがある単語だが、まあスルーさせてもらおう。

よくわかってないが、bucketというものを作ってアクセスするようだ。Put/GetがBucketにしかないしね。
lmdbのmdb_dbi_open()で指定するnameのようなものだろうか。

01: package main
02: 
03: import (
04:     "log"
05: 
06:     "go.etcd.io/bbolt"
07: )
08: 
09: func main() {
10:     db, err := bbolt.Open("./db.bbolt", 0666, nil)
11:     if err != nil {
12:         log.Fatalf("%v\n", err)
13:     }
14:     defer db.Close()
15: 
16:     err = db.Update(func(tx *bbolt.Tx) error {
17:         b, err := tx.CreateBucket([]byte("MyBucket"))
18:         if err != nil {
19:             if err == bbolt.ErrBucketExists {
20:                 b = tx.Bucket([]byte("MyBucket"))
21:             } else {
22:                 log.Fatalf("create bucket: %v\n", err)
23:             }
24:         }
25:         err = b.Put([]byte("answer"), []byte("42"))
26:         return err
27:     })
28:     if err != nil {
29:         log.Fatalf("update: %v\n", err)
30:     }
31:     err = db.View(func(tx *bbolt.Tx) error {
32:         b := tx.Bucket([]byte("MyBucket"))
33:         v := b.Get([]byte("answer"))
34:         log.Printf("The answer is: %s\n", v)
35:         return nil
36:     })
37:     if err != nil {
38:         log.Fatalf("view: %v\n", err)
39:     }
40: }

 

まあ、サンプルが動いただけなので、これでいいのかどうかはよくわからん。
追々だ、追々。

追記:
今回の使い方だったら、CreateBucketIfNotExists()の方がよさそうだ。

 

最初、これをWindows10のWSLで動かそうとしたのだが、db.Update()の方は通るもののdb.View()の方で落ちてしまった。DBファイルが存在すると動く。
Linuxの方だと問題なく動くので、これはWSLでlmdbを動かしたときと同じくファイルシステムの問題だろう。
WSL2に期待しております。

[golang]named return values

golangでは戻り値とする変数名に予め名前を決めておくことができる。

Named return values
https://tour.golang.org/basics/7

named returnではなく、named return valuesなので、return valuesがnamedなのだ。

 

01: package main
02: 
03: import "fmt"
04: 
05: func namedReturn(param int) (a int, b string) {
06:     if param == 0 {
07:         a = 10
08:         b = "hello"
09:         return
10:     } else {
11:         return 99, "world"
12:     }
13: }
14: 
15: func main() {
16:     p, q := namedReturn(0)
17:     fmt.Printf("p=%d, q=%s\n", p, q)
18:     p, q = namedReturn(1)
19:     fmt.Printf("p=%d, q=%s\n", p, q)
20: }

かといって、名前を付けていたからといってreturnが空っぽ(naked returnというそうだ)でなければ指定した値を返すこともできる。

この辺は、namedにしたらnamedだけ、みたいなルールの方が良かったんじゃないかと思うが、まあ自分で気をつければいいか。

2020/05/03

[golang]go.modのreplaceを使ってlocal pathにする

ルールが分かればあきらめが付くはず、というわけで、golangのモジュールを理解しようと努めている。
いつか決定版の記事を書きたいものだが、それまでは試行錯誤が続く・・・。

 

golangで実装する場合、必ずgitなりなんなりを使うとは限らない。
どちらかといえば、使わない場合の方が多いかもしれない。
しかし、golangはおそらくバージョン管理システムを使う前提になっているので、そこで混乱してしまうのだろう(仮説)。

 

というわけで、これだ。

When should I use the replace directive?
https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive

Can I work entirely outside of VCS on my local filesystem?
https://github.com/golang/go/wiki/Modules#can-i-work-entirely-outside-of-vcs-on-my-local-filesystem

Version Control Systemを使ってないローカルファイルシステムでもできますか?というところか。
こういうFAQがあるからVCSを使う前提なのだろうと感じているのだ。Googleはなんでもネット上においてもらう戦略なんだけど抜け道はあるよ、ということなのかしらね。

 

replace自体はそんなに難しいものではなく、左側になっているものを右側とみなしてgoコンパイラというかgoコマンドが処理する、というところだろう。
左側にはimportに書いたものを、右側には置き換えたい先を書く。基本的にネットにあるものを取得する前提なので、ローカルパスを指定する場合は、

  • /で始まるパス(絶対パス)
  • ./で始まるパス(カレントディレクトリからの相対パス)
  • ../で始まるパス(上位ディレクトリからの相対パス)

のいずれかになる。

 


ここまでは、まあいいだろう。

いずれGitHubにアップする予定で、2つのpackageを作っていたとしよう。
github.com/hirokuma/helloとgithub.com/hirokuma/world。
helloはworld側の関数を呼び出して文字列を取得し、それをfmt.Printf()するだけということにする。
world側はwordingとlistというpackageを内部で持っていて、wordingの方はlistから文字列を取得するようにしている。

 

これをGitHubにアップする前にビルドしたい。
そうすると、最終的にこうなった。

 

image

hello/go.mod

01: module github.com/hirokuma/hello
02: 
03: go 1.14
04: 
05: require github.com/hirokuma/world/wording v0.0.0
06: require github.com/hirokuma/world/list v0.0.0
07: 
08: replace github.com/hirokuma/world/wording => ../world/wording
09: replace github.com/hirokuma/world/list => ../world/list
  

 

  • helloからは直接参照していないworld/listについてもgo.modに書かないといけない
  • world/listにもreplaceがいる
  • world/wordingとworld/listにそれぞれgo.modがいる

replaceのwildcard指定については要望にありそうだが、v1.4には入っていないし、今後も不明だ。

 

じゃあ、いっそのことimportの方を相対パスで書けばいいやん、と思ったのだが、それはダメだった。
"non-local package"はエラーらしい。
packageのあるディレクトリにあるファイルはダメだとか、そんな記事があったけど確かめてはいない。

Relative import paths(これの2番目の方)
https://golang.org/cmd/go/#hdr-Relative_import_paths

>To avoid ambiguity, Go programs cannot use relative import paths within a work space.
などといっているので、work space(作業ディレクトリ?)を全然別にしてしまえばよいのかもしれん。

が、なんか面倒なので、gitのsubmoduleにして全部平たくしてしまう方がいいのか。

 

ちなみに、go.modにrequireを書いていない場合、go buildすると勝手に追加された。

01: module github.com/hirokuma/hello
02: 
03: go 1.14
04: 
05: replace (
06:     github.com/hirokuma/world/list => ../world/list
07:     github.com/hirokuma/world/wording => ../world/wording
08: )
09: 
10: require (
11:     github.com/hirokuma/world/list v0.0.0-00010101000000-000000000000 // indirect
12:     github.com/hirokuma/world/wording v0.0.0-00010101000000-000000000000
13: )

勝手に追加しないで、別ファイルにしてくれると非常に助かるのだけどね! せめて更新を許可したときだけ上書きとかにしてほしいんだけどね!

2020/04/27

VirtualBox 6.1.6にしたらMint Linuxのフルスクリーンが黒い

タイトル通り。

VirtualBoxを6.1.6にアップデートしたのだが、Mint Linuxをフルスクリーンにすると黒い画面になってしまうようになった。
フルスクリーンでも、最初に出てくるログイン画面は大丈夫なのだ。あそこまではVGAだかSVGAだかのサイズになっていて、画面の中央に表示される。
そこでログインすると、真っ黒なのだ。

 

一度フルスクリーンを解除すると表示されるので、またフルスクリーンに戻せば済む。
済むのだが、何度かやっていると面倒になってきた。

じゃあ1つ前のバージョンに戻すかというと、そうするとクリップボードの共有で問題が出てくる。
なので、6.1.2まで戻した。
そうすると、うん、ちゃんと表示されるね。

 

なんかMint Linuxにしてからあれこれ相性が悪いのだ。
もしかしたらcinnamonとかいうのを選択したからかもしれないが、LubuntuかXubuntuに戻そう。
ここは、最近出たばかりの20.04LTSを試すべきか。

2020/04/26

[golang]"local import "./xxx" in non-local package"はエラーなのか?

こそこそとgolangの勉強を続けている。
別にこそこそしなくてもよいのだが、成果が上がらないので書けるものが無い、というところだ。

 

golangの勉強をしていて一番嫌なのは、importについてだ。
基本的に公開しないプログラムを書くことが多いので(お仕事だからね)、localでgit管理はしていてもリポジトリを外部に公開しないことが多い。
でも、golangはローカルを参照するのは推奨しないとかいってるじゃないか。
なんか、もう、あー、うー、みたいな気持ちになってしまう。

 

そこで、golangのimportについては言語仕様ではない、と思い込むことにしようと考えた。
例えば、importする中に"yoyo"と書いていた場合、そんなものはないのでエラーになる。

package yoyo is not in GOROOT (/usr/lib/go-1.14/src/yoyo)

では、これを"./yoyo"にしてみる。

local import "./yoyo" in non-local package

まあ、実際にないので、これもわかる。
"mkdir yoyo"としても同じ。

では、ここでyoyoディレクトリを作って、その中にhoho.goを作り、"package yoyo"という1行だけのファイルを置く。

local import "./yoyo" in non-local package

うーーーん・・・。
バイナリができていないのでエラーなのだろうけど、ディレクトリつくってpackage指定までしてもimportで文句を言われるというのは、いったいなんなのだろうか?


あれこれやったのだけど、go.modでreplaceしているときはgo get -uじゃない方がよさそう、ということくらいしかわからなかった。

エラー?のようになってたのも、go.modのrequireのところに書いていたせいのような気がしなくもない。が、-u無しでgo getしてもgo.modが更新されてrequireに追加されているようだ。

わからない、わからない。。。

 

今回困っていたのは、github.com/xxxの下に2つディレクトリを作っていたのだ。
ディレクトリAの方は単体で動きつつサブディレクトリA/aでライブラリ的な使い方もできるようにしている。そしてAaは同じ階層にあるA/bをimportしている。
ディレクトリBの方はAのサブディレクトリA/aをimportして使っている。

ビルドしたいのはディレクトリB。
なので、B/go.modではrequireにAaを書いて、replaceでA/aを相対パスで指定していた。
が、そこでgo getすると、

cannot find module providing package github.com/xxx/A/b

のような怒られ方をしてしまう。
そこでreplaceでA/bを相対パス指定するようにするとgo getが通って、B/go.modのrequireにA/bも追加されていた。
ただ、これでもgo get -uするとgitがどうのこうのと怒られてしまった。

 

うん、よくわからんが、go get -uはgo.modよりも強い、ということなのかな。

2020/04/18

[golang]サブコマンドを使う

gitみたいなコマンドは、サブコマンドであれこれできる。
そんな感じのアプリを作りたい。

 

flagというパッケージがあるのだが、ピンとこなかったのでこちらを使ってみる。

google/subcommands: Go subcommand library.
https://github.com/google/subcommands

標準パッケージではないそうだ。まあいい。

 

Usageをそのまま貼り付けてコンパイル。

引数無しで実行。

$ go run subcmd.go
Usage: subcmd <flags> <subcommand> <subcommand args>

Subcommands:
         commands         list all command names
        flags            describe all known top-level flags
        help             describe subcommands and their syntax
         print            Print args to stdout.

exit status 2

コマンド名がsubcmdなのは、ディレクトリがsubcmdだから、subcmd.goというファイル名だからか。。
main.goにリネーム。

$ go run main.go
Usage: main <flags> <subcommand> <subcommand args>

Subcommands:
        commands         list all command names
        flags            describe all known top-level flags
        help             describe subcommands and their syntax
        print            Print args to stdout.

exit status 2

うーん。

$ go run .
Usage: subcmd <flags> <subcommand> <subcommand args>

Subcommands:
        commands         list all command names
        flags            describe all known top-level flags
        help             describe subcommands and their syntax
        print            Print args to stdout.

exit status 2

うーーーん・・・。
まだこの辺のルールが理解できていない私であった。
まあ、ここはgolangのことだからいいとしよう。

$ ./subcmd commands
help
flags
commands
print

`print`しか実装していないので、残りは自動でやっているのだろう。
表示する順番は、自動が先になっているのかソートされているのか。
`print`を`energy`に変更してみる。

$ go run . commands
help
flags
commands
energy

自動が先になっている。
追加した方がどういう順なのかはわからんな。

 

$ go run . help
Usage: subcmd <flags> <subcommand> <subcommand args>

Subcommands:
        commands         list all command names
        energy           Print args to stdout.
        flags            describe all known top-level flags
         help             describe subcommands and their syntax

ここはソートされるのか。
なお、オプション無しでやcommandsにないパラメータで実行するとhelpと同じ出力+exit status 2だった。

flagsは出力がなかった。
`print`にはあるから、ここのflagsはグローバルなフラグなのだろうか?

先に`print`を見ていこう。

$ go run . print

$ go run . print help
help
$ go run . print --help
print [-capitalize] <some text>:
        Print args to stdout.
     -capitalize
        capitalize output
exit status 2

最後のはエラー扱いなのか。
ということは、こうか。

$ go run . flags print
  -capitalize
        capitalize output

そういうことか。ただ"all known top-level flags"だから、違う使い方があるのかもしれん。

$ go run . print MomonGa -capitalize
MomonGa -capitalize
$ go run . print -capitalize MomonGa
MOMONGA

後ろに付けるとオプションではない扱いになるのか。


では、多少コードを変更してみよう。

 

まず、Register()の順序を変更して、`print`を先頭で行うようにする。

$ go run . commands
print
help
flags
commands

うむ、追加した順番なのだな。
helpも順番通りの方が良い気がするのだが、どうなんだろうね。
でも、CommandGroupというのがあるから、グループにできるのかもしれん。

Register()のところを、こうしてみた。

subcommands.Register(&printCmd{}, "ぷりんと")
subcommands.Register(subcommands.HelpCommand(), "よしお")
subcommands.Register(subcommands.FlagsCommand(), "よしお")
subcommands.Register(subcommands.CommandsCommand(), "ぷりんと")

そうすると、helpがこうなる。

$ go run . help
Usage: subcmd <flags> <subcommand> <subcommand args>

Subcommands for ぷりんと:
        commands         list all command names
        print            Print args to stdout.

Subcommands for よしお:
        flags            describe all known top-level flags
        help             describe subcommands and their syntax

第2引数はグループ名で、グループ内でソートされる、と。
たぶんグループ名でもソートされているのだろう。

2020/04/17

[golang]ifの1行で実行とエラー判定をしたい

golangのコードを見ていると、ifで実行しつつエラーの判定をしていることがある。

When Should I Use One Liner if...else Statements in Go? - Calhoun.io
https://www.calhoun.io/one-liner-if-statements-with-errors/

ここの最初に出てくるようなやつね。

01: if err := doStuff(); err != nil {
02:   // handle the error here
03: }

見た目から入っていきたいお年頃。こういう書き方はgolangっぽいという気がするのでまねしたい。

 

16進数の文字列が渡されたら処理をして、そうじゃなかったら別の処理、みたいなことをやろうとしていた。
0xで始まる数字であれば16進数と見なそうかと思ったが、そんなに急ぐ処理でも無いのでデコードしてエラーがなければ、という判定までしよう。
20byteなので、0xまで入れたら42文字。

01: if (len(mojimoji) == 42) && (_, err := hex.DecodeString(mojimoji[2:]); err == nil) {
02:     ...
03: } else {
04:     ...
05: }

syntax error: unexpected comma, expecting )

えっ、ダメなの??

ifを2つに分けると、大丈夫。

01: if len(mojimoji) == 42 {
02:     if _, err := hex.DecodeString(mojimoji[2:]); err == nil {
03:         ...
04:     }
05: } else {
06:     ...
07: }

golang以外だったら分けて書くだろうし、やっぱりセミコロンを挟む書き方はちょっと違うのだろう。

 

言語仕様を探し出せなかったのだが、ifにセミコロンがあると、セミコロン前が処理相当になるらしい。
じゃあ、ダメか。

 

先にhex.DecodeString()してしまえば、セミコロンの後ろに条件文を&&で書いてしまえば良いかもしれん。
が、それは嫌だ!
文字長の処理の方が16進数文字列のデコードより処理が軽いのは間違いなかろう。だったら、先に軽い処理で露払いをして、その壁を乗り越えてから本番を迎えるのがよかろう。

 

「急ぐ処理じゃあない」と書いておきながら矛盾している気もするが、譲れない線もあるのだ。
意味があるかどうかは別としてね。。。

2020/04/12

[linux][xubuntu]Mozcが使えなかったが、何かしたら使えた

タイトルからしてダメダメだな・・・。
そして、内容もその通りなのだ。
すまん。

ただ、記録として残しておきたいだけだ。


事の発端は、VirtualBoxのゲストOSを新しく作ることにしたことだった。

ubuntu系であることは決めていたのだが、それにするかは決めていなかった。
オリジナルもいいし、最近使っていたLubuntuもいい。
別のところでMintを初めて使ってみたのだが、ときどきMintだからうまくいかないと思われるところがあった。もちろん回避方法はあるのだが、今の作業がubuntu環境を前提としているので、ちょっと困る。
ならdockerとかでやりゃいいやん、となるのだが・・・まだうまく使えないのだ。

 

まあ、私の技術的に足りないところは置いておくとして。
今回はXubuntuを使うことにした。Xubuntu 18.04.4。
初めてUbuntu系でオリジナル以外を使ったのが、Xubuntuだったのだ。

そして、ようやく本題。
Xutuntuをインストールして、環境設定をした。
私の場合、全体的にはen_US.UTF8にして、日本語の表示と入力だけはできるようにしている。
英語が苦手なので、ソースのコメントはしばしば日本語で書いているのだ。

日本語を追加してMozcを有効に使用としたのだが、input methodに何も出てこない。
そう、Mozcだけでなく、他の項目も出てこないのだ。
そういえばLubuntuのときもそういうことがあった気がする。

あれこれいじったのだが、結局どれが有効だったかわからないまま、いつの間にかinput methodにリストが表示されるようになっていた。
これはたぶん、Mozcや日本語とは関係なく、リストを更新するところがうまくいかないままだったりとか、そういうものなのかもしれない。

 

ただ、最初に書いたように、何かしたら直った、というレベルなのだ。
今回はfcitxのmozc(という表現であってるのか?)を使っているのだが、im-config, fcitx, fcitx-configなどを最後の方で使った気がする。

さっぱりわからんのだが、input methodに候補が出てこないとダメということはわかった。

2020/04/08

[golang]slackのmentionに返信

slack-go/slackのeventサンプルは返信をするようになっている。
今できていないのだが、それはPermissionが足りないからだろう。

image

うん、この2つがあればmentionを受けられるし、それによる返信もできた。

 

できれば、特定のキーワードがあれば勝手に返信してくれるようにできるとよいのだが。
次回はそれを探そう。

[golang]mentionの戻りtext

こんな構造体を作った。

01: type MsgEvent struct {
02:     Event struct {
03:         Blocks []struct {
04:             Elements []struct {
05:                 Elements []struct {
06:                     Type string `json:"type"`
07:                     UserId string `json:"user_id"`
08:                     Text string `json:"text"`
09:                 } `json:"elements"`
10:             } `json:"elements"`
11:         } `json:"blocks"`
12:     } `json:"event"`
13: }

 

そして、slack-go/slackのeventサンプルでbodyがあるので、こんな感じでデコードした。

01:             var msgEvent MsgEvent
02:             if err := json.Unmarshal([]byte(body), &msgEvent); err != nil {
03:                 log.Fatalf("json: %v\n", err)
04:             }
05:             for _, item := range msgEvent.Event.Blocks {
06:                 for _, item2 := range item.Elements {
07:                     for _, item3 := range item2.Elements {
08:                         if item3.Type == "text" {
09:                             log.Printf("text=%s\n", item3.Text)
10:                         }
11:                     }
12:                 }
13:             }

 

気力が尽きたので、今日はここまで。

2020/04/07

[golang]slack-goのeventsサンプルを動かしたい

以前あきらめた、slackのbotをgolangで作る件だ。
そろそろやろう。

slack/events.go at master · slack-go/slack
https://github.com/slack-go/slack/blob/master/examples/eventsapi/events.go

"TOKEN"が2箇所あるので、そこだけ自分の"xoxb-"で始まるやつと、Verification Tokenというやつに置き換えれば済むはずだ。

しかし、何が悪いのか分からないけど、golang側で動いている形跡がない。
権限などの設定が足りないのか?

 

Basic Information

"Add features and functionality"は、3つ

* Event Subscriptions
* Bots
* Permissions

Verification Tokenはこのページに載っている。

 

OAuth & Permissions

Scopesは、"Bot Token Scopes"だけ。

* app_mentions:read

"xoxb-"出始まるTokenはこのページに載っている。

 

Event Subscriptions

ここのRequest URLが、なんだかすっきりしない。
events.goで"/events-endpoint"となっていたので、ここも"http://x.x.x.x:xxx/events-endpoint"にしたのだよ。あ、ポート番号はgoファイルの下の方で3000番になっていたのだけど、ちょうどiptablesで5000番が空いていたので変更したのだ。

これがよくわからないのだが、goサンプルをrunしていてもいなくても、ブラウザの方ではOKになるのだ。なのに、goの方にはログなども出ない。
あれこれやったところ、どちらも"/evt"にするとアクセスが飛んできた。

こんなbodyが飛んでくる。

{"token":"VTOKENの値","challenge":"ODiveSYjXafQWNBXY9PIIeNLP87Q5KM8gEUVD98rDNajxAebTrta","type":"url_verification"}

 

Subscrie to bot eventsは、"app_mention"を指定。

 

そうして、installなどして、どこかテスト用のチャネルにbotを追加してやって、メンションを投げるとイベントが飛んでくるようになった。
メンションと、Appsの一覧に出てきたアプリ名のところに書き込むのは同じかと思ってたけど、違うのだな。
app_mentionにしているからかもしれないけど、アプリ名以外のところで@つきでメッセージを投げないとダメなようだ。

 

まあいい。
あとは、ここからじわじわ変更していこう。

2020/04/05

[golang]NFC-AのUIDを読む

NFC-AのUIDを読むようにした。

https://github.com/hirokuma/go_pasori370/tree/13639388afe725696a6550cab07e760c9f5ce7b4

NFC-FとNFC-Aを順番にInListPassiveTargetして、先に見つかった方を返す。まあ、2つしかないので先も何もないのだが。

UIDの長さが、Single / Double / Trippleのどれかなのを確認すべきなのだろうが、仕様書を引っ張り出すのが面倒だったので4byte以上ならOKとしてしまった。

 

コードがきれいなのかどうかはまだ判断できないけど、そこまで悪くはないんじゃないかなぁ、どうかなぁ。。
他の人のコードなどを見て勉強するところまでやらないと、レベルは上がらんだろうな。

 

ともあれ、golangでNFC R/Wを動かすのはこれでおしまいだ。

2020/04/04

[golang]ようやくIDmを読む

ようやくgolang + RC-S370でIDmを読むところまでできた。

https://github.com/hirokuma/go_pasori370/tree/fed6133f67075d9dfc065274f71fc84391d38577

$ make
$ make run
2020/04/04 20:49:24 Opened
2020/04/04 20:49:24 write= 0000ff03fdd418011300
2020/04/04 20:49:24 read done: 6(0000ff00ff00)
2020/04/04 20:49:24 read done: 9(0000ff02fed5191200)
2020/04/04 20:49:24 write= 0000ff06fad43202000000f800
2020/04/04 20:49:24 read done: 6(0000ff00ff00)
2020/04/04 20:49:25 read done: 9(0000ff02fed533f800)
2020/04/04 20:49:25 write= 0000ff06fad43205000000f500
2020/04/04 20:49:25 read done: 6(0000ff00ff00)
2020/04/04 20:49:25 read done: 9(0000ff02fed533f800)
2020/04/04 20:49:25 write= 0000ff04fcd43281b7c200
2020/04/04 20:49:25 read done: 6(0000ff00ff00)
2020/04/04 20:49:25 read done: 9(0000ff02fed533f800)
2020/04/04 20:49:25 write= 0000ff09f7d44a010100ffff0101e000
2020/04/04 20:49:25 read done: 6(0000ff00ff00)
2020/04/04 20:49:25 read done: 31(0000ff18e8d54b01011401xxxxxxxxxxxxxxxx100b4b428485d0ff0003e600)
2020/04/04 20:49:25 IDm: xxxxxxxxxxxxxxxx
2020/04/04 20:49:25 PMm: 100b4b428485d0ff
2020/04/04 20:49:25 SystemCode: 0x0003
2020/04/04 20:49:25 Closed

なんとなくIDmは隠してみた。

 

Receiverはポインタ型が良いのかそうでない方が良いのか基準がよくわからなかったのだが、どこかのサイトで「実質は引数に与えられて呼ばれるのと同じ」と説明してあって理解できた。

 

あとは、NFC-AのID読み込みを作って、Pollingで両方実行して先に見つかった方を返す、というところを作ったら終わりかな。
いつもは汎用ライブラリみたいにしてたけど、あれは疲れるからな。

[golang]sliceの先頭に追加してみよう!

意味も無くタイトルでテンションを上げてみました。

データのパケットを作る関数を考えよう。
パケットの詳細を上位層に知らせないようにするため、パラメータをもらって中で加工するはずだ。
加工する際には、パケットの構造によってパラメータを切った貼ったすることだろう。

 

今回はNFCのtagでID読込だけすることにしたので、まずはInListPassiveTargetのパケットを作ろうとしている。
このパケットは汎用的といえばいいのか、NFC-A, B, Fの誰もが使うのだけど、パラメータに共通性はほとんどない。
まあ、このパラメータがほぼそのままRFで飛んでいくのだから仕方あるまい。

 

それはともかくとして、上位層からもらったデータをInListPassiveTargetの形式に収めるのに切った貼ったしたい。
RC-S956のパケットは可変長なのでsliceを使っている。
なので、sliceへの追加という処理が必要だ。


sliceにはappend()という関数があるので、それを使えば用は済む。
そう思っていたのだが、検索していると「遅い」という言葉がよく出てきた。
JavaでStringの処理をするような、そんな雰囲気だろう。

【Go言語】append使い分けのススメ 〜スライスの先頭へ要素を追加するとき、中身の型は固定長?可変長?〜
https://medium.com/eureka-engineering/go%E8%A8%80%E8%AA%9E-append%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%E3%81%AE%E3%82%B9%E3%82%B9%E3%83%A1-%E3%82%B9%E3%83%A9%E3%82%A4%E3%82%B9%E3%81%AE%E5%85%88%E9%A0%AD%E3%81%B8%E8%A6%81%E7%B4%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E3%81%A8%E3%81%8D-%E4%B8%AD%E8%BA%AB%E3%81%AE%E5%9E%8B%E3%81%AF%E5%9B%BA%E5%AE%9A%E9%95%B7-%E5%8F%AF%E5%A4%89%E9%95%B7-dbf31fbf2f69

URL長いよ。。。

それはともかく、パケット生成程度では気にするものではなさそうだ。
たぶんデバイスとの送受信の方が時間かかるだろう。

 

私が思ったのは、コンパイラの限界についてだ。

ハードウェア制御をしていると、ここはアドレスバスを1本ずらしてRAMに接続しているから必ず16bitでアクセスしないとだめ、みたいな状況がしばしばある。
もちろん、コンパイラはそういう状況は知らないので、こっちがソースコードを書いたそのままコンパイルせざるを得ない。

 

そういう外部の状況であれば仕方が無いとして、C言語をメインで使っている人間としては、そういう使い分けを勝手にやってくれるようになってるんじゃないかと期待してしまう。

どうなんだろうか、どうなんだろうか。
私はgccを主に使っていたので、その範囲だとgcc4になって最適化が行いやすくなったような話を聞いた気がする。
しかし、関数単位でやっていると、そこは最適化しにくいだろう。inlineくらいか。

そういう下位層の部分はしかたないとしても、コピーしながら領域を拡張していくようなタイプだったら、うまいことやってくれてもいいのでは・・・。

もしかすると、append()は以前はなかったけれども、あまりにも使い勝手が悪いのでやむなく追加した、とかいう経緯があるのかもしれない。

 

まあいい、ともかく対処はいるのだ。

2020/04/01

[golang]NFCIDだけ読み取ろう、ということにした

設計が・・・とか考えて行動が止まっていたのだが、それくらいだったら適当に実装して作った方がよいだろう。
それを繰り返しているから設計がうまくならんのだ、といわれればそれまでなのだけど、深くは考えまい。

 

というわけで、今回はこういう構成にしよう。

image

 

pcdのところでdevを吸収して、devでRC-S370を受け持つ。
RC-S956を別に分けて、RC-S370ならUSB、RC-S620/SならUART、というようにしてもよいだろうが、今回はRC-S370だけでよい。

 

今はdev.IoCtlというインターフェースを作ってみたものの、まだ活躍していない。
一応、pcdはdev.IoCtlを持たせて、毎回devを呼ぶときに引数で渡して・・・あれ?

Linuxのドライバなんかはopen()してからclose()するまではファイルディスクリプタを使うけど、今回は特にそこまでしなくていいんじゃないのかね。
というわけで、グローバル変数を使うことにした。

 

図のdevでは省略しているが、これ以外にもコマンドごとに構造体を用意している。
それを使ってpcdから呼び出してもらっていたので、devは引数にしていたのだ。
まあ、それならコマンドの構造体メンバにdevを持たせるべきなのかもしれないが、それってあんまり意味がなさそうな冗長だと思ったのだ。

そういう余裕があればあとから改造が楽になる、ということもあるのだろうが。。。

 

とにかく、だ、あっさりした構成で作ることにしよう。

今日のできばえ
https://github.com/hirokuma/go_pasori370/tree/ec94e2dd82be08dd4020ddf285236058818a22c8

2020/03/29

うまく抽象化できてない

いまgolangで書こうとしているRC-S370のアプリというか何というかだが、どうにも抽象化がうまいことできていない。

全然golangとは関係なく、前からできていないと思っているものがまたやってきただけだ。

 

今日までのところ
https://github.com/hirokuma/go_pasori370/tree/e8289f371d29810a9c371eaa91232882f12d2a03

 

mainはどうでもいいとして、それ以外はdevとpcdに分けている。
devでRC-S370のコマンドを書いて、pcdではそれを組み合わせて呼び出すだけにしようかと考えている。

 

が、pcdは意味があるのだろうか。
RC-S370のコマンドを個別に書いたとして、それを呼び出す順番もまたRC-S370に依存していることがほとんどだ。
だとすると、pcdはもっと抽象化してタグを読み書きするインターフェースだけにして、どう呼び出すのかはdevに任せてしまった方がよいのではないか。

それだったら、devでインターフェースを切って、dev/rcs370、みたいな構成にしてしまえばいいんじゃないか。
pcdのように間に入る人がいらなくなる。

 

でもなぁ・・・タグの読み書きといっても、NFC-A, B, Fのような形だとそこは抽象化できないのだよな。
NDEFでやればいいのだろうけど、そこまで気力が湧かない。
偉大だな、NDEF。

 

というわけで、方向性が自分の中ですらモヤモヤしているというところであった。