OmniAICreator/Qiita-1.07M huggingface dataset:
経験の少ないエンジニアに贈る、おすすめ書籍3選

# はじめに
初心者の方は書籍を悩まれる事が多い印象ですが、いかがでしょうか？
私自身も立場上よくオススメの書籍を聞かれるのですが、いつもご紹介する本が何冊かありますので、そんな中でもご紹介頻度の高い書籍を３冊ご紹介したいと思います。

# オススメな書籍１：リーダブルコード

https://www.amazon.co.jp/%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89-%E2%80%95%E3%82%88%E3%82%8A%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B8%E3%81%8F%E3%81%9F%E3%82%81%E3%81%AE%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E5%AE%9F%E8%B7%B5%E7%9A%84%E3%81%AA%E3%83%86%E3%82%AF%E3%83%8B%E3%83%83%E3%82%AF-Theory-practice-Boswell/dp/4873115655/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=ITVKQ0AJDDBN&keywords=%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BC%E3%83%89&qid=1648204694&s=books&sprefix=%E3%83%AA%E3%83%BC%E3%83%80%E3%83%96%E3%83%AB%E3%82%B3%E3%83%BCd%2Cstripbooks%2C308&sr=1-1

これはエンジニア界隈では知らない人の方が少ないかもしれない良書ですね。
読みやすいコードを書くという一点において、この本を超える本を私は知らないくらいです。
技術力という点とはまた違った視点での解説を行なっている本ですが、チーム開発において技術力と並ぶほど重要な技術がこの本には記されています。
読む本を迷った時にはまずこの本を読む事でレベルアップ間違いなしですので、読んだ事のない方は是非一度熟読される事をオススメします。

# オススメな書籍２：CODE COMPLETE

https://www.amazon.co.jp/gp/product/489100455X/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=489100455X&linkCode=as2&tag=hivokiblog0b-22&linkId=72f8d17fe65f9cffbb8430ac4db3cb5b

この本は少し古めの本ですが、リーダブルコードと同じくらい良書だと考えています。
少し読み応えのある書籍にはなりますが、リーダブルコードと方向性は同じで、読みやすいコードとは何かという点を追求した本になります。
チーム開発において、読みやすさというのはサービスの品質にも直結する要素であり、再現力(技術力)と並ぶほど重要な技術です。
是非一度、リードブルコードと合わせて読んでいただくと良いかと思います。

# オススメな書籍3：現場で困らない! ITエンジニアのための英語リーディング

https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E5%9B%B0%E3%82%89%E3%81%AA%E3%81%84%EF%BC%81IT%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E8%8B%B1%E8%AA%9E%E3%83%AA%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0-%E8%A5%BF%E9%87%8E-%E7%AB%9C%E5%A4%AA%E9%83%8E-ebook/dp/B073J7N5GR

最後の本は非常に悩みましたが、、、
エンジニアにとって切り離すことの出来ない、stackoverflowやAPIのドキュメントなど、基本英語で記述されていること多いですよね。
翻訳で解決されている方も多いですが、目を通す機会の多い物はなるべく時間をかけずに読むことができれば、問題と対峙する時間もできるので、余裕につながるかと思います。
上記2冊とは方向性がまた違った本ですが、エンジニアとして歩み続ける為にも常に余裕持つ努力ができるとベストですね。

# さいごに
各言語に関する書籍はすぐに劣化してしまいますが、ご紹介した書籍は色褪せる事なく紹介ができる本という認識です。
上記書籍から学べる技術は間違いなくご活躍される中で外す事の出来ない技術ですので、読んだ事のない方は是非一度読んでいただくと見識を広めることができると思います。
cscの作法 その62

# 概要
cscの作法、調べてみた。
スクリーンキャプチャーやってみた。

# 参考にしたページ

https://qiita.com/santarou6/items/080eff9be95309101eed

# サンプルコード

```

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;

namespace scr_cap
{
	public class Form1 : Form {
		public Button button1;
		public Form1() {
			this.Text = "scr_cap";
			this.TransparencyKey = this.BackColor;
			this.TopMost = true;
			this.FormBorderStyle = FormBorderStyle.Sizable;
			button1 = new Button();
			button1.Size = new Size(30, 1000);
			button1.Location = new Point(0, 0);
			button1.Text = "-";
			this.Controls.Add(button1);
			button1.Click += new EventHandler(button1_Click);
		}
		private void button1_Click(object sender, EventArgs e) {
			try
			{
				Rectangle r = this.ClientRectangle;
				Bitmap bmp = new Bitmap(r.Width - 30, r.Height, PixelFormat.Format32bppArgb);
				Graphics g = Graphics.FromImage(bmp);
				Point iSource = this.PointToScreen(new Point(30, 0));
				Point iDestination = new Point(0, 0);
				g.CopyFromScreen(iSource, iDestination, this.ClientSize, CopyPixelOperation.SourceCopy);
				Pen redPen = new Pen(Color.Red, 1);
				Rectangle rect = new Rectangle(0, 0, bmp.Width - 1, bmp.Height - 1);
				g.DrawRectangle(redPen, rect);
				Clipboard.SetDataObject(bmp, true, 20, 500);
			}
			catch(Exception ex)
			{
				MessageBox.Show("エラー:\n\n" + ex);
			}
		}
		[STAThread]
		static void Main() {
			Application.EnableVisualStyles();
			Application.Run(new Form1());
		}
	}
}





```


以上。
【Python】アルゴリズム問題を解く際によく使う小技集 

自分の備忘録もかねて随時追加していきます。
キーワードを書いておくのでそれでググれば詳細は出てくると思います。
▽：キーワードマーク

# 空白区切りの文字列を数値配列に変換
```python
str_num = '1 2 3 4 5 6'

list_num = [int(x) for x in str_num.split()]

print(list_num)
# [1,2,3,4,5,6]
```
▽内包表記

# 2次元配列の重複を削除
```python
dup_list = [
    [1,2],
    [3,4],
    [5,6],
    [1,2],
    [3,4]]

uni_list = list(map(list,set(map(tuple,dup_list))))

print(uni_list)
#  [[1,2],
#   [3,4],
#   [5,6]]
```
▽2次元配列 重複行削除

# 文字列を文字の配列に変換
```python
word = 'abcde'

word_list = list(word)
print(word_list)
# ['a','b','c','d','e']
```

# 配列をアンパック
```python
num_list = [1,2,3,4,5,6]

print(num_list)
# [1,2,3,4,5,6]

print(*num_list)
# 1 2 3 4 5 6

#配列の前後に要素を入れる場合なども使用
add_list = [-1,0,*num_list,7,8]
print(add_list)
# [-1,0,1,2,3,4,5,6,7,8]
```
▽アンパック

# H × Wの2次元配列を(H + 2) × (W + 2)へと拡張する
```python
H = 4
W = 3
field = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
    [1,2,3]]

sentinel = []
#ダミーデータを0とする
sentinel.append([0 for i in range(W + 2)]) 
for f in field:
    sentinel.append([0,*f,0])
sentinel.append([0 for i in range(W + 2)])

print(sentinel)
#[[0,0,0,0,0],
# [0,1,2,3,0],
# [0,4,5,6,0],
# [0,7,8,9,0],
# [0,1,2,3,0],
# [0,0,0,0,0]]
```
▽番兵法
配列の前後を拡張することで、例外処理を省いて効率化

# フラグを使わずにbreakで抜けた際の処理
<dl>
    <dt>問題</dt>
    <dd>配列を比較し同じ要素番号に同じ値が格納されていれば'Yes'、なければ'No'を出力する</dd>
</dl>

```python
tar_1 = [1, 3, 5, 7, 9, 11]
tar_2 = [2, 4, 5, 8, 10, 12]
```

### フラグを使用する場合
```python
flg = False
# 全要素を走査
for i in range(len(tar_1)):
    # 一致すればフラグを立ててbreak
    if tar_1[i] == tar_2[i]:
        flg = True
        break

# フラグによって出力を決める
if flg:
    print('Yes')
else:
    print('No')
```
### フラグを使用しない場合
```python
# 全要素を走査
for i in range(len(tar_1)):
    # 一致すれば'Yes'と出力しbreak
    if tar_1[i] == tar_2[i]:
        print('Yes')
        break
else:
    # for文がbreakされなかった場合の処理
    print('No')
```
▽for - else文

:::note warn
注意！
else文は<strong>breakされなかった場合のみ通らない</strong>ので、
そもそも**for文の中を通らない場合でもelse文が処理される**
(今回のだと、`len(tar_1)`が`0`の場合など)
:::

```python
tag = []

for i in range(len(tag)):
    # ここは通らない
else:
    # ここは通る
```
Chromebook (Crostini) にLinuxアプリのアイコンを追加する



通常、アプリケーションをインストールすると、下記パス内に `○○.desktop` ファイルが作成されるが、Chrome OSのシェルフに表示されない場合がある。
今回は `lxappearance` を例に、アイコンを追加する方法を記録しておく。

# インストール
インストールは、通常のDebian系Linux同様。
```shell
$ sudo apt install lxappearance
```

インストールが完了すると、下記パス内にショートカットアイコンになる `○○.desktop` ファイルが作成されるのだが、Chrome OSのシェルフ内には追加されていない...
```
/usr/share/applications
```

# カレントユーザー用にコピー
アイコンを表示させるためには、カレントユーザーのフォルダにコピーする必要がある。
コピーする場所は下記パスなのだが、初期状態では存在しない。（ `~` は `/home/《ユーザー名》` と同義）
```
~/.local/share/applications
```

まずはフォルダを作成する。
```shell
$ mkdir ~/.local/share/applications
```

作成したフォルダに移動して、先ほどの `○○.desktop` ファイルをコピーしてくる。
```shell
$ cd .local/share/applications
$ cp /usr/share/applications/○○.desktop .
```

# 設定の修正
ファイルをコピーしてくるだけでは、表示されない事がある。
`○○.desktop` 内に `NotShowIn=GNOME;` `Categories=Settings;` が含まれているとシェルフ内には表示されない様なので、複数の値で構成されている場合は該当箇所のみを削除、該当する値のみで構成されている場合は行ごと削除。（表示名などは言語ごとの記載があるが、下記では日本語以外省略）
標準でインストールされている vi(vim) などで編集する。
```ini
[Desktop Entry]
Type=Application
Name=Customize Look and Feel
Name[ja]=ルックアンドフィールを設定します
GenericName=Customize Look and Feel
GenericName[ja]=ルックアンドフィールを設定します
Comment=Customizes look and feel of your desktop and applications
Comment[ja]=あなたのデスクトップとアプリケーションのルックアンドフィールを設定します
Keywords=windows;preferences;settings;theme;style;appearance;
Keywords[ja]=windows;preferences;settings;theme;style;appearance;
Icon=preferences-desktop-theme
Exec=lxappearance
NotShowIn=GNOME;KDE;XFCE;MATE;    # <- この設定に GNOME; が含まれていると表示されない
StartupNotify=true
Categories=GTK;Settings;DesktopSettings;X-LXDE-Settings;    # <- この設定に Settings; が含まれていると表示されない
```
L5-SwaggerのSwagger UIからLaravel SanctumのSPA認証する

L5-Swaggerを使うと`/api/documentation`でSwagger UI上からAPIのテストができるようになりますが、Laravel SanctumのSPA認証を使ったAPIには対応していません。Viewを修正して対応してみます。

## 環境
- PHP: 8.0.3
- Laravel: 8.65.0
- darkaonline/l5-swagger: 8.0.9

## 手順

### 1. L5-Swaggerのviewファイルを生成する
```bash
php artisan vendor:publish --provider "L5Swagger\L5SwaggerServiceProvider"
```
`resources/views/vendor/l5-swagger/index.blade.php`が生成されます。このviewファイルを修正します。

### 2. viewファイルを修正する

viewファイル84行目以降を以下のように変更します。

```diff_php:resources/views/vendor/l5-swagger/index.blade.php
    requestInterceptor: async function(request) {
-      request.headers['X-CSRF-TOKEN'] = '{{ csrf_token() }}';
+      if (!document.cookie.includes('XSRF-TOKEN')) {
+        await fetch('/sanctum/csrf-cookie');
+      }
+      request.headers['X-XSRF-TOKEN'] = unescape(document.cookie
+        .split('; ')
+        .find(row => row.startsWith('XSRF-TOKEN'))
+        .split('=')[1]);
      return request;
    },
```

あとはログインするAPIを実行すれば、他の認証が必要なAPIも実行できるようになります。

SanctumでSPA認証するにはCSRF保護を受ける必要がありますが、`XSRF-TOKEN`クッキーの値を`X-XSRF-TOKEN`ヘッダで送信することで、後続のリクエストは自動的にCSRF保護を受けます。`X-CSRF-TOKEN`クッキーがない場合は`/sanctum/csrf-cookie`にアクセスしてCSRF保護を初期化すればOKです。

## 参考

https://readouble.com/laravel/8.x/ja/sanctum.html#spa-authenticating
nuxt.jsでchatplusのscriptを適用させる

chatplusはmoduleがないので全体に適用させるために`nuxt.config.js`に設定しなければいけなかった。


これ↓
![スクリーンショット 2022-03-25 19.12.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265805/826bfaba-43bf-b4ad-3445-cc2e8338b51a.png)


```nuxt.config.js
const chat_script = `(function() {var w = window, d = document;
                var s = "https://app.chatplus.jp/cp.js";
                d["__cp_d"] = "https://app.chatplus.jp";
                d["__cp_c"] = "ID的なの";
                var a = d.createElement("script"),
                    m = d.getElementsByTagName("script")[0];
                a.async = true, a.src = s, m.parentNode.insertBefore(a, m);
              })();
            `;




    script: [
      {
        innerHTML: chat_script,
        body: true,
        hid: "chat-script",
        charset: "utf-8",
        async: true,
      },
     ]

```
Node.js: stream.ReadableをAsyncGeneratorに変換する方法

Node.jsのstreamのReadableを非同期ジェネレーターに変換する方法を紹介します。

Node.jsでは、child_process.spawnのstdoutなど様々なI/OでReadableオブジェクトが返されます。Readableオブジェクトからデータを取得するには、コールバック関数を使ったイベントドリブンなAPIを使うのが一般的です。

```js
let dataSize = 0;
readable
 .on("data", (chunk) => { dataSize += chunk.length; })
 .on("end", () => { console.log(dataSize); };
```

イベントドリブンな書き方だと読みづらかったりもするので、非同期ジェネレーター(AsyncGenerator)に変換して手続き型の書き方にすると、コードが馴染みのある読みやすい形になることがあります。

```js:AsyncGeneratorを使った場合
let dataSize = 0;
for await (const chunk of toIterator(readable)) {
  dataSize += chunk.length;
}
console.log(dataSize);
```

## ReadableをAsyncGeneratorに変換する関数

次がReadableをAsyncGeneratorに変換する関数です。一からイテレータークラスを実装するなど、他にもいろいろなやり方があると思いますが、これが一番短く手っ取り早く書ける形だと思います。

```typescript
import { type Readable } from "stream";

const toIterator = async function* (readable: Readable): AsyncGenerator<any> {
  let resolve: (reason?: Error) => void;
  let reject: (value: any) => void;
  let promise: Promise<any> | undefined = new Promise((_resolve, _reject) => {
    resolve = _resolve;
    reject = _reject;
  });
  readable
    .on("data", (chunk) => {
      resolve(chunk);
      promise = new Promise((_resolve, _reject) => {
        resolve = _resolve;
        reject = _reject;
      });
    })
    .on("error", (err) => {
      reject(err);
    })
    .on("end", () => {
      promise = undefined;
    });
  while (promise) {
    yield await promise;
  }
};
```

### 使用例: 個プロセスの標準出力をループする

```typescript:read.ts
import child_process from "child_process";
import { type Readable } from "stream";

const toIterator = /* ...上の実装... */;
const ping = child_process.spawn("ping", ["-c", "5", "127.0.0.1"], {
  stdio: ["ignore", "pipe", "inherit"],
});
(async () => {
  for await (const chunk of toIterator(ping.stdout)) {
    console.log({ chunk: chunk.toString() });
  }
})();
```

![20220325_185806.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/78d4861d-c564-c046-e735-00181f9ab4fd.gif)
Dynamics 365 Finance and Operations ~ 在庫会計 ~

[2022年Wave1リリース](https://qiita.com/TaichiKayama/items/de5431dc8e20a765e4b6)の中で、Global Inventory Accounting Add-in という機能が出てくることもあるのか、FastTrackチームがコスト（原価）に関しての [TechTalk](https://community.dynamics.com/365/dynamics-365-fasttrack/b/techtalks/posts/inventory-costing-in-dynamics-365-supply-chain-management-techtalk-series) を連続シリーズで出してきています。

原価の評価方法は、「品目モデルグループ」を基本設定として、他にも様々なパラメータの掛け算で成り立っているということもあり、複雑なのでこの機会に少しずつ頭の中を整理しておきたいと思い、こちらに投稿しておきます。

# コスト（原価）とは
（在庫を持つ製造業を前提として）原価というと、売上から粗利を引いた「売上原価」がまず思い浮かびますが、これはあくまで販売した後にわかるコストです。当然売れなくて在庫に残っている製品も、それまでに材料・労務・経費といった「製造原価」が掛かっていますので、特に製造部門はしっかり把握しなくてはいけません。詳しいことは簿記2級などで学習ください（特に工業簿記）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/14b4f0a6-0bcf-0396-d5f5-587a3681baff.png)

# Inventory Accounting（在庫会計）の基本
在庫は増えるか（仕入や製造や移動）、減るか（出荷や移動）だけです。（俺か、俺以外かと同じです。）
しかし、在庫（物）はタダじゃないです。在庫は、物とコスト（金額）がセットです。
受領・着荷時に物は計上されますが、金額は請求してから計上されます。これで在庫（棚卸資産）の金額がわかります。イメージとしては以下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/21a2cb14-3de0-e1bd-6c63-d53d0997c461.png)
また、もう少し詳細に在庫トランザクションのステータス別に定義すると以下になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/91c5eb0b-ffb4-99e7-057c-98708a6838e6.png)
個人的にありがたいと思ったのは、転記内容ごとのステータスと物・金額の対応表です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/11694282-00e5-4752-71d8-8714e4d0038f.png)

# 棚卸評価方法（品目モデルグループ）について
FO の品目モデルグループで選択できる棚卸評価方法については以下の通りです。

・FIFO（先入先出法）
・LIFO（後入先出法）
・Moving Average（移動平均法）
・Weighted Average（加重平均法）
・Standard cost（標準原価法）

それぞれの細かい動きについては割愛しますが、性質や種類は以下の通りです。イメージはつくのではないでしょうか？Periodicなものは、締日前には再計算・在庫締め処理を行い、その評価法に従って調整と決済を済ませる必要があります。※なお、マーキングを使って受入と払出を紐づけている場合は、その評価法で評価されず実際原価にオーバーライドされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/59a54032-a36f-d72e-987e-9968e4488e08.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/71efa658-c7a7-d435-a33d-e461e1f7eb92.png)
Actual costing や Standard costing であれば、仕入れた物と、払い出された物の金額は一致します。ただ、Average costing はそれぞれ仕入れた時の物の金額は違えど、在庫トランザクションとしてごちゃまぜにされて、払い出された時はその金額の平均値を取るような評価法なので、一致しません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375815/def59e62-4e22-bff8-7011-eaf73fb92bbe.png)

棚卸評価方法の選択時に考慮すべき事項について

DO's
・各国の会計制度・法律を考慮すること。
・トランザクションが走る前に慎重に検討をすること。
・販売手数料の計算を考慮すること。
・品目に既定の価格を入力しておくこと。
・Actual costing を用いるなら、倉庫レベルまで Financial inventory を有効にしておくこと。
・手動でマーキングする労力は減らすことを検討すること。
・LIFOであれば、LIFO dateを使うことを検討すること。
・在庫金額のマイナスを許容する設定をすること。
・基本的には月末に在庫締めや調整は行うこと。


DON'Ts
・財務の人や監査人（会計士）との相談なしに棚卸評価法を変えること。
・管理会計的なインパクトを評価しないまま棚卸評価法を変えること。
・頻繁に在庫調整する場合に移動平均を使うこと。
・在庫トランザクションが残っているのに棚卸評価法や保管分析コードを変えること。
・在庫が0になったときとかの[代替原価](https://docs.microsoft.com/ja-jp/dynamics365/supply-chain/cost-management/moving-average-fallback)を設定しないこと。
・標準原価法を使っているのに仕入時に違う固定価格を入力すること。
・現物在庫のマイナスを許容すること。

以上です。
Laravel独自のバリデーションをつくる方法【個人的なお勉強アウトプット】

## 参考図書
https://www.amazon.co.jp/dp/B07SPT6XJV/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

オリジナルのバリデータの作成にはいくつか方法がある。

- Illuminate\Validation\Validatorクラスを継承したクラスを作成する方法（現在は非推奨のようです）
- Validator::extendを使う方法
- 独自のバリデーションルールをつくる


## Illuminate\Validation\Validatorクラスを継承したクラスを作成する方法（現在は非推奨のようです）
```
use Illuminate\Validation\Validator;

class クラス名 extends Validator{
public function validate*** ($attribute, $value, $parameters){
...バリデーションの処理...
return 真偽値;
}
}
```
Validatorクラスを継承して作成。その中に「validate***」という名前のメソッドを用意。これがバリデーションで使われるルールとして認識される。
例えば「validateAbc」という名前でメソッドを用意すれば'abc'としてつくぁれる。

### 実例
#### バリデータクラスの作成
バリデータクラスはコードを生成するコマンドは用意されていない。作業でスクリプトファイルを用意する。
```app/Http/Validators/HelloValidator.php
namespace App\Http\Validators;

use Illuminate\Validation\Validator;

class HelloValidator extends Validator{
public function validateHello($attribute, $value, $parameters){
return $value % 2 == 0;
}
}
```
HelloValidatorという名前で暮らすを作成。
偶数なら許可、奇数なら非許可となるバリデーションルール。

#### サービスプロバイダに組み込む
```app/Providers/HelloServiceProvider.php
use Validator;
use App\Validators\HelloValidator;

public function boot(){
$validator = $this->app['validator'];
$validator->resolver(function($translator, $data, $rules, $messages){
return new HelloValidator($translator, $data, $rules, $messages);
})
}
```
バリデータは`$this->app['validator']`に保管されている。resolvverというメソッドでバリデーションの処理を粉う設定ができる。
クロージャでHelloValidatorクラスのインスタンスをreturnすることで設定できる。

#### HelloValidatorルールを利用
フォームリクエストのバリデーションルールを設定する箇所にHelloValidatorルールを設定する。
(多分からなずしもフォームリクエストじゃなくても大丈夫。)
```app/Http/Requests/HelloRequest.php
public function rules(){
return [
'age' => 'numeric|hello'
]
}
```

#### コントローラでフォームリクエストを利用の設定
```app/Http/Controllers/HelloController.php
public function post(HelloRequest $request){
return view('hello.index', ['msg'=>'正しく入力されました']);
}
```
## Validator::extendを使う方法
上記のように独自のバリデータクラスを定義シて組み込むのはきちんとしたバリデータ処理を作成して汎用的に使えるようにする場合は有効。しかし、このフォームだけちょっとカスタマイズしたいルールを使いたい、という場合にextendを使うと簡単。

```app/Providers/HelloServiceProvider.php
public function boot(){
Validator::extend('hello', function($attribute, $value, $parameters, $validator){
return $value % 2 == 0;
});
}
```
これで'hello'というルール名が追加される。
あとはフォームリクエストでルールを設定すればいいだけ。

## 独自のバリデーションルールをつくる
バリデータ自体の独自のルールをつくる方法
バリデーションルールはIlluminate\Contacts\Validation名前空間の「Rule」というクラスを継承して作られている。
この「Rule」を継承したクラスを用意すれば、そのクラスをバリデーションのルールとして使えるようになる。

### バリデーションルールファイルの作り方
`php artisan make:rule Myrule`
appフォルダの中にRulesというフォルダが作成され、そのなかにMyrule.phpが作成される。
```app/Rules/Myrule.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Myrule implements Rule
{

    public function __construct($n)
    {
        $this->num = $n;
    }

    public function passes($attribute, $value)
    {
        return $value % $this->num == 0;
    }

    public function message()
    {
        return $this->num . 'で割り切れる値が必要です。';
    }
}


```
指定した数値で割り切れるかどうか判定するバリデーション

### Myruyleを使う
フォームリクエストのrulesメソッドに設定。
```app/Http/Requests/HelloRequest.php
public function rules(){
return [
'age' => 'numeric|new Myrule(5)',
];
}
```
5で割り切れるかどうか判定できるようになる。
【AWS環境構築メモ④】セキュリティーグループを作成する

## 0.はじめに

**ELB, EC2, RDS**に関連付けるセキュリティーグループを、先に作っちゃいます。

- **セキュリティーグループ**
VPC上で通信を制御するファイヤーウォール機能。
instanceのアクセス許可や制御などの役割を果たします。

![スクリーンショット 2022-03-26 15.52.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/91d38fa9-1afa-f004-d553-76c3eccd6711.png)

## 1.前回の記事
**[【AWS環境構築メモ③】VPCを作成する](https://qiita.com/yuuichimizuta/items/cee204b9e2776056b863)**

## 2.前提条件

- **AWSアカウント作成済み**
- **リージョンはアジアパシフィック(東京) ap-northeast-1**
- **VPC作成済み**

## 3.作成手順(サマリー)

|順番|手順|
|---|---|
|1|ELB(ALB)のセキュリティーグループ作成|
|2|EC2のセキュリティーグループ作成|
|3|RDSのセキュリティーグループ作成|

## 4.作成手順

#### 1.ELB(ALB)のセキュリティーグループ作成

**ELBに関連付けるセキュリティグループを作成します**

![スクリーンショット 2022-03-25 17.30.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/83695f3f-298f-9dcf-a956-dac8dd69fb04.png)

- **サービスよりVPCを選択 → セキュリティーグループ → セキュリティーグループの作成をクリックする**

![スクリーンショット 2022-03-25 17.30.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/39f71d01-7979-c6af-76d3-a0c6a5192273.png)

- **セキュリティーグループ名**
  - サービス名-ELB-SG　など分かりやすい名前がおすすめ
- **説明**
  - このセキュリティーグループの説明を入力
- **VPC**
  - 対象のVPCを選択
- **インバウンドルール**
  - 今回は以下の設定にします。

**インバウンドルール①**

|ルール|設定|
|---|---|
|タイプ|HTTP|
|ポート番号|80|
|ソース|0.0.0.0/0|
|説明|ルールの説明|

**インバウンドルール②**

|ルール|設定|
|---|---|
|タイプ|HTTPS|
|ポート番号|443|
|ソース|0.0.0.0/0|
|説明|ルールの説明|

![スクリーンショット 2022-03-25 17.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/072acf1d-f445-eb51-1bb3-00b88dedb436.png)

- **アウトバウンドルールはデフォルトまま**
- **タグ**
  - タグが**Name**の役割を果たすので、分かりやすい名前を入力
- **セキュリティーグループを作成をクリック**

<font color="Green">**ELBのセキュリティーグループを作成できました**</font>

#### 2.EC2のセキュリティーグループ作成

**EC2に関連付けるセキュリティグループを作成します**

- **基本的にELBのセキュリティーグループと同じ方法で作成します。**
- **インバウンドルール**を以下のように設定して作成します。

**インバウンドルール①**

|ルール|設定|
|---|---|
|タイプ|HTTP|
|ポート番号|80|
|ソース|カスタム : ELBのセキュリティーグループを紐付ける|
|説明|ルールの説明|

**インバウンドルール②**

|ルール|設定|
|---|---|
|タイプ|SSH|
|ポート番号|22|
|ソース|0.0.0.0/0|
|説明|ルールの説明|

- **セキュリティーグループを作成をクリック**

<font color="Green">**EC2のセキュリティーグループを作成できました**</font>

#### 3.RDSのセキュリティーグループ作成

**RDSに関連付けるセキュリティグループを作成します**

- **基本的にELBやEC2のセキュリティーグループと同じ方法で作成します。**
- **インバウンドルール**を以下のように設定して作成します。

**インバウンドルール①**

|ルール|設定|
|---|---|
|タイプ|MYSQL/Aurora|
|ポート番号|3306|
|ソース|カスタム : EC2のセキュリティーグループを紐付ける|
|説明|ルールの説明|

- **セキュリティーグループを作成をクリック**

<font color="Green">**RDSのセキュリティーグループを作成できました**</font>

## 5.最後に

以上でセキュリティーグループ作成は完了しました。

後々のEC2,ELB,RDS作成の際に関連付けていきます。

**次回はEC2インスタンスの作成をしていきます。**

**次回 : [【AWS環境構築メモ⑤】EC2インスタンスを作成する](https://qiita.com/yuuichimizuta/items/279bef2573c30b4175a5)**

## 6.参考

https://catalog.us-east-1.prod.workshops.aws/workshops/47782ec0-8e8c-41e8-b873-9da91e822b36/ja-JP/hands-on/phase2

https://qiita.com/hiroshik1985/items/f078a6a017d092a541cf#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%BC%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97
【HTML】リンクタイプとは

## リンクタイプとは
リンクタイプは文書と他の文書、もしくは文書と外部リソースを関連付ける `rel属性` の値として指使用する。
* rel属性とは
現在の文書から見たリンク先の文書（href属性で指定した文書）の関係を示す。

:::note alert
※ rev属性はHTML Living Standardで廃止されているため、使用するべきではない。リンク先から見た現在の文書の関係を示す際もrel属性を使用する。
:::

[havin'a coffee break](https://web.havincoffee.com/html/tag/a/rev.html)に詳しい説明が記載されています。

## 目次
* rel属性を内包できる要素
  
* リンクタイプの一覧

## rel属性を内包できる要素
| 要素 | 説明 |
|:-:|:-:|
| ＜a＞  | 現在の文書から見たリンク先との関係  |
| ＜area＞  | 現在の文書から見たリンク先との関係   |
| ＜link＞  | 現在の文書から見たリンク先との関係   |
| ＜form＞  | 現在の文書から見たリンク先との関係   |

:::note info
＜link＞要素ではrel属性は必須属性。
＜a＞要素と＜area＞要素、＜form＞要素ではrel属性はリンク先の文書と現在の文書との関係性を参考情報として伝える。
:::

## リンクタイプ一覧
| リンクタイプ | 説明 | 指定できる | "body-ok" |
|:-:|:-:|:-:|:-:|
| alternate  | リンク先は現在の文書の代替書  | ＜link＞＜a＞＜area＞  |   |
| author  | リンク先は著者情報  |＜link＞＜a＞＜area＞   |   |
| bookmark  | リンク先は最も近い祖先セクションへのパーマリンク  | ＜a＞＜area＞  |   |
| canonical  | リンク先が類似する文書の中で最も推奨される文書  | ＜link＞  |   |
| dns-prefetch  | リンク先のDNSによる名前解決を事前に行う  | ＜link＞  | "body-ok"  |
| external  | リンク先は現在の文書があるウェブサイトの外部  | ＜a＞＜area＞＜form＞  |   |
| help  | リンク先は詳細なヘルプを提供する文書  | ＜link＞＜a＞＜area＞＜form＞  |   |
| icon  | リンク先は現在の文書を表すアイコン  | ＜link＞  |   |
| license  | リンク先はライセンス情報を説明する文書  | ＜link＞＜a＞＜area＞＜form＞  |   |
| manifest | リンク先はウェブアプリマニフェスト | ＜link＞  | "body-ok"  |
| modulepreload  | リンク先のモジュールスクリプトを先行して読み込む  | ＜link＞  | "body-ok"  |
| next  | リンク先は一連の文書の中で現在の文書の次の文書  | ＜link＞＜a＞＜area＞＜form＞  |   |
| nofollow  | リンク先は現在の文書の著者が推奨しない  | ＜a＞＜area＞＜form＞ | |
| noopener | リンク先を新しいブラウジングコンテキストで開き、リンク先が現在の文書へアクセスできないようにする| ＜a＞＜area＞＜form＞ |  |
| noreferrer | リンク先を読み込むときに現在の文書のURLを含むリファラーを送信しない | ＜a＞＜area＞＜form＞ | |
| opener | リンク先を新しいブラウジングコンテキストで開いたときにリンク先が現在の文書へアクセスできるようにする（暗黙的にrel="noopener"が適用されるのを防ぐ） | ＜a＞＜area＞＜form＞ |
| pingback | リンク先は現在の文書のピングバックを扱うピンバックサーバー | ＜link＞ | "body-ok" |
| preconnect | リンク先への接続を事前に確立する | ＜link＞ | "body-ok" |
| prefetch | リンク先を事前に取得する | ＜link＞ | "body-ok" |
| preload | リンク先への接続を事前に確認する | ＜link＞ | "body-ok" |
| prerender | リンク先を事前に取得してレンダリングする | ＜link＞ | "body-ok" |
| prev | リンク先は一連の文書の中で現在の文書の前の文書 | ＜link＞＜a＞＜area＞＜form＞ | |
| search | リンク先現在の文書と関連する文書内を検索するための機能 | ＜link＞＜a＞＜area＞＜form＞ | |
| stylesheet | リンク先は現在の文書に適用する外部スタイルシート | ＜link＞ | "body-ok" |
| tag | リンク先は現在の文書に敵意要するタグを説明する文書 | ＜a＞＜area＞ | |

## その他のリンクタイプ
通常HTMLの仕様で定義されているものを使用しますが、ブラウザなどが独自に実装しているリンクタイプもある。
| リンクタイプ | 説明 | 指定できる要素 | "body-ok" |
|:-:|:-:|:-:|:-:|
| apple-touch-icon  | リンク先は現在の文書のウェブクリップアイコン  |   | ＜link＞  |
| apple-touch-icon-precomposed  | リンク先は現在のウェブクリップアイコン（古いバージョンのiOSではアイコンの光沢がない）  | ＜link＞  |   |
| mask-icon  | リンク先はSafariのページピン用のアイコン  | ＜link＞  |   |




## 参考サイト
[havin'a coffee break](https://web.havincoffee.com/html/tag/att-rel.html#inpage-ank00)

## 最後に
間違っている点がありましたらご指摘お願いします。
角丸のプログレスバー 実装方法

# 初めに
今回、記事にするのは進捗率を表す際に使用するプログレスバーの角丸実装方法です。
通常の実装ではただの長方形になりますが、少し手を加えることで角丸のプログレスバーが実装できます

### 実装方法
一般的にはプログレスバーを利用する場合、通信中であることを示すためのサークルのものがほとんどだと思います。
しかし、プログレスバーに下記の設定を追加することで最初に書いた様な長方形の進捗率を表すためのViewに変わります。

```xml:
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
```
![スクリーンショット 2022-03-25 18.07.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638092/b19515ee-c78d-9bbf-a103-bf831f57364f.png)

実際に使うとなると、角丸で実装することの方が多いかと思います。
そこで利用するのが今回のメインである`progressDrawable`です。
上記に対して独自に作ったDrawableファイルを設定してあげることにより、角丸のProgressBarを作ることができます。
一例ではありますが、進捗率を黒色で表す角丸のプログレスバーを実装したい場合は下記の様になります。
```xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:tools="http://schemas.android.com/tools"
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Define the background properties like color etc -->
    <item Android:id="@android:id/background">
        <shape>
            <solid android:color="@color/white"/>
            <corners android:radius="16dp"/>
        </shape>
    </item>

    <!-- Define the progress properties like start color, end color etc -->
    <item Android:id="@android:id/progress">
        <scale android:scaleWidth="100%">
            <shape>
                <solid android:color="@color/black"/>
                <corners android:radius="16dp"/>
            </shape>
        </scale>
    </item>
</layer-list>
```

![スクリーンショット 2022-03-25 18.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638092/5ca1d3f4-ff5e-ccf4-d468-120cf8b5fad5.png)

### 最後に
以上が、角丸のプログレスバーの実装方法です。
地味に使う機会が多いので、備忘録として残しておきます。
どなたかの役に立てれば幸いです
Rails  MVCモデルとは何か

# 結論


アプリケーション設定を整理するための概念。

この概念に基づいてアプリ制作を行うことで、**開発がしやすくなったり**、**保守性が高くなったり**します。

Q：開発がしやすい？

A:プログラムを書き込む場所がルール化されているので作業が早くなる。

例えば`夕飯を用意してください。`と指示されるよりも`カレーを作ってください、ただし人参は抜きなさい`とルールが決められている方が動きやすいのです。

Q:保守性が高い？

A:メンテナンスのしやすさのこと


つまり、こういう考え方で作ると安全で壊れにくいアプリケーション作りやすいよってことです。


# ちなみに

Model  View  Controller の頭文字です。
それぞれ役割が分かれていて、どこに何のプログラムを書くか決まっています。

M：　模型、型

V：　光景、眺め

C：　支配者、制御装置

## Modelの役割

データベース操作に関わる処理を作る

商品情報や、顧客情報のデータを扱うデータベース（db）のデータ操作をするためのプログラムを作る。

例：個人情報に関するデータや自己紹介メソッドを定義する

```app/model/user.rb
class User
  def initialize    #インスタンスが生成される段階で実行される処理
    @name = "Kuramoto30"
    @birthday = "1994/1/3"
    @age = 28
    @hobby = "Food"
  end

  def introduce
    <<~EOS

    私の名前は#{@name}です。
    誕生日は#{@birthday}で、年齢は#{@age}歳。
    趣味は#{@hobby}です。

    EOS
  end
end
```
このデータはコントローラーへ渡されます。

## Controller
ModelとViewの橋渡しとなる処理を作る

```app/controllers/homes_controllers.rb
     #HomesControllerはApplicationControllerを継承する
class HomesController < ApplicationController 
  #一覧アクション
  def index
    user = User.new　　　　　#userモデルをインスタンス化しuserへ格納
    @my_introduce = user.introduce　#userのintroduceメソッドを呼び出し@my_introduceへ格納
  end
end

```

Modelから受け取ったデータを扱えるようにインスタンス変数に格納しています。
インスタンス変数をViewで扱うことでModelのデータを受け渡すことができます。


## Viewの役割
コントローラーからモデルのデータ（インスタンス変数を参照する形）を受け取り、表示する処理を作る

```app/views/homes/index.html.erb
<%= @my_introduce %>
```

以上です。全体像を大まかに捉えながら、一緒に頑張りましょう。
Apex テストクラス書き方

## Apex 単体テスト
### Apex テストクラス作成の考慮事項
・System.debugはApexコードカバー率の対象外です。
・Apexコードは単体テストでカバー率が75%を超えている必要があります。
・テストデータはユーティリティクラスで作成するか、静的リソースを使用して保持した方がいいです。
・テストメソッド間ではトランザクションは保持されません。
・IsTest(SeeAllData=true)を使用すれば、組織の実データにアクセスできますが、価格表などの一部データは他のメソッドを使用する必要があります。
### テストクラス雛形 (Apex) 
```Apex:(XXXXXXTest )
@isTest
private class XXXXXXTest {
    @testSetup
    static void setup() {
        // 各テストメソッドで使用できるテストデータを作成する
    }

    @isTest
    static void XXXTest() {
        System.runAs(new User(ID = UserInfo.getUserID())) {
            /* ＝＝＝＝＝＝テストメソッド起動＝＝＝＝＝＝ */
            Test.startTest();
            // 対象メソッドを呼び出す
            Test.stopTest();

            /* ＝＝＝＝＝＝結果検証＝＝＝＝＝＝ */      
            // 期待値と実行結果の検証
            System.assertEquals(expected, actual);
        }
    }
}
```
## テストアノテーション
### @isTest アノテーション
アプリケーションのテストに使用するコードのみを含むクラスおよびメソッドを定義するには @isTest アノテーションを使用します。
### @testSetup アノテーション
これを利用するとテストクラス内の各テストメソッドで使用できるテストデータを作成することが可能です。これにより処理が効率化されテスト実行時間を短縮することが可能になります。
テストメソッド「setup()」で作成された Salesforce レコードは、データベースにコミットされません。テストの実行が終了すると、レコードはロールバックされます。
## System.runAs()
### System.runAsでテスト対象のユーザを指定する
System.runAs無しで実行すると、システム実行となり権限を考慮したテストが出来なくなります。
なので、必ずSystem.runAsにてテスト対象のユーザを指定して実行します。

## Test.startTest() と Test.stopTest()
テスト対象の処理をTest.startTest()とTest.stopTest()で囲む
### １：ガバナ制限のテスト範囲を限定する

テストメソッドで、事前準備としていろいろレコードを Insert してから、テストしたいコードを書くとガバナ制限を超えてしまうことがあります。

でも実務においては、既にレコード等の準備はされている状況で処理を実行しますよね。
つまり実務における１回のトランザクション分のガバナ制限を満たしていることが確認できれば十分なわけです。

これをテストメソッドで実現するのがTest.startTest() と Test.stopTest() です。
Test.startTest() と Test.stopTest() で挟まれた部分は、新しいガバナ制限セットが割り当てられます。
```Apex
// この部分は別のガバナ制限セット
// テストのためのレコードの準備など

Test.startTest();
// この間のコードには新しいガバナ制限セットが割り当てられる
// 実務での１回のトランザクションに相当する処理を記述する
Test.stopTest();
```
### ２：非同期処理を同期処理として扱う
一括処理バッチなどの非同期処理をテストする場合、非同期処理が終わらないまま System.assert() などの判定が行われてしまい、正しくテストすることができません。
このような場合にも Test.startTest() と Test.stopTest() が有効です。
この間に非同期処理を書くことで、同期処理のように扱うことができます。

``` Apex
Test.startTest();
SampleBatch batch = new SampleBatch();  // 一括処理バッチなどの非同期処理
Database.executeBatch(batch)
Test.stopTest()

System.assertEquals('aaa', hoge);       // バッチ処理が終わった状態で判定処理ができる
```
## System assertはアサーションを検証するメソッド
Systemクラスの assertEquals、assertNotEqualsは、プログラムが実行する動作の検証に使用できます。
#### SystemクラスのassertEquals
SystemクラスのassertEqualsは、最初の2つの引数が一致することを確認します。結果が一致しない場合は、エラーを返してコードの実行を停止します。
#### SystemクラスのassertNotEquals
SystemクラスのassertNotEqualsは、最初の2つの引数が一致しないことを確認します。結果が一致する場合はエラーを返し、コードの実行を停止します。
JavascriptのDateオブジェクトをUnix時間として扱う

## Javascriptでデータベースに日付（時間）データを格納して取り出して表示したい
いろいろとDate()オブジェクトを活用すれば文字列や時間オブジェクトへ変換などできそうである。
React/TypeScript　を利用して Node.js の mongoose を介して MongoDB へ情報を登録する、となるとDateオブジェクトとして型を簡単に受け渡しできるのかどうかよくわからないので、一旦の解決策として Date オブジェクトの受け渡しを「Unix時間」としてみる。

## Javascript Date()オブジェクトでユニックス時間を取得する
これが最も自分の目的にあっているのでは？と思っている。

```
// データベースで見て計算しやすいようにunix timeで格納する
const dtime = new Date().getTime() / 1000.0;
```
これでMongoDBに格納しておいて（float型）取り出し側で以下のようにして時間へ変換する。
```
// Unix timeから普通の読めるやつへの時間変換
let convTime = new Date(time_on_db * 1000);
```
これでJST時間への変更が問題なくできた。
時間は文字列にしてしまっても良いのだが、あとあと差分を計算するとか考えるとDBへの格納はUnix時間が最適なのではないかと思っている。
この例だと丸められて時間の誤差は１秒未満のは精度を失うと思うが自分には問題はない。
（2022/03/25時点）

### 差分を取得する：目的＝今の時間から24時間以内の更新を調べる
```
    const time_on_db = item.datetime * 1000.0;

    // 今日の日付のやつを選択する
    const todayNow = new Date().getTime();
    // Unix timeから普通の読めるやつへの時間変換
    const convTime = new Date(time_on_db * 1000);

    // 現在からの乖離時間を計算（単位は hours)
    const diff_hours = (todayNow - time_on_db) / 1000.0 / 3600.0;
    console.log(diff_hours);

    if (diff_hours < 24.0) return true;
```
【Laravel】get() / first() / find()の返り値の違い

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 状況

deleteする際エラーが発生。

```
Method delete does not exist.
```

```php
public function destory($id)
{
	$article = Article::where('id', $id)->get();
	$article->delete();

	return redirect()->route('home');
}
```

## 原因
```Article::where('id', $id)->get();```の返り値が**Collectionクラス**だから。
Collectionクラスに対してdeleteできないというエラーだった。

（Collectionクラスは、RailsでいうEnumerableモジュールだと思う）

https://docs.ruby-lang.org/ja/latest/class/Enumerable.html

```php
>>> Article::where('id', 9)->get();
=> Illuminate\Database\Eloquent\Collection {#4467
     all: [
       App\Models\Article {#4461
         id: 9,
         user_id: 1,
         title: "title",
         content: "content",
         created_at: null,
         updated_at: null,
       },
     ],
   }
```

## 解決法

```php
public function destory($id)
{
    $article = Article::where('id', $id)->first();
    //OR
	$article = Article::find($id);
	$article->delete();

	return redirect()->route('home');
}
```

## get / first / findの返り値の違い
>get()　→ Eloquent Collectionクラス
first() → modelオブジェクト
find()　→ modelオブジェクト


```Eloquent Collection```クラス：```Illuminate\Database\Eloquent\Collection```のインスタンス

```php
>>> Article::where('id', 9)->first();
=> App\Models\Article {#4460
     id: 9,
     user_id: 1,
     title: "title",
     content: "content",
     created_at: null,
     updated_at: null,
   }

>>> Article::find(9);
=> App\Models\Article {#4477
     id: 9,
     user_id: 1,
     title: "title",
     content: "content",
     created_at: null,
     updated_at: null,
   }
```


## 最適解
ただ、deleteする際の取得の仕方としてよりベターなのは```findOrFail```を使う。
```findOrFail```で取得したい```article```が見つからなかったときはエラーを吐いてくれる。

（Railsでは、```@article.find(id)```だけでエラー吐いてくれる）


```php
public function destory($id)
{
	$article = Article::findOrFail($id);
	$article->delete();

	return redirect()->route('home');
}
```

## 参考

https://stackoverflow.com/questions/43899678/laravel-method-delete-does-not-exist


https://qiita.com/sola-msr/items/fac931c72e1c46ae5f0f
開発前の準備「とにかくローカルに表示する！プロジェクトに参加していく！」2

<br>

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

 ・ローカルにクローンしたけど次はサーバー設定？
 ・新しいプロジェクトのIIS（サーバー）の初期設定（バインドポート設定など）
 ・IISのセキュリティ設定

---

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

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

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

<br>

---

#### 【手順の流れ】

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

※➀、➁はここから[戻る](https://qiita.com/kusaharajiji/items/71a6598abc2818f5b29c)

<br>

---

#### 【手順】
#### 「➂IIS（ローカルサーバー）の設定」

###### 1. WindowsでIISを開く
　※以下の２方法（◆）どちらかを実行で可能

　◆モニター下左端の「ここに入力して検索」に「IIS」と入力
　　↓ 「インターネット インフォメーション サービス (IIS) マネージャー」と出てくるのでそれをクリック

　◆モニター下左端の「Windowsロゴ」をクリック
　　↓アルファベットごとの一覧が表示されるので Wまでさがり「Windows管理ツール」をクリック
　　↓「インターネット インフォメーション サービス (IIS) マネージャー」と出てくるのでそれをクリック


###### 2. IISにサイト追加

　・左端の接続欄の中の「サイト」を右クリック
![追加サイトpng.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/357246f2-3436-920a-9a56-75b3eb599812.png)
　・「サイトを追加」をクリック
　　↓Webサイトの追加のフォームを入力する（サイト名、物理パス、バインドのポート）

>サイト名 ：　例：XXX.com
>物理パス（wwwまで）:　クローンしてきたプロジェクトへのパスを選択（www含む）
>バインドのポートを設定：例：8000
　　プロジェクトに設定してあるものプロキシの方の数字を入力
　　「proxy:"localhost:8000"」ポート「port: "3000"」は入力しない。※数字は例です

###### 　ーこれでIISのソフト設定完了です！ー

<br>

###### 3. セキュリティ設定

　・設定画面へ移動
　　　※以下の２方法（◇）どちらかを実行で可能。後者は先輩から教えていただいた方法

　　◇IISから設定へ移動
　　　　IIS開く➡左「操作」欄の「サイト」➡サイト名を右クリック➡
　　　　「アクセス許可の編集」➡「wwwのプロパティ」内のタブ「セキュリティ」

　　◇ローカルに用意したディレクトリから設定へ移動（IISは閉じるパターン）
　　　　クローンしたファイル名を右クリック➡プロパティ➡
　　　　「xxxx（プロジェクト名）のプロパティ」内のタブ「セキュリティ」

<br>

　・セキュリティを設定する（Windowsはセキュリティ設定があるようです）
　　※アクセス権限の設定はその時によるので参考URLのみ貼っておきます。
　　https://creativeweb.jp/tips/iis_acl/


---

#### ➂のIISの設定は完了しました！
###### 次回[【➃サイト表示の確認】【➄画像がコード管理から外されている場合はダウンロード（git管理下ならこの作業は不要）】](https://qiita.com/kusaharajiji/items/d4e07d51a282f79d1d62)です。

次からはnpx gulpコマンドで表示されるか確認しながら足りない設定があれば追記していきます。

※注意IISはWindowsでのみ使えるサーバーです。
※筆者はMacでの開発も行っております。IIS代替えとしてMAMPを使用しておりますので、別記事で追記予定です。

<br>

---

#### 【気になるワード】---記事内でより理解を深めたいワード
 
- [IIS のアクセス許可](https://creativeweb.jp/tips/iis_acl/)
- [IIS でのフォルダーアクセス権限を設定する](https://sk44.hatenablog.com/entry/20180808/1533699138)
prsim使って爆速でモックAPIサーバをセットアップする

# prismのドキュメントを通読する

https://stoplight.io/open-source/prism/


# prismをインストールする

```
npm install -g @stoplight/prism-cli
# or
yarn global add @stoplight/prism-cli
```

# yamlを用意する

サンプルのyamlをとってくる

https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/api-with-examples.yaml

# 動かしてみる

```
prism mock api-with-examples.yaml
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/cca9168b-337b-a2c5-b714-dba41a3628c9.png)


# 別ターミナルからモックサーバにアクセスする

```
curl 127.0.0.1:4010/
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/132ef985-87f4-3330-3c95-9e0df1a358f2.png)


apiのyamlに記載されているexamplesのjson文字列が返ってくる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/a53c03a3-aab6-140b-e348-bf4377e0d63a.png)

# docker-compose.ymlを用意しておきました。

すぐ試せるようにサンプルコードを用意しておきました。
https://github.com/hiyasichuka/sample-prism-api

使い方

ソースコードをとってくる
```shell
git clone https://github.com/hiyasichuka/sample-prism-api.git
# or
git clone git@github.com:hiyasichuka/sample-prism-api.git
```

ソースコードからモックサーバを立ち上げる
```shell
docker-compose up
```

別のターミナルを立ち上げて、テスト的にアクセスしてみる。
```shell
curl 127.0.0.1:4010/
# or ブラウザアクセスで確認
```


# 終わりに

APIの仕様が書かれたyamlファイルさえ用意すればコマンド１つで簡単にモックサーバを立ち上げることができました。
フロントエンド開発が捗りそうです。



以上。
【Laravel】fillableはなぜ必要かを具体的に。

Laravelのfillableやguardedがなぜ存在しているのかを、メモを兼ねて記事にしてみました。

## 結論：fillableは複数代入の脆弱性に対応するために必要

Laravel公式には以下のように書かれています。

>createメソッドを使用する前に、モデルクラスでfillableまたはguardedプロパティを指定する必要があります。すべてのEloquentモデルはデフォルトで複数代入の脆弱性から保護されているため、こうしたプロパティが必須なのです。

しかし、初心者の僕にはよくわかりません。
複数代入の脆弱性とはなんでしょうか？

## 複数代入の脆弱性とは？

例えばユーザー情報を更新するための、下記のようなフォームがあったとします。
![sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/985396/e293d7e6-5e4b-b4d6-a9a8-7de650980e0e.jpeg)
見てわかる通り、ユーザーが変更できるのは「ユーザー名」と「メールアドレス」のみです。「会員ランク」は確認のためだけに表示されています。

しかし、もしfillableやguardedの機能がLaravelに無かった場合、コードの書き方によっては、「会員ランク」を不正に変更されてしまう可能性があるのです。

では、どういうコードの書き方だと不正な変更に繋がってしまうのでしょうか？
それが、"複数代入"と呼ばれる下記のようなコードです。
```php:
pubic function update(Request $request,User $user)
{
    $user->update($request->all());
}
```
問題となるのは、3行目の`$request->all()`の箇所です。
`$request->all()`を使用すると、フォームから送られてきたリクエストのデータが自動で配列になります。そしてupdateメソッドにより、その配列の各要素に対応するDBの値が更新されます。

このとき、普通であれば、更新されるのはフォームに入力欄のある「ユーザー名」と「メールアドレス」だけです。
しかし、もしユーザーがブラウザの機能を使って入力項目を不正に増やした場合、「会員ランク」などの、本来であればユーザーが操作できない値までもが更新されてしまう可能性があるのです。

これが、「複数代入の脆弱性」です。

## Laravelは、複数代入の脆弱性にデフォルトで対策できている

前置きが長くなりましたが、この"複数代入の脆弱性"への対策となるLaravelの機能がfillableやguardedです。

上にも書かせて頂いた通り、複数代入の脆弱性は、リクエストのデータを配列にすることで発生します。そのためLaravelでは、配列を使ってモデルを生成・更新するメソッドは、自動でfillableかguardedによるチェックを受けるようになっています。

「配列を使ってモデルを生成・更新するメソッド」とは、代表的なもので言うと下記の3つです。

・createメソッド
・updateメソッド
・fillメソッド（saveメソッドと併せて使用）

つまり、モデルクラスに以下のようにfillableを定義すると「ユーザー名（name）」と「メールアドレス（email）」カラムはcreateやupdateやfillメソッドによる値の登録・書き換えが可能（それ以外のカラムは不可）という状態を作成することができます。

```php
class User extends Model
{
  protected $fillable = ['name', 'email']; 
}
//「複数代入によって書き換えられたくないカラム」はここには入れないよう注意。
```

そして逆に言えば、上に挙げたような「配列を使ってモデルを生成・更新するメソッド」を使用せずにモデルを生成・更新する場合は、複数代入による脆弱性は発生しないので、fillableやguardedによるチェックも入りません。

## fillableやguardedによるチェックが入らないケース
コードとしては、例えば下記のように、createやupdateやfillメソッドを使わずに、モデルの各カラムに対して１項目ずつデータを代入していった場合には、fillableやguardedによるチェックが入りません。

```php:

pubic function update(Request $request,User $user)
{
    $user->name = $request->name;
    $user->email = $request->email;
    $user->save();
}
// ユーザーがブラウザの機能を使って入力項目を不正に増やしたとしても
// その入力項目をモデルに代入する処理が無いのでDBの値が不正に変更される心配もない。
```
もし複数代入による脆弱性以外の、コード上のミスや、その他の予期せぬ操作への対策としてfillableやguardedのチェックを通したい場合で、なおかつ何らかの理由で上記のように１項目ずつの代入が必要な場合は、下記コードのようにcreateやupdateやfillメソッドの中に、配列として１項目ずつの代入を記述します。

```php:updateメソッドの場合
pubic function update(Request $request,User $user)
{
    $user->update([
            'name' => $request->name,
            'email' => $request->email,
    ]);
}
```
```php:fillメソッドの場合
pubic function update(Request $request,User $user)
{
    $user->fill([
            'name' => $request->name,
            'email' => $request->email,
    ])->save();
}
```


本記事は以上となります。何かおかしな部分や間違った記述などありましたら教えて頂けると嬉しいです！
for文の条件を条件付きで書けるとは知らんかった

# for文の条件を条件付きで書けるとは知らんかった

書けたら良いのに…とは思ってたけど、試してなかった。
JavaScriptなら書けるのね。
今まで見たことがなかったからメモっとく。

さすがにif文は書けないけど、これで正順でも逆順でも気にしなくて済む。３項演算子は好みじゃないけど、これができるなら使う。

```javascript:reverse_loop.js
function reverse_loop(from,to)
{
	for(i=from; (from<to?i<=to:i>=to); (from<to?i++:i--)){
		document.writeln(i+'<br />');
	}
	document.writeln('<hr />');
}
reverse_loop(2,5);
reverse_loop(5,2);
```
Next.jsで「前の記事」「次の記事」を実装

今後も使いそうなので、忘れないようにメモとして残しておきます。

# 前提
Next.js
TypeScript
GraphQL

# 前後記事へのリンクを作成
前後記事へのリンクは[slug].tsx(または[id].tsx)にgetStaticProps内に追記していきます。
```javascript:[slug].tsx
export async function getStaticProps({ params }) {
  
  // データ取得部分は割愛
  // const { data } = await... 

  // 全ページを取得
  const allPosts = data.posts

  // 現在のページを取得
  const currentPost = allPosts.find((data) => data.slug === params.slug)

  // 現在のページ番号を取得
  const postNum = allPosts.indexOf(currentPost)

  // 現在のページの1つ前のページを取得
  const prevPost = postNum === allPosts.length - 1 ? null : allPosts[postNum + 1]

  // 現在のページの1つ後のページを取得
  const nextPost = postNum === 0 ? null : allPosts[postNum - 1]

  return {
    props: {
      posts: data.posts,
      prevPost,
      nextPost,
    },
  }
}
```

# 前後記事へのリンクを作成
前後記事へのリンクは下記のようにすると作成できます。
```React:[slug].tsx
{prevPost && (
  <Link href={`/posts/${prevPost.slug}`}>
    <a>
      BACK
      <span>{prevPost.title}</span>
    </a>
  </Link>
)}
{nextPost && (
  <Link href={`/posts/${nextPost.slug}`}>
    <a>
      NEXT
      <span>{nextPost.title}</span>
    </a>
  </Link>
)}
```
Next.jsの前後記事リンクの情報があまり落ちていなかったので、
下記の記事には本当に助けていただきました。
ありがとうございます。

この記事は以下の情報を参考にして執筆しました。
- [Next.js - チュートリアル後](https://kakioku.com/posts/2103040)
Django データベース作成について整理してみた

DjangoのDatabase作成方法を整理しました

プロジェクト作成からwebアプリケーションの作成までは次のサイトを参考に実施済みとなります
https://docs.djangoproject.com/ja/3.2/intro/tutorial01/

プロジェクトはmysite、webアプリケーションはtestで作成しています


## Databaseを作成するまでの流れ
Django経由でDatabaseを作成、変更する手順としては大まかに3工程発生します
![2021-11-30-17-43-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997750/b4ccd600-207f-344f-c181-f81b072011cf.png)


1. modelに作成したいテーブルの情報を記載
2. modelからmigrations（更新部分をまとめたもの）作成
3. migrationsを元にmigrateを実行し、Databaseを更新していくという流れです

<br/>

またDjangoのサイトにはadminページというDatabaseの情報を見れるページがあります
adminページにて情報の表示、編集を行うようにするためには次の手順が必要です

- user作成
- admin.pyの更新

### model作成
modelを作成する際は、下のように記述します

```
class テーブル名(models.Model):
    列名 = フィールドタイプ(フィールドオプション)
```

フィールドタイプは種類があるので、下の記事などを参考にしてみてください
https://note.com/saito_pythonista/n/n920bbc48c8fd


変更箇所：mysite\test\models.py
作成したwebアプリケーション配下のmodels.pyを変更する必要があります
「# Create your models here.」を目印にしてみてください

```
from django.db import models

# Create your models here.
class test(models.Model):
    test_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=100)

```

<br/>

続いて、settings.pyを更新することで、
mysiteに認識させます

変更箇所：mysite\settings.py
31行目あたり
今回の場合、「'test.apps.TestConfig',」を追記しました
わからなくなったときは、\作成したプロジェクト名\作成したwebアプリケーション名\apps.pyのクラス名を確認するとわかります

```
# Application definition

INSTALLED_APPS = [
    'test.apps.TestConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
```


### migrations作成
migrationsの作成は、pythonを実行すればOKです

```
python manage.py makemigrations test
```

```
Migrations for 'test':
  test/migrations/0001_initial.py
    - Create model test
```
これでmigrationsファイルの作成は完了です
結果にある通り「test/migrations/0001_initial.py」が新しく作成されています


もしどんなSQL文が実行されるか気になる場合、次のコードを実行するとわかります
test 0001の部分は適宜変更してください
webアプリケーション名とmigrationsファイルの数字部分（例でいう0001_initial.pyの0001）の組み合わせになります

```
python manage.py sqlmigrate test 0001
```

```
BEGIN;
--
-- Create model test
--
CREATE TABLE "test_test" ("test_id" integer NOT NULL PRIMARY KEY, "name" varchar(100) NOT NULL);
COMMIT;
```

### Datebaseを作成、更新
migrateの実行もpython実行でOKです

```
python manage.py migrate
```
```
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions, test
Running migrations:
  Applying test.0001_initial... OK
```
### user作成

adminページのログインユーザの作成です
Email addressは空白でも作成できます

```
python manage.py createsuperuser
```

```
Username:
Email address:
Password:
Password (again):
Superuser created successfully.
```

### admin.pyの更新

変更箇所：mysite\test\admin.py
「# Register your models here.」を目印にしてみてください

```
# Register your models here.
from .models import test

admin.site.register(test)
```

### adminページ確認
adminページにアクセスし、作成したuserでログインします
デフォルトは、http://localhost:8000/admin でアクセスできます

TEST（webアプリケーション名）という項目ができていれば完了となります
![2021-11-30-17-42-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1997750/58e55e09-8279-21d9-d6ca-16503455de91.png)
【Microsoft365】Windows Hello for BusinessのPINの安全性

# はじめに
とある会社の情報システム部門に常駐をしていた際に、Windows Hello for Business(略してWHfB)のPINの安全性について調査していました。
そこで、調査して分かった内容をこちらの記事にアウトプットしたいと思います。

# 前提
Windows10の環境を前提に記事を記載しております。

# 各用語について

|  用語  |  内容  |
| ---- | ---- |
|  Windows Hello  |  指紋認証または顔認証を使って、パスワードを入力せずにWindowsにサインインできる認証機能(パスワードベース)  |
|  Windows Hello for Business  |  指紋認証または顔認証を使って、パスワードを入力せずにWindowsにサインインできる認証機能(デジタル証明書ベース) |
|  PIN  |  「Windows Hello」と「Windows Hello for Business」にて利用できる暗証番号 |

※「Windows Hello」と「Windows Hello for Business」の違いは、以下の記事を参照下さい。
[【連載企画第二弾（第三回）】多要素認証（MFA）の落とし穴](https://www.lanscope.jp/trend/21238/)

# PINの安全性とは？

大まかに以下の2つになります。

- PINと端末が紐づいている
- ローカル上で認証可能

## PINと端末が紐づいている
以下のように1端末につき1つのPINが紐づいている状態になります。

![PIN.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/408e625a-956e-64ff-52d8-24712464b188.png)

具体的には、以下になります。
- **PIN**は他の端末やOffice365のサービスのログインに利用することができない
- 端末とPINを両方盗難されなければ、端末にログインすることができない

※PINを4桁にする場合、総当たり攻撃でログインできる可能性があるため、複雑にすることをおすすめします。
(Intune上で設定可能)

## ローカル上で認証可能
PINはローカル環境に保存されており、インターネット上には存在しないことも安全な理由になります。

Windows Hello for Businessの初期設定を実施する際には、ネットワークを介してAzureADと認証を実施する必要があります。
しかし、以下のように鍵で暗号化された状態のため安全性は高い状態です。
(盗聴される可能性が低いです。)

![PIN-WHfB.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/452e5a1e-73b9-6395-dc53-8f2f5f5605b5.png)

一方、通常のアカウントでのログインを実施する場合は、ネットワークを介してアカウント情報を傍受される可能性があります。

![PIN-パスワード.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/dff5345a-fb0c-e8a4-eada-9e17c114d511.png)

# Intune上での設定 
Intuneの構成ファイルにてWindows Hello for Businessの設定をすることが可能です。
設定後、対象のデバイスグループに発信することが可能です。

■設定できる箇所(例)
- PINの文字数や長さ等
- TPMの使用
- 生体認証許可

![スクリーンショット 2022-03-25 17.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/bfb3b2ce-66fb-c7d9-4fe4-50a93f69f698.png)

# さいごに
直近で関わっていた情シス案件でこちらについて調査をしていましたが、記載した以上の情報は出てきませんでした。
お客様に説明する際に一番戸惑った部分になります。
**PINと端末が密接に紐づいている**ことが安全性なのだと思います。

# 参考情報
[PIN がオンライン パスワードよりも優れている理由](https://docs.microsoft.com/ja-jp/windows/security/identity-protection/hello-for-business/hello-why-pin-is-better-than-password)
[Azure AD 参加後に有効になる Windows Hello for Business とその無効化方法について](https://jpazureid.github.io/blog/azure-active-directory/how-to-disable-whfb/)
[Windows10 サインインはPINを使う方が安全](https://nettble.com/sign-pin.html)
[Windows 10: パスワード、スマート カード、そして Windows Hello ＋ Microsoft Passport。それぞれの違いを理解しよう (1)](https://msrc-blog.microsoft.com/2016/03/17/hello_passport_scenario_01/)
Laravelの条件に応じてバリデーションルールを追加するsometimes【個人的なお勉強アウトプット】

## 参考図書
https://www.amazon.co.jp/dp/B07SPT6XJV/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

必要に応じてルールを追加したい場合、Validatorクラスの「sometimes」というメソッドを利用できる。
`$validator->sometimes(項目名,ルール名,クロージャ)`

クロージャは以下の形
```
function($input){
...処理を実行
return 真偽値;
}
```
引数`$input`には、入力された値をまとめたものが渡される。
`$input->name`としてフォームの値を取り出せる。
戻り地は、ルールを追加すべきかどうかを指定する真偽値。
trueの場合、sometimesで指定したルールを指定の項目に追加する。

```app/Http/Contorllers/HelloController.php

public function post(Request $request){
$rule = [
'項目名' => 'ルール名'
];

$messages = [
'項目名.ルール名' => 'メッセージ内容'
];

$validator = Validator::make($requset->all(),$rules,$messages);

$validator->sometimes('age', 'min:0', function($input){
return is_numeric($input->age);
});

$validator->sometimes('age', 'max:200', function($input){
return is_numeric($input->age);
});

if($validator->fails()){
return redirect('/hello')
->withErrors($validator)
->withInput();
}
return view('hello.index', ['msg'=>'正しく入力されました！'])
}

```
入力されたageの値が`is_numeric`つまり数字のとき、sometimesで指定した項目に指定のルールを追加する。
【必見】リモートで仕事が集中できない！！

エンジニアの業界ではリモートワークが大きく普及しています。
リモートワークは最高すぎます。

**しかし**集中できない！！
ということでリモートワークでも`集中力を向上するテクニック`を紹介します。

## 作業中
- 耳栓をする または 森や海の自然音を流す
- 視界にものを置かない。特にスマホや私用PC（★重要）
- 仕事以外の全ての通知をOFFにする
- 時たま、立って作業をする（おすすめはスタンディングデスク）
- ポモドーロタイマーを利用し、25分ごとに5分の休憩をする
- 集中できなくなった場合、違うタスク（簡単なものから）を行う


## 休憩中
- マインドフルネス瞑想をする
- 好きな音楽を聴く
- 仮眠をとる

## それでも集中できない場合
- カフェやコワーキングスペースで作業する
- ビデオ通話を繋げて、仕事の意識を高める
Scala + Mockitoで入れ子のフィールドをモック

下記コードのように`mock`メソッドの引数に設定情報を渡してやると、入れ子のフィールドをモックできます。

```scala
import org.specs2.mock.Mockito

object Main extends App with Mockito {
  import org.mockito.Answers
  import org.mockito.Mockito.withSettings

  case class Hoge(fuga: Fuga)
  case class Fuga(fuge: String)
  
  val hoge = mock[Hoge](withSettings.defaultAnswer(Answers.RETURNS_DEEP_STUBS))
  hoge.fuga.fuge returns "f u g e"
  println(hoge.fuga.fuge) // f u g e
}
```

(もし仮に単に`val hoge = mock[Hoge]`と書いて`hoge`を定義してやると、Null Pointer Exceptionになります。)
GitHubアクセス用の.dockerconfigjsonを手作業で作る

GitHub Packagesに置いてあるプライベートなコンテナイメージをKubernetesで使うために、認証情報をシークレットとして登録したい。そのためには、`.dockerconfigjson`というファイルが必要である。

認証情報が平文で`~/.docker/config.json`に置いてあればこのファイルを`.dockerconfigjson`として使えば良いが、最近はセキュアな場所に保存されていて`auths`には次のように空オブジェクトがあるだけかと思う。

```~/.docker/config.json
{
  "credsStore" : "desktop",
  "auths" : {
    "ghcr.io" : { }
  }
}
```

GitHubが求める認証情報はシンプルなので、`.dockerconfigjson`は次のように手作業で作成できる。

```json:.dockerconfigjson
{
  "auths": {
    "ghcr.io": {
      "username": "<user>",
      "password": "<token>",
      "auth": "<base64 username:token>"
    }
  }
}
```

`<user>`はGithubのアカウント名、`<token>`は[アクセストークン](https://github.com/settings/tokens)、`<base64 username:token>`はアカウント名とアクセストークンをコロンで繋いだ文字列をBase64エンコードしたものをそれぞれ記入する。

ちなみに、この`.dockerconfigjson`をkustomizeから使う場合、Secretの種類を`kubernetes.io/dockerconfigjson`にする。

```kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
secretGenerator:
  name: github
  type: kubernetes.io/dockerconfigjson 
  files:
    .dockerconfigjson
```


### 参考
- [GitHub Container Registry(ghcr.io)のPrivateイメージをKubernetesで使う](https://qiita.com/tomoyk/items/5cafe2f43caf80a40aad)
- [macOSで~/.docker/config.jsonのauthesに認証文字列がない場合の対処](https://qiita.com/reoring/items/a1c229fd895f3c1b43bb)