OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonで複数画像を1つのPDFにさせてみた

どうも、学生エンジニアのirohasです。
本日は、複数の画像をPDFにして送りたいときに手動でやるのは手間だなぁと思ったので、Pythonを使って自動でPDFにしてくれるプログラムを作っってみました。

まずは、コードを走らせるにあたって必要なライブラリたちを紹介します。

img2pdf ・・・画像をPDfにするための外部ライブラリです。
glob ・・・ディレクトリから目的のものを取得する際に使う標準ライブラリです。
natsort・・・画像を自然順にソートするための外部ライブラリです。


上記の通り、img2pdfとnatsortは外部ライブラリですので、インストールしてない方はまずインストールしてください。

```
pip install img2pdf
pip install natsort
```

上記のライブラリをインストールしたら、いよいよコードを書いていきます。

まず先に今回使用したコードを紹介します。

```python:pdf.py
import img2pdf
import glob
from natsort import natsorted #PDF化する際に画像を自然順にするため

# PDf化させたい画像を一括で取得
lists = list(glob.glob("画像が格納されているパス/*.jpg"))

# PDFファイル出力
pdfpath = "適当な名前.pdf"
with open(pdfpath,"wb") as f:
    f.write(img2pdf.convert([str(i) for i in natsorted(lists) if ".jpg" in i]))
```


まず、globでワイルドカードを使用して画像が格納されているパス内の指定した拡張子の画像を一括で取得します。
その後、出力する際のPDF名を指定し、with open関数を用いてpdfファイルを作成するだけです。
なお、pdfのパスを指定したフォルダに保存したい場合は、パスを指定するのを忘れないでください。

個人的に作成してみた感想としてはたった数行でpdfにすることができるんだなと感心しました。
これ以降はこのコードを書き替えて走らせるだけでPDFが作成できるので、かなり便利だと感じています。


※注意点
.jpgの際は関係ないのですが、.pngの画像をpdf化させる際はpngファイルに透過チャンネルがある場合、 `img2pdf.AlphaChannelError: Refusing to work on images with alpha channel` というエラーが出るのでそこの対応が必要になります。
米Netflix決算発表。2019-2021年収益・会員純増ExcelデータをPower Query エディター活用しグラフ化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/2965b5a1-566b-5da5-9032-a0283ea7488f.png)

##Power BI Desktopにインポート

米Netflix（ネットフリックス）が1月20日に発表した2021年10〜12月期決算、会員の純増数が自社の予想に届かず、株価が下がったことがニュースに取り上げられていました。
10〜12月売上高はの77億932万ドル、四半期ベースで過去最高を更新したとのことです。
当期純利益は6億743万ドル。3カ月間の会員の純増数は828万人でした。

https://ir.netflix.net/ir-overview/profile/default.aspx

上記投資家向けサイトから決算データ（Excel）を取得、「Power BI Desktop」に取り込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/c5e1afd8-1895-e4ff-f66f-a7f52320f7a8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/6cc2817a-f2cb-3b70-7123-c94c09483ad3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/8140d505-3a27-df27-8d0c-b0ca67c655e0.png)

##Power Query エディターでデータ加工

このままでは使えないので、加工します。
その大まかな手順は以下のようになります。

>**`「上位の行の削除」　→　「1行目をヘッダーとして使用」
　→　「列の削除」 → （全列選択）「フィル下」
　列名手動変更`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/318d733b-eca6-b8e3-6360-48194e80f103.png)

>**`「上位の行の削除」
　列名手動変更`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/76b1c872-d1d1-f84e-e42a-58568668c794.png)

>**`　列を移動（金額列を先頭に）
　値置換（「(1)」が入っていたのでブランクに置換）`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/7dec24ac-9741-d94e-75e8-069d9b8f7f1a.png)

>**`　（最初の2列を選択して）「その他の列のピボット解除」
　（解除してできた列の）列名手動変更`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/3820f9e2-fb56-d492-d8cb-8d7606f73cc1.png)

>**`　（アンダースコアで）「列の分割」（YYYYだけの列を作る）`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/34a9aa2a-252e-4299-5ddd-52f4e54d7ba6.png)

>**`　（時系列順に並べるために）「インデックス列（1から）」
　値置換（先頭列に入っている(losses)をブランクに置換」）`**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/20854974-958f-2580-b14c-e27d96f13b7f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/73730f65-aee1-6d8a-5966-7fdab6604551.png)

これでデータ加工は完了です。

##フィルター機能を使い可視化

作成したグラフは、以下のように配置しています。

| 左側のグラフ | 右側のグラフ |
|:-:|:-:|
| 収益  | 有料会員増加分  |
| 期末の有料会員  | エリア別年度末収益  |

各グラフは主に「フィルター」で表示要素をコントロールしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/cb49cc8d-9c3d-6a9f-d33e-e10794e736a2.png)

作成したのが冒頭のグラフです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1143963/2965b5a1-566b-5da5-9032-a0283ea7488f.png)

**了**
【Nuxt 3】npm と yarn の速度比較

# 前置き

Nuxt 3 のベータ版があったので調べてみようと思いました。

[Nuxt 3 - Installation (nuxtjs.org)](https://v3.nuxtjs.org/getting-started/installation)

依存パッケージのインストールには `npm` か `yarn` を使いますが、マニュアルでは先にコマンドが紹介されている yarn のほうを推奨しているように見えます。
そこで Nuxt の中身を見る前に、先にどのパッケージマネージャを使うか決めたいと思います。

node 周りを触るのは久しぶりで、npm は激重、yarn は速くて快適という先入観があるのですが、最近は npm も成長しているそうです。

[npmとyarnとpnpmの違い2021 (zenn.dev)](https://zenn.dev/hibikine/articles/27621a7f95e761)

相変わらず速度については npm がビリのようですが、思ったより差がなくなってるなぁという印象です。
また機能面は npm が yarn を真似て、こちらも似通ってきているようです。
速度面については興味があるので npm と yarn で簡単な比較をしてから、どちらを使うか判断することにしました。pnpm とかいうのは今回はスルーします。

ちなみに Nuxt については数年前に少し触ったことがあるだけでほとんど何もわかりません。

# 環境

<dl>
  <dt>コンピュータ</dt>
  <dd>
    <ul>
      <li>Ubuntu 20.04 @ WSL2 on Windows 10 Home</li>
      <li>Intel Core i7-1160G7 @ 1.20GHz 2.11 GHz</li>
      <li>RAM 16GB</li>
    </ul>
  </dd>
  <dt>Node.js 関連</dt>
  <dd>
    <ul>
      <li>node 16.13.1</li>
      <li>npm 8.3.2</li>
      <li>yarn 1.22.15</li>
    </ul>
  </dd>
</dl>

# 速度比較

## 計測方法

npm と yarn でキャッシュ無し・有りのインストールを5回ずつ行い、それぞれの平均秒数と中央値を出しました。

```bash
# (1) Nuxt の新規プロジェクトを作成
$ npx nuxi init nuxt3-app
# (2) 依存パッケージのインストール時間計測
$ cd nuxt3-app ; time npm -i # npm
$ cd nuxt3-app ; time yarn # yarn
# (3) プロジェクトとキャッシュの削除
## キャッシュ無しの場合
$ cd .. ; rm -rf nuxt3-app ~/.npm # npm
$ cd .. ; rm -rf nuxt3-app ~/.cache/yarn # yarn
## キャッシュ有りの場合
$ cd .. ; rm -rf nuxt3-app # npm/yarn
# (1)に戻る
```

新規プロジェクトの初回インストール時のみの比較なので、node_modules や lockfile の有無といったややこしい話は無しで、計測のたびにプロジェクトごと削除して実行し直しました。

## 結果

| （単位：秒） | キャッシュ無し：平均値 | キャッシュ無し：中央値 | キャッシュ有り：平均値 | キャッシュ有り：中央値 |
| --- | --- | --- | --- | --- |
| **npm** | 80.51 | 79.80 | 19.95 | 19.85 |
| **yarn** | 56.28 | 51.03 | 25.34 | 23.43 |
| **npm - yarn**  | **+24.23** | **+28.77** | **-5.39** | **-3.58** |

キャッシュ無しだと yarn のほうが1.5倍速い感じです。
一方キャッシュ有りだと意外にも npm のほうが速かったです。
上で紹介されている記事とは異なる結果ですが、バージョンが上がったおかげでしょうか。

# どちらを使うか

今回は npm にします。

yarn は速くて素敵ですが、v1系がクラシック扱いで[今はv3がアクティブ](https://github.com/yarnpkg/berry/blob/7758c0cf4df7361007d31be4078d74c8d2001fe4/CHANGELOG.md#311)なのと、そのv3だと依存パッケージのインストールが失敗するのでもう少し様子を見ようと思います。
ETC証明書をPower Automate Desktopで簡単ダウンロード

#Webログインと保存を１分で
出張が多く、車を使うと高速も必ずと言っていいほど使います。
出張報告のたびにWebにログインしてTEC証明書をダウンロードして印刷してと、本社スタッフ誰もがやっていることを自動で取ってみることにしてみました。

#使用するもの
[Power Automate Desktop](https://powerautomate.microsoft.com/ja-jp/desktop/)
Microsoft　Excel

#流れ
前もってExcelにログインIDとパスワードを準備しておき、ファイルを保存しておきます。
ログインから印刷前までをPADのレコーダー機能で覚えさせました。
![コピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/e78d96d0-6d34-07e1-6103-7e97e579fc54.jpeg)

当月分をチェックし、証明書をパソコンにダウンロード。
![ETC画面.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/de8a6d28-b700-f137-ff8e-2b1531994a53.jpeg)

この証明書をパソコンに保存するようにしました。

#フロー
全てのフローはこのような感じです。
![全体.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/909cf964-2d88-66ae-679c-4de4abad20fc.jpeg)


##壁にぶち当たってからチャレンジしたところ

本当はchromeで作っていたのですが、どうしても保存ができなかったのでIEに切り替えました。
chromeもIEも証明書を表示してから保存しようとすると上手くレコーダー機能が使えませんでした。

IEではなんとかUI要素の追加をすることでメニューからの選択、ファイル→名前を付けて保存が実現しました。
![メニュー追加.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2495084/db124a74-a87b-4ca7-d991-efd0e4a2879d.jpeg)

ただ、IEが不安定なのか、フローの改善が必要なのか保存まできちんと動作する時と途中で止まるときがあります。
次はchromeで作成、保存、印刷まで実施できるようにチェレンジ中です。
Tempfile オブジェクトから Content-Type(mime type) を取得する方法

## やりたいこと

Tempfile のオブジェクトを作成後、そこから Content-Type(mime type) を取得したい。

## 解決策

[marcel](https://github.com/rails/marcel) の `Marcel::Magic.by_magic` を使うと取得できる。

```ruby
> tempfile = # PDF を Tempfile オブジェクトに変換
> Marcel::Magic.by_magic(tempfile).type
=> "application/pdf"
```

[実装](https://github.com/rails/marcel/blob/fc69a19d17de4fedca354b2404b04834b16eacd8/lib/marcel/magic.rb#L85-L88) を読むと `io` を引数に取れるみたいなので、 `File` クラスへの Delegator の `Tempfile` だけでなく `StringIO` もいけるかも（未検証）
ちなみに `activestorage` が依存してる gem なので、 `rails` の gem を入れたら一緒に付いてくるのでそのまま使える。便利。

## 確認バージョン

marcel: 1.0.2
rails: 6.1.4.4
Azure Blob StorageをNFSでマウント

Azure Blob StorageをVMやAKSからマウントするにはこれまでは、Azure Blob Storage CSI driverを使わなければいけませんでした。

https://github.com/kubernetes-sigs/blob-csi-driver

2021年12月にNFSもサポートされるようになったので、それを試してみます。

https://docs.microsoft.com/ja-jp/azure/storage/blobs/network-file-system-protocol-support

#NFSを使用可にしたストレージ アカウント
現在のところ、既存のストレージ アカウントにNFSを追加することはできないようです。ですので、新しいストレージ アカウントの作成が必要です。

Terraformの場合は、以下のような感じです。`nfsv3_enabled = "true"`とするだけです。

```terraform
resource "azurerm_storage_account" "nfssa1" {
  name                     = "nfssa"
  resource_group_name      = "mygroup"
  location                 = "Japan West"
  account_tier             = "Standard"
  account_replication_type = "ZRS"
  min_tls_version          = "TLS1_2"
  account_kind             = "StorageV2"
  is_hns_enabled           = "true"
  nfsv3_enabled            = "true"

  network_rules {
    default_action             = "Deny"
    ip_rules                   = ["x.x.x.x/28"]
    virtual_network_subnet_ids = [data.azurerm_subnet.mysubnet.id]
  }  
}

resource "azurerm_storage_container" "sa_container" {
  name                  = "mycontainer"
  storage_account_name = azurerm_storage_account.nfssa1.name
  container_access_type = "private"
  depends_on = [
    azurerm_storage_account.nfssa1
  ]  
}
```
ちなみに、`default_action = "Deny"`がないとエラーが出ます。

#VMからNFSでマウント
AzureでUbuntuのVMを使用する場合は、こんな感じでできます。

```bash
sudo apt install -y nfs-common
install -d /mnt/mystorage

#mount -o sec=sys,vers=3,nolock,proto=tcp <storage-account-name>.blob.core.windows.net:/<storage-account-name>/<container-name>  /mnt/mystorage
mount -o sec=sys,vers=3,nolock,proto=tcp nfssa.blob.core.windows.net:/nfssa/mycontainer  /mnt/mystorage
```

/etc/fstabを編集する場合は、以下のように1行足せば永続的にマウントできます。

```bash
#vi /etc/fstab
nfssa.blob.core.windows.net:/nfssa/mycontainer /mount/mystorage nfs sec=sys,vers=3,nolock,proto=tcp 0 0
```

NFSのアクセスの制限は、VNetやネットワークセキュリティキー設定で行う必要があるようです。デファルトでは、Terraformで設定した`virtual_network_subnet_ids = [data.azurerm_subnet.mysubnet.id]`内からはマウントが可能になります。一部のVMのみにアクセスを制限する場合は、ネットワークセキュリティキー設定を使う必要があるでしょう。
IBM Cloudの新認定試験IBM Cloud Professional Developer v5を受けてみた

# IBM Cloud Professional Developer v5とは
IBM Cloudの認定技術者の1つで、2022年1月から受験可能になりました。レベル感としては、1～3年程度の実務経験を積んだ中級レベルの試験です。

IBM Cloud Professional Professional v5に合格すると、IBM Certified Professional Developer - Cloud v5の認定資格を得ることができます。もちろんOpen Badgeももらえます。

<img width="160" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/3213c2d2-c07e-5182-53a0-8d448b789f89.png">

認定資格および試験の概要はこちら。

https://www.ibm.com/training/certification/C0001905

# 学習方法

難易度はやや高めです。下記サイトでラーニングパスが公開されていますので、一通り目を通すことをお勧めします。合計56時間です。

> https://www.ibm.com/training/path/ibmcloudprofessionaldeveloper

# 受験方法

PearsonVUE社のサイトで予約して受験してください。

https://www.pearsonvue.co.jp/Clients/IBM.aspx

以前は最寄りのテストセンターでしか受験できなかったのですが、最近はカメラ付きPCがあれば自宅でも受験可能になりました。こういうご時世ですので、可能であれば自宅での受験をお勧めします。ただし部屋の片づけはきちんとしておいてください。

# 合格点

60問中38問以上の正解で合格です。正答率は63%です。IBMの認定試験では甘い方だと思いますが、問題がやや難しいので、あまり余裕はないかもしれません。

# 出題内容

試験規約により具体的な問題文は書けませんので、雰囲気になりますが、いくつか問われそうな箇所を書きます。

* IBM Cloud Kubernetesサービス
* Waston関連サービス
* API Connect
* Continuous Deliveryサービス
* Functions
* Schematics
* VPC Virtual Server
* IBM Cloud Object StorageのプランとSDK
* Db2 Warehouse on Cloud
* IBM Cloud Databasesそれぞれの特徴、用途

# 感想

新試験が出たということで、早速挑戦してみました。例によって無勉強でしたが、合格できました。昨年受けたArchitect v5よりは簡単だったかなという印象です。

Developerと称していますが、開発そのもののスキルに関する問いはなかったです。IBM Cloudのサービスに関する問題がほとんどでした。
GitでLFS対象ファイルのプル、プッシュができない不具合の解消法

最近数日間悩まされていたトラブルが解消したので備忘録としてのメモです。

LFS対象のファイルを含まないコミットであればプルもプッシュもできるのですが、
LFS対象のファイルを含むコミットだと、プルもプッシュもできない状態でした。

LFS対象のファイルをプッシュしようとすると以下のようなエラーがでました。

```
Pushing to https://bitbucket.org/(Gitリポジトリのパス)/src/master
Uploading LFS Objects: 0%(0/4), 0B | 0B/s, done.
batch response: Repository or object not found: https://bitbucket.org/(Gitリポジトリのパス)/src/master.git/info/lfs/objects/batch
Check that it exists and that you have proper access to it

error: failed to push some refs to 'https://bitbucket.org/(Gitリポジトリのパス)/src/master'
```

SourceTreeを使っていたのですが、コマンドラインで試しても同じで、TortoiseGitでもダメで、新規にセットアップした別のパソコンでも同じ症状でした。

解決方法は簡単で、SourceTreeの場合は、
「設定」→「リモートリポジトリのパス」→「編集」で、リモートリポジトリのパスを
「https://bitbucket.org/(GitリポジトリのURL)/src/master」
のような書き方ではなく、

「https://(Gitのユーザー名)@bitbucket.org/(Gitリポジトリのパス).git」
のようにすると、LFS対象ファイルを含むコミットのプルとプッシュができるようになりました。

LFSを使わなければ正常に動作するので、途中からLFSを使おうとしてはまってました。
Windows用Anacondaで「Pythonで学ぶ音声認識」の環境をセットアップする

「Pythonで学ぶ音声認識」ではタイトル通りPythonのコードを動かしながら音声認識について学ぶことができるようになっている。
せっかくなのでAnaconda Navigatorを使って仮想環境をそれ用に構築しようと思ったが、この本だけでは情報が足りない。
なので、ここに環境構築手順をまとめておこうと思う。

1. Anaconda Navigatorで環境を"Create"する。　2022年1月の段階ではPython 3.10に対応していないライブラリがあるようなので、それより古いPythonで作成する。
1. 「Pythonで学ぶ音声認識」P.2に記載された"numpy"、"matplotlib"、"pyyaml"をNavigatorでインストールする。　"sox"はリストにないので後回し。
1. NavigatorからCreateした環境のTerminalを起動する。
1. Treminalで"pip install sox"を実行する。
1. Windows環境の場合、sox本体をインストールしなくてはいけないようなので、本家からインストーラをダウンロードして、インストールする。
1. 仮想環境内でsoxが参照できるように、<br><dd>conda env config vars set PATH="%PATH%";"C:\Program Files (x86)\sox-14-4-2"</dd>を実行する。
1. Pythonの文字コードのデフォルトをUTF-8にするために、<br><dd>conda env config vars set PYTHONUTF8=1</dd>を実行する。
1. 環境を再度Activateする。

これで「第３章　第１節　データの準備」にあるPyrhonスクリプトを動作させることができるようになる。　文書内では明示的に書かれていないが、実行ディレクトリは00prepareだ。
PATHの上書きによって、環境立ち上げ時にWARNINGが出るのが鬱陶しい。もしかするともっと良いやり方があるのかもしれない。
文字コードを設定してやらなきゃなんないのも面倒だが、まあ、しょうがないのかな。
数学の学び直しにおすすめMOOCS講座【edex】

###A-level Mathematics for Year 12 - Course 1: Algebraic Methods, Graphs and Applied Mathematics Methods
※イギリスのA level試験に必要な数学の知識を身につけるためのコース
※Year12は高校2年に相当
※無料版の場合の情報となります

主な内容：
　　・因数定理
　　・座標幾何学
　　・図形の変換
　　・力学入門
　　・統計学入門

特徴：
　　・講義は全て英語（英語字幕あり）
　　・Exercise - 何度でも回答可能
　　・Assessment - 2回まで回答可能

感想：
　　・講師の方の英語が聞きやすい。
　　・解説動画が分かりやすく、式の展開も丁寧でつまづきにくい。
　　・問題が秀逸で問題を解くことで確実に力が付く。
MinGWのコンパイルでアイコンを含めてみた。

Mingwでアイコンを含めるてコンパイルする方法を紹介しています。
環境は
OS : Windows10
コンパイラ:Mingw-w64

#まずはコンパイル

もうコンパイルできる人は次へ飛ばしてください。

```c++:main.cpp
#include <stdio.h>

int main (){
    printf("Hello word!!\n");
    while(1)
    {
        
    }
    
    return 0;
}
```

下記のコマンドを実行してコンパイルしてみましょう。

```
g++ main.cpp
```

#アイコンを含めてみる

アイコンファイルを同じディレクトリに配置します。しかし、そのままではコンパイルに使用できません。そのため、リソースファイルというものを作成します。

### リソースファイル
```test.rc
id ICON "アイコンファイル名.ico"
```

環境などにあわせて書き換えてください"id"はてきとうに英語・数字などを使えばよいです。詳しくは分からないが、idは1回だけ定義する識別子のようなものだと思います。僕の場合は下のようになります。

```icon.rc
1 ICON "icon.ico"
```
コマンドラインで下記を実行します。

```
windres icon.rc -O coff -o icon.res
g++ main.cpp icon.res -o main.exe
```

windoresはリソースファイルをリンクできるようにすることができます。
リソースファイルもリンクさせることでアイコン付きのexeを作ることができます。

# まとめ

### 参考にしたサイト

https://stackoverflow.com/questions/33000158/embed-manifest-file-to-require-administrator-execution-level-with-mingw32

###追記
間違い等あった場合は報告してくれると助かります。
【読書メモ】ドメイン駆動設計 サンプルコード & FAQ

松岡幸一郎さん著 [ドメイン駆動設計 サンプルコード&FAQ](https://booth.pm/ja/items/3363104)  を読んだ感想です。書籍の要約ではなく、自分が参考になった箇所や疑問に思った箇所を書きます。

[ドメイン駆動設計 モデリング/実装ガイド](https://little-hands.booth.pm/items/1835632) はモデリングや実装パターンの総論的な書籍でしたが、サンプルコードFAQはもう少し具体的なサンプルコードやFAQがメインでした。

読む順番としてはモデリング/実装ガイド → サンプルコードFAQが良いと思います。

## エンティティとORマッパーの違い

- エンティティ： ドメインモデルをそのまま表現したクラス。 ``` RDBのテーブルに関する知識やORマッパー固有の実装に影響を受けないようにする ``` 
- ORマッパー： データベースにプログラムのデータをマッピングするクラス

> ORマッパーのクラスは、インフラ層のリポジトリの実装クラスの中だけで使用し、ドメイン層とユースケース層では参照されないようにします。前節で解説した通り、ORマッパーのクラスをそのままエンティティやドメインオブジェクトとして使用することは非推奨です。

(P.36)

かなり腑に落ちた部分
RailsやLaravelで保守性が低下しやすいのはModelクラスをエンティティとして利用しているのが大きそうです。

ORマッパーをエンティティとして使用するのはドメインモデルを正確に反映できない(DBのテーブル設計に制約されるため)・インフラ層の知識がドメイン層に漏れ出すという2つの理由でアンチパターンだと理解しました。

## リポジトリでソートするにはどうすれば良いか

- リポジトリ層のメソッドの引数に「並び替え条件」を表すenumを渡す

ソート条件をenumで定義すると不正な値がソートキーに渡ることを防止できます。

ドメイン層にソートに関する知識を定義して良いのか、と思いましたが「ユーザエンティティの名前」や「ユーザID」のようにドメイン層の知識で表現されていれば問題ないようです。
(逆にorder by やlimitのようにソート・絞り込みを実現する具体的な技術の情報がドメイン層に流出しているのはNGです)

ただ、昇順降順指定はどのように実現するか書かれていませんでした。
ソートが昇順か降順かという情報をドメイン層に持たせるのは不自然なので、リポジトリで制御するんでしょうか...

### ユースケースオブジェクトのテストでエンティティのアサーションは必要か

- ユースケース層の責務はおおまかに言って「エンティティクラスのインスタンスを生成してリポジトリに渡す」ことなので、改めてインスタンスのプロパティをアサーションする必要はない。(たただし、ユースケース層とドメイン層の結合テストという観点では実施しても良い)

ユースケース層でエンティティのテストを省略するためにもエンティティクラスのテストはちゃんとやっておく必要がありますね。
(クラスの責務を明確にするとテストの重複を減らしやすく、品質を担保しやすいと思いました)

### 各レイヤーで送出したレイヤーはどのように処理するか

> プレゼンテーション層に共通の例外ハンドラーを定義し、そこで例外をキャッチしてエラーレスポンス用のオブジェクトに詰め替えるのがよいでしょう。

(P. 106)

- 例外の送出： 各レイヤーの責務
- エラー情報の表示： プレゼンテーション層の責務

と整理できるでしょう。
例外ハンドラーはフレームワークの実装に依存します。
フレームワークの実装に則る方が実装コストが低いというのもあると思いますが、クライアントとのデータのやり取りはプレゼンテーション層の責務であるというのが一番の理由だと思います。

### 業務ロジックとは？

この書籍では、「業務ロジック」という言葉が示す範囲が広すぎるのでより詳細化した言葉で分類すべきとされています。

- ドメイン知識： ソフトウェアで問題解決する領域に存在するルール/制約。 ソフトウェアが無くても存在する。 ドメイン層に記述
- ユースケース： ユーザがソフトウェアで行う操作。 ソフトウェアありきのもの。 ユースケース層に記述
- 表示に関するもの： 書式やフォーマットなど、表示時のルール。 プレゼンテーション層に記述

私は表示ルールをドメイン層の関心事としてとらえてしまいがちなので、この部分は特に参考になりました。 表示形式を整える処理はプレゼンテーション層のコントローラとは別のパッケージで管理すると責務が明確になりそうです。

##　まとめ

リポジトリのソートや例外処理など疑問に思っていたことが解消されました。
本書ではテストが丸々1章を割いて扱われていましたが、十分に理解することができませんでした。
typeof と instanceof

変数 `s` が文字列かどうかを確認するコードで、

```js
typeof s === 'string' || s instanceof String
```

というものを見かけた。

名前の通り、あるクラスをインスタンス化してできたものは `instanceof` で判別、それ以外で作られたものは `typeof` で判別？

```js
str1 = new String('str1')
str2 = 'str2'

console.log(typeof str1) // object
console.log(typeof str2) // string
console.log(str1 instanceof String) // true
console.log(str2 instanceof String) // false
```

# 読んだ記事

- https://stackoverflow.com/questions/899574/what-is-the-difference-between-typeof-and-instanceof-and-when-should-one-be-used
Git で文書管理（下書き中）

・Git で文書管理したい。
・GitHub or　GitLab ?

https://pfs.nifcloud.com/navi/beginner/git.htm

・GitLabを使ってみるか。
GitHub とは違って、GitLab ではプライベートリポジトリが使えるらしい。

https://www.anken-navi.jp/news/work-freelance/git-description/


【参考リンク】
6.1章の図が見やすい

https://itcweb.cc.affrc.go.jp/affrit/documents/guide/gitlab/start

http://wiki.cis.iwate-u.ac.jp/~kimura/csd/2018/material/gitlab/
[JS]繰り返しの処理

アウトプットとして

Rubyの繰り返しの処理とは違う書き方をするので、自分の中で整理するために記事にしたいと思います。

##for文
JavaScriptでは、繰り返し処理を行う際にfor文を使用する。
構文は以下の通り

```javascript
for([①初期化式]; [②条件式]; [③加算式]) {
  // 繰り返す処理の内容
}

//例
for ( let i = 1; i <= 100; i++ ) {
  // 100回処理を繰り返す
}
```

①初期化式（initialization）：for文の中で使用する変数を定義する。ここで定義した変数は「今何回目の処理か」を判定するために参照される。

②条件式（condition）：for文の処理を何回繰り返すかを指定する。この条件式の戻り値がtrueで有る限り処理が行われ続ける。往復する前に評価される。

③加算式（final-expression	）：初期化式として定義した変数の増減を記述できる。往復した後に評価される。
例）i = i+1とすれば1周ごとに1が加算されて、処理が実行されます。
i = i + 1の省略形
・ i += 1
・ i++

 
Rubyの構文とは違うので気をつけたい。

※補足等ございましたらコメントいただけると幸いです。
素のJSでQiitaAPIを叩く(Ajax)



# AjaxとAPIの学習用

ソース書く前に取得できるかcurlコマンドで確認。
※以降、XXXXXXは自分のアクセストークン

```
curl -H "Authorization: Bearer XXXXXX" https://qiita.com/api/v2/authenticated_user
```

```JavaScript:api.js
// 素のJavaScriptでAjax
const api_endpoint = "https://qiita.com/api/v2/authenticated_user/items";
const token = "XXXXXXX"; // 個人のアクセストークンを利用
let out = document.getElementById("out");
console.log(out);
/**
 * Qiita API v2で、自分のアカウントプロフィールを取得
 * @param {string} url -  エンドポイントurl
 */
let readQiitaApi = (url) => {
    console.log(out);
    // 1, XMLHttpRequest オブジェクトを生成
    let xhr = new XMLHttpRequest();

    // 2, サーバ応答時の処理を定義(onreadystatechangeイベント)
    xhr.onreadystatechange = () => {
        // 通信完了時
        if(xhr.readyState == 4){
            // 通信成功時
            if(xhr.status == 200){
                out.innerHTML = xhr.responseText;
                console.log("成功");
            }else{
                console.log("失敗");
            }
        }else{
            out.innerHTML = "通信中・・・";
        }
    };

    // 3, サーバにリクエストを送信 
    // open(HTTPメソッド, URL, 非同期モードで通信するか, ユーザー名, パスワード)
    xhr.open("GET", url, true);
    
    // リクエストヘッダ設定(第一引数にヘッダ名、第二にヘッダの値)
    xhr.setRequestHeader('Authorization', 'Bearer ' + token);

    // send(): openメソッドでGETにした場合はnull
    xhr.send(null);

}
```
結果出力html

```HAML:index.html
    <input type="button" value="実行" onclick="readQiitaApi(api_endpoint);">
    <p id="out"></p>
    <script src="api.js"></script>
```
PipedOutputStream を使ってオーディオをストリームで扱う

PublicClodなどの音声認識サービスにおいてSDKで実装しようとするとインターフェースとしてInputStreamとなっている事があります。
byte[] で扱いたい場合にはPipedOutputStream/PipedInputStreamを使うと実装の幅が広がったりします。

```java
import static java.lang.System.out;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

public class PipedSoundStreamExample {

	public static final int PIPE_SIZE = 1024 * 32;

	public static final AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
	public static final DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);

	static boolean finish = false;

	static long senderSize = 0;
	static long receiverSize = 0;

	public static void main(String[] args) throws IOException, InterruptedException {

		if (!AudioSystem.isLineSupported(info)) {
			out.println("Line not supported");
			System.exit(0);
		}

		final PipedOutputStream sender = new PipedOutputStream();
		final PipedInputStream receiver = new PipedInputStream(sender, PIPE_SIZE);

		Thread WriterThread  = new Thread(() -> {
			TargetDataLine line = null;
			try {
				line = (TargetDataLine) AudioSystem.getLine(info);// ### read from microphone
				line.open(format);
				line.start();
				long end = System.currentTimeMillis() + (3 * 1000);// ### run for 3 seconds
				byte[] bytes = new byte[1024];
				while (line.isOpen()) {
					if (System.currentTimeMillis() > end)
						break;
					int numBytesRead = line.read(bytes, 0, bytes.length);
					if ((numBytesRead <= 0) && (line.isOpen()))
						continue;
					senderSize += bytes.length;
					sender.write(bytes);// ### send byte.
				}
			} catch (LineUnavailableException | IOException e) {
				e.printStackTrace();
			} finally {
				if (line != null) {
					line.stop();
					line.close();
				}
				// Thread.sleep(100);
				finish = true;
			}
		});

		Thread ReaderThread = new Thread(() -> {
			try {
				int ready;
				byte[] buffer;
				while (!finish) {
					ready = receiver.available();
					if (ready <= 0)
						continue;
					buffer = new byte[ready];
					receiver.read(buffer);// ### read byte.
					// out.println(Arrays.toString(buffer));
					receiverSize += buffer.length;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		});

		WriterThread.start();
		ReaderThread.start();

		WriterThread.join();
		ReaderThread.join();

		sender.close();
		receiver.close();

		out.println(senderSize + " => " + receiverSize);

	}
}
Visual Effect GraphのLinear dragとは？ Keijiroさんのコード読み

## Linear Drag とは何か？

[Visual Effect Graphの公式ドキュメント](https://docs.unity3d.com/Packages/com.unity.visualeffectgraph@10.2/manual/Block-LinearDrag.html
) によると，

```
Linear Drag Blockは、パーティクルに力を加えて、方向を変えずに速度を落とすことができます。
```

と書かれていて，ここでのdragとは抗力らしいです．つまり空気抵抗や摩擦に近いものっぽい．

## 実際にやってそうな計算

Keijiroさんの[KvantSwarm](https://github.com/keijiro/KvantSwarm/blob/master/Assets/Kvant/Swarm/Shaders/Kernel.shader#L114) を読んでいて，Linear dragが何かがおおよそわかりました ↓

```HLSL
 //現在のフレームで設定する速度 = (前のフレームの速度) * (抵抗力) + (加速度) * (時間 dt)
velocity = velocity * _Drag + (force) * _DeltaTime;
```

現在のvelocityの方向は変更せず，大きさだけ若干落とすというやり方になっていました．ここでの `_Drag ` の数値として，C#側から ` Mathf.Exp(-_drag * deltaTime)` が設定されていました（実際の値は`Mathf.Exp(- 2 * 0.025) = 0.951..`でした）．

dragの値における減少度合いは以下の通りです．

```Python
math.exp(- 0 * 0.025) => 0.0
math.exp(- 100 * 0.025) => 0.08208..
math.exp(- 1 * 0.025) => 0.9753..
math.exp(- 10 * 0.025) => 0.7788..
math.exp(- 100 * 0.025) => 0.08208..
```
という感じです．ちなみにdragの値をマイナスにすると抵抗ではなく，加速的な状態になるので注意が必要です．

```Python
math.exp(- (-1) * 0.025) => 1.0253..
math.exp(- (-10) * 0.025) => 1.0253..
math.exp(- (-100) * 0.025) => 12.182...
```

## 用途

ちなみにKvantSwarmでは，特定のオブジェクト(Attractor objectと呼ばれる)に追従するトレイルの速度を決める際に使われていました，

linear dragがないと，速度が強すぎてAttractor objectよりも遠くにトレイルがいってしまう（発散する）ので，その速度を落とすのにLinear dragが使われていました．
pm2 deploy　しようとしたが、「WARNING: UNPROTECTED PRIVATE KEY FILE!」でデプロイ出来なかった。

PM2デプロイコマンドを叩いたら、下記のようなエラーがでて、デプロイできなかった。
そうなった原因はわからない。数日前までは問題なくデプロイ出来ていたので…

```terminal
$ pm2 deploy production
--> Deploying to production environment
--> on host ***********

○ deploying origin/master
○ executing pre-deploy-local
○ executing pre-deploy `git pull`
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/Users/***/.ssh/***.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/Users/irahara/.ssh/candeo-fm.pem": bad permissions
*********: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

pre-deploy hook failed

Deploy failed
Deploy failed with exit code: 1
```
対処方法としては、再度鍵に権限を付与してあげる。

```
$sudo chmod 0600 ***.pem
```

これでデプロイ出来ました。

##　参考にした記事

https://qiita.com/shimajiri/items/5716068da4d3a042b97c
Visual Studio 2019 のキーバインドをVS Codeに合わせる手順

よく忘れるので、個人用の備忘録として手順を記載します。

1. ツール > オプション > 環境 > キーボード に移動

2. 既定の設定からVisual Studio Codeに変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515183/67961f5c-1ff9-3884-7d19-6e892204d4a6.png)
これだけだと、Ctrl+PageUp,PageDownでタブ移動ができない、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515183/64e5e5cb-aa7f-0745-285d-275714dce14c.png)


3. 「編集.上端まで移動」と「編集.下端に移動」を変更する
<br>テキストエディターからのCtrl+PageUp/Downが上書きされているので、
削除してから好きなコマンドを割り当てる。
(個人的には同じような動作に割り当てられているCtrl+Home/Endを割り当てるのがおすすめ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515183/1053b1f5-f6a6-7dfc-91ad-ec216f0cb6e0.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2515183/3cdc8789-e6e3-9d0a-f846-ab3bb3d04b31.png)

今のところこれだけですが、
設定変更あれば追加していく予定です。
Qtで作ったアプリケーションを配布するためのインストーラを作ろう

# Qtで作ったアプリケーションを配布するためのインストーラを作ろう

直近でQtを使った業務が行われるのだが、それをお客さんに配布するのだが、あまりパソコン操作が得意じゃないお客さんなので親切心からインストーラを作ることにした

## 使用環境

- Windows 11
- Qt6
- Inno Setup: 6.2.0

事前準備のため必要ツールをインストール

```powershell
# Inno Setupをインストールする
> winget install JRSoftware.InnoSetup
```

## 手順

### Qtを使ったアプリを作成する

とりあえずアプリがないと始まらないので以下のようなアプリを作ってみる

![qt_demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/7d11d24c-3998-9019-b1ef-7af6dde1dec0.gif)

※ 久しぶりに触ってみたら開発環境がQtCreatorとQt Design Studioに増えてたので次回触ってみよう

ここまでで以下のようなフォルダ構成になっているとします

```bash
Test/
├───build
│   └───Release
│       └ Test.exe # 今回作成したアプリケーションの実行ファイル
```

### 依存関係DLLを配布用に集める

Qtには配布をするために実行ファイルに依存しているDLLを調べて、直下にコピーしてくれるコマンドがある。
それを利用させてもらう。

```powershell
> cd .\Test
> windeployqt --dir .\dist .\build\Release\Test.exe
```

コマンドを実行したことで'\dist'フォルダに`Qt6Core.dll`などの依存していたDLLがコピーされている。
この段階で以下のようなフォルダ構成になる

```bash
Test/
├───build
│   └───Release
│       └ Test.exe # 今回作成したアプリケーションの実行ファイル
└───dist # 依存するファイルがここに準備される
```

### インストーラを作成する

ここからは`Inno Setup`を使用する

`Inno Setup`を起動すると`Inno Setup Script Wizard`が起動します。新規でインストーラを作る場合に起動するようです。

ここは気にせず`Next`ボタンを押しましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/70163a21-bc1c-cfba-b716-35b60bfefbe7.png)

アプリケーションの情報を記入します。`Application name`と`Application version`以外は空欄でも動きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/113343ea-05fe-1a6d-ad2e-bd0a4ed169d3.png)

インストーラでアプリケーションをインストールした際に、インストールフォルダの名前をどうするか入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/348944ca-596d-05b3-8f0f-b82c30642ae7.png)

今回、配布するアプリケーションの実行ファイル`.exe`を選択し、`Other application files`には`Add folder`ボタンから先ほど作成した`dist`フォルダを追加する。

※`dist`フォルダを追加する際、サブディレクトリを検索するか聞かれるので必ず`Yes`と答えましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/c92eabee-9656-eab4-e232-f30d00f3ff60.png)

あとは適当に`Next`ボタンを押していればインストーラが完成します。
Rubymineいろいろ

順次追記予定。

## フォントサイズ変更
`Preferences => Editor => General で、Change font size with Command + Mouse Wheel`
出典：[RubyMineでフォントサイズを変更したい](https://k-koh.hatenablog.com/entry/2021/01/22/114237)

## 検索の件数をカスタマイズ
100件は少なすぎるという貴方に。
Preferences → 詳細設定 → 検索/置換 「複数ファイル内検索/使用箇所の表示」 プレビューに表示する検索結果の最大件数→100件から好きな数字に

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90217/cb38ea2d-af4b-3798-7895-066b55adc75a.png)

## メモリ使用量の変更

ツールバーの［ヘルプ］ → メモリ設定を変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90217/f844900e-ce18-1be8-8322-fe3b44142632.png)
【Salesforce】【MFA】Salesforce Authenticator 複数アカウントの登録

2022年2月1日から必須化されるSalesforceの多要素認証について
**1つの端末のSalesforce Authenticatorアプリで同一環境の複数アカウントの登録ができるか**
検証してみました。

#検証環境
ぴえさん個人のDeveloper Editionです。
Salesforce Authenticatorはandroid端末にインストールしました。

#結果
**1つの端末のSalesforce Authenticatorアプリで同一環境の複数アカウントの登録ができた！**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/cb80ae44-2a57-cfda-be50-5cc3e210da34.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461666/7e457dc2-9c1f-db5d-1fbf-fcd62cc79698.png)
※アプリの画面はスクショできませんでした。セキュリティ上の問題かしら。仕方ないので別のスマホで撮りました。

ちなみにDeveloper EditionはMFA必須化の対象ではないようです。下手に設定してログインできなくなると悲しいのでお勧めしません。

#参考
https://help.salesforce.com/s/articleView?id=000356005&type=1
https://help.salesforce.com/s/articleView?id=000352937&type=1
Vue3 + Spring Bootでフロント・バックを分離したアプリのDev環境API通信設定

# なにこれ？
フロントエンドとバックエンドアプリケーションを分離したときにAPI通信をする必要があるわけですが、ポート指定とかどうすんのってところで詰まったので備忘録です。

#環境
- フロントエンド：Vue3 (vue-cli3)
- バックエンド：Java (Spring Boot)

フロントエンドはvue-cli、バックエンドはSpring Bootでプロジェクトを新規生成して、ざっくりと下のようなフォルダ構成になっているものとします。

```
root/
  ├ frontend
  │     └　vue-cliで生成したディレクトリ構成
　└ backend
        └  Spring Bootで生成したディレクトリ構成
```

# バックエンド側の設定
Vue側でリクエスト先のポート指定をするために、バックエンド側のポートを設定しておきます。

application.ymlで起動構成を設定できるので、下のようにポート番号を指定しておきます。DBの接続情報なんかもここで設定していますね。

```yaml:application.yml
spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/hoge
    username: fuga
    password: fuga
    driver-class-name: org.postgresql.Driver
server.port: 8081
```

application.ymlの場所はsrc/main/resources配下です。

# フロントエンド側の設定
vue-cli3でフロントエンドプロジェクトを生成した際はvue.config.jsに起動構成を設定します。詳しいことは[vue-cli公式](https://cli.vuejs.org/config/#devserver-proxy)を参照してください。パスによって振り分けるみたいなこともできるそうです。

```js:vue.config.js
module.exports = {
    devServer: {
        proxy: 'http://localhost:8081'
    }
}
```

vue.config.jsの場所はこの記事の例でいうとfrontend配下で、package.jsonとかがいる場所になります。
systemdでunicornの自動起動を設定してみた

# 目次
[1.はじめに](#はじめに)
[2.serviceファイル](#serviceファイル)
[3.自動起動設定](#自動起動設定)
[4.まとめ](#まとめ)

# はじめに
以前の記事[「Webアプリデプロイ方法(AWS EC2編)」](https://qiita.com/Unimaru/items/66a01ad5dab54e66ff47)を通し、railsアプリをNginx＋Unicornの環境で構築しましたが、unicornの自動起動設定が未済でしたので実施していきます。大まかな流れは以下の通りです。

①serviceファイルを作成する
②serviceファイルを設定する
③自動起動の設定をする

# serviceファイル
## serviceファイルの作成

```sh:EC2
#systemdの設定ファイルを格納するパスに移動する
$ cd /etc/systemd/system
#unicorn用のserviceファイルを作成する
$ sudo touch unicorn.service
#パーミッションが644でない場合はセキュリティを高める観点で644に設定する
$ sudo chmod 644 unicorn.service
```
## serviceファイルの設定
```sh:EC2
#serviceファイルを編集する
$ sudo vi unicorn.service

1. 「i」を入力し、入力モードに切り替え、以下を追記する
-------------------------------------------------------------------------------------------------
[Unit]
#ユニットの説明
Description=The unicorn process
#設定するユニットの後に起動するユニット
Before=nginx.service
#設定するユニットの前に起動するユニット
After=network.target remote-fs.target

[Service]
#実行時のユーザ　 ※適宜、自らのアプリに合わして設定すること
User=memadmin
#作業ディレクトリの指定　 ※適宜、自分のアプリにおけるフルパスを記載すること
WorkingDirectory=/var/www/rails/memory_tank
#標準出力先をsyslogに設定
StandardOutput = syslog
#標準エラー出力先をsyslogに設定
StandardError = syslog
#syslogへ出力する際の識別子を設定
SyslogIdentifier = unicorn
#PIDファイルのフルパスを記載  ※適宜、自分のアプリにおけるパスを記載すること
PIDFile=/var/www/rails/memory_tank/tmp/pids/unicorn.pid
#サービスの起動完了を判定するタイミングを指定。指定コマンドがフォアグラウンドで実行を継続する場合。コマンドを実行したらすぐに起動完了と判定。
Type=simple
#プロセスが異常終了した場合にサービス再起動する
Restart=always
#変数 　※適宜、アプリの環境を指定
Environment=RAILS_ENV=production
#変数　 ※適宜、unicornの設定ファイルのフルパスを記載すること
Environment=UNICORN_CONF=/var/www/rails/memory_tank/config/unicorn.conf.rb
#unicornの起動　※　-lはログイン状態のシェルで-cは引数のコマンドを実行するという意味
ExecStart=/bin/bash -l -c 'bundle exec unicorn_rails -c ${UNICORN_CONF} -E ${RAILS_ENV} -D'
#unicornの停止
ExecStop=/usr/bin/kill -QUIT $MAINPID
#unicornの再起動
ExecReload=/usr/bin/kill -USR2 $MAINPID

[Install]
#enable時にこのUnitの.wantsディレクトリにシンボリックリンクをはる
WantedBy=multi-user.target

-------------------------------------------------------------------------------------------------
2. 「esc」を押して入力モードを終了する
3. 「:wq」を入力後、エンターを押して編集を完了する
```

# 自動起動設定

```sh:EC2
#unicornの自動起動設定
$ systemctl enable unicorn.service
#シンボリックリンクが貼られたことの確認
$ ll /etc/systemd/system/multi-user.target.wants/unicorn.service
lrwxrwxrwx 1 root root 35  1月 22 08:32 /etc/systemd/system/multi-user.target.wants/unicorn.service -> /etc/systemd/system/unicorn.service
#OS再起動
$ reboot
#unicornの自動起動確認
$ systemctl status unicorn
● unicorn.service - The unicorn process
   Loaded: loaded (/etc/systemd/system/unicorn.service; enabled; vendor preset: disabled)
   Active: active (running) since 土 2022-01-22 13:21:38 UTC; 3min 51s ago
 Main PID: 3488 (bundle)
   CGroup: /system.slice/unicorn.service
           ├─3488 unicorn_rails master -c /var/www/rails/memory_tank/config/unicorn.conf.rb -E production -D
           ├─3545 unicorn_rails worker[0] -c /var/www/rails/memory_tank/config/unicorn.conf.rb -E production -D
           └─3546 unicorn_rails worker[1] -c /var/www/rails/memory_tank/config/unicorn.conf.rb -E production -D
```

# まとめ
今回はsystemdでunicornの自動起動を設定しました。これにより、OS再起動後も自動でunicornが起動されるため、EC2インスタンスの自動停止・再開(コスト削減のための夜間停止)を組み込んだケースにおいても、スムーズにアプリ利用が可能になると思います。


以上、最後まで読んで頂きありがとうございました！
よく使うコマンド集

# はじめに 
コマンドを使用する際に、いつも検索する事から始めてしまい、時間も取られてしまうので、予めメモとして投稿しようと思いました。
- - -
# 指定先に移動する 
```
cd　指定ファイル、フォルダまたはディレクトリ
```
cdの後に半角スペース、後は指定先をドロップアンドドラッグでOKです。
# gitの初期化
```
git init
```
# Repositoryの設定
```
git remote add origin　"GitHub.RepositoryのSSH"
```
# 設定したRepositoryの確認
```
git remote -v
```
# コミット履歴確認
```
git log
```
# ローカルエリアの差分確認
```
git status
```
# ステージングエリアに保存(全て)
```
git add .
```
# コミットする
```
git commit -m"任意のメッセージ"
```
# 現在のブランチの確認
```
git branch
```
# リモート環境にアップロードする
```
git push origin 現在のブランチ
```
# ・トラブル発生時によく使うコマンド
# ファイル全体のキャッシュ削除
```
git rm -r --cached .
```
# コミットの差分を巻き戻す
```
git reset --hard HEAD^
```
^(キャロット)を付けた数分コミットが巻き戻ります
# git resetの操作を戻す
```
git reflog
```
【Ruby】検索問題

※初心者向け
※アウトプット練習の為
※学習の復習

開発環境
rails 6.0.4.4
ruby 2.6.5

##問題
任意の文字列に"code"が、左から何文字目に出てくるかを返し、その数を出力するメソッドを作りましょう。

**出力例：**
count_code("codexxcode") → 1
count_code("aaacodebbb") → 4
count_code("cozexxcode") → 7

ヒント: indexメソッドを使用しましょう

**index**
indexメソッドは、文字列や配列の中に指定した文字列が含まれていた場合、その文字列の開始位置を整数の値で返します。

```ruby
str.index(検索したい文字列, [検索を開始する位置])
```

##解答

```ruby
def count_code(str)
  puts str.index("code", 0) + 1
end
```

##解説
indexメソッドは文字列の先頭を0から数えた数字を返すため、+1をしています。

また、文字列の先頭から検索を開始する場合、第二引数は省略が可能です。
そのため、下記のようにコードを書き換えることが可能です。

```ruby
def count_code(str)
  puts (str.index("code") + 1)
end
```
IntelliJ IDEAのPHP x Dockerプロジェクト設定

## この記事の概要

IntelliJ IDEAでPHP x Dockerプロジェクトを作成した時のメモ。

## この記事で触れないこと

それぞれについての詳細。（IntelliJ IDEA、PHP、Docker）

## 環境

- Windows 10 Pro 21H1
- Docker Desktop 4.4.3
- IntelliJ IDEA 2021.3.1
- PHP 8.0

## 環境構築

### 1. IntelliJ IDEAをインストール

[ダウンロード IntelliJ IDEA](https://www.jetbrains.com/ja-jp/idea/download/)

**Ultimate版**をインストールする。
後述のPHPプラグインはUltimate版しかサポートしておらず、Community版では使用できないらしい。

:::note warn
30日間の無料体験か、購入しての利用になる。
:::

### 2. プラグインをインストール

PHP x Dockerプロジェクトに必要なプラグインをインストールする。

- PHP
- PHP Docker

また、日本語で使いたければ言語パックをインストールする。
Japanese Language Pack / 日本語言語パック

### 3. リモート PHP インタープリターの構成

Dockerコンテナ上のPHPを使用するので、リモート PHP インタープリターを構成する。
設定に進む前に、docker-compose.ymlやDockerfileを作成しておく。

設定（`Ctrl+Shift+A`）の言語＆フレームワーク > PHP >
CLI インタープリターの`...`からCLIインタープリターを開く。

`+` から「From Docker, Vagrant, WSL, Remote...」を選択し、
「リモート PHP インタープリターの構成」を開く。

今回は**Docker Compose**を選択し、phpがインストールされたサービスを選択する。

![リモート PHP インタープリターの構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595926/c0b89efa-1579-8517-cd1e-879cc6111289.png)

https://pleiades.io/help/idea/configuring-remote-interpreters.html

以上

## まとめ

これでDockerコンテナ上のPHPを利用できる。
Composerコマンドやテスト（PHPUnit）も実行できるようになった。
秘密鍵を貰ったので、SSH接続してみた

## 経緯
本番サーバーにデータをアップロードするべく、サーバーを管理している他ベンダーから秘密鍵を共有して頂いていたので、それを使ってリモートサーバーにSSH接続しました。

## SSH接続とは
SSHとは、ネットワーク上のリモートサーバにアクセスし、UNIXコマンドを使用して、PCから直接サーバ操作を行うこと。



# 手順

貰った秘密鍵をクライアント側に設定し、それを元に公開鍵を生成して、その公開鍵をサーバー側に登録することでSSH接続できる。

### ①キーペアを作る

まずはクライアント側のキーペアを作らなくてはならないので、

```terminal
$ cd ~/.ssh
$ ssh-keygen -t rsa -b 4096
```

で作成できる。

作成したら、id_rsa、id_rsa.pubができていることを確認する。

```terminal
$ ls -la
```



### ②〜/.ssh/id_rsaを編集する

```terminal

# viエディタで編集
$ vi id_rsa

#編集モードに切り替え
i

#全削除
:%d


#共有されている秘密鍵を貼り付ける。

#保存
ESC
:wq

```

### ③〜/.ssh/config を編集する。

```
Host hogehoge
 HostName ホスト名(IPアドレス)
 User ユーザー名
 IdentityFile ~/.ssh/id_rsa
```

### ④公開鍵の作成



下記のコマンドで、先ほどの秘密鍵をもとに公開鍵を作ることができる。

```terminal
$ ssh-keygen -y -f id_rsa> ~/.ssh/id_rsa.pub
```

このコマンドでid_rsa.pubは書き換えられたので、これでSSH接続、ログインできる。

### ⑤SSHログイン

```terminal
$ ssh user@host
```

 でログインできる。

この鍵さえ登録しておけば、FileZillaやSequelAce等のクライアントツールでこの鍵を使って、SSH接続が可能になります。



### 参考にした記事

[https://qiita.com/kazokmr/items/754169cfa996b24fcbf5](https://qiita.com/kazokmr/items/754169cfa996b24fcbf5)

[https://qiita.com/Hiroro0970/items/95fe203d8a6a4e17884c](https://qiita.com/Hiroro0970/items/95fe203d8a6a4e17884c)
Rails ルーティング

#Rails ルーティング設定
## ルート設定
rootを使用する

```ruby:Routes.rb
root to: "main#index"
```
## 名前空間を使用する
名前空間(admin)のteamsコントローラを使用する場合

```ruby:Routes.rb
  namespace :admin do
    resources :teams
  end
```
AWS ElastiCashe Redis でエンドポイントを用いてバージョン確認する方法

# 概要

- AWSのElastiCasheで建てているRedisサーバーに接続先からエンドポイントを用いてRedisのバージョンを確認するコマンドをまとめる

# 方法

- aws cliコマンドをインストールする。
- 疎通確認済み & aws cliコマンドがインストールされた環境で下記コマンドを実行するとRedisのバージョンが返される。

    ```terminal
    $ redis-cli --version -h エンドポイント
    ```

# 関連記事

- [AWS EC2インスタンスからのS3のバケットとElastiCasheのRedisへ疎通確認をする](https://qiita.com/miriwo/items/dcb4a6172358a1eac55c)
【JavaScript】HTMLのある要素の親の親の要素を取得する方法


本記事では、ある要素の親の親の要素をJSで取得する方法を紹介します。

##やり方

closestメソッドを使います。
このメソッドはparentNodeメソッドと同様、親要素を取得するメソッドです。
しかし、parentNodeメソッドと違い、このメソッドは全親要素（親の親や、親の親の親の要素など）を取得できます。
（parentNode.parentNodeみたいな事をする必要はありません！）

##実例

今回使用するHTMLは以下です。
idがgrandParantのdivタグを取得します。
取得処理はtest.js（後述）に記載し、htmlファイルからこのjsファイルを呼び出します。

```ruby:test.html
<!DOCTYPE html>
<html>

<head>
	<title>Test</title>
	<meta charset="UTF-8" />
</head>

<body>
    <div id="grandParent">
        <div id="Parent">
          <div id="Child">子ども</div>
        </div>
    </div>
    <script src="test.js"></script>
</body>
</html>
```

・test.js
まず、getElementByIdを使用して子要素を取得します。
次に、closestメソッドを使用して、grandParentを取得します。
引数に、取得したい親要素を示すセレクタを指定することで、親要素を取得できます。

```ruby:test.js
const child = document.getElementById("Child");
const grandParent = child.closest("#grandParent");
console.log(grandParent);
```

####実行結果

コンソールにgrandParentのdivタグが表示されればOKです。
![2022-01-22_21h25_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2485934/f4786a2f-5734-d385-2363-d25775d82b30.png)

##参考記事

https://www.sejuku.net/blog/36728
【React】ストップウォッチの作成方法【JavaScript】

## はじめに
　本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## ストップウォッチの作成方法

### react-timer-hookを導入

```:Terminal
$ npm install --save react-timer-hook
```

### コンポーネントの作成

```MyStopwatch.jsx
import React from 'react';
import { useStopwatch } from 'react-timer-hook';

export const MyStopwatch = () => {
  const {
    seconds,
    minutes,
    hours,
    days,
    isRunning,
    start,
    pause,
    reset,
  } = useStopwatch({ autoStart: false });


  return (
    <div style={{textAlign: 'center'}}>
      <h1>ストップウォッチ</h1>
      <div style={{fontSize: '100px'}}>
        <span>{hours}</span>:<span>{minutes}</span>:<span>{seconds}</span>
      </div>
      <p>{isRunning ? '計測中...' : '一時停止中'}</p>
      <button onClick={start}>スタート</button>
      <button onClick={pause}>一時停止</button>
      <button onClick={reset}>リセット</button>
    </div>
  );
}
```

```App.jsx
import { MyStopwatch } from './MyStopwatch'

export default function App() {
  return (
    <div>
      <MyStopwatch />
    </div>
  );
}

```
GitHub Desktopとターミナルを使ってGitの操作の比較（初学者歓迎）

#概要
私自身GitHub Desktopを使用してGitの仕組みに慣れていきました。しかし、実務案件に参加した際に皆さんターミナルで操作をしていてGitHub Desktopを使用していませんでした、、、、

学び始めの方にはGitHub DesktopはGUIで直感的で分かりやすくおすすめです。しかし実際の現場ではターミナルで操作しているのが主流と現役のエンジニアの方に聞きました。

私自身の学びのアウトプットと初学者の方がGitHub Desktopからターミナル操作に移行するの役に立てたらと思い記事を書かせていただきます。

#操作方法の比較
###1.　ローカルリポジトリを作成~firstコミット
＜GitHub Desktop編＞
①GitHub Desktopを起動し写真のAddボタンを押す
②Addボタンの中のAdd Existing Repositoryを押してchooseボタンから管理したいアプリケーションをAdd Repositoryで選択
③.gitディレクトリが作成されアプリケーションが管理される

![スクリーンショット 2022-01-22 7.41.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/fd3d89b5-9c4a-870a-6c50-78654bc4ee20.png)

＜ターミナル編＞
①扱うディレクトリに移動
②git initコマンドを入力。（railsの場合、rails new時に自動で初期設定されるためコマンドを打たなくてもOK）
③.gitディレクトリが作成されアプリケーションが管理される

```
 hoge＿MacBook-Pro % cd practice_with_git
 practice_with_git % git init
```

###2. ローカルリポジトリに記録（add〜first-commit）

＜GitHub Desktop編＞
①commit前にaddしたいファイルにチェック。
(以下画像をみるとわかりやすいかと思います)

![スクリーンショット 2022-01-22 12.18.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/03cc3cb6-d28b-d06f-34ef-0ef6c56d95ac.png)

②コミットメッセージを記載します。書き終えたらCommit to masterボタンを押してローカルリポジトリにpushします
（以下画像をみるとわかりやすいかと思います）

![スクリーンショット 2022-01-22 12.26.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/5423987f-f16b-a419-ca5a-a584cbb8d69b.png)



＜ターミナル編＞

①commit前にaddコマンドを入力します。（今回は全ファイル選択を想定しgit add .コマンドを使っています）
②コミットメッセージを記載します。書き終えたらローカルリポジトリにpushします

```
practice_with_git % git add .
practice_with_git % git commit -m "first_commit"
```

###3. リモートリポジトリを作成&ローカルリポジトリの内容をプッシュ
＜GitHub Desktop編＞

①Publish repositoryボタンを押すとリモートリポジトリ作成とローカルリポジトリの内容をプッシュを同時にしてくれます。

![スクリーンショット 2022-01-22 12.36.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/d0ccb2bd-721c-d476-ffbd-c52479cd4db5.png)

＜ターミナル編＞

【やり方】
①GitHubへサインインし、Repositories横の"New"をクリック
②リポジトリ名を入力し、公開するかしないかを選択します。その後、Create repositoryをクリックします。
③以下コマンドを入力リモートリポジトリとやりとりができます。

```
practice_with_git % git remote add origin http://GitHub.com/ご自身のGitHubID/アプリ名.git
practice_with_git % git push -u origin master
```

###3. ブランチ切り替え

＜GitHub Desktop編＞
①NEW Branchボタンを押して新しいブランチ作成
![スクリーンショット 2022-01-22 17.44.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/632ed4b3-f662-57b3-375e-8c89a26b4a47.png)

②ブランチ名を決めてCreate Branchを押す

![スクリーンショット 2022-01-22 16.21.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/83769ee9-7088-40ee-962e-4b084a18cc48.png)

③Publish　branchボタンを押してリモートリポジトリに置き場所を作る
![スクリーンショット 2022-01-22 16.22.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1788321/8d8115fd-99c1-f017-1712-de7f531a9dc8.png)


＜ターミナル編＞

```
practice_with_git % git switch -c "ブランチ名"
```
git switchボタンでブランチの切り替えができ、-cのオプションを付けると、ブランチ作成後そのブランチへ移動します。
現在のブランチ名を確認したい時は、以下のコマンドを入力します。

```
practice_with_git % git branch
*master        #現在のブランチに*がつく
 practice_with_git
 hoge_branch
```

#最後に

僕自身もターミナルでの操作に慣れましたが、最初はいまいちGitHub Desktopでやってる動きと、ターミナルでの操作の違いに慣れませんでした、、
GitHub Desktopで学んだけど「ターミナルだと分かんない！」って方のお役に立てたらと思い書かせていただきました。
ご覧頂きありがとうございましたm(_ _)m
dartでN-gramのMapをreturnする関数

# dartでN-gramのMapをreturnする関数
https://qiita.com/oukayuka/items/d3cee72501a55e8be44a

↑の記事のtokenMapをdartでreturnする関数です

```dart
Map<String,dynamic> tokenToSearch({ required String searchTerm }) {
  final int nGramIndex = 2;
  final int length = searchTerm.length;
  Map<String,dynamic> tokenToSearch = {};
  if (length < nGramIndex) {
    tokenToSearch[searchTerm] = true;
  } else {
    int termIndex = 0;
    for (int i = 0; i < length - nGramIndex + 1; i++) {
      final String key = searchTerm.substring(termIndex,termIndex + nGramIndex);
      tokenToSearch[key] = true;
      termIndex++;
    }
  }
  return tokenToSearch;
}
```
見積もりの最適解ってなんだろうと思ったので整理してみた。

#見積もりの最適解
最近自社の事業部側から開発チームに対して見積もり依頼が多く、肝心の実装にリソースを割きづらい状況が生まれてきていたので、見積もりについて整理してみた。
___状況：チームはアジャイルで周っていて、自社の開発チームで、見積もり提出先も自社の事業側。___

##結論：
見積もりの方法は使い分けよう。
というのも、見積もりを依頼している目的が依頼ごとに異なるからである。
また、開発チームが目的を解釈して、適切な見積もり方法を決めて、提出したとしても相手も理解していないと後々トラブルになると思うので、下記の手順で実施するとよさそう
・見積もりの目的を聞く
・実施する見積もり方法のメリット、デメリット、提出する見積もりはどのような性質かを説明する。
・合意の上で見積もり実施、提出

##・見積もりの目的について：
___(ほんとはこちらで想像するものではなく、見積もり依頼が来た時に依頼者に確認するべき)___
今までの経験上、以下のものが思い浮かぶ。
・会社の方針上ほぼ実装することが決まっている機能で予算を確保するのに必要。
・いくつかある機能のなかで、工数の大小も実施判断の材料にしたい。

上記二つだけでも利用する目的の違いから求められるものが違うことがわかる。
1つ目に関しては、予算も絡んでくることから正確性が求められる。その場合、時間を要したとしても正確性のある見積もり方法をとるべき。
2つめに関しては、大小を比較するために使うので、相対的に把握できることを求められてる。

このように、見積もりの目的に応じて求められるものが違うのでその都度最適な方法を選択するのが良い。
そうすれば、無駄にリソースを割いてものすごく正確な見積もりをだそうとすることもないし、逆に大きなプロジェクトなのにざっくりとした見積もりを出して、後々追加を許容できないほど予算が足りない、ということも避けられると思います。


##・工数見積もり方法：
___以下は、少し調べて自分のいるチームに合いそうな見積もりの方法を箇条書き___
・プランニングポーカー
チームでタスクやユーザーストーリーごとにポイントを決める。
メリット：bottom upより時間がかからない。チームでやるので見積もり時点で課題点などを共有できる。
デメリット：慣れていないシステムや新規の大きいプロジェクトの場合に誤差が大きくなる。

・ボトムアップ
作業を明確に細分化してその作業に対する工数を積み上げていく。
メリット：タスクを細分化しているので誤差が少ない。
デメリット：時間がかかる

・類推見積もり
過去の類似の事例の実績値をもとに見積もる。
メリット：過去の実績に基づいているので誤差は少ないのが期待できる。
デメリット:どれくらい類似しているかで誤差が変わってくる。

自分のいるチームは、ADOに過去のUSやそれに対するタスクと実績があるのでそれを参照できる。
また現在の環境を考慮して算出した見積もり￥に係数(0.75 ~ 2)をかけてもよいかと。
0.75の例:過去に対応したものとものすごく類似していて、また過去の実装担当者と今回の実装担当者が同じ。
2の例：過去に対応したものが少しだけ類似していて、また過去の実装担当者がいなく、過去の実装担当者と今回の実装担当者を比較した際に過去の実装担当者が誰もが優秀だと思う方だった。

##・最後に：
会社の文化や状況によって適切な方法は変わると思いますので、手順、特に事業側と見積もりの性質については合意することが大事だと思います。
また正確で短い時間で出せる、こんな素敵でみんながハッピーになるような方法がいつか出てくることを願う。
Raspberry Pi 3 Model BにSDIO接続のSDカードアダプタを追加

# 概要
Raspberry Pi 3 Model BにSDIO接続でSDカードアダプタを追加する。
SDIOで接続できるSDカードアダプタを手に入れたので改めてSDカードアダプタの追加をリベンジ。
前の記事は以下。
https://qiita.com/tetsuoMikami/items/4d1876a0f6ba1e92a258

使用したのはサンハヤトのCK-35

#準備
## 接続
Raspberry Piのピンアサインは以下で調べた。
https://pinout.xyz/pinout/sdio

SDカードのピンアサインは以下で調べた。
http://nc30mtd.oops.jp/blog/2015/04/sd.html

| |SDモードの機能|Raspberry Piのピン番号|
|-|-|-|
|DATA3|1|13|
|CMD|2|16|
|Ground|3|39|
|VDD|4|1|
|CLK|5|15|
|Ground|6|39|
|DATA0|7|18|
|DATA1|8|22|
|DATA2|9|37|

## 接続後の様子
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/c23f4e37-ec87-d21e-eb3a-c8e70689f06e.png)

## 設定の変更
ここを参考にした
https://tshell.hatenablog.com/entry/2019/09/04/200850

[設定をオーバーライドするdtsをここから入手](https://github.com/raspberrypi/linux/blob/rpi-4.9.y/arch/arm/boot/dts/overlays/sdio-overlay.dts)

設定を追加

```
sudo dtc -@ -I dts -O dtb -o sdio22.dtbo sdio22-overlay.dts
sudo mv sdio22.dtbo /boot/overlays/
```

/boot/config.txtの最終行に以下を追加する。

```
dtoverlay=sdio22,poll_once=off,bus_width=1,sdio_overclock=50
```

その後、再起動する。

# 認識されているか確認
## デバイスが検出されているか

```
pi@raspberrypi:~ $ sudo dmesg | grep mmc2
[    3.717449] mmc2: host does not support reading read-only switch, assuming write-enable
[    3.719378] mmc2: new high speed SDXC card at address 59b4
[    3.720505] mmcblk2: mmc2:59b4 SPCC  58.9 GiB
```

## 速度確認
```
pi@raspberrypi:~ $ time dd if=/dev/random of=/media/pi/9C33-6BBD/out bs=4k count=23040 conv=fdatasync
23040+0 レコード入力
23040+0 レコード出力
94371840 bytes (94 MB, 90 MiB) copied, 20.5605 s, 4.6 MB/s

real	0m20.576s
user	0m0.002s
sys	    0m4.087s
```

遅い・・・

# バス幅を4bitに変更(2022/01/23追記)
あまりにも遅いので原因を調べたら、その1つとしてバス幅が1bitになっていた。つまりDATA0しか使っていない状態だった。
そこで以下の対策を行う。

/boot/config.txtの最終行に追加した設定を変更し、「bus_width=1,」を削除する。つまり以下の状態。

```
dtoverlay=sdio22,poll_once=off,sdio_overclock=50
```

## 速度確認
2倍近くになったけど、まだ遅い。

```
pi@raspberrypi:~ $ time sudo dd if=/dev/random of=/media/pi/9C33-6BBD/out1 bs=4k count=23040 conv=fdatasync
23040+0 レコード入力
23040+0 レコード出力
94371840 bytes (94 MB, 90 MiB) copied, 10.947 s, 8.6 MB/s

real	0m11.001s
user	0m0.065s
sys	0m4.091s
```

# 追加で行いたいこと
UHSでの接続を見たいと思っている。但し、ハードウェアが対応しているのかは未確認。

# 参考
https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/overlays/README
ビッグデータとデータベース!データのインポートに関する

データベースはデータを保存するための倉庫です。毎日データベースを使用してデータを保存しており、ゆえに、データをインポートすることは避けられません。この記事は主にデータのインポートに関連するヒントを共有して、お役に立てば幸いです。
##SQLファイルをインポートする
sqlファイルは一般的にinsert文です。mysqlコマンドラインまたはsourceを使用してSQLファイルを実行できます。例えば、mysql -uroot -pxxx testdb < /tmp/testdb.sql 。コマンドラインからSQLファイルを実行することをお勧めします。特に大きなSQLファイルの場合は、コマンドラインの実行速度が速くなります。
![22040986_l.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482909/9cc78d4f-27ae-4313-da8c-d4a6a8e61bd1.jpeg)
データをインポート前に、まず、元の表にデータがあるかどうかを確認してください。インクリメンタルインポートの場合、自己増加IDは指定しないほうがいいです。一意のインデックスがあるフィールドも注意してください。元の表を空にしてインポートする場合は、事前にバックアップしておくとよいでしょう。
![4380238_l.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482909/46988ccf-b481-be5f-7e26-edefe0baa1b3.jpeg)
##ExcelまたはCSVファイルのインポート
sqlファイルよりもExcelファイルのインポートが複雑になります。sqlファイルのinsert文はデータベースで直接認識できます。Excelファイルをインポートするには他のツールを利用する方が便利になります。例えば、Navicat など。
![navicat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482909/3baa95a8-08e0-e344-e9e5-528923f3d489.png)
##ScrapeStorm
ScrapeStormは、Excel、csv、html、txt、データベース、ローカルなどさまざまなエクスポート方法を提供します。抽出されたデータを直接データベースにエクスポートできます。MySQL、MongoDB、SQL Server、PostgreSQLおよびクラウドストレージ(Googleスプレッドシート)に適応します。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482909/80ac5a5e-b437-8c08-36c5-389a4fb89053.png)