感染症数理モデルについて触りの部分だけ学ぶ

目的 特にしっかりした目的はない。 なんとなく数値シミュレーションについて学び直したくなったため、現在身近にある現象を題材にして学ぶ。 ネットの情報を参考に、適当にシミュレーションを走らせてみる。 ※本シミュレーションは、実測値等には全く基づいていないため、完全に空想上のシミュレーションになります。 本シミュレーションの結果が実情を反映していたり、今後の予測を示していたりはしません。 今回扱うシミュレーションモデル SEIRモデルを扱う。 SEIRモデルとは SEIRモデル(エスイーアイアールモデル)とは感染症流行の数理モデルである。 モデルは 感染症に対して免疫を持たない者(Susceptible) 感染症が潜伏期間中の者(Exposed) 発症者(Infectious) 感染症から回復し免疫を獲得した者(Recovered) から構成され、その頭文字をとってSEIRモデルと呼ばれる。 (Wikipediaより) モデル式は以下のような式で表される。 $$ \begin{aligned} \frac{dS}{dt} &= m(N - S) - bSI &(1) \cr \frac{dE}{dt} &= bSI - (m + a)E &(2) \cr \frac{dI}{dt} &= aE - (m + g)I &(3) \cr \frac{dR}{dt} &= gI - mR &(4) \end{aligned} $$ ここで\(t\)は時間、\(m\)は出生率及び死亡率、\(a\)は感染症の発生率、\(b\)は感染症への感染率、\(g\)は感染症からの回復率を表す。 また\(N\)は全人口を示し、 $$N \equiv S + E + I + R (5)$$...

May 2, 2020 · 2 min

Chart.jsで時刻データを扱う

Chart.js公式のドキュメントを参考にして、Chart.jsで時刻データを扱う場合の描画オプションについて確認する。 入力データ 入力データはx軸データをy軸データを各点それぞれ指定する。 今回はx軸データに時刻データを使う。 例としては、以下のように指定すればOK。 data: [{ x: '1995-12-17T00:00:00', y: 1 }, { x: '1995-12-18T00:00:00', y: 10 }, { x: '1995-12-21T00:00:00', y: 20 }, { x: '1995-12-25T12:00:00', y: 30 }, { x: '1996-01-01T00:00:00', y: 40 }] データフォーマット 時刻スケールのデータを使う場合、フォーマットはMoment.jsが扱えるフォーマットであればどういった形式でも良い。詳細はMoment.jsのドキュメント参照。 描画オプション 時刻目盛りを扱う場合、以下のオプションを設定できる。 adapters.date 外部の時刻ライブラリ(つまりMoment.js以外)を使うためのオプション。 distribution データのプロット方法。 指定できる値はlinearまたはseriesのいずれか。 初期値はlinear。 linearはデータ描画間隔が時間間隔に応じて変化する。 seriesはデータ描画間隔がすべて同じになる。 以下に同一データを用いてdistribution設定のみ変えた場合の描画例を示す。 linearを指定した場合 var ctx = document.getElementById('distribution_linear').getContext('2d'); var chart = new Chart(ctx, { // The type of chart we want to create type: 'line', // The data for our dataset data: { datasets: [{ label: 'linear', backgroundColor: 'rgb(255, 99, 132)', borderColor: 'rgb(255, 99, 132)', fill: false, data: [{ x: '1995-12-17T00:00:00', y: 1 }, { x: '1995-12-18T00:00:00', y: 10 }, { x: '1995-12-21T00:00:00', y: 20 }, { x: '1995-12-25T12:00:00', y: 30 }, { x: '1996-01-01T00:00:00', y: 40 }] }] }, // Configuration options go here options: { scales: { xAxes: [{ type: 'time', //!...

April 26, 2020 · 9 min

Vue.jsを使ったSPAにおいてTwitter等でのリンク表示がいい感じになるようにする

Vue.jsでSPAを構成した際、TwitterなどのOGPが上手く表示されなかったので、対処した。 SPAとは?→シングルページアプリケーション この記事で扱っているSPAとは、シングルページアプリケーションを指す。 SPAについては少し以下の記事で触れたが、詳細は他のサイトの方が詳しいと思う。 OGPとは?→Webページのリンクを表示する仕組み OGPとはOpen Graph Protocolの略で、TwitterとかFacebookとかでリンクがいい感じに表示されるアレに使われているプロトコルのこと。 ↓これ。 Chart.jsで横軸が日付のグラフを作成する https://t.co/evu4HqqQ4f @aoki_kouyaさんから — 青木晃也 (@aoki_kouya) April 4, 2020 webサイトをいちから作る際、OGP対応していないと、Twitterとかでリンクを貼り付けても画像や説明文は表示されない。 そこらへんはTwitter側でなんとかしてくれるわけではなく、サイト作成者側が適切にOGP設定を行う必要がある。 SPAの場合はOGP設定にひと工夫必要 OGPは、具体的にはHTMLにmetaタグを設定することで対応できる。 例えば、以下のようなmetaタグを<head>要素内に設定する。 上記は私が作成したサイトの実装例になるが、他のサイトを調べると、head要素にprefix属性を適切に設定する必要があるようだ。 私は設定していなかったが、とりあえずTwitterあたりでは問題なく動いているように見える。 まあ、正しい対応ではないと思う。 このOGP設定だが、SPAの場合はひと工夫必要になる。 理由は、OGPによってリンクを作成する際、JavaScriptが動かないケースがあるため。 OGPによってリンクを表示する際、クローラーと呼ばれるプログラムによって、リンク先のページをスキャンする。 スキャン結果に従ってリンクを表示するのだが、TwitterやFacebookのクローラーはJavaScriptを実行してくれないらしい。 よって、JavaScriptによってmetaタグを生成しても、リンクには反映されない。 SPAでOGP設定を適切に行う場合はここら辺の対処が必要。 今回は特定条件時のみ静的ページを返すように実装 今回の結論、解決策になる。 調べてみると、(Vue.jsを用いた)SPAでのOGP設定については色々対応策があった。 いくつか参考にさせていただいたページを挙げておく。 上記のページの方法はページ内にも書かれている通り、全てのページで同じ内容のOGPになってしまう。 今回はそれぞれのページで異なるOGPを設定したいため、同じ方法はとらなかった。 上記のページは詳しく書いてあり、参考になりそうだったが、Firebaseを使ってない、使ったことがないため今回は同じ方法をとれなかった。 最終的には以下のページの方法を真似させていただいた。 上のページの方法は、TwitterやFacebookなど特定のクローラーに対してのみOGP対応用のテンプレートを返すというものになっている。 アプローチとしては一番最初に挙げたページと同じだが、こちらはクローラー検出用にControllerを作成して、テンプレートの出し分けをしている。 比較的容易に実装でき、ページごとに異なるOGP設定ができそうだったため、こちらの方法を採用した。 この方法の課題としては、OGP対応用のテンプレートを返す相手をピンポイントで指定する必要があるため、明示的に指定したクローラー以外に対しては対応できない点がある。 また、OGP対応用のControllerを新規に作成する必要があり、Controllerが単純に1個増える。 なお、各サービスのクローラーの情報は以下のサイトを参考にさせていただいた。 雑記 Twitterでのリンク表示内容確認には以下の公式のサイトが便利。 これからはじめるVue.js実践入門 山田 祥寛 Amazon Kindle 楽天 楽天Kobo

April 25, 2020 · 1 min

Chart.jsで横軸が日付のグラフを作成する

webサイト上で横軸が日付情報のグラフを作りたかったのでChart.js周りで色々調べた。 横軸が単純な数値じゃない場合は面倒くさくなるかなと思っていたが、Chart.jsが非常に使いやすく、すんなりできた。 最終的に作ったもの 画像で貼ろうと思ったが、結構サイズが大きいのでリンクで貼り付けておく。 Chart.jsとは グラフ類を描画するためのJavaScriptライブラリ。 HTMLの<canvas>要素に2Dグラフィックを描画できる。 ライセンスはMIT。 Chat.jsのインストールと使い方 基本的な使い方を公式に従って確認してみる。 インストール 今回はとりあえず手軽そうなCDNを使う。 よってHTMLに以下のタグを追加する。 <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script> なお、ここで Chart.bundle.min.js を選択したのは、今回日付データを扱うため。 Chart.min.js の方は日付データを扱うためのライブラリMoment.jsが含まれていない。 使い方 HTML側はグラフ描画用の<canvas>タグを作成する。 先ほどのCDNの参照及び今回作成するJavaScriptの読み込みを合わせて、HTML側のソースは以下のようになる。 index.html JavaScript側は公式のサンプルを参考にして以下のようにする。 main.js これら2つのファイルを適当なところに保存して、index.htmlをブラウザで開く。 以下のようなグラフがブラウザ上に表示される。 横軸が日付情報のデータをプロットする サンプルが動いたので、今回扱いたい、横軸が日付情報のデータをプロットする。 HTML側は特に変更せず、JavaScript側を以下のように変更する。 main.js 参考ページ main.jsを上記のように変更し、index.htmlをブラウザで開くと以下のようなグラフが描画される。 横軸が日付になっており、横軸の間隔もデータに合わせていい感じになっている。 まとめ Chart.jsを使って横軸が日付情報のデータをプロットできた。 色々と描画オプションがあるようなので、それぞれ変更させるとどのようにグラフが変化するか、また今度まとめたい。 確かな力が身につくJavaScript「超」入門 第2版 狩野 祐東 Amazon Kindle 楽天 楽天Kobo

April 5, 2020 · 1 min

Laravel+Vue.jsでSPA(シングルページアプリケーション)を作成した

今回作成したサイト 今回作成したサイトは以下のサイト。 ClubPage 私が所属している電子工作サークルのホームページを作った。 このブログからcssを流用しているので、見た目がだいぶ似ている。 構成 Laravel Vue.js バックエンドはLaravel、フロントエンドはVue.jsを使っている。 シングルページアプリケーションとは 今回はシングルページアプリケーション(SPA)という構成を採用した。 シングルページアプリケーションとは シングルページアプリケーション(英: single-page application、SPA)とは、単一のWebページのみから構成することで、デスクトップアプリケーションのようなユーザ体験を提供するWebアプリケーションまたはWebサイトである。必要なコード(HTML、JavaScript、CSS)は最初にまとめて読み込むか[1]、ユーザの操作などに応じて動的にサーバと通信し、必要なものだけ読み込みを行う。 Wikipediaより というものらしい。 これまでRuby on RailsやDjangoとかを使ってwebサイトを作ってみてきたが、どれも各ページ毎に、サーバ側でHTMLの生成を行うマルチページアプリケーションだった。 今回はLaravelでwebAPIを作成し、そのAPIから取得した情報を、Vue.jsを使ってブラウザ上に表示するような構成にした。 なぜSPAにしたのか 理由は1つで、今回参考にしたサイトがSPAを採用していたから。 今回参考にしたサイトは以下のサイト。 このサイトにあるチュートリアル、書かれている情報量がかなり多くて、これだけの情報をタダで得られるのが信じられない。 今回初めてLaravelとVue.jsを触ったが、このサイトのおかげで色々と基礎を学ぶことができた。 今回学んだこと、感じたこと インタフェース部とエンジン部の分離はやはり重要 今回の構成はAPI(Laravel)と表示部(Vue.js)を分離している。 たとえばhttps://home.lchika.club/api/tagsにアクセスすれば、Laravelの機能によって、タグの一覧をJSON形式で取得できる。 こういったAPIから取得した情報をVue.jsで処理して、ブラウザにレンダリングする。 このように分離することで、UIを変えたいときは、基本的にVue.jsの部分のみを修正するだけですむ。 Laravelの処理部は一切手を加える必要がない。 まあ、一般的なwebフレームワークを使っていれば、実装の分離は適切に行われているが、ある一部分のフレームワークをごっそり切り替えることはできない。 今回の構成では、例えばフロントエンドにReactを使いたければ、Laravel部分はそのままで、フロントエンド部分をごっそり切り替えられる(と思うけど、Laravel-mixとかの関係で難しいのかもしれない…)。 このように、インタフェースとエンジン部の分離で得られる効果はやはりでかいなと思った。 ローディング表示がないとwebサイトの質が落ちる これは個人的な印象かもしれないが、ローディング画面の表示はユーザにとって(ある程度)重要だなと思った。 現状ではローディング表示は実装していないため、読み込み直後は一部のコンテンツが表示されていないし、一部のコンテンツについては結構な時間表示されないことがある。 これはサイト利用者側からすると、違和感を覚える要因になり、満足度の低下につながると思った。 YouTubeとかもローディング中はコンテンツ表示部をグレーで表示したりしている。 最初はこれ意味あるのか?と思っていたが、今回自分でJavaScriptを多用したサイトを構築してみて、こういった対応も重要だなと思った。 WYSIWYGエディタの選定は毎回の課題 今回はブログのようなサイトを構築したので、フォームから記事を投稿できる必要があった。 さすがにHTML直打ちで入力はできないし、リッチテキストエディタを採用する必要があった。 毎回どのリッチテキストエディタを使うか苦労するが、今回も例に漏れず苦労した。 とりあえず今のところはCKEditorを使っている。 ただ、まだ課題があって、iframeの挿入が上手くいっていない。 いつも大体、リッチテキストエディタまわりは 画像の挿入 画像の整形 外部コンテンツの挿入 目次の作成 あたりで詰まっている。 今回はまだ目次の作成について考えていないので、目次が必要になった時に多分また詰まる。 SPAのパフォーマンス向上はバンドルサイズの削減こそ正義 今回作成したサイトのパフォーマンス向上については以下の記事に書いた。 最初特に何も考えずにサイトを作っていたら、パフォーマンスが崩壊した。 今もパフォーマンスが良いとは言えないが、バンドルサイズを削減することで、パフォーマンスが向上した。 こういったパフォーマンス向上のための施策は必要不可欠だなと感じた。 まとめ 今回はLaravelとVue.jsを使ってサイトを作った。...

March 15, 2020 · 1 min

Laravel+Vue.jsでLighthouseのスコアを0点から97点にした(バンドルサイズ削減)

Laravel+Vue.jsで作成していたwebサイトの応答速度が激遅だったので、対策を実施した。 環境 Laravel 6.14.0 Vue.js 2.6.11 対策前はページロードに20秒かかっていた 特に何も考えずにwebサイトを作っていたら、トップページのロードに20秒ほどかかっていた。 これではさすがにwebサイトとして成立しない。 Googleが提供しているwebページ分析ツールLighthouseを使ってパフォーマンスの測定を行ったところ、以下のような結果になった。 堂々の0点である。提示されている対応策の詳細を見ると、以下のように書かれていた。 どうやらバンドル後のapp.jsのサイズが約4MBと、超巨大になっているらしい。対応策としてapp.jsのサイズ削減を行った。 対策1:本番用ビルド設定を適用する バンドルサイズ 3.86MB(app.js) → 1.59MB(app.js) 解説 そもそもビルド設定が間違っていた…。ビルドコマンドとして npm run dev を実行していたが、これは開発用のビルドコマンドらしい。 本番用のビルドコマンド npm run prod を実行したところ、バンドルサイズは3.86MB→1.59MBと、約40%になった。 Lighthouseの結果 0点→10点に上昇した。 対策2:gzipで圧縮する バンドルサイズ 1.59MB(app.js) → 395KB(app.js.gz) 解説 以下のページを参考に、gzipでapp.jsを圧縮した。 そのままコピペで適用できた。 Lighthouseの結果 10点→63点に上昇した。 対策3:ページごとにJSファイルを分割する バンドルサイズ 395KB(app.js.gz) → 243KB(app.js.gz) 解説 以下のページを参考に、ページごとにJSファイルを分割した。 こちらも特に詰まることはなく、ほぼコピペで実装できた。 この対策を実装したことで、ビルド後のJSファイルが以下のように、分割されて生成されるようになった。 Lighthouseの結果 63点→87点に上昇した。 対策4:bootstrap-vueの選択的インポート バンドルサイズ 243KB(app.js.gz) → 129KB(app.js.gz) 解説 対策1~3で、あらかた大きなところは対策できたと思ったので、より細かいところを対応するため、webpack-bundle-analyzerを使ってバンドル結果の分析をした。 webpack-bundle-analyzerの出力結果は以下のようになった。 この結果から bootstrap-vue ckeditor lodash あたりのサイズが大きいらしいことが分かった。...

March 8, 2020 · 1 min

カメラ画像から対象物の向きを検出する(OpenCV)

やりたいこと 俯瞰で見ているUSBカメラの画像を使って、自律的に動いているロボットの向きを検出する。 また、カメラ画像における指定の座標と、ロボットがなす角を算出する。 動作環境 ターゲットボード JetsonNano OS Ubuntu 18.04.4 LTS 使用ライブラリ Python版 OpenCV 4.1.1 処理結果 今回実装した処理の結果は、画像で示すと以下のような感じになる。 方法 今回実装した方法は以下の通り。 カメラ画像をHSV形式に変換 カメラ画像のうち指定のHSV範囲に従ってマスク画像を作成 マスク画像から輪郭を抽出し、1番面積の大きい領域のみ残したマスク画像を作成 カメラ画像とマスク画像の共通領域を抽出 4.で作成した画像から黒色領域を抽出 5.で抽出した黒色領域のうち、1番面積の大きい領域の重心p1、2番目に面積の大きい領域の重心p2を計算 p2からp1へのベクトルと、p1とp2の中点から指定の座標へのベクトルのなす角を計算 処理順に従って中間生成画像を並べると以下のような感じになる。 元画像 手順3.で作成したマスク画像 手順5.で抽出した黒色領域 手順6.で算出した各黒色領域の重心 処理結果 ソースコード 一部自作モジュールもimportしているのでコピペでは動きません。 呼び出し方は例えば以下のように。 処理時間や実行時のリソース使用量など 処理時間 今回の一連の処理呼び出しにどれだけ時間がかかっているか計測したところ、以下の通りだった。 elapsed_time:0.49050045013427734[sec] elapsed_time:0.500530481338501[sec] elapsed_time:0.49204468727111816[sec] だいたい0.5秒ほどかかっている。このままだとリアルタイム性が求められる場合は使えない。 リソース使用量 Jetsonのモニタツールjtopの出力は以下のような感じ。 プログラム稼働中 GPUが稼働していない。GPUを使うようにすれば高速化できるのだろうか(全然そこらへんは調べていない)。 なぜこの処理を実装したか 全体を俯瞰できるカメラの情報を使って、ロボットを指定位置に誘導したかった。 カメラ側がロボットに指定の位置に対する角度・距離情報を伝え、ロボット側でその情報を使って、モータ値を計算する。 設計の経緯や苦労したところなど 目印をどう設計するか 向き検出のための目印をどう設計するかが、検出精度や処理速度に最も影響を与える部分だと思う。 今回は黄色の画用紙の上に、面積の異なる黒色の画用紙を2つ(前方に面積が大きいもの、後方に面積の小さいもの)つけて目印にした。 単純だが、思っていたより認識出来ていたと思う。しっかりしたベンチマークはとっていないが。 最初はQRコードの活用を考えていた。OpenCVにはQRコード認識処理が実装されており、向きも検出出来そうだったので。今後複数台ロボットを同時に動かすことを考えても、QRコードだったら文字列情報を付加できるので、各ロボットの識別に使えそうとも思っていた。 ただ、ある程度QRコードが大きく写っていないと認識できなかった。今回はカメラと認識対象ロボットの距離が遠い時でも認識できるようにしたかったので、QRコード案はやめた。...

February 24, 2020 · 1 min

VTuberの簡易ランキングサイトを作った

概要 適当に抽出したVTuberについて、チャンネル登録者数増加数のランキングサイトを作成した。 1日1回、午前5時30分ごろ更新。 構成 Golang + Gin + Bootstrap 雑記 Golangを使ったwebアプリを初めて作成した。Golangは未使用の変数、importがデフォルトでコンパイルエラーになるのが印象的だった。ルールが厳格な印象。 YouTubeの現在の仕様で、チャンネル登録者数が多いほど、刻み幅が大きくなる。その刻み幅分を超えないと、増加量が0になってしまうので、1日単位だと正確なランキングにならない。 今回のサイトを作るにあたって、既存サイトを調べてみた。色々凝っているサイトが多数あった。やはりここら辺(YouTube周り)は色んなビジネスが成り立っているんだろうなと思った。 改訂2版 みんなのGo言語 技術評論社 Amazon Kindle 楽天 楽天Kobo

January 17, 2020 · 1 min

今年(2019年)作ったものを振り返る

今年もあっという間だったがもう終わるらしい。 この1年で作った物の振り返りをしたいと思う。 今年作ったもの 1月~2月 ロボサッカー用ロボ作成 2月終わりごろにロボカップジュニア同等のルールのロボコンに出る機会があり、プログラムの一部作成を担当した。 ロボの構成は大体以下の通り。 機体はLEGOのマインドストーム 赤外線センサでボールの位置を検出 ラズパイを使って、カメラからの画像を解析しゴール位置を検出 3人でチームを組んでおり、進捗管理ツールとしてtrello、情報共有ツールとしてslack、ソースコード管理ツールとしてGitHubを使った。 trello、slackあたりはあまり活用できなかったが、GitHubはやはり便利だなと思った。 できたもの マインドストーム側プログラム(GitHub) ラズパイ側プログラム(GitHub) 3月~7月 イライラ棒作成 私が所属している電子工作サークル「メカトロ同行会エルチカ」の作成物として、イライラ棒ゲームを作成した。基本的にプログラム部分を担当した。上の写真はNT名古屋出展時のもの。 この作品では以下のように色んな機器の通信を試してみた。 ArduinoとPCの通信(USBシリアル通信) PCとラズパイの通信(HTTP) PCとESP32の通信(HTTP) ラズパイとwebアプリの通信(HTTP) 色んな機器を連携させる作品を初めて作ってみたが、どれか一つが動かないと全部ダメになる仕組みに一部なってしまった。 できたもの イライラ棒wikiページ スコア表示用ソフト(GitHub) 結果プリント用ラズパイプログラム(GitHub) スタートモジュール用プログラム(GitHub) ゴールモジュール用プログラム(GitHub) イライラ棒結果ランキングページ 4月 github.ioページ公開 github.ioを使ってwebページを公開した。なお、現在更新はしていない。 できたもの github.ioページ 8月 KiCad用ツール作成 KiCadを使う機会が多くなってきたので基板発注用の簡単なツール(Windowsアプリ)を作ってみた。 こちらの記事で少し内容について紹介している。 できたもの KiCadHelper(GitHub) 8月~ 射的ゲーム作成 赤外線を使った射的ゲームを現在も作成中。同じようなものを以前一度作成していて、今回は複数人プレイに対応させる予定。 できたもの 鋭意諸々作成中 今年を振り返ってみて 今年は電子工作に割ける時間が結構多かった。ただこうして振り返ってみると、かけた時間に比べ、出来上がった物の量がいまいち物足りないな…と思う。

December 28, 2019 · 1 min

マトリクスLEDドライバを使ってフルカラーLEDを制御してみる

今回の経緯 フルカラーLEDを最大5個制御したい! 最初NeoPixel(マイコン内蔵LED)を使う予定だったが、いろいろ試した結果、今回の条件では使えなさそうという結論になった。 マイコン内蔵ではない、通常のフルカラーLEDを使うことにする。 ただ、使用できるピン数は限られているため、マイコンボードからはI2CやSPI等で制御する形にしたい。 フルカラーLEDドライバを探す。 スイッチサイエンスで探したらよさそうなのがあったけど値が張る。 秋月でさがしたらこんなのがあった。 安い。もともとはドットマトリクス制御用らしいが、フルカラーLED制御にも転用できそう。 準備物 部品名 購入先 ESPr Developer 32 スイッチサイエンス 16×8LEDマトリクスドライバーモジュール(HT16K33) 秋月電子通商 RGBフルカラーLED 秋月電子通商 結果 とりあえず2個のフルカラーLEDを制御できた。 ただし、r, g, bはそれぞれ0(OFF)か1(ON)でしか調整することは出来ない。 プログラムとハマりポイント プログラム GitHub ハマりポイント I2Cアドレスでハマった。 秋月の解説ページでは初期状態なら0xE0(write)と書いてあったので、Arduinoのスケッチでアドレスを0xE0に指定したがなにも反応しなかった。 調べてみるとこの方法は誤りで、Arduinoの場合は最下位ビットを除いた7ビット分をアドレス値に設定する必要があるらしい。 スレーブアドレスを0x70と設定したらうまくいった。 参考:https://tool-lab.com/make/pic-practice-37/ 雑記 いま探したらaitendoでもっと安い、100円のフルカラーLEDドライバ(単体)があった。 ただこっちはチップ単体の値段だし、データシートが中文で読むのが大変そう…。 IoT開発スタートブック ── ESP32でクラウドにつなげる電子工作をはじめよう! 技術評論社 Amazon Kindle 楽天 楽天Kobo

December 8, 2019 · 1 min