OmniAICreator/Qiita-1.07M huggingface dataset:
Big Surへのアップデートでエラー [An error occurred preparing the software update]

CatalinaからBig Surへのアップデートに丸１日の作業を要しました。
原因は、インストール時のディスクの空き容量不足によるインストールの失敗です。これにより、Catalinaに戻すこともBig Surのインストールを行うこともできなくなりました。再起動時にBig Surのインストールが始まり、途中で[An error occurred preparing the software update]という以下の画像のエラーが発生し、OSのインストールが中断します。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256060/0d2f05eb-75c2-45a7-69da-f26fe3ded6d2.png)

以下に挙げる参考記事と同じ現象だと思います。以下の記事の方法はディスクを初期化してOSを一から再インストールするというようなものがほとんどであり、以前のデータが失われてしまいます。電源起動時にoptionを押し、元のOSの状態に戻す方法は自分には不可能でした。電源起動時にoptionを押すと、Big Surのインストールメディアのみが起動デバイスとして選択可能であり、それを選択した際には再びインストールが始まり、結局、上のエラーが発生しました。
**参考記事**
https://discussions.apple.com/thread/252038616
https://ibhuman.com/an-error-occurred-preparing-the-software-update-macbook-pro/

データのバックアップを直前で取っておらず、何とかデータを復活させたいと思いました。
結果、データを失うことなく、OSをアップデートすることができたのでその方法を以下に示したいと思います。

## 経緯
1. Big Surのイメージのダウンロード（12GB程度の容量なので、ダウンロードするのにもかなり時間がかかります。）
2. 指示に従いBiG Surのインストール
3. 「30分ほどかかる」と出ますが、残り８分程度のところでエラーが出て、止まってしまい「An error occurred preparing the software update」のエラーが発生します。
5. アップルのサポートに問い合わせてみると、外付けHDDにOSをインストールして、外付けHDDにインストールされたOSを起動し、そこから元のデータを復元することができるということでした。

## 具体的な解決方法
1. 電源ボタンで強制的にシャットダウンし、その後電源をつけると同時にCommand+Option+Shift+Rを押し続けます。これにより、Disk UtilityやOSの再インストールが可能な画面に行くことができます。
2. 「Machintosh HD」にOSを再インストールすると、いままでのデータがすべて消えてしまい、初期状態でOSが再インストールされるので注意が必要です。ここで、外付けHDDをUSBケーブルなどで接続し、その後Disk Utilityを選択し、外付けHDDが認識されていることを確認します。外付けHDDは５００GB程度より大きいもので中身が空か、消えても問題のないものを用います。
3. 外付けHDDが認識されていることが確認されたら、このHDDをOSをインストールするためにフォーマットします。外付けHDDを選択し、「削除」ボタンを押して、名前は自由に決め、フォーマット方式を「APSF」を選択します。ほかにも選択するところがあったように思いますが、デフォルトのままにします。これで、OSをインストールするためのフォーマットが完了します。
4. Disk Utilityを終了し、「OSを再インストール」に行きます。ここで、インストールするデバイスを先ほどフォーマットした外付けHDDを選択します。これにより、外付けHDDにOS（自分の場合は購入時のMojave）がインストールされました。インストールには３０分から１時間ほどかかります。そして、外付けHDDにインストールされたOSが起動します。
5. Finderを開くと「Machintosh HD」や「Machintosh HD-Data」などのデバイスが 以下の画像のように見えると思います。そして、Machintosh HD-Dataの中にはアップデートしようとする前のデータが入っていると思います。このデータを外付けHDDの中にバックアップしておきます。ここで心配な方はクラウドなどに保存しておくといいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256060/d3b7e45e-3201-eebb-b650-9faae0788bde.png)

6. そして、必要なデータのバックアップが取れた後には、再起動を行い、今度は「Command+Option+R」を押します。前回起動したのとは違い、Shiftは押しません。Shiftを押すと、工場出荷時のOSができる状態になり、Shiftを押さないと、最新のOSがインストールできる状態になるそうです。
7. 外付けHDDに必要なデータのバックアップが完了したので、「Machintosh HD」と、「Machintosh HD - Data」の中身をDisk Utilityから削除します。これにより、使用量がほぼ０になったと思います。
8. ひとつ前の画面に戻り、Big Surをインストールします。今回は外付けHDDではなく、Machintosh HDを選択します。これにより、自分のMacBookにBig Surがインストールされます。
9. バックアップしてあったデータをBig Surに戻します。これでOSのインストールとデータの移行が完了しました。

## OSをアップデートする前にしておけばよかったこと
#### データのバックアップ
OSをアップデートする際には何がるかわからないので、一応、タイムマシーンなどで、フルバックアップを取っておいたほうがいいと思います。
#### 空き容量の確保
アップデートする前には25GBほど空き容量がありましたが、50GBくらいあったほうが良いのではないかと思いました。SSDが128GBしかないMacだったのでかなりつらいところではありますが…

##  終わりに
ディスクの容量がない場合は警告をだして、インストールをできないようにする、などのApple側の配慮があればよいなとも少し思いました。ディスクの容量が足りない状況でインストールをしてしまうというのは結構ありがちな状況な気がするので、同じ状況になった人の役に立てれば幸いです。何かわからないことや気になる点がありましたら、コメントか[twitter](https://twitter.com/masato199791)までお知らせください。
OpenStack CLI 備忘

# インスタンス作成

```bash
openstack server create \
  --image fd70f9ca-4577-4fd8-baaf-ecd2da185487 \
  --flavor 2ce31fef-68b6-4953-81bc-b1c79d22f1b0 \
  --network 0e4fe3c8-b09e-4f98-ba2d-af5975a833a5 \
  --key-name key01 \
  test
```

# floating IPの確保

```
openstack floating ip create public
```

# floating IPの付与

```bash
openstack server add floating ip d2073786-5965-46f5-ba91-456da59cda2c 172.16.70.18
```

# イメージスナップショットの作成

```bash
openstack server image create \
  --name ubuntu-2004-kube-v1.19.7 \
  d2073786-5965-46f5-ba91-456da59cda2c
```

# イメージをpublicに変更

```bash
openstack image set --public 66387e93-633f-4c49-9c3b-a578ac6d412b
```

# イメージ登録

```bash
openstack image create \
  --disk-format qcow2 \
  --container-format bare \
  --public \
  --file ./ubuntu-2004-kube-v1.18.15 \
  ubuntu-2004-kube-v1.18.15
```

# イメージのダウンロード

```bash
openstack image save 9d39e405-9c3f-4f1b-9331-ff4e56b0bbbb --file large-snapshot.qcow2
```

# ボリュームのイメージ化

```bash
openstack image create --volume 194a1b89-d263-4c1b-bde7-7c43c8180b8f --force --disk-format qcow2 image01
```

**使用中のボリュームをイメージ化する場合、`--force`の指定が必要**

# フレーバーの作成

```bash
openstack flavor create m1.tiny --ram 512 --disk 0 --vcpus 1
```

# ネットワーク、サブネットの作成

```bash
openstack network create private-net
openstack subnet create private-subnet --network private-net \
  --subnet-range 10.0.0.0/24
```

# 仮想ルーターの作成とネットワークの接続

```bash
openstack router create admin-router
openstack router set admin-router --external-gateway public
openstack router add subnet admin-router private-subnet
```

# ネットワークポートの作成

```bash
openstack port create \
  --network 4507ad6f-361d-4b4e-bc20-2327dca81756 \
  --fixed-ip subnet=e87d8830-c075-4359-9907-182d7d17fadd,ip-address=10.0.0.21 \
  bootstrap
```

# `default`セキュリティグループにSSHとICMPを許可するルールを追加

```bash
openstack security group rule create default \
  --protocol tcp --dst-port 22:22 --remote-ip 0.0.0.0/0
openstack security group rule create default \
  --protocol icmp --remote-ip 0.0.0.0/0
```

# キーペアの登録

```bash
openstack keypair create --public-key ~/.ssh/id_rsa.pub admin-key
```
個人開発アプリをhttps化する際につまづいたところ

環境
rails 5.2.4
unicorn
nginx
EC2でIPアドレスを取得済み
ROUTE53でドメイン取得済み
個人開発したアプリをhttps化したい方向け

参考記事
【初心者向け】AWSのサービスを使ってWebサーバーをHTTPS化する
https://dev.classmethod.jp/articles/aws-web-server-https-for-beginner/

上記の記事を参考にしてhttps化をしようと試みたところ、難しいところがあったので参考になればと思い書き留めておく。つまづいたところだけ書くので基本は上記記事を参考にしてください。

##　個人開発したアプリをhttps化したい。
　あるていどアプリが形にはなったのだが、友人に使用してもらうにはhttps化しないと自信をもってつかってください！と言いにくいし、不完全だと感じていた。同じような思いをもっている駆け出しエンジニアの方も多いのではないだろうか
　調べたところ、AWSのEC2とROUTE53を使用している場合は、ACMからセキュリティ証明書を取得し（取得自体は無料）、ロードバランサーを適用するのが簡単なようだった。上記の記事を参考にして進めてみた。

## ①AWSコンソールでは、最初に右上のリージョンを確認しよう。
　最初にAWSコンソールにログインしたところ、us-east-1になっていたのだがそこに気づかないまま進めてしまった。リージョンを起動しているEC2インスタンスと同じにしましょう。
　![スクリーンショット 2021-02-08 17.38.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636210/b566c0ad-0861-1dfb-de5d-9a329b9cf7e0.png)

## ②証明書を取得する際にはドメイン名を正しく入力しよう。
　何を当たり前のことを言っているのかと思うんですが、私の場合``*.ドメイン名``で証明書を取得しましたが、ワイルドカードを使う必要はなく、``ドメイン名``そのままでACMでセキュリティ証明書を取得すればいいです。
　![スクリーンショット 2021-02-08 17.36.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636210/20bc372d-f58b-1330-3222-56466a2183fb.png)

## ③ROUTE53でホストゾーンの設定からALBを設定する。
　1.ホストゾーンの詳細からAタイプにチェックを入れ、レコードを編集する。
![スクリーンショット 2021-02-08 17.50.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636210/266b92f6-cb98-a016-9c4a-41edfd9cf605.png)
　2.値/トラフィックのルーティング先を変更する。おそらく変更前はIPアドレスになっているのではないでしょうか。プルダウンを正しく選択していけば、リージョンを選択した後に選択できるはずです。
　![スクリーンショット 2021-02-08 18.00.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636210/5fdfc527-6e26-52c5-187f-cf8ac0ecb371.png)
　もし、うまくいかない場合はセキュリティグループ、ターゲットグループの設定にミスがあるかもしれません。すでにアプリをAWSにデプロイできているならば、nginxの設定などはいじらなくてもいいようです。ただアプリの構成などでこのへんは変わってくるかもしれません。
[OpenCV] マウスクリックで画像からROIを切り取る [2]

# はじめに
OpenCVを利用して、マウスクリックイベントを練習してみました。

#やりたいこと
マウスでBounding Boxを描き、その領域を切り取りたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/7c889e5d-0223-8903-2d5a-eb6d1679610f.png)

# やり方の説明

OpenCVのcv2.selectROI()を使います。
Raw Image(img_raw)に対し、下記の命令を実行すると、Bounding Boxの座標がROI変数に格納されます。

```Python
ROI = cv2.selectROI('Select ROIs', img_raw, fromCenter = False, showCrosshair = False)

print('ROI',ROI)

結果
ROI (115, 99, 275, 336)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/e3a9cd0a-6485-bd9a-c633-60b3cdd988ea.png)

ROIに格納された座標を利用して、Raw ImageからCropします。

```Python
x1 = ROI[0]
y1 = ROI[1]
x2 = ROI[2]
y2 = ROI[3]

#Crop Image
img_crop = img_raw[int(y1):int(y1+y2),int(x1):int(x1+x2)]

```

#実行結果

![ROI_bounding_box.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/b1e9aea1-7cf9-41b8-71dd-79de7cdd0cab.gif)

# コード

```Python
import cv2
import numpy as np

img_raw = cv2.imread('./images/lena.png')

#select ROIs function
ROI = cv2.selectROI('Select ROIs', img_raw, fromCenter = False, showCrosshair = False)


x1 = ROI[0]
y1 = ROI[1]
x2 = ROI[2]
y2 = ROI[3]

print('ROI', ROI)

#Crop Image
img_crop = img_raw[int(y1):int(y1+y2),int(x1):int(x1+x2)]

cv2.imshow("crop", img_crop)

cv2.waitKey(0)


```

#参考資料
1. [[OpenCV] マウスクリックで画像からROIを切り取る [1]](https://qiita.com/kotai2003/items/6c286132d36a620bc975)
2. [Multiple ROISを得る方法はこちらのリンクをご参照ください。](https://blog.electroica.com/select-roi-or-multiple-rois-bounding-box-in-opencv-python/)
3. [How to select a bounding box ( ROI ) in OpenCV (C++/Python) ?](https://learnopencv.com/how-to-select-a-bounding-box-roi-in-opencv-cpp-python/)
DelayedJobとSidekiq

シュッとメモる。

## 共通点

- いずれもActiveJobで作られたjobの永続化に使われる。
- jobを実行するためのプロセスを別に実行する必要がある。

## 違い

- DelayedJobはRDB, SidekiqはRedisを永続化に用いる。


## その他メモ

- ActiveJobのspecは、`perform_now`でテストする。
- ActiveJobをfeture specで実行したい時には、`perform_enqueued_job`。
西暦と和暦と何年前なのかのリスト生成するjs

# 西暦とそれに対応する和暦、また何年前なのかのリストを生成するJavaScriptの実装

仕事で必要だったので書きました。またどこかで使うかも知れないのでメモです。

## 実装

```JavaScript
const FINAL_YEAR = 1800

const createOneYear = (thisYear) => {
  return (index) => {
    const date = new Date(thisYear - index, 11, 31)
    const japaneseYear = (new Intl
      .DateTimeFormat('ja-JP-u-ca-japanese', { era: 'long', year:'numeric'  })
      .format(date))
    const yearsAgo = index === 0 ? '今年' : `${index}年前`
    return { ad: `西暦${date.getFullYear()}年`,
             japaneseYear: `${japaneseYear}年`,
             yearsAgo: `${yearsAgo}` }
  }
}

const createYears = () => {
  const thisYear = (new Date()).getFullYear()
  const years = [...Array(thisYear - FINAL_YEAR).keys()].map(createOneYear(thisYear))
  return years
}

console.log(createYears())
```

コンソールには、

```json
[
  {
    "ad": "西暦2021年",
    "japaneseYear": "令和3年年",
    "yearsAgo": "今年"
  },
  {
    "ad": "西暦2020年",
    "japaneseYear": "令和2年年",
    "yearsAgo": "1年前"
  },
  {
    "ad": "西暦2019年",
    "japaneseYear": "令和元年年",
    "yearsAgo": "2年前"
  },
  {
    "ad": "西暦2018年",
    "japaneseYear": "平成30年年",
    "yearsAgo": "3年前"
  },
  {
    "ad": "西暦2017年",
    "japaneseYear": "平成29年年",
    "yearsAgo": "4年前"
  },
...
```

と表示されているはず。

意外とミソでハマりどころなのが以下の箇所で、`11, 31`と12月31日を指定しています。(JavaScriptのDate型なので、0が1月、11が12月という仕様です。)

```JavaScript
    const date = new Date(thisYear - index, 11, 31)
```

ここの指定を1月1日としてしまうと、それぞれの年号の元年が表示されず、例えば、令和元年→平成31年と表示されてしまいます。なぜなら、2019年1月1日は、まだ令和に入っていないからですね。逆に、元年の表示をさせたくない場合は、(平成31年の表記にしたい場合は)1月1日を指定すれば良いことになります。


和暦、まだまだ、いろんなところで使われていますね。。。

## 参考文献

* [日付から元号・和暦と曜日を取得 - JavaScriptの学習・参考リファレンス/ドキュメント](https://javascript-reference.org/tips/wareki-weekday/)
* [Intl.DateTimeFormat - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)
* [令和元年🎉 JavaScript International Date フォーマットで和暦を表示させるには （再） - Qiita](https://qiita.com/girlie_mac/items/484ca063cf547b4a61fd)
Open3D 0.12.0 for Python (Windows) 入門 ～ 1. Numpyを用いたポイントクラウドデータの読み込みから表示まで

以前に比べ、ポイントクラウドもスマートフォン等で手軽にスキャンできるようになったが、本格的にポイントクラウドを活用する場合、ノイズも多く含まれているため、データをうまく補正する作業が必要となります。

補正処理するためのツールとしては、[MeshLab](https://www.meshlab.net/) などが代表的であるが、何かのアプリケーションの一部として処理したい場合や、独自のアルゴリズムで補正処理したい場合には、MIT ライセンスでもある Open3D ライブラリの活用はとても有効だと思います。現時点での最新バージョンは、 0.12.0 ですが、[TensorFlow](https://www.tensorflow.org/) や　[PyTorch](https://pytorch.org/) 用の [Open3D-ML](https://github.com/intel-isl/Open3D-ML) といったオプション等も開発され、今後がますます楽しみです。但し、Open3D-ML を使いたい場合は自分でビルドする必要がありますが、 Linux 以外の環境では、ビルドにかなり苦労するため、本記事は基本機能のみの Open3D で行います。

Open3D のバージョンは、0.12.0 (古いバージョンだと書き方が異なるので注意)を 前提としています。

### 1. Open3D 公式サイト: http://www.open3d.org/

- 実行環境: Windows 10 , Python 3.7 ( [Miniforge](https://github.com/conda-forge/miniforge) ※ Anaconda は、リポジトリの商用利用規約が変更されたため今後は Miniforge で Python 仮想環境をつくることをお勧めします。ちなみに、Mac の [M1 チップに最適化された TensorFlow](https://github.com/apple/tensorflow_macos) を使う場合なども、Miniforge を使うため、今後 Miniforge のシェアも増えるのではないかと思います。
- 3.8 以降も動作するが、Open3D 以外のライブラリの中には、まだ 3.7 以外対応していないものが多い為、3.7ではじめるのが無難です。

### 2. ソースコード: https://github.com/intel-isl/Open3D 

  - Open3D は、C++ など Python 以外でも扱えるが、Python とサポートしている関数名が
  微妙に異なる部分も多い。そのため、example の中の [Pythonコード](https://github.com/intel-isl/Open3D/tree/master/examples/python) は、とても参考になります。
  - [Google Colaboratory](https://colab.research.google.com/) でも試すことはできるが、レンダリング等で一部制約があるため、とりあえずすぐに行いたい場合は、ローカル環境で行うほうが Open3D の入門としては苦労がないように思います。

### 3. インストール方法:

- conda create -n open3d python=3.7 のようにして、Open3D 専用の仮想環境を準備します。
- conda activate open3d
- conda install -c open3d-admin open3d

### 4. PCD 形式のポイントクラウドの読み込み

とりあえず、ポイントクラウドの標準的なフォーマットである [PCD](https://pcl.readthedocs.io/projects/tutorials/en/latest/pcd_file_format.html) ファイルとして、Open3D の example 内にあるテストデータを読み込む場合は、次のようになります。

```
pcd0 = o3d.io.read_point_cloud("../test_data/fragment.pcd")
```

### 5. テスト用ポイントクラウドの読み込み( NumPy を使用する方法について)

さきほどの例は PCD フォーマットの場合ですが、実践的には、独自にスマホでポイントクラウドをスキャンするアプリを開発した場合など、PCD 形式での出力が難しい場合があります。そんなとき、NumPy を用いた読み込み方法を知っておくと様々なフォーマットに柔軟に対応できるため、ここでその一例を紹介します。

以下は、float32 形式で、x,y,zの座標値が float32 のバイナリで作られたファイルから Open3D で扱えるようにするための例です。とりあえず、NumPy で取り込むのがベストです。取り込む際は、例のように、データタイプも指定し簡単にパースすることができます。取り込んだあと、reshape している理由については後ほど説明します。

```
import numpy as np

fn = 'ファイル名'
p0 = (np.fromfile(fn, dtype='f')).reshape(-1, 3)
```

ちなみに、dtype の f は float32(4バイト)の意味であるが, d と指定した場合は、float64(8バイト)毎にパースされます。また、取り込むデータがビックエンディアンである場合は、dtype='>f' のようにします。そのほか、区切り文字の指定など、たいていのデータは NumPy で処理できます。

NumPy 形式で取り込んだあとは、Open3D のインスタンスを作り、次のようにセットします。

```
pcd0 = o3d.geometry.PointCloud()
pcd0.points = o3d.utility.Vector3dVector(p0[~np.isnan(p0).any(axis=1)])
```

Open3D では、ポイントクラウドは [Vector3d](http://www.open3d.org/docs/release/python_api/open3d.utility.Vector3dVector.html#open3d.utility.Vector3dVector) 形式である必要があるため、事前に reshape(-1,3) を行い、それを、utility を使って変換したものをセットします。なお、上記の例では、p0 の中に、nan が含まれている場合があったため x,y,z いずれかが nan であるデータは除外した上で取り込んでいます。

最後に、これを表示したい場合は、次のように記述する。表示したい Open3D オブジェクトを [ ] 内に列挙すると複数のポイントクラウドを重ねて表示することもできます。

```
o3d.visualization.draw_geometries([pcd0])
```

続きは、[次回](https://qiita.com/bit2zero/items/32ad5e6024c735847fa4)。
Cluster API: v0.3.14 変更内容

## はじめに

ここでは Cluster API v0.3.14 の変更内容についてまとめています。

- https://github.com/kubernetes-sigs/cluster-api/releases/tag/v0.3.14

Cluster API は複数の Kubernetes クラスタのプロビジョニングやアップグレード、オペレーションをするための宣言的な API とツールを提供する SIG Cluster Lifecycle のサブプロジェクトです。

## 🐛 バグ修正

- ClusterResourceSet が Secret/ConfigMap の TypeMeta を取得しないのを修正 ([#4142](https://github.com/kubernetes-sigs/cluster-api/pull/4142))
    - :memo: controller-runtime の変更の影響でただしく機能しなくなったようです
    - :memo: このバグが致命的だと判断してパッチリリースを出したのだと思いますが、この機能は実験的な機能なのでこれだけでリリースしなくてもいいんじゃないかと思ったりします

## 📖 ドキュメンテーション

- `cluster describe` コマンドのドキュメントを追加 ([#4123](https://github.com/kubernetes-sigs/cluster-api/pull/4123))

## 🌱 そのほか

- CVE-2020-26297 の修正のため、mdbook を 0.4.5 に更新 ([#4144](https://github.com/kubernetes-sigs/cluster-api/pull/4144))
- `gcr.io/kubernetes-ci-images` から `gcr.io/k8s-staging-ci-images` に移行 ([#4143](https://github.com/kubernetes-sigs/cluster-api/pull/4143))
Huawei Adsの実装方法－広告用識別子（OAID）編

# Huawei Adsの実装方法－広告用識別子（OAID）編

OAIDとパーソナライズド広告制限はAdvertisingIdClient.getAdvertisingIdInfo()で取得できます。ただ、メインスレッド以外で実行しなければなりません。

```kotlin
fun getAdvertisingIdInfo(context: Context) {
    Single.create<AdvertisingIdClient.Info>{ emitter ->
        val info = AdvertisingIdClient.getAdvertisingIdInfo(context)
        emitter.onSuccess(info)
    }.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({ info ->
            // OAID = info.id
            // パーソナライズド広告制限 = info.isLimitAdTrackingEnabled
        },{
            it.printStackTrace()
        })
}
```

# Huawei Adsシリーズ
- [Huawei Adsの機能のまとめ](https://qiita.com/Rei_2020/items/87804f2057d4b143fc12)
- [Huawei Adsの実装方法－準備編](https://qiita.com/Rei_2020/items/9f9eb35f781051eba811)
- [Huawei Adsの実装方法－広告用識別子（OAID）編](https://qiita.com/Rei_2020/items/f5446a2bbbb4d5d3df67)
- [Huawei Adsの実装方法－インストールリファラー編](https://qiita.com/Rei_2020/items/977eabb3a514ba5c2476)
- [Huawei Adsの実装方法－バナー広告編](https://qiita.com/Rei_2020/items/308ebf626c1423a7cb1f)
- [Huawei Adsの実装方法－ネイティブ広告編](https://qiita.com/Rei_2020/items/f60976c23c1268261d5f)
- [Huawei Adsの実装方法－リワード広告編](https://qiita.com/Rei_2020/items/06744db6572c1603b0bd)
- [Huawei Adsの実装方法－インタースティシャル広告編](https://qiita.com/Rei_2020/items/3c9d9a19861a2d139737)
- [Huawei Adsの実装方法－スプラッシュ広告編](https://qiita.com/Rei_2020/items/5a138945d7b343602df1)

# GitHub
HMS Ads Kit Demo : [https://github.com/Rei2020GitHub/MyPublicProject/tree/master/AdsDemo](https://github.com/Rei2020GitHub/MyPublicProject/tree/master/AdsDemo)

# 参考
* HMS：[https://developer.huawei.com/consumer/jp/](https://developer.huawei.com/consumer/jp/)
* HMS Ads Kitの紹介：[https://developer.huawei.com/consumer/jp/hms/huawei-adskit/](https://developer.huawei.com/consumer/jp/hms/huawei-adskit/)
* HMS Ads Kitのドキュメント：[https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/publisher-service-introduction-0000001070671805](https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/publisher-service-introduction-0000001070671805)
* HUAWEI Ads Publisher Service：[https://developer.huawei.com/consumer/jp/monetize/](https://developer.huawei.com/consumer/jp/monetize/)
* HUAWEI Ads Publisher Serviceのドキュメント：[https://developer.huawei.com/consumer/jp/doc/distribution/monetize/advantage-0000001051201913](https://developer.huawei.com/consumer/jp/doc/distribution/monetize/advantage-0000001051201913)
* Huawei Developers：[https://forums.developer.huawei.com/forumPortal/en/home](https://forums.developer.huawei.com/forumPortal/en/home)
* Facebook Huawei Developersグループ：[https://www.facebook.com/Huaweidevs/](https://www.facebook.com/Huaweidevs/)
Laravel ファクトリーを利用したシーディング処理まとめ

# Laravel ファクトリーを利用したシーディング処理まとめ
Laravelにて、DBを利用する際、ダミーデータを手軽に用意してくれる機能があります。
以下にまとめます。

## 補足
『PHPフレームワーク Laravel実践開発』 著：掌田津耶乃
の18ページに記載されているSQLを、シーディングとファクトリーを利用して実行するという試みです。

## バージョン
Laravel バージョンは6.x

## 詳細は以下
[シーディング](https://readouble.com/laravel/6.x/ja/seeding.html)
[ファクトリー](https://readouble.com/laravel/6.x/ja/database-testing.html)


## 前提
本には以下の様なSQLを叩いて、ダミーデータを作ってね、と書いてあるが、
自動でそれを行えるようにしたい。

```sql
CREATE TABLE `people` (
    `id` INTEGER PRIMARY KEY AUTOINCREMENT,
    `name` TEXT NOT NULL,
    `mail` TEXT,
    `age` INTEGER
);
```

1. dbファイルを作成します。
今回は、[こちら](https://readouble.com/laravel/6.x/ja/database.html)にも記載されている
`sqlite`で行きます。

```bash
$ cd database
$ sqlite3 database/sdatabase.sqlite
```

2. マイグレーションを生成

```bash
$ php artisan make:migration create_people_table
```

3. おそらく、`database/migrations/20XX_MM_DD_XXXXX_create_people_table.php`というものが出来上がっています。

その中のupメソッドを以下の様に修正。

```php
public function up()
{
    Schema::create('people', function (Blueprint $table) {
　　　　　// ↓ここに必要なカラムや、型を記載してあげる。
        $table->bigIncrements('id')->autoIncrement('id');
        $table->TEXT('name');
        $table->TEXT('mail')->nullable();
        $table->INTEGER('age')->nullable();
        $table->timestamps();
    });
}
```
この様に、function内に
`$table->指定したい型('カラム名');`
のような形にしてあげます。

詳細は、[ここ](https://readouble.com/laravel/6.x/ja/migrations.html)

4. 記載できたら

```bash
php artisan migration
```

すると、テーブルが作成されます。（この時点でデータは空っぽ）

5. シーダーの作成
ダミーデータを入れてくれるシーダーを用意します。

```bash
$ php artisan make:seeder PeopleTableSeeder
```
すると、`/database/seeds/PeopleTableSeeder.php`というファイルが作成されます。
その中身を以下の様に記載

```php
class PeopleTableSeeder extends Seeder
{
    public function run()
    {
        // ２つ目の引数は作成したい件数。10と書けば、10件作成される。
        $users = factory(App\Person::class, 3)->create();
    }
}
```

このrun()メソッドの中に、手動でダミーデータを書くこともできますが、
面倒なので、ファクトリーというダミーデータを生成してくれる機能にお願いすることにします。

※現時点で、Personモデルが無ければ 

```bash
$ php artisan make:model Person
```
で作成しておく。

6. ファクトリー作成

```bash
$ php artisan make:factory PersonFactory
```

これで、`/database/factories/PersonFactory.php`が作成されます。

このファイルの中身を以下のように記載

```php 

// ↓model名を変更
use App\Person;
use Faker\Generator as Faker;
　　　　　　　　// ↓model名を変更
$factory->define(Person::class, function (Faker $faker) {
    return [
// ダミーデータを入れたい「 'カラム名' => $faker->ルール名　」　の形で記載
        'name' => $faker->name,
        'mail' => $faker->unique()->safeEmail,
        'age' => $faker->randomNumber(2),
        'created_at' => $faker->datetime($max = 'now', $timezone = date_default_timezone_get()),
        'updated_at' => $faker->datetime($max = 'now', $timezone = date_default_timezone_get()),
    ];
});

```

`$faker->ルール名`の形で利用できます。
上記例の場合は、
- nameカラムに、ダミーの名前データを入れたいので、`$faker->name`
- ageには、2桁の数字を入れたいので、`$faker->randomNumber(2)`

これらどの様なfakerの種類が有るかは[こちら](https://qiita.com/tosite0345/items/1d47961947a6770053af)に詳しいです。
（まとめありがとうございます！）

7. `/database/seeds/DatabaseSeeder.php`のrunメソッドの中身を以下のように修正

```php
    public function run()
    {
        $this->call(PeopleTableSeeder::class);
    }
```
runの中の1行を変えて下さい。
今回は、`PeopleTableSeeder`を使うので、上記の様に記載。


8. 最後に、

```bash
$ php artisan db:seed
```
して、ダミーデータが作成されているかを確認したら終了です。
Teamsで使いたい/作成したい機能メモ

####(1)発表者ツール
https://idea.tostring.jp/?p=5302

####(2)FAQ Bot
https://cloudsteady.jp/post/8239/

####(3)Teamsに通知を出す（メッセージ）
https://qiita.com/miyay/items/38a21f00768a19737d12
MacOS11(Big Sur)にアップデートしたら、pyenv環境でlzmaのエラーとpyenv installのエラーが発生した 

##環境
- Mac OS 11.0.1
- pyenvでインストールしたPython 3.8.4
- pyenv 1.2.22

##背景と対処
以前までのMacOS10(Catalina)で動いてはずのpyenv環境がMacOS11(Big Sur)にしたら
エラーが発生して動かなくなってしまった。
エラーの内容は以下の通り。

```
Your installed Python is incomplete. Attempting to use lzma compression will result in a RuntimeError.
```
ふむふむ。
なんか知らんが、lzmaが入ってないから怒られていそうだ。
調べて入れたらいけるやろ！
参考記事：[Mac｜Pythonのエラーの解決方法｜Could not import the lzma module](https://blog.novonovo.jp/python/mac%EF%BD%9Cpython%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%AE%E8%A7%A3%E6%B1%BA%E6%96%B9%E6%B3%95%EF%BD%9Ccould-not-import-the-lzma-module/
)
やはり先人がいましたね。感謝感謝！

```
$ brew install xz
$ pyenv uninstall 3.8.4
$ pyenv install 3.8.4
```

とりあえず、xz入れて(Macではこれらしい)、pyenvのPython3.8.4をuninstallして、またPython3.8.4を入れるっと・・・
あれ？？？
pyenvにPython3.8.4が入らない・・・
エラー内容がこちら。

```
$ pyenv install 3.8.4
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.8.4.tar.xz...
-> https://www.python.org/ftp/python/3.8.4/Python-3.8.4.tar.xz
Installing Python-3.8.4...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk

BUILD FAILED (OS X 11.0.1 using python-build 20180424)

...
./Modules/posixmodule.c:8433:15: error: implicit declaration of function 'sendfile' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
        ret = sendfile(in, out, offset, &sbytes, &sf, flags);
              ^
1 error generated.
make: *** [Modules/posixmodule.o] Error 1
make: *** Waiting for unfinished jobs....
1 warning generated.

```
...なんでや。
またしても、調べるか、、、
参考記事：[pyenv installでエラーが出た話（叙事的な話で、結局クリティカルな原因は不明）](https://qiita.com/ukwksk/items/2fd46812bc66ed06e9b0)
こちらも同じようなエラーが起きている。
とりま試してみよう。

```
$ brew doctor

...

Warning: A newer Command Line Tools release is available.
Update them from Software Update in System Preferences or run:
  softwareupdate --all --install --force

If that doesn't show you an update run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install
```

なんかWarningのエラーが出たな。
解消するしかない...
参考記事：[brew doctor で警告が出た！warningとの奮闘記](https://info-wcn.com/brewdoctor-warning01/
)
書いてあるやつ、打ってみるか

```
 $ softwareupdate --all --install --force
 $ sudo rm -rf /Library/Developer/CommandLineTools
 $ sudo xcode-select --install
```
お、なんかやたら時間かかったけどWarningエラーは消えたな

いざ!

```
 $ pyenv install 3.8.4
```

おお！！やっとpyenvに3.8.4が入った！！

## 感想
なんかlzma入れるだけだと思ったら色々エラーでハマってしまった。
なんとか無事に解決できてよかった。
環境変数定義で`brew --prefix`使ってると遅かったと言うくだらない話

## 事の発端はZshの起動が遅いから早くしたかった
起動は約4秒
遅すぎた

## とりあえずよくある改善を試した
`oh-my-zsh`を使っていたので、辞めて`prezto`に変えた。
ここら辺はたくさん記事あるので特に書きません。

この変更で4秒から1.2秒くらいまで一気に早くなった

## 1.2秒でも地味に遅い
計測した結果○○env系が遅かったので[こちらの記事](https://qiita.com/Suzuki09/items/6c27a8a875cf94d981a4)を参考に遅延ロードするようにした。

ここまでで0.8秒くらいまで早くなった。

## 0.8秒でもまだ遅い気がする
原因が分からなかったが、`zshrc`に記述している何かが悪いことまではわかっていた。

## 結論
環境変数定義のために何箇所が記述している`brew --prefix`が遅かった。

厳密に言うと`brew --prefix`だけならそこまででもないが、`brew --prefix python`など何かを指定している部分がかなり遅かった。

とりあえず`brew --prefix`系を全部書き換えたら早くなりました、と言うくだらない話でした。
Webpack+BabelでReactの環境構築時に"Support for the experimental syntax 'jsx' isn't currently enabled"が出たときの解消メモ

#結論
**npmまたはyarnを用いて@babel/preset-reactをinstall**

npm:

```shell
npm install --save-dev @babel/preset-react
```
yarn:

```shell
yarn add -D @babel/preset-react
```
**.baelrc** に以下を記述

```:.babelrc
{
  "presets": ["@babel/preset-env","@babel/preset-react"]
}
```

>引用元 https://babeljs.io/docs/en/#jsx-and-react

#原因
Webpack+BabelでReactの開発環境構築をしている際に、React用のpresetを導入していなかったために起きた。

#メモ
これ単体で検索かけても解決に至らなかったため、公式サイトに情報がないかと探したら一番上に書いてあった.....。
なにかあったら公式ドキュメントを読んだ方が速そう。
計算の誤差をBigDecimalクラスで回避する

# はじめに
Javaを用いて円の面積を求める計算を行ったところ、丸め誤差が発生しました。
BigDecimalクラスを利用することで丸め誤差を回避することができたので、その経験を記事にします。

認識の甘い部分が多々あるかと思います、お気づきの際はご指摘いただけたら幸いでございます！

# まずは結論から
Double型ではなくBigDecimalクラスを利用することで、丸め誤差を回避できました。

# 実行環境
Java 15.0.1

# 意図しない挙動が発生したソースコード（Double型の利用）

円の面積`S`は円周率を`π`, 半径を`r`としたとき、`S =π * r * r`で求めることができます。
ここでは円周率を`3.14`, 半径を`6`として計算を行いました。
`113.04`の結果を想定していたのですが、`113.03999999999999`という結果が得られました。


```Main.java
public class Main {
	public static void main(String[] args) {
		final double pi = 3.14;
		final double radius = 6;
		final double area = pi * radius * radius;
		System.out.println(area);
	}
}
// 113.03999999999999
```

# 意図しない挙動の原因を探る

> ほとんどの10進数の「小数」は、2進数に正しく変換できないから
[小数計算の誤差 0.1 + 0.2 が 0.30000000000000004 になる理由](https://blog.apar.jp/program/8900/)

10進数を計算する場合であっても、コンピュータ上では以下のようなフローで計算が行われます。

1. 10進数を2進数に変換する
2. 2進数で計算を行う
3. 計算結果を10進数に戻す

小数を2進数で表そうとすると、ほとんどの場合において無限に続く数字で表すことになってしまい、
最終的にdouble型（64ビット型浮動小数点数表現）では表現しきれなくなるために、丸め誤差が発生します。

> 丸め誤差とは、ある桁以降を無視することによって生じる誤差のことです。
[丸め誤差、打ち切り誤差、情報落ち、桁落ちの意味と例](https://mathwords.net/marumegosa)

10進数の小数を2進数に変換した場合、どのような数値になるかは[こちら](https://note.cman.jp/convert/bit/)で簡単に測定できます。
ちなみにこちらを利用して`3.14`を2進数に変換すると、`0000 0011 . 0010 0011 1101 0111 0000 1010 0011 1101 0111 0000 1010 0011 1101 0111(64bitを超えたため、小数点以下の一部を削除しました)`と出力されました。

# 丸め誤差を回避できるBigDecimalクラスとは

> 意図しない丸めを許さない
double/floatのプリミティブの計算では丸めが指定できなかったが、BigDecimalでは計算が全てメソッドなので引数として丸め方法を渡すことができる。
> 
～中略～

> 整数と10のマイナス乗で表す
浮動小数点方式により丸めてしまう問題については、整数と10のマイナス乗による表現で回避されている。BigDecimalは内部的には次のように値を保持している。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549712/89160a80-590b-4dd6-f4b6-18d0184dcbb1.png)

> 整数であれば小数と違い2進数で循環することはないので、それによる丸めは心配ない。10のマイナス乗で表現することで値としても小数と同値を表現可能になっている。これによって、メモリに乗せただけで丸められてしまうこともなくなる。

> 桁数についても200億桁ぐらいまでいけるようなので、ほんとうに特殊な分野以外の人は考慮する必要も無い。
[なぜBigDecimalを使わなければならないのか](https://javazuki.com/articles/bigdecimal-why.html)

上記引用から、BigDecimalクラスを用いると、Double型よりも高精度で計算可能であると解釈しました。
（少なくとも10進数小数を2進数変換することによる丸め誤差は発生しない）
また、必要に応じて丸めることもできるようです。


# BigDecimalクラスを利用して、意図する挙動を実現した

実際にBigDecimalクラスを利用してみます。
BigDecimalクラスを導入した次のソースコードで、`3.14 * 6 * 6 = 113.04`の計算処理に成功しました！


```Main.java
import java.math.BigDecimal;

public class Main {
	public static void main(String[] args) {
        final BigDecimal pi = new BigDecimal("3.14");
        final BigDecimal radius = new BigDecimal("6");
        
        BigDecimal area = pi.multiply(radius);
        area = area.multiply(radius);
        
        System.out.println(area);
    }
}
// 113.04
```

# おわりに

BigDecimalクラスと題したものの、BigDecimalクラス / BigDecimal型どちらの表現がより適切なのか、いまいちよくわからずにいます。
（BigDecimalクラスでも、とりあえず間違ってはいないと思うのですが）
有識者の方はコメント頂けたら幸いです。







# 参考
- [BigDecimal (Java Platform SE 8 )](https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html)
- [小数計算の誤差 0.1 + 0.2 が 0.30000000000000004 になる理由](https://blog.apar.jp/program/8900/)
- [2,8,10,16進数 計算・変換（マイナス、小数点対応）](https://note.cman.jp/convert/bit/)
- [小数点つき10進数を2進数に変換する方法とツール](https://mathwords.net/syosuu2sin)
- [なぜBigDecimalを使わなければならないのか](https://javazuki.com/articles/bigdecimal-why.html)
クラスタリング結果の評価Adjusted Rand Index(ARI)について

## はじめに
クラスタリングの性能評価でよくAdjusted Rand Index (ARI) が使われます。
2つのクラスタリング結果が一致しているとき、ARI=1となる程度しか知りませんでした。
ARIについては日本語のレファレンスが少なくて、数式である程度理解しようと思いましたが、ARIの式を見ると、Σが多く、数弱な自分にはよくわかりまんでした。。
ということで、具体例を用いて自分なりの解釈を記します。

参考文献は以下です。
https://link.springer.com/article/10.1007/BF01908075
https://en.wikipedia.org/wiki/Rand_index

## Rand Index (RI)について
RIについてはわかりやすい例を用いた説明がありました。
https://qiita.com/carushi@github/items/192c51ca904fab406115#comments


## 具体例
例えばX, Yというふたつの実験でそれぞれ対応するn個のサンプルが、別々にクラスタリングをしたときの結果が以下のようになったとする。


```
X: 1, 2, 1, 1, 2
Y: 1, 1, 2, 1, 2
```
この5つからとりうるすべてのペア間でX, Yにおけるクラスタリングの結果を比較します。
ペア数は5つから2つを選ぶ組み合わせなので、

```math
{}_5 \mathrm{C} _2=10 (通り)
```
となります。

**評価の基準はそれぞれが同じクラスに入っていたか、そうでないか。**

例えば1,2番目のペア同士を比較すると、

```
X: 1 x 2
Y: 1 o 1
```
となり、Xのクラスタリング結果は不一致、Yの結果は一致です。
これをすべてのペアに対し、一致、不一致を調査し、その数をContingency tableにまとめます。

|  | $Y_{○}$ | $Y_{×}$ |  sum |
|:-----------|------------:|------------:|:------------:|
| $X_{○}$       | 1        | 3         |4    |
| $X_{×}$    | 3      | 3       | 6    |
| sum       | 4        | 6         |10    |

先ほど調査した、Xのクラスタリング結果は不一致、Yの結果は一致の例は2行1列のセルにカウントされています。

XでもYでも同じ結果となっているものは、
$X_{○}$かつ$Y_{○}$のセルと$X_{×}$かつ$Y_{×}$のセルの合計値となります。

この例の場合、

```math
1+3=4
```
となります。
したがって、RIは

```math
Rand\ index= \frac{(1+3)}{10}=\frac{4}{10} =0.4
```
となります。

## Adjusted rand index(ARI)について
RIの欠点として、二つのクラスタリングに相関がなくても，高い値をとってしまうことが考えられます。
このような問題を解決しようと提案されたのがARIです。
ARIでは，相関のない適当に行われたであろうクラスタリングにペナルティを与えます。
どのようなペナルティが適切でしょうか？ 
ARIでは，ペナルティ＝「相関のない（独立な）クラスタリングをした時のRIの値」と考えます。

## 具体例
先ほどのRIの例の続きとして、以下このペナルティを求めていきます。
2つのクラスタリング結果が独立であると仮定したとき、
独立なときの期待値を考えます。

```math
E(○,○)=P(X_{○})*P(Y_{○})=\frac{4}{10} *\frac{4}{10} = \frac{16}{100}\\

E(×,×)=P(X_{×})*P(Y_{×})=\frac{6}{10} *\frac{6}{10} = \frac{16}{100}\\

```
期待値の合計は

```math
{}_n \mathrm{C} _2 \ (E(○,○) +E(×,×))={}_n \mathrm{C} _2*\frac{16}{100}*\frac{16}{100}=\frac{52}{10}=5.2\\
```

これがペナルティ項となり、ARIは

```math
Adjusted \ Rand\ index= \frac{4-5.2}{10-5.2}=-0.25
```
となります。
LiteSpeed Let’s EncryptでQualys SSL Labs A+

<h1>LiteSpeedでA+評価を得る</h1>
LiteSpeedにLet’s Encryptで取得した証明書をあててHTTPS化は完了してる前提です

https://www.ssllabs.com/ssltest/
![スクリーンショット 2021-02-08 172109.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269221/2c9c5b1e-a4ef-daee-39b3-52c4b8a3e777.png)

<B>1.サーバ側でRSA鍵長を4096ビットにする</b>
<code>sudo certbot renew --rsa-key-size 4096</code>

強制的に行う場合
<code>sudo certbot renew --force-renewal --rsa-key-size 4096</code>

<b>2.LiteSpeedのリスナー443portのSSL</b>

![スクリーンショット 2021-02-08 170601.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269221/80526bd4-2f49-e9b0-75b0-1656e7573f0a.png)

<b>SSL 秘密鍵 & 証明書</B>
<b>SSL プロトコル</b>
プロトコルバージョン TLS v1.2　TLS v1.3    
<b>セキュリティ & 機能</b>
SPDY/HTTP2を有効にする	 SPDY/3 HTTP/2 HTTP/3     なし    

<b>3.バーチャルホストのコンテキスト</b>

![スクリーンショット 2021-02-08 171230.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269221/9fbacbd0-d773-c05a-af65-3ac3c8e218db.png)

<b>静的コンテキストの定義</b>
URI	/
場所	$DOC_ROOT/
アクセス可能	はい
Header Operations <code>Strict-Transport-Security: max-age=31536000; includeSubDomains; preload</code>

HSTSの設定について
<code>Header always set Strict-Transport-Security max-age=31536000</code>
では「サーバーが無効なHSTSポリシーを送信しました。詳細については、以下を参照してください。」が表示されたので以下に変更しました。

<code>Strict-Transport-Security: max-age=31536000; includeSubDomains; preload</code>
git branchでbranch名が表示されない!!!(ローカルリポジトリ )

はいどうも、git苦手なプログラミング初心者です。

Railsでアプリケーションを作っていたのですが、
「コマンドラインで git branch と打ってもローカルのbranchが表示されないよー」という状態になりました。

```
mbc:ディレクトリ名  ユーザー名$ git branch
mbc:ディレクトリ名  ユーザー名$
```
さっきまでbranchのmasterを表示できていたのに!
なんでだろう?

###環境

`ruby 2.7.2`
`Rails 6.0.3.4`
`git version 2.29.2`

###発端

```
mbc:ディレクトリ名  ユーザー名$ git branch
* master
mbc:ディレクトリ名  ユーザー名$
```

最初はこんな感じでmasterが表示されていました。その後、少しいじっていたら


```
mbc:ディレクトリ名  ユーザー名$ git branch
mbc:ディレクトリ名  ユーザー名$
```
あれ?masterが出ない...

###原因

原因は**初回のcommitの取り消し**でした。
[こちらの記事](https://teratail.com/questions/213882)を参考にしました。

なるほど、git branchはcommitが無いと表示されないのか。
そういえばcommitの取り消しをしてたのを忘れてました...

```
mbc:ディレクトリ名  ユーザー名$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   .browserslistrc
        new file:   .gitattributes
        new file:   .gitignore
```

ステージング状態になってますわ

###解決
では実際にcommitしてこの状態を解決してみようと思います。

```
mbc:ディレクトリ名  ユーザー名$ git branch
mbc:ディレクトリ名 ユーザー名$ git log
fatal: your current branch 'master' does not have any commits yet
```

はい、確かにmasterにcommitがまだないよって書かれています。
ちなみに現時点でもbranch名は表示されていません。

それでは
`git commit`
`git log`
`git branch`

を入力してみます。

```
mbc:ディレクトリ名 ユーザー名$ git commit -m "first commit"
     ~~省略~~
mbc:ディレクトリ名 ユーザー名$  git log
Author: ユーザー <メールアドレス>
Date:   Mon Feb 8 15:52:34 2021 +0900

    first commit
mbc:ディレクトリ名 ユーザー名$ git branch
* master
```
git commitをしたらbranch名が出て来ました!

###結論

結構初歩的なつまづきですね。お恥ずかしい限りです。
やっぱりプログラミング周りの予備知識ってメインのプログラミングよりも難しいですね。もっと学ばねば。
おわりー。
AS/400の数値型に対して、SQLで条件指定する場合の注意点

※個人の備忘録からの投稿で、一般化したスクリーンショットを用意できていません。すみません。


#■まず結論から
結論から言えば、安全策として、
 
○　select * from AAA.BBB where slipno = '1705';
 
のように数値であっても文字型として指定することを心掛けるとトラブルを回避できます。
#■解説

###●問題が起きる事例

BBBは物理ファイルで『slipno』以外がキー、
BBBZは『slipno』がキーとなっている論理ファイルです。
『slipno』は数値型のnumericです。


×　select * from AAA.BBB  where slipno = 1705;
○　select * from AAA.BBBZ where slipno = 1705;
○　select * from AAA.BBB  where slipno = '1705';
○　select * from AAA.BBBZ where slipno = '1705';

データが1000万件以上ある環境下でしたが、
○は0.1秒以下
×は180秒以上
の処理時間が掛かりました。


###●問題が起きる理由
+ AS400内RPGで使用していた数値型はNUMERIC、SQLクエリ上の数値型はINTEGERで、データ型が異なる
 
+ 基本的には、照合ベースとしては、NUMERICよりINTEGER側が精度が高いということで優先される
　⇒INTEGERが優先される
　⇒全行でキャストが行われ、当然索引も利用されない
 
+ 論理ファイルを直接指定した場合は、(キーに関しては)照合の際の型が、論理ファイル側が優先される　(索引を利用するという明確な意思があるため)
　⇒(論理ファイル側の型である)NUMERICが優先される


###●検証

1) ○　select * from AAA.BBB where slipno = cast(1705 as numeric);
2) ×　select * from AAA.BBB where slipno = cast(1705 as integer);
3) ×　select * from AAA.BBB where slipno = 1705;
4) ○　select * from AAA.BBB where slipno = '1705';
5) ○　select * from AAA.BBBZ where slipno = cast(1705 as numeric);
6) ○　select * from AAA.BBBZ where slipno = cast(1705 as integer);
7) ○　select * from AAA.BBBZ where slipno = 1705;
8) ○　select * from AAA.BBBZ where slipno = '1705';


※これらを実行し、利用された索引名をVisualExplainで確認しました。
※社内環境での検証のためスクショ載せられずすみません。

1) ○　select * from AAA.BBB where slipno = cast(1705 as numeric);
　明示的にNUMERICにキャストした場合は、型が同一のため、高速になる。
　索引も自動的にBBBZが使用される。

4) ○　select * from AAA.BBB where slipno = '1705';
　文字列型の場合、NUMERICが優先されるため、’1705’　は内部で　cast(1705 as numeric)　され、
　同様に索引はBBBZが使用され、高速に処理される。

3) ×　select * from AAA.BBB where slipno = 1705;
　INTEGERのほうが優先度が高く、
　NUMERIC側(slipno)をキャストするため、索引(インデックス)が利用されず、非常に低速となる。

7) ○　select * from AAA.BBBZ where slipno = 1705;
　ただし、例外的に、明示的にBBBZを指定した場合は、
　索引の型が優先され、1705　は内部で　cast(1705 as numeric)　されるようで
　索引が利用され、高速に処理される。

99) ○　select * from AAA.BBBY where slipno = '1705';
　なお、素晴らしいことに、適切でない論理ファイル名(BBBY)を指定した場合であっても、
　オプティマイザが適切な索引を利用しようとして、自動的にBBBZを利用して処理されている。(これは素晴らしい！)
　当然、高速に処理される。


###●まとめ
まとめると、正しい論理ファイルを指定した場合は、SQL文の中で数値指定(つまりINTEGER)でも問題ないが、論理ファイル名を間違えたり、単に物理ファイル名の指定では、索引が適用されず、テーブルスキャンかつキャスト処理で、非常に重たい処理となってしまう。
SQL文の中で文字列として指定した場合は、NUMERIC型が優先されるため、文字列がNUMERIC型に一度だけキャストされる。さらにこの場合は、どの論理ファイル・物理ファイルを指定していても、適切な索引が自動で判定されて、利用される。
一応、cast(1705 as numeric)　のようにキャストしても良いが、事前にどの数値型か調べる必要があり、書き方として面倒でもあるので、文字列型で指定する方法は、非常に便宜的といえる。

###付記
Visual Explainでは使用された索引の名前として論理ファイル名が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234814/35b145d6-477f-68dd-581f-b108b12ff0af.png)
【Spring Boot + Angular + MySQLでWebアプリ作成】 データベース編

##MySQLにログイン
コマンドプロンプトを開き以下のコマンドを実行します。

```
mysql -u root -p
```

パスワード（root）を入力します。

```
Enter password:
```



##データベース作成
データベースを作成します。

```
mysql> create database sampledb;
```

使用するデータベースを選択します。

```
mysql> use sampledb;
```
##テーブル作成
社員テーブルと部署テーブルを作成します。
以下のSQLをMySQLのコマンドプロンプトに貼り付けて実行します。
###社員テーブル

```sql

CREATE TABLE employee (
    id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    name VARCHAR(50),
    department_id int,
    birthday date
);
```

###部署テーブル

```sql

CREATE TABLE department (
    id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
    name VARCHAR(50)
);
```

##データ作成
アプリで使用するダミーデータを挿入します。
社員名はテストデータ・ジェネレータで適当に生成したものを使います。
https://yamagata.int21h.jp/tool/testdata/
以下のSQLを貼り付けて実行します。

```sql

INSERT INTO department(name) VALUES ('総務部');
INSERT INTO department(name) VALUES ('人事部');
INSERT INTO department(name) VALUES ('経理部');
INSERT INTO department(name) VALUES ('営業部');
INSERT INTO department(name) VALUES ('開発部');
INSERT INTO department(name) VALUES ('事業部');
INSERT INTO department(name) VALUES ('製造部');

INSERT INTO employee(name, department_id, birthday) VALUES ('黒田 繁樹', 1, '1999/1/1');
INSERT INTO employee(name, department_id, birthday) VALUES ('大崎 義将', 2, '1998/12/14');
INSERT INTO employee(name, department_id, birthday) VALUES ('川原 恵志', 6, '1997/5/2');
INSERT INTO employee(name, department_id, birthday) VALUES ('古賀 督彦', 5, '1996/6/6');
INSERT INTO employee(name, department_id, birthday) VALUES ('田中 由枝', 4, '1999/1/15');
INSERT INTO employee(name, department_id, birthday) VALUES ('亀井 康伸', 3, '1998/12/1');
INSERT INTO employee(name, department_id, birthday) VALUES ('溝口 大夢', 1, '1997/2/1');
INSERT INTO employee(name, department_id, birthday) VALUES ('山中 一智', 2, '1996/5/6');
```

##データ確認

以下のようにデータが入っていればOKです。

```
mysql> select * from employee;
+----+-----------+---------------+------------+
| id | name      | department_id | birthday   |
+----+-----------+---------------+------------+
|  1 |  黒田 繁樹 |             1 | 1999-01-01 |
|  2 |  大崎 義将 |             2 | 1998-12-14 |
|  3 |  川原 恵志 |             6 | 1997-05-02 |
|  4 |  古賀 督彦 |             5 | 1996-06-06 |
|  5 |  田中 由枝 |             4 | 1999-01-15 |
|  6 |  亀井 康伸 |             3 | 1998-12-01 |
|  7 |  溝口 大夢 |             1 | 1997-02-01 |
|  8 |  山中 一智 |             2 | 1996-05-06 |
+----+-----------+---------------+------------+

mysql> select * from department;
+----+--------+
| id | name   |
+----+--------+
|  1 | 総務部 |
|  2 | 人事部 |
|  3 | 経理部 |
|  4 | 営業部 |
|  5 | 開発部 |
|  6 | 事業部 |
|  7 | 製造部 |
+----+--------+
```

これでデータベースの準備は完了です。
[【Spring Boot + Angular + MySQLでWebアプリ作成】 SpringBoot編①へ](https://qiita.com/k-yamada-neut/private/56598999da3506e1eb7e)
【備忘録】CSSやSassで使われる擬似クラスその１

#はじめに
擬似クラスはCSSやSCSSで見栄えをよくするためによく使われています。学習した内容を忘れないための備忘録です。

#目次
- 擬似クラスとは
- 擬似クラスその１
- 参考サイト

# 擬似クラスとは
擬似クラス(Pseudo-classes)とは、CSSのセレクタに付け加えて使用し、要素の特定の状態に対してあるスタイルを適用するものです。 今までのCSSは静的な要素にしかスタイルを付けられませんでしたが、擬似クラスを利用することによって動的にスタイルを適用することが可能になります。うまく活用すればjavascriptを使わなくても同じような動作をするページを実装できます。

# 擬似クラスその１
①:link擬似クラス
まだクリックしていない（未訪問）リンクのスタイルを指定します。

```html
<!-- htmlファイル -->
<body>
    <div class="letters">
        <a class="yahoo" href="https://www.yahoo.co.jp/">Yahoo Japan</a>
    </div>
</body>
```
```css
/* :link擬似クラス */
.yahoo:link {
    color: #d4d63a;　/*薄い黄色*/
}
```
> 表示される画面
![スクリーンショット 2021-02-08 16.45.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/f1ce0e2c-71c3-6a6e-b0f0-cf82ec0b231b.png)

②:visited擬似クラス
クリックした（訪問した）リンクのスタイルを指定します。

```css
/* :visited擬似クラス */
.yahoo:visited {
    color: #e73023;  /*赤色*/
}
```
> 表示される画面
![スクリーンショット 2021-02-08 16.53.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/9977321d-4203-3229-5a08-4aea587dde09.png)

③:hover擬似クラス
マウスのカーソルをリンクに乗せた時のスタイルを指定します。とても良く使われます。

```css
/* :hover擬似クラス */
.yahoo:hover {
    color: #d819ce;;  /*ピンク色*/
}
```
> 表示される画面
![スクリーンショット 2021-02-08 16.57.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/aa39a782-f9e9-e354-86ad-7eb1a0661dc6.png)

④:active擬似クラス
ユーザーの操作で要素がアクティブになった際のスタイルを指定します。linkではクリックされてから指が離れるまでの間に適用されるスタイルです。

```css
/* :active擬似クラス */
.yahoo:active {
    color: rgb(178, 0, 248); /*紫色*/
}
```
> クリックされている間に表示される画面
![スクリーンショット 2021-02-08 17.05.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/966135/6239f831-7688-4b76-f7bb-17d790cccf0c.png)

# 参考サイト

http://www.htmq.com/selector/link.shtml
https://www.itra.co.jp/webmedia/what-is-pseudo-class.html
Blockchain 頻出用語

# P2PKH / P2SH
 - PSPKH：``公開鍵``のハッシュ
 - P2SH：``スクリプト``のハッシュ

# Base58 / Base64
 - Base58：Base64から``紛らわしい6文字``を除いたもの
 - Base58Check：``無効なビットコインアドレス``を検出

# RIPEMD-160
 - ``SHA256 + RIPEMD-160``の組み合わせで使われる
 - OP_HASH160 = ``RIPEMD160(SHA256(data))``

# ビックエンディアン / リトルエンディアン
 - ビックエンディアン：``最初``のバイトからデータを並べる（そのまま）
 - リトルエンディアン：``最後``のバイトからデータを並べる（逆）

# BIP
 - ``Bitcoin Improvement Proposals``の略
 - ビットコイン技術の発展のためのに作成、公開される``草案群``

# BIP32
 - ``階層的決定性``ウォレット
 - ``128bits``エントロピー
 - ``HMAC-SHA512``


# 参考文献
 - [P2PK[H] (Pay to Public Key [Hash])](https://programmingblockchain.gitbook.io/programmingblockchain-japanese/other_types_of_ownership/p2pk-h-_pay_to_public_key_-hash)
 - [P2PK、P2PKH、P2SH、P2WPKHとは-ELI5](https://bitcoin.stackexchange.com/questions/64733/what-is-p2pk-p2pkh-p2sh-p2wpkh-eli5)
 - [アドレスや秘密鍵の見間違えを防ぐ特徴的なフォーマットBase58](https://bitcoin.stackexchange.com/questions/64733/what-is-p2pk-p2pkh-p2sh-p2wpkh-eli5)
 - [​Base58とは？仮想通貨のアドレス、公開鍵、秘密鍵などを作成する技術を簡単に説明します！](https://coinotaku.com/posts/18451)
 - [用語集](https://bitflyer.com/en-eu/glossary/ripemd160)
 - [How to compute OP_HASH160 of public key](https://gist.github.com/t4sk/0740f224a70d9eae9564c3d856039264)
 - [[バイトオーダー]ビックエンディアン/リトルエンディアン](https://qiita.com/ryuichi1208/items/31442f9e8a7a7c94aeec)
 - [BIP32でマスターキーを生成するために必要なHMAC-SHA256のラウンド数](https://bitcoin.stackexchange.com/questions/83807/how-many-rounds-of-hmac-sha256-needed-to-generate-the-master-key-in-bip32)
 - [ビットコイン（Bitcoin）用語集](https://bitflyer.com/ja-jp/glossary/bip)
 - [暗号資産（仮想通貨）用語集](https://bitbank.cc/glossary/bip0032)
 - [【ビットコイン】ウォレットの概要とHDウォレットの仕組み](https://blockchain.gunosy.io/entry/2017/12/21/165314)
@storybook/addon-docsでNo inputs found for this component.が表示された時の対応

# はじめに
@storybook/addon-docsを導入したところ、本来propsの項目が表示されるはずの箇所に`No inputs found for this component.`が表示されてしまう状態でした。
解決してみれば大した原因ではなかったのですが、地味に時間がかかったので備忘録として残しておきます。同じ現象でハマっているひとの助けになれば幸いです。

## 参考画像
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113074/17433a57-a899-ac7b-766d-b3b6641d8113.png" width="400px">

# 解決方法
storieファイルにインポートしたReactComponent名とファイル名に差異があるとpropsの項目が表示できないらしく、今回の現象が発生した環境では、tsxのファイル名をケバブケースで記載するルールにしており、ファイル名が小文字になっていたためコンポーネント名と差異が発生していました。

```button.tsx
const Button:React.FC<Props> = (props) => {
  return (
    <StyledButton className={ props.className } to={props.to}>
      <ButtonText>{ props.children }</ButtonText>
    </StyledButton>
  );
}
export default Button;
```

ファイル名を`Button.tsx`に変更したところpropsの項目を意図した通りに表示することができました。
とりあえずファイル名はパスカルケースで記載するルールに変更。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113074/abf99d18-8109-baa3-ca2a-58a644104335.png" width="400px">

# 補足
ハイフンが入る分には問題ないらしく、大文字小文字の差異が主な原因のようです。
例えば、`IconBtn`という名前のコンポーネントを持つ`icon-btn.tsx`のようなファイルは`Icon-Btn.tsx`にすることでpropsの項目を表示できるようです
[OpenCV] マウスクリックで画像からROIを切り取る [1]

#はじめに
OpenCVを利用して、マウスクリックイベントを練習してみました。

#やりたいこと

1.画像の上にマウスで4か所をクリックする。（左側の緑ポイント）
2.その4か所の内側の部分を切り取り、別の画像として表示する。（右側）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/7d870bd7-6c97-a7ea-c533-f04daf2264f2.png)

#やり方の説明

OpenCVのマウスクリックイベントを利用します。

マウスカーソルが選択する座標を格納するcircles配列を宣言
マウスクリックを数えるcounter変数を宣言
マウスの左クリックを検知すると、画像の座標をcircles[]に格納する関数を定義

```Python

import cv2
import numpy as np

circles = np.zeros((4,2), np.int)
print(circles)
counter = 0

def mousePoints(event, x, y, flags, params):
    global counter
    if event == cv2.EVENT_LBUTTONDOWN:
        print(x,y)
        circles[counter] = x,y
        counter = counter + 1
        print(circles)

```

画像処理部分。
OpenCVのPerspectivTransformを利用し、マウスで選択された部分をwarp処理する。
マウスが4回クリックされた時のみに、処理を行う。

```Python

while True:

    if counter ==4 :
        width , height = 250, 350
        pts1 = np.float32([circles[0],circles[1],circles[2],circles[3]])
        pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]])
        matrix = cv2.getPerspectiveTransform(pts1,pts2)
        imgoutput = cv2.warpPerspective(img, matrix,(width, height))
        cv2.imshow('Output image', imgoutput)

    for x in range(0, 4):
        cv2.circle(img, (circles[x][0], circles[x][1]), 3, (0, 255, 0), cv2.FILLED)

```

#全体コード

```Python
import cv2
import numpy as np

circles = np.zeros((4,2), np.int)
print(circles)
counter = 0

def mousePoints(event, x, y, flags, params):
    global counter
    if event == cv2.EVENT_LBUTTONDOWN:
        print(x,y)
        circles[counter] = x,y
        counter = counter + 1
        print(circles)


img = cv2.imread('lena.png')

while True:

    if counter ==4 :
        width , height = 250, 350
        pts1 = np.float32([circles[0],circles[1],circles[2],circles[3]])
        pts2 = np.float32([[0,0],[width,0],[0,height],[width,height]])
        matrix = cv2.getPerspectiveTransform(pts1,pts2)
        imgoutput = cv2.warpPerspective(img, matrix,(width, height))
        cv2.imshow('Output image', imgoutput)

    for x in range(0, 4):
        cv2.circle(img, (circles[x][0], circles[x][1]), 3, (0, 255, 0), cv2.FILLED)

    cv2.imshow('Original image', img)
    cv2.setMouseCallback('Original image', mousePoints)

    cv2.waitKey(1)
```
#参考資料
Bounding Boxを利用する方法の内容も掲載しました。
[[OpenCV] マウスクリックで画像からROIを切り取る [2]](https://qiita.com/kotai2003/items/acfe925a3c535cc526e4)
[2021Feb] M5Stack / M5StickC / M5Atom 向け esp-idf の make が通ったよ

# 結論

[前回](https://qiita.com/teruo-oshida/items/9bb601235dfcb2d61907)と同じく make が通った組み合わせのメモです。


### モジュール構成

|module|version (tag)|
|---|---|
|Debian|10.0 ※1|
|Python|3.7.9 ※1|
|esp-idf|v3.3.4|
|gcc|1.22.0-96-g2852398-5.2.0 ※2|
|arduino-esp32|1.0.4|
|M5Stack|0.2.8|
|M5StickC|0.2.0|
|M5StickC Plus|0.0.1|
|M5Atom|0.0.1|

※1 Docker image の python:3.7.9-slim-buster をベースにしてます。
※2 普通に esp-idf の install.sh でインストールされるやつ（[tools/tools.json](https://github.com/espressif/esp-idf/commit/ff29e3e7a24a715bc7f5ba453c83d694ba0ec1e2#diff-c5616b2ed67010e9d507b92123ad73c8eedb635e58db89d1a5eeee2a59ccfc20R58) に登録されているやつ）です。


### その他

Python を 3.7 にしている理由は特にありません。ESP32 始めたとき 3.7 が最新だったとかそのくらいの理由です。
esp-idf を v4 にすると Python 2.7 縛りが入っていたような気がします。[このへん](https://github.com/espressif/esp-idf/commit/dc98d0aeee8b4766d9b312c6065b503073c42105#diff-4d7c51b1efe9043e44439a949dfd92e5827321b34082903477fd04876edb7552R20)？　最近ですね。
CSSを使用してヘッダーを固定する。

##やりたいこと
ヘッダーを常に上部に固定する。

##実際のコード
```html
<header>ヘッダー</header>
```
上記のヘッダーに対してCSSを記述する。

```CSS
header {
  height: 70px;
  width: 100%;
  background-color: #F8F1F1;
  position: fixed;
}
```

positionの値をfixedにすることでヘッダーを固定することができる。
固定する場合widthを100%にしないと画面幅いっぱいに表示されない。
開発プロセスについて

# はじめに
引き続き研修のアウトプットをしていきます！
今回は「開発プロセスについて」です。

# 学んだこと
実際に開発していくときどういう流れでおこなわれて、どういう成果物が作られるのか。

### 開発のプロセス
#### 要件定義
「なにをつくるか」を決める。

`目的`

- 要件（顧客のもつふんわりとした要望を満たす条件）を定義して一貫性のある形へ整える。
- 顧客と開発者の認識をすりあわせる。
- コミュニケーションによる信頼関係の構築
- 顧客要望の背景理解

`成果物`
要件定義書

#### 設計
「どのようにしてつくるか」を決める

`目的`

- 要件から実現可能なふるまいへソフトウェアの仕様を定める
- どのようなものが作成されるか全体のイメージを共有

`成果物`
機能仕様書、基本設計書、詳細設計書、DB設計図、UI設計図、UML図など

##### 基本設計と詳細設計
基本設計とは：ソフトウェアのふるまい（エンドユーザーから見た画面の動き）を設計。外側から見てどのような動きをするのか確認する

詳細設計とは：ソフトウェアの中身（アルゴリズム部分）を設計。プログラムに落とし込めるかどうかを確認する

##### DB図とは？
データベース設計で使われる図。テーブルの定義や、ER図などがある。

##### UI図とは？
ウェブページ上の画面構成。誰に何をどうしてほしいかをもとに「どう伝えるか」を設計する。

##### UML図とは？
人や言語の違いによる表現の方法を統一した手法。システムの全体像を図形を使って表現する。
UML図にも種類があり、表現内容や用途によって使用するUML図が異なる。

参考：https://cacoo.com/ja/blog/what-is-uml/

#### 製造
実際に「つくる」
開発でいう実装にあたる

`成果物`
ソースコード

#### テスト
つくったものを「確かめる」

`目的`
品質に不備がないと自身をもっていえるよう、機能要件を満たしているかを確認する

`成果物`
テスト結果報告書

#### 納品
「使える」ようにする
#### 運用
「使い続けられるように」保つ。
例）OSのアップデートに対応できるようにする　など

### プロセスモデル
#### ウォーターフォールモデル

- 上流から下流に向かって順番に開発を進める
- 後戻りがしにくい。下流フェーズで上流フェーズの不具合が見つかった場合には、修正が困難。
- 段階を踏んで開発していくため、スケジュール・資源の管理がしやすい
- `大規模システム開発` に向いている


#### プロトタイプモデル
- 試作品（プロトタイプ）を作成して顧客と確認しながら開発する
- 要件定義　→　プロトタイプ作成　⇔　プロトタイプ確認　→　設計という流れ
- 早い段階でイメージの共有ができることで認識のズレを回避し、手戻りを減らせる
- プロトタイプの作成、確認、修正の工程を繰り返すため、開発への負担が大きい
- `小規模開発`に向いている

#### スパイラルモデル
- 全体の機能を分割して機能ごとに開発していく
- 完成した機能から順番に顧客に引き渡す

例）機能１を設計→製造→テスト。完了したら機能１は引き渡し、機能２を作成。これを繰り返す。

- 工程を小さく回せるので柔軟
- 柔軟であるがゆえに仕様が肥大化したり、コストや人員がかかることがある
- `品質を高めたいシステム`に向いている

#### アジャイル開発
- アジャイル＝素早い
- 要件定義からリリースまでを小さなサイクルで繰り返す
- スパイラルモデルとの違いは、１つの機能の開発が完了し、品質が保証された段階で、その都度リリースするところ
- [アジャイルソフトウェア開発宣言](https://agilemanifesto.org/iso/ja/manifesto.html)に則っている
- `開発期間を短縮したい`ときに向いている

# まとめ
ウォーターフォールやアジャイル開発は聞いたことがありましたが、プロトタイプモデルなどはじめて聞く開発モデルがあり、勉強になりました。
開発工程についても、個人で勉強していたときは製造の部分しか考えていなかったので、今後は全体の流れも意識しながら開発に携わっていきたいと思いました。