OmniAICreator/Qiita-1.07M huggingface dataset:
既存クラスのメソッドにエラーハンドリングを追加する

## この記事の内容

ライブラリなどに定義されているクラスの全ての関数に対し `try...except` でエラーを捕捉し、適切なエラーを返す方法を紹介します。

## 背景
PySparkを用いて開発する際、`spark.sql.DataFrame` のメソッド関係のエラーが頻発していました。最初はいちいち `try...except` で囲うことも考えたのですが、可読性の問題を考えて何か良い方法はないかと考えてこの方法に辿り着きました。

## 関数にエラーハンドリングを付与する
本題に入る前に、関数定義の際にエラーハンドリングを付加するための方法としてデコレータを用いた方法が取られます。

```python:python
class MyException(Exception):
    def __init__(self, message = "An error occurred"):
        super().__init__(message)

def error_handling_wrapper(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            raise MyException(f"An error occurred in {func.__name__}: {e}") from e

    return wrapper
```

もちろん `except Exception as e` の部分は全てのエラーを補足してしまうので適切なエラーのみに書き換えるべきですが、今はこのまま話を進めます。この関数をデコレータとして使用すると例えば以下のようになります。

```python:python
@error_handling_wrapper
def test():
    1/0

test()

# 前略
# MyException: An error occurred in test: division by zero
```

この関数をクラスのメソッドに適用していきます。

## クラスメソッドへの適用

以下の `decorate_all_methods_in_cls` を使用することでエラーハンドリングをクラスの全ての関数に適用することができます。
例として `pyspark.sql.DataFrame` に適用しています。
```python:python
from pyspark.sql import DataFrame

def decorate_all_methods_in_cls(decorator):
    def decorate(cls):
        for attr in dir(cls):
            if callable(getattr(cls, attr)) and not attr.startswith("_"):
                setattr(cls, attr, decorator(getattr(cls, attr)))
        return cls
    return decorate

DataFrame = decorate_all_methods_in_cls(error_handling_wrapper)(DataFrame)
```
全ての関数に適用、と言いましたが実際は `_` から始まらない、public な使用を想定された関数に対して `error_handling_wrapper` を適用するような形になっています。これによってクラスに含まれる関数がエラーを出した時に例外処理が行われます。

### 使い道
背景の部分にも書いたように、PySpark を使用する際（厳密には Spark と Sedona で地理的操作をする際）にエラーが頻発しており、関連する操作すべてに `try...except` を使用するのは憚られたのでこのような対策を思いつきました。ただこんなことが起こるのはそもそもコードが悪い可能性もあるのでまずはコードの見直しが必要であると思います。
ライブラリ内で発生するエラーをカスタムエラーで統一的に処理したいなんて場合にもこの方法は使えそうです。
また今回紹介した例は `DataFrame` クラスに対し適用する形となっていますが、PySpark では `DataFrame` を直接生成することよりも csv やデータベースからの読み込みによって生成することのほうが多く、今回の手法は使えません。多分ラッパークラスとかを使うんだと思いますがまだよく理解していないのでまた理解したら記事にしたいです。

## おわりに
今回紹介した方法とは別のベストプラクティスがあればぜひコメントでお教えいただければ幸いです。最後までお読みいただきありがとうございました。
画像で横幅が-90度回転した場合に縦に合わせる



```
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Rotate and Center with Proportional Div2</title>
  </head>
  <body>
    <div class="p-body">
      <img class="div1" src="./img/blue-tit-8024809_1280.png" alt="" width="1280" height="640" />
      <img class="div2" src="./img/img2.webp" alt="">
    </div>

    <style>
      body {
        margin: 0;
      }
      .p-body {
        position: relative;
        height: 100vh;
        display: flex;
        justify-content: center;
      }
      .div1 {
        height: auto;
        width: calc(100vh - 72px);
        object-fit: contain;
        transform: translateY(36px) rotate(-90deg);
      }
      .div2 {
        position: absolute;
        top: calc(50% + 36px);
        left: 50%;
        width: 33vw;
        transform: translate(-50%, -50%);
        background-color: rgb(10, 42, 42);
      }
    </style>
    <script>
      document.addEventListener("DOMContentLoaded", function() {
        const div1 = document.querySelector('.div1');
        const div2 = document.querySelector('.div2');

        function updateDiv2Width() {
          const div1Width = div1.naturalWidth;
          const div1Height = div1.naturalHeight;
          const aspectRatio = div1Height / div1Width;

          const div1RotatedHeight = window.innerHeight - 72
          const div1RotatedWidth = div1RotatedHeight * aspectRatio;

          div2.style.width = `${div1RotatedWidth}px`;
        }

        div1.onload = updateDiv2Width;

        // If the image is already loaded (from cache), trigger the onload event manually
        if (div1.complete) {
          updateDiv2Width();
        }

        window.addEventListener('resize', updateDiv2Width);
      });
    </script>

  </body>
</html>

```
renameコマンドが使えないときにファイル名を一括置換するワンライナー

本稿ではrenameコマンドが使えないLinux環境においてファイル名を一括置換するワンライナーの例を紹介する。

# forループを利用する場合

forループの使用が許容される場合は

```sh:bash系
for file in *test1*; do mv -n "$file" "${file/test1/test2}"; done
```

```sh:csh系
foreach file (*test1*) ; mv -n "$file" `echo "$file" | sed 's/test1/test2/'` ; end
```

などとすればよい。拡張子が `.txt` のファイルのみリネームしたい場合は `*test1*` の部分を `*test1*.txt` と書けばよい。

> このうち、bash系のワンライナーの方が処理は速い。bashのワンライナーは、ループの中で外部プロセスを生成することなく、組み込み機能だけで処理を行うためである。

# forループを利用しない場合

何らかの理由でforループの使用が躊躇われる場合は以下のようにする。

```sh:ファイル名の "test1" の部分を "test2" に一括置換するコマンド①
ls * | xargs -n 1 | sed 'p;s/test1/test2/g' | xargs -n 2 mv
```

この一連のコマンドは以下のように機能している。
1. `ls *` でカレントディレクトリ内の全ファイルとディレクトリをリストする。
2. `xargs -n 1` でそれらを1行ずつ `sed` に渡す。
3. `sed 'p;s/test1/test2/g'` で各ファイルについて変更前後の名前をそれぞれ出力する。1回目（`p`の部分）はそのまま、2回目（`s`で置換している部分）は `test1` を `test2` に置き換えたもの。
4. `xargs -n 2 mv` で2つの引数をまとめて `mv` コマンドに渡し、ファイル名を変更する。最初の引数は元のファイル名、2番目の引数は新しいファイル名となる。`-n` オプションは同名のファイルが既に存在する場合に上書きを禁止する。


例えば、ディレクトリに次のファイルがある場合を考える。
```
file_test1.txt
file_test2.txt
test1_document.txt
```
この場合、コマンドは次のように動作する。

① `ls *` で全ファイルリストを取得：
```
file_test1.txt
file_test2.txt
test1_document.txt
```
② `xargs -n1` で1行ずつ処理：
```
file_test1.txt
file_test2.txt
test1_document.txt
```
③ `sed 'p;s/test1/test2/g'` で各行を2回出力：
```
file_test1.txt
file_test2.txt
file_test2.txt
file_test2.txt
test1_document.txt
test2_document.txt
```
④ `xargs -n 2 mv` で2つの引数を渡し、`mv` でファイル名を変更：
```sh
mv file_test1.txt file_test2.txt
mv test1_document.txt test2_document.txt
```
先程のコマンドにより、ワンラインでこれを一括実行できる。
拡張子が `.txt` のファイルのみリネームしたい場合は `ls *` の部分を `ls *.txt` と書けばよい。

## findを利用するケース

以下のように `find` コマンドを利用することもできる。カレントディレクトリ配下の全ファイルについて `rename` の操作を一括で実行したい場合には便利である。

```sh:ファイル名の "test1" の部分を "test2" に一括置換するコマンド③
find . -type f -name '*test1*' | sed 'p;s/test1/test2/' | paste - - | xargs -n 2 mv -n
```

`paste - -` によって標準入力を2行ずつ結合して一行にまとめている。
なお `-n` が2回登場しているが、 `xargs` コマンドの `-n` オプションと `mv` コマンドの `-n` オプションは別物なので、この形式で正しい。

> `find . -type f -name '*test1*'` は現在のディレクトリ以下で名前に test1 を含むファイルを検索する。そのため、カレントディレクトリ配下の該当するすべてのファイルに `mv` コマンドが適用されることに注意。

`sh` を呼び出しているのでやや回りくどいが、以下の方法でも同様の処理が実行される。

```sh:ファイル名の "test1" の部分を "test2" に一括置換するコマンド②
find . -type f -name '*test1*' | xargs -I {} sh -c 'mv -n "$1" "${1//test1/test2}"' _ {}
```

* * *

環境によっては `mv` や `ls` などに特殊なaliasが設定されている場合もあるため、事前に挙動を検証してから実行することが推奨される。
ディレクトリトラバーサル

## はじめに

ディレクトリバーサルについてまとめる

### ディレクトリトラバーサルとは

本来想定していたパスを遡って自由にファイルを読み書きされてしまう脆弱性のこと。

### 例

クエリ情報経由でパスを受け取る以下のコードがあったとき、

```php:download.php
$fl = $_GET['path'] ?? "default.jpg";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename= "' . $fl . '"');
print file_get_contents("./doc/{$fl}");
```
ユーザーが
`http://localhost/download.php?path=../../../../apache2/conf/httpd.conf`
のようなアドレスを指定するとhttpd.confを入手できてしまう。
(`file_get_contents()`が相対パスも受け入れ可能なため)

本来は`/doc`フォルダの配下だけにアクセスさせるつもりだったのが想定している公開フォルダを超えて、公開すべきでない上位フォルダのファイルが勝手に参照できてしまう。

### 対策

リクエスト情報としてディレクトリ情報を受け渡ししないこと。
ファイル名のみを指定する。

```php:download.php
$fl = basename($_GET['file_name']) ?? 'default.jpg';
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename= "' . $fl . '"');
print file_get_contents("./doc/{$fl}");
```
TypeScriptにおける反復可能なオブジェクト：`Map` と `Set`

## はじめに
JavaScriptおよびTypeScriptでは、反復可能なオブジェクトを使ってデータの集合を効率的に管理できます。反復可能なオブジェクトには、`Map`と`Set`があります。

## `Set`オブジェクト

`Set`は一意の値の集合を保持するデータ構造です。同じ値を重複して持つことができません。

### 基本的な使い方

#### `Set`の作成

```typescript
let mySet: Set<number> = new Set<number>();

mySet.add(1);
mySet.add(2);
mySet.add(2); // 重複する値は無視される
mySet.add(3);

console.log(mySet); // Set { 1, 2, 3 }
```

#### `Set`の反復処理

`for...of`構文を使用して、`Set`内のすべての要素を反復処理できます。

```typescript
let mySet: Set<number> = new Set([1, 2, 3, 4, 5]);

for (let value of mySet) {
    console.log(value);
}
// 出力: 1, 2, 3, 4, 5
```

### その他のメソッド

- **`has`**：指定した値が`Set`に存在するかどうかをチェックします。
- **`delete`**：指定した値を`Set`から削除します。
- **`clear`**：`Set`のすべての要素を削除します。

```typescript
console.log(mySet.has(3)); // true
mySet.delete(3);
console.log(mySet.has(3)); // false
mySet.clear();
console.log(mySet.size); // 0
```

## `Map`オブジェクト

`Map`はキーと値のペアを保持するデータ構造です。各キーは一意であり、任意の値をキーとして使用できます。

### 基本的な使い方

#### `Map`の作成

```typescript
let myMap: Map<string, number> = new Map<string, number>();

myMap.set("one", 1);
myMap.set("two", 2);
myMap.set("three", 3);

console.log(myMap); // Map { 'one' => 1, 'two' => 2, 'three' => 3 }
```

#### `Map`の反復処理

`for...of`構文を使用して、`Map`内のすべてのキーと値のペアを反復処理できます。

```typescript
let myMap: Map<string, number> = new Map([
    ["one", 1],
    ["two", 2],
    ["three", 3]
]);

for (let [key, value] of myMap) {
    console.log(`${key} = ${value}`);
}
// 出力:
// one = 1
// two = 2
// three = 3
```

### その他のメソッド

- **`get`**：指定したキーに対応する値を取得します。
- **`has`**：指定したキーが`Map`に存在するかどうかをチェックします。
- **`delete`**：指定したキーとその値を`Map`から削除します。
- **`clear`**：`Map`のすべてのエントリーを削除します。

```typescript
console.log(myMap.get("two")); // 2
console.log(myMap.has("three")); // true
myMap.delete("three");
console.log(myMap.has("three")); // false
myMap.clear();
console.log(myMap.size); // 0
```

## 反復可能なオブジェクトの共通点

`Set`や`Map`を含む反復可能なオブジェクトは、`Symbol.iterator`プロパティを持ち、`for...of`構文を使用してその要素を順番に反復処理することができます。これにより、データの集合に対して簡単かつ効率的に操作を行うことができます。

### `for...of`構文の利点

- **シンプルで読みやすい**：`for...of`構文は、従来の`for`ループよりもシンプルで読みやすいコードを実現します。
- **汎用性**：配列、文字列、`Set`、`Map`など、すべての反復可能なオブジェクトに対して使用できます。

### 例

```typescript
const numbers = [1, 2, 3, 4, 5];
for (let num of numbers) {
    console.log(num);
}
// 出力: 1, 2, 3, 4, 5
```

```typescript
const mySet = new Set(["apple", "banana", "cherry"]);
for (let fruit of mySet) {
    console.log(fruit);
}
// 出力: apple, banana, cherry
```

## まとめ

`Set`と`Map`は、TypeScriptおよびJavaScriptでデータを管理するための強力なツールです。`Set`は一意の値の集合を保持し、`Map`はキーと値のペアを管理します。これらのデータ構造は反復可能であり、`for...of`構文を使用して効率的に反復処理できます。これにより、コードの可読性と効率が向上します。
【 Python 】辞書型

## ■　はじめに
Python勉強につき、メモを残します。
下記内容は、備忘録レベルで書いてますので間違い等あるかもしれません。
参考にする際にはその点ご認識のほどお願いします〜。。

## ■ 辞書型
・ 空の辞書型定義
・ データの追加
・ データへのアクセス
・ 変数定義と値の代入
・ データの編集
・ データの削除
・ keyの全取り出し
・ valueの全取り出し
・ 存在しないkeyへのアクセス(エラー)
・ setdefault関数

##  ■ サンプルソース
```python:辞書型
# 空の辞書型を作成し、後からデータを追加
teacher = {}

# 追加構文：変数名['key'] = value
teacher[1] = 'Oniduka'

# データへのアクセス
print(teacher[1])
# 出力結果： Oniduka

# 変数定義と値の代入：変数名 = {key: value...}
student = {1: 'Aida', 2: 'Uida', 3: 'Iida'}

# データの編集
print(f'studentデータ編集前：{student}')
student[2] = 'Iida'
student[3] = 'Uida'
print(f'studentデータ編集後：{student}')
# 出力結果： studentデータ編集前：{1: 'Aida', 2: 'Uida', 3: 'Iida'}
# 出力結果： studentデータ編集後：{1: 'Aida', 2: 'Iida', 3: 'Uida'}


# データの削除
print(f'studentデータ削除前：{student}')
student.pop(3)
print(f'studentデータ削除後：{student}')
# 出力結果： studentデータ削除前：{1: 'Aida', 2: 'Iida', 3: 'Uida'}
# 出力結果： studentデータ削除後：{1: 'Aida', 2: 'Iida'}

# keyの全取り出し
print(student.keys())
# 出力結果： dict_keys([1, 2])

# valueの全取り出し
print(student.values())
# 出力結果： dict_values(['Aida', 'Iida'])

# 存在しないkeyへのアクセス(エラー)
print(student[3])
# 出力結果： 
#   Traceback (most recent call last):
#   print(student[3])
#   KeyError: 3

# setdefault関数
print(student.setdefault(4, 'データが存在しません'))
# 出力結果： データが存在しません

```

##  ■ ネストした構造の辞書型
```python:ネスト辞書
# ネスト構造の辞書型
students = {
    'student_01':
        {
            'name': 'Aida',
            'age': 25,
            'courses': ['Math', 'Science', 'English']
        },
    'student_02':
        {
            'name': 'Iida',
            'age': 30,
            'courses': ['Dotoku']
        },
}
# student_01の名前にアクセス
print(students['student_01']['name'])
# 出力結果： Aida

# student_01のコースにアクセス
print(students['student_01']['courses'])
# 出力結果： ['Math', 'Science', 'English']

# student_02のコースの1つ目にアクセス(添字アクセス)
print(students['student_02']['courses'][0])
# 出力結果： Dotoku

# student_02の年齢にアクセス(setdefault関数)
print(students.setdefault('student_02', {}).setdefault('age', 'No Data'))
# 出力結果： 30

# 第一引数に辞書型、第二引数に生徒IDを受け取り、年齢から生徒か判定
def is_student(students, student_id):
    age = students.setdefault(student_id, {}).setdefault('age', 'No Data')
    if age >= 25:
        print(f'{students[student_id]["name"]}さん、、、がっ..学生じゃなかったんですか。。。？')
        return False
    return True


print(is_student(students, 'student_02'))
# 出力結果： Iidaさん、、、がっ..学生じゃなかったんですか。。。？
# 出力結果： False
```
方向ベクトルを角度に変換する

## 方向ベクトルを角度に変換する方法
方向ベクトルをそのまま角度（Quaternion）にしたい場合はこの関数が使えます。
```cs
var rotation = Quaternion.LookRotation(vector);
```
### 使い道
- ゆっくり方向転換したい（LookAt だと即方向転換してしまうのでめんどくさい）
- RaycastHit.normal を角度に治したい
## 方向ベクトル同士の角度を取得する方法
方向ベクトルの角度（度数）を取得したい場合はこの関数が使えます。
```cs
var vectorA = /* 方向ベクトル A */;
var vectorB = /* 方向ベクトル B */;
var rotation = Quaternion.Angle(
    Quaternion.LookRotation(vectorA),
    Quaternion.LookRotation(vectorB)
);
```
この青い部分の角度（度数法）が`float`で取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3091949/c88a3a37-14e9-70ca-3f72-3ba159094de4.png)
### 使い道
- カメラの角度を制限したい
- 監視カメラなどで、一定角度の中にオブジェクトがあるか確認したい
JavaScript/TypeScriptの`for`構文について

## はじめに
`for`構文は、特定の条件が満たされるまで繰り返しコードを実行するためのループ構造を提供します。ループ処理は、同じ処理を複数回行いたい場合に非常に便利です。

## 基本構文

`for`ループの基本構文は以下の通りです。

```javascript
for (初期化; 条件; 更新) {
    // 繰り返し実行するコード
}
```

- **初期化**：ループが開始される前に一度だけ実行される。ループカウンタ変数を初期化するために使用されることが多いです。
- **条件**：ループが継続する条件を指定。条件が`true`である限り、ループは繰り返し実行されます。
- **更新**：各ループの最後に実行される。通常はループカウンタ変数のインクリメントやデクリメントを行います。

### 例

```javascript
for (let i = 0; i < 5; i++) {
    console.log(i);
}
// 出力: 0, 1, 2, 3, 4
```

この例では、変数`i`を0から始め、5未満の間、ループを繰り返します。各ループごとに`i`は1ずつ増加します。

## `for...in`構文

`for...in`構文は、オブジェクトのプロパティを反復処理するために使用されます。

### 例

```javascript
const person = {
    name: "Alice",
    age: 25,
    city: "Tokyo"
};

for (let key in person) {
    console.log(key + ": " + person[key]);
}
// 出力: 
// name: Alice
// age: 25
// city: Tokyo
```

この例では、`person`オブジェクトのすべてのプロパティを繰り返し処理し、それぞれのキーと値をコンソールに出力します。

## `for...of`構文

`for...of`構文は、配列やその他の反復可能なオブジェクト（例えば、`Map`や`Set`）の要素を反復処理するために使用されます。

### 例

```javascript
const fruits = ["apple", "banana", "cherry"];

for (let fruit of fruits) {
    console.log(fruit);
}
// 出力: 
// apple
// banana
// cherry
```

この例では、`fruits`配列のすべての要素を繰り返し処理し、各要素をコンソールに出力します。

## 無限ループ

`for`構文を使用して無限ループを作成することも可能です。無限ループは通常、特定の条件が満たされるまでループを終了させない場合に使用されます。

### 例

```javascript
for (;;) {
    console.log("This will run forever");
}
```

この例は無限に実行され続けるループを作成します。条件が省略されているため、常に`true`とみなされ、ループが永遠に続きます。無限ループを使用する際には、明示的に`break`文を使ってループを終了させることが重要です。

## `break`と`continue`文

### `break`文

`break`文は、ループを即座に終了させるために使用されます。

### 例

```javascript
for (let i = 0; i < 10; i++) {
    if (i === 5) {
        break;
    }
    console.log(i);
}
// 出力: 0, 1, 2, 3, 4
```

この例では、`i`が5に達した時点でループが終了します。

### `continue`文

`continue`文は、現在のループの反復をスキップし、次の反復に進むために使用されます。

### 例

```javascript
for (let i = 0; i < 10; i++) {
    if (i % 2 === 0) {
        continue;
    }
    console.log(i);
}
// 出力: 1, 3, 5, 7, 9
```

この例では、`i`が偶数の場合に反復をスキップし、次のループに進みます。

## まとめ

`for`構文は、繰り返し処理を実行するための基本的かつ強力なツールです。基本的な`for`ループに加え、`for...in`や`for...of`構文を使うことで、さまざまなデータ構造を効率的に反復処理できます。また、`break`や`continue`文を使うことで、ループの制御を柔軟に行うことができます。
【個人開発】DjangoでつくるはじめてのWebアプリケーション

## はじめに
就職活動用のポートフォリオとしてブログアプリケーションを作ったので、その概要と開発の流れについて書きました。

## 成果物
簡単なブログ投稿サイトを作りました。
[GitHubリポジトリ](https://github.com/takuto-abc/first_app)

## 技術構成
・ログイン機能
・管理者画面
・記事の作成
・登録済みユーザーの管理
・GAEへのデプロイ
・Cloud SQL & My SQLと連携

## 作るにあたって
Udemy講師藤本拓真さんの「【Python】 Django3で「本当に使える」WEBアプリケーションを開発しよう」という講座を参考にしました。
期間にして約2週間といったところです。
Pythonについては半年ほど経験がありますがWebアプリケーションについては完全に初心者だったため、まずはDjangoを使って簡単なアプリケーションを1つ作ってみようという気持ちで始めました。
なお、今回はとりあえず動くアプリケーションをつくってみようということなので、決済機能やコメント機能、画像の挿入などは機能として盛り込みませんでした。

藤本先生の講座は以下のリンクから↓
[【Python】 Django3で「本当に使える」WEBアプリケーションを開発しよう
](https://www.udemy.com/course/reallysite/?couponCode=JPQ2CP24")

## 開発の流れ
講義に沿って開発を進めました。以下、大まかな流れとなります。

1.仮想環境に入る
                                        

2.DjangoおよびDjangoのアプリケーションをインストールする
 

3.HTMLを書き、Bootstrapでデザインを構成する
                   

4.管理者画面およびトップページを完成させる
 

5.ログイン画面を作成する
                   

6.入力されたURLのパターンに対し、必要なパスを用意する
                

7.本番環境用データベースとしてMySQLを使う


8.GAEへデプロイする


## 苦労した点
特に７番のデータベース接続と８番のデプロイで苦戦しました。
変更を加えるディレクトリの数がこのプロジェクトの中で最も多く、エラーが出た際にどのディレクトリのどの部分か特定するまでにかなりの時間を費やしました。
覚えている範囲でいくと、デプロイ時に「502 Bad Gateway」が表示され、動画を何度も遡りながらどこでズレているのか特定しようとしましたが、最終的に'DB_CONNECTION'の'I'のつけ忘れだったことは苦い思い出です（笑）

## うれしかった点
やはりデプロイして自分のドメインでアクセスできるようになった時は達成感を感じましたしうれしかったです。
同時に当たり前のように存在するwebページの多くもこういった地道な過程を経てつくられているんだなと、改めて技術の凄さに感嘆しました。

## 今後について
講師の藤本先生からポートフォリオへの使用許可をいただいたので、今回つくったwebアプリケーションをベースにフロント部分や機能面を変えながら自分オリジナルのポートフォリオにしていきたいです。なお、JavaScriptについては基礎的な学習は終えているためフロントはNext.jsを使って充実させたいと思っています。
また、webアプリケーションの仕組みについて専門書等で学習する前にとりあえずアプリをつくってみただけであるため、コードの意味や全体としてどう機能しているかわかりかねる点が多いです。そのため、今後は講義をもう一度視聴しながら気になった点やわからない点に関して都度調べながら理解を深めたいと思います。
TypeScriptのタプルについて

## はじめに
TypeScriptでは、配列の要素の型と数を厳密に定義することができる「タプル」型をサポートしています。タプルを使用することで、特定の数と順序の要素を持つ配列を定義できます。これにより、データの構造をより明確に表現し、型安全性を向上させることができます。

## タプルとは

タプルは、特定の型と順序を持つ要素の集まりです。配列とは異なり、各要素の型を個別に指定できます。

### タプルの定義

以下に、基本的なタプルの定義と使用例を示します。

```typescript
// 文字列と数値のタプルを定義
let person: [string, number];

// 値を代入
person = ["Alice", 30]; // OK

// 不正な値を代入
person = [30, "Alice"]; // エラー: 型 'number' を型 'string' に割り当てることはできません。
person = ["Alice"]; // エラー: タプル型 '[string, number]' の長さに一致しません。
```

この例では、`person` は `[string, number]` 型のタプルとして定義されています。したがって、最初の要素は文字列、2番目の要素は数値である必要があります。

## タプルの利点

タプルを使用することで、以下の利点があります。

1. **型安全性の向上**：各要素の型が厳密に定義されているため、誤った型のデータが代入されることを防げる
2. **データ構造の明確化**：データの構造が明確になるため、コードの可読性が向上する
3. **静的検査**：コンパイル時にエラーが検出されるため、バグの早期発見が可能

## タプルの応用例

### 複数の戻り値を返す関数

タプルを使用して、複数の戻り値を返す関数を定義できます。

```typescript
function getPersonInfo(): [string, number] {
    return ["Bob", 25];
}

let [name, age] = getPersonInfo();
console.log(name); // "Bob"
console.log(age);  // 25
```

### 複数の型を持つ配列

タプルを使用して、異なる型の要素を持つ配列を定義できます。

```typescript
let data: [string, number, boolean] = ["Alice", 30, true];
console.log(data); // ["Alice", 30, true]
```

### オプショナルな要素

タプルにはオプショナルな要素を含めることもできます。

```typescript
let tuple: [string, number?];
tuple = ["Hello"];  // OK
tuple = ["Hello", 42];  // OK
tuple = [42];  // エラー: 型 'number' を型 'string' に割り当てることはできません。
```

### 名前付きタプル

TypeScript 4.0からは、タプルに名前を付けることができ、可読性がさらに向上します。

```typescript
let person: [name: string, age: number] = ["Alice", 30];
let [name, age] = person;
console.log(name); // "Alice"
console.log(age);  // 30
```

## タプルと配列の違い

タプルと配列は似ていますが、いくつかの重要な違いがあります：

1. **要素の型**：配列ではすべての要素が同じ型である必要がありますが、タプルでは各要素の型を個別に指定できる
2. **要素の数**：配列の要素数は固定されていませんが、タプルの要素数は固定されている
3. **アクセスの安全性**：タプルでは要素の型が保証されるため、安全にアクセスできる

## まとめ

TypeScriptのタプルは、特定の型と順序を持つ要素の集まりを定義するための強力なツールです。タプルを使用することで、データの構造を明確に表現し、型安全性を向上させることができます。複数の戻り値を返す関数や異なる型の要素を持つ配列など、さまざまな場面でタプルを活用することができます。
TypeScriptのリテラル型を使った型安全なコード

## はじめに
リテラル型とは、特定の値を型として扱うことができる型のことです。JavaScriptの基本データ型（例えば、文字列や数値）をそのまま型として使用できるのがリテラル型です。リテラル型を使うことで、特定の値のみを許容する変数や関数の引数を定義することができます。本記事では、リテラル型について詳しく解説し、具体的な使用例を紹介します。

## リテラル型の基本

リテラル型は、特定の値のみを許容する型です。以下に、リテラル型の基本的な例を示します。

### 文字列リテラル型

文字列リテラル型は、特定の文字列のみを許容する型です。

```typescript
let direction: "Up" | "Down" | "Left" | "Right";

direction = "Up"; // OK
direction = "Down"; // OK
direction = "North"; // エラー: 型 '"North"' を型 '"Up" | "Down" | "Left" | "Right"' に割り当てることはできません。
```

### 数値リテラル型

数値リテラル型は、特定の数値のみを許容する型です。

```typescript
let one: 1;
one = 1; // OK
one = 2; // エラー: 型 '2' を型 '1' に割り当てることはできません。
```

### ブールリテラル型

ブールリテラル型は、`true` または `false` のみを許容する型です。

```typescript
let isTrue: true;
isTrue = true; // OK
isTrue = false; // エラー: 型 'false' を型 'true' に割り当てることはできません。
```

## リテラル型の用途

リテラル型は、特定の値のみを許容することで、コードの安全性と可読性を向上させるために使用されます。具体的には、以下のような用途があります。

### 定数オブジェクトの定義

リテラル型を使用して、定数オブジェクトを定義することができます。これにより、オブジェクトのプロパティが特定の値を持つことを保証できます。

```typescript
const Suit = {
    Club: "Club",
    Diamond: "Diamond",
    Heart: "Heart",
    Spade: "Spade",
} as const;

type Suit = typeof Suit[keyof typeof Suit];
```

ここで `Suit` は `"Club" | "Diamond" | "Heart" | "Spade"` というリテラル型のユニオンを持ちます。

### 関数の引数にリテラル型を使用

関数の引数としてリテラル型を使用することで、特定の値のみを許容する関数を定義できます。

```typescript
function move(direction: "Up" | "Down" | "Left" | "Right") {
    // 関数の実装
}

move("Up"); // OK
move("Down"); // OK
move("North"); // エラー: 型 '"North"' を型 '"Up" | "Down" | "Left" | "Right"' に割り当てることはできません。
```

### リテラル型の型推論

TypeScriptは、リテラル型を使って型推論を行うことができます。`as const` を使用すると、オブジェクトのプロパティがリテラル型として推論されます。

```typescript
const suit = {
    Club: "Club",
    Diamond: "Diamond",
    Heart: "Heart",
    Spade: "Spade",
} as const;

type Suit = typeof suit[keyof typeof suit];
// Suitは "Club" | "Diamond" | "Heart" | "Spade" 型
```

この例では、`suit` オブジェクトの各プロパティがリテラル型として推論され、`Suit` 型は `"Club" | "Diamond" | "Heart" | "Spade"` となります。

## まとめ

リテラル型は、特定の値のみを許容する型であり、コードの安全性と可読性を向上させるために非常に有用です。TypeScriptでは、文字列、数値、ブール値などをリテラル型として扱うことができ、これを活用することで型安全なコードを記述することができます。
【 Python 】関数処理

## ■　はじめに
Python勉強につき、メモを残します。
下記内容は、備忘録レベルで書いてますので間違い等あるかもしれません。
参考にする際にはその点ご認識のほどお願いします〜。。

## ■ 関数
・引数なし関数(戻り値なし)
・引数あり関数(戻り値なし)
・引数あり関数(戻り値あり)

```python:関数処理
# 引数なし関数(戻り値なし)
def message_print():
    print('処理が完了しました。')

# 引数あり関数(戻り値なし)
def arg_message_print(arg):
    print(f'{arg}が完了しました。')

# 引数あり関数(戻り値あり)
TAX = 1.1
def get_tax_calculation(price):
    return int(price * TAX)

 
message_print() #1
print(message_print()) #2
#1 処理が完了しました。(関数呼び出し結果)
#2 処理が完了しました。(関数呼び出し結果)
#2 None(戻り値なしの場合、Noneが返却される)

arg_message_print('評価計算処理') #3 
print(arg_message_print('評価計算処理')) #4
#3 評価計算処理が完了しました。(関数呼び出し結果)
#4 評価計算処理が完了しました。(関数呼び出し結果)
#4 None(戻り値なしの場合、Noneが返却される)

get_tax_calculation(1000) #5
print(get_tax_calculation(1000)) #6
#5 関数呼び出しのみ行なっているためコンソールへの表示はない
#6 1100(戻り値をprint関数で表示)

```
Dockerの基本概念

## 概要
ここでは、Dockerの以下の概念についての関係性についてを明確にする。

- `Dockerfile`
- `Docker Image`
- `Docker Container`
- `Volume`
- `Network`

## Dockerとは？

そもそもDockerとはなんなのだろうか。

Dockerは、コンテナ（`Docker Container`）という隔離（`isolated environment`）された環境でアプリケーションのパッケージ化と実行をする機能を提供する。

Dockerは、インフラとアプリケーションを切り離す。

:::note
インフラとは、サーバーやネットワークなどの計算資源の基盤となるもの。
:::

- Dockerについてのメモ
    - アプリケーションをパッケージ化し、実行する機能を持つ
    - アプリケーションを管理するのと同じ方法でインフラを管理することができる
    - ソフトウェアを短時間で提供できる
    - Dockerはコンテナのライフサイクルを管理するツールとプラットフォームを提供する

### なぜ、Dockerを利用するのか？

Dockerの使用目的は、主に以下の三つが考えられる。

**環境統一**

Gitなどのバージョン管理ツールでDockerの設定ファイルごと管理しておくことで、開発環境や本番環境を統一することができる。
例えば、開発環境をコンテナ上で構築した場合には、ホスト上にJDKのインストールが不要になる。

このバージョンが変わった場合にも、masterで変更すれば、開発者がホスト上で何かしらの設定をする必要はない。

**依存関係の管理**

使用するライブラリやパッケージなどを`Dockerfile`で管理することができる。

**隔離**

Dockerコンテナ上はホスト上の他のプロセスから完全に隔離された環境となる。
そのため、ホスト上で実行中のプロセスからの影響を受けない。加えて、ライブラリやパッケージなどのインストールの制約を受けない。

### Dockerの基盤技術

Dockerは以下のLinuxカーネルの機能により構成される。

- `namespace`
    - 実行中のプロセスに対する隔離（isolate）を提供し、システムリソースに対するアクセスを制限する。
- `cgroup`
    - システムリソースをグループごとに管理する

## Dockerの重要概念について

詳細は、[こちら](https://docs.docker.jp/get-started/overview.html#docker-architecture)を参照。

**Dockerのアーキテクチャ**
![スクリーンショット 2023-12-18 19.53.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3791376/32186ebd-a1e2-64f7-e7b7-df7c0938c9aa.png)

以下では、Dockerオブジェクトについての詳細を記載する。

### Docker Image

Dockerコンテナを作成する命令が入った読み込み専用のテンプレートのこと。
レジストリに公開されたイメージもしくは、カスタムのイメージからコンテナを作成することができる。

`image`を作成する場合には、`Dockerfile`というファイルを生成する必要がある。
`Dockerfile`は、イメージを生成してから作成するまでの手順を定義する。

### Docker Container

`image`が実行状態となったインスタンスのこと。
ホストOSマシン上にある他すべてのプロセスから隔離されている。

例えば、ホストOSや異なるコンテナのプロセスはコンテナ上で実行されているプロセスを認識できない。

:::note
Linuxの`namespace`や`cgroup`によリ実現している。
:::

Docker APIやCLIを使用し、コンテナの作成・開始・停止等をすることができる。（`docker run`など）

**ファイルシステム**

コンテナでは、隔離された特別なファイルシステムを使用する。

> イメージにはコンテナのファイルシステムが含まれており、アプリケーションの実行に必要な全てを含む必要があります。
> 

**Network**

コンテナ同士は隔離されているが、コンテナに`Network`の設定をすると、コンテナ間での通信が可能となる。

**Volume**

ホストOSの`Volume`をコンテナ内のファイルシステムにマウントすることができる。
この領域は、ホストOSとコンテナとの間で共有され、もしコンテナを停止した場合にもデータは削除されない。

## 参考文献

- https://docs.docker.jp/get-started/overview.html
コンテナの構築の流れ

## 概要
ここでは、コンテナ構築の流れを示す。

アプリのコンテナを作成するためには、イメージ名を指定して、`Docker CLI`からコンテナを起動する必要がある。

1. `Dockerfile`を作成する
2. Dockerイメージを構築する
3. Dockerコンテナを起動する

## Dockerコンテナの構築

**`Dockerfile`の作成**

まずは、イメージを構築するための`Dockerfile`を作成する。
プロジェクトのルートディレクトリに移動し、`Dockerfile`を用意する。

```bash
# プロジェクトのルートディレクトリに移動する。
cd project-root

# Dockerfileを作成する。
touch Dockerfile
```

`Dockerfile`に以下の内容を追加する。

```docker
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
```

**Dockerイメージの構築**

**`docker build`** コマンドで`Dockerfile`を使用し、新たなイメージを構築する。

```bash
$ docker build -t getting-started .
```

<details><summary>コマンド詳細</summary>

- `-t`フラグ
    - イメージにタグを付与する。  
- `.`
    - カレントディレクトリから`Dockerfile`を探すように指示する。
</details>

**コンテナの起動**

先ほど作成したイメージ名を指定し、`docker run`コマンドでコンテナを起動する。

```bash
$ docker run -dp 127.0.0.1:3000:3000 getting-started
```

<details><summary>コマンド詳細</summary>

- `-p`フラグについて
    - ホストとコンテナ間でポートの関連付けを作成する。
    - `HOST:CONTAINER`と記載する。
    - `127.0.0.1:3000:3000`では、コンテナのポート3000をlocalhostの3000に公開する。
</details>

## `Dockerfile`について

[Dockerfile リファレンス — Docker-docs-ja 24.0 ドキュメント](https://docs.docker.jp/engine/reference/builder.html)

Dockerは、`Dockerfile`から自動的に命令を読み上げ、イメージを生成する。
`docker build`コマンドを実行すると、順次コマンドライン命令を自動化した処理を行い、ビルド結果となるイメージが得られる。

`docker build`コマンドは、`Dockerfile`と`コンテキスト`によって、イメージを構築する。

ここでの`コンテキスト`とは、`Docker CLI`で指定した`PATH`または`URL`にあるファイルの一式のこと。

```docker
# 以下の場合、"."（カレントディレクトリ）を構築コンテキストとして利用する。
$ docker build .
```

### `dockerd`による、イメージ構築の流れ

1. コンテキストの全体を`dockerd`（Dockerデーモン）に送信する
コンテキスト・ディレクトリに`.dockerignore`ファイルを用意することで、不要なファイルやディレクトリを除外することができる。
1. `Dockerfile`内に書かれている命令を実行する前に、事前に`Dockerfile`を検証する。
構文が間違っている場合には、エラーを返す。
1. `Dockerfile`内の命令を実行する。
1行ずつ命令を実行し、必要な場合にはビルドイメージ内にその処理結果をコミットし、最後に新しいイメージのIDを出力する。
`dockerd`は、送信されたコンテキストの内容は自動的に除去する。

:::note
イメージの構築は Docker デーモンが実行する。
:::
    

**ポイント**

- `Dockerfile`内の各命令は、個別に実行される
前の行でディレクトリの移動をしたとしても、次の行ではその影響を受けない。   
- Dockerは可能な限り構築キャッシュを利用する
構築キャッシュとは、デフォルトでは、構築するマシン上で以前に構築された結果に基づく
    

### `Dockerfile`の書式

```docker
# コメント
命令 引数
```

命令は、慣例的に大文字を用いる。（引数との区別のため）

Dockerは、`Dockerfile`内の命令を記述順に実行する。ただし、1行目は`FROM`から始めなくてはならない。

`FROM`命令の引数は、構築時の元となる親イメージを指定する。

```docker
# nodeを親イメージとして指定する。
FROM node:18-alpine
```

## `Docker CLI`について

[Docker CLI (docker) — Docker-docs-ja 24.0 ドキュメント](https://docs.docker.jp/engine/reference/commandline/toc.html)
『JavaScript』プロパティ参照とオフセット計算について

## はじめに
JavaScriptのオブジェクトのプロパティにアクセスする際、内部的には「プロパティのオフセット計算」が行われています。この計算により、オブジェクトの特定のプロパティがメモリ内のどこに位置しているかを特定し、効率的なアクセスが可能になります。また、プロパティ参照にはオーバーヘッドが伴うことがあります。

## プロパティのオフセット計算の概要

プロパティのオフセット計算とは、オブジェクトの特定のプロパティがオブジェクトの開始位置（ベースアドレス）からどれだけ離れているかを計算するプロセスです。この計算は、以下のステップで行われます：

1. **オブジェクトのベースアドレスを取得**：オブジェクトがメモリ上のどこに格納されているかを示すベースアドレスを取得する
2. **プロパティのオフセットを計算**：アクセスするプロパティがオブジェクトの開始位置からどのくらいの距離にあるかを計算する
3. **プロパティの値を取得**：計算されたオフセットをベースアドレスに加算して、プロパティの値をメモリから取得する

## 実例での説明

以下のようなオブジェクトがあるとします。

```javascript
const obj = {
    a: 10,
    b: 20,
    c: 30
};
```

ここで、プロパティ `b` にアクセスする場合を考えます。

### オフセットの計算

オフセットは、メモリレイアウトに依存しますが、簡単な例として以下のように考えます。

- `obj` のベースアドレスが `0x1000` と仮定する
- 各プロパティが4バイト（32ビット）と仮定すると、プロパティ `a` はベースアドレス `0x1000` に、プロパティ `b` は `0x1004` に、プロパティ `c` は `0x1008` に格納される

この場合、プロパティ `b` のオフセットは `4バイト` です。

### プロパティへのアクセス手順

1. オブジェクト `obj` のベースアドレス `0x1000` を取得する
2. プロパティ `b` のオフセット `4バイト` を計算する
3. `0x1004` のメモリアドレスから値 `20` を取得する

これにより、JavaScriptエンジンは `obj.b` の値に効率的にアクセスできます。

### 実際のコード

JavaScriptでは、ユーザーがオフセットを直接操作することはありませんが、内部的にはこのような手順が行われています。

```javascript
const obj = {
    a: 10,
    b: 20,
    c: 30
};

console.log(obj.b); // 20
```

上記のコードでは、`obj.b` にアクセスする際に、JavaScriptエンジンがプロパティ `b` のオフセットを計算し、その位置から値を取得します。

## プロパティ参照のオーバーヘッド

プロパティ参照のオーバーヘッドとは、プログラムが変数やプロパティの値を取得する際に発生する追加の計算コストや時間のことを指します。特に、動的なメモリアクセスやオブジェクトのプロパティ参照などが関わる場合に、これが顕著になることがあります。

### メモリアクセスのコスト

変数の参照には、以下のようなさまざまなステップが含まれる場合があります。

1. **メモリアドレスの計算**：変数がどのメモリアドレスに格納されているかを計算する必要がある
2. **メモリの読み取り**：メモリから実際の値を読み取る
3. **キャッシュのミス**：特定のメモリアドレスがCPUキャッシュにない場合、メインメモリからデータを読み込む必要があり、これには追加の時間がかかる

### オブジェクトのプロパティ参照

オブジェクトのプロパティを参照する場合、追加のオーバーヘッドが発生することがあります。

```javascript
let obj = {
    value: 42
};

console.log(obj.value);
```

ここでは、`obj.value` の参照が発生します。この場合、以下のステップが関わります。

1. **オブジェクトのベースアドレス取得**：`obj` のメモリアドレスを取得する
2. **プロパティオフセットの計算**：`value` プロパティのオフセットを計算する
3. **値の読み取り**：`value` の実際の値を読み取る

これにより、単純な変数参照よりも多くのステップが必要となります。

## インライン展開とオフセット計算の関係

インライン展開（inline expansion）は、変数参照や関数呼び出しが直接コード内に埋め込まれる最適化手法です。これにより、プロパティ参照のオーバーヘッドを削減し、実行時のパフォーマンスを向上させることができます。

### インライン展開の例

```typescript
const enum Direction {
    Up,
    Down,
    Left,
    Right
}

let direction = Direction.Up;
console.log(direction); // 0
```

このコードは以下のようにコンパイルされます：

```javascript
let direction = 0 /* Direction.Up */;
console.log(direction); // 0
```

`Direction.Up` の参照が `0` にインライン展開され、実行時にオブジェクト `Direction` を参照する必要がなくなります。これにより、参照のオーバーヘッドが削減されます。

## まとめ

プロパティのオフセット計算は、JavaScriptエンジンがオブジェクトのプロパティに効率的にアクセスするための重要なステップです。また、プロパティ参照にはオーバーヘッドが伴うことがありますが、インライン展開を使用するとこれらの参照がコンパイル時に直接コードに埋め込まれ、実行時のパフォーマンスが向上します。ユーザーが直接この計算を行うことはありませんが、内部でのこの処理があるため、プロパティアクセスが実現されています。
【 Python 】データ型

## ■　はじめに
Python勉強につき、メモを残します。
下記内容は、備忘録レベルで書いてますので間違い等あるかもしれません。
参考にする際にはその点ご認識のほどお願いします〜。。

## ■ 型
・文字列
・整数
・浮動小数点数
・真偽値

```python:データ型
# 文字列(シングル, ダブルクォーテーションどちらでも可能)
char = 'sample'

# 整数(桁数制限なし)
number = 12345678901234567890

# 浮動小数点数(64bit(15~17桁)まで代入可能)
formatted_number = 1.2345678901234567890

# 真偽値(True, False)
boolean = True
 
# 表示結果
print(char)
# sample

print(number)
# 12345678901234567890

print(formatted_number)
# 1.2345678901234567

print(boolean)
# True

```


## ■ 参照

https://www.youtube.com/watch?v=hv0w4ZCT-uQ&t=5769s
【Phalcon】期待したクエリが生成されないことがある【v4,v5】

# 概要
担当プロジェクトでPhalconのアップデートを行なっており、その際に発生した不具合の備忘録です。
issueを見つけるのに時間がかかったので、同じ現象に遭遇した方の助けになれば幸いです。
Phalconにはphqlという独自のsqlのようなものがあり、ベタ書きしたのをPhalconが用意しているparser内で変換しクエリ実行している箇所で、そんなカラムないよ！と怒られるエラーが発生していました。
parserにカラム名先頭で「not」が来ると削除されてしまうバグがあり、そのためエラーが発生していたようです。

例えば元のSQLが以下だったとします。（Modelにnoteがある前提）
```
Select m.note From Model m.
```
これをcreateQuery()やexecuteQuery()でparseしてしまうと...
```
Select m.e Form Model m.
```

当然「Column not found」でエラーになります。
2019年からあるバグのようで、未だに修正されていないようです😭
対象バージョンは4.0.0〜

Githubのissueは↓
issue：https://github.com/phalcon/cphalcon/issues/14641

# 解消するには？
カラム名を[]で囲ってあげればOK。
```
Select m.[note] Form Model m.
```
これで解消できます。
もしくはparser周りを修正してあげれば解決できるかもしれません
【Flutter】ボタンの連打を無効にする対応メモ。onPressedの処理中は押せないボタンを作成する方法

## この記事でやりたいこと・紹介すること

:::note info
ボタンを押した後の処理を実行中は、ボタンを押せないようにするボタンを作成して、ユーザーが連打や実行中に比較的短い時間内でボタンを再度タップする動作等をしても二重で処理が発生しないようにする
:::

## 実施した概要
ボタンクラスのラッパークラスを作成して、処理中はボタンの"onPressed"パラメータにNullを渡すことでタップ動作を無効にする。

:::note info
上記の実装をすることで、容易に連打防止対応をしたボタンをコード全体で簡単に何度も使用することができます。
:::

## 実際の方法とソースコード

実際の導入方法を紹介します。

### ボタンクラスのラッパークラスを作成

ボタンクラスのラッパークラスである`WaitableElevatedButton`クラスと`WaitableOutlinedButton`クラスを作成

以下のファイルを任意の場所に作成します。

:::note info
私は、基本的にUtilディレクトリ等を作成して、その配下に以下の`waitable_button.dart`クラスを作成します。
:::

```dart:waitable_button.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class WaitableElevatedButton extends StatefulWidget {

  WaitableElevatedButton({
    required this.onPressed,
    required this.child,
    this.style,
    super.key,
  });
  @override
  createState() => _WaitableElevatedButtonState();

  final AsyncCallback? onPressed;
  final ButtonStyle? style;
  final Widget child;
}

class _WaitableElevatedButtonState extends State<WaitableElevatedButton> {
  bool _waiting = false;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: widget.style,
      onPressed: widget.onPressed == null || _waiting
          ? null
          : () async {
        setState(() => _waiting = true);
        await widget.onPressed!();
        setState(() => _waiting = false);
      },
      child: widget.child,
    );
  }
}

class WaitableOutlinedButton extends StatefulWidget {

  WaitableOutlinedButton({
    required this.onPressed,
    required this.child,
    this.style,
    super.key,
  });
  @override
  createState() => _WaitableOutlinedButtonState();

  final AsyncCallback? onPressed;
  final ButtonStyle? style;
  final Widget child;
}

class _WaitableOutlinedButtonState extends State<WaitableOutlinedButton> {
  bool _waiting = false;

  @override
  Widget build(BuildContext context) {
    return OutlinedButton(
      style: widget.style,
      onPressed: widget.onPressed == null || _waiting
          ? null
          : () async {
        setState(() => _waiting = true);
        await widget.onPressed!();
        setState(() => _waiting = false);
      },
      child: widget.child,
    );
  }
}

```

### コード内での利用方法

後は上記の`WaitableElevatedButton`クラスと`WaitableOutlinedButton`クラスを通常の`ElevatedButton`のように記述することで連打防止ボタンが実装できます。

```dart:変更例.dart
- child: ElevatedButton(  //元のクラス
+ child: WaitableElevatedButton(  //新しいクラス
```

```dart:使用例.dart
ElevatedButton(
  child: const Text('Button'),
  style: ElevatedButton.styleFrom(
    primary: Colors.yellow,
    onPrimary: Colors.black,
    shape: BeveledRectangleBorder(
      borderRadius: BorderRadius.circular(10),
    ),
  ),
  onPressed: () async {
    // 何らかの処理。(下記は単純に１０ミリ秒Delayをさせているだけ)
    await Future.delayed(Duration(milliseconds: 10));
  },
),
```

## 参考記事

https://zenn.dev/ttskch/articles/5acf1e420cc28f
【Rails】Boolean 型を入力必須にする

## 概要

`Rails` で `Boolean` 型の値を入力必須にしたいときに `presence: true` を使っても期待通りに動作しませんでした。この記事ではその原因と対処法について説明します。

## 原因

```rb
validates :column, presence: true
```

このように記述すると `false` を選択した場合には値が入力されていないと認識されてしまい、バリデーションエラーが発生します。`presence: true` は `false` を無視してしまうため、`Boolean` 型の値には適していません。

## 対処法

```rb
validates :column, inclusion: { in: [true, false] }
```

`inclusion` バリデーションを使って `true` か `false` のどちらかの値が含まれているかを確認します。これにより `false` も有効な値として認識されるため、正しくバリデーションが行われます。

## まとめ

`Boolean` 型の値を入力必須にしたい場合には `presence: true`ではなく、`inclusion: { in: [true, false] }` を使います。これにより `false` も有効な値としてバリデーションを通過することができます。
「SAML認証でSSOする」とは

# SSO(シングルサインオン)とは
1回ログインすれば、他のシステムでもログインできる仕組み。
色々実現の方法があり、SAML認証はその実現方法の1つ。

# SAML認証とは
最初に具体例から説明すると、FigmaにGoogle認証でログインするような外部サービスでの認証のこと。

次の登場人物がいて、
- SP（Service Provider）
    - ログインしたい先（例だとFigma）
- IdP（ID Provider）
    - 代わりに認証するサービス（例だとGoogle）
認証用サービスであるIdPで認証できたら、その認証情報を使いたいSPに認証情報を渡すってだけのこと。

SAML(Security Assertion Markup Language)という言葉がやたら難しいけど、
認証情報を渡すときの形式がXML形式で決まっていて、
その形式に則って情報を渡せば、受け取った側も解釈できるよっていう書き方のルールってだけの意味。

# 「SAML認証でSSOする」とは
「外部サービスでの認証の仕組み使って、SSO（シングルサインオン）やったるでー」
ってだけのこと




# 補足
1回わかると大して難しくないのに、久々に聞くとめっちゃ忘れてて、難しそうに聞こえるから備忘録として残した

SSOするためにSAML以外の方法もあるみたいだけど、
https://www.intra-mart.jp/im-press/useful/security_assertion_markup_language
システム開発するにあたって、SSOするってなったら、「認証用にいつもみんなが使ってる別システムでの認証するSAML認証だよね」か、「アイパス使ったIdPへのログインするフォーム認証」で片付くケースが圧倒的そう。

概要理解はそんな難しくないけど、実装も難しくないとは言ってない笑



# 参考資料
https://www.youtube.com/watch?v=oTR0eWFtrqg&t=182s
https://www.hitachi-solutions.co.jp/iam/saml.html
「Terminalが予期しない理由で終了しました」から再度開くことができなくなってしまった

## 背景
急にCLI（Macのターミナル）が落ちてしまって、再度開くことができなくなってしまった。
また、Macを再起動してもダメだった。

## OS

Chip: Apple M1
OS: macOS Sonoma Verstion 14.5

## ライブラリから問題となるファイルの退避・削除することで解決できた

ホームフォルダ（Finder）のLibraryにある下記フォルダ内（/Users/ユーザー名 ）の関係ありそうなものを退避もしくは削除することによって解決（実際、ここまで辿り着くのに結構詰まりました）

![Screenshot 2024-05-18 at 17.50.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256394/e3537494-e74c-a479-092b-951962de1613.png)

Libraryは隠しファイルになっている。
MacのFinderで隠しファイル を表示するためのショートカットは、
`command + shift + .`
これで画像のようにLibraryが表示されるはず。

問題となっている可能性のファイルを退避・削除するわけだが、私の場合は、
/Users/ユーザ名/Library/Saved Application State/

の中に含まれている

com.apple.Terminal.savedState

というファイルが悪さをしていたっぽい。
このフォルダの中にあるファイルを全て削除し、ターミナルを起動してみると、問題なくターミナルが起動した。

なにが原因で急にターミナルが落ちたのかはわかってない！

## お疲れ様でした。
わからないところ、間違っているところ、もっといい方法がある場合は、コメントでもDMでも教えてください。
[Video] 動画で学ぶアクセシビリティ

# はじめに
私は、社会課題や社会貢献に挑んでいる動画を見るのが好きでよく見ています。
特に技術で解決しようとしているものを見ると、働いている意義を思い出せて好きです。(使っている技術などは違うことがほとんどですが、考え方として)

本記事投稿キャンペーンをきっかけに動画を検索していると、アクセシビリティに関して、マイクロソフトが頭一つ抜けていると感じました。
[ミッション](https://www.microsoft.com/ja-jp/mscorp/college/msd-company-mv)が口だけではない強い組織だなぁと思いました。
```
地球上のすべての個人とすべての組織が、より多くのことを達成できるようにする
```

`アクセシビリティの知見を発信しよう！`を機にアクセシビリティ系のショート動画いくつか見つけたので、紹介します。
他にもたくさんあるので、興味がわいたら検索してみることをお勧めします。

# 動画紹介
以下にいくつか動画を紹介します。
## アクセシビリティとは
デジタル庁の動画です。「アクセシビリティとは」から入って、分かり易かったです。
実際の取り組み、何に困るのか、どうすればどう助かるのかが説明されています。

https://www.youtube.com/watch?v=KNsjNU8OTKg

ウェブアクセシビリティ導入ガイドブックもありました。デジタル庁の印象変わりました。

https://www.digital.go.jp/resources/introduction-to-web-accessibility-guidebook

## Satya Nadella CEOの Keynote
動画内の Video で AI がどんな貢献をしているのか。その方々の感動してる顔、笑顔が印象的です。

https://www.youtube.com/watch?v=z3SP6X1_wuc

## Microsoft 社自体の働きやすさ
まずは自社の社員を大切にしていることが分かる。
多くの企業にこの考え方をまねてほしい...

https://www.youtube.com/watch?v=TpjlGp4r-LY

※動画内で campus という単語が出てきて何かと思ったが、コーポレートキャンパスという存在らしい。大規模過ぎて正直意味が分からない。

https://www.workersresort.com/articles/corporate-campus1/

## 日本マイクロソフトの取り組み
日本語。Microsoft 製品のアクセシビリティ機能の使い方がよくわかる。
OS や Office などのアクセシビリティについての説明がある。

https://www.youtube.com/watch?v=aCf5EAb4MPg

## 一目でわかるアクセシビリティ動画シリーズ
他にも勉強になりそうな動画シリーズ
>マイクロソフト 一目でわかるアクセシビリティ は、障碍のある方のためにテクノロジを活用したデジタル体験のヒントや、インクルーシブ（包括的）なデジタル体験に関して、多くの人が理解を深めるための様々な情報を短いビデオでまとめた動画シリーズ

https://www.youtube.com/playlist?list=PL1RqQ3kddIpa1ajLVJBYL_UMjfyLThcOm


# おわりに
技術発表動画も好きですが、やはりそれを使ってどう貢献してるのか。
そこを見ることができる動画が好きです。感動します。

この度は、アクセシビリティについて勉強になりました。
良い記事投稿キャンペーンでした。素敵な機会をありがとうございました。
RasPI + Processingで構築する展示環境

## 作品展示のための環境構築
メディアアートやインタラクティブな作品を展示会場で展示をする場合、面倒なのが朝の起動と夜のシャットダウンです。作者が会場に滞在できる場合は自分でできますが、他の人にお願いするのもアレなので自動化するのが確実です。
## 環境
Raspberry PiにUbuntuをインストールしてProcessingをインストールします。Export as Applicationで単独で動くアプリとして書き出しておきます。このアプリをRasPiの起動時に起動して一定時間経過後にshutdownするようにします。
起動は物理的なタイマーを使用します。例えば（https://www.monotaro.com/g/06053445/）
こんなタイマーでセットした時間に電源が入るようにします。

書き出したアプリは以下の場所にあるとします。
```
/home/USER/Document/Processing/displayProgram/linux-aarch64/displayProgram
```

起動から決められた時間後にshutdownするようにセットしアプリを起動するためのスクリプトを作成します。
~/にautoStart.shを作成します。
```terminal
$ cd ~/
$ vi autoStart.sh
```
autoStart.shの中身は次のとおりです。
```shell:autoStart.sh
#!/bin/sh
shutdown -h 720
/home/USER/Document/Processing/displayProgram/linux-aarch64/displayProgram
```
これで720分後（12時間 x 60分＝720分）後にshutdownするようにセットします。そしてProcessingで書き出したアプリを起動します。タイマーで朝8時に起動すると午後8時にshutdownされます。
権限を変更して実行権限を追加しておきます。
```terminal
$ chmod 755 autoStart.sh
```
このシェルスクリプトを実行して起動するか確認してみます。
```terminal
$ ./autoStart.sh
```
起動が確認できたら.bashrcを編集してこのスクリプトを追加します。
```terminal
$ vi .bashrc
```
最後に以下の一行を追加します。
```bash:.bashrc
/home/USER/autoStart.sh
```
これでターミナルを起動するとautoStart.shが動きます。
次にUbuntuが起動した時にターミナルが起動するようにします。
```bash
$ vi .config/autostart/gnome_terminal.desktop
```
でファイルを作成して以下の内容を入れます。
```
[Desktop Entry]
Exec=gnome_terminal
Type=Application
```
以上で完了です。
RasPIを起動しUbuntuが起動した後にterminalが開きautoStart.shが実行されます。
指定された時間が経つとshutdownです。

ただ一つ問題、Processingのアプリで
```java:Processing
setup(){
    fullScreen(P2D);
    noCursor();
    ...
}
```
としてマウスカーソルを非表示にしている場合でもマウスカーソル起動から全く動いてないとカーソルが表示されたままになってしまいます。マウスをterminalから動かす方法もあるようですがUbuntuの新しいバージョンでは対応してないらしいです。そこで「マウスジグラー」とか「マウスムーバー」とか呼ばれるものを使います。USBに差してマウスの振りをしてカーソルを動かすものらしいです。
例えばこんな商品があります。https://amzn.asia/d/0Bq5BHs

以上でした。
[UE5]ノードと関数とマクロの違い

## はじめに

UnrealEngineのBPの記述を整理する方法として、下記図のようにノードと関数とマクロが備わっています。

![スクリーンショット 2024-05-18 16.27.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555157/827699ea-f21b-edf8-ed85-439be70b7553.png)


ではそれぞれなにが違うのでしょうか。

その違いについて調べてみたのでこの記事でまとめてみたいと思います。


## 公式による説明

#### ノードとは

```:公式の説明
ノード は、イベント、関数呼び出し、フロー制御、変数等のオブジェクトです。 これらは、オブジェクトを含んだ特定のグラフやブループリントの機能性を定義するために グラフで使用します。
```

公式のURL:https://dev.epicgames.com/documentation/ja-jp/unreal-engine/nodes-in-unreal-engine

#### 関数とは

```:公式の説明
関数 は、ブループリントで他のグラフから実行または呼び出しができる 特定の ブループリント に属しているノードグラフです。関数には、ノードによって指定され、単一の実行出力ピンを含む関数名がつけられた エントリーポイントがあります。関数が別のグラフから呼び出されると、出力実行ピンが有効になり、 接続されたネットワークが実行されます。
```

公式のURL:https://dev.epicgames.com/documentation/ja-jp/unreal-engine/functions-in-unreal-engine


#### マクロとは

```:公式の説明
ブループリントマクロ または マクロ は、本質的にノードの折り畳まれたグラフと同一です。トンネルノードで指定される エントリーポイントと出口点があります。それぞれのトンネルは、別のブループリントやグラフに使用されるとマクロノード上で可視化できる 実行またはデータピンがいくつもあります。
```

公式のURL:https://dev.epicgames.com/documentation/ja-jp/unreal-engine/macros-in-unreal-engine



## 意訳（筆者の解釈に準拠）

これらの公式を見て筆者なりに説明してみると以下のようになります。

- **ノード**は親BPに１処理として表示されるすべての機能の総称。
関数もマクロもノードの一種になる。
ノードを折りたたむというのは複数のノードを一個にまとめたように見せるということで、多くの処理でごちゃごちゃしてしまった親BPを見やすくすることができる。


<div></div>

- **関数**は簡単な処理をまとめた機能の総称。
同じ処理がBP内で存在する時共通化することで保守の工数を減らすことができる。

<div></div>

- **マクロ**は難しい処理をまとめて１処理にした機能の総称。
関数ではできないけどノードではできることを共通化するのに使用。
ノードとの違いは複数箇所で使用するかどうか。

## 使用例

#### ノード

（関数とマクロ以外の場所で使う処理全てになるので、例は特にありません。）

#### 関数

  - 与えられた引数を2を足して3倍する
  - ３倍したものから４引いて５をかけた値が１０より大きいかどうかの値を返す

※主に数値を特定のロジックで整形する処理の共通化で使用します。

#### マクロ

  - Loop処理
  - Do Once処理

※主にイベント管理を必要とする処理の共通化で使用します。

## まとめ

- ノードも関数もマクロも何かの処理を指す

<div></div>

- 関数もマクロもノードの一種といえる

<div></div>

- 関数は簡単な処理をまとめたもので、マクロは難しい処理をまとめたもの


## おわりに（余談）

筆者はこれまでいろんな場所でノードという言葉は聞いてきたのですが、処理の塊のことというのは知らず、ぼんやり処理の変わり目（分岐の条件句）だと思っていたので、その誤解を晴らすことができてよかったです。

このようにこの記事でみなさんの曖昧だった部分を少しでも明らかにできていれば幸いです。
Spring FrameworkとSpring BootのEOLとCompatibilityについての備忘録

Spring FrameworkとSpring BootのEOLとCompatibilityについて備忘録も兼ねてまとめています。

# Spring Framework
|Branch|Initial Release|End of Support|End Commercial Support|JDK|Java/Jakarta EE|
|:-|:-|:-|:-|:-|:-|
|6.2.x|2024-11-14|2025-11-14|2027-03-14|17-25(expected)|Jakarta EE 9-11|
|6.1.x|2023-11-16|2025-08-31|2026-12-31|17-23|Jakarta EE 9-10|
|6.0.x|2022-11-16|2024-08-31|2025-12-31|17-21|Jakarta EE 9-10|
|5.3.x(LTS)|2020-10-27|2024-08-31|2026-12-31|8-21(as of 5.3.26)|Java EE 7-8|

https://spring.io/projects/spring-framework#support

https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions

https://endoflife.date/spring-framework

# Spring Boot
|Branch(Latest)|Initial Release|End of Support|End Commercial Support|Java|Spring Framework|
|:-|:-|:-|:-|:-|:-|
|[3.3.x(RC1)](https://docs.spring.io/spring-boot/3.3/system-requirements.html)|2024-05-23|2025-05-23|2026-08-23|17-22|6.1.6以降|
|[3.2.x(5)](https://docs.spring.io/spring-boot/docs/3.2.5/reference/html/getting-started.html)|2023-11-23|2024-11-23|2026-02-23|17-22|6.1.6以降|
|[3.1.x(11)](https://docs.spring.io/spring-boot/docs/3.1.11/reference/html/getting-started.html)|2023-05-18|2024-05-18|2025-08-18|17-21|6.0.19以降|
|[3.0.x(13)](https://docs.spring.io/spring-boot/docs/3.0.13/reference/html/getting-started.html)|2022-11-24|2023-11-24|2025-02-24|17-21|6.0.14以降|
|[2.7.x(18)](https://docs.spring.io/spring-boot/docs/2.7.18/reference/html/getting-started.html)|2022-05-19|2023-11-24|2025-08-24|8-21|5.3.31以降|

https://spring.io/projects/spring-boot#support

https://endoflife.date/spring-boot

# 所感
EOLが早く感じるのはJava界隈のスピード感に自分がついていけてないのだろうか。
改めてCommercial Supportもどれくらい契約されてるのかちょっと気になった。
契約しなくても切れるの早いからバージョンアップする方が業種によっては多そう。
次はJava目線で書いてみるつもり。

そしてこれがQiita初の記事！
ラズパイをヘッドレスもどきした話【いんちきヘッドレス】

こんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/469010b5-1d3d-8314-d4a1-f75f520dc95e.png)


# はじめに
- ゴールデンウィークは、色々工夫してヘッドレス運用可能にしてみたけど、今回はインチキ手法でヘッドレス（モニタとキーボードなし）してみたので紹介する。
- まぁ、コロンブスの卵的発想というか、多分、誰もが最初に考えつくことかと思うけど...
    - モニタ：HDMI信号をキャプチャして母艦のモニタに映す
    - キーボード：母艦のキーボードをBluetoothキーボード化して、ラズパイに繋ぐ
- それだけ

# 買ったもの
- キャプチャ機器：[z29e](https://akiba-pc.watch.impress.co.jp/docs/news/news/1471401.html)（別途、HDMI-microHDMIケーブルを購入）
- Bluetoothキーボード化アプリ：[KeyPad](https://bluetooth-keyboard.com) (無料でも使えるけど、購入でも400円)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/c4ac90c7-0035-d197-170f-6c2b44d8976d.png)




# 利用方法
- キャプチャ画面
    - macos用アプリとして、[obs](https://obsproject.com/ja)を使用。
    ※ [vlc](https://www.videolan.org/vlc/index.ja.html)も使えるけど、遅延がすごくて使い物にならなかった。vlcの設定方法次第では、使い物になるのかもしれないけどね。
    - obsを立ち上げた後の画面の下部に、「ソース」と書かれたエリアがあるから、その左下の「＋」ボタンを押して、映像キャプチャデバイスをソースに追加し、接続されたキャプチャ機器（z29eは「USB3 Video」と表示された）を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/eaccb8ef-fac1-f48a-1fa0-1e6036945a2b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/4f340d69-f0be-75ae-5d8b-d80d4a3dcee3.png)
    - 画面を配信したいわけでもないので、ラズパイ画面のみを表示するため、画面上で右クリックしてリスト表示し、「全画面プロジェクター（ソース）」を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/7ddeb02c-d213-3fb9-a455-4a9cc117437f.png)
:::note info
macos用のキャプチャアプリを[自作](https://qiita.com/kei_tnk/items/6a3aaaa1f9e64bc44e7c)したので、playgroundsを使えるひとは、obsの代わりに使ってみてください。画面の遅延が減って、使い勝手が向上します。
:::
- Bluetoothキーボード化アプリ
    - app storeで購入可能。他にも[いくつかの候補](https://alternativeto.net/software/keypad-bluetooth-keyboard/)はあるけど、これが最もまともな気がした。typeetoも1keyboardも、昔は定番っぽかったみたいだけど、最近は更新されてないし、値段も1000円以上するし。
    - これの導入はつまづきポイントもないし、解説サボってもいいよね...まあ、最低限の留意点を言えば、最初にBluetooth設定するときは、有線で繋ぐキーボードやマウスが必要ってことと、設定後は、「オプション＋コマンド＋P」でキーボードの支配権がこのアプリに移ると言うことかな。
- そして、タッチパッドの支配権は自動的には移らないから、「コントロール＋オプション」で切り替えることとなる。キーボードの支配権を移したときに、自動的にタッチパッドの支配権も移したければ、下記のフラグを立てておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2733720/c85d5e4d-113b-3df1-af09-b1121f998d1b.png)
:::note info
M5stack社の小さいキーボードを有線式のusbキーボード&マウスにする[スケッチ](https://qiita.com/kei_tnk/items/a3f6e005d01b4506e0ea)を書いたので、気が向いたら参考にみてください。
:::

# おわりに
- とりあえず、linuxの知識ゼロでもヘッドレスもどきが出来るということが分かったけど、実際にやってみると、タッチパッドの反応がワンテンポ遅れるから、気持ち悪い。
- この方法は、[usb-cヘッドレス](https://qiita.com/kei_tnk/items/33b2d99b4c84c564237e)なんかの作業をしているときに、緊急避難的にhdmiで画面を見たいケースに限定した使い方かなぁ。やっぱり、タッチパッドの反応が悪いのは駄目だわ。
ざっくりLinuxをまとめた

# 概要
エンジニアをしていて、Linuxサーバを触ることがありますね。私はLinuxについて全く知らず、プロジェクトに参画したためチンプンカンプンでした。
そこで、業務を通してやUdemyで教材を購入して学習をしました。

# Linuxとは
LinuxとはOSの一つであり、普段私たちが利用してる、MacやWindowsと同じOSの種類の一つである。
WindowsやMacとは違い思いマウス等を使わないコマンドを入力して操作する。

- OSとは
OS(Operating System)は基本ソフトと呼ばれている。普段私たちが利用している、Wordやエクセルのようなアプリケーション(応用ソフトウェア)を動かすために機能していいる。
そのため私たちはOSがあるおかげでデジタル機器を使ってアプリケーションを使用できている。
他にも、OSにはネットワーク通信、プロセス管理、メモリ管理、デバイス管理などアプリケーションよりは地味だが重大な役割を果たしている。
また、OSはカーネルとその周辺のソフトウェアで構成されている。


### Linuxカーネルとは
カーネル（kernel）とは「中核」と日本語ではいい言葉の通りOSの中核となる部分である。
カーネルの周辺にソフトウェアがありそれらを合わせてOSという。

### シェルとは
シェルはユーザーが入力したコマンドをカーネルに伝えその返答をする機能を持っている。
主にカーネルとセット(シェル以外にもあるが)でLinuxOSという。
そのため、ユーザーが入力したコマンドをカーネルは解釈できない。
シェルがカーネルとユーザーとの懸け橋となっている。

# まとめ
以下の図のようにまとめてみた。

## 1 ハードウェア、OS、アプリケーションについて
![Linuxとは.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659733/bbad87b2-3948-c2db-abc0-5af113060082.png)

## 2 カーネルとシェルの関係
![カーネルとシェル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3659733/2af283fb-bf04-4b8b-f4e5-5d30b1f79831.png)

# 参考文献
以下を参考にして学習しました。
ありがとうございます。
[もう絶対に忘れない Linux コマンド【Linux 100本ノック+名前の由来+丁寧な解説で、長期記憶に焼き付けろ！】](https://www.udemy.com/course/linux100test/?utm_source=aff-campaign&LSNPUBID=txFqVPrD5W4&utm_medium=udemyads&ranMID=47984&ranSiteID=txFqVPrD5W4-MeSy11lgp6_Ha2VjeIBGVA&couponCode=LEADERSALE24A)

[Linuxの絵本 サーバーOSが楽しくわかる9つの扉](https://amazon.co.jp/Linux%E3%81%AE%E7%B5%B5%E6%9C%AC-%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BCOS%E3%81%8C%E6%A5%BD%E3%81%97%E3%81%8F%E3%82%8F%E3%81%8B%E3%82%8B9%E3%81%A4%E3%81%AE%E6%89%89-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BE%E3%82%A2%E3%83%B3%E3%82%AF/dp/4798163198/ref=asc_df_4798163198/?tag=jpgo-22&linkCode=df0&hvadid=411479791081&hvpos=&hvnetw=g&hvrand=14008678064254030485&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009250&hvtargid=pla-860963693462&psc=1&mcid=e10e99994c773d7db5b7847ac614681a&th=1&psc=1)