骨伝導イヤホン買った

いくつかの骨伝導イヤホンを比較検討して、AVIOT Openpiece Elite を購入しました。

今回主に比較したイヤホンは次のものになります。

比較結果

感覚的な部分については1~5の5段階評価しています。主観的な評価となりますが、ご了承ください。

製品名 音質 *1 着け心地 音漏れ デザイン 防塵/防水 価格 コーデック 備考
Shokz OpenRun 2 2 4 3 IP67 SBC 17880 骨伝導といえばのブランド。
ちょっと大きめ
Shokz OpenRun Mini 2 4 4 3 IP67 SBC 17880 頭が大きいつもりだったが、普通に装着できた。
Shokz OpenRun Pro 4 2 4 3 IP55 SBC 23880 これならOpen Run無印でいいかなという印象
Shokz OpenRun Pro Mini 4 4 4 3 IP55 SBC 23880 頭が大きいつもりだったが、普通に装着できた。
AVIOT Openpiece Playful 4 1 3 4 IP67 AAC/SBC 15950 試着は絶対にすべき
AVIOT Openpiece Elite 5 1 3 5 IPX5 AAC/SBC 23870
(ブームマイク付き)
音質マイク共に素晴らしい!
試着は絶対にすべき
ブームマイク無しのマイク音質は微妙
HAYLOU PurFree BC01 1 *2 5 2 2 IP67 aptX/SBC 12900 着け心地最高!
最後まで迷った。
audio-technica ATH-CC500BT 4 2 3 3 IPX4 aptX HD/aptX/
AAC/SBT
17600 アプリが良さげだった。
防水性能もう少し欲しい

まとめ

  • 2023/10 現在これ選んでおけばいいというのはないなーという印象。
  • Openpiece は耳にフィットすれば、かなりいい感じ
  • 音漏れは HAYLOU PurFree BC01 以外はほぼ気にならかなった。満員電車とかではさすがに気になるだろうけれど
  • 絶対試着すべき。

*1:耳が良くない人間の雑な評価です。。

*2:5段階評価という性質上1ですが、若干OpenRunに劣るかなという程度でそこまで悪くないです。

電子書籍/紙書籍の技術書をどのように選択して購入すべきか

はじめに

電子書籍/紙書籍の技術書のどちらを選択して購入すべきかの私見をまとめた記事となります。

電子書籍/紙書籍の技術書の選定基準

電子書籍と紙書籍のどちらを選択して購入すべきかを考える際に、私が考える主なポイントは次の通りです。

  • 購入する電子書籍のフォーマット
  • 読みたい場所。外で読む場合、紙書籍は不便なため、電子書籍を選択します。

基本的には、後述する電子書籍のフォーマットによって、購入する書籍の形式を決定します。
また、索引や目次などの参照が必要な場合や速読に近い読み方をする書籍などは、電子書籍購入後に紙書籍を購入することが多いです。

購入する書籍の形式

電子書籍のフォーマットは、主に以下の 3 つがあります。

  • EPUB こちらのフォーマットは、一般的にはリフロー型のフォーマットです。
    基本的には DRM フリーとなります。1
  • PDF こちらのフォーマットは、一般的には固定型のフォーマットです。
    基本的には DRM フリーとなります。2
  • 電子書籍ストア専用フォーマット Amazon Kindle などの総合電子書籍ストアで販売されている電子書籍専用のフォーマットです。リフロー型と固定型の両方があります。
    電子書籍ストア専用フォーマットは、原則 DRM がかかっています。

電子書籍を購入する場合、基本的には私は EPUB, Kindle (リフロー型), 紙書籍 の優先順位で購入するようにしています。
PDFKindle の固定レイアウトは、PC やスマホなど電子機器で読むことに特化されていることが少なく、読みにくいことが多いためほぼ購入しません。これらを購入するのは、主に 2 つあり、外で読みたい書籍または、絶版の書籍など他のフォーマットで購入できない場合のみとなります。

固定型とリフロー型について

日本電子出版協会のサイトからそれぞれの説明を引用させていただきます。

リフロー型電子書籍とは、表示するデバイスの画面サイズや文字サイズの変更などに合わせて、テキストやレイアウトが流動的に表示される方法で制作された電子書籍である。フォントを拡大したり縮小すると、1行の文字数が自動的に変更されて再表示されるため、紙の書籍のようなページの概念を持たない(ただしページ機能を持たせることは仕組みとして可能)。

https://www.jepa.or.jp/ebookpedia/201508_2551/

フィックス型電子書籍とは、表示するデバイスの画面サイズに関わらず、印刷された本と同じように文字や図表などのレイアウトが固定される方式で制作された電子書籍をいう。非リフロー型、固定レイアウト型などとも呼ばれる。

https://www.jepa.or.jp/ebookpedia/201508_2553/

EPUB が購入できる電子書籍ストア

EPUB は Amazon などの総合的な電子書籍ストアでは購入できないため、一般的には各出版社の電子書籍ストアで購入することになります。

私が良く購入する出版社ごとの電子書籍ストアは次のような傾向があります。

  • 技術評論社 (Gihyo Digital Publishing) 最近の書籍はほぼ EPUB が購入できます。
  • O'Reilly Japan (O'Reilly Japan Ebook Store) 最近の書籍はほぼ EPUB が購入できます。
  • インプレス (インプレスブックス) ほぼ PDF のみですが、まれに EPUB もあります。
  • 翔泳社 私の知る限り、EPUB は存在しません。Kindle ではリフロー型のレイアウトの事が多いので、そちらを購入します。
  • その他 その他の出版社の電子書籍ストアは、基本的には PDF または、電子書籍ストア専用フォーマットのみのことが多いです。リフロー型レイアウトはほぼ存在しないため、紙書籍を購入することが多いです。

  1. 技術的に EPUB にも DRM をかけることは可能です。
  2. 技術的に PDF にも DRM をかけることは可能です。

sudo -i と sudo su -の違い

どちらもrootユーザーに昇格することができるがこれらの違いが気になったので調査結果をメモ。

まず、これらのコマンドがどういう意味であるかを調べた。

  • sudo: Super User DO
  • su: Substitute User

sudo -iオプションの意味は simulate initial loginであるようだ。

違い1: 実行されるプロセス数が違う

当然だが、sudo su -sudosuコマンドを実行する。rootに昇格している間はこれらのプロセスが立ち上がったままとなる。 対してsudo -iコマンドはsudoコマンドのみを実行する。rootに昇格している間はsudoプロセスのみとなる。

どちらも利用したことがあればわかるが、体感的な速度差はない。

リソースは以下のような結果となった。

sudo su -昇格時

# pidstat -r -C su
Linux 5.4.0-58-generic (ubuntu2004)     2020年12月21日  _x86_64_        (1 CPU)

15時26分13秒   UID       PID  minflt/s  majflt/s     VSZ     RSS   %MEM  Command
15時26分13秒     0      5064      0.00      0.00   10280    4572   0.49  sudo
15時26分13秒     0      5065      0.00      0.00    9428    4292   0.46  su
$ time sudo su - -c :

real    0m0.013s
user    0m0.008s
sys     0m0.003s

sudo -i昇格時

~# pidstat -r -C su
Linux 5.4.0-58-generic (ubuntu2004)     2020年12月21日  _x86_64_        (1 CPU)

15時31分08秒   UID       PID  minflt/s  majflt/s     VSZ     RSS   %MEM  Command
15時31分08秒     0      6061      0.00      0.00   10364    4572   0.49  sudo
$ time sudo -i :

real    0m0.009s
user    0m0.006s
sys     0m0.003s

リソース面だけでみれば、sudoコマンドの結果はほぼ変わらず、suコマンドが加わった分、sudo -iほうが有利なようだ。

違い2: 環境変数

sudo -iの場合以下の環境変数がセットされている。

  • SUDO_COMMAND: 実行コマンド
  • SUDO_UID: 昇格前のUID
  • SUDO_GID: 昇格前のGID
  • SUDO_USER: 昇格前のUSER

CentOSの sudo -iだと/usr/local/binがPATH環境変数がセットされていない。

CentOS7, CentOS8で動作を確認

$ sudo -i echo '$PATH'
/usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin:/root/.dotnet/tools:/root/bin

$ sudo su - -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.dotnet/tools:/root/bin

Ubuntu20.04ではPATH環境変数に /usr/local/binがセットされていることを確認。

これは/etc/sudoersのデフォルト設定による違いとなる。

CentOS8

$ sudo grep secure_path /etc/sudoers
Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin

Ubuntu20.04

$ sudo grep secure_path /etc/sudoers
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

suコマンドでPATH環境変数は suコマンドがデフォルトでセットしているようだ。

       ENV_SUPATH (string)
           Defines the PATH environment variable for root.  The default value is /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin.

環境変数の引継ぎ

sudo -iでは環境変数が引き継がれる

$ sudo -i date
2020年 12月 21日 月曜日 19:37:30 JST

$ LANG=C sudo -i date
Mon Dec 21 19:37:36 JST 2020

sudo su -では環境変数が引き継がれない

$ sudo su - -c date
2020年 12月 21日 月曜日 19:38:54 JST

$ LANG=C sudo su - -c date
2020年 12月 21日 月曜日 19:39:44 JST

昇格後に環境変数をセットすれば対応可能

$ sudo su - -c 'LANG=C date'
Mon Dec 21 19:40:06 JST 2020

これは一長一短だと思う。個人的には引き継ないsudo su -のほうが自然な動作に感じる。

まとめ

違い sudo -i sudo su -
プロセス sudo のみ実行 sudo, suを実行
デフォルト環境変数 /etc/sudoersのsecure_path
(ディストリビューションによってデフォルト値が異なる)
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
環境変数の引継ぎ 引き継ぐ 引き継がない

各種リソース面では sudo -iが有利、環境変数関連は sudo su -のほうが好み(ディストリビューションの違いを意識しなくてよい)

用途によって使い分けるとよさそう。

参考情報

The Differences between Su, Sudo Su, Sudo -s and Sudo -i

linux - What is the difference between sudo -i and sudo su - - Server Fault

command line - 'sudo su -' vs 'sudo -i' vs 'sudo /bin/bash' - when does it matter which is used, or does it matter at all? - Ask Ubuntu

bash 管理者実行「su」「su -」「sudo -s」を比べてみる(スド、スドゥ) - min117の日記

suとsudoの違い - Qiita

Rustのmockallクレートを利用してみた。

Rustでモッククレートはいくつかあるが、一番良さそうであったmockallクレートを利用してみた。

https://crates.io/crates/mockall

今回確認した各種バージョン情報

名称 バージョン
Windows10 Pro 1909
Rust 1.47.0
mockall 0.8.3

automockアトリビュートが何をしているのかわからないので、Usageにあるトレイトをcargo expandしてみる

#[cfg(test)]
use mockall::{automock, mock, predicate::*};
#[cfg_attr(test, automock)]
trait MyTrait {
    fn foo(&self, x: u32) -> u32;
}
cargo expand --lib --tests

結果

#[cfg(test)]
use mockall::{automock, mock, predicate::*};
trait MyTrait {
    fn foo(&self, x: u32) -> u32;
}
#[allow(non_snake_case)]
#[allow(missing_docs)]
pub mod __mock_MockMyTrait {
    use super::*;
}
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(missing_docs)]
struct MockMyTrait {
    MyTrait_expectations: MockMyTrait_MyTrait,
}
impl ::std::default::Default for MockMyTrait {
    #[allow(clippy::default_trait_access)]
    fn default() -> Self {
        Self {
            MyTrait_expectations: Default::default(),
        }
    }
}

#[allow(non_snake_case)]
#[allow(missing_docs)]
pub mod __mock_MockMyTrait_MyTrait {
    // 長いので省略
}

#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(missing_docs)]
struct MockMyTrait_MyTrait {
    foo: __mock_MockMyTrait_MyTrait::__foo::Expectations,
}
impl ::std::default::Default for MockMyTrait_MyTrait {
    fn default() -> Self {
        Self {
            foo: Default::default(),
        }
    }
}
impl MockMyTrait_MyTrait {
    /// Validate that all current expectations for all methods have
    /// been satisfied, and discard them.
    pub fn checkpoint(&mut self) {
        {
            self.foo.checkpoint();
        }
    }
}
impl MockMyTrait {
    /// Validate that all current expectations for all methods have
    /// been satisfied, and discard them.
    pub fn checkpoint(&mut self) {
        self.MyTrait_expectations.checkpoint();
    }
    /// Create a new mock object with no expectations.
    ///
    /// This method will not be generated if the real struct
    /// already has a `new` method.  However, it *will* be
    /// generated if the struct implements a trait with a `new`
    /// method.  The trait's `new` method can still be called
    /// like `<MockX as TraitY>::new`
    pub fn new() -> Self {
        Self::default()
    }
}
impl MyTrait for MockMyTrait {
    fn foo(&self, x: u32) -> u32 {
        self.MyTrait_expectations
            .foo
            .call(x)
            .expect("MockMyTrait::foo: No matching expectation found")
    }
}
impl MockMyTrait {
    #[must_use = "Must set return value when not using the \"nightly\" feature"]
    ///Create an [`Expectation`](__mock_MockMyTrait_MyTrait/__foo/struct.Expectation.html) for mocking the `foo` method
    fn expect_foo(&mut self) -> &mut __mock_MockMyTrait_MyTrait::__foo::Expectation {
        self.MyTrait_expectations.foo.expect()
    }
}

トレイト名に接頭辞Mockを付けた構造体とそれに加えて接尾辞__トレイト名の構造体を実装するようだ。 トレイトメソッドはexpect_メソッド名のメソッドが実装されこれがモックメソッドになるようだ。

基本的には、複数の実装(impl)をする場合は、mockマクロを使い、一つだけの実装であれば、automock属性を使うのが良さそう。

reqwest利用箇所をモック化してみた。

Comparing cec9d1802ecd70deabe52eec958f898867f3d6c3..081591db09244044b2bd8278579edba24bd4cb37 · masinc/checkip-rust · GitHub

基本的にはautomockアトリビュートかmockマクロを使うだけで非常に簡単に実装できる。

AWS ソリューションアーキテクト アソシエイト合格した。

AWS ソリューションアーキテクトアソシエイト(SAA-C02)合格した。

7月くらいから勉強を始めて、10月に取得。

スコアは 822

事前知識

AWSの業務経験は主業務でない時期も含めて2年程度。インフラ・アプリケーションどちらもそこそこやる。

主に利用したことのあるサービスとしては VPC, EC2, S3, CloudWatch, Lambda, IAM, EFS, RDSなど。

学習

学習教材としては、以下を利用

www.amazon.co.jp

SAA-C02には対応していないが、主要なサービスは掲載されていたように思う。 本書に載っていない問題で出題されたサービスもいくつか存在した。

問題集としてUdemyの以下を利用

www.udemy.com

1週目は50~70点ほどであったが、間違えた問題やよくわからない問題の解説を熟読して、 2週目は90点程度になった。

Udemyの問題集にはあり、AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイトには掲載されていないサービス例として以下のものが存在した。*1

  • Amazon FSx
  • Active Directory Connector
  • Simple Active Directory
  • AWS Organizations
  • AWS Transit Gateway
  • AWS Snowball
  • Amazon Athena

本番より難しいと感じる問題がいくつもあったが回答の解説が丁寧に記載してあるものが多いため、勉強になった。

*1:Athenaと Snowballは名前だけは存在する

Node.jsのN-APIをRustから使ってみた。

Node.jsにてRustのプログラムをffiしたいと思い、node-ffiを調べてみたが、しばらく更新されておらず、Node.js 12以降だと利用できない模様。

GitHub - node-ffi/node-ffi: Node.js Foreign Function Interface

RPCではない方法で他に連携する方法はないかと調べてみた結果Node.jsにはネイティブアドオンを作成するためのAPIが用意されているらしい。

nodejs.org

今回はこれをRustから利用できる形で提供してくれているnapi-rsを使用してみる。

github.com

今回検証する環境の各バージョン

  • Windows 10 1909
  • Node.js v14.15.0
    • napi-rs 0.3.9
  • Rust 1.47.0
    • napi 0.5.1
    • napi-derive 0.5.1
    • napi-build 0.2.1

napi-rsのドキュメントに従いcargo buildしてみたところ以下のエラーが発生

thread 'main' panicked at 'Unable to find libclang: "couldn\'t find any valid shared libraries matching: [\'clang.dll\', \'libclang.dll\'], set the LIBCLANG_PATH environment variable to a path where one of these files can be found (invalid: [])"'

clangが必要なようのでLLVMをインストール

今回インストールしたバージョンは11.0.0

The LLVM Compiler Infrastructure Project

他は特に問題なくcargo buildすることができた。

Node.jsからRustのfibonacci関数を呼び出すサンプル

github.com

Node.jsとRustのfibonacci関数を比較

 PASS  ./fib.test.js (14.479 s)
  √ fibonacci(30) for rust (3 ms)
  √ fibonacci(30) for js (16 ms)
  √ fibonacci(31) for rust (2 ms)
  √ fibonacci(31) for js (24 ms)
  √ fibonacci(32) for rust (3 ms)
  √ fibonacci(32) for js (39 ms)
  √ fibonacci(33) for rust (5 ms)
  √ fibonacci(33) for js (64 ms)
  √ fibonacci(34) for rust (13 ms)
  √ fibonacci(34) for js (102 ms)
  √ fibonacci(35) for rust (15 ms)
  √ fibonacci(35) for js (168 ms)
  √ fibonacci(36) for rust (26 ms)
  √ fibonacci(36) for js (263 ms)
  √ fibonacci(37) for rust (47 ms)
  √ fibonacci(37) for js (432 ms)
  √ fibonacci(38) for rust (68 ms)
  √ fibonacci(38) for js (701 ms)
  √ fibonacci(39) for rust (108 ms)
  √ fibonacci(39) for js (1119 ms)
  √ fibonacci(40) for rust (168 ms)
  √ fibonacci(40) for js (1828 ms)
  √ fibonacci(41) for rust (294 ms)
  √ fibonacci(41) for js (3061 ms)
  √ fibonacci(42) for rust (474 ms)
  √ fibonacci(42) for js (4855 ms)

Rust版のほうが概ね10倍程度は高速なようだ。 fibonacci関数は本来キャッシュすべきとか、Rust版は末尾再帰最適化がかかっているとかはあるがnapi-rsの検証が目的なのでパフォーマンスは次回以降にちゃんと検証したい。

WindowsでRustのDieselライブラリを利用

TLDR

開発用途であればWSLを使うほうが楽。
本番用途でも静的リンクは大変。

Dieselとは

RustのORM/クエリビルダライブラリ

diesel.rs

PostgreSQL, MySQL, SQLite3に対応しているが、それぞれのSQLクライアントライブラリにリンクする必要がある。

後述するが、それぞれのクライアントに限定してインストールすることもできる。

Vcpkg

VpkgはC言語とC++のライブラリ管理ツール
今回はVcpkgを利用して各種SQLクライアントのライブラリインストールしてみる。Vcpkgのインストール方法については下記ページを参照。

github.com

特筆すべき事項としては、Visual Studioの英語の言語パックのインストールが必要。

静的リンク

以下で全てのインストールはできそうだが7/26現在MySQL, PostgreSQLの静的リンクはできなかった。

#!pwsh
cd $env:VCPKG_ROOT
.\vcpkg.exe --triplet x64-windows-static install libpq
.\vcpkg.exe --triplet x64-windows-static install libmysql
.\vcpkg.exe --triplet x64-windows-static install sqlite3

$env:RUSTFLAGS= "-Ctarget-feature=+crt-static"
cargo install diesel_cli

PostgreSQL(静的リンク)

2020/07/26 インストール失敗

#!pwsh
cd $env:VCPKG_ROOT
.\vcpkg.exe --triplet x64-windows-static install libpq

$env:RUSTFLAGS= "-Ctarget-feature=+crt-static"
cargo install diesel_cli  --no-default_features --features postgres

MySQL(静的リンク)

2020/07/26 インストール失敗

#!pwsh
cd $env:VCPKG_ROOT
.\vcpkg.exe --triplet x64-windows-static install libmysql

$env:RUSTFLAGS= "-Ctarget-feature=+crt-static"
cargo install diesel_cli  --no-default_features --features mysql

SQLite(静的リンク)

#!pwsh
cd $env:VCPKG_ROOT
.\vcpkg.exe --triplet x64-windows-static install sqlite3

$env:RUSTFLAGS= "-Ctarget-feature=+crt-static"
cargo install diesel_cli  --no-default_features --features sqlite

動的リンク

#!pwsh
cd $env:VCPKG_ROOT
.\vcpkg.exe --triplet x64-windows install libpq
.\vcpkg.exe --triplet x64-windows install libmysql
.\vcpkg.exe --triplet x64-windows install sqlite3
# 動的リンクする場合は VCPKGRS_DYNAMICに値を設定する。 (参考: https://docs.rs/vcpkg/)
$env:VCPKGRS_DYNAMIC = 1
cargo install diesel_cli

動的リンクは可能だが、当然DLLのパスを通す必要がある。通常は %VCPKG_ROOT%\installed\x64-windows\bin あたり。汎用DLLも存在するためDLL Hellが起きないか不安だ。

WSL1 (Ubuntu 2004)

開発環境ならこれがもっとも簡単

ただし 2020/07/26現在WSL1のUbuntu2004ではrustupのインストールがうまくいかない

qiita.com

環境変数に RUSTUP_IO_THREADS=1 に付与すればインストールできた。

github.com

#!bash
export RUSTUP_IO_THREADS=1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

sudo apt install libpq-dev libmysqlclient-dev libsqlite3-dev
cargo install diesel

Windowsからdieselを使うときは以下のように実行

#!pwsh
wsl bash -lc 'diesel ...'