OmniAICreator/Qiita-1.07M huggingface dataset:
int,Index,Rangeをまとめたい

# 配列の引数
配列の引数として、int型に加えて、Index,Range型が追加された。
これによって、関数の引数にもIndex,Rangeが使えるようになって、使い方の幅が広がった。
しかし、int,Index,Rangeそれぞれに対して関数のオーバーロードをすると~~面倒臭い~~ケアレスミスの懸念が増える。

# int,Index,Rangeを全て受けられるようにしたい
<details><summary>旧</summary>

```C#
var ex = new Sum();
int i = ex[5];
int j = ex[^3];
int k = ex[2..5];
```
とできるクラスを作るときに
```C#
class Sum
{
    int[] values;
    public int this[int i] => values[i];
    public int this[Index i] => values[i];
    public int this[Range r] => values[r].Sum();
}
```
ではなく
```C#
class Sum
{
    int[] values;
    public int this[XRange r] => values[(Range)r].Sum();
}
```
とかけるようなXRangeクラスを作りたい。

もちろん、合計しない場合は、int,IndexとRangeで戻り値の型が違うので、あんまりメリットはない。
また、前述のように関数が1つの場合は、素直に全てオーバーロードを書いたほうが良いだろう。

それでも、同じような関数が複数あった場合に便利だと考えた。
というか必要に迫られて実装した。
</details>
<details open><summary>新（例を見直した）</summary>

```C#
var ex = new Sum();
int i = ex[5, 3];
int j = ex[^3, ^2];
int k = ex[2..5, 3..8];
```
とできるクラスを作るときに
```C#
class Sum
{
    int[][] cells;
    public int this[Index row, Index column] => cells[row][column];
    public int this[Index row, Range columns] => values[row][columns].Sum();
    public int this[Range rows, Index column] => values[rows].Sum(r => r[column]);
    public int this[Range rows, Range columns] => values[rows].Sum(r => r[columns].Sum());
}
```
ではなく
```C#
class Sum
{
    int[][] cells;
    public int this[XRange rows, XRange columns] => cells[rows].Sum(r => r[columns].Sum());
}
```
とかけるようなXRangeクラスを作りたい。

もちろん、合計しない場合は、int,IndexとRangeで戻り値の型が違うので、あんまりメリットはない。
例は、行列の2次元だが、次元が増える分だけメリットも増えると思う。
</details>

# XRangeクラス
前述で使用したXRange関数の実装はこれ
```C#
public class XRange
{
    public static implicit operator XRange(int i) => new(i..++i);
    public static implicit operator XRange(Index i) => new(i..Next(i));
    public static implicit operator XRange(Range r) => new(r);
    public static implicit operator Range(XRange r) => r.value;

    static Index Next(Index i) => new(i.Value + (i.IsFromEnd ? -1 : 1), i.IsFromEnd);

    readonly Range value;

    XRange(Range r) => value = r;

    public Index Start => value.Start;

    public Index End => value.End;

    public (int Offset, int Length) GetOffsetAndLength(int length)
    {
        var left = value.Start.GetOffset(length);
        var right = value.End.Value > length ? left + 1 : value.End.GetOffset(length);
        return (left, right - left);
    }
}
```

# まとめ
暗黙の型変換を使って、int,Index,Rangeから変換できるようにした。
勝手に変換されてしまうので、ソースが読み難くなる気もする。
型変換を何回も挟むので、パフォーマンスも悪いと思われる。
cpuの割り当て時間

# プロセススケジューラ
* 一つの論理CPU上で同時に```動けるプロセスは一つだけ```。
* 実行可能な複数のプロセスに、タイムスライスと呼ばれる単位で```順番にCPUを使わせる```

### 気づき
繰り返し一つのプロセスに対して少しずつ使用時間を割り当てることで、複数のプロセスを一つのCPUで処理できるのか。

# プロセスの経過時間、使用時間
## 経過時間
```プロセスが開始してから終了するまでの経過時間```。ストップウォッチでプロセス開始時から終了時までを経過した値というイメージ。
## 使用時間
```プロセスが実際に論理CPUを使用した時間```

### timeコマンド(CPUの経過、使用時間を計測）
```
root@********:**************# time ./load.py

real	0m2.516s
user	0m2.243s
sys	0m0.179s
```
realは```経過時間``` userとsysは```使用時間```を示します。userはプロセスがユーザランドで動作していた時間を指します。
これに対してsysは、プロセスによるシステムコール発行の延長でカーネルが動作していたときの時間を指します。
#### 論理CPUを使わないコマンドの場合
```
root@********:**************# time  sleep 3

real	0m3.008s
user	0m0.004s
sys	0m0.000s
```
開始直後にCPUを手放しスリープ状態となり、....userとsysはほぼ０です。

#### 論理CPUが一つに対して一つのプロセスの場合
プロセス数で指定した数だけ動作させて、全ての終了を待ちます。
```
root@********:**************# ./multiload.sh 1

real	0m2.400s
user	0m2.227s
sys	0m0.121s
```
#### 論理CPUが一つに対して複数のプロセスの場合
```
root@********:**************# ./multiload.sh 2

real	0m4.196s
user	0m1.922s
sys	0m0.135s

real	0m4.318s
user	0m1.993s
sys	0m0.160s
root@********:**************# ./multiload.sh 3

real	0m6.711s
user	0m2.080s
sys	0m0.115s

real	0m6.791s
user	0m2.113s
sys	0m0.119s

real	0m6.801s
user	0m2.156s
sys	    0m0.084s
```
#### 気づき
一つに時間を割けられないのでその分時間がかかっている。

#### 論理CPUが複数に対して複数のプロセスの場合
```
root@********:**************# ./multiload.sh -m 1

real	0m2.433s
user	0m2.185s
sys	0m0.187s
root@********:**************# ./multiload.sh -m 2

real	0m4.400s
user	0m2.032s
sys	0m0.110s

real	0m4.509s
user	0m2.102s
sys	0m0.136s
root@********:**************#./multiload.sh -m 3

real	0m6.310s
user	0m1.955s
sys	0m0.110s

real	0m6.537s
user	0m2.129s
sys	0m0.039s

real	0m6.718s
user	0m2.258s
sys	0m0.075s
```
#### 気づき
それぞれレニ時間を避けるから早くなっている。

#### realよりもuser＋sysが大きくなることもある
```計測の精度がそれほど高くないことから来ています```。あまり気にしてもしょうがないので「こういうこともある」という意識を持っていただければいいです。
```
root@********:**************# time ./multiload.sh -m 2

real	0m4.215s
user	0m1.940s
sys	　　　　　　　　0m0.129s

real	0m4.366s
user	0m2.106s
sys	　　　　　　　　0m0.084s

real	0m4.378s
user	0m4.054s
sys	    0m0.213s
```
timeコマンドで得られるuserとsysの値は、情報取得対象のプロセス、および終了済みの子プロセスの値を合計したものなのです。したがってあるプロセスが子プロセスを生成して、それらがそれぞれ```別の論理CPUで動作したような場合はrealよりもuser+sysの値が大きくなり得ます```。

#### 気づき
自分のは大きくならなかった。

# 出典
https://gihyo.jp/book/2022/978-4-297-13148-7

# 感想
まだまだ
コマンドプロンプトでmp4をwavファイルへ変換するコマンド作ってみた

# 背景
最近音楽にはまって録画した動画ファイルから音楽ファイルへ変換できるコマンドがったらいいなと思い暇つぶしで作った。
どっか間違っていても温かい目で見てください...

# 不具合
なぜか変換後のファイル名が入力されないです.....

# 早速作り方
バッチファイルを作成しそこにコードを記述していきます。いろいろやり方はありますが皆さんのやりやすいやり方でどうぞ。
## ファイル作成
まず**windowsキー**を押して**cmd**と入力し、管理者として実行をおします。すると以下のようなウィンドウが開きます。

![cmd.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3052647/416d4e3b-307e-ae54-045f-c9265d2ebc94.png)

ここでファイルを作成し入力していきます。

    vim wav.bat

ここで"wav"は自由に変えてもらってもいいですが、長すぎるとあと後面倒くさいので覚えやすくて短いものをお勧めします。またこれが実際に使用するコマンドになります。
※アクセスが拒否されましたと出力された場合は管理者として実行されていません。

## コード入力
以下をぶちこみましょう。

    @echo off
    if "%~x1"==".mp4" (
    	set "filename=%~dpn1"
    	ffmpeg -i %1 "%filename%.wav"
    	echo File converted successfully.
    ) else (
    	echo Invalid file format. Please provide a .mp4 file.
    )

終わったら保存のし忘れに注意して終了します。

# 使ってみる
実際に使ってみましょう。
新しくコマンドプロンプトを開きます。**windowsキー**を押して"**cmd**と入力しエンターを押します。今回は管理者で開く必要はありません。開いた直後は　C:\Users\ユーザーネーム>　です。ここから動画ファイルがあるところへ移動しましょう。

**dir**と打つと今いるファイル内にあるファイルとフォルダが表示されます。
**cd Video**と打つとVideoのディレクトリへ移動します。
cd ..　と打つと一個前のファイルへ移動します。

動画ファイルがあるところへたどり着いたら以下のコマンドを打ち、wavへ変換しましょう。

    wav test.mp4

長ったらしい出力がされますが問題がなければそこにwavファイルが出来上がります。

# 結果
ファイル名が出てこないのはなんでだろうか。まだ勉強が必要ですね。
いつか修正します。（しない）
SwiftUIはおせっかいにもToolBarItemのButtonのタップ範囲を広げる

# 検証
### 検証してみる。
``` ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationStack {
            button
                .toolbar {
                    button
                    button
                }
        }
    }

    var button: some View {
        Button(action: {}){
            Image(systemName: "heart.fill")
                .padding(4)
        }
        .border(.red)
    }
}

#Preview {
    ContentView()
}
```

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/6fc6ddf4-3ffb-d841-4573-5ace242e2e84.png">

やめて？
ただ単にViewとそのタップ範囲を広げるだけでなく、画面端のボタンは気を遣って画面中央に向かってタップ範囲を広げてくれている。やめて。

### Buttonのlabelに対してサイズ指定してclipしてみる

```diff_swift
...

            Image(systemName: "heart.fill")
+                .resizable()
+                .frame(width: 20, height: 20)
+                .clipped()
                 .padding(4)

...
```

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/ac0786c9-9e82-72e8-a017-cb2affd4d1cd.png">

タップ範囲は大きいまま。

### Buttonそのものに対してサイズ指定してclipしてみる

```diff_swift
...

        Button(action: {}){
            Image(systemName: "heart.fill")
                .resizable()
                .frame(width: 20, height: 20)
-               .clipped()
-               .padding(4)
        }
+        .frame(width: 20, height: 20)
+        .padding(4)
+        .clipped()
+        .border(.red)

...
```
|  |
|:-:|
| <img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/53ee74b7-7f22-f1d1-f769-6be16b24c944.png">  |
| <img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/bb1e09db-b2f2-63b1-b47a-b675b27c9bb6.png">  |

なんで？

# .buttonStyle(.plain)をつけてみる

```diff_swift
        Button(action: {}){
            Image(systemName: "heart.fill")
                .resizable()
                .frame(width: 20, height: 20)
                .padding(4)
        }
+       .buttonStyle(.plain)
+       .foregroundStyle(Color.accentColor)
        .border(.red)
```

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2361573/9609812c-ceb2-45bb-bce6-9cbaa70ea792.png">


ようやく意図した通りに設定された。
ソフトウェアテスト ~

<h2>表題の通り、ソフトウェアテストについてまとめる。</h2>
私はSES会社に勤務しており、それぞれの案件に行事している。しかし、ソフトウェアテストについて深く知らないまま、テストの用語が飛び交うPJTに参画している。ここでは主に、どのようなテスト設計やテストケースがベストであるのかをまとめて話していきたい。

<h3>経緯</h3>
今までのPJTでは、単体テスト、結合テスト、総合テストなどが曖昧でした。

それぞれのテストの意味合いやテスト領域を表面上、理解していいるものの、PJTベースで単体テストについて
理解していなかった。また、テストケースを書く際に、どんなふうに書けば良いか自身の基準の軸を持てておらず、
これを機に、テスト設計やテストする際の基準値を持ちたく、学習を進めていく。


まえがき
- 第1章 テストのプロセス
- 第2章 ケーススタディの説明

SectionI
 -
SectionII

SectionIII

SectionIV

SectionV
JetpackCompose LazyColumnを使用して、指定したindexにスクロールする方法

LazyColumnを使用して、指定したindexにスクロールする方法です。

今後も使うことがありそうなので、こちらに実装方法を記載します。

# サンプルコード

```Sample.kt
@Composable
fun Sample() {
    val sampleList = mutableListOf<String>()
    repeat(100) {
        sampleList.add("アイテム$it")
    }
    Column(
        modifier = Modifier
            .fillMaxSize()
    ) {
        val listState = rememberLazyListState()
        val scope = rememberCoroutineScope()

        LazyColumn(
            state = listState
        ) {
            items(sampleList) {
                Text(
                    text = it,
                    modifier = Modifier.height(30.dp),
                )
            }
            scope.launch {
                listState.scrollToItem(index = 10, scrollOffset = 0)
            }
        }
    }
}
```

![Screenshot_20240519_182719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/b385c6b6-ea36-5e62-39f6-02ceb51489a7.png)


実行した結果`10件目`のアイテムが一番上に表示されてます。

`listState.scrollToItem(index = 10, scrollOffset = 0)`
こちらのコードの引数で`index`にわたしたアイテムが一番上に表示されます。
作業用スクリプトをClojureで書く２

# 概要

[前回](https://qiita.com/hylanger/items/6281cea20e731d034a7a)の記事でClojureの立上がりが遅いので役に立たないと言ったのですが、[joker](https://github.com/candid82/joker)を利用すると高速に起動できることがわかったので、導入の手順を以下にまとめていきます。

前提としてMacなので

# インストール

公式の手順に則ってbrewでインストールしていきます。
WindowsやLinuxの場合は[Nix](https://nixos.org/)を使うか、[リリースページ](https://github.com/candid82/joker/releases)からバイナリを落とすかのいずれかになります。

```sh
brew install candid82/brew/joker
```

# 使い方

`joker`とコマンドを打つとインタープリタが起動します。
単純にClojureの動作を確認したいだけであれば、これで十分かと思います。

テストファイルを作成して実行する場合は、以下のように`joker`の後にファイルパスを記述すればOKです。

```sh
joker test.clj
```

# スクリプトファイル

前回の記事とほぼ一緒ですが、単独実行可能なスクリプトファイルとして記述する場合は、以下のように記述すれば良いです。

```clojure
#^:shebang '[
  exec joker "$0" "$@"
]

;; nsの後は通常はnamespace名を入れるが、単独実行ファイルであり
;; 何でも良いので"_"にしている
(ns _ (:require [joker.os :refer [sh]]))

;; 引数は文字列の配列で取得できる
(let [args *command-line-args*]
  (println args))

(defn run-cmd [cmd]
  (let [res (sh cmd)]
    (println "[Exit code]")
    (println (:exit res))
    (println "[Output]")
    (println (:out res))
    (println "[Error]")
    (println (:err res))))

(run-cmd "ls")
```
シングルクォートで括られたテキスト内にシングルクォート記号を書く

Vue.jsの書籍で勉強中にシングルクォート記号の書き方について分からない部分があったので調べたことのメモです。

# 分からなかった箇所
```vuejs
template: '<p v-on:click="doAction" v-bind:class="{\'alert-warning\':isInfo,\'alert-dark\':isDark}" class="alert">clicked:{{counter}}.</p>'
```

## 不明点
`\'alert-warning\'`と書くのはなぜか？

## 調べて分かったこと
### オブジェクトのキー名にハイフン（‐）を含む名前を指定できない
:::note info
算術演算子として認識されてしまうのかな？と思っています（違っていたら教えて下さい…！）
:::

→{alert-warning:isInfo}とは書けない。alert-warningをテキストとして{'alert-warning':isInfo}と書きたい

### シングルクォートで括られたテキストの中でシングルクォート記号を書く特別なやり方がある

- 今回だとtemplate:以降のシングルクォート（'）で囲まれているすべてがテキストであり、シングルクォートで括られたテキストの中でシングルクォート記号を書くということになる。


このときにシングルクォート記号を書くやり方が`\'`

:::note info
エスケープシーケンスの一種のようです
:::

→{'alert-warning':isInfo}とも書けないので{\\'alert-warning\\':isInfo}と書く

# 参考

https://jsprimer.net/basic/object/

https://www.javadrive.jp/javascript/string/index3.html
メールヘッダーインジェクション

## はじめに

メールヘッダーインジェクションについてまとめる。

### メールヘッダーインジェクションとは

メールヘッダーに不正なヘッダー情報を混入させることで、スパムメールなどを送信させる攻撃のこと。

### 例

以下のようなコードがあったとして、

```php:mail_send.php
mb_send_mail('test@example.com', $_POST['subject'], $_POST['body'], 
"From: {$_POST['from']}");
```

`"From: {$_POST['from']}")`の箇所に以下のような値を渡した時、

```
test@example.com
Bcc: injection@example.com
```

新たなBccヘッダーが認識されてしまう。
(入力値を介して、ユーザーが勝手に送付先を忍び込ませることができてしまう。)

メールヘッダーインジェクションのあるサイトは、スパムメールの踏み台にされる。

### 対策

メールアドレスの妥当性を検証する。
「`/\A\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\z/`」は、メールアドレスを表す正規表現パターン。

このようなチェックを入れることで、メールアドレスを複数含んだ文字列は指定できなくなる。

```php:mail_send.php
if (!preg_match('/\A\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*\z/', $_POST['from'])) 
{
    die('不正なメールアドレスです。');
}
mb_send_mail('test@example.com', $_POST['subject'], $_POST['body'], "From: {$_POST['from']}");
```
DOM操作について

今回はJavaScriptを学習して特に大事だと考えたDOM操作についてアウトプットしていきたいと思います。

## DOM操作とは
DOM（Document Object Model）は、HTMLやXML文書をプログラムから操作するための仕組みです。Webページを動的に変えるために、DOM操作は必要となります。この記事では、初心者が基本的なDOM操作について学んだことを説明していきます。

## 基本的なDOM操作
要素の取得

まず、操作したい要素を取得する方法を説明します。以下の方法があります。

IDで取得: getElementByIdメソッドを使います。
クラス名で取得: getElementsByClassNameメソッドを使います。
タグ名で取得: getElementsByTagNameメソッドを使います。
CSSセレクタで取得: querySelectorやquerySelectorAllメソッドを使います。

```
// IDで要素を取得
let element = document.getElementById('exampleId');

// クラス名で要素を取得
let elements = document.getElementsByClassName('exampleClass');

// タグ名で要素を取得
let elements = document.getElementsByTagName('div');

// CSSセレクタで要素を取得
let element = document.querySelector('.exampleClass');

// CSSセレクタで複数の要素を取得
let elements = document.querySelectorAll('.exampleClass');
```

##### 要素の操作

取得した要素を操作する方法を説明します。

##### テキストの変更
要素のテキストを変更するには、textContentプロパティを使います。

```
let element = document.getElementById('exampleId');
element.textContent = '新しいテキスト';
```

##### 属性の変更
要素の属性を変更するには、setAttributeメソッドを使います。

```
let element = document.getElementById('exampleId');
element.setAttribute('class', 'newClass');
```

##### スタイルの変更
要素のスタイルを変更するには、styleプロパティを使います。

```
let element = document.getElementById('exampleId');
element.style.color = 'red';
```

##### クラスの追加・削除
クラスを追加したり削除したりするには、classListプロパティを使います。
```
let element = document.getElementById('exampleId');
element.classList.add('newClass');
element.classList.remove('oldClass');
```

##### 要素の追加・削除

新しい要素を追加したり、既存の要素を削除する方法です。

##### 要素の追加
新しい要素を作成し、親要素に追加します。
```
let parentElement = document.getElementById('parent');
let newElement = document.createElement('div');
newElement.textContent = '新しい要素';
parentElement.appendChild(newElement);
```

##### 要素の削除
要素を削除するには、removeメソッドを使います。
```
let element = document.getElementById('exampleId');
element.remove();
```

# イベントリスナーの追加
ユーザーの操作に応じて特定の処理を実行するために、イベントリスナーを追加します。例えば、ボタンがクリックされたときにアラートを表示するには、以下のようにします。
```
let button = document.getElementById('exampleButton');
button.addEventListener('click', function() {
    alert('ボタンがクリックされました');
});
```

# 効率的なDOM操作
大量のDOM操作を行うときは、パフォーマンスに注意が必要です。例えば、ドキュメントフラグメントを使うと、複数の要素を一度に追加でき、再描画の回数を減らすことができます。
```
let fragment = document.createDocumentFragment();

for (let i = 0; i < 10; i++) {
    let newElement = document.createElement('div');
    newElement.textContent = '要素 ' + i;
    fragment.appendChild(newElement);
}

document.getElementById('container').appendChild(fragment);
```

# まとめ
DOM操作は、Webページを動的に変更するための基本技術だと学びました。今回は、基本的な要素の取得方法、テキストや属性の変更、要素の追加・削除、イベントリスナーの追加などの基本操作を理解しました。これらの基本をマスターすることで、よりインタラクティブでダイナミックなWebページを作成できるようになると思いました。
今回は以上になります。
[React] メモ化で効率的なコンポーネントを作れるように

### メモ化とは？

計算結果をキャッシュしておき、同じ計算が再度必要になったとき、キャッシュされた結果を再利用する技術

Reactでは主に以下のメソッドを利用する。
- `useMemo`
- `useCallback`
- `React.memo`

---

### useMemo
- `useMemo`はメモ化された値を返すためのReactフック
- 第1引数に関数、第2引数に依存配列を渡す（省略不可）
- 依存配列を省略した場合は初回のみ実行される

#### 使用するべきケース
- 重い計算の結果をメモ化
計算コストが高い処理をメモ化することで、パフォーマンスを向上させる
    ```typescript
    const heavyCalculation = useMemo(() => {
        return expensiveFunction(a, b);
    }, [a, b]);
    ```

- オブジェクトや配列の再生成を避ける 
オブジェクトや配列を再生成すると再レンダリングが発生するため、これを避けるために使用
    ```typescript
    const memoizedObject = useMemo(() => ({ key: value }), [value]);
    ```

#### 使用しない方が良いケース
- 安価な計算
    - 計算コストが低い場合、`useMemo`のオーバーヘッドの方が大きくなる
- 依存配列が頻繁に変わる
    - 頻繁に依存配列が変わる場合、再計算のコストが無視できない

### 注意点
- `useMemo`はパフォーマンス最適化のために使うが、必要以上に使用すると逆効果になる場合がある
- 重い計算や再生成のコストが高いオブジェクトのメモ化に限定して使うのが良い

---

### useCallback
- `useMemo`はメモ化された関数を返すためのReactフック
- 第1引数に関数、第2引数に依存配列を渡す
- 依存配列を省略した場合は初回のみ実行される

#### 使用するべきケース
- 関数の再生成を避ける
子コンポーネントに渡す関数をメモ化することで、不要な再レンダリングを防ぐ

    ```typescript
    const memoizedCallback = useCallback(() => {
      doSomething(a, b);
    }, [a, b]);
    ```
<br>

- イベントハンドラのメモ化
頻繁に再生成されるイベントハンドラをメモ化することで、パフォーマンスを向上させる
    ```typescript
    const handleClick = useCallback(() => {
      console.log('Clicked');
    }, []);
    ```

#### 使用しない方が良いケース
`useMemo`と同様

---

### React.memo
- メモ化されたコンポーネントを返すために使用される
- 再レンダリングを防ぐために使用され、親コンポーネントの再レンダリング時に子コンポーネントが再レンダリングされないようにする
- 親コンポーネントから渡される`props`が更新された場合は再レンダリングが実行

#### 使用するべきケース
- コンポーネントの再レンダリングを防ぐ
再レンダリングコストが高いコンポーネントや、頻繁に再レンダリングされるコンポーネントに対して使用
    ```tsx
    const MyComponent = React.memo((props) => {
      return <div>{props.value}</div>;
    });
    ```

#### 使用しない方が良いケース
- 軽量なコンポーネント

---

### まとめ
- `useMemo`: 値をメモ化するために使用
- `useCallback`: 関数をメモ化するために使用
- `React.memo`: コンポーネント全体をメモ化するために使用
Amazon EFS

## はじめに
この記事はAWS SAA試験勉強のための、Amazon EFSに関する知識のまとめです。

## Amazon EFS(Elastic File System)
<font color="red">**複数の**</font>EC2インスタンスにマウントして共通ストレージとして利用できる分散ストレージサービス。ファイル形式で保存できるNASとして機能します。
EFSはLinuxのみサポートしており、Windowsで利用されるファイル共有(SMB)形式はサポートしていません。

### NAS

NAS（Network Attached Storage）は、ネットワークに直接接続される記憶装置のことを指します。

## Amazon EFSの基本的な性質
- 強力な一貫性を持っています

- EFSの方がEBSより高価です
- データの整合性を保つためにファイルに対するロック機構（排他制御）が使用されています
- 保存したデータ量に伴ってストレージサイズが自動的にスケーリングされます

## [AWS DataSync](https://qiita.com/naoya_ok/items/1842c875b3cfc2dc52e7)
Amazon EFS ファイルにデータ移行するために利用するのはAWS DataSync。

## バーストスループットモード

バーストスループットモードではスループットがファイルシステムのサイズに合わせて自動でスケールされ、ファイルベースの多数のワークロードの不規則なリクエスト増に対して、動的にバーストしてパフォーマンスを向上させることができます。

## 汎用モード

Amazon EFSの汎用モードは、ファイルシステムオペレーション単位で最小レイテンシーを実現するだけでなく、ランダムまたはシーケンシャル IO パターンでも同じ結果を得ることができます。

## プロビジョンドスループットモード

データ量は少ないがアクセス頻度の多い場合に適しています。
Anacondaを再インストールした話

# 事件
Anacondaをインストールした後、環境構築しようとしたら構築に失敗して、１からやり直そうとして、PCの設定→アプリでAnacondaをアンインストールし再度インストールしようとしたところ以下のエラーが出てインストールできなくなった。
![スクリーンショット (1929).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771189/c233fa38-5b1d-ba61-a860-19656d85846a.png)

# 解決策
1.手動でanaconda3フォルダを削減
![スクリーンショット (1930).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771189/42e567b4-6b49-93a2-92e4-c7b238f6cd8f.png)

**また、自分の名前のフォルダに移動し、CTRL+Fで「anacond」と検索します。なぜかanaconda3フォルダ以外にもanacondaに関するファイルを削除する必要があるかも。**

2.インストーラーを管理者として実行

# 結果
見事元通り

![スクリーンショット (1931).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3771189/c820680e-a4d3-ab5b-ace6-9e66f9bd2a81.png)
Ubuntu 24.04 で incus を使う

Ubuntu 24.04 から incus がパッケージに含まれました。

```text
$ dpkg -l | grep incus
ii  incus                                                       6.0.0-1                                  amd64        Powerful system container and virtual machine manager - daemon
ii  incus-agent                                                 6.0.0-1                                  amd64        Incus guest agent
ii  incus-client                                                6.0.0-1                                  amd64        Powerful system container and virtual machine manager - client
```

## バージョン

```text
$ incus --version
6.0.0
```

## 使い方

次のページを参考にしました。
[Incusを使う最初のステップ](https://incus-ja.readthedocs.io/ja/latest/tutorial/first_steps/)

一般ユーザーで、incus を使えるようにする

```bash
sudo adduser uchida incus-admin
newgrp incus-admin
```

初期化

```bash
incus admin init --minimal
```

イメージのインストール

```bash
incus launch images:ubuntu/22.04 first
```

コンテナが動いていることの確認

```text
$ incus list
+-------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| NAME  |  STATE  |         IPV4         |                     IPV6                      |   TYPE    | SNAPSHOTS |
+-------+---------+----------------------+-----------------------------------------------+-----------+-----------+
| first | RUNNING | 10.158.98.219 (eth0) | fd42:16ef:86e0:dbd7:216:3eff:fe8f:9dcf (eth0) | CONTAINER | 0         |
+-------+---------+----------------------+-----------------------------------------------+-----------+-----------+
```

ルートのパスワードの設定

```bash
incus exec first  -- bash
```
よく使うターミナルのコマンド


こんにちは！
ご覧いただきありがとうございます。
新卒1年目の小川です。
この記事が初めての投稿になります。
これからよろしくお願いいたします！

初めての記事ということで、これまでの研修の中でよく使用したコマンドをまとめたいと思います。

# こんな人に読んでほしい！
* プログラミングの勉強を始めたばかりの方
* これから勉強をしようと思っている方
* 未経験エンジニアの方

# 使用環境

* Macのターミナル

# よく使うコマンド
それでは早速、まとめていきたいと思います。

## mkdir+ディレクトリ名（ディレクトリの作成）
**mkdir**コマンドは、**ディレクトリ**を作成するコマンドです。
**ディレクトリ**とは、ファイルを入れていくためのフォルダのようなものです。
ここでは**Hello**という名前のディレクトリを作成します。

* **mkdir Hello**

## touch+ファイル名（新しいファイルを作成する）
**touch**コマンドは、上記で作成した**Hello**というディレクトリの中に**ファイル**を作成するときに使用します。
ここでは**good**というファイルを作成します。

* **touch good**

## rmdir+ディレクトリ名（ディレクトリの削除）
**rmdir**コマンドは、不要になったディレクトリを削除するときに使用します。

* **rmdir Hello**

## rm+ファイル名（作ったファイルを削除する）
**rm**コマンドを使うと、不要になったファイルを削除することができます。

* **rm good**

## cd（ホームディレクトリに移動）
**cd**コマンドは、ホームディレクトリに移動するコマンドです。
ディレクトリを切り替えるときなどに使用します。

* **cd**

## cd+ディレクトリ名（指定したディレクトリに移動する）
先ほどの**cd**コマンドの後にディレクトリ名を指定すると、指定したディレクトリに移動することができます。
上記の**mkdir**コマンドで作成した**Hello**というディレクトリに移動する場合は以下のようになります。

* **cd Hello**

## ls（ファイルの一覧を確認）
**ls**コマンドは。ファイルの一覧を確認したい時に使います。

* **ls**
* **ls Hello**

## pwd（今いる場所を確認）
複数のディレクトリで作業していると、今どこで作業していたか分からなくなったり、確認が必要になったりすることがあるかもしれません。
そのような時には、ぜひ**pwd**コマンドを使って今いる場所を確認してみてください。

* **pwd**

## cat+ファイル名（ファイルの内容を確認）
**cat**コマンドは、ファイルの内容を確認したいときに使用します。

* **cat good**

## code+ファイル名（エディタでコードを入力したい時にファイルを指定して開く）
**code**コマンドは、VS Codeやテキストエディタなど、コードを記載するときにファイルを指定して使用するコマンドです。
例として、touchコマンドの時に作ったgoodというファイルにコードを記載したい時に以下のように入力して開きます。

* **code good**

## open+ファイル名（ファイルやディレクトリをブラウザなどで開く）
**open**コマンドは、Google chromeやSafariなどのブラウザで開いて表示させたいときに使用します。

* **open good**

# 最後に
今回は、使用例も踏まえて特によく使用したコマンドをまとめてきました。
最初は色々なコマンドがあり、覚えるのが大変だと思うこともありましたが、打っていくうちに、だんだんと上記で紹介したようなよく使うコマンドは覚えてきました。
今後も、わかりやすい記事を意識しながら投稿していきたいと思っています。
これからよろしくお願いいたします！
アクセシビリティの重要性とその実践方法

## はじめに
2024年4月1日、日本で障害者差別解消法の改正が施行され、アクセシビリティに対する関心がますます高まっています。アクセシビリティとは、障害の有無や年齢に関わらず、すべての人々が情報にアクセスしやすくすることを指します。本記事では、アクセシビリティの重要性とその実践方法について詳しく解説します。

## アクセシビリティとは何か
アクセシビリティの概念は、すべての個人が直面する障壁を取り除くことです。これには物理的な環境だけでなく、デジタルコンテンツやサービスも含まれます。視覚障害者がスクリーンリーダーを使用してウェブサイトを閲覧できるようにすることや、聴覚障害者が字幕付きのビデオを視聴できるようにすることがその例です。

### 法的背景
改正された障害者差別解消法は、公共機関や民間企業に合理的配慮を提供することを義務付けています。これにより、アクセシビリティの確保は単なる倫理的義務ではなく、法的義務となりました。

## アクセシビリティの実践方法
アクセシビリティを実現するためには、以下のような具体的な取り組みが必要です。

### ウェブアクセシビリティ
ウェブサイトをアクセシブルにするための基準として、WCAG（Web Content Accessibility Guidelines）があります。WCAGは、視覚、聴覚、運動能力に関する障害を持つユーザーがウェブコンテンツにアクセスしやすくするためのガイドラインを提供しています。具体的な実践例としては、以下のようなものがあります。

- **代替テキストの提供**：画像に代替テキストを追加することで、視覚障害者がスクリーンリーダーを使って画像の内容を理解できるようにします。
- **キーボード操作のサポート**：すべてのインタラクティブな要素がキーボード操作でアクセス可能であることを確認します。
- **色のコントラスト**：十分な色のコントラストを確保し、視覚的な識別がしやすくします。

### モバイルアクセシビリティ
モバイルアプリケーションにおいてもアクセシビリティは重要です。例えば、iOSやAndroidはそれぞれアクセシビリティ機能を提供しており、これらを活用することでユーザーエクスペリエンスを向上させることができます。

### 物理的環境のアクセシビリティ
デジタルだけでなく、物理的な環境もアクセシブルにする必要があります。例えば、建物内のバリアフリー設計や、公共交通機関のアクセシビリティ向上などが挙げられます。

## まとめ
アクセシビリティは、すべての人々が平等に情報やサービスにアクセスできる社会を実現するために不可欠です。改正された障害者差別解消法を契機に、企業や個人が積極的にアクセシビリティの向上に取り組むことが求められます。具体的な取り組みとして、ウェブサイトやモバイルアプリケーションのアクセシビリティ改善、物理的環境のバリアフリー化などがあります。これからのためにも、アクセシビリティの知見を共有し、より良い社会の実現に向けて取り組んでいきたいと思います。
プロンプトエンジニアリングのすすめ～いいプロンプトを書くために気を付けること～

みなさん、ChatGPTなどのAIは使ってますか？
こういった記事を読まれている方は、なんらかの形で使われていることと思います。

プロンプトエンジニアリングの概要については、こちらの記事にざっくりと概要をまとめてありますのでよければご一読ください。

https://qiita.com/shioccii/items/0f3af9aac192bd47ce9b

## プロンプトを書く前に

どういったプロンプトを書くとAIがより精度のいい回答をしてくれるのでしょうか。

ごくごく個人的な解釈ですが、AIが様々な知識を取り込んだ結果、より人間っぽくなったと考えると自然かもしれません。つまり、何かを人にお願いする時にはあまりにもざっくりとした指示をすると、出力内容は中途半端なものが仕上がってくるのに対して、事細かく指示をした場合はそれなりのものが仕上がってくる・・つまりそんな感じです。

プロンプトエンジニアリングを突き詰めていった結果、「いいプロンプトを作るにはどうしたらいいんだろうか」→「そうだ、いいプロンプトをたくさん集めればいいんだ！」というアプローチを言語化すると下記のサイトになります。

https://chatgpt-lab.com/?gs=349c0cb96c31

日本語で様々なタスクを実現するためのプロンプトがたくさんあり、プラグインを導入することでChatGPTなどに自動的にプロンプトを流し込んで実行してくれるとても便利なツールを扱っているサイトです。

たくさんの人が作ったプロンプトを参考に自分のオリジナルのプロンプトを考えることもできますので、そういった意味でも有益な情報と思います。

## よいプロンプトとは
一般的にAIのパフォーマンスを上げるためのテクニックは下記のようなものがあげられます。

* タスクと成功基準を定義すること
* 明確かつ直接的であること
* AIに対してロールを与えること
* 回答の例を示すこと
* 複雑なタスクは小さく管理しやすいステップに分解すること
* AIに思考させること

それぞれの内容について見ていきましょう。

## 明確かつ直接的であること
基本的にAIは豊富な知識があって賢いが、若葉マークがついた新入社員のようなものです。初めての人に仕事を指示するときと同じように、あなたが何を望んでいるのかを率直に説明すればするほど、AIの回答品質は良くなります。

例えば、「日本人で最高の野球選手は誰ですか？」という質問の場合、王貞治なのか、長嶋英雄なのか、松井秀喜なのか、はたまた大谷翔平なのか、たくさん候補があがって回答する人の好みが出ると思いませんか？

もっと具体的に「日本で活躍したホームラン王の異名を持つ最高の野球選手は誰ですか？」と質問した場合はどうでしょう。ホームラン王で最高の野球選手といえば王貞治となりますよね。このように具体的な指示をすることで回答の品質が格段によくなるということです。

## AIに対してロールを与えること
基本的にAIはとても優秀なアシスタントです。そしてAIに対してロール（役割）を与えることでさらに優秀なアシスタントとなります。特にロールを割り当てることでパフォーマンスがよくなるものとしては、コーディングやロジック解析などの高度技術タスクや、その役割が果たす聴衆向けの文章作成タスクなどになります。

## 回答の例を示すこと
人に何か指示をする場合に「こういう風に資料を作ってください」というように出力結果のサンプルを示すことで、指示を受けた人がそのサンプルを参考にして出力結果を調整してくれるのと同じように、AIに指示をする場合でも出力サンプルを示すことで、そのサンプルを参考情報として出力結果をサンプルに合わせて調整してくれて、一貫性の向上や精度の向上を図ることができるようになります。

## 複雑なタスクは小さく管理しやすいステップに分解すること
AIに対して1つのプロンプトで処理させるタスクが増えるほど、何かの処理をしなかったり、単一のタスクの実行結果が悪くなる可能性は高くなります。こうしたタスクを処理する場合は、複雑なタスクを小さなタスクに分割して、順番に連結タスクとして処理させることでトータルのパフォーマンスを向上させることができるようになります。

## AIに思考させること
複雑な質問やタスクに直面した場合、最終的な答えを出す前にAIに対して問題を段階的に考えてもらうことで出力品質を向上させることができるようになります。あなたのチームでプロジェクトに大きな課題が出た場合に、チームで集まってあれやこれや課題に対して議論をすることで思考が進み課題解決の糸口になることと同じで、AIもおおきな課題に対して思考させることでパフォーマンスに差がでるということです。

思考させる場合は、「段階的に考えてみよう」、「ステップバイステップで考えてください」、「手がかりを1つずつ調べて、それぞれに関連する可能性があるかどうかを検討してください」などをプロンプトに追加することでAIに思考を促すことができるようになります。


## まとめ
自分もふわっと理解していた部分があったので、改めて自分の言葉におきかえることで、言語化できていなかった部分の理解が進みました。

## 参考サイト
https://docs.anthropic.com/en/docs/prompt-engineering
[HTML レイジーローディング] 複数の画像表示コツ

本記事ではどのように複数な画像を適当に表示するのをご共有させていただきます

# 前提
・画像を1000枚表示
・[picsu photos](https://picsum.photos)でランダムな画像を取得

### コード
```javascript
function App() {
  const images = [];
  for (let i = 0; i < 1000; i++) {
    images.push(i);
  }
  return (
    <div className="App">
      {images.map((i) => {
        return (
          <div>
            <img src={`https://picsum.photos/500/500?random=${i}`} />
          </div>
        );
      })}
    </div>
  );
}
export default App;
```


```css
/* index.css */
img {
  height: 500px;
  width: 500px;
}
```


# レイジーローディングを導入しない

上記のコードの検査
![ScreenRecording2024-05-19at15.55.34-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/0b17860c-60b8-7b36-6579-79350d013c8d.gif)

### 現象
ページをレフレッシュすると画面サイズで２枚だけ表示できまが、
+ 画面を全部取得　（１回にAPIを1000件ほ叩く）
+ パフォーマス面では悪い

# レイジーローディングを導入

### 対策
```img```タグに「loading="lazy"」というプロパティを入れます

```js
// 修正前： <img src={`https://picsum.photos/500/500?random=${i}`} />
// 修正後
 <img loading="lazy" src={`https://picsum.photos/500/500?random=${i}`} />
 
```

### 結果
+ 画像を全部取得せずにスクロールする時は該当する画像を取得
+ １回にあたり５枚取得
→ 小さい変更ですがパフォーマンスがすごく改善できますね

　![ScreenRecording2024-05-19at15.56.28-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/54cdd98d-13ea-45c7-2240-6ec62c01f57e.gif)


# その他
### DevToolsが開き方
「右マウス」→「inspect」→「network」タブ→絞り込みに「img」を選ぶ
「network」みつかない場合は[>>]をクリックしてください
![Screenshot 2024-05-19 at 16.12.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/7716360a-a1f7-30a6-7095-9a9a74f7a7f9.png)


### 参考
https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading


最後までご覧くださいましてありがとうございました。
役に立つを感じしたらハートやコメントやを残ってください:bow:
Outlook VBAで、スケジューラ設定する時の　保存時のイベントを捕捉したい

# Outlook スケジューラ登録／保存時、当該イベントを捕捉するVBAコード

```vb
ThisOutlookSeesion
```

のドあたま

```vb:sample.vb
Public WithEvents myAppointment As Outlook.AppointmentItem
```

と記載。

次に、アイテムロード時ののイベントに、アポイントメントクラスの場合、当該クラスをセット

```vb:sample.vb
Private Sub Application_ItemLoad(ByVal Item As Object)

If Item.Class = olAppointment Then
Set myAppointment = Item
End If

End Sub
```

ほんで、以下に、スケジューラアイテム保存時の処理を書く。
myAppointmentは、毎回、解放してあげる必要がありそう。

```vb:sample.vb
Private Sub MyAppointment_Write(Cancel As Boolean)

' ここに必要な処理を書く

Set myAppointment = Nothing

End Sub
```




ちなみに、私は、以下のように使用。
（自分の勤務先仕様で？、他人主催者の会議体を、勝手に作れてしまい、かつその予定を、自分で変更できなくなってしまうことから（←むちゃくちゃ）、自分でエラーとして捕捉している。）


```vb:sample.vb
Private Sub MyAppointment_Write(Cancel As Boolean)

If InStr(1, myAppointment.Organizer, "【自分の名前】") > 0 Then
' OK
Else If myAppointment.Organizer = "" AND InStr(1, myAppointment.RequiredAttendees, "【自分の名前】") > 0 Then
' OK

Else
' NG
MsgBox "Organizer is " & myAppointment.Organizer & "_" & myAppointment.RequiredAttendees
Cancel = True
'myAppointment.Close olDiscard
End If

Set myAppointment = Nothing

End Sub
```
Proxmox上のVMの音声を聞く

Proxmoxではコンソールを開くとWebGUIを開いている端末でVMを操作できるが、通常音声は聞くことができない。（VNCでは有償のものでしか音声を聞くことができない[^1]）
サクッと解決したので、方法をメモ書き程度の雑なものではあるが残しておく。

# 手順
### WebGUIでの作業
1. VMのハードウェアから追加を押す
2. 音声デバイスを追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349830/f4705a1b-04c7-40ae-f019-4f906f2f9247.png)
3. 音声デバイスはとりあえずデフォルトのままで、バックエンドドライバはSPICEを選択する
3. 「追加」を押して終了

### アクセスしたいPCでの作業
1. https://pve.proxmox.com/wiki/SPICE で「SPICE client」にあるvirt-viewerをダウンロードする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349830/53996fe0-a553-737e-f861-757d128a9708.png)
Windowsならhttps://www.spice-space.org/download.html にアクセス
1. Windows installersからvirt-viewer Windows installerのダウンロード先へアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349830/c856e181-f7d4-862c-84c2-7820d3525aee.png)
1. virt-viewerの「Win x64 MSI」を押すとダウンロードできる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2349830/3cb8d9da-e926-4666-e053-9811fbba8025.png)
1. ダウンロードしたインストーラーを起動して、手順に従ってインストールする

### WebGUIでの作業
1. アクセスしたいVMのコンソールでSPICEを選択する
1. 「.vv」ファイルがダウンロードされるので、それを開くとVMの画面が開く
1. 音声も聞けることが確認できる

[^1]: https://www.nslabs.jp/remote-desktop-with-sound-audio.rhtml より
blastengineを使ってPostfixでメール送信を行う

[blastengine](https://blastengine.jp/)はシンプルに使える開発者向けメールサービスを提供しています。何かと面倒なメール配信をシンプルに、かつ確実に送信先に届くようになります。

今回はblastengineを使って、Postfix経由でメール送信を行う方法を紹介します。

## ユーザ登録する

blastengineにユーザ登録します。管理画面に入るためのユーザID、パスワードが手に入るので、ログインします（ユーザIDは後で使います）。

![getting-started-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/5c6c8cb0-9ad1-0a6d-88fe-e24bc3ee7b17.jpeg)

## 送信元ドメインのSPFを設定する

送信元として利用するドメイン（自分で持っているもの）の設定をします。これは任意のドメイン管理サービスで設定できますが、TXTレコードに以下のSPFを追加します。

```
txt @ v=spf1 include:spf.besender.jp ~all
```

## SMTP用のパスワードを設定する

ログイン後、管理画面の右上にある設定メニューに移動します。

![getting-started-6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/78a4eeb3-4649-149f-8246-44f83d03a0cf.jpeg)

そしてSMTPリレーの設定で、SMTP用のパスワードを設定できます。また、IPアドレスベースの認証も可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/e615c636-8bf6-0937-6ed6-d06e933b84c7.png)

## Postfix で SMTP リレーとしてblastengineを構成する

PostfixでSMTPリレーとしてblastengineを使用する設定を行います。基本的にターミナルで作業します。全体として、ルートユーザーの方が良さそうですが、sudoでも可能です。

設定ファイルを編集します。

```bash
sudo vi /etc/postfix/main.cf
```

設定内容は以下の通りです。

```
# 以下が有効であればコメントアウト
# default_transport = error
# relay_transport = error

# SMTP host and port
relayhost = [smtp.engn.jp]:587
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
header_size_limit = 4096000
smtp_sasl_security_options = noanonymous
```

完了したら保存します。

次に、認証情報を保存します。 `/etc/postfix/sasl_passwd` を開くか、新規作成します。

```bash
sudo vi /etc/postfix/sasl_passwd
```

内容は以下の通りです。 `USER_NAME` と `SMTP_PASSWORD` はblastengineのユーザーIDとSMTP用のパスワードに置き換えてください。

```
[smtp.engn.jp]:587 USER_NAME:SMTP_PASSWORD
```

保存したら、`portmap` コマンドで `.db` ファイルを作成します。

```bash
sudo postmap /etc/postfix/sasl_passwd
```

*.dbが作られていることを確認します。

```bash
ls -l /etc/postfix/sasl_passwd*
```

作成されていれば、元々の `sasl_passwd` ファイルは削除します。

```bash
sudo rm /etc/postfix/sasl_passwd
```

さらに `saasl_passwd.db` ファイルの権限を変更します。

```bash
sudo chmod 600 /etc/postfix/sasl_passwd.db
```

設定が間違っていないか、確認します。エラーがなければ問題ありません。

```bash
sudo postfix check
```

設定を反映させるために、Postfixを再起動します。

```bash
sudo systemctl restart postfix
# または開始
sudo systemctl start postfix
```

OSによっては `postfix` コマンドの場合もあります。

```bash
sudo postfix restart
# または開始
sudo postfix start
```

## メール送信

メール送信を行います。 `mail` コマンドでは送信元が変更できないので、 `sendmail` コマンドを使います。 `FROM_ADDRESS` と `TO_ADDRESS` は適宜変更してください。

```bash
/usr/sbin/sendmail -t <<EOF
From: FROM_ADDRESS
To: TO_ADDRESS
Subject: Test from blastengine

Message from terminal
EOF
```

これで、blastengineの管理画面にて、メール送信完了が確認できていれば問題ありません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/46dce935-ad1a-8215-45bf-d101560bf45b.png)

もちろんメールクライアントでも受信を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/4f4eb623-22e1-e582-23d1-47bb25ee6f46.png)


## まとめ

Postfixを使えば、メール送信はローカルのものが使えるので、より手軽です。ぜひお試しください。

[エンジニア向けメール配信システム「ブラストエンジン」](https://blastengine.jp/)
テンプレートリテラルをもう少し理解したい(MDNを添えて)

## 俺たちは雰囲気でテンプレートリテラルをやっている
MDNより
> テンプレートリテラルはバッククォート (`) で区切られたリテラルで、substitutionと呼ばれる埋め込み式が利用できます。
タグなしテンプレートリテラルは文字列となるため、文字列の補間に便利です（エスケープされていない改行が許されるため、複数行の文字列も可能です）。

変数を埋め込んで見やすい形式で文字列を生成できて便利だー、という漠然とした理解の下に雰囲気で使っていた & 何も困らなかったためこれまで調べてこなかった。

が!調べて見るといくつか発見があったため、まとめてみる。

## タグなしテンプレートリテラル
おなじみ。改行できたり、式を埋め込めて見やすい形式で文字列を生成できて便利。

```ts
// 文字列リテラル
const name = "foo";
console.log("Hello\n" + "World\n" + name + "-san");
// Hello
// World
// foo-san

// テンプレートリテラル
const name = "foo";
console.log(`Hello
World
${name}-san`);
// Hello
// World
// foo-san
```

### テンプレートリテラルは文字列リテラルではない
雰囲気で使っていたために見落としていた点がこちら。

MDNより
> テンプレートリテラルは非公式に「テンプレート文字列」と呼ばれることもありますが、文字列リテラルではないので、文字列リテラルが使えるところならばどこでも使えるわけではありません。

使えない場所ってどこよ?と思ったので具体例で理解しよう。

- 例: オブジェクトのプロパティ名
```ts
const key3 = "key3"
const obj = {
  'key': "value", // 文字列リテラル
  key1: "value1", // 識別子
  // `key2`: "value2", // テンプレートリテラル(これはエラー)
  // `${key3}`: 'value3', // テンプレートリテラル (これもエラー)
};
```

同様に JSON などスタティックなキー値を要求する場所はNG。

## タグ付きテンプレートリテラル
MDNより
> タグつきテンプレートリテラルは、リテラルから任意のテキストセグメントの配列と、任意の置換の値を引数として関数（タグ関数）を呼び出します。これは、 DSL に便利です。

### 無知の頃の感想「これ文法エラーじゃないの???」
わりと初見殺しな気がする。通常、関数は`myFunction(person, age)`みたいな感じにカッコで囲んでパラメータを渡すが、でもMDNにある例のように myTag\`That \\${person} is a \\${age}.\` という形式が使え、文字列を生成する前処理として機能する。
```ts
let person = "Mike";
let age = 28;

function myTag(strings, personExp, ageExp) {
  let str0 = strings[0]; // "That "
  let str1 = strings[1]; // " is a "
  let str2 = strings[2]; // "."

  let ageStr;
  if (ageExp > 99) {
    ageStr = "centenarian";
  } else {
    ageStr = "youngster";
  }

  // テンプレートリテラルを用いて組み立てた文字列を返すこともできます
  return `${str0}${personExp}${str1}${ageStr}${str2}`;
}

let output = myTag`That ${person} is a ${age}.`;

console.log(output);
// That Mike is a youngster.

```

### 具体的にどこで使われてるの?
(再掲) MDNより
> タグつきテンプレートリテラルは、リテラルから任意のテキストセグメントの配列と、任意の置換の値を引数として関数（タグ関数）を呼び出します。これは、 DSL に便利です。

DSL に便利らしい。例えばどのように使われているのか?

- 例1: CSS-in-JS
styled-components では CSS を定義するのにタグ付きテンプレートが使われている。
```ts
// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: #BF4F74;
`;
```

- 例2: Deno dax と Bun Shell
地味に今回テンプレートリテラルを調べようと思ったきっかけ。 dax ではコマンドをテンプレートリテラル形式で記載し、$ 関数内で実行している様子。
```ts
#!/usr/bin/env -S deno run --allow-all
import $ from "@david/dax"; // "dax-sh" in Node

// run a command
await $`echo 5`; // outputs: 5
```

Bun Shell も同様
```ts
import { $ } from "bun";

const response = await fetch("https://example.com");

// Use Response as stdin.
await $`cat < ${response} | wc -c`; // 1256
```

## 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Template_literals

https://styled-components.com/docs/basics#getting-started

https://github.com/dsherret/dax

https://bun.sh/docs/runtime/shell
MVVMモデルの簡単な解説



# MVVM

MVVM（Model-View-ViewModel）パターンは、ソフトウェアの設計パターンの１つです。
MVC（Model-View-Controller）モデルでは、VとCの分離が必要となりますが、Windowsアプリや
Androidアプリに準備されているフレームワークではその分離が難しいです。

例えば、Androidのフレームワークでは、ActivityやFragmentがViewとControllerの両方の役割を果たします。これらのクラスは、UIのレイアウトを管理し、ユーザー入力を処理し、データをModelから取得します。これらの理由から、ViewとControllerの分離は難しいと言えます。

同様に、Windowsのフレームワークでは、ViewとControllerの役割が混在しており、UIイベントは通常、Viewの範囲で処理されます。


## 概要

MVVMはアプリケーションの構造を３つの主要なコンポーネントに分割します。
1. Model（モデル）
1. View（ビュー）
1. ViewModel（ビューモデル）

```plantuml
@startuml

class View {
    + displayData()
}

class Model {
    + data
    + getData()
    + updateData()
}

class ViewModel {
    + model
    + view
    + updateView()
    + getModelData()
    + updateModelData()
}

Model -L-> ViewModel : <<provides>>
ViewModel -L-> View : <<updates>>
View ..> ViewModel : <<databinding>>

@enduml
```

## コンポーネントの内容

1. Model（モデル）：アプリケーションのデータとビジネスロジックを表します。モデルはデータベース、ファイル、APIなどからデータを取得し、それをアプリケーション内で使用できる形式に変換します。

1. View（ビュー）：ユーザーに表示されるUI部分です。ビューはユーザーの操作を受け取り、それをViewModelに伝えます。

1. ViewModel（ビューモデル）：ViewとModelの間の接続役を果たします。ViewModelはViewからの入力を間接的に受け取り、それに基づいてModelを更新します。具体的には、ViewがViewModelのメソッドを呼び出すことで入力を受け取ります。また、ModelのデータをViewが表示できる形式に変換します。

## MVCとの違い
MVVMにおいて、MVCと違ってVが入力も管理します。Cが制御していたキー入力部分も含めての対応となります。
MVCに比較し、WindowsアプリやAndroidアプリに提供されているフレームワークでの実現がしやすいです。
Chat with RTX インストールエラー

:::note info
この記事は旧インストーラーの情報です
最新は以下のURLからDLできます。 ~~ChatWithRTX~~ >>> ChatRTX
[chatrtx](https://www.nvidia.com/en-us/ai-on-rtx/chatrtx/)
:::

## 背景
ローカルで実行できるLLM ChatwithRTXをインストールするときのトラブル対応メモ。
私の環境(Acer Nitro ANV15-51 Windows11 Pro)では、初期起動でPythonライブラリのインストールで以下のエラーが出た。このメッセージだけでは対処できなかったのでその内容を記載します。
```rb
'Please install it with `pip install sentence-transformers'
```
## 内容
### インストール
インストーラーをダウンロードし、実行する。約38GB
[chat-with-rtx](https://www.nvidia.com/ja-jp/ai-on-rtx/chat-with-rtx-generative-ai/)

### 起動
NVIDIA Chat with RTX（デスクトップにアイコンができる）
を起動する。初期化のためにプロンプトが起動し、Python環境のインストールが始まるが以下のライブラリがないためにエラーで停止してしまう。
```rb
`sentence-transformers'
```

ChatwithRTXのインストーラーによりインストールされたPython環境(miniconda)のプロンプトを起動して、指示通りにこのライブラリをインストールするが改善されない。
```rb
'pip install sentence-transformers'
```

### 対策
minicondaの仮想環境をChatwithRTXの環境に切り替える。

ライブラリのインストールコマンドに-U オプションを追加する。
```rb
'pip install -U sentence-transformers'
```
コマンドプロンプトでの作業一覧
![chatwithrtx_install004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/544164/5c49fde0-d008-e12e-e247-1b65fc969e56.png)

### 再起動
NVIDIA Chat with RTX（デスクトップにアイコンができる）を再起動する。
ブラウザでChat with RTXの初期画面が表示される。

### まとめ
Python環境に不足するライブラリを入れるだけの対策であったが、ネット検索しても直接的な対応方法が見つからず、何度か試行錯誤して漸く上手く動作することができた。conda環境に慣れていないと対応が難しいと思い、内容をこちらにメモしておいた。
indexが日付、データが個数になっているSeriesについて、存在しない日のデータをreindexを使って0で埋めようと思ったらすべて0で埋まった件

## 結論
reindexする前に、```df.datatype```で形式を確認しよう。
indexの型が```date```と思っていたが、実は```date```ではなく、```object```になっていた。そうすると、```df.reindex```ではすべてのindexについて、fill_valueで指定した値に埋められてしまう。

今回はpandas.Seriesを、```dataframe.groupby()```を使って作成したが、その処理の前に、```groupby()```する対象のcolumnを```pd.to_datetime()```を使ってdatetime型にしておくのが良い。

csvは以前datetimeのdtypeを持ったdataframeから作ったものだったので、```read_csv()```で読み込んだ後に`dtype`が`object`となっていることに気が付かなかった。

## うまくいかない例

```python
import pandas as pd
import seaborn as sns

df = pd.read_csv('some_kind_of.csv')

# csvの中身
# 日毎の発生件数をヒストグラムに表すのが今回の目的。
# ...
# 2018-02-01,ANAウイングス,ホﾞンハﾞルテﾞｨア式DHC-8-402型,ANA331,中部国際空港,熊本空港,中部国際空港,上昇中、プロペラの除氷系統に不具合が発生したことを示すライトが点灯したため引き返した。,,2018,2
# 2018-02-04,日本エアコミューター,サｰフﾞ式SAAB340B型,JAC2321,大阪国際空港,但馬飛行場,大阪国際空港,上昇中、気流の擾乱により機体への荷重に係る運用限界一時的に超過した可能性があり、点検が必要となったため引き返した。,,2018,2
# 2018-02-05,全日本空輸,ホﾞｰインクﾞ式737-800型,ANA313,東京国際空港,富山空港,東京国際空港,上昇中、副操縦士席側前方の操縦室窓にひび割れが発生したため引き返した。,,2018,2
# ...

date_range = pd.date_range(start='2000-02-01', end='2024-03-31')
daily_count = df.groupby('発生日').count()['運航者']

daily_count = daily_count.reindex(date_range, fill_value=0)
```
この結果、daily_countとして、2000/2/1から2024/3/31まですべて0となるSeriesを得る。

## うまくいく例
```python
import pandas as pd
import seaborn as sns

df = pd.read_csv('some_kind_of.csv')

# csvの中身
# 日毎の発生件数をヒストグラムに表すのが今回の目的。
# ...
# 2018-02-01,ANAウイングス,ホﾞンハﾞルテﾞｨア式DHC-8-402型,ANA331,中部国際空港,熊本空港,中部国際空港,上昇中、プロペラの除氷系統に不具合が発生したことを示すライトが点灯したため引き返した。,,2018,2
# 2018-02-04,日本エアコミューター,サｰフﾞ式SAAB340B型,JAC2321,大阪国際空港,但馬飛行場,大阪国際空港,上昇中、気流の擾乱により機体への荷重に係る運用限界一時的に超過した可能性があり、点検が必要となったため引き返した。,,2018,2
# 2018-02-05,全日本空輸,ホﾞｰインクﾞ式737-800型,ANA313,東京国際空港,富山空港,東京国際空港,上昇中、副操縦士席側前方の操縦室窓にひび割れが発生したため引き返した。,,2018,2
# ...

df['発生日'] = pd.to_datetime(df['発生日']) # この行を加える。

date_range = pd.date_range(start='2000-02-01', end='2024-03-31')
daily_count = df.groupby('発生日').count()['運航者']

daily_count = daily_count.reindex(date_range, fill_value=0)
```
初心者が聞きかじったネットワークの超基本用語

# この記事の対象
対象となるのは全くネットワークの知識がないといったレベルの方向けの話です。
私自身超初心者で、最近先輩からネットワークの話を聞く機会があったので自分なりにまとめてみたいと思い書きました。
初心者に向けての話だったので、いろいろ省略していることや正確でないことがあると思いますが、それでも勉強になりました。
ちゃんと理解するなら他の方の投稿などを参考にするのをおすすめします。
間違っていることなどあればご指摘お願いします。

# 基本用語
## ドメイン
ざっくりいうとURLの一部であるホスト名のこと。どのWebページでも上部に表示されているやつ（https://qiita.com/ の`qiita.com`など）。最初の通信でURLを持ってDNS（ドメインネームシステム）に行き、そこからこのURLのIPアドレス（住所のようなもの）を受け取って、目的のページにアクセスしている。

## IPアドレス
Web上での住所のようなもの。
IPはInternet Protocolのこと、直訳で通信規格。ルールみたいなもの。（例えるなら、日本でいえば「車は左車線を走る」みたいな感じらしい。）
この規格に沿って決められた住所で、スマホやPCなどのデバイスごとに世界で唯一のものが割り振られる。
住所の表し方にIPv4やIPv6などのバージョンが存在する。

## IPv4アドレス
IP version 4 のアドレス。255までの整数を4つ使って表す。
```
192.3.21.233
```
なぜ255までなのかというと、
- IPv4アドレスは32ビットで表す（なぜ32ビットなのかは昔の人がそう決めたから。）
- CPUが扱うのは2進数で表した数字（0か1だけ）。数字1つで1ビット。
- 255は2進数で表すと11111111（8ビット）
ということで、この255（8ビット）までの数字を4つ組み合わせることにより32ビットで表すことができる。

※ちなみに4つのセクションをそれぞれ第1オクテット～第4オクテットという。オクテットは8ビットをひとまとまりとした単位。

## IPv6アドレス
IP version 6 のアドレス。
```
2024:0db8:1234:5678:90ab:cdef:0519:1435
```
それぞれの区切りがコロン（：）になり、16進数で表記されている。16進数なので0～9とa～fまでを使った表記になっている。

近年のIT化などに伴いIPv4アドレスの枯渇が懸念されるようになり登場した。
IPv6アドレスに対応している環境かどうかは確認が必要。

## サブネットマスク
IPアドレスのグループ化みたいなこと。
```
IPアドレス　192.3.21.233
サブネットマスク　255.255.255.0
```
となっていたら、サブネットマスクの255の部分はそのサブネットでは共通で、最後の0の部分だけ、それぞれのデバイスに255までの数字を割り振っていく。
ある限られた範囲・グループでネットワークを作るとき、IPアドレスの一定部分までを共通にしておくことで通信の簡略化などが可能になる仕組み。

## デフォルトゲートウェイ
宛先のわからないパケットの転送先となるIPアドレス。
普段家などでWi-Fiを使ってネットを使っていると思うが、実際には直接グローバルネットワークに接続するのではなく、一度ルーターを通して通信をする。
そのときのルーターのアドレスと思っておけばOK。

## ローカルネットワーク
文字通り、ローカルだけでつながっており、グローバルに出ていかないネットワークの範囲。先ほどのWi-Fiなどでつながっている範囲もこれに含まれる。

## グローバルネットワーク
こちらも文字通り世界につながったネットワーク。家のWi-Fiの場合、デフォルトゲートウェイを通って繋がっている。

## ポート
通信の識別子のようなもの。実際にネットワークにつながっているからと言って、すべてにアクセスできるわけではなく、このポート番号を指定して、許可されたポート番号しか通信できないように設定ができる。
普段使用しているhttpsの通信のポート番号は443で、これが許可されているからいろんなWebページを開いたりできる。

## ファイアウォール
ネットワークの出入り口に設置して、外部からの不正な侵入や内部から外部への不正なアクセスを禁止する装置。
許可されたポート番号だけこのファイアウォールを抜けられる。
ポート番号の許可を設定しておくことを「穴あけ」と言ったりするらしい。

## TCP/UDP
ネットワークでのコンピュータ同士の通信はアプリケーション同士の通信であり、その時のデータのやり取りの仕方みたいなもの。
それぞれ、Transmission Control Protocol と User Datagram Protocol である。
TCPは送るものを何度も確認しながら通信を進めるのに対し、UDPは送る順番も関係なしに一気にデータを送り付けるイメージ。
もっとざっくりいうとTCPは丁寧だけど少し遅い通信、UDPは雑だけど早い通信って感じ。もし選択する必要がある場合は基本的にTCPにしておけば大丈夫らしい。
リダイレクト">"を使用してファイルに出力できなかったので調べて対応した

# 課題
[Linux標準教科書](https://linuc.org/textbooks/linux/)を読んで">"でファイルに出力しようとしたが以下のメッセージが出力された。
```
$ sudo echo "Hello" > ls-result
bash: ls-result: 許可がありません
```
">”のところで、権限がないユーザーによりファイル出力をするため。エラーメッセージが出力された。


# 解決法
まず、ls-resultファイルの権限を確認
```
-rw-r--r-- 1 root root       889  5月 18 23:51 ls-result
```
その他のユーザーには読み取りしかないことを知った。

teeコマンドを使った。
- teeコマンドとは出力した結果をファイルに出力でき、結果も返してくれるコマンド

つまり、echoコマンドで出力させる"Hello"を引数としてteeを実行すればよい。
こんな感じでやってみた。
```
echo "Hello" | sudo tee ls-result
[sudo] ユーザ名 のパスワード: 
Hello
```

# まとめ
">”を使う際にはユーザーが現在のユーザーになってしまい、sudoでrootユーザー">”以降を実行できないため注意が必要。

# 参考文献
以下を参考にして学習しました。
ありがとうございます。
[sudoで">"でファイル出力しようとすると、Permission deniedエラーが出る時の対処法](https://qiita.com/matsu_qiita/items/d30f25595cc63e072ba0)
ChatGPT新機能でできちゃうこと

### ChatGPT新機能について！

2024年5月中旬において、OpenAIが開発している生成AI、**ChatGPT**について新たな情報が出ましたので、簡単な記事として紹介させていただきます。

#### 1. ChatGPTデスクトップアプリ
ChatGPTのデスクトップアプリが登場！このアプリでは、ドキュメントをアップロードして要約したり、メールをリライトしたりできちゃいます

#### 2. GPT-4 Omniの登場
次に紹介するのは、最新モデルのGPT-4 Omniです。これには以下のすごい機能があります

- **多形式入力・応答**：テキスト、音声、画像を組み合わせて質問すると、同じように多形式で答えてくれます。
- **超高速応答**：[平均232ミリ秒](https://www.psypost.org/how-fast-you-respond-to-someone-during-conversation-is-a-signal-of-how-connected-you-are-study-finds/)で、まるで人間と話しているみたいに素早い応答ができちゃいます！(こちらはまだできる人とそうじゃない人がいるみたいで全員ができるように随時対応しているそうです)
- **感情表現**：応答に感情がこもるので、会話がよりナチュラルになります。

さらに、他のモデルと比べて圧倒的なパフォーマンスを誇ります。

#### 3. GPT-4 Omniが無料に！
以前は有料だったGPT-4 Omniが、なんと**無料**で使えるようになりました！これ、すごくないですか(；ﾟДﾟ)！！一部の機能（音声会話など）は有料ですが、無料でもウェブ検索や画像生成が楽しめます。

#### まとめ
デスクトップアプリ、GPT-4 Omni、そして無料アクセスと、ChatGPTの新しいアップデートが盛りだくさんでした。この記事が少しでも参考やきっかけになればよいなと願っております。
2分で読める「AWS Amplify」について

# 1. AWS Amplifyとは

https://aws.amazon.com/jp/amplify/?nc=sn&loc=1

AWS Amplifyは、Amazon Web Services（AWS）が提供する一連のツールとサービスで、フロントエンドのウェブアプリケーションおよびモバイルアプリケーションの開発、デプロイ、ホスティングを簡素化することを目的とした「クラウドプラットフォームサービス」です。以下の主要なコンポーネントから構成されています。

### Amplify CLI
コマンドラインツールで、プロジェクトのセットアップ、リソースのプロビジョニング、アプリケーションのデプロイを行います。


### Amplify Console
継続的デプロイメントとホスティングを提供するサービスで、Gitリポジトリと連携してコードの変更を自動的にデプロイします。

### Amplify Libraries
クライアントサイドライブラリで、認証、データストレージ、API呼び出し、分析などの機能を簡単に統合できます。

### Amplify UI Components
事前に構築されたUIコンポーネントで、開発速度を向上させ、ユーザーエクスペリエンスを向上させます。


# 2. 他サービス（Firebase）との比較表

クラウドプラットフォームがどのようなサービスなのかを把握するために、Firebaseと比較してみました。いずれのサービスも各項目でサービスが提供されていることがわかります。


| 機能/サービス       | AWS Amplify     | Firebase           |
|------------------|----------------|------------------|
| **提供元**          | AWS            | Google            |
| **主な機能**        | フロントエンドとバックエンドの統合、認証、データストレージ、API、ホスティング | 認証、データベース、ストレージ、ホスティング |
| **ターゲットユーザー** | 全ての開発者       | モバイルアプリ開発者、ウェブアプリ開発者 |
| **料金体系**        | 使用量に応じた課金  | 無料枠＋使用量に応じた課金 |
| **認証**           | AWS Cognito     | Firebase Authentication |
| **データベース**     | Amazon DynamoDB, Aurora | Firebase Realtime Database, Firestore |
| **ストレージ**      | Amazon S3       | Firebase Storage   |
| **ホスティング**     | Amplify Hosting | Firebase Hosting   |
| **サーバーレス機能**  | AWS Lambda      | Cloud Functions for Firebase |
| **分析**           | Amazon Pinpoint | Firebase Analytics |
| **継続的デプロイ**    | あり             | あり               |
| **カスタマイズ性**    | 高い             | 高い               |
| **ドキュメントとサポート** | 豊富なドキュメント、AWSサポート | 豊富なドキュメント、Firebaseサポート |

# 3. QuickStartを使ってみた

ここまでキャッチアップしてみて、言葉だけではイメージしづらい箇所が多い...
そこで、以下サイトにある QuickStartを使いました。

https://docs.amplify.aws/react/how-amplify-works/concepts/

簡易的なTODOリポジトリ（ドキュメントでは「starter template」と表現されている）が既に準備されており、手順が丁寧で分かりやすいです。そのため、全体像を把握するにはもってこいの内容だと個人的には感じました。手順に関してはドキュメントがあるので割愛します。

QuickStartで理解できる内容は以下の通りです。

### ①Amplifyの操作感
私はGitHubアカウントを連携して、Amplifyへの登録からデプロイまでを確認しました。

### ②TODOアプリを更新・再デプロイ
デプロイ後、削除機能を実装して再デプロイする手順も書かれています。
再デプロイ時にAmplify側でどのような挙動になるかを確認できます。

### ③認証機能の実装
「Amplify UI Components」で提供されている「Authenticator UIコンポーネント」を使い、ログイン機能を実装できます。思いのほか簡単に実装できました。

### ④ユーザーごとの認可を実装
すべてのユーザー間で共有されるデータをユーザーごとに分離する実装も学べます。

# 4. さいごに

ちなみに「starter template」を使わずに一から理解を深めたいという方は、以下から手順に沿って対応ができます。

https://docs.amplify.aws/react/start/manual-installation/


最後までご覧いただきありがとうございました！

# おまけ（用語集）

| 用語               | 説明                                         |
|------------------|--------------------------------------------|
| ホスティング         | ウェブサイトやアプリケーションをインターネット上で公開するサービス               |
| プロビジョニング     | 必要なリソースや環境を準備し、利用可能な状態にするプロセス                     |
| リソース           | コンピューティング、ストレージ、ネットワークなどの計算資源                    |
| デプロイ           | アプリケーションやサービスをサーバーに配置して稼働させること                     |
| 継続的デプロイメント   | コードの変更を自動的にデプロイし、即座に本番環境に反映するプロセス                 |
| ユーザーエクスペリエンス | ユーザーが製品やサービスを使用する際の総合的な体験                           |
| Firebase         | Googleが提供するモバイルおよびウェブアプリ開発プラットフォーム                |
| 認証              | ユーザーの身元を確認し、システムにアクセスできるかを判断するプロセス               |
| 認可              | 認証されたユーザーが特定のリソースや機能にアクセスできるかを制御するプロセス
なぜか毎回忘れてしまう事項

# 記事の趣旨
　初心者の自分が勉強をしている中、なぜかわからないが記憶に残らない事項がいくつかあるのでそれを記事にすることで記憶への定着を図る。基本的なことばかりなのでこの記事を読む人に学びを提供できるものではない。
# コード例
```HTML
<body>
  <section>
    <div>
      <img src="sample.jpg">
    </div>
  </section>
</body>
```

```CSS
section {
  width: 400px;
  height: 400px;
  margin: 0 auto;
}

div {
  height: 100%;
}

div img {
  opacity: 1;
}

img {
  width: 100%;
  height: 100%;
  opacity: .6;
}
```

# ポイント
1. divにつけたheight
1. opacityの優先順位
1. imgの高さと幅

### 1について
　imgに`width: 100%;`と`height: 100%;`を指定すると、幅は変化するものの高さには変化がない。これは以下の仕様によるものである（MDNより）。
> パーセント値は、生成ボックスの包含ブロックの高さを基準に計算されます。包含ブロックの高さが明示的に定義されず (すなわち、コンテンツの高さに依存します)、この要素が絶対位置指定されていない場合は、値は auto になります。

　そこで、imgの親要素であるdivに高さを指定している。widthと挙動が異なるので注意。

### 2について
　imgのopacityがふたつあるので下に書いた`opacity: .6;`が適用されるようにも思えるが、詳細度は`opacity: 1;`のほうが高いので、こちらが優先される。

### 3について
　imgはインライン要素なので`display: inline-block;`にしなければ高さと幅を設定できないようにも思えるが、imgは置換要素であるのでそのまま高さと幅を設定できる。