OmniAICreator/Qiita-1.07M huggingface dataset:
Spring Bootで動画ファイルをアップロードし、画面に表示させる

# 開発環境
・macOS Monterey Version 12.6.3
・Spring Tool Suite Version: 4.17.2.RELEASE
・MySQL 8.0.32
・Sequel Ace Version 4.0.5

# 実現したい処理
新規作成画面にファイル選択ボタンを設置し、保存ボタン押下でDB登録する。
保存完了後、再度作成画面に遷移し、画面に動画を表示させる。
ファイルが選択されていない場合は何も表示されない。

# 画面サンプル
アップロード前
![スクリーンショット 2023-03-23 23.55.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/9c39dbb5-0e41-4705-a7d7-c43f3b7c83fa.png)
アップロード後
![スクリーンショット 2023-03-23 23.57.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/2431eec9-7389-03e5-33db-35de3d69cc39.png)

# DB設計
##### taskテーブル
動画などサイズの大きいデータを登録する場合はLONGBLOB型を指定する。
![スクリーンショット 2023-03-24 0.02.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075609/f9aead53-4112-50f2-edca-3ce3aaa0c411.png)

# サンプルコード
##### 画面側
わざわざ書く必要はないと思うのでvideoタグのみ表記。
動画が選択されている場合のみ表示する。
th:ifについてはthymeleafのリファレンスマニュアルなどを参考にしてください。
```html:create.html
<span th:if="${base64video}">
    <div class="video">
        <video controls th:src="${'data:video/mp4;base64,' + base64video}"></video>
    </div>
</span>
```
##### コントローラー
画面のformタグでaction属性に/uploadを指定するとファイルをアップロードできる。
```java:CreateController.java

@Controller
public class CreateController {
	// taskテーブル用リポジトリ
	@Autowired
	private TaskRepository taskRep;
	// 画面名
	private static final String PAGE_NAME = "create";
	// 動画ファイルをDBに登録する
	@PostMapping("/upload")
	@Transactional
	public String upload(MultipartFile videoFile,Model model, User user, Task task) throws IOException {

		// videoFileをbyte型に変換
		byte[] cvideo = videoFile.getBytes();
		//動画が選択されていない場合
		if(videoFile.isEmpty()) {
			taskRep.save(task);
			model.addAttribute("Task", task);
		}else {
			//選択されている場合
			// base64にエンコード
			String encodedVideo = Base64.getEncoder().encodeToString(cvideo);
			// setter
			task.setVideo(cvideo);
			// DB登録
			taskRep.save(task);
			// モデル
			model.addAttribute("base64video", encodedVideo);
			model.addAttribute("Task", task);
		}
		// 画面遷移
		return PAGE_NAME;
	}
}
```
##### Entity用クラス
```java:Task.java
//Entity用クラス
@Entity
@Table(name = "task")
public class Task {
	// 動画
	@Lob
	// @Lobはサイズが大きいデータのカラムにつける
	@Column(name = "video")
	private byte[] video;

	// 追加
	@Transient
    // @TransientでDBに登録しない変数を宣言できる
	private MultipartFile videoFile;

	// ID
	@Id
	@Column(name = "id")
	private int id;
}
```
【Unity】unityroomにアップロードしたいのに拡張子が「.unityweb」でビルドされる

## はじめに
以前、筆者がUnity1週間ゲームジャムに向けて制作していた際に起こった問題に後輩が遭遇し、他にも同じ問題に直面したいる方の役に立ったらと思います。

※筆者の環境での撮影し忘れのため前半と後編で画像の関連がありません。参考程度にご覧ください。

## unityroomにアップロードするには
そもそもunityroomへのアップロードは拡張子は「.gz」である必要があり、そのためにProject Settingsの「Compression Format」を「Gzip」に変更する必要がある。

## 起きたトラブル
unityroomへのアップロードの拡張子は「.gz」だが、Project Settingsの「Compression Format」を「Gzip」にしても「.unityweb」で出力される 。
![FkQiAz6aUAAqNHw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296035/85c4f894-392f-6214-cf67-b468004d9fdf.png)
![FkQiEQbaEAA4YT-.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296035/0ca49425-5422-1a7b-bf5c-d0440ca5a7b7.png)
※上記画像は筆者の環境

## 解決策
解決策は拡張子を手動で変更すれば問題ないらしい。
![2023-03-23_17.57.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296035/74980bdc-98d8-4b37-0572-eb6e40905a07.png)
↓変更後
![2023-03-23_17.59.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3296035/2eb2b072-e491-c6f0-a166-55b53381f703.png)
※上記画像は筆者の後輩の環境
【PHP】PHPの特徴

# PHPの特徴
### PHPはスクリプト言語
PHPは`スクリプト言語`と呼ばれる。`スクリプト言語`は、プログラミング言語のうち、プログラムの記述や実行を比較的簡単に行うことができる言語の総称である。多くの場合、`スクリプト言語`はインタープリタ型言語[^1]であり、コンパイラ型言語[^2]に比べて実行までの処理の手間がかからないという特徴を持っている。また、他のプログラミング言語に比べると、習得が比較的容易とされている。

[^1]:インタープリタ型言語とは、プログラムを部分的に機械語に変換しながら実行すること。
[^2]:コンパイラ言語とは、プログラム全体を機械語に変換してから実行すること。

### PHPはWebアプリの開発に特化している
PHPはWebアプリの開発に特化している。例えば、JavaはWebアプリの開発ばかりではなく、スマートフォンアプリの開発にも利用できる。
しかし、PHPはあくまでもWebアプリの開発に特化した言語であり、そのほかの用途で使うことはできない。

### セキュリティ面が脆弱
PHPの欠点としてセキュリティ面が脆弱な部分がある。しかし、Laravelなど、Webフレームワークと呼ばれる枠組みを利用することによって克服できる。

# 参考
https://www.amazon.co.jp/1%E9%80%B1%E9%96%93%E3%81%A7PHP%E3%81%AE%E5%9F%BA%E7%A4%8E%E3%81%8C%E5%AD%A6%E3%81%B9%E3%82%8B%E6%9C%AC-1%E9%80%B1%E9%96%93%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%BA%80%E7%94%B0-%E5%81%A5%E5%8F%B8/dp/4295013579/ref=sr_1_1_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2DUKRTRPQMVNJ&keywords=php&qid=1679585436&sprefix=php%2Caps%2C188&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUEyMTFNUU5IWUQ4VTdLJmVuY3J5cHRlZElkPUEwNDM1MDY1MUExSlFSRjdBMFhHMiZlbmNyeXB0ZWRBZElkPUEyNEtBVk1GODRTTVI4JndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ==
【PL/SQL備忘録 1】SQL中で変数を使用する

# 今回の備忘録を書くことにした理由
　2023年3月、文系未経験の新卒として入社した会社での実務が開始して半年ほどが経過した頃、今までまったく触れた経験のないPL/SQLの案件へ唐突にアサインされることとなりました。
　PL/SQLに関する研修や勉強期間等も設けられないままなんやかんやで開発がスタートしましたが、いかんせんややマイナーな言語であるため調べてもあまり情報がヒットせず…。案の定基礎的な部分で躓きまくっている(現在進行形)ため、ひとまず業務で学んだことを忘れないように簡単にですがまとめていこうと考え記事にしました。

# SQL中で変数を使用する方法
　PL/SQLなんだからそりゃそうでしょうという感じではありますが、宣言した変数をそのまま使えるので直感的にSQLを書くことができるという話を会社の先輩から教わり、少し感動しました。以前VB.netの開発を行った際(DBはOracle)はバインド変数を使用し、当時はバインド変数が何者かもよく分かっていませんでしたので困惑した記憶がありますが、PL/SQLでは以下のように簡単に書くことが可能でした。
　なお以下の例はかなり雑にまとめています。実務ではFUNCTIONの呼び出し元でカーソルからフェッチした値を引数に指定し、FUNCTIONの方でその引数をSELECT文のWHERE句の条件にするような形で使用しました。

### 例: WHERE句で使用する
```
// NUMという名前のNUMBER型の変数を宣言する。
NUM        NUMBER;
// SELECT結果格納用変数を宣言する。
RESULT     VARCHAR2(100);

// NUMに5を代入する。
NUM := 5;

// 年齢が5歳(※NUMの値によって変化)の生徒の名前を取得して変数RESULTに格納する。
SELECT NAME
INTO RESULT
FROM STUDENT
WHERE AGE = NUM
;
```
# まとめ
正直備忘録を書くほどの内容でもなく、プログラミング全般の知識が浅いため内容に誤りがあるかもしれませんが、細切れでもアウトプットしていくことによって理解が深まるかなと思いますので簡単にまとめてみました。まだ案件は継続中なので後日また学びを得ることができましたら追記・修正を行っていきたいと思います。
マイクロ秒が任意の桁数の乱数代わりになるんじゃないかと考えた実験

とあるプロジェクトの中で、乱数を発生させたくないが、
乱数的な挙動をする数列を探しているとき、
マイクロ秒が使えるんじゃないかと思いつき、
それで実装し、動かしています。

小ネタのところなので意図しない動きでも影響はないのですが、
実際のところはどうだったんだろ？
との疑問が湧いてきたので、試してみることにしました。

## ほしかった数列
下記の条件
 - 一様分布
 - 値は不連続
 - 桁数は可変
 - 進数も可変で対応できる

 ※下２つは数値の表現なので、
 　乱数さえ取れればなんとでもなる、と思う

## Pythonで動くようにしてみる
方向性としては、何桁で計算したいかというところから、
必要な繰り返し回数などを計算しました


### time-stat.py
```python
import datetime
import pandas

# 何桁必要か
NeedDigit = 3

nums = []
LoopTimes = 10**NeedDigit	# 繰り返しの回数 10^桁数 で算出

# LoopTimes回現在時刻のマイクロ秒の後ろNeedDigit桁を取得し配列化
for i in range(LoopTimes):
	NowDateTime = str(datetime.datetime.now())	# 現在の時刻をマイクロ秒まで取得し型を文字列に
	num = int(NowDateTime[-NeedDigit:]) # 後ろから初期値の桁数を取得
	nums.append(num) # 配列に挿入

df = pandas.Series(nums) # データフレーム化

#個々の統計量の出力
print('合計',df.sum())
print('平均',df.mean())
print('最大',df.max())
print('中央値',df.median())
print('最小',df.min())
print('分散',df.var(ddof=1))
print('標準偏差',df.std(ddof=1))
print('歪度',df.skew())
print('尖度',df.kurt())
print('四分位',df.quantile(q=[0,0.25,0.5,0.75,1]))
print('最頻値',df.mode())
```
元のソースは
[hama-caffeine/time-stat](https://github.com/hama-caffeine/time-stat)
にあります

### コードの補足
```python
import datetime
import pandas
```
まずは必要なライブラリの呼び出し


```python
# 何桁ほしいか
NeedDigit = 3

nums = []
LoopTimes = 10**NeedDigit	# 繰り返しの回数 10^桁数 で算出
```
値の設定。
NeedDigitで必要な桁数を入力したら、後は勝手に計算されるようにする。

```python
# LoopTimes回現在時刻のマイクロ秒の後ろNeedDigit桁を取得し配列化
for i in range(LoopTimes):
	NowDateTime = str(datetime.datetime.now())	# 現在の時刻をマイクロ秒まで取得し型を文字列に
	num = int(NowDateTime[-NeedDigit:]) # 後ろから初期値の桁数を取得
	nums.append(num) # 配列に挿入
```
必要な桁数から算出した繰り返し回数だけ、
マイクロ秒を取得し、配列に放り込む


```python
df = pandas.Series(nums) # データフレーム化

#個々の統計量の出力
print('合計',df.sum())
print('平均',df.mean())
print('最大',df.max())
print('中央値',df.median())
print('最小',df.min())
print('分散',df.var(ddof=1))
print('標準偏差',df.std(ddof=1))
print('歪度',df.skew())
print('尖度',df.kurt())
print('四分位',df.quantile(q=[0,0.25,0.5,0.75,1]))
print('最頻値',df.mode())
```
配列をもとに、pandasのデータフレームにし、
データフレームから各種統計値を取得

### 実行結果（例）
```bash
$ python3 time-stat.py
合計 503526
平均 503.526
最大 999
中央値 499.0
最小 0
分散 92987.78110510511
標準偏差 304.9389793140672
歪度 -0.0059686175466188126
尖度 -1.3920210735116008
四分位 0.00      0.00
0.25    225.75
0.50    499.00
0.75    782.25
1.00    999.00
dtype: float64
最頻値 0        4
1       11
2       14
3       19
4       24
      ...
243    981
244    984
245    986
246    989
247    991
Length: 248, dtype: int64
```
結果、動かしてみるといくらかのブレはあるものの、
想定通りの分布になってるっぽく、
ざっと、平均や中央値とか見る感じだと、
ある程度は想定した形で動いてくれていたので、
まあ、良かったのかと。


## これから
とりあえず作ってみたという次元なので、
分布や統計値がなんとなく見えればよかったのだけれども、
手元では繰り返し実行して値のブレを見たりもしています。

それも踏まえてコード上で上記のフローの繰り返しの実行と
集計にあわせ、グラフ化して出力できるようにして、
ビジュアル的に分布が見えると直感的にわかりやすいかと思いました。
（たぶんやんないけど）

よくよく考えたら、
値が不連続っぽい挙動になっているかを見てなかったんで、
目視ではなく統計的な処理で確認してみようと考えています。

あと、あらためてデータフレーム便利。
UIkitのuk-*プロパティがESLintに怒られるので黙らせる

ESLintがとても有難いツールであることに間違いはないと思いますが、プロジェクトの途中から導入するとなかなかツラいものがありますよね・・・。

# 例えば、こんな箇所に・・・

```tsx:foo.tsx
const MyIcon = (name: Name) => <span uk-icon={`icon: ${name}`} />
```

# こんなエラーが出ます

```
/Users/matoruru/my_project/foo.tsx
  32:38  error    Unknown property 'uk-icon' found     react/no-unknown-property
```

これは「`uk-icon`なんてプロパティは`span`タグにはないよ。間違ってるよ。」というありがたいメッセージなんですが、[UIkit](https://getuikit.com/docs/icon#usage)を使ってると`uk-`から始まるプロパティを使う必要が出てくるので、今回はただのお節介でした。我々は間違っていません😡

# `uk-icon`は正しいので黙っててください！

`.eslint.json`に以下のルールを加えて黙らせます。

```json:.eslint.json
    "rules": {
        "react/no-unknown-property": ["error", { "ignore": ["uk-icon"] }]
    }
```

他のプロパティも追加したい場合は`ignore`の配列にどんどん足していってください。

```json:.eslint.json
    "rules": {
        "react/no-unknown-property": ["error", { "ignore": ["uk-icon", "uk-nav", "uk-offcanvas"] }]
    }
```

# 最後に

記事を読んでくださってありがとうございます！

Twitterフォローしていただけると記事を書き続けるモチベーションになります😺
https://twitter.com/_matoruru
【Markdown】文章を折りたたむ方法


## 記述方法

Markdownでは以下のように記述することで文章を折りたためます。

```markdown :sample.md
<details>
  <summary>見出し（クリックすると以下の文章が展開される）</summary>

  折りたたまれる内容
</details>
```

## 注意事項

`<summary></summary>`の後に空行を挿入しないとスタイルが適用されません。

````markdown :sample.md
<details>
  <summary>空行なし(クリックしてください)</summary>
  ### Heading
  1. Foo
  2. Bar
     * Baz
     * Qux
      
  ### Some Code
  ```js
  function logSomething(something) {
    console.log('Something', something);
  }
  ```
</details>
````

上記のように空行を挿入しないと以下のようになります。
<details>
  <summary>空行なし(クリックしてください)</summary>
  ### Heading
  1. Foo
  2. Bar
     *Baz
     * Qux
  ### Some Code
  ```js
  function logSomething(something) {
    console.log('Something', something);
  }
  ```
</details>

````markdown :sample.md
<details>
  <summary>空行あり(クリックしてください)</summary>
  
  ### Heading
  1. Foo
  2. Bar
     * Baz
     * Qux
  
  ### Some Code
  ```js
  function logSomething(something) {
    console.log('Something', something);
  }
  ```
</details>
````

空行を挿入した場合には以下のように表示されます。
<details>
  <summary>空行あり(クリックしてください)</summary>
  
  ### Heading

  1. Foo
  2. Bar
     * Baz
     * Qux
  
  ### Some Code

  ```js
  function logSomething(something) {
    console.log('Something', something);
  }
  ```

</details>

## デフォルトで展開

`<details open>`と記述するとデフォルトで展開された状態にできます。

````markdown :sample.md
<details open>
  <summary>デフォルトで展開</summary>
  
  ### Sample
  1. Foo
  2. Bar
     * Baz
     * Qux
  
  ### Sample Code
  ```js
  function logSomething(something) {
    console.log('Something', something);
  }
  ```
</details>
````

Qiitaでは展開されなかったので画像を添付します。

![IMG_778734B79E74-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/2ed5e79a-dd5b-5660-cfc2-293fae89d99b.jpeg)
【JavaScript】JavaScriptまとめ③（繰り返し処理）

# 概要
JavaScriptの理解を深めるため、
[<img width="200" alt="51vlB3JskRL.jpg" src="https://m.media-amazon.com/images/I/41vZUGXaYML._SX350_BO1,204,203,200_.jpg">](https://www.amazon.co.jp/%E3%82%B9%E3%83%A9%E3%82%B9%E3%83%A9%E3%82%8F%E3%81%8B%E3%82%8BJavaScript-%E6%96%B0%E7%89%88-%E6%A1%9C%E5%BA%AD-%E6%B4%8B%E4%B9%8B/dp/4798173266/ref=sr_1_15?crid=341O9294X80Z7&keywords=javascript&qid=1679238835&sprefix=javas%2Caps%2C185&sr=8-15)
で学習した内容を記載していく。

本記事では、繰り返し処理について記載する。

## for文
`for`文は指定した回数だけ同様の処理を行う。

#### for文の仕組み
`for`文は、指定した回数だけ処理を繰り返して実行することができるが、その繰り返し処理の途中で「繰り返した回数」を記憶しておく必要がある。この役割を担うのが`ループカウンター`と呼ばれる変数である。ループカウンターは始めに、例えば１という数値で初期化され、繰り返し処理を行うたびに２、３、４・・・・・と加算されていく。最終的にループカウンターが指定の数値に達したら、繰り返し処理全体を終わらせる。

#### for文の書き方
```
for (初期化式; 条件式; 加算式) {
    処理;
}
```
`for文の式`
| 式の種類 | 説明 | 実行タイミング |
|--|--|--|
| 初期化式 | ループカウンターを初期化する式  | 最初の1回だけ実行される |
| 条件式  | 処理を継続する条件式  | 繰り返し処理の最初に毎回実行される |
|  加算式 | ループカウンターを加算する式  | 繰り返し処理の最後に毎回実行する |

```結果を繰り返し表示する（for.js）
for (let　i = 1; i <= 5; i++) {
    console.log(`${i}回目の処理`);
}
```
```
let i = 1
```
ループカウンターの変数iを宣言している。ループカウンターは、加算されて変更されていくものなので、`const`ではなく`let`によって宣言している点に注意。

```
i <= 5
```
上の条件式が`true`の場合、ブロック内の処理を実行する。ブロック内ではループカウンターiを参照することができる。今回は繰り返し処理の回数を表示するため、以下のように記述している。

```
console.log(`${i}回目の処理`)
```
`i`が加算され、５より大きい数値になったタイミングで`for`文は終了する。

```
i++
```
上の式ではインクリメント演算子を使っている。`i`を１増加させる。
加算式が実行された後は、条件式に戻り、条件式が`false`になるまで処理を繰り返し`for`文を終了させる。

## while文
回数を指定せずに繰り返し処理ができるのが`while文`。

#### while文の書き方
```
while (条件式) {
    処理;
}
```
`while`文の仕組みはシンプル。
①条件式を評価する
②条件式がfalseなら終了、trueなら処理を実行
条件式がfalseになるまで①と②を繰り返す。
```2倍ずつ増えていく数列を作る(while_example.js)
let number = 2;

while (number < 100) {
    console.log(`${number}番`);
    number = number * 2;
}
```
このコードを順番に説明する。
①`let number = 2`と初期化する。
②初めの段階では`number`は`2`なので、条件式`number < 100`は満たされ、③④に移る。
③\`${number}番\`をコンソールに表示する。
④`number`の2倍を`number`自身に再代入する。この処理が終わったら②に戻る。
最終的には、`number < 100`という条件を満たせなくなり、`while文`は終了する。

## 「配列」に対する繰り返し処理
`['りんご', 'みかん', 'バナナ']`のような配列が与えられたときに、各要素をコンソールに表示するプログラムはどのように書けばよいか。
#### 「配列」に対するfor文を使った処理
```for_array1.js
const fruits = ['りんご', 'みかん', 'バナナ'];

for (let i = 0; i < 3; i++) {
    console.log(fruits[i]);
}
```
上のコードは問題なく動くが、配列が`['りんご', 'みかん', 'バナナ', 'ぶどう']`のように変更され、要素数が変わったとする。このとき条件式の`i < 3`の部分を`i < 4`のように書き換えれば、意図した動作になる。しかし、与えられた配列が変わるたびに、`for`文を書き換えるのは面倒である。そこで、配列の要素数を取得することができる`length`を使う。
```for_array2.js
const fruits = ['りんご', 'みかん', 'バナナ', 'ぶどう'];

for (let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}
```

#### for・・・・of文の書き方
「配列」に対する繰り返し処理を簡単に書く方法として`for・・・・of文`と呼ばれるものがある。
```
for (変数 of 配列) {
    処理;
}
```
これだけで、自動的に配列の要素数回だけ繰り返し処理を行える。

```for_of.js
const fruits = ['りんご', 'みかん', 'バナナ'];

for (const fruit of fruits) {
    console.log(fruit);
}
```
`for・・・of`文は、配列の要素数だけ繰り返し処理が行われるので、この例の場合は3回繰り返される。そして、変数fruitsには、順番にりんご、みかん、バナナという文字列が格納される。
React.jsのKeyでむやみにインデックスを使うべきではない理由

#### コンポーネントのkeyにインデックスを使ってしまいがち
map関数で、returnで返すコンポーネントにユニークなkeyを与えると思いますが、
その時ついつい何も考えずにmap関数の第二引数であるインデックスを使ってしまいがちです。
```
例）
users.map((user, index) => (
  <UserDetail key={index} />
))
```
こういった書き方は基本推奨されてません。
公式にもそう記載されてます。

https://ja.reactjs.org/docs/lists-and-keys.html

ただ、keyをつけないとwarningが発生するため、回避策としてついつい楽をしてindexを使ってしまうことが多いと思います。（僕も結構やっちゃってました）

## インデックスを使うべきではない理由
#### 中身が変わってないのに再更新かかってしまう

以下公式ドキュメントの一文を抜粋
>key として配列のインデックスが使用されている場合、並べ替えはコンポーネントの状態に関しても問題を起こすことがあります。コンポーネントのインスタンスは key に基づいて更新、再利用されます。インデックスが key の場合、要素の移動はインデックスの変更を伴います。結果として、非制御の入力などに対するコンポーネントの状態が混乱し、予期せぬ形で更新されてしまうことがあります。

ここに記載の通り、インデックスをkeyにすると並び替え処理やフィルター処理をした時に、
各コンポーネントに紐づくインデックスが変わることになるため、結果状態は変わってないのににコンポーネントが更新されてしまいます。

#### 予測不能なバグの発生を起こす可能性がある

https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318

https://jsbin.com/wohima/edit?output

こちらに簡単な例を作成されおります。
インデックスのように順番をkeyにしてしまうと、例のように要素が増えたときに意図しない挙動を起こしてしまいます。


## その他、こういうのも好ましくない
#### 毎回関数で値を生成してkeyに使う
不安定な値（Math.random()とか毎回関数を実行してkeyを生成するようにする）をkeyに使うのも推奨されてません。
まあ、あまりそういうことをすることはあまりないと思いますが、パフォーマンスの低下にも繋がるので気をつけましょう。

#### keyを子コンポーネントで使用する
keyはReact側で何か状態が変わったのかを推測するために使用するためのものなので、このkeyを子コンポーネント配下で使用するのは好ましくないようです。
もし使いたい場合は別途値を定義して渡すようにしましょう。
```
<UserDetail key={user.id} userId={user.id} />。
```

## 正しい書き方
#### データ内にあるユニークな値を使おう
```
users.map((user) => (
  <UserDetail key={user.id} /> // 各データに入っているユニークな値を使用
))
```
ループ処理で回す配列内のデータに入っているユニークな値を使うようにしましょう。
恐らくAPIから取得したデータには各データにidがあると思うので、それをkeyに使うのがベストです。

#### もし配列データにユニークな値がなかった場合
keyで使うために、新しくユニークなプロパティを作成しましょう。

【以下参考】

https://robinpokorny.medium.com/index-as-a-ke

## 最後に
#### こういった状況の時はインデックスを使っても大丈夫
以下の状況の時はインデックスをkeyに使っても問題ないです。

- 配列内のデータが計算とかしないとき
- もともと配列データにユニークなIDがないとき・ユニークなIDを作成するロジックを作るのが面倒な時
- 並び替えやフィルター処理をしない時

ただ、基本的にインデックスを使わずにデータ内のidとかユニークな値を使うことを心掛けた方が良いかと思います。

#### ESlintを使用してkeyにインデックスを使用してないか監視

また、ESLintのプラグインでkeyにインデックスを使用してる時にwarningを出してくれるので、導入するのオススメです。

https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md
SAS PROC IMPORT/EXPORTのEXCEL関連オプションについてまとめ（日本語）

SASのPROC IMPORT/EXPORTについて、DBMSによってオプションが使えたり使えなかったり、
案の定英語ページのみで膨大なため、自分用忘備録として日本語でまとめます。
未確認の部分もあるので、誤りがありましたらご指摘お願いいたします。
その他にも情報がある方はコメントお願いいたします。

## DBMSの主な違い
参考ページのUsing the DBMS= Identifiers for Microsoft Excel FilesのOverviewの日本語訳です。

Microsoft ExcelファイルのDBMS=識別子は、以下の通りです。

* DBMS=EXCEL
を使用すると、Microsoft Excel 97、2000、2002、2003、2007、2010、およびそれ以降のワークブックの読み取りと書き込みが可能になります。DBMS=EXCELはLIBNAMEステートメントを透過的に使用します。.xls .xlsb .xlsm .xlsx ファイルをサポートします。.xlsb ファイルと Linux について詳しくは、「Linux の .XLSB ファイル」を参照してください。

* DBMS=XLS、DBMS=XLSX
を使用すると、.xlsまたは.xlsxファイルからデータを読み取ったり、.xlsxファイルにデータを書き込んだりすることができます。DBMS=XLSは、Excelバージョン5/95、97、2000、2002、2003をサポートしています。DBMS=XLSXは、2007、2010、およびそれ以降をサポートしています。SASでは、サポート強化のため、.xlsxファイル形式の使用を推奨しています。この方法は、Excel .xlsbファイルをサポートしません。.xlsxファイルには16,384列、1,048,576行という制限があるため、SASデータセットからデータを書き出す（エクスポートする）場合、16,384列、1,048,576行を超えるデータを書き出すことができません。そうでない場合は、エラーメッセージが表示されます。

* DBMS=XLSXは、ダブルバイト文字セット（DBCS）をサポートしています。.xlsファイルのDBCSを取得するには、.xlsx形式で保存してください。
※DBMS=XLSXは使えるオプションが他のDBMSと比べて著しく少ないが、ダブルバイト文字が使える、OSとEXCELのbit数が違ってもPC Files Serverなしで使えるなど利点もある。（環境がないので未確認。）

* DBMS=EXCELCS
は、SAS PC Files Server（有料（SAS ACCESSに加えてさらに契約する必要あり））を経由して接続し、サーバー上のExcelワークブックを読み書きします。EXCELCS は PC Files エンジンを透過的に使用します。PC Files Serverは、SAS Viya 3.4以前には含まれていません。SAS 9 クライアントを使用して接続します。PC Files Server は Windows 上でのみ実行されます。
※Windowsが64bit、EXCELが32bitのようにbit数に違いがあるときに必要。

## DBMSごとの使えるオプション
### IMPORT
|IMPORT|EXCEL|EXCELCS|XLS|XLSX|
|:----|:----|:----|:----|:----|
|DBDSOPTS|○|○| | |
|DBSASLABEL|○|○| | |
|ENDCOL| | |○| |
|ENDNAMEROW| | |○| |
|ENDROW| | |○| |
|GETNAMES|○| |○|○|
|MIXED|○| | | |
|NAMEROW| | |○| |
|PORT| |○| | |
|RANGE|○|○|○|○|
|SCANTEXT|○|○| | |
|SCANTIME|○|○| | |
|SERVER| |○| | |
|SERVERPASS| |○| | |

### EXPORT
|EXPORT|EXCEL|EXCELCS|XLS|XLSX|
|:----|:----|:----|:----|:----|
|DBDSOPTS|○|○| | |
|NEWFILE|○| |○| |
|PORT| |○| | |
|PUTNAMES| | |○| |
|SERVER| |○| | |
|SERVERPASS| |○| | |
|SERVERUSER| |○| | |
|SERVICE| |○| | |
|SHEET|○|○|○|○|
|VERSION| |○| | |

## DBMS別 読み込んだときの変数名の扱い
PROC IMPORTでGETNAMES=YESとしたとき、ヘッダがラベルとなるが、データセットが裏で持っている変数名がどのような法則でつけられるかについて。

工事中

## で、DBMSは結局どれがベストなの？

### OSとEXCELのbit数が違う
* PC Files Serverを導入するお金がある→EXCELCS
* お金がない→XLSX（未確認）

### OSとEXCELのbit数が同じ
検討中
DBMS=EXCELが一番メジャーな気がするが、、

## 参考ページ
https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/acpcref/n0msy4hy1so0ren1acm90iijxn8j.htm
ChatGPTで簡単に記事を作成する方法

# 1. ChatGPTとは
ChatGPTは、OpenAIによって開発された自然言語処理技術です。
人工知能を用いて、文章の自動生成や応答などを行うことができます。

# 2. ChatGPTを使った記事作成のメリット
ChatGPTを使った記事作成には以下のようなメリットがあります。

* 短時間で多くの記事を作成できる
* 記事の品質が一定以上のレベルで保たれる
* 初心者でも簡単に記事を作成できる

# 3. ChatGPTを使った記事作成の手順
### 3-1. トピックの選定
>まずは、記事のトピックを選定しましょう。適切なトピックを選ぶことで、より良い記事を作成することができます。

### 3-2. キーワードの入力
>次に、トピックに関連するキーワードを入力します。これによって、ChatGPTが文章を生成する際のヒントとなります。
どんなことが書きたいのか決まっているのであれば、目次などを作成しておくといいかもしれません。

### 3-3. 文章の生成と修正
>キーワードを入力すると、ChatGPTが自動的に文章を生成します。この時点で生成された文章を修正することもできます。

### 3-4. 文章の構成と編集
>最後に、文章の構成や編集を行いましょう。例えば、タイトルや見出しを設定することで、記事の読みやすさを向上させることができます。

# 4. 注意点と改善方法
### 4-1. 著作権や情報の信頼性に注意する
>ChatGPTで自動生成された文章には、著作権や情報の信頼性に問題がある場合があります。
そのため、必ず確認し、適切に改善するようにしましょう。

### 4-2. ChatGPTが生成する文章を改善する方法
>ChatGPTが自動生成する文章には、改善する余地がある場合があります。
例えば、単語の選択や文法の修正を行うことで、より良い文章を作成することができます。

# 5. まとめ
ChatGPTを使った記事作成は、初心者でも簡単に行うことができる方法です。
ただし、著作権や情報の信頼性には十分注意し、適切な改善を行うようにしましょう。

最後にこちらの記事についてですが、
もちろんこの記事もChatGPTを活用して作成したもので、下記のように入力することで作成しています。

```
以下の内容の記事を書いてください。

タイトル：ChatGPTで簡単に記事を作成する方法
目次：
1. ChatGPTとは
2. ChatGPTを使った記事作成のメリット
3. ChatGPTを使った記事作成の手順
 3-1. トピックの選定
 3-2. キーワードの入力
 3-3. 文章の生成と修正
 3-4. 文章の構成と編集
4. 注意点と改善方法
 4-1. 著作権や情報の信頼性に注意する
 4-2. ChatGPTが生成する文章を改善する方法
5. まとめ
```
whisper.cppでHuggingFaceに公開されているfine-tuneモデルを使う

whisper.cpp でOpenAI Whisperのファインチューニングモデルを実行する方法のメモです。

```bash
# whisper.cpp のコンパイル
git clone https://github.com/ggerganov/whisper.cpp
cd whisper.cpp
make

# OpenAI Whisperのclone
git clone https://github.com/openai/whisper whisper
# ファインチューニングモデルを取得
git clone https://huggingface.co/clu-ling/whisper-large-v2-japanese-5k-steps
# ggmlの出力先ディレクトリ
mkdir outputs

# whisperのファインチューニングモデルをggmlに変換
python3 ./models/convert-h5-to-ggml.py whisper-large-v2-japanese-5k-steps whisper outputs

# 音声認識の実行
./main -m outputs/ggml-model.bin -l ja -nt -f path_to_audio.wav
```
【Vue2】孫から親コンポーネントへのデータの受け渡しを簡単に行う

# 概要
孫コンポーネントから親コンポーネントにデータを渡したい状況って結構な頻度であると思います。
今回はcomposition apiでやっていますが、

何も考えずに書くとこんな感じ

```parent.vue
<template>
    <Button @update="update">
</template>

<script>
    update(value) {
      console.log(value)
    }
</script>
```


```child.vue
<template>
    <Button @update="update">
</template>

<script>
    update(value) {
    	this.$emit('update', value);
    }
</script>
```

```grandchild.vue
<template>
    <Button @update="update">
</template>

<script>
    update(value) {
    	this.$emit('update', value);
    }
</script>
```

ですが、このコンポーネントの階層がさらに深くなったとしたら、とてもじゃないけど、追いきれません。
絶対にもっと簡単にする方法があるやろってことで調べていたら、やっぱりありました。

# 解決方法
`$listeners`というものを使います。
親と最後の孫以外の挟まれているコンポーネントで使うことで無駄な記述がかなり減らせます！


```parent.vue
<template>
    <Button @update="update">
</template>

<script>
    update(value) {
      console.log(value)
    }
</script>
```


```child.vue
<template>
    <Button @update="$listeners['update']">
</template>

<script>
// ここで行なっていたemit処理が不要になる
</script>
```

```grandchild.vue
<template>
    <Button @update="update">
</template>

<script>
    update(value) {
    	this.$emit('update', value);
    }
</script>
```





# 補足
ちなみにvue3では`$listeners`はなくなり、`$attrs`というものになるみたいです。
https://v3-migration.vuejs.org/breaking-changes/listeners-removed.html

# 参考
https://jp.vuejs.org/v2/guide/components-custom-events.html
Go言語を学ぶ　～環境構築～　part1

## 目的
業務でもGoを使う機会がありそうだし、本格的にフリーな時間を使って触ることにする。
せっかくならフロントもTypescriptを使って考えてみたいけどそれは別の話とする。

## 目標
業務でいろいろ調べものをよくするからGithub REST API活用したなんかを作ることを目指す。
フレームワークはGinでもよかったが、echoに挑戦する

## この記事で目指すこと
バックエンドをGo、DBはMySQLの開発環境を作る。
個人的にはDockerが扱いやすいのでDockerで用意する。

## 開発環境の用意
### 初期作業
ネットを探せば見つかるだろうが、せっかくなので１からつくる
実はGoのコンテナを用意するのは少し面倒(何回か作ったのでなれてきてはいる）

#### STEP1 docker-compose.ymlおよびDockerFileの用意
STEP1でのフォルダ構成以下のようになる
```
.
├── echo/
│   └── Dockerfile
└── docker-compose.yml
```

用意する**docker-compose.yml**はGo絡みの作業を優先するのでまずは以下の内容で用意
```
version: '3'
services:
  go_echo:
    container_name: go_echo
    build:
      context: ./echo/
    volumes:
      - ./echo:/go/src/app
    tty: true
    environment:
      - TZ=Asia/Tokyo
```

**Dockerfile**も簡潔に用意する。作業時にはv1.20がリリースされているのでせっかくなのでこちらを使う
```
FROM golang:1.20-alpine

RUN apk update && apk add git

RUN mkdir ./app
WORKDIR /go/src/app
```

準備ができたらdocker-compose.ymlの場所でコマンドを実行
```
docker-compose up
```

起動したらコンテナの中に入る
```
docker exec -it go_echo /bin/bash(Windowsだとshの可能性あり）
```

コンテナ内でGoの初期化コマンドを実行する
```
go mod init app
```
実行結果として
```
go: creating new go.mod: module app
```
がでればOKです。
これで作業用のGoプロジェクトの準備が完了です

#### STEP2 MySQLの用意
続いて、MySQLをDocker環境内に用意する。
フォルダ構成は次のようになる。
```
.
├── database/(new)
├── echo/
│   ├── go.mod
│   └── Dockerfile
└── docker-compose.yml
```
**dockedr-compose.yml**にMySQLのサービスを追加
```
version: '3'
services:
  go_echo:
    container_name: go_echo
    build:
      context: ./echo/
    volumes:
      - ./echo:/go/src/app
    tty: true
    environment:
      - TZ=Asia/Tokyo

  go_echo_db:
    image: mysql:5.7
    container_name: mysql_host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: echo
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
      - ./database/data:/var/lib/mysql
    ports:
      - 3306:3306
```
dockerが起動しているときは再起動、起動していなければ起動を行う
```
docker-compose up
```
用意したdatabaseフォルダ内にファイルがたくさん作成されれば成功
これは、MySQLのDB情報を永続化させているため、初期軌道したときにMySQLの初期処理でファイルが用意されるため

環境構築はこれで完了！！

## 終わりに
今回は環境構築でDocker環境を用意しただけ
次からは本格的なecho周りの設定を行う
MySQL(学習用)

●クエリ・・データベースに対する命令のこと。データベースからデータを取得するために必要。

●テーブルの作成・・CREATE TABLEとしてテーブルの名前をつける（命令の区切りはセミコロン）

●DESC テーブル名 とすると、テーブルの構造を確認することができて、 SHOW TABLES; とするとテーブルの一覧を確認することができる

●テーブルの削除・・DROP TABLE.(if exists)＊一度テーブルを作成して再度実行するとエラーになる。そのため削除して新しくテーブルを作る

●テーブルの挿入・・INSERT INTO

●データ型・・整数：INT,TinYINT,BIGINT 実数：DECIMAL,FlOAT, 

●特定の文字列の中から一つだけ格納できるENUM というデータ型。複数格納したいならSET(データを挿入する際にはカンマ区切りで値を渡す。カンマ以外に空白などを入れてはいけない）

●値の範囲に制限をつける　UNIQUE

●主キーを設定する・・・PRIMARY KEY という指定をすることで、 id をこのテーブルのプライマリーキーつまり、主キーにすることができる

●データの抽出・・・SELECT * FROM レコード名 とすると、全てのレコードを抽出しなさいという意味。

●データの条件指定・・・「WHERE」が意味するのは、「どこのレコード（横の行）を取得するか

●データ取得の最大値・・最大で何件取得するか」を指定するためには、「制限する」という意味の「LIMIT」を用いる
●複数の条件を組み合わせる(WHERE)
AND
BETWEEN
OR
IN

・AND演算子を使うと、WHEREに複数の条件を指定することができる

●文字列の抽出・・
%
LIKE
BINARY
_
\%
\_

・ある文字を含むデータ」を取得したい場合は、「〜のような」という意味を持つ、「LIKE演算子
●文字列に関する関数・・SUBSTRING()・文字列の一部を切り出す関数

●ORDER BYでは「昇順」は「ASC」、「降順」は「DESC」と指定

●重複データの削除・・DISTINCTを用いると、検索結果から重複するデータを除くことができる

●合計はsum,平均はAVG,指定したカラムのデータの合計数はcount,最大最小はMAX,MIN

●データのグループ化はGROUP BYを用いる。＊GROUP BYの注意点　GROUP BYを用いる場合、SELECTで使えるのは、GROUP BYに指定しているカラム名と、集計関数のみ。

●データの絞り込み・・GROUP BYでグループ化したデータを更に絞り込みたい場合には、HAVINGを用いる

●実行順序によって、WHEREとHAVINGは検索対象に違いがある。WHEREはグループ化される前のテーブル全体を検索対象とするのに対し、HAVINGはGROUP BYによってグループ化されたデータを検索対象とする。

●サブクエリとは　SQLでは、クエリの中に他のクエリを入れることができる。この他のクエリをサブクエリという。

●AS・・ASを使うことでカラム名などに別名を定義することができる。「カラム名 AS "名前"」で、カラム名に定義する名前を指定

●JOINは複数のテーブルを1つに結合したいときに使う。ONで条件を指定。結合条件は、「ON テーブル名.カラム名 = テーブル名.カラム名」で指定

●記述順序
WHERE句 … 条件を指定してレコードを絞る
GROUP BY句 … 指定した属性でレコードをグループ化する
HAVING句 … 条件を指定してグループを絞る
ORDER BY句 … レコードの表示順を指定する

●LEFT JOINを使うことで、FROMで指定したテーブルのレコードを全て取得する。外部キーがNULLのレコードもNULLのまま実行結果に表示される。
初投稿



hello:relaxed:

unityでのゲーム開発を行おうと思います。
本格的に触れたのは2022年9月からです。「たのしい2Dゲームの作り方」翔泳社を主に用いて作成開始。
臨地実習などもあったため、間を空けながら勉強中。
3Dグラフィックやアニメーションについても興味あり。


疑問と解決を書いていきます。

自分の性格上、こだわると多分続かないので、気軽にやっていきます。
CDNやnpmを使用しないで、Element Uiを導入する方法

# 概要
　`Element Ui`をCDNで使用していた際、ソース元の不具合により、CDNが使用できなくなり、画面が表示されない不具合が発生しました。この問題を防ぐ為、CDNで読み込んでいる`Element Ui`のソースコードを開発環境に移植し、外的要因によるコンポーネントライブラリが使用できなくる問題を改善しました。
今回は、その方法について、備忘録も含めてご説明します。

# Element Uiの概要
「Element Ui」は、Vue.js2系で使用できるコンポーネントライブラリです。汎用性の高いUi(ユーザーインターフェース)のコンポーネントがたくさん用意されています。
（ユーザーインターフェースとは、ボタンやダイアログ等をユーザーが操作しやすいようにする部品を意味する)

**Element Ui 公式ドキュメント**
https://element.eleme.io/

# 今回の開発環境
- `vue.js`は、CDNで実装
- `Element Ui`は、ソース元のコードをローカル環境に複製

# 今回の開発環境のディレクトリー構成
使用するディレクトリーとファイルのみを記載しています
<font color="Red">※ 記載していないディレクトリーやファイルは、必ず消さずに残しておく</font>
```
.
├── element_ui/
│   └── lib/
│       ├── theme-chalk/
│       │   └── index.css
│       ├── umd/
│       │   └── locale/
│       │       └── ja.js
│       └── index.js
├── .gitignore
├── index.html
└── README.md
```

# 構築手順
## 1. Element Uiのコードをダウンロード
　下記のgit hubから`git clone` または `zipファイル`にて、コードをローカル環境に複製して下さい。
（筆者は、zipファイルでローカル環境に落としています)

https://github.com/ElementUI/lib

## 2. Element Uiをインポートする
ローカル環境に移植した`Element Ui`を読み込ませます。最初に、htmlファイルのheadタグに`index.css`を読み込ませるコードを記述します。
```html
<!-- Element Uiのcssを読み込 -->
<link rel="stylesheet" href="element_ui/lib/theme-chalk/index.css" />
```
次に、bodyタグの下に、下記の二つのscriptタグを記載して、`index.js`、`ja.js`を

```html
<!-- Element Uiのimport -->
<script src="element_ui/lib/index.js"></script>

<!-- Element UIを日本語化する為に使用する -->
<script src="./element_ui/lib/umd/locale/ja.js"></script>
```
これまで説明した行程を全て行えば、CDNを使用しないで、`Element Ui`が使用できると思われます。

## 注意事項
:::note alert
ソースコードを直接開発環境に複製する為、バージョンの更新を自身で行う必要があります。
その事をご理解した上で、今回の実装方法を行なって下さい。
:::

## 著者が構築した環境
　自信が実際に作成した環境を`git hub`に上げましたので、もし確認したい事がありましたら、閲覧して頂ければと思います。

https://github.com/kengo-sk8/no-cdn-element_ui

# 感想
 公式ドキュメントを参照しても、`Element Ui`のコードを開発環境に落として実装する方法は記述がなかった為、この環境を作るのに凄く苦労しました。今後もソース元のコードを落として、開発環境に導入する事はありそうなので、とても勉強になりました。
[laravel]Docker使用時のPHPのバージョンの上げ方

## はじめに
laravelを使っている中で`composer install`をする必要があったのだが、
PHPのバージョンが足りていないと怒られ、バージョンをあげなくてはいけなくなった。
その中で今回バージョンアップのやり方をまとめていく。

## PHPのバージョンをあげる方法
Dockerを使用してLaravelを実行している場合、
PHPのバージョンを上げるには以下の手順を実行する必要がある。

### LaravelプロジェクトのDockerfileを編集する
LaravelプロジェクトのルートディレクトリにあるDockerfileを開き、
PHPのバージョンを更新する必要がある。
具体的には、FROM命令を使用して、使用するPHPのバージョンを指定する行を変更する。
例えば、PHP 8.0を使用している場合、次のように記述されていると思われます。

css
Copy code
FROM php:8.0-fpm
これを、PHP 8.1を使用する場合には以下のように変更します。

```Dockerfile
FROM php:8.1-fpm
```
変更が完了したら、Dockerfileを保存する。

### Dockerイメージを再ビルドする
Dockerfileを編集した後は、Dockerイメージを再ビルドする必要がある。
Dockerイメージをビルドするには、以下のコマンドを実行する。

```terminal
docker-compose build
```
これにより、Dockerイメージが再ビルドされ、新しいPHPのバージョンが含まれるようになる。

### コンテナを再起動する
最後に、Dockerコンテナを再起動して、変更を反映する必要がある。
Dockerコンテナを再起動するには、以下のコマンドを実行する。

```terminal
docker-compose up -d
```
これにより、Dockerコンテナが再起動され、新しいPHPのバージョンが使用されるようになる。

これらの手順を実行することで、Dockerを使用してLaravelを実行している場合にPHPのバージョンを上げることができる。
ただし、変更が正しく反映されていることを確認するために、Laravelアプリケーションの動作をテストを必要に応じてすること。

以上
[AWS Q&A 365][Batch]AWSのよくある問題の毎日5選 #13

# 1. AWS Batchとは何ですか？また、そのコンポーネントは何ですか？
回答: AWS Batchは、AWSクラウド上でバッチコンピューティングワークロードを実行できるフルマネージドサービスです。そのコンポーネントには、ジョブ、ジョブ定義、ジョブキュー、およびコンピュート環境が含まれます。

# 2. AWS Batchを設定する方法は？
回答: AWS Batchを設定するには、AWSアカウントにサインアップし、管理ユーザーを作成し、コンピュート環境とコンテナインスタンス用のIAMロールを作成し、キーペアを作成し、VPCを作成し、セキュリティグループを作成し、AWS CLIをインストールする必要があります。

# 3. AWS Batchで作成できるジョブ定義の種類は何ですか？
回答: Amazon EC2リソース、AWS Fargateリソース、およびAmazon EKSリソースでシングルノードのジョブ定義を作成できます。また、Amazon EC2リソースでマルチノード並列ジョブ定義を作成することもできます。

# 4. AWS Batchでコンピュート環境を作成する方法は？
回答: コンピュート環境を作成するには、環境のタイプ、環境の状態、コンピュートリソース、およびAmazon EKSの設定（該当する場合）を指定する必要があります。AWS Fargateリソース、EC2リソース、またはEKSリソースを使用してマネージドコンピュート環境を作成するか、EC2リソースを使用してアンマネージドコンピュート環境を作成できます。

# 5. AWS Batchジョブを監視およびトラブルシューティングする方法は？
回答：AWS Batchジョブを監視およびトラブルシューティングするには、ジョブログ、CloudWatchコンテナインサイト、CloudWatchログ、およびCloudTrailを使用します。 また、AWS Batchジョブを検索およびフィルタリングし、ジョブ状態、ジョブ環境変数、自動ジョブの再試行、ジョブ依存関係、ジョブタイムアウト、およびGPUジョブを表示することもできます。
[AWS Q&A 365][Batch]Daily Five Common Questions #13

# 1. What is AWS Batch and what are its components? 
Answer: AWS Batch is a fully managed service that enables you to run batch computing workloads on the AWS Cloud. Its components include Jobs, Job Definitions, Job Queues, and Compute Environments. 
# 2. How do I set up AWS Batch? 
Answer: To set up AWS Batch, you need to sign up for an AWS account, create an administrative user, create IAM roles for your compute environments and container instances, create a key pair, create a VPC, create a security group, and install the AWS CLI. 
# 3. What are the different types of job definitions that I can create in AWS Batch? 
Answer: You can create single-node job definitions on Amazon EC2 resources, AWS Fargate resources, and Amazon EKS resources. You can also create multi-node parallel job definitions on Amazon EC2 resources. 
# 4. How do I create a compute environment in AWS Batch? 
Answer: To create a compute environment, you need to specify the type of environment, the state of the environment, the compute resources, and the Amazon EKS configuration (if applicable). You can create managed compute environments using AWS Fargate resources, EC2 resources, or EKS resources, or unmanaged compute environments using EC2 resources. 
# 5. How do I monitor and troubleshoot AWS Batch jobs? 
Answer: You can monitor and troubleshoot AWS Batch jobs using job logs, CloudWatch Container Insights, CloudWatch Logs, and CloudTrail. You can also search and filter AWS Batch jobs and view job states, job environment variables, automated job retries, job dependencies, job timeouts, and GPU jobs.
【Oracle】名簿から「○行」始まりの人は何人いるか抽出するSQL文

次のように、名簿を表すNAMELISTテーブルがあり、苗字(LAST_NAME)があ行始まりは何人か、か行始まりは何人か・・・、わ行始まりは何人か知りたいとする。使用DBはOracle。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230599/85b4cec6-032f-ee06-13ed-4e719d3dd2df.png)

これを実現したSQLは以下。
Oracleでは、正規表現はREGEXP_LIKE関数を使う。
先頭が「あいうえお」は「あ行」として扱い、先頭が「かきくけこ」は、「か行」として扱い・・・を列挙していく。その後、COUNTするのにGROUP BYする。
```sql:what_column_count.sql
SELECT CASE
WHEN REGEXP_LIKE(LAST_NAME, '^[あいうえお]') THEN 'あ行'
WHEN REGEXP_LIKE(LAST_NAME, '^[かきくけこ]') THEN 'か行'
WHEN REGEXP_LIKE(LAST_NAME, '^[さしすせそ]') THEN 'さ行'
WHEN REGEXP_LIKE(LAST_NAME, '^[たちつてと]') THEN 'た行'
WHEN REGEXP_LIKE(LAST_NAME, '^[なにぬねの]') THEN 'な行'
WHEN REGEXP_LIKE(LAST_NAME, '^[はひふへほ]') THEN 'は行'
WHEN REGEXP_LIKE(LAST_NAME, '^[まみむめも]') THEN 'ま行'
WHEN REGEXP_LIKE(LAST_NAME, '^[やゆよ]') THEN 'や行'
WHEN REGEXP_LIKE(LAST_NAME, '^[らりるれろ]') THEN 'ら行'
WHEN REGEXP_LIKE(LAST_NAME, '^[わ]') THEN 'わ行'
ELSE 'etc.' END AS WHAT_COLUMN,
COUNT(*)
FROM NAMELIST
GROUP BY CASE
WHEN REGEXP_LIKE(LAST_NAME, '^[あいうえお]') THEN 'あ行'
WHEN REGEXP_LIKE(LAST_NAME, '^[かきくけこ]') THEN 'か行'
WHEN REGEXP_LIKE(LAST_NAME, '^[さしすせそ]') THEN 'さ行'
WHEN REGEXP_LIKE(LAST_NAME, '^[たちつてと]') THEN 'た行'
WHEN REGEXP_LIKE(LAST_NAME, '^[なにぬねの]') THEN 'な行'
WHEN REGEXP_LIKE(LAST_NAME, '^[はひふへほ]') THEN 'は行'
WHEN REGEXP_LIKE(LAST_NAME, '^[まみむめも]') THEN 'ま行'
WHEN REGEXP_LIKE(LAST_NAME, '^[やゆよ]') THEN 'や行'
WHEN REGEXP_LIKE(LAST_NAME, '^[らりるれろ]') THEN 'ら行'
WHEN REGEXP_LIKE(LAST_NAME, '^[わ]') THEN 'わ行'
ELSE 'etc.' END
ORDER BY WHAT_COLUMN;
```

実行結果は以下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3230599/f8a94076-615b-4797-bfda-aa8a179630af.png)

正規表現とCASEを上手く使えば、上記のようなことが実現できるということで備忘録として残しておいた。
ChatGPT選手権！エンジニアリングに組み込んでみたらこうなりました LT大会　資料一覧

[「ChatGPT選手権！エンジニアリングに組み込んでみたらこうなりました LT大会」](https://findy.connpass.com/event/276736/?utm_campaign=event_message_to_selected_participant&utm_source=notifications&utm_medium=email&utm_content=title_link)の資料一覧です。
 

[イベント資料一覧](https://findy.connpass.com/event/276736/presentation/?utm_campaign=new_event_links_to_participant&utm_source=notifications&utm_medium=email&utm_content=detail_btn)

[アーカイブ動画](https://findy-code.io/events/w9DsoeuNu7Keh/archive)


[LT①「ChatGPTによるデータ変換がもたらすインパクト」](https://speakerdeck.com/masahiro_nishimi/chatgptniyorudetabian-huan-gamotarasuinpakuto)


[LT②「バクラクに入れ込むためのPOC(仮)」](https://speakerdeck.com/yuya4/layerx-poc-with-chatgpt)


[LT③「一緒にスクラム開発: GPT-4と人間が共創するプロダクトの進化」](https://speakerdeck.com/itohiro73/xu-nisukuramukai-fa-gpt-4toren-jian-kagong-chuang-suruhurotakutonojin-hua)


[LT④「スマートラウンドで試してみたChatGPT活用成功/失敗事例8選！」](https://speakerdeck.com/doyaaaaaken/shi-bai-shi-li-8xuan)

[LT⑤「ChatGPTをプロダクトに入れる開発が“毎日がAfter GPT”だった件」](https://speakerdeck.com/lmi/chatgpt-lt-link-and-motivation)

[LT⑥「LLMに論文を読ませてJARVISを作る」](https://www.slideshare.net/SasakiYuichi1/20230323spiralai-256741851)
 

[LT⑦「エンジニアキャリアまとめ作ってみた(仮)」](https://speakerdeck.com/sasanoshouta/chatgptxuan-shou-quan-ltda-hui-at-findy)
Spring Security その2.5〜デフォルトのログアウト画面

カスタムログインページを作成する中で、ログアウト処理で少しハマってしまったので、先にその話を

## .formlogin()を実装すると/logoutのデフォルト画面は提供されなくなる
 .formlogin()を実装する前はGETリクエスト（URL直接指定）でも/logoutへの遷移が可能であった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555551/15ce11f6-4f9c-f6a5-d146-a660d199e2de.png)

上記の画面が表示され、Log Outボタンを押下することでログアウト処理が実施され、ログアウトを行うことができた。

しかし、.formlogin()を実装後に/logoutへGETリクエストを送信すると以下のエラーとなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555551/93ed1e38-2644-806a-cdb1-99c05864046f.png)

色々調べたら、.formlogin()を実装するとデフォルトのログアウト画面（正確にはログアウトを行うための画面）は提供されなくなり、直接ログアウト処理を呼び出すことになるらしい・・・

## /logoutへはPOSTリクエストである必要がある
では、なぜ、直接ログアウト処理を呼び出すとエラーとなるのか。
それは/logoutへのリクエストはPOSTである必要があるから。
SpringSecurityでは、GETリクエスト時はCSRFのチェックは行わないが、ログアウトの時はCSRFトークンのチェックを行うらしい。
GETではCSRFトークンは送信されないので、エラーとなる。

## 解決策
/logoutへはPOSTでCSRFトークンを送信してあげる
やり方は簡単。Thymeleafで「th:action」でPOST送信するだけで、CSRFトークンを送信してくれます。
具体的にはこんな感じ
```html
    <form th:action="@{/logout}" method="post">
        <input type="submit" name="logout" value="ログアウト"/>
    </form>
```

これでログアウトが可能となり、.formloinの実装（カスタムログインページ）ができるようになる。
Rubyを使用するメリット、デメリット

## はじめに
今までなんとなくRubyを使っていたので、Rubyを使うことでどんな恩恵、苦労が得られてるのかを知りたくなりました。

## メリット
+ __学習コストが低いこと__

Rubyは日本発祥の言語なため、日本人が使う機会が多くドキュメントや参考書が豊富。
そのため困った際やわからないことがあった時に解決しやすい。

+ __シンプルな構文が多く、柔軟性が高いため学びやすい__
+ __オブジェクト指向なため、保守性や再利用性が高い__
+ __インタプリタ型言語のため、デバッグがしやすい__

## デメリット
+ __柔軟性が高いことで、同じ処理でも人によって書き方が違うなど、差が出やすい。__
+ __将来性が高いと言われている、機械学習の開発に不向き__
+ __コンパイル式より実行速度が遅い__
push済みのブランチに差分を取り込むGit操作の検証

以下のサンプルアプリを使って確認を行っていきます。

![sample-app1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/70f2255f-6345-6149-42ed-0780f331136b.jpeg)

## 想定シナリオ

派生元ブランチに取り込まれた機能をリモートにプッシュ済みのブランチに取り込む

### シナリオ

画面にhelloを追加する作業を担当することになり、コンポーネントを更新しています。
すると追加依頼があり、別のブランチから取り込まれた画像も今回の作業で使うことになりました。
この時のシナリオをmergeとrebaseでそれぞれ実践してみます。

### merge案

まずは完成形から。

![sample-app3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/d1a897c3-00a2-1531-88af-124843419e09.jpeg)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/68b9a977-52c1-d8fe-a487-002a57458aad.png)

別ブランチから取り込まれた画像を使うために、ローカルで派生元のブランチ`main`を作業中のブランチ`featuer/hello`にマージしました。
その後、取り込んだ機能を使ってソースコードを更新しマジリクを作成。`main`にマージしています。

マジリクの内容を確認したところ、マージコミットが含まれています。取り込んだ画像作成のコミットや変更は含まれませんでした。

![Feature-hello-by-dfukui-smn-·-Pull-Request-2-·-dfukui-smn-git-concurrent-development.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/dbf10cd1-d6b2-bbfe-aa23-41354895725c.jpeg)

![Feature-hello-by-dfukui-smn-·-Pull-Request-2-·-dfukui-smn-git-concurrent-development (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/b88d003f-dd41-0014-dfe1-ba7240bc6459.jpeg)

画像を追加したブランチの変更はこちら。`feature/hello`には含まれなかった部分。

![ロゴを追加-by-dfukui-smn-·-Pull-Request-1-·-dfukui-smn-git-concurrent-development.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/a5d5d18e-4012-2a1d-1141-d399ae903b04.jpeg)

### rebase案

まずは完成形から。

![sample-app.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/50cd6ab0-bea3-cb22-7c29-407afc162141.jpeg)


![スクリーンショット 2023-03-23 22.02.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/8c7395ad-6a68-6d7a-1d2e-7ecda153b1cd.png)


別ブランチから取り込まれた画像を使うために、ローカルで作業中のブランチ`featuer/hello2`を派生元のブランチ`main`にリベースしました。
リベースによって`featuer/hello2`の変更は以下のように`main`に追加して実装した形になりました。

![スクリーンショット 2023-03-23 21.49.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/c38b694f-edca-f022-e528-129abeebc653.png)

それぞれの機能を使ってソースコードを更新しソースコードをプッシュしますが、ローカルとリモートの履歴に差異が生まれたためエラーになりました。
作業中のブランチ`featuer/hello2`は自分以外は使用しないブランチのため`-f`で強制プッシュします。

```sh
$ git push -f 
```

マジリクを作成。`main`にマージします。

マジリクの内容を確認したところ、マージコミットがありません。


![Feature-hello2-by-dfukui-smn-·-Pull-Request-4-·-dfukui-smn-git-concurrent-development.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/0b4df79c-fcd6-5308-94f1-0051b073cd71.jpeg)

![Feature-hello2-by-dfukui-smn-·-Pull-Request-4-·-dfukui-smn-git-concurrent-development (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235642/3c9313b9-0c66-a0f1-c5ff-cd3f05f79d9a.jpeg)


## まとめ

merge案よりもrebase案のほうが履歴が見やすいのが良いと思いました。
rebase案だと強制プッシュが必要になりますが自身しか操作しないブランチであれば問題ないので、今後はrebaseを使いながら履歴を見やすい状態で維持したいと思います。
【Docker基礎】Dockerとは？利点と構成

## この記事について
Dockerについて学習を始めたため、備忘録を残していきます。

## Dockerとは？コンテナとは？
Docker：コンテナ技術の名称
コンテナ：互いに影響しない隔離された実行環境を提供する技術

### 隔離された実行環境のメリット
**一台のサーバーで複数のシステムを実行する際の不都合が起こりにくい**

- 同じサーバー上で動く複数システムが同じフレームワークを使っているケース
    - 実行環境が隔離されていない場合：
　　いずれかのシステムでのフレームワークのアップデートの影響が他システムにも及ぶ
    - 実行環境が隔離されている場合：
　　コンテナごとに異なるバージョンのフレームワークを使用することができる


**ポータビリティ性がある**

- システムが動くのに必要なファイルはすべてそれぞれのコンテナ内に含まれる。
コンテナ外のものが参照されることがない特性を"ポータビリティ性"（持ち出し可能）という。

    ⇨ ポータビリティ性があるため、コンテナを別のサーバーにコピーして動かすのが容易。


## Dockerの構成要素
		
- Dockerクライアント		
    Dockerデーモン(後述)と通信してDockerコンテナの構築・実行・配布を行う。	
ユーザーは直接デーモンと通信せず、Dockerクライアントを通じて通信を行う。
	
- Dockerホスト		
    - Dockerデーモン
　メインのサーバ。イメージの管理・コンテナの起動や停止を行う。
    - Dockerイメージ
　システムを動かすのに必要なファイル群。
    - Dockerコンテナ
　Dockerイメージから作成されるマシンの実態。
	
- レジストリ		
    Dockerイメージの保管システム。Docker公式はDocker Hub。	
pullすることでイメージを誰でも使用することができる。	

## 参考
書籍『さわって学ぶクラウドインフラ docker 基礎からのコンテナ構築』
https://docs.docker.jp/engine/understanding-docker.html (Docker公式サイト)
UdonSharpのinputeventの一部の変数に関する備忘録

この記事はVCC2.0.2を使用しています(2023/3/23現在の最新版)。
使用機材と環境は以下の通りです。
- Unity(2019.4.31f1)
- Meta Quest2と付属コントローラ)
- UdonSharp
- VCC2.0.2

UdonSharpでスクリプト書いていく上で調べても全然出てこず自前で確認する羽目になってめんどくさ..って思ったので備忘録として書き残しておきます(どこかにあるなら調査不足ですね..教えてください)。

# 確認したこと
### Input EventのButton Eventに関するargsのhandTypeの出力値
確認方法: Debug.Logに出力してHMDでコントローラ使用
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Use(trigger)とGrab(grip)のそれぞれについて出力して確認しています

結果: args.handTypeの出力値: LEFT,RIGHT(全部大文字でした.後型がStringでは無いので条件に使う場合は注意)

(Debug.Logに出力するコードやログの出し方については https://tech.framesynthesis.co.jp/vrchat/ を見てください。)

とりあえずは以上です。(もしかしたら今後必要なものが増えてなかったら追記するかもしれません..)
中規模AWSシステムのTerraformディレクトリ構造

先日、中規模AWSシステムを０から構築する機会がありました。構築中、コードが長くなったり、ファイルが多くなったり、関数が多くなったり悩みのつきなかったディレクトリ管理でしたが、自分なりに最適解を導いたのでここに記録しておきます:pencil:

### 前提
dev（開発）とprd（本番）でわかれてます。環境差異が非常に多く、共通化できる項目が少なかったため、次回も新たにディレクトリをきるほどのモジュール化は不要と考えました。またセキュアな環境のため、サービスによってはコードが非常に長くなりました。そういった項目は２つくらいにならわけてもよさそうなので、ファイル分割の余地がありそうなものには★をつけています。

### ディレクトリ
```
#必須の４ファイル
tfstate.tf
provider.tf
output.tf
terraform.tfvars

#IAM系 セキュアな環境ほどコードが長くなりやすいです。
iampolicy.tf
iamgroup.tf
iamrole.tf
iamuser.tf

#このへんもセキュアな環境ほどコードが長くなりやすいです。
network.tf（VPC、サブネット、ルートテーブル、DHCPオプションセット、ピアリング、エンドポイント）★
securitygroup.tf★
EC2.tf★

#CWも同じくセキュアなほど長くなりやすい。
cloudwatch-event-rule
cloudwatch-metric-filter★
cloudwatch-metric-alarm★

S3.tf
trail.tf

#jsonは下記ディレクトリを作成して格納
bucketpolicy
event_pattern
kmspolicy
inpolicy（インラインポリシー）
mgpolicy（ユーザー管理ポリシー）
```

### 設計
一度作りはじめるとディレクトリ構成を修正するは困難です。なので、システムの要件をしっかりと把握した上でディレクトリ構成は検討すべきです。要件から構成をどう考えるかは経験するしかないので、数をこなすことでより理想的なディレクトリ構造を設計できるのかなと思いました:fire:

### サービスごとのデプロイ
それからコード量があまりにも多い（=デプロイが遅い）＆AWSコンソールを意図しないところ（IAMの範囲内で）から操作される（=Terraform側と差分がでる）可能性があるという環境特有の理由から、一括デプロイのリスクを減らすためにサービスごとにデプロイできないかとかも考えました。ただ、この事象はあまりに環境特有すぎる&コードの管理が複雑になるため、Terraform側の対処するのは相当なレベルの問題になってから考えるでよさそうでした:fire: :fire:

### 参考
そもそもterraform自体が:question:なお方へ

https://qiita.com/hiyanger/items/9efdc570e6cfed5aab13

その他、本ディレクトリ構造に関して参考になった記事:pray:

https://dev.classmethod.jp/articles/directory-layout-bestpractice-in-terraform/

https://qiita.com/reireias/items/253529c889cafb3fa4c7

https://zenn.dev/himekoh/articles/202208191916

https://dev.classmethod.jp/articles/terraform-bset-practice-jp/
【Java】初めてJavaに触れた「スッキリシリーズ」

# 【Java】を勉強していこう
Javaを学びたい！ということで本買いました:relaxed:
お勧めによく出てくる本。

https://sukkiri.jp/books/sukkiri_java3

https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BJava%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1%E6%B8%85%E5%96%AC/dp/4295007803

これを買ってみました！


どうやって設定していくんだろうか～
と思いながら本を開いたら…
なんと！
`dokojava`というクラウドサービスを展開ているようで
手間のかかるローカル環境開発の構築をすることなく、今すぐJavaを体験することが出来るらしい…！始めやすくてとってもよさそう！
早速やってみよう:v:


# dokojava新規登録

https://dokojava.jp


こちらから入って会員登録していきましょう！
メールアドレスとパスワードで簡単に登録できます。


登録して気が付いたのですが…
Pythonとかも使えるのですね！！
Pythonもかなり気になっている言語で本持っているので
何時か挑戦したいです…

登録したら本を見ながら進めていきましょう～:fist_tone1:
JavaScriptでのAjaxの使い方基礎

JavaScriptでのAjax通信について簡単にまとめました。JavaScriptとの組み合わせで様々な実装ができますが、雛形となる知識を纏めています。

# 「Ajax」とは？
Ajax（Asynchronous JavaScript + XML）の略称で、ブラウザ上で非同期通信を利用して、ページの内容を更新する通信技術のことを言います。

# 非同期通信とは？
非同期通信とは、リクエストを出してからデータが返って来る前の処理を、ブラウザ上で行い、更新した部分だけをリクエストして処理を行う、という通信の事を言います。
クライアント側で動くjavascriptが直接サーバーとのやりとりを行い、それによって取得したデータを元に、HTMLファイルを更新するという仕組みになっています。

通常の通信ではクライアントからのリクエストをサーバーに送り、サーバーからデーター(HTMLファイルなど)が帰ってきて、レスポンスが反映される様になっています。そのためレスポンスが返ってくるまで操作が一切できなくなってしまいます。

非同期通信の場合は、レスポンスを待つことなく次の操作に移ることができます。
また、ページ内の必要な部分だけを書き換えることができ、更新する必要のない部分を無駄に読み込み直す時間がないため、ユーザーは快適にブラウザを操作することができるメリットがあります。


# Ajaxをjavascriptで使う方法
## 「XMLHttpRequest()」によるAjax通信の作り方

JavaScriptには、サーバーと非同期で通信するために「XMLHttpRequest()」というAPIが提供されています。
XMLHttpRequestとは、WebブラウザとWebサーバーとの間で、データのやり取りを行うために利用するオブジェクトのことです。

### インスタンスの作成
まずは下記の様にインスタンスを作成します。
```javaScript:test.js
let xhr = new XMLHttpRequest();
```
### 
インスタンスに対して、「どんな方法で」、「どのサーバーに」、「いつデータを取得するか？」を決めていきます。

```javaScript:test.js
var xhr = new XMLHttpRequest();
 
xhr.open("「どんな方法で？」", "「どのサーバーに？」");
xhr.send();
 
xhr.onreadystatechange = function() {
 
    if("「いつデータを取得するか？」") {
 
        //データを取得した後の処理を書く
    }
}
```



### open()
XMLHttpRequestオブジェクトのメソッドの一種で、リクエストの内容(「どんな方法で」、「どのサーバーに」)を指定するためのメソッドです。
第一引数にはHTTPメソッド(POST\GET)、第二引数にはパスやURLを記述します。

### POSTで通信する場合
`xhr.open("POST", "/posts");`のように表記します。

### 「readyState」、「status」による条件分岐の方法
`xhr.onreadystatechange`でサーバーから取得したデータを受け取ることができます。ただし、「通信が完了しているか？」「通信が成功したか？」などをIF文で条件分岐しながら確認する必要があります。



通信が完了して成功しているのかどうかが分からないと目的のデータを取得できないため、`readyState`を使って条件分岐の処理を記述していきます。
さらに、基本的にはサーバーと正常な通信をしている場合は、`status`の値が「200」になるため、二つを組み合わせて条件分岐をします。

```javaScript:test.js
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
 
        //データ取得処理を書く
 
    }
};
```
xhr.readyStateは通信の状態を表す数値を返します。
対応表は以下の通り

| 値  |     状態  | 	解説                               |
| --- | ---------| -------                            |
| 0    | 準備段階 |  まだ通信は行われていない状態           |
| 1    | 準備完了 |  通信を行う準備が完了している状態        |
| 2    | 通信開始 |  サーバーと通信が始まっている状態        |
| 3    | 受信中  | サーバーから目的のデータを取得している状態 |
| 4    | 通信完了 | 成功、失敗に関わらず、通信を終了した状態   |

xhr.statusでレスポンスにおける数値の HTTP ステータスコードを返します。
対応表は以下の通り

| 値  |     状態  | 	解説                               |
| --- | ---------| -------                            |
| 200   | 成功   |  特に問題なく通信が成功した状態         |
| 401   | エラー |  認証が必要なため通信できない状態        |
| 403   | エラー |  アクセスが禁止されていて通信できない状態  |
| 404   | エラー | 情報が存在しないために通信できない状態    |
| 500   | エラー | サーバー側の不具合で通信できない状態      |
| 503   | エラー | サーバーに負荷がかかって通信できない状態   |

### send()
XMLHttpRequestオブジェクトのメソッドの一種で、リクエストを送信するメソッドになります。

以上がAjax通信の雛形になります。

### formDatオブジェクト
sendメソッドで送るデータを作成できます。
newでインスタンスを作成し、appendメソッドでキーと値を追加し、任意のデータを作成できます。
```javaScript:test.js
let formData = new FormData();
formData.append("キー", "値");

```

HTMLの`<form>`要素からFormDataオブジェクトを作成することもできます。

```javaScript:test.js
let form = document.getElementById("form");
let formData = new FormData(form);

```

### responseレスポンスプロパティ
XMLHttpRequestオブジェクトのプロパティの一種でサーバーからのレスポンスに関する情報が格納されたプロパティのです。

`xhr.response`で取得できます。

返ってきたレスポンスのデータを使い、実行処理を記述することで、非同期での処理を実行できます。
「良いコード悪いコードで学ぶ設計入門」を読んだので不変な値オブジェクトをPythonで実装してみる

# はじめに
積読になりかけていた良いコード悪いコードで学ぶ設計入門を読了した。
私はこれまで設計に関する本としては自走プログラマーやリーダブルコードなどを読んできたが、この本では主にドメイン駆動開発の考え方に基づいて、保守性、特に変更容易性の向上を目的とした設計手法を取り扱っている。

https://www.amazon.co.jp/%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89-%E6%82%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E5%AD%A6%E3%81%B6%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80-%E2%80%95%E4%BF%9D%E5%AE%88%E3%81%97%E3%82%84%E3%81%99%E3%81%84-%E6%88%90%E9%95%B7%E3%81%97%E7%B6%9A%E3%81%91%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9-%E4%BB%99%E5%A1%B2/dp/4297127830

> 変更容易性を高めることは、ソフトウェアの成長性を高めることなのです。ソフトウェアの成長性を高めることが、本書の意義です
(15章　設計の意義と設計への向き合い方)

大規模開発における数万行のコードを長期的に成長可能なものにするための設計手法の基礎がクラス設計、メソッド設計、命名、SOLID原則、エンジニア組織など広い領域にわたって記載されており、読み物として非常に面白かった。しかし、かといって自分の技術力が爆上がりするかというと、そんなことはない。技術というのはコードを書いて試しながら身につけていくものであり、本を読んだだけでは一朝一夕に身につかないものであると感じた。（本の中にもインプット２割アウトプット８割を意識せよとある）（８割はキツくない？）
というわけで少しでも覚えたての設計手法を手に馴染ませるため、Javaで書かれた本書のコードを私の業務上利用しているPythonで書くとどうなるのかやってみた。

# 値クラスの設計
今回は6章におけるinterfaceの実装をPythonで書き換える。

## 抽象基底クラスによるInterfaceの実装
JavaのinterfaceはPythonには存在しないため、抽象基底クラスabcを利用する。
pythonで基底クラスをつくるabcにはabstractmethodデコレーターがあり、これで修飾されたメソッドとプロパティのすべてがオーバーライドされていない限り、インスタンス化できなくなる。


```magic.py
class Magic(ABC):
    @abstractmethod
    def cost_magic_cost(self) -> MagicCost:
        pass

    @abstractmethod
    def attack_power(self) -> AttackPower:
        pass

    @abstractmethod
    def technical_power(self) -> TechnicalPoint:
        pass
```
abstractmethod指定されたメソッドを１つでもオーバーライドしていない継承クラスの場合、インスタンス化がTypeErrorとなる。
```python
class Mera(Magic):
    def cost_magic_cost(self) -> MagicCost:
        return super().cost_magic_cost()
    
    def attack_power(self) -> AttackPower:
        return super().attack_power()

    #technical_powerの実装がない
```

```test_magic.py
class TestMagic:
    def test_abstractmethod(self):
        with pytest.raises(TypeError):
            mera = Mera() #TypeErrorになる
```
以上のように、abc.abstractmethodデコレーターにより必要なメソッドが定義されていないクラスの実装を防げる。

## dataclassによる不変
加えて、攻撃魔法を実装する際にはdataclassを利用し、frozen=Trueとすることで、メソッドやプロパティを不変にできる。


```magic.py
@dataclass(frozen=True)
class Fire(Magic):
    member: Member

    def cost_magic_cost(self):
        return MagicCost(2)

    def attack_power(self):
        value = 20 + self.member.level
        return AttackPower(value)

    def technical_power(self):
        return TechnicalPower(0)
```
データクラスにして、frozen=Trueとすることで不変にできる。
例えば、attack_powerに代入を実行しようとすると以下のエラーが出る。 
```
E   dataclasses.FrozenInstanceError: cannot assign to field 'attack_power
```
しかし本当の本当に不変なわけではなく、以下のようにすれば変更は可能。
```
object.__setattr__(fire, "attack_power", 0)
```
さらにイミュータブル型の場合には、削除や追加、変更が可能になってしまう。

https://qiita.com/valusun/items/621bc29745e686d92386

というわけで、frozenは不変性を模倣しているだけであって、変更される可能性がなくなったわけではないことには注意が必要。


## 参考
https://docs.python.org/3/library/abc.html

https://docs.python.org/3/library/dataclasses.html

https://ivergara.github.io/ABC-and-dataclasses.html