OmniAICreator/Qiita-1.07M huggingface dataset:
Amazon SageMaker Canvasを使ってみた！

先日、アマゾンウェブサービスジャパン合同会社が主催する勉強会に参加しました！
内容はAWSが提供する機械学習サービスについてで、今回はAmazonSageMakerの話でした。

ノーコードで機械学習が利用できるということなので、早速試してみようと思います！

# 前提
・AWSアカウント作成済み
・基本的なAWS操作ができる

# 初期設定
Amazon SageMaker Canvasを使うには、最初にユーザー・ドメイン・S3バケットを作成していきます。

左側のメニューからCanvasを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/6e3070d2-b974-b53c-6ad2-2d6be426a401.png)
デフォルトのまま送信。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/bdbabacc-e2d5-cc7a-10d3-0ac29d5e3092.png)
適当にVPCとサブネットを選択し、保存して続行。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/7513b14e-e921-093a-c84f-7afd446c1540.png)
SageMaker Domain作成が完了するまで数分かかる。
以下のようなエラーが出るのですが、ページを読み込み直すと消える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/492a17c8-a64c-ec3a-99fb-4f7220be4498.png)
ユーザーが作成されたので「アプリケーションの起動」からCanvasを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/3f2b9061-1e2c-e3ff-940c-a071871b0615.png)
数分の待ち時間の後、Canvas専用画面が立ち上がる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/be48e8c4-f257-35d0-01b6-a8887ecd94bf.png)

# サンプルデータ入手
次にサンプルデータを用意しておきます。(分析したいデータがある人は飛ばしてOK)
S3経由でCSVをアップロードするのが一番楽なので、そのやり方で行きます！

以下で簡単にサンプルデータを用意できました。
感謝ですm(_ _)m
http://kazina.com/dummy/

# データインポート
学習用のデータをインポートします。

自動で作成されたS3バケットの名前を以下で確認し、S3バケットにCSVデータをアップロードしておく。
左メニューの「Datasets」→「＋ Import」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/33e45995-dedd-8d83-193d-e56ec8118be3.png)
「＋ New model」を選択し、モデル名を決めたら「Create」。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/892eb570-cc85-5e2e-54a9-79205672342f.png)
説明ダイアログボックスを閉じて、「Import data to Canvas」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/5939dbbb-5b05-2b76-9499-179aeffa6ce4.png)
バケットから該当のCSVデータをチェックし、「Import data」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/9186b730-ddff-4f32-4f60-e5e7a828c292.png)
数秒でStatusが「Ready」になるので、押下するとデータの確認ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/6662bc7f-3a68-1dd9-5c18-efe9e18d1a03.png)

# 機械学習を開始
「Select dataset」で、どの列を分析するかを選ぶ。
今回は「婚姻」に設定し、「Quick build」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/932ba7cc-ac9c-cd06-ae03-8fe58e849132.png)
学習が始まり、数分後に以下のような結果が出る。
精度が84.5%で、「婚姻」には「年齢」が最も大きな影響を与えていることがわかりました。
適当に作成したサンプルデータの割には、とても現実的な結果が出ました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/26b36bb2-2fab-2525-f567-68afcbc6a03b.png)

# 予測
先程のモデルを利用して、新しいデータの婚姻を予測してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/ac7080a7-222b-4c6c-c298-10767c719b13.png)
５歳に設定したのに既婚か・・
作成されたモデルを見る限り年齢が高いほど、既婚になりそうな気がしたのですが^^;

# 終わりに
今回はAmazon SageMaker Canvasを使ってみました。
ノーコードで手軽に利用はできますが、元データがとても重要なので、実務で利用する前に多少のお勉強は必要かな〜と思いました。
WSLの不要なディストリビューションを消す

# コマンドプロンプトまたはPowerShellを立ち上げて一覧を出力する

```shell:Powershell
wsl -l -v
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/0b50d520-744c-7a31-d81f-9dea60ac22c0.png)



# NAMEを確認して削除する

```shell:Powershell
wsl --unregister rancher-desktop
wsl --unregister rancher-desktop-data
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/4b1340f9-62f3-03d5-65d0-12e21b1c3c26.png)

# 消えたのを確認する

```shell:Powershell
wsl -l -v
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/6574d23e-df0b-1117-69e4-84017611f96d.png)

以上
Railsアプリでデータベースを作成する方法

# 結論
ターミナルで以下を入力する
```
$ rails db:create
```
これでデータベースを作成できます。

## 成功した場合
```
Created database 'db/development.~~~~'
Created database 'db/test.~~~'
```
`データベースが作成された`と表示されます。

## ちなみに　
rails db:create　を2回以上打ち込むと
```
Created database 'db/development.~~~~'already exists
Created database 'db/test.~~~'already exists
```

`既にデータベースが存在している`とエラーが表示されます。


以上です。
第29回 レイヤ3 デフォルトゲートウェイ

ブロードキャストドメイン
---
ルーターとは、最適ルートを選択してくれる
ネットワーキングデバイスであり、それを中
継しないとネットワーク間でのデータ転送が
できない。

他にも重要な役割を持ち、ブロードキャスト
を他ネットワークに送り出さないという役割
も持つ。

例えば、送信元IPアドレスを取得するために
、動的IPアドレスである、DHCPを行ったと
しよう。その際に、DHCPサーバを探すため
に、DHCPDISCOVERをブロードキャストで
送信をするが、それはそのLAN内とルータを
駆け巡る。ルータの機能性として「ブロード
キャストを他ネットワークに流さない」とい
うものを持たないと、全世界中にそれが発信
されてしまい、結果として回線をパンクさせ
てしまう。

ブロードキャストが届く範囲のことを、ブロ
ードキャストドメインというが、ルータはブ
ロードキャストドメインを分けることができ　る。
※衝突の影響が及ぶ範囲が衝突ドメイン。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/8109f4c3-9af5-1630-9162-26d0f6459215.png)


衝突ドメインは、ブリッジ・スイッチが区
分けし、ブロードキャストドメインはルー
タが区分けする。


ARPとルータ
---
ただ、ARPがブロードキャストであること
が問題。ARPは宛先MACアドレスを知るた
めに、宛先IPアドレスを元に取得しようと
する。

ARPテーブルになければ、ARP要求を行う
が、その際の要求方法はブロードキャスト
である。

ルータが他ネットワークへ流さないとする
と、一見、宛先MACアドレスが取得できな
いように見える。つまり、他ネットワーク
でのデータ転送ができない。

そのため、インターネットワークでは、デ
フォルトゲートウェイというものが必要と
なる。これは、他ネットワークと接続点に
位置するデバイスのようなもので要は出入
口である。


デフォルトゲートウェイ
---
他のネットワークへデータ転送を希望する
ホストは、一度デフォルトゲートウェイに
データを送り、他ネットワークへ転送して
もらう。

これはルータが担うものでプロキシサーバ
ーなどもデフォルトゲートウェイになるこ
ともある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/83650407-b120-8cfd-230e-7bf5e7d63dc3.png)


MACアドレスは直接接続されている宛先に
使うもので、ホストは宛先が同じネットワ
ーク内ならば宛先(MACアドレス)に、違うネッ
トワークならばデフォルトゲートウェイに
ARPを送信する。

また、送信するホストは、MACアドレスを
手動で設定するか、DHCPサーバに要求する
ことによって、知ることができる。

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
第28回 レイヤ3 ルーター

インターネットワークでのデータ転送
---
なぜ、4つのアドレスの取得方法を学んでき
たのか、それはレイヤ2・3におけるカプセ
ル化において、4つのアドレスが必須となる
ため。

カプセル化に必要なイーサネットヘッダと
IPヘッダの要素に「宛先IP・MACアドレス
、送信元IPアドレス、MACアドレス」が必
要。

実際に、単一なネットワーク（複数のネッ
トワークを繋がないLANのみ）であればMA
Cアドレスだけでもデータ転送は可能。

例として、NetBEUIというプロトコルでは
MACアドレスだけを使用してデータ転送を
行うプロトコルである。ただし、大規模な
ネットワークには向かない。

IPアドレスさえあれば、あとは不要とも思
えるが、やはりそうはいかない。LANのよ
うな環境であれば、レイヤ2での制御には
MACアドレスが必須となる。

レイヤ2の制御はCSMA/CDやトークンパッ
シングのようなメディアアクセス制御であ
るが、レイヤ3のどのプロトコルでもパケ
ット転送を行えるようレイヤ2でのメディ
アアクセス制御をMACアドレスで行ってい
る。

そうすることで、レイヤ3はインターネット
ワークでの転送だけを考えることが可能。


ルーティング
---
インターネットでのデータ転送に必要なこ
とは、論理アドレスもそうだが、経路選択
、つまりルーティングである。

このルーティングを行うのが、ルーター。
ルーターがルートを決定することにより、
ネットワークは相互にデータ転送が可能と
なる。逆にルーターがなければ、異なるネ
ットワーク間はデータ転送ができない。

ルーターを使った接続図が下図。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/4a34f220-6d2a-efcf-0e79-9130b0289357.png)


ルーターもハブやブリッジのように複数の
ポートを持つが、唯一論理アドレスを持つ
。ルーターの各ポートは下記のようにそれ
ぞれのネットワークに所属している。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/4cc97600-c949-d10b-2618-6618c697be17.png)

そもそも、ハブやブリッジは流れている信
号やフレームを間で制御する役割だがルー
ターはパケットを受け取って、送り出すデ
バイス。

そのため、他ネットワークへデータ転送を
希望するホストは、ルーターに送って、届
けてもらうという形をとるために、アドレ
スが必要となる。


ルータの動作
---
まず、ルータはルーティングテーブルを持っ
ている。これは最適なルートの地図みたいな
もの。地図には宛先ネットワークまでの距離
、中継するルータ、ルータへつながっている
自分のポートなどが載っている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/f67dc1b2-91ed-6baf-b145-453ba3eee29a.png)

<table>
<tr>
<th>宛先ネットワーク</th>
<th>次のルータ</th>
<th>距離</th>
<th>ポート</th>
</tr>
<tr>
<td>192.168.1.0</td>
<td>210.81.36.1</td>
<td>3</td>
<td>１番ポート</td>
</tr>
<tr>
<td>91.0.0.0</td>
<td>210.81.36.1</td>
<td>6</td>
<td>１番ポート</td>
</tr>
<tr>
<td>172.36.0.0</td>
<td>130.82.10.1</td>
<td>2</td>
<td>２番ポート</td>
</tr>
<tr>
<td>221.194.38.0</td>
<td>なし</td>
<td>0</td>
<td>３番ポート</td>
</tr>
</table>

[Figure28-05:ルーティングテーブル]

次のルータなし、距離0というのは、自分と
すぐにつながっているネットワークであると
いうこと。

ルータの動作としては、
---

```
1,ホストから、パケットを受け取る
2,パケットの宛先IPアドレスから、
　宛先ネットワークを決定する
3,ルーティングテーブルを参照し、宛先
　ネットワークまでのルートを決定する
4,決定されたルートに従って、決められた
　パケットを送信する
```

ホストは、他ネットワークへ宛先IPアドレス
を送りたいからルータへパケットを送る。

次に、ルーティングテーブルを見てわかる通
り、テーブルにはネットワークアドレスしか
載っていない。ホストまで届けず、宛先ネッ
トワークへ届けるのがルータの役割。ホスト
まではそのネットワークのLANの制御方式に
よって(イーサネットやIEEE801.5)届けられる
。


ルータの動作
---
ルータはバスターミナルのようなもの。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/434c6645-63c5-6845-6184-2ced8b11f819.png)


C市のX町からA市のY町へ行きたい場合、X町
(ホスト)から5番乗り場のバスターミナル(ル
ータ)へ行き、B市の1番乗り場バスターミナ
ル(ルータ)を中継し、A市の3番乗り場バスタ
ーミナル(ルータ)へ行く。その後Y町まで行く
ことができる。

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
laravelのメール

# 送信処理
```php
// viewなし
Mail::raw('メール本文', function ($mail) {
    $mail->to('example@example.com');
});

// viewのみ
Mail::send('view.name', function ($mail) {
    $mail->to('example@example.com');
});

// 通常
Mail::to('example@example.com')->send(new HelloMail());

```

## viewなし
```php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class HelloMail extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
        //
    }

    public function build()
    {
        return $this->html('メール本文');
    }
}
```

# サーバーなしでメール送信
```.env
MAIL_MAILER=sendmail
```

# 参考
https://laravel.com/api/9.x/Illuminate/Mail/Mailable.html#method_html
https://laravel.com/api/9.x/Illuminate/Contracts/Mail/Mailer.html#method_raw
【トリプルディスプレイ】WindowsからMacBookに乗り換え【予算20万円】

# はじめに

転職をしましたが、転職先ではBYODでMacBookを使っていました。
Windowsユーザーだった私は初めてMacBookを買うことになったのですが、その資金として20万円が支給されました。

後世のために、この20万円でMacBookの周辺環境をセットアップした内容を残します。

# 現環境
## 全体像
まず、Windowsの環境はこんな感じです。

![全体.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951272/561378c9-6351-38c4-2d16-99b2b70a1dfc.jpeg)

- 左のモニターでUdemyを開いて、
- 真ん中のモニターでVSCode
- 右はフォルダ操作等

って感じでやっていました。
（「もっと作業環境をこうしろ」というご意見があれば教えてください。。。）

## 周辺機器
PCの周辺機器はこんな感じです。

![PC.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951272/2cfe70e3-615b-7c0e-b4ed-52c3e01be99f.jpeg)

- 一番左上：**電源ケーブル**
- 左上から二つ目：左の**モニター**に繋がるTypeC-HDMI変換ケーブル
- 左上から三つ目：**キーボード**に繋がるUSBケーブル
- 左上から四つ目：真ん中の**モニター**に繋がるHDMIケーブル
- 右上：**マウス**に繋がるUSBケーブル

ちなみに使っているのはこんな感じです。
（「もっとお金をかけろ」っていうツッコミはご容赦ください。。。）
（なんか画面汚い、、、？）

|機材|製品|料金|
|--|--|--|
|PC本体|ThinkPad X280| 8万くらい|
|左のモニター|BenQ|ジモティーで3000円|
|キーボード|バッファロー|大学の時に使ってた|
|真ん中のモニター|PHILIPS|楽天で10000円くらい|
|マウス|バッファロー|大学の時に使ってた|
|PCスタンド|？？？|楽天で1500円くらい

# 新環境

## 全体像

こんな感じになりました。

![全体 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951272/4830cc4d-2f44-9388-8b98-d5344ffe24c8.jpeg)

基本的には元通り、キーボードが少し小さくなりました。


## 周辺機器
PCの周辺機器はこんな感じです。

![PC2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951272/0feb4fd6-04e9-07cd-5bb0-2b8aacb7bcb7.jpeg)

- 上：真ん中の**モニター**に繋がるHDMIケーブル電源ケーブル
- 上から二つ目：**電源ケーブル**
- 上から三つ目：**マウス**に繋がるUSBケーブル
- 上から四つ目：左の**モニター**に繋がるUSB-HDMI変換ケーブル
- **キーボード**はBluetoothです。

新しく買い足したのはこんな感じです。

|機材|製品|料金|
|--|--|--|
|PC本体|[MacBook Air](https://www.apple.com/jp/shop/buy-mac/macbook-air/%E3%82%B7%E3%83%AB%E3%83%90%E3%83%BC-8%E3%82%B3%E3%82%A2cpu%E3%81%A88%E3%82%B3%E3%82%A2gpu%E3%82%92%E6%90%AD%E8%BC%89%E3%81%97%E3%81%9Fapple-m1%E3%83%81%E3%83%83%E3%83%97-512gb)<br>M1チップ メモリ16GB ストレージ1TB | 186,780円|
|ドック|[Anker 7 in 2](https://www.ankerjapan.com/products/a8371)|5,999円|
|USB-HDMI変換ケーブル|[Basicest](https://www.amazon.co.jp/Basicest-%E3%82%B0%E3%83%A9%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF-%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%83%BC-Displaylink-Win10%E5%AF%BE%E5%BF%9C%E3%80%90%E7%9B%B8%E6%80%A7%E4%BF%9D%E8%A8%BC%E4%BB%98%E3%81%8D%E3%80%91/dp/B015XESLTO)|6,290円|
|キーボード|[Anker](https://www.ankerjapan.com/products/a7726)|ラクマで1,000円

- MacBookのスペックは会社の推奨水準を満たすものです。これより金額を落とすとしたら、GPUを7コアにするとかかな、、、
- M1チップを搭載している場合は、DisplayLinkというものを利用しないとトリプルディスプレイにはできないようだったので、変換ケーブルを買いました。[この記事](https://yoshigadge.com/m1mac-triple-display/)をめちゃめちゃ参考にしましたが、変換ケーブルがまさかのもう売ってないそうで、代替品を探しました。
- ドックはAnkerの7 in 2というのを買いましたが、熱が直接伝わったりとか、カバーをしたいという場合は7 in 1という方を使う方も多いようです。
- もしくは最初から[Display Linkに対応しているドック](https://www.amazon.co.jp/WAVLINK-3-0%E3%83%89%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3-DisplayLink-%E6%9C%80%E5%A4%A7%E8%A7%A3%E5%83%8F%E5%BA%A62560-%E6%9C%80%E5%A4%A7%E8%A7%A3%E5%83%8F%E5%BA%A62048/dp/B083176BW8)を使うという手もあるようです。総額的にはこっちの方が安いかな？




# 合計金額
186,780 + 5,999 + 6290 = 199,069円
ギリギリ20万以内で収まりました。

キーボードは自腹かな。
ラクマだし、、、

（MacBookを買う時にポイントサイトを経由すると結構ポイントがつくとかなんとか、、、）

# ひとこと
誰かの何かの参考になれば嬉しいです。
M2チップ出なかったなあ。。。
プログラミングスクールのメンタリングでもらったアドバイス

私がプログラミングスクールのメンタリングでメンターの人からもらったアドバイスについてお話します。
# 分からないことは言語のドキュメントで調べたほうがいい
前提として、ググって調べるよりドキュメントを読んだほうが正確と言うことらしいです。
## その理由は？
メンターの人曰く、ググっても初心者向けの結果しか出てこない。
と言うことイコール情報が正確かは不明だと言うことらしいです。

確かにその側面はあります。どの言語でも調べれば、コードの書き方が出てきますが、
書き方は分かるけど、いまいちよくわからない部分もあります。

## ドキュメントは書いてあることが難しい場合がある。
初心者にとって、ドキュメントの内容が難しい場合があるそうです。
メンターの人は **ドキュメントで分からないことがあったらそれを検索せよ** と
言うことらしいです。

プログラミングはほぼ調べる作業なので、そういう理由なんでしょう。

# 私はと言うと
現在プログラミングスクールでPHPなどをしているので、PHPやLaravelのドキュメントをたまに読んでますが、分かる部分と分からない部分があります。Laravelについてはほぼわかりません。

# 結論
とにかく調べたほうがいいと言うことに落ち着きます。
第27回 DNS,Windowsネットワーク

4つのアドレス・最後の1つ
---
送信元MACアドレス・送信元IPアドレス・
宛先MACアドレスを学習してきた。最後は
「宛先IPアドレスをどうやって知るか」に
なる。

一番簡単な取得方法は、データ転送を望む
アプリケーションやユーザが宛先IPアドレ
スをすでに知っている場合だ。

「http://61.193.0.66/~aji/」ダイレクトにブ
ラウザのアドレス欄に打ち込むと「Roads 
to Node」ブラウザが表示される。

これは「Roads to Node」が置いてあるサー
バのIPアドレスが「61.193.0.66」だからこそ
こういったことが起こる。

IPアドレスは単なる数字であるため、覚えに
くく、だからドメイン名とホスト名が使われ
る。


DNS
---
ドメイン名とホスト名とは、送信をする相手
のコンピューターの名前を指す。

下記を例とすれば、「www5e.biglobe.ne.jp
」＝「http://61.193.0.66/~aji/」であれば、
「biglobe.ne.jp」という組織の、「www5e」
というコンピュータ、という意味になる。

組織名が「ドメイン名」、コンピューター名
が「ホスト名」となる。ドメイン名はユニー
クなため、ICANNと各地域のNICが管理してい
る。また、ホスト名もその組織の管理者が管
理する。

これにより、簡単に送信した相手のIPアドレ
スを覚えることができるようになった。そし
て、この「ドメイン名」「ホスト名」とIPア
ドレスを紐づけるのがDNSというシステムで
ある。

実際の取得方法としては、名前とIPアドレス
の対応データベースを持っているDNSサーバ
に対し問い合わせをし、データを転送したい
デバイスのIPアドレスを手に入れる。

DNSサーバは各組織に1つずつあり、その組織
のドメイン名やホスト名のみを管理している
。他の組織のドメイン名やホスト名が必要と
なれば、その組織のDNSサーバに聞く形をと　
る。

DNSとは、世界中のドメイン名・ホスト名を
管理する一種の分散型データベースのことを
指す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/35d45535-3452-5c6a-a0dc-6a51b2f24a6c.png)


細かい話は置いておき、機能性として一時保
存をすることができる。これは、同じところ
にデータ転送をするたびに何度も各組織に問
い合わせる手間を省くため。


Windowsネットワーク
---
LAN内の他のWindowsマシンの共有フォルダ
をIPアドレスなしでも共有することができる
。あくまでWindowsで作られたネットワーク
の話であるが、これをNetBIOS(ネットバイオ
ス)という。

NetBIOSだけでは、現在のTCP/IP環境に対応で
きないためNetBIOS over TCP/IPが使われている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/7bdbabcf-3bf7-3625-6a8f-17b4233357c9.png)


NetBIOSの機能をTCP/IPでも使えるようにし
たもの。これにより宛先IPアドレスを知るこ
とができる。

Windowsには、NetBIOSの機能があるコンピ
ューターが存在するがそのコンピューターをNetBIOS名という。

データ転送を行いたい場合、NetBIOS名とIP
アドレスを紐づける必要がある。

ARPと同様に、ブロードキャスト送信するこ
とによりIPアドレスを取得することができる。


4つのアドレス・完結編
---
まとめではあるが、
・送信元MACアドレスはNICを取り付けたら
　自動的に取得
・送信元IPアドレスは手動かDHCPによって
　割り振られ取得
・宛先IPアドレスは、ユーザもしくはアプリ
　ケーションが宛先のホスト名もしくはNet
　BIOS名を決定後、DNSかNetBIOS over TCP
　/IPで取得
・宛先MACアドレスはARPによって取得。

結果、データ転送が可能。

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
Railsを使ってアプリケーションを立ち上げる方法

# 結論
ターミナルで以下を入力
```
$ rails new アプリ名

#具体例
$ rails new hello_world
```
これで`hello_world`という名前のディレクトリが生成されます。その中にはrailsアプリを動かすために必要なファイルも生成されています。


## Railsバージョンを指定してアプリを立ち上げる場合
```
$ rails _20.2.2_new アプリ名
```

これでRailsのバージョンを指定することが出来ます。
実際に入力する際は、制作環境に応じたバージョンを入力してください。

## Railsバージョン,データベースを指定してアプリを立ち上げる場合
```
$ rails _20.2.2_new アプリ名　　-d DB名
```
これでrailsのバージョン、データベースを指定してアプリを立ち上げることが出来ます。実際には制作環境に応じたデータベース名を入力してください。
（任意のDB名を入力してください）
第26回 レイヤ3 ARP

4つのアドレス・おさらいのおさらい
---
送信先のMACアドレスの入手方法はNICを取
り付けた段階で分かる

送信先のIPアドレスは主に2種類あり、「静
的」「動的」がある。「静的IPアドレス」は
管理者によって教えてもらうアドレスで、「
動的IPアドレス」はDHCPによって自動で割
り振られるアドレスである。

残りは「宛先MACアドレス」「宛先IPアドレ
ス」。つまり、相手のアドレスを知る手段と
なる。今回は、宛先MACアドレスを知るため
のARPというプロトコルの説明を行う。


アドレス解決プロトコル
---
宛先MACアドレスを知る方法として、「ARP
(アープ)」がある。アドレス解決プロトコル
と呼ばれ、「宛先MACアドレスが分からない
」状態を「解決」してくれるプロトコル。

「ARP」は、宛先のIPアドレスが決定した時
点で実行される。
```
ーーーー「ARPが実行されるまでの流れ」ーーーー
ユーザー：「ワンピース」とネットに検索する
※ページの場所を探す
↓
PC：DNSが起動し、サーバーのIPアドレスを教えてもらう。
※この時点で、宛先のIPアドレス、
　送信元のMACアドレス、送信元のIPアドレスが分かっている
↓
ARP実行
ーーーーーーーーーーーーーーーーーーーーーーーーーーー
```

ARPテーブル
---
宛先IPアドレスが決定した時点で、宛先
MACアドレスを知るためにARPテーブル
を参照する。

ARPテーブルには、IPアドレスとMACアド
レスの対応表がありそれによって、決定す
る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/1dcd5549-32ca-ee8d-fa84-d878de6a31a0.png)


上記がそれにあたり、「IPアドレス」「IPア
ドレスのホストのMACアドレス」「ARPのエ
ントリのタイプ」が分かる。

宛先IPアドレスが「192.168.0.1」なら宛先MAC
アドレスは「00-40-f4-1a-02」

※cmdによって、自身のアドレス表を算出
```
C:\>arp -a 
インターフェイス: 192.168.11.7 --- 0x6 
  インターネット アドレス 物理アドレス           種類 
  192.168.11.1          58-27-8c-1a-6a-e0     動的 
  192.168.11.2          82-50-77-30-68-ca     動的 
  192.168.11.255        ff-ff-ff-ff-ff-ff     静的 
  224.0.0.22            01-00-5e-00-00-16     静的 
  224.0.0.251           01-00-5e-00-00-fb     静的 
  224.0.0.252           01-00-5e-00-00-fc     静的 
  239.255.255.250       01-00-5e-7f-ff-fa     静的 
  255.255.255.255       ff-ff-ff-ff-ff-ff     静的 
インターフェイス: 172.20.32.1 --- 0x41 
  インターネット アドレス 物理アドレス           種類 
  172.20.47.255         ff-ff-ff-ff-ff-ff     静的 
  224.0.0.22            01-00-5e-00-00-16     静的 
  224.0.0.251           01-00-5e-00-00-fb     静的 
  239.255.255.250       01-00-5e-7f-ff-fa     静的
```

上記に宛先IPアドレスがあれば、自動的に宛先
MACアドレスが分かる。ただ、その参照表にな
い場合は、自身で付け加える必要がある。

その時に、「IPアドレスのホスト、MACアドレ
スを教えて」と聞き、ARPテーブルに乗せる。
この「教えて」という動作を「ARP要求」とい
う。


ARP要求＆ARP応答
---
ARPはレイヤ3のプロトコルで、ARP要求は
IPを使わない。

IPの代わりにARPでデータの転送を行う。
(IPパケットの代わりに、ARPパケットを使う)

ARPパケットはそれ自体がデータであり、
上のレイヤのプロトコルを使わない。
(IPのように上のレイヤからセグメントをもらい、
 パケットにするということをしない)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/fa0d3e65-ac32-2d23-7a9d-4d103a549ecc.png)


実際のARPの動きとして、
```
・宛先にデータを転送しようとして、宛先IPアドレスがわかった後。 
1.ARPテーブルを参照し、宛先IPアドレスに対応するMACアドレスがあるかどうか調べる。 
2.なければARP要求をブロードキャスト送信する。 
3.ARP要求を受け取った各ホストは、ARPパケットの中の宛先IPアドレスと自分のIPアドレスを比較する。 
　→一致しなければ、無視。 
　→一致した場合、ARP応答を送信。 
4.ARP応答を受け取った(ARP要求を送った)ホストは、ARPテーブルにそのMACアドレスを追加する。 
・４つのアドレスがそろい、宛先へのデータ転送が可能になる。
```
<table>
<tr>
<th>バイト</td>
<th>名前</td>
<th>意味</td>
</tr>
<tr>
<td>4</td>
<td>アドレスタイプ</td>
<td>アドレスの方式を表す</td>
</tr>
<tr>
<td>2</td>
<td>アドレス長</td>
<td>アドレスの長さを示す</td>
</tr>
<tr>
<td>2</td>
<td>オペレーションコード</td>
<td>要求か応答かを示す</td>
</tr>
<tr>
<td>6</td>
<td>送信元MACアドレス</td>
<td>送信元のMACアドレス</td>
</tr>
<tr>
<td>4</td>
<td>送信元IPアドレス</td>
<td>送信元のIPアドレス</td>
</tr>
<tr>
<td>6</td>
<td>宛先MACアドレス</td>
<td>宛先のMACアドレス</td>
</tr>
<tr>
<td>4</td>
<td>宛先IPアドレス</td>
<td>宛先のIPアドレス</td>
</tr>
</table>
[Table26-01:ARPパケット]

ARPはあまり多発させないほうがよく、理由
としては、ブロードキャスト送信であるから
。

スイッチやブリッジのデバイスではブロード
キャストをフィルタリングできず、トラフィ
ックに影響を及ぼしやすい。

ブロードキャストを多発しすぎるとネットワ
ーク全体が通信不能となる。
(=ブロードキャスト・ストームという)

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
第25回 レイヤ7 DHCP

4つのアドレス・おさらい
---
データの転送には、宛元のMACアドレス・
宛先のIPアドレス・送信元のMACアドレス
・送信元のIPアドレスの4つの情報が必要。

送信元のMACアドレスは、NICを取り付け
た段階で、決定される。送信元のIPアドレ
スは、2つのパターンによって決定される。

〇静的に決定されるパターン
これはネットワーク管理者によって決定さ
れる値を手動でパソコンに打ち出すケース
。

〇動的に決定されるパターン 
サーバーから通信を行い、自動的に決定す
るケース。この動的なIPアドレスの取得の
方法として、現在主流となっているのがDH
CP。


DHCP・概論
---
DHCPは、割り当てるIPアドレスを管理し
実際に割り当て作業を行うサーバーと割
り当ててもらうクライアントから成り立
つ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/63494578-0df7-c1aa-4055-f38dd6632a2b.png)


DHCPを行うサーバーをDHCPサーバーと
いいDHCPサーバーソフトを実行している
ホストを指す。

一方、クライアントはDHCPクライアント
といい、DHCPクライアントソフトを実行
する。



DHCP・承前
---
自動的に割り振る際に事前にいくつか設
定する必要があるものがある。

・IPアドレスの範囲設定
・リース期限の設定

〇IPアドレスの範囲設定
どの範囲のアドレスをホストに割り振っ
ていくかの設定である。この範囲のこと
をIPアドレスのプールという。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/0e481818-a09f-9b80-4a74-7fbe7321e186.png)

〇リース期限の設定
”割り当てる”というよりも実際は”貸し出
す”という表現のほうが近く、期間を設け
てIPアドレスを割り当てる。期間は管理者
によって変動する。


DHCP・メッセージ
---
サーバーとクライアントがやりとりする際
に使うのがDHCPメッセージ。カプセル化
される前のデータと同義。
<table>
<tr>
<th>バイト数</th>
<th>名前</th>
<th>説明</th>
</tr>
<tr>
<td>1</td>
<td>オペレーションコード</td>
<td>クライアント→サーバ…1<br>サーバ→クライアント…2</td>
</tr>
<tr>
<td>1</td>
<td>ハードウェアタイプ</td>
<td>10Mイーサネット…1</td>
</tr>
<tr>
<td>1</td>
<td>ハードウェアアドレスタイプ</td>
<td>10Mイーサネット…6</td>
</tr>
<tr>
<td>1</td>
<td>リレーエージェントhop数</td>
<td>リレーエージェントの経由数</td>
</tr>
<tr>
<td>4</td>
<td>トランザクションID</td>
<td>一連の通信で使用される識別番号</td>
</tr>
<tr>
<td>2</td>
<td>経過時間</td>
<td>クライアイントの初期化後の時間</td>
</tr>
<tr>
<td>1</td>
<td>フラグ</td>
<td>ブロードキャスト・フラグ</td>
</tr>
<tr>
<td>4</td>
<td>クライアントIPアドレス</td>
<td>現在のクライアントのアドレス<br>(再リース時のみ)</td>
</tr>
<tr>
<td>4</td>
<td>割り当てIPアドレス</td>
<td>サーバが割り当てたアドレス</td>
</tr>
<tr>
<td>4</td>
<td>サーバIPアドレス</td>
<td>サーバのアドレス</td>
</tr>
<tr>
<td>4</td>
<td>DHCPリレーエージェントアドレス</td>
<td>リレーエージェントのアドレス</td>
</tr>
<tr>
<td>16</td>
<td>クライアントハードウェアアドレス</td>
<td>クライアントのMACアドレス</td>
</tr>
<tr>
<td>64</td>
<td>サーバ名</td>
<td>サーバのホスト名</td>
</tr>
<tr>
<td>128</td>
<td>ブートファイル名</td>
<td>ブートファイルの名前</td>
</tr>
<tr>
<td>可変</td>
<td>オプション</td>
<td>クライアントのその他設定</td>
</tr>
</table>

[Table25-01:DHCPメッセージ]

メッセージの中にある、「オプション」が
DHCPが主流となった要因でそのほかのネッ
トワークの設定情報を送ることができ、動
的ホスト設定プロトコルと呼ばれる。


DHCP・割り当て動作
---
DHCPサーバーとDHCPクライアントのやり
とりは下記のように流れる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/cf3c4729-3b09-b290-3567-dc0627c78259.png)

```
1. クライアントがサーバを発見するためDHCPDISCOVERを送信
2. DHCPDISCOVERを受け取ったDHCPサーバは、割り振る候補のアドレスをDHCPOFFERで送信
3. DHCPOFFERを受け取ったクライアントは要求するIPアドレスをDHCPREQUESTで送信
4. DHCPREQUESTを受け取ったDHCPサーバは、要求を認めるならDHCPACKを送信。駄目ならばDHCPNAKを送信。
5. DHCPACKを受け取ったクライアントは、そのIPアドレスを設定する。DHCPNAKなら再度DHCPREQUESTを送信。
```
このやりとりの際に重要なことは「ブロー
ドキャスト送信」を使っていること。クラ
イアント側はアドレスは未定のため、
「0.0.0.0」を使う。

クライアント側にIPアドレスがないため、
サーバ側は必ず受け取ってもらうためブロ
ードキャストを使う。


DHCPの・リース期限
---
リース期間が短すぎる場合、リース期間の
延長を申し出ることができる。その際、下
記のようなフレームを送信する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/88ba8cb8-2cda-5f79-81e5-42c53c207ac5.png)

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
【CSP】OWASP ZAP で Wildcard Directive がでて困った

# はじめに

OWASP ZAP の診断をすると `CSP: Wildcard Directive` で怒られるのですが、その原因がわからずに時間を使ってしまいました。
原因と対策を書いて供養します。

# 原因

### 原因１

`form-action` が書かれていませんでした。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action

`form-action` は指定されていないと `form` タグの `action` が自由に実行されてしまいます。
XSS につながって危ないです。

指定されていない directive はすべて `default-src` に fallback されると思っていたので、調査に時間がかかりました。今回のように fallback されない directive もあるんですね。

### 原因２

docker 版の OWASP-ZAP を html に出力してテストしていたのもよくなかったです。

docker 版は手軽に利用できていいのですが、エラー内容が不親切でした。

ちゃんと PC にインストールして実行すると、詳しいエラー内容を教えてくれました。

# 対策

`form-action` は `default-src` に fallback されないので、直接指定します。

```
form-action 'self';
```

あと、めんどくさがらずにインストールしましょう。

# 他の fallback されない directive たち

おまけで、おなじく fallback されないものを列挙します。
この顔にピンときたら、、、。

### base-uri

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri

### form-action

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/form-action

### frame-ancestors

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors

### navigate-to

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/navigate-to
【chai】chaiのassertメモ

**chai**の``assert``を自分が使用したものを中心にメモしておく。
今回紹介しなかったものは、次のサイトを参照。【参考：[https://www.chaijs.com/api/assert/](https://www.chaijs.com/api/assert/)】

# assert.equal()
実際の値と期待値が等しい(``==``)かチェックする。これの否定(``!=``)の場合は、``.notEqual()``になる。
```javascript
assert.equal(<実際の値>,<期待する値>)
```
また、JavaScriptでの``===``としてチェックしたい場合は``.strictEqual()``で、これの否定(``!==``)が``.notStrictEqual``となる。

# assert.isTrue() / .isFalse()
値が``ture``または``false``であるかチェックする。この否定がそれぞれ``.isNotTrue() / .isNotFalse``
```javascript
assert.isTrue(<値>)
```

# assert.instanceOf()
値がコンストラクタのインスタンスであるかチェックする。これの否定が``.notInstanceOf``となる。
```javascript
assert.isTrue(<値>,<コンストラクタ>)
```

# assert.isfail()
テストの失敗を投げる。下記サンプルのメッセージは省略することもできる。
```javascript
assert.isfail(<メッセージ>)
```

# assert.isNull()
値が``null``であるかチェックする。これの否定が``.isNotNull``となる。
```javascript
assert.isNull(<値>)
```

# assert.exists()
値が``null``または``undefined``ではないことをチェックする。これの否定が``.notExists``となる。
```javascript
assert.exists(<値>)
```
OHHTTPStubsでリダイレクトがうまくいくかどうかの単体テストは書かないほうがいい

リダイレクト処理がうまくいくことを保証するためにOHTTPStubsを利用して単体テストを記述しました。
僕の場合はローカル環境ではうまく動くのですが、パイプラインのVM上でその単体テストを動かそうとするとまれに失敗することがありました。

下記のIssueがそれに対応するようです。

https://github.com/AliSoftware/OHHTTPStubs/issues/230

非常に残念ですが、リダイレクトについては単体テストで担保しないか、OHHTTPStubsを用いないで実装するしかなさそうです。

ただ先輩に教えていただいたとおり、基本的にはURLSessionがリダイレクトの機能を持っているため、単体テストで担保する必要はないとは思います。

もしiOSのリダイレクトの挙動についての品質保証をどうされているか知見がある方がいらっしゃれば教えていただきたいです。
開発前の準備「とにかくローカルに表示する！プロジェクトに参加していく！」

<br>

#### 【この記事を読むのは、こんなことに困った時】

 ・プロジェクトに参加するために環境構築するけど流れがわからない
 ・すでにリモートにあるプロジェクトをローカルに用意したい
 ・クローンしたあと必ずすることnpm install

---

#### 【環境構築手順メモ　ーⅠ】

###### ＜前提＞
PC：Windows
Webサーバー：IIS
言語：html css C# PHP JS TS
作成：HP
その他：リモートからプロジェクトをクローン

###### ＜きっかけ＞
サイト引継ぎの際の環境構築。

<br>

---

#### 【手順の流れ】

➀ ローカルにプロジェクトを用意する　◀今回はここ！
➁実行環境の導入（npm install）  　 ◀今回はここ！
➂IIS（ローカルサーバー）の設定
➃サイト表示の確認
➄画像がコード管理から外されている場合はダウンロード（git管理下ならこの作業は不要）

<br>

---

#### 【手順】
#### 「➀ローカルにプロジェクトを用意する」

###### 1. 保存したい場所にプロジェクト用の空ファイルを新規作成
　 　※これは好みですが練習なら練習用ファイル、複数人との共同開発ならそろえた場所にあってもいいかもです。

```.例（個人）
・C:/プロジェクトファイル（Windows）
・User/プロジェクトファイル（Mac）
・デスクトップ上
　　　　　　　　　　　　　　　　　　　　　...など
```


###### 2. リモートからプロジェクトをクローン
　　・リモート（GitHub、BitBucketなどコード管理システム）からgit clone用のURLをコピーしてくる
      （「例：git clone https://xxx@クローン元サイト/xxx/xxx.git」 こんなのがプロジェクトのところにあるはず！)

###### 3. ターミナル（もしくは、コマンドプロンプト）を開く
　　・1.で用意した空のプロジェクトファイルに移動（コマンド：　cd 移動したいファイル名）

```.例（windows）
 cd Desktop
```

###### 4.移動できたらコピーしたURLを貼ってクローン

<br>
<br>
<br>



#### 「➁実行環境の導入（npm install）」

###### 1. ➀で用意したプロジェクトをVScodeで開いてそのターミナルでコマンド「npm install」

###### 2.これでgulpのモジュールが使えるようになったので「npx gulp」が使えるようになる。

<br>
<br>
<br>


---

#### ➀、➁のりローカルでの用意はここで完了！
###### 次回[【➂IIS（ローカルサーバー）の設定】](https://qiita.com/kusaharajiji/items/abb20f7da971bc032f9e#iis%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9A)です。
※注意IISはWindowsでのみ使えるサーバーです。
※筆者はMacでの開発も行っております。IIS代替えとしてMAMPを使用しておりますので、別記事で追記予定です。

<br>

---


#### 【気になるワード】---記事内でより理解を深めたいワード
 
- [Node.js(npm)とはなにもの？](https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb)

- デバッグとnpx gulp（タスクランナー）の違い
　※どちらもサイトなどの実行でサイトが見られるようになるという感覚
 - [ビットバケットってなにもの？](https://siderlabs.com/blog/ja/3-major-git-platforms/)
React router v6 で route にパラメータを渡したい（クエリパラメータ編）

# React router v6 でクエリパラメータを渡す
初心者が調べながらやっています。間違っていたら教えてください。
## 目的
+ あるページを表示するComponentがある
+ そのComponentに動的なパラメータ（ユーザが指定）を渡して表示をしたい

## 少し詳しめに
+ React router v6を利用してページを切り替えている
+ ページを切り替えるときについでにパラメータを渡すのが props で渡すより楽かなと思った
+ 現時点ではApp.tsxという一番根本のところでRouteを設定している
+ なので、最初にGUIからユーザの希望するパラメータを設定するためにはApp.tsxのRouteはできるだけパスだけにしておいて
+ あとからパラメータを設定できるようにしないといけないと思った

このあたり、勉強したらもしかしたらもっとよい解決方法があるかもしれない。

## 今回試した方法
+ React router v6 
+ Routerを利用してComponentへのリンクを定義
+ navigate(useNavigate())でリンク先へ移動するときのアドレスにパラメータを入れる
+ それをComponent側で受け取って処理を進める


# Router の設定自体は普通のままで大丈夫
```
<Route path="/results" element={<Results />} />
```

# これでリンクをナビゲートするときにパラメータを渡すのが以下
やりたいことはリンク先に username と subject を渡すということ
(JavaScript の　テンプレートリテラルを利用して呼び出す側で定義しているパラメタをリンクに含めてあげる)
```
navigate(`/results?username=${selectedUser.name}&subject=${subject}`);
```

# Component側でクエリパラメータを解釈する仕組みを以下のように実装した
```
import { useSearchParams } from "react-router-dom";

export const Results = () => {
　// こういうhooksがあるらしい
  const [searchParams] = useSearchParams();
  const username = searchParams.get("username");
  const subject = searchParams.get("subject");

  console.log("Username=" + username);
  console.log("Subject =" + subject);

  return (
    <>
      <h1> Hello {username}</h1>
      <h1> Your quiz results of {subject}</h1>
    </>
  );
};

```

これで無事にResultsコンポーネントにパラメータ username と subject を渡すことができた。
第24回 4つのアドレス

データ転送に必要なもの
```
〇LANでのデータ転送に置いてのカプセル化について
レイヤ4からセグメントが渡される
※使用プロトコルはIP。使用アーキテクチャはイーサネット。
↓
IPにIPヘッダを取り付ける
↓
IPをパケットにする
↓
レイヤ2に渡して、イーサネットのヘッダとトレーラーをつける
```
また、データ転送においてIPヘッダと
イーサネットヘッダの共通点として、
送信元と宛先、それぞれMACとIPの4
つのアドレスが必要となる。


送信元MACアドレス
---
MACアドレスは、NICを取り付けた段
階で認識されるもので勝手に決まる。


送信元IPアドレスの静的な決定
---
送信元IPアドレスは、誰かに割り振って
もらう必要がある。具体的には、ネット
ワーク管理者によって割り振られる。

割り振られたIPアドレスをダイレクトに
入力するIPアドレスを「静的IPアドレス」
という。

静的IPアドレスには、欠点がありそれは
ネットワークを別に移動させた際に、何
度もIPアドレスを入力する必要があると
いうこと。管理が煩雑で、非常に面倒。


送信元IPアドレスの動的な決定
---
前述したように、ある程度の台数を管理
するLANや、頻繁にデバイスの移動が起
こるLANでは「動的IPアドレス」を使用
するのが一般的である。

ネットワークに接続された時点で、自動
的にIPアドレスが決定される形をとる。

具体的には、IPアドレスを管理している
サーバに対して、「IPアドレスをくださ
い」といい、IPアドレスをもらう。

一見、IPアドレスをもらうためにIPアド
レスを管理しているサーバに通信を行う
ことが矛盾に思えるが、それを解決する
のがDHCPと呼ばれるプロトコル。

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
Google Drive API を使って Jamboard ファイルを PDF 出力する

2022/3/25 時点で Jamboard のデベロッパー向け API がなく、システム間連携する方法を見つけるのに苦労したので、備忘録として記事にしておきます。Google Drive API を使って PDF 出力ができました。

## 作ったもの
![download-jamboard-using-drive-api.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/9a8ef8f3-7cbc-bb0e-dfef-42c779350bae.gif)

## 実現方法
Jamboard ファイルは [Google Drive API の Files: export](https://developers.google.com/drive/api/v3/reference/files/export) を利用して PDF 形式でダウンロードできます。今回は npm の [googleapis](https://www.npmjs.com/package/googleapis) パッケージを用いて実装し、 API 認証にはサービスアカウントを利用しました。

## サービスアカウントの設定
まず API 認証のために Cloud Console 上でサービスアカウントを作成します。Jamboard ファイルが格納されているフォルダの共有設定からサービスアカウントに対して閲覧権限を付与します。（ファイル単位でも良いですが、今回の実装の都合上フォルダに対して権限を付与しています）

![スクリーンショット 2022-03-25 14.16.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19698/adc1958e-b7d0-fa61-b243-f67302ad2083.png)

## 実装

Google API に対する認証を行います。事前に JSON 形式でダウンロードしたサービスアカウントキーの相対パスを記載します。

```JavaScript
const { google } = require("googleapis");

const auth = new google.auth.GoogleAuth({
  keyFile: "./serviceAccount.json",
  scopes: ["https://www.googleapis.com/auth/drive.readonly"],
});
const drive = google.drive({ version: "v3", auth });
```

`drive.files.list` メソッドでファイル一覧を取得します。今回は Google Docs や Google Slide などのファイルも同様の仕組みでダウンロードしたかったので特定のフォルダ配下のファイルを一覧取得しました。

```JavaScript
const q = `'${folderId}' in parents`;
const res = await drive.files.list({ q });
const files = res.data.files;
```

`drive.files.export` メソッドで対象のファイルを PDF 形式でダウンロードします。出力形式として `mimeType` を指定できますが、 Jamboard の場合 `application/pdf` 以外で有効な値を見つけられませんでした。

以下のページでいずれ情報公開されるんじゃないか、と思っているリンクを貼っておきます。
https://developers.google.com/drive/api/guides/ref-export-formats

```JavaScript
async function download(file) {
  const destPath = path.join("./dst", `${file.name}.pdf`);
  const dest = fs.createWriteStream(destPath);
  const res = await drive.files.export(
    { fileId: file.id, mimeType: "application/pdf" },
    { responseType: "stream" }
  );
  await new Promise((resolve, reject) => {
    res.data
      .on("error", reject)
      .pipe(dest)
      .on("error", reject)
      .on("finish", resolve);
  });
}
```

以上です。

全ソースコードは [tanabee/google-drive-downloader](https://github.com/tanabee/google-drive-downloader) に置きましたのでご参考ください。
第23回 レイヤ3 サブネッティング

プライベート・アドレス
---
ネットワーク機器はクラスフルアドレッシン
グを前提に作られていることが多く、ネット
ワークに接続しないからといってビット数や
番号を適当につけていいというわけではない。

そのため、そういったIPアドレスをネットワ
ーク・デバイス、特にルータは、マルチキャ
スト用アドレスと認識する。

インターネットに接続しないLAN、WANや直
接接続しない内部ネットワーク（NATを使っ
てインターネットと接続するLANのこと）は
プライベートIPアドレスを使う。
<table>
<tr>
<th>クラス</th>
<th>第１オクテット</th>
<th>第２オクテット</th>
<th>第３オクテット</th>
<th>第４オクテット</th>
</tr>
<tr>
<td>Ａ</td>
<td>ネットワーク番号</td>
<td colspan=3>ホスト番号</td>
</tr>
<tr>
<td>Ｂ</td>
<td colspan=2>ネットワーク番号</td>
<td colspan=2>ホスト番号</td>
</tr>
<tr>
<td>Ｃ</td>
<td colspan=3>ネットワーク番号</td>
<td>ホスト番号</td>
</tr>
<tr>
<td>Ｄ</td>
<td colspan=4>マルチキャスト用</td>
</tr>
<tr>
<td>Ｅ</td>
<td colspan=4>研究用</td>
</tr>
<tr>
</table>

[Table23-01:プライベートアドレス]
プライベートIPアドレスは合計273個存在し、
プライベート用に予約されているため、NIC
に割り振らない。

プライベートIPは、インターネットに接続し
ない環境で使われるアドレスで、万が一イン
ターネットと接続できる状況になってもルー
タがインターネット上に流さないように止め
る。


小さなネットワーク
---
論理アドレスは階層型であり、これが大きな
メリット性を持つ。仮に大規模ネットワーク
を構築するとなった場合、例えば、800万人
のホスト番号を割り振るとなった場合、大規
模ネットワークを小規模ネットワークに分割
することで管理しやすくする。これをサブネ
ットワークという。


サブネットサブネットワーク
---
サブネットワークに分割するため、IPアドレ
スの内、ホスト番号のビットを、サブネット
番号とホスト番号に分割する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/499beaaf-1746-683e-cf4b-402f1c908a15.png)

上記のようにIPアドレスをサブネットワーク
に分割可能。ネットワーク番号はNICより割
り振られた番号なため変更できないが、ホス
ト番号はネットワークの管理者が独断で調整
できる。

<table>
<tr>
<th rowspan=2>第１オクテット</th>
<th rowspan=2>第２オクテット</th>
<th rowspan=2>第３オクテット</th>
<th colspan=2>第４オクテット</th>
<th rowspan=2>サブネットの数</th>
<th rowspan=2>各サブネットのホストの数</th>
</tr>
<tr>
<td>サブネット</td>
<td>ホスト</td>
</tr>
<tr>
<td rowspan=9>11000000</td>
<td rowspan=9>10101000</td>
<td rowspan=9>01100100</td>
<td>-</td>
<td>00000000</td>
<td>0個</td>
<td>254個</td>
</tr>
<tr>
<td>0</td>
<td>0000000</td>
<td>2個</td>
<td>126個</td>
</tr>
<tr>
<td>00</td>
<td>000000</td>
<td>4個</td>
<td>62個</td>
</tr>
<tr>
<td>000</td>
<td>00000</td>
<td>8個</td>
<td>30個</td>
</tr>
<tr>
<td>0000</td>
<td>0000</td>
<td>16個</td>
<td>14個</td>
</tr>
<tr>
<td>00000</td>
<td>000</td>
<td>32個</td>
<td>6個</td>
</tr>
<tr>
<td>000000</td>
<td>00</td>
<td>64個</td>
<td>2個</td>
</tr>
<tr>
<td>0000000</td>
<td>0</td>
<td>128個</td>
<td>0個</td>
</tr>
<tr>
<td>00000000</td>
<td>-</td>
<td>256個</td>
<td>0個</td>
</table>

[Table23-02:クラスCアドレスのサブネット化] 

見てわかる通り、ホスト1ビット残っている
のに、ホスト数0となっているのは、ネット
ワークアドレスとブロードキャストアドレス
が存在するため。

つまり、ネットワーク内の管理者によって定
義されていたとしても前回のルールは適応さ
れる。(ネットワークアドレスとブロードキャ
ストアドレス)


サブネットマスク
---
どのネットワークに属しているかは経路選
択の際に非常に重要なこと。

ルータはネットワークアドレスを元に経路
選択をする。つまり、IPアドレスのどこま
でがネットワークを表すかはインターネッ
トワークでとても重要なこと。

現状、クラス・サブネットワーク、ネット
ワーク番号が区切りとして存在するが、サ
ブネットワークは管理者によって決められ
るため、属人化している。

つまり、ルータは確定された情報を得にく
い。だから、サブネットを使用する際、サ
ブネットマスクをIPアドレスと同時に表記
する必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602995/cd529e8f-3b42-dd6a-3f2b-43e69adc4826.png)


「255.255.252.0」がサブネットマスクと呼
ばれ、つまり、ネットワーク番号とサブネ
ット番号のビットがすべて1、ホスト番号を
0にしたものがサブネットマスク。

参照URL：
<a href="http://www5e.biglobe.ne.jp/~aji/3min/">3分間ネットワーキング</a>
（< EF Core 7.0）C# null許容参照型を有効にした場合のEF Core DbSet<T>の書き方

# 追記 

[Null 許容参照型の使用 - DbContext と DbSet](https://docs.microsoft.com/ja-jp/ef/core/miscellaneous/nullable-reference-types#dbcontext-and-dbset)
> EF Core 7.0 以降では、この警告は抑制されます。

とのことなので、EF Core 7.0 未満を使用していた時代の記録となりました。
~~いやでもこういうのアップデートする工数とかなかったりしますよね~~

# はじめに

C# 8 から導入されたnull参照許容型ですが、VS2022で新しいプロジェクトを作成するとデフォルトで有効になるようです（私の環境では）。
そこで、既存プロジェクトを参考にEntityFrameworkCoreのDbContextを作っていたところ、少々引っかかったところがあったので備忘録として残しておきます。

# 現象

いつものように`DbContext`に`DbSet<T>`を記載していたのですが……
``` cs
public class MyDbContext : DbContext
{
    public DbSet<User> Users {get; set;}
}
```
ここで `Users`には破線が表示され、以下の警告が表示されます。

> CS8618 null 非許容のフィールドには、コンストラクターの終了時に null 以外の値が入っていなければなりません。Null 許容として宣言することをご検討ください。

とは言っても、ここに値をセットするのは自分じゃあないし……。と思いつつ、当初は以下のように`null`許容して対応していました。
``` cs
public DbSet<User>? Users {get; set;}
```
でもこれでは参照する側で`null`を考慮した記述をしなきゃならず、ちょっとモヤる感じに。


# 解決

公式にちゃんと書いてありました

[Null 許容参照型の使用 - DbContext と DbSet](https://docs.microsoft.com/ja-jp/ef/core/miscellaneous/nullable-reference-types#dbcontext-and-dbset)

以下のように記載しましょう、とのことです。

``` cs
public class MyDbContext : DbContext
{
    public DbSet<User> Users => Set<User>();
}
```

これでちゃんと警告なく動くようになりました。以上、万々歳。

# 追記：Null 免除演算子を使用する方法
コメントより、以下の方法でも可能との指摘を受けました。

``` cs
public class MyDbContext : DbContext
{
    public DbSet<User> Users  {get; set;} = Null!;
    // または
    // public DbSet<User> Users  {get; set;} = default!;
}
```

テーブルからリバースエンジニアリングでコードを生成した場合はこちらが使用されるようです。
この方法は自分もBlazorでは以下のように使用したので、この方法もありですね。
``` cs
    // ExampleRazor.razor.cs
    public partial class ExampleRazor
    {
        [Inject]
        HogeService HogeService { get; set; } = default!;
    }
```
pyenvでPythonのversionが切り替わらない！

## 状況

Homebrewを使用して、pyenvをインストールした後、
pyenvでPythonの3.6.5をインストールしました。

```:ターミナル
% python -V
Python 2.2.5

% pyenv global 3.6.5

% pyenv versions
  system
* 3.6.5 (set by /Users/user/.pyenv/version)

% python -V
Python 2.2.5
```
pyenvでバージョン3.6.5をglobalで設定してもバージョンは2.2.5を参照しており
pyenvを使ったPythonのバージョンを切り替えることができていません。

## 対処法: シンボリックリンクの再関連付け

下記ディレクトリの中にpython-buildがあるか見る
```:ターミナル
/usr/local/Cellar/pyenv/2.2.5/bin/
```
もしあれば、下記コマンドで再度関連づけしてみる
```
% brew unlink pyenv && brew link pyenv
Unlinking /usr/local/Cellar/pyenv/2.2.5... 5 symlinks removed.
Linking /usr/local/Cellar/pyenv/2.2.5... 5 symlinks created.
```
できた！
```
% python -V
Python 3.6.5
```

## ※参考: Path再確認
上記の方法でダメだった場合、念のため以下のことも確認してみてください。

下記のpyenvに関する記述があるか再確認する。
```:~/.zshrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
```
環境変数を書き換えたあとは下記コマンドをターミナルで実行し、Pathを通します。
```:ターミナル
% source ~/.zshrc
% exec $SHELL -l　
```

## 反省
おそらく今回Pythonの3.6.5を入れるために
一度Pythonをアンインストールして、pyenv経由で入れ直したのですが
Python関係の不要なシンボリックリンクが残っていたせいでうまく行かなかった模様。

あとは単純に環境変数を書き換えたあとにターミナル再起動をしていなかったりで
時間をとってしまったので、忘れないようにしたいものです。

## 参考元
[Pyenv を入れた後、”command not found” で Python がインストールできない時の対処](https://dev.classmethod.jp/articles/pyenv-command-not-found/)
$thisについて

$thisは自身のクラスのオブジェクトを指している。
$thisを使うことで自身のクラスで設定しているプロパティにアクセスできる。
動的（インスタンス）メソッドとして利用可能。
静的（スタティック）メソッドでは利用できない。

# 参考記事
https://techacademy.jp/magazine/35967
https://www.m5a.jp/this.html
https://qiita.com/vanshi/items/488845780a3a8ffa90bb
Cloud Pak for Data as a Serviceがサポートするデータソース

この記事では、IBM Cloud の Cloud Pak for Data as a Service がサポートするデータソースに関するマニュアルのリンクを紹介します。
CP4DaaSと言っても、Watson Knowledge Catalog 関連のものをご紹介します。

WKCでは、使う機能/サービスによってサポートされるデータソースが微妙に異なります。
マニュアルから探すのが手間なので、サポートされるデータソースに関して抜粋して備忘録として記載します。

Watson Knowledge Catalog for CP4D については[こちら](https://qiita.com/nax/items/2b6007688302becfd930)。

## CP4DaaS がサポートするデータソース

https://dataplatform.cloud.ibm.com/docs/content/wsj/manage-data/conn_types.html?audience=wdp

## Watson Queryでサポートされるデータソースとデータタイプ

https://dataplatform.cloud.ibm.com/docs/content/dvaas/dv_supported_data_sources.html?audience=wdp


### Data Refineryでサポートされるデータソース

明記されているサイトが見つかがらず取りあえすこれをメモしておきます。

https://dataplatform.cloud.ibm.com/docs/content/wsj/refinery/refining_data.html?audience=wdp

### Metadata Import / Metadata Enrichmentがサポートされるデータソース

https://dataplatform.cloud.ibm.com/docs/content/wsj/governance/connections-mdi-mde-dq.html?audience=wdp&locale=en

### データのプレビューがサポートされているファイル

https://dataplatform.cloud.ibm.com/docs/content/wsj/getting-started/previews.html?audience=wdp&locale=en#files

### プロファイルがサポートされている資産タイプ

https://dataplatform.cloud.ibm.com/docs/content/wsj/getting-started/profile.html?audience=wdp&locale=en

## お断り
このサイトの掲載内容は私自身の見解であり、必ずしも所属会社の立場、戦略、意見を代表するものではありません。 記事は執筆時点の情報を元に書いているため、必ずしも最新情報であるとはかぎりません。 記事の内容の正確性には責任を負いません。自己責任で実行してください。
Watson Knowledge Catalog for CP4Dがサポートするデータソース

この記事では、Watson Knowledge Catalog for CP4Dがサポートするデータソースに関するマニュアルのリンクを紹介します。

WKC for CP4Dでは、使う機能/サービスによってサポートされるデータソースが微妙に異なります。
マニュアルから探すのが手間なので、サポートされるデータソースに関して抜粋して備忘録として記載します。

IBM Cloud版 の Watson Knowledge Catalog については[こちら](https://qiita.com/nax/items/baf7fa31de9a6eb002a9)。



## WCK（Watson Knowledge Catalog）がサポートするデータソース

https://www.ibm.com/docs/en/cloud-paks/cp-data/4.0?topic=data-supported-sources

それぞれのデータソースに対してサポートされるサービスが異なります。


## ~~クイック・スキャンや自動ディスカバリーがサポートするデータソース~~
~~https://www.ibm.com/docs/en/cloud-paks/cp-data/4.0?topic=data-discovering-assets~~
~~データソースに応じて、クイック・スキャンがサポートされていなかったりするので要注意です。~~
~~また、データソースによっては、専用コネクターが存在するも、ディスカバリーでは使えない、などもあります。~~
~~例えばSnowflake~~
~~Snowflakeは専用のコネクターを持っていますが、ディスカバリーはGeneric JDBC（汎用JDBC接続）しかサポートされていません。~~

:::note info
メタデータ・インポートとメタデータ・エンリッチメントの機能が登場したことにより、従来の機能が非推奨になりました。
:::

## メタデータ・インポートやメタデータ・エンリッチメントがサポートするデータソース

https://www.ibm.com/docs/en/cloud-paks/cp-data/4.6.x?topic=data-supported-connection-types

## Data Virtualizationでサポートされるデータソースとデータタイプ

https://www.ibm.com/docs/en/cloud-paks/cp-data/4.0?topic=sources-supported-data


### Data Refineryでサポートされるデータソース

https://www.ibm.com/docs/en/cloud-paks/cp-data/4.0?topic=data-supported-sources-refinery

:::note warn 
注意
上記のCP4Dのマニュアルは常に最新バージョンに関する情報が掲載されます。
過去のバージョンについては以下から確認してください。
https://www.ibm.com/docs/en/cloud-paks/cp-data/4.0?topic=versions-documentation-previous-40x-refreshes
:::

## お断り
このサイトの掲載内容は私自身の見解であり、必ずしも所属会社の立場、戦略、意見を代表するものではありません。 記事は執筆時点の情報を元に書いているため、必ずしも最新情報であるとはかぎりません。 記事の内容の正確性には責任を負いません。自己責任で実行してください。
1-1_VirtualBoxインストール_CentOS設定

# Oracle VM VirtualBoxとは
既存のOS上で、別のOSを実行するために使用する仮想環境構築のためのオープンソースソフトウェア。複数のOSを同時に動作することやデータ間共有、またテスト用・学習用の環境を簡単に用意することができる。
表題1-xxで取り扱うVMに関する内容は学習用として記録していく。


# Oracle VM VirtualBoxのインストール


（1）VirtualBoxをインストール※今回使用するのはver6.1.18

・過去のインストーラ(※2021/12/28現在)

https://www.virtualbox.org/wiki/Download_Old_Builds_6_0

・最新(※2021/12/28現在)

https://www.virtualbox.org/wiki/Downloads

（2）拡張パッケージをインストール
・[All supported platform](https://www.virtualbox.org/wiki/Downloads)
　→USB2.0や3.0に対応できるようになる

（3）exeをクリック、デフォルトのままセットアップを完了させる。


# CentOSのインストール

下記サイトからCentOSのバージョンを選択。
今回は【CentOS-7-x86_64-DVD-2009.iso】を使用

https://www.centos.org/centos-linux/

※下記でも可能だが、インターネット設定等が必要
【CentOS-7-x86_64-Minimal-2009.iso】

# 仮想マシン作成

OracleVM VirtualBoxマネージャの「新規」ボタンを押下し
下記の通り、仮想マシンを新規作成する。

```rub
名前：ご自由に
マシンフォルダ：デフォルトのまま
タイプ：Linux
バージョン：Red Hat(64-bit)

メモリ：必要よりは大目に積むとよい
仮想ハードディスク：作成する
ハードディスクのファイルタイプ：VDI(Virtual Box Image)
物理ハードディスクにあるストレージ：可変サイズ
```

# CentOSの設定

※ここから先の操作でVMから抜けたい場合は、右側の[Ctrl]をクリック

（1）起動ハードディスクを選択【CentOS-7-x86_64-DVD-2009.iso】
（2）Install CentOSを[Enter]で選択
（3）ここから先は下記の通り登録する

```rub
言語：日本語
ソフトウェアのインストール：GNOME Desktop※
ネットワークとホスト名：DHCPをオン（オンオフをオンにするだけ）
インストール先：自動パーティション
```


# めも
nRF Connect SDK:タイマー

# タイマーはちょっとだけ扱いが違う
nRF SDK時代にはタイマーもペリフェラルの一つとして扱われており、TWIMやSPIMと同列にインスタンスを作って使っていました。これらのAPIはnRF Connect SDKでも残っており、Zephyrのお作法としてはあまり好ましくないと思われますが直接APIを叩くことで各種ペリフェラルを使うことができます。
TWIM

https://qiita.com/yoshihiro0709/items/bc4ccbf5beb475f37768

SPIM

https://qiita.com/yoshihiro0709/items/da74a06d35f6a36a4598

## タイマードライバーも同様に残っていますが・・・
タイマードライバーもTWIMやSPIMと同様に残っています。残ってはいるのですが・・・Zephyr OSが使っているため、ユーザーは使用することができません。厳密には使おうとするとFatal Errorを起こして動きません。
ですので、タイマーに関する一切の制御はZephyrの機能を使って実装することになります。

# タイマーAPI
ZephyrのAPI一覧はこちらです。

https://docs.zephyrproject.org/apidoc/latest/group__timer__apis.html

使うのはk_timer_start()とk_timer_stop()、そしてK_TIMER_DEFINEの3つだけだと思います。

# サンプルコード
0.5秒毎にHello Worldを表示し、3秒後にタイマーを停止します。

```main.c
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <sys/printk.h>

static void timer_stop_handler(struct k_timer *timer)
{
    printk("Finish!\n");
}

static void timer_handler(struct k_timer *timer)
{
    printk("Hello World! %s\n", CONFIG_BOARD);
}
K_TIMER_DEFINE(timer, timer_handler, timer_stop_handler);

void main(void)
{
    k_timer_start(&timer, K_NO_WAIT, K_MSEC(500));
    k_msleep(3000);
    k_timer_stop(&timer);
}
```

## 実行結果
こんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/340602/f9ac64be-1ed5-54a2-5943-68774961d05e.png)

# 余談
あれ、タイマーのことについて書いたと思っていたのに書いてなかった・・・。
そんなに難しくないですし、内容もZephyr寄りなのでこのくらいで(笑)。
Git HookでSpotlessとktlintを使った自動コードチェック

チームで開発する時に一律でフォーマット揃ってたり、
既存のコードも一律に綺麗にしたりを今後維持できるようにできたらいいなと思ったので
とりあえずやってみました。


## Git Hookとは

Gitでコマンドを実行する際に、前後でスクリプトを実行できるGitの機能。

今回使う`pre-commit`の場合、commitを行うとその前にスクリプトが実行され、
問題があればcommitを中止し、なければcommitを通すといったことが出来ます。

例としては
* commit時にテストを流す
* commit時にlinterでチェック、あるいはフォーマッターをかける
* 特定のブランチへのcommitを禁止(masterやdevelopなど)
* ...etc


## Spotlessとは

https://github.com/diffplug/spotless

Javaのコードチェック、フォーマットが出来るLinterです。
指定したフォーマットに従ってJavaのコードをいい感じにフォーマットしてくれます。


## Ktlintとは

https://github.com/pinterest/ktlint

こちらはKotlinのコードチェック、フォーマットが出来るLinterです。
公式の規約に沿っていい感じにしてくれるのと先述のSpotlessと連携ができるので、
JavaとKotlin両方をいい感じ(概念)に出来ます。

## 導入

### pre-commit

gitで管理されているプロジェクトであれば `.git/hooks` ディレクトリの中に、
`pre-commit.sample` というファイルがあるのでそれをリネームして使うでも作成するでもいいと思います。
`pre-commit`が`.git/hooks`の中にあればcommit時にスクリプトが呼ばれるようになります。

```
// 今回はとりあえず作りました
$ touch pre-commit
```

### Spotless,Ktlint

`build.gradle`にこんな感じで追加すると使えるようになります。
Spotlessの方はここでどのフォーマット形式を使用するかを指定します。
Ktlintは基本的に公式の規約に従うみたいです。
```gradle
apply plugin: "com.diffplug.spotless"

spotless {

    ratchetFrom 'origin/main'

    java {
        target "**/*.java"
        targetExclude("$buildDir/**/*.java")

        googleJavaFormat("1.14.0")
    }
    kotlin {
        target '**/*.kt'
        targetExclude("$buildDir/**/*.kt")

        ktlint("0.44.0").userData(['disabled_rules': 'no-wildcard-imports'])
    }
}
```
この状態だとデフォルトのルールが適用されますが、
コード内の下側に書いてある方法や`.editorconfig`を使うことでもルールのカスタムが出来たりします。


これでフォーマットとコードチェックが出来るようになりました。
```
// コードのフォーマット
$ ./gradlew spotlessApply
// コードのチェック
$ ./gradlew spotlessCheck
```

## pre-commitのスクリプト

`pre-commit`に記載するスクリプトですが、
普通に`./gradlew spotlessApply`してしまうと、
既存のコード全てにかかってしまう(ちゃんといつか全部やりたい)ので、
差分だけを抽出したものにフォーマットをかけていくことにしたのが以下。

```sh
set -e

# ステージングされた変更のあるファイルを抽出
# java,kotlinが対象
formatFileList="$(git --no-pager diff --name-status --no-color --cached | awk '$1 != "D" && $2 ~ /\.kts|\.java|\.kt/ { print $NF}')"

# 抽出したファイルに対してフォーマットを適用する
echo "spotlesscheck start..."
for filePath in $formatFileList
do
  ./gradlew spotlessApply -PspotlessIdeHook="$(pwd)/$filePath"
  echo "git add $filePath"
  git add "$filePath"
done;
echo "spotlesscheck finish."

```

これでcommit時に自動でフォーマッタをかけることはできるのですが、
`pre-commit`は`.git`配下のためgitで管理することができません。
なのでプロジェクトルートにpre-commitファイルを配置しておき、
gradleのタスクに`.git/hooks`へ配置させることでいい感じにならんかなということでこちら。

```gradle
task installPreCommitScript(type: Copy) {
    from new File(rootProject.rootDir, './pre-commit')
    into { new File(rootProject.rootDir, '.git/hooks') }
    fileMode 0775
}
```

これで他の人もリポジトリから取得してきた状態で下記を実行すれば`pre-commit`が使えるようになります。
```
$ ./gradlew installPreCommitScript
```
## まとめ

今回は自身がAndroidエンジニアだったためKotlinとJava向けの内容でしたが、
他の言語でも同じようなことは出来るのでGitHookは他でもいい感じに使えるんじゃないかなーと思います。
猫をCSSでスタイリングしたった

猫をCSSでスタイリングしてみました。

.cat {
    width: 100%;
    height: 100%;
}

![E5Cp6IvXEAE290K.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605262/70b5a042-0f29-c15f-d053-3900f10687c6.jpeg)
【GeekSalon Gameコース】AppStoreConnect TestFlightの方法


# AppStoreConnectで自分のアプリを開く
1. 初めての人は、AppStoreConnectの招待メールがきているはずなので、そちらからAppStoreConnectに登録する。もしきていない場合はメンターに連絡する。
2. すでに登録している人は、https://appstoreconnect.apple.com からログインする。
3. 右上の自分の名前をクリックして、Ylab Inc.を選択する。
4. [マイApp]を開く。
5. 自分のアプリを探して開く。

![TestFlight1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/19291594-7a0e-a611-3f48-46f86b241857.gif)


# テストの詳細を記入
1.上のメニューの[TestFlight]を選択する
2.[ビルド]>[iOS]>アイコンの横の数字をクリック
3.[テストの詳細]を記入
4.右上の保存を押す
テストの詳細は、アプリの下に表示される、アプリの情報

![TestFlight2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/468fee91-0509-5fc0-5e55-0683032a5ccf.gif)


# 内部テスターを追加する
左上の[iOSビルド]を押し前の画面に戻り、
1.左のメニューから[内部テスト]横の＋を選択
2.適当な名前をつけて[作成]
3.テスター横の+をクリック
4.ylabに登録されている人の中（自分、メンターや同期など）からテスターに追加したい人を選択
5.[追加]を選択

![TestFlight3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/2e140836-94c5-b6f2-fb28-0042e35d84a0.gif)

# 外部テスターを追加する
内部テスターと同様に、
1.左のメニューから[外部テスト]横の＋を選択
2.適当な名前をつけて[作成]
3.テスター横の+をクリック
4.[新規テスターを追加]
5.AppStoreのアカウントを持っている人でテスターに追加したい人（家族や友人）のメールアドレスと名前を記入
6.[追加]を選択

![TestFlight4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/cc879951-3392-7acd-d711-5af4800b458e.gif)

# 配布できるURLを作成する
1.外部テスト下の[ビルド]横＋をクリック
2.ビルドを選択して[次へ]
3.[サインインが必要です]のチェックを外す
4.フィードバックメールアドレスは自分のメアドを記入
5.連絡先情報も自分の情報を記入、[次へ]
6.テスト内容を記入
7.[審査へ提出]

![TestFlight5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/2ff35555-8bcc-c7b5-25b9-0f440e76ebc2.gif)


審査に提出したビルドが承認されると、パブリックリンクが作成できるようになる
8.[バブリックリンクを有効にする]
9.テスター数を適当な数に変更
10.[リンクをコピー]

![TestFlight6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500397/0c7290a0-5bb5-eba7-6736-cb00cc6693fc.gif)



# アプリのダウンロード方法
ここからはiPhoneの操作についての説明
1.AppStoreでTestFlightをインストール
2.招待メールの[View in TestFlight]、もしくはパブリックリンクからTestFlightに飛ぶ
3.[同意]を押して[インストール]
4.普通のアプリと同じように遊ぶことができる
Ktorで、ファイルのダウンロードでプログレスを表示する

### Ktorで、ダウンロード

ktorの導入は、下記を参照してください。

https://qiita.com/shimizu-you/items/86ca6fa7d7d6cbd17e02


Ktorで、ダウンロードする際にプログレスを表示したいと思ったのですが、公式サイトに記載されてる内容が動作しなかったので、実際に動作する実装を記載します。

### KtorのonDownloadを使う

onDownloadを使う場合、callbackFlowで受信する必要があります。
callbackFlowを使用する場合、callbackFlowをクローズする際にonDownloadを初期化する必要がありますので、awaitCloseで初期化します。

```kotlin
    suspend fun downloadFile(url: String, context: Context): Flow<DownloadFileResult> = callbackFlow {
            val httpClient = HttpClient(OkHttp) {
            }
            val httpRequestBuilder = HttpRequestBuilder().apply {
                url(url)
                onDownload { bytesSentTotal, contentLength ->
                    val progress = (bytesSentTotal * 100f / contentLength).roundToInt()
                    trySend(DownloadFileResult.Progress(progress))
                }
            }

            try {
                httpClient.apply {
                    val httpResponse = get<HttpResponse>(httpRequestBuilder)
                    val responseBody: ByteArray = httpResponse.receive()

                    val file = File(context.cacheDir, "file")
                    file.writeBytes(responseBody)

                    trySend(DownloadFileResult.Success("ok"))
                }
            } catch (e: Exception) {
                trySend(DownloadFileResult.Failure(e.message))
            }
            awaitClose {
                httpRequestBuilder.onDownload(null)
            }
        }
```

```kotlin
sealed class DownloadFileResult {

    data class Progress(val progress: Int) : DownloadFileResult()
    data class Success(val result: String) : DownloadFileResult()
    data class Failure(val errorMessage: String) : DownloadFileResult()
}
```

---
KtorのonDownloadで簡単にプログレスを表示したかったけど、公式サイトのonDownloadだと機能しなかったので、こちらで試してみてください。