OmniAICreator/Qiita-1.07M huggingface dataset:
FastAPIインストール🔰

# 前提
Python 3.11.7

# インストール
ターミナル上で実行
```
pip install "fastapi[standard]"
```

## 確認
```
fastapi --version 
```

## ソースコード
main.pyをアプリのファイル内に入れて以下のコードをコピペ

```main.py

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
async def root():
    return {"message": "Hello World"}
```

## サーバー起動

```
fastapi dev main.py
```
こんな感じのが出たら成功
FastAPI CLI - Development mode
の
 Serving at:にあるURLで（この場合は`http://127.0.0.1:8000`）
 {"message":"Hello World"}
 が出る。


```
INFO     Using path main.py
INFO     Resolved absolute path /home/user/code/awesomeapp/main.py
INFO     Searching for package file structure from directories with __init__.py files
INFO     Importing from /home/user/code/awesomeapp

 ╭─ Python module file ─╮
 │                      │
 │  🐍 main.py          │
 │                      │
 ╰──────────────────────╯

INFO     Importing module main
INFO     Found importable FastAPI app

 ╭─ Importable FastAPI app ─╮
 │                          │
 │  from main import app    │
 │                          │
 ╰──────────────────────────╯

INFO     Using import string main:app

 ╭────────── FastAPI CLI - Development mode ───────────╮
 │                                                     │
 │  Serving at: http://127.0.0.1:8000                  │
 │                                                     │
 │  API docs: http://127.0.0.1:8000/docs               │
 │                                                     │
 │  Running in development mode, for production use:   │
 │                                                     │
 │  fastapi run                                        │
 │                                                     │
 ╰─────────────────────────────────────────────────────╯

INFO:     Will watch for changes in these directories: ['/home/user/code/awesomeapp']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [2265862] using WatchFiles
INFO:     Started server process [2265873]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
```
Wordの数式におけるアクチュアリー記号：余命・有期年金の表現

## 今回説明するもの
- 平均余命記号$\overset{\circ}{e}$
- 有期年金記号$a_{x:{\overline{n}\rceil}}$

## 平均余命記号

1. まずは数式エディタで、[数式ツール]->[デザイン]->[アクセント]->[グループ文字(上)]を選択します。
![20240923_平均余命1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/dddc0781-5d1c-40bd-ffbf-fb5428b2d110.png)
1. 次の図のとおり上向き括弧を含む選択状態にしてから、Delキーを押下します。
![20240923_平均余命2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/6c3a51a8-bf8b-7ed6-308c-5af01735efff.png)
1. すると、次のような二段組になります。
![20240923_平均余命3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/65360e41-083a-7d3e-cfa9-9e5682359418.png)
1. 下に$e$、上に$\circ$を入力します。
![20240923_平均余命4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/216f1233-f8dd-3019-5839-112affdd480e.png)
1. 続く式を任意に入力できます。
![20240923_平均余命5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/8eb820b3-35c1-6045-faa4-d9648a82331b.png)

## 有期年金

1. まずは数式エディタで$\ddot{a}_{x:n}$と入力します。
1. $n$を選択した状態で、[数式ツール]->[デザイン]->[アクセント]->[四角囲み数式]を選択します。
![Word数式_PensionPV_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/7bb2633f-8ca1-7048-d8ae-06b39e9c8620.png)
1. 四角で囲まれた$n$を選択した状態で右クリックし、[罫線のプロパティ]->[下端を表示しない]を選択し、再度右クリックして同[左端を表示しない]を選択します。
![Word数式_PensionPV_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/f9e57e40-2d4b-04c3-909e-143d6c78df7d.png)
1. 有期年金現価率を表す表記の完成です。
![Word数式_PensionPV_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744936/5b30a252-8194-35c2-da1e-905cf491e04b.png)
AWS Datapipelineとは

##勉強前イメージ
Kinesis周りのサービスと何が違うんだ・・
違いが全然分からない・・

##結論
ざっくりと以下の内容で理解
・AWS内でのデータの転送・変換を自動化するもの、何か特定の機能を持つサービスではなく、複数のＡＷＳリソース間のデータの橋渡しを定義する連携サービス

例）以下のようにアプリログを毎日保存し、週末にログ分析を実行する流れを自動化できたりする。
アプリケーションサーバ（ＥＣ２）　→　Ｓ３に日次保存　→　EMRでデータ解析
![AWS-datapipeline-概略図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3892426/c2a8a672-11ba-f922-84a5-bfc9ca1f1218.png)

##Kinesis関連のサービスとの違い
結論、実行していること自体はほぼ一緒（リソース間のデータの転送・分析）だが、目的が違い、それぞれの目的に沿ってサービスが設計されている
・Kinesis
「リアルタイムに」データを分析したり転送したりしたい場合にはこっちを選択
データが発生したら即座に他リソースへ転送したり分析したりしたい場合に適している。まさにログデータとか、ストリームデータとか。

・Datapipeline
日次/週次のように、ある一定の間隔でパッチ的にデータの変換や分析を行いたい場合にはこちらが適している。例で示したアプリログを日次で保存して週末に解析、などはこちら。

以上！
Laravel✖︎javascript非同期処理について

## 非同期処理についてメモ
実務で非同期処理の実装をする際に気付いたことやエラーの対応方法など

## 実装方法について
登録処理が成功した場合は、編集ページに遷移して完了のメッセージをalert関数を使って表示。
エラーが発生した場合は、ページの一番上にスクロールして適切な位置にバリデーションメッセージを表示する。
javascriptの非同期は 「fetch」jQueryの非同期は「$.ajax」を使用する
Fetchを使ったコードの参考サイト：https://gray-code.com/javascript/implement-ajax-using-fetch-api/
FetchとAJAXの違いについて参考サイト：https://apidog.com/jp/blog/javascript-fetch-ajax/

## エラーの種類と概要
・302エラー
セッションの取得の失敗やjavascript側とバックエンド側の処理でレスポンス形式が違う
→javascript側では return response.json(); 、バックエンド側では return view('ブレードファイル'); など

・500 Internal Server Error エラー
サーバー側で起きるエラーで、SQLの操作(テーブルに対しての値の格納やテーブルから値の取得)に失敗した場合に発生する。
Laravel.logファイルに出力されるため、その内容を参考にする。

・422 Unprocessable Content エラー
バリデーションエラーが発生した場合などに起こります。
バリデーション設定の確認や値の受け渡しが行われているか確認をする必要がある。

## 学んだこと
・Logger関数について
コントローラやサービスクラスの処理の初めなどにLogger('使用している機能や変数を入れる')関数を記載して、ボタンなどを押した際に処理が走っているか確認する。
変数を入れた場合は変数の中身がログで確認出来る、値が入っていない場合はエラーとなる。
通常の文字を入れたのみでも、処理が動作していればLogファイルに記載される。

・console.logについて
javascriptの処理で確認したい部分でconsole.log('変数名')を実施して、変数に値が格納されているか、DBからの値受け取りがうまくいっているかなどを確認することが重要。
デベロッパーツールのソースでブレークポイントを用意し、コードの動きなどを見ることも問題解決の糸口になる可能性がある。
条件分岐などでどのコードを実施しているかなど追うこと。

## 参考サイト
https://qiita.com/ryosuketter/items/dd467f827c1b93a74d76
https://zenn.dev/nameless_sn/articles/javascript_async_tutorial
https://enginiya.com/entry/laravel-how-to-use-ajax#google_vignette
Laravel 11 とりあえずAPIサーバーを立ててみる。

バックエンドを人に任せているが、せめてAPIだけでも使えるようになってないとフロントエンド開発しにくいなあと言うことで、簡易的にAPIサーバーを立てて値の取得することに。

とりあえずGET前提で試してみる。
## 一応環境
Laravelバージョン 11
php 8系

## プロジェクト作成
```shell 
laravel new api-server
```
## Controller作成
今回はApiControllerという名前で作成する。

```shell
php artisan make:controller ApiController
```
app/http/controllers/ApiController.phpが作成される。

## メソッド作成
ApiControllerを開いてメソッドを追加する。
```php
public function apitest(){
    return  response()->json(['message' => 'hello world!']);
}
```
## ルート設定
routeにapi.phpを新規作成する。
ファイルを開いて以下を記述する。
```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ApiController;


Route::get('/apitest', [ ApiController::class,'apitest']);
```

api.phpに追加すると、アクセスするためのURLにdomain/api/routeと言う感じでapiが挟まるらしい。
なので今回のapitestのエンドポイント、アクセスするためには
__localhost:8888/api/apitest__ にアクセスすることになる。

## ルートファイルの追加
作成したapi.phpをシステムに追加する。
bootstrap/app.phpを開いて、以下を追加する。
```php
api: __DIR__.'/../routes/api.php',
```
これで、同じlocalhostからはapiで接続できるようになったはず。

## 実験
resources/views/welcome.blade.phpを開く
57行目あたりに ```<main class="mt-6">``` があるので、ここを書き換えてやる。
```html
<main class="mt-6">
<!--ここ以下を追加-->
<script>
    async function get_test(){

        let res =await ( fetch('http://localhost:8888/api/apitest')) ;
        console.log(res);
        let data = await( res.json());
        alert( data['message']);
    }
</script>
<button style="width:200px; height:100px;"
onclick="get_test()">テスト</button>
```

適当にサーバー起動。なんでもいいけどターミナルで次を打つ。
```shell
php artisan serve
```
http://localhost:8000/ にアクセスする。
![スクリーンショット 2024-09-23 8.56.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3353026/b7819058-28cf-ab36-5905-49672fac33e3.png)

ボタンを押して、hello worldが出たらOK

## 外部から接続できるようにする
正確には別のoriginと言うことみたいが、要はシステムの気持ちでいえば外部ってことやろ
corsを設定する必要がある。
```shell
php artisan config:publish cors
```
corsのファイルを作成する。publishと言うことがあまり理解できてない。
corsファイルが config/cors.phpにできる。

これで外部からアクセスできるようになった。

あとは、corsの内容を編集して制限かけておく。
cscの作法 その520

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
ComboBoxで表示で、id とnameをくっつけて、表示する。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b3be0846-b92f-98ab-2e92-0446a232cce1.png)

# サンプルコード

```

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Data;

namespace App
{
	public partial class Form1: Form {
		ComboBox comboBox1;
		public Form1() {
			Text = "ComboBox";
			ClientSize = new Size(300, 300);
			Label label = new Label();
			label.Location = new Point(10, 50);
			label.Text = "フルーツ";
			Controls.Add(label);
			DataTable dt = new DataTable();
			dt.Columns.AddRange(new DataColumn[] {
				new DataColumn("id", typeof(int)),
				new DataColumn("name", typeof(string))
			});
			dt.Rows.Add(0, "");
			dt.Rows.Add(1, "バナナ");
			dt.Rows.Add(2, "マンゴー");
			dt.Rows.Add(3, "パパイア");
			dt.Rows.Add(4, "キウイ");
			dt.Columns.Add("idname", typeof(string));
			for (int i = 0; i < dt.Rows.Count; i++)
			{
				dt.Rows[i]["idname"] = dt.Rows[i]["id"].ToString() + " " + dt.Rows[i]["name"];
			}
			comboBox1 = new ComboBox();
			comboBox1.Location = new Point(30, 100);
			comboBox1.DataSource = dt;
			comboBox1.DisplayMember = "idname";
			comboBox1.ValueMember = "id";
			comboBox1.SelectedIndex = -1;
			comboBox1.SelectedValueChanged += comboBox1_TextChanged;
			Controls.Add(comboBox1);
		}
		private void comboBox1_TextChanged(object sender, EventArgs e) {
			int n = comboBox1.SelectedIndex;
			string str = comboBox1.Text;
			string str1 = comboBox1.SelectedValue.ToString();
			MessageBox.Show("selected: " + n + " (" + str + ": " + str1 + ")");
		}
		[STAThread]
		public static void Main() {
			Application.Run(new Form1());
		}
	}
}





```


以上。
[リファクタリング技法]参照から値への変更

## リファクタリング前

以下のコードを考えます。
Person 内部で　 Telephone クラスをインスタンス化していますが、電話番号は途中で変更するのではなく値オブジェクトとして新しいインスタンスを生成することが望ましいです。

```python
class Person:
    def __init__(self) -> None:
        self._telephone_number = Telephone()
    @property
    def office_area_code(self):
        return self._telephone_number.area_code
    @office_area_code.setter
    def office_area_code(self, arg):
        self._telephone_number.area_code = arg
    @property
    def office_number(self):
        return self._telephone_number.number
    @office_number.setter
    def office_number(self, arg):
        self._telephone_number.number = arg

class Telephone:
    def __init__(self) -> None:
        self._area_code = 'area_code'
        self._number = 'number'
    @property
    def area_code(self):
        return self._area_code
    @area_code.setter
    def area_code(self, arg):
        self._area_code = arg
    @property
    def number(self):
        return self._number
    @number.setter
    def number(self, arg):
        self._number = arg


if __name__ == '__main__':
    telephone = Telephone()
    person = Person()
    person.office_area_code = '03'
    print(person.office_area_code) # 03
```

## リファクタリング後

リファクタリング後のコードは以下です。
Person のセッター内部で新しいインスタンスを生成してセッターを削除することで Telephone クラスは初期化後に変更が不可となり、値オブジェクトに変更することが可能となります。

```python
from __future__ import annotations


class Person:
    def __init__(self) -> None:
        self._telephone_number = None
        self._office_area_code = ''
        self._office_number = ''
    @property
    def office_area_code(self):
        return self._telephone_number.area_code
    @office_area_code.setter
    def office_area_code(self, arg):
        self._telephone_number = Telephone(arg, self._office_number)
    @property
    def office_number(self):
        return self._telephone_number.number
    @office_number.setter
    def office_number(self, arg):
        self._telephone_number = Telephone(self._office_area_code, arg)

class Telephone:
    def __init__(self, area_code, number) -> None:
        self._area_code = area_code
        self._number = number

    def __eq__(self, other: Telephone) -> bool:
        return self._area_code == other._area_code and self._number == other._number
    @property
    def area_code(self):
        return self._area_code
    @property
    def number(self):
        return self._number


if __name__ == '__main__':
    person = Person()
    person.office_area_code = '03'
    print(person.office_area_code)# 03
```

また、等価比較メソッド(**eq**)を定義し機能することをテストコードで検証します。

```python
import pytest

from refactor_a import Telephone


class TestTelehoneNumber:
    def test_telephone_equal(self):
        assert Telephone('03', '03-1111-1111') == Telephone('03', '03-1111-1111')
```
リファクタリング技法

## 目的

[リファクタリング](https://www.amazon.co.jp/%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0-%E6%97%A2%E5%AD%98%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E5%AE%89%E5%85%A8%E3%81%AB%E6%94%B9%E5%96%84%E3%81%99%E3%82%8B%EF%BC%88%E7%AC%AC2%E7%89%88%EF%BC%89-%EF%BC%AD%EF%BD%81%EF%BD%92%EF%BD%94%EF%BD%89%EF%BD%8E%EF%BC%A6%EF%BD%8F%EF%BD%97%EF%BD%8C%EF%BD%85%EF%BD%92-ebook/dp/B0827R4BDW/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2GXTC8X6IZK8&dib=eyJ2IjoiMSJ9.9eaC7zAw4E0773Za3bwdjeZFEVbfuJniE9oDf8nfzaqZU0JwQ6VelRroMXWwmTY5LqSfQUeyJPb4kjn8-WRIGrZonuaIXxg4Nkti2u8qUSrK-eSPNQ3-vM2dNdgVNr9_Rx-Fc6jBemxSJcwD_9u02i06IZifQPmKOdFztn8abHwLMUiuzEyRRqlDjsV9n6H4QkoYrwW-NQ0kbPZ3nzRRaFe2kEL5RLGB1RbfFNJbca6ZWdYt2fcwoXuecM9IiiePKtoBRpV40TQUqxydFxpBYZkZTKOpSkXPFtF5m0yn6XU.paX9eyTJzx0ZA8j-63AVHqhN4ut8MptApiRehO1XWOU&dib_tag=se&keywords=%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0&qid=1727043668&sprefix=%E3%83%AA%E3%83%95%E3%82%A1%E3%82%AF%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0%2Caps%2C180&sr=8-1)に記載の技法のうちよく使うものを列挙し必要な時に参照できるようにする。
各技法の詳しい使い方については Python プログラムに置き換えて別記事として作成する。

## 7 章 カプセル化

- オブジェクトによるプリミティブの置き換え
- クラスの抽出

## 9 章 データの再編成

- [参照から値への変更](https://qiita.com/Ryosuke11/items/e0517e61df19567a626f)
- 値から参照への変更

## 10

- ポリモーフィズムによる条件記述の置き換え

## 11

- ファクトリ関数によるコンストラクタの置き換え
- コマンドによる関数の置き換え

## 12

- スーパークラスの抽出
- 委譲によるサブクラスの置き換え
- 委譲によるスーパー　クラスの置き換え
ネットショッピング「実物の想像がつかない🤔💭」を解消したい！5分で3Dモデルを作ってARで表示しちゃおう！

みなさんは、こんな経験ありませんか？
ネットで買い物をして、家に届いてみたら‥‥「え？！思ってたのと違う！」

自分の家にやってきたときの雰囲気やサイズ感って、ネットだとどうしても把握しづらいですよね。そこで‥‥

## スマホだけで3Dモデルを作って、品物を家の中に表示させてみよう！

さっそくこちらを見てください～！！（字幕あり）

https://x.com/tabisurujapaniz/status/1837884189817164242

試してみたい方は、スマホで[こちら](https://scaniverse.com/scan/2rzu52rhlhfojujo)のリンクを開くか、下のQRコードを読み取ってみてください。動画に登場しているカートが実寸大で出現します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819429/27f8ff7a-c521-dac9-7b2e-172cd29dae7f.jpeg"= width="50%">

自分で作っておいて大感動！オンラインショップの商品ページにこういった体験ができるURLがあると、ネットで買い物での「思ってたより大きすぎた」「部屋のイメージに合わなかった」という失敗が減らせるのではないでしょうか。写真も撮れるので、他の人にも共有して「これどうかな〜？」なんて相談もできますね✨

そしてオンラインショップ側から見ても、楽しく、便利な買い物体験が提供できて◎なのでは？！世界中のオンラインショップの運営者さん、ぜひお願いします！

## :hammer_pick: 3Dモデルの作り方
作り方解説動画はこちら（字幕あり）↓↓

https://x.com/tabisurujapaniz/status/1839582237731496366

#### :iphone: 使用するもの
・[Scaniverse](https://scaniverse.com/)（無料スマホアプリ）

Scaniverse（スキャニバース）は、スマートフォンで利用できる3Dスキャンアプリです。物や建物をスキャンして、3Dデータに変換することができます。

#### :gear: 作り方
1. Scaniverseを開き、対象物のサイズを選択する
1. 対象物の表面に赤いしましまが出なくなるまで、全方向からスキャンする
1. モードを選択して、3Dデータを書き出す
1. 3Dデータをトリミングする
1. 共有方法を選択する

たった5分で3Dモデルの完成です！
発行したURLを商品詳細ページに以下の様に埋め込めば、ユーザーが簡単に3Dモデルを呼び出せるようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819429/dc8ff202-f36f-82a9-ac3b-734ffeed4c83.png" width=80%">
※画像はイメージです。

#### :raised_hand: 使い方
1. スマホでURLをタップする
1. 実寸大の品物を表示させたい場所で、3Dモデルを表示させる
1. 移動・回転をさせてサイズ感や雰囲気を確認する


## 💭オンラインショップの中の人に見せてみた！

実際にオンラインショップを運営している人に、見せて意見を聞いてみました！

**Goodな点👍**
・試せないというネットショップのデメリットを補完できている
・特に家具や家電はサイズ感がわかるので◎
・ショップのユーザーが、専用のアプリなど使わずワンタップで利用できて◎
・無料でできて◎だし、スキャンするための人件費などにお金をかけてもいいと思う
・このサービスを提供することで、返品を減らせそう

**懸念点😥**
・商品を1つ1つ手作業でスキャンするのは大変
・どんどん新しい商品が入って入れ替わっていく部門では使いづらい（3Dモデル作成のリードタイムを考えると難しい）
・3Dモデルの画質が荒いし綺麗にスキャンできていない部分もあるので、お客様に見せるものとしては微妙なところ
・商品のメーカーやブランドから掲載の許可を得るのが大変かも
・3D画像と実物の差異があったときに起こりうるリスクについての検討が必要

実際に導入しようとすると、よく検討しなければいけない点はありまが、ポジティブに言えば、**家具・インテリアなどの限定した品物で、 費用をかけずに便利なサービスを提供しようとする目的では有効**で、ARサービスの本格導入前に**効果測定のためのプロトタイプ**として活用できるのではないでしょうか！

## :point_up: ちなみに
私はいつもこんな風にChatGPTにお願いして、シチュエーションに合わせた最適な英文を描いてもらっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3819429/f4f8798a-badb-33f3-f3ec-3225eca470cc.png)
【Laravel】Collectionで使用できるメソッドの返り値

# 返り値（戻り値）ってみんな覚えてるの・・・？
LaravelのCollectionを扱っていると、

「あれ、このメソッドの返り値ってなんだっけ・・・」
「データがない時ってエラーになるんだっけ・・・あ、コレクション型だ」

という場面が往往にしてあります。
公式ドキュメントに載っていなかったり、コードヒントなどで一々確認したり、実際にコードを書いてみたりしていましたが、まとまったドキュメントがあれば整理しやすいな〜と思い下記にまとめてみます。

:::note warn
Laravel10の公式ドキュメントや実コードを元にまとめています。
:::

# よく使うCollectionのメソッドの返り値
| メソッド    | 説明 | データ存在時の返り値 | データが存在しない時の返り値 |
|:-----------|:------------|:-------------|:-------------|
| `all` | コレクションの元の配列表現を返します。 | `array` | `array` |
| `get` | 指定されたキーのアイテムを返します。キーが存在していない場合は`null`を返します。 | `mixed (値)` | `null` |
| `pluck` | 指定したキーの全コレクション値を取得します。 | `Collection` | 空の`Collection` |
| `only` | コレクション中の指定したアイテムのみを返します。 | `array` | `array` (指定キーがない場合、空配列) |
| `except` | キーにより指定したアイテム以外の全コレクション要素を返します。※exceptの正反対の機能はonly | `Collection` | `Collection` |
| `first` | （条件に合う）コレクションの最初の要素を返します。 | `mixed (値)` | `null` |
| `firstOrFail` | 結果が見つからない場合に`ItemNotFoundException`例外を投げる以外、`first`メソッドと同じです。 | `mixed (値)` | `ItemNotFoundException` |
| `count` | コレクションのアイテム数を返します。 | `int` | `0` |
| `values` | キーをリセット後、連続した整数にした新しいコレクションを返します。 | `Collection` | 空の`Collection` |
| `sort` | コレクションをソートします。 | `Collection` | `Collection` |
| `sortBy` | 指定したキーでコレクションをソートします。 | `Collection` | `Collection` |
| `isEmpty` | コレクションが空の場合に`true`を返します。そうでなければ`false`を返します。 | `bool` | `bool` |
| `max` | 指定したキーの最大値を返します。 | `mixed (値)` | `null` |
| `min` | 指定したキーの最小値を返します。 | `mixed (値)` | `null` |
| `search` | コレクションを検索し、指定値が見つかった場合はそのキーを返します。見つからない場合は`false`を返します。 | `int (キー)` | `false` |
| `toArray` | コレクションをPHPの「配列」へ変換します。 | `array` | `array` |
| `unique` | コレクションの重複を取り除いた全アイテムを返します。 | `Collection` | `Collection` |
| `where` | 指定したキー／値ペアでコレクションをフィルタリングします。 | `Collection` | 空の`Collection` |
| `collect` | コレクション中の現在のアイテムを利用した、新しい`Collection`インスタンスを返します。 | `Collection` | `Collection` |
| `concat` | 指定した`array`またはコレクションの値を別のコレクションの最後に追加します。 | `Collection` | `Collection` |
| `duplicates` | コレクション中の重複値を返します。 | `Collection` | 空の`Collection` |
| `each` | コレクション内のアイテムを反復処理し、各アイテムをクロージャに渡します。 | `Collection` | `Collection` |
| `forget` | キーによりコレクションのアイテムを削除します。※呼び出し元のコレクションを更新する | `void` | `void` |
| `groupBy` | 指定したキーによりコレクションのアイテムをグループ化します。 | `Collection` | 空の`Collection` |
| `has` | 指定したキーがコレクションに存在しているかを調べます。 | `bool` | `bool` |
| `implode` | コレクション内のアイテムを結合します。 | `string` | `string` |
| `last` | 指定したテストをパスしたコレクションの最後のアイテムを返します。 | `mixed (値)` | `null` |

# 参考
* [10.x コレクション Laravel](https://readouble.com/laravel/10.x/ja/collections.html)
【すぐにテスト環境構築】超簡易なJSONファイルを使ったMockサーバーを作った


## 概要
`/responses`配下にJSONファイル(`*.json`)を置くだけで、JSONを返すMockサーバーを作成しました。（自分用）

### 対象者
小規模なアプリケーションのテストをしたい方、テスト環境構築にとにかく時間をかけたくない方 
### 制限事項
とってもシンプルな構成のため、以下のケースには現状対応していません。  
`JSON-server`や`postman`を検討してください。または、ソースコードを自由に改変していただいて構いません。

- `200`以外のステータスコード
- BodyやHeaderに応じたレスポンスの条件分岐
- JSON以外のレスポンス

### ソースコード
```bash
git clone https://github.com/RyutaSato/mock-api.git
```

## 使い方
リポジトリをクローンし、以下のコマンドでDockerを起動します。

`${PORT}`はListenしたいポート番号に置き換えるか、環境変数で指定します。
```bash
# cd mock-api
# PORT=8080
docker build -t mock-api .
docker run -d -p ${PORT}:8080 -v $(pwd)/responses:/responses mock-api
```

Windows上でPowerShellを使用している場合
```powershell
# cd mock-api
# $PORT=8080
$PWD="$((pwd).Path.Replace('\', '/'))"
docker build -t mock-api .
docker run -d -p ${PORT}:8080 -v ${PWD}/responses:/responses mock-api
```

`responses`配下はコンテナにマウントされるので、コンテナ起動中でもJSONファイルを変更することで続けてテストができます。

## 例 
- `/v2/index`をテストしたい場合  
`/responses`配下に`v2`ディレクトリを作成し、その配下に`index.json`を配置します。
`/responses/v2/index.json`を配置します。  

- `/v2`をテストしたい場合  
実装方法は2つあります。
    - `/responses/v2.json`を配置します。  
    - `/responses/v2`配下に`.json`を配置します。

- `/v2?id=123&name=json`をテストしたい場合
`/responses`配下に`v2_id=123&name=json.json`を配置します。
> クエリパラメータは、`?`を`_`に置き換えて指定できます。(ファイル名に`?`が使用できないため)

- `/v2`をPOSTリクエストでテストしたい場合
`/responses`配下に`v2.post.json`を配置します。
> メソッドは、`(path).(method).json`の形式で指定できます。(`GET`のみ省略できます)

## おわりに
`Dockerfile`と`main.go`合わせてコード量100行程度です。
理解するのも書き換えるのも容易なので必要に応じて改変して使ってください。
ACDLを提唱します。その5

# 概要
ACDLとは、アプリは、クラウド、大切なデータは、ローカルです。
素晴らしいアプリ見つけたので、plunkerに上げてみた。

# 参考にしたページ

https://qiita.com/yaju/items/66678f9abb530f169a80


# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f607630c-3dd3-bba2-7d5a-ee2ec7e29927.png)


# 成果物

https://embed.plnkr.co/plunk/h0d0hXwRkoeZPkpv

以上
GitHub SSH

# GitHubでSSHキーを設定する手順

GitHubでリモートリポジトリにパスワードなしでアクセスできるようにするには、SSHキーを設定する必要があります。この記事では、GitHub初心者向けに、SSHキーを作成してGitHubアカウントに紐付ける方法を説明します。

## 前提条件
まず、GitHubアカウントを作成していることが前提となります。また、ローカルで作業する際は、GitHubでリポジトリを作成しておくとスムーズです。

GitHubリポジトリの作成手順:
1. GitHubにログインし、右上の「+」メニューから「New repository」を選択します。
2. リポジトリ名を設定し、公開/非公開を選んで「Create repository」をクリック。

このリポジトリが後でSSHキーを使って接続するリモートリポジトリになります。

---

## SSHキー作成手順

### 1. ターミナルを開く
Macの場合は「ターミナル」、Windowsの場合は「Git Bash」または「コマンドプロンプト」を使用します。

### 2. SSHキーを生成する
ターミナルで以下のコマンドを実行して、SSHキーを作成します。`your_email@example.com` の部分を自分のGitHubアカウントに登録しているメールアドレスに置き換えます。

```bash
ssh-keygen -t ed25519 -C "your_email@example.com"
```


- `ssh-keygen`: SSHキーを生成するコマンド。
- `ed25519`: 推奨されているSSHキーのタイプ。
- `-C`: メールアドレスをコメントとして追加。

### 3. 保存場所を指定する
SSHキーを保存する場所を聞かれますが、特に変更しない場合はそのまま `Enter` を押してデフォルトの場所に保存します。通常は `~/.ssh/id_ed25519` に保存されます。

### 4. パスフレーズの設定
パスフレーズを設定するよう求められます。セキュリティを強化したい場合はパスフレーズを入力しますが、不要な場合は `Enter` を押してスキップできます。

---

## 5. 公開キーをGitHubに追加する

SSHキーが生成されたら、公開キーをGitHubに登録します。まず、公開キーの内容を確認します。以下のコマンドで公開キーを表示します。

```bash
cat ~/.ssh/id_ed25519.pub
```

このコマンドを実行すると、ターミナルに公開キーの内容が表示されます。このキーをコピーして、GitHubに登録します。

### GitHubにSSHキーを追加する手順
 - GitHubにログインし、右上のプロフィールアイコンから「**Settings**」を選択。

![スクリーンショット 2024-09-23 5.45.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/b770e85b-3fd4-f1d4-2147-cf839fb5d567.png)

 - 左側のメニューから「**SSH and GPG keys**」を選択。
 - 右上の「**New SSH key**」をクリック。
![スクリーンショット 2024-09-23 5.37.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1664191/fb561e5f-a66f-8e8e-726f-8a3f1e1fb54b.png)



- 「Title」に識別しやすい名前（例:「My PC」）を入力し、公開キーを貼り付けて「**Add SSH key**」をクリック。
---

## 6. SSH接続をテストする

SSHキーが正しく設定されているかを確認するために、以下のコマンドを実行します。

```bash
ssh -T git@github.com
```

初回接続時に「Are you sure you want to continue connecting (yes/no/[fingerprint])?」と聞かれたら `yes` と入力します。正しく設定されていれば「Success」と表示されます。

これで、GitHubのリモートリポジトリにSSHで接続し、パスワードなしでコードをプッシュしたりプルしたりできるようになりました。

---

これでSSHキーの設定が完了です。今後、`git push`や`git pull`などの操作をするときに、毎回パスワードを入力することなく、GitHubとローカル環境が連携できるようになります。
ビジュアルプログラミングで高位合成 その10

# 概要
ビジュアルプログラミングで組み合わせ回路を組み立てて、シュミレーションして、verilogを生成します。
高位合成です。
実は、今の実装では、全加算器が高位合成できません。
全加算器の高位合成を実装しました。検証します。
検証編

# テストベンチを書く。

```

module x(input B, input A, input Cin, output Sum, output Cout);
	wire w0;
	wire w1;
	wire w2;
	wire w3;
	assign Sum = (Cin ^ w0);
	assign w0 = (A ^ B);
	assign w1 = (A ^ B);
	assign w2 = (A & B);
	assign Cout = (w3 | w2);
	assign w3 = (Cin & w1);
endmodule


module test;
	reg A;
	reg B;
	reg Cin;
	x u(.A(A), .B(B), .Cin(Cin), .Sum(Sum), .Cout(Cout));
	initial
	begin
		$display(" A   B   Cin Sum Cout");
		$monitor(" %b   %b   %b   %b   %b", A, B, Cin, Sum, Cout);
		A = 0;
		B = 0;
		Cin = 0;
	#10;
		A = 0;
		B = 1;
		Cin = 0;
	#10;
		A = 1;
		B = 0;
		Cin = 0;
	#10;
		A = 1;
		B = 1;
		Cin = 0;
	#10;
		A = 0;
		B = 0;
		Cin = 1;
	#10;
		A = 0;
		B = 1;
		Cin = 1;
	#10;
		A = 1;
		B = 0;
		Cin = 1;
	#10;
		A = 1;
		B = 1;
		Cin = 1;
	#10;
		$finish;
	end
endmodule





```

# iverilogでシュミレーション実行

```
>iverilog fa1.v

>vvp a.out
 A   B   Cin Sum Cout
 0   0   0   0   0
 0   1   0   1   0
 1   0   0   1   0
 1   1   0   0   1
 0   0   1   1   0
 0   1   1   0   1
 1   0   1   0   1
 1   1   1   1   1
fa1.v:58: $finish called at 80 (1s)

```

以上
Gitコミットの著者情報を修正する方法

## 問題

プライベートリポジトリへのコミットで、誤って関係ない情報のGit設定で作業してしまい、著者情報が間違ってしまいましたので、修正の過程をまとめてた内容です。

```bash
commit abc123def456ghi789jkl101112mnop131415qr (HEAD -> main, origin/main)
Author: incorrect_user <incorrect_email@example.com>
Date: Mon Sep 22 11:03:45 2024 +0900
push 3
commit stu161718vwx192021yz222324abc252627de
Author: incorrect_user <incorrect_email@example.com>
Date: Mon Sep 22 10:56:36 2024 +0900
push 2
commit fgh282930ijk313233lmn343536opq373839rs
Author: user_id <private_email@example.com>
Date: Mon Sep 22 09:57:09 2024 +0900
Initial commit
```
注意：commitやユーザー情報はマスク済みです。

## 解決方法

### 1. 最新のコミットの修正

1. 対話的なrebaseを開始:
   ```
   git rebase -i fgh282930ijk313233lmn343536opq373839rs
   ```

2. エディタで最新のコミットを`edit`に変更:
   ```
   edit abc123d push 3
   pick stu1617 push 2
   ```

3. 著者情報を修正:
   ```
   git commit --amend --author="user_id <hogehoge_email@example.com>" --no-edit
   ```

4. rebaseを続行:
   ```
   git rebase --continue
   ```

### 2. 2番目のコミットの修正

1. 再度対話的なrebaseを開始:
   ```
   git rebase -i fgh282930ijk313233lmn343536opq373839rs
   ```

2. エディタで2番目のコミットを`edit`に変更:
   ```
   pick tuv4041 push 3
   edit stu1617 push 2
   ```

3. 著者情報を修正:
   ```
   git commit --amend --author="user_id <hogehoge_email@example.com>" --no-edit
   ```

4. rebaseを続行:
   ```
   git rebase --continue
   ```

### 3. 変更の確認

   ```
   git rebase --continue
   ```

### 4. リモートリポジトリへの反映

```
git push --force origin main
```

## 結果
全てのコミットの著者情報が正しく修正されました。

```
commit tuv404142wxy434445zab464748cde495051fg (HEAD -> main)
Author: user_id <hogehoge_email@example.com>
Date: Mon Sep 22 11:03:45 2024 +0900
push 3
commit hij525354klm555657nop585960qrs616263tu
Author: user_id <hogehoge_email@example.com>
Date: Mon Sep 22 10:56:36 2024 +0900
push 2
commit fgh282930ijk313233lmn343536opq373839rs
Author: user_id <hogehoge_email@example.com>
Date: Mon Sep 22 09:57:09 2024 +0900
Initial commit
```

## 注意点

- 強制プッシュ（`git push --force`）は他の人と共有しているリポジトリではやめましょう。
- 重要なデータのバックアップを取ることをお勧めします。（一度ミスってコード消えたので焦りますした）
- もし何か問題が発生した場合は、`git reflog`を使用して以前の状態に戻ることができます。

## まとめ

今後同様の問題を防ぐために、`.gitconfig.A`と`.gitconfig.B`の設定を再確認し、必要に応じて調整しましょう。また、プロジェクトの`.git/config`ファイルに`user.name`と`user.email`が設定されていないことを確認しましょう。（今回はグローバルにuser情報を残したままにしていたのが原因でした）
2024/9/23主にITとかセキュリティの記事

物流代行事業者のランサムウエア感染についてまとめてみた(9/21)
https://piyolog.hatenadiary.jp/entry/2024/09/21/002152

松竹で最大23万人の個人情報漏えいか　「ランサムウエア」によるサイバー攻撃受け住所や氏名・電話番号など　クレジットカード決済情報は漏えいなし(9/20)
https://nordot.app/1209836017071326163

松竹通販サイト ランサムウエア被害 23万人の個人情報漏えいか(9/20)
https://www3.nhk.or.jp/news/html/20240920/k10014587051000.html

松竹委託先がサイバー被害(9/21)
https://www.nikkei.com/article/DGKKZO83611010Q4A920C2TB0000/

Amazon CloudWatch Logs Data Protection による機密ログデータの検出と保護(9/21)
https://aws.amazon.com/jp/blogs/news/how-amazon-cloudwatch-logs-data-protection-can-help-detect-and-protect-sensitive-log-data/

Microsoftは「Azure」をサイバー攻撃から守れているのか(9/20)
https://kn.itmedia.co.jp/kn/articles/2409/20/news095.html

インターネット全体のLayer 0 プライバシー・インフラ(9/20)
https://qiita.com/pseudonym2/items/839db297692332d36b63

追跡 中国・流出文書 1 ～世論操作ツール～(9/20)
https://www3.nhk.or.jp/news/html/20240920/k10014585911000.html

アベニュー社の被害から学ぶランサムウェア対策とリスク管理
https://cybersecurity-park.com/2996/

サイバー対策放置は経営の怠慢だ　正義のハッカー警鐘 直言(9/21)
https://www.nikkei.com/article/DGXZQOUE220QJ0S4A520C2000000/

“QRコードを使った詐欺”が増加中 専門家が注意を促す3つのパターンとは 対策は「安易に読み込まない」(9/21)
https://nordot.app/1210179602548016009

大手仮想通貨取引所BingXにハッキング、60億円以上が流出　全額補償へ(9/21)
https://coinpost.jp/?p=560165

サイバー防犯アニメ動画　大学生が声優　「くまむす」伝授　幅広い年齢層にアピール　県警(9/21)
https://www.yomiuri.co.jp/local/kumamoto/news/20240920-OYTNT50131/

【第60回】埃を被っているRaspberry Pi 4やミニPCをメディアサーバーとして活用する(9/21)
https://pc.watch.impress.co.jp/docs/column/ubuntu/1625361.html

グーグルやMSら警鐘、生成AIでITエンジニアは不要になる？「90％以上影響」の詳細(9/21)
https://www.sbbit.jp/article/cont1/148536

BCP対策とは？企業が知るべき基礎知識と策定方法をわかりやすく紹介(9/20)
https://liskul.com/business-continuity-plan-152995

DX推進とは？企業での進め方と課題、具体例をわかりやすく解説(9/20)
https://www.skillupai.com/blog/for-business/about-dx-promotion/

証券会社、ウイスキーに着目　デジタルで小口投資可能に(9/21)
https://www.toonippo.co.jp/articles/-/1863800

自民党総裁選は「デジタル化」加速の議論を、生成AI開発・活用は成長戦略の柱(9/21)
https://news.yahoo.co.jp/articles/83a2f5e20372dcbd48eb8bd38ef60ae379ce242b

現代の「トロイの木馬」:レバノンで2日間にわたる大混乱(9/21)
https://www.arabnews.jp/article/middle-east/article_129613/

中国 国家情報化発展報告 (2023) (2024.09.06)(9/21)
http://maruyama-mitsuhiko.cocolog-nifty.com/security/2024/09/post-bee71f.html

11月施行のフリーランス保護新法、「おねだり」など無知による違反が経営リスクに(9/20)
https://xtech.nikkei.com/atcl/nxt/column/18/00989/091800159/
Docker, docker-compose, rails を使って、HelloWorld を表示する。

## 目的
docker, docker-compose, rails を使って、HelloWorld を表示する。

## 環境
EC2 ubuntu

## 前提
・Vscode の Remote SSH を使う。
・3000 ポートのポートフォワーディングができている。

## 手順
(1)
```
~$ sudo apt update
~$ sudo apt install docker.io docker-compose
~$ sudo systemctl start docker
~$ sudo systemctl enable docker
~$ mkdir rails_api
```
vscode で rails_api フォルダに移動
```
~/rails_api$ docker-compose --version
~/rails_api$ sudo apt remove docker-compose
~/rails_api$ DOCKER_COMPOSE_VERSION=2.20.3
~/rails_api$ sudo curl -SL https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
~/rails_api$ sudo chmod +x /usr/local/bin/docker-compose
~/rails_api$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
~/rails_api$ docker-compose version
```

(2)
`docker-compose` コマンドを実行するために、ubuntuユーザにdockerグループを割り当てる。
ただ、sudo をつければ実行できるので、必要ないかも。
```
~/rails_api$ groups
~/rails_api$ sudo usermod -aG docker $USER
~/rails_api$ newgrp docker
```

(3)
下記のように `~/rails_api` にファイルを作成。

```Dockerfile
# Dockerfile
FROM ruby:3.2

RUN apt-get update -qq && apt-get install -y nodejs

WORKDIR /my_app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install

COPY . .
```

```docker-compose.yml
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/my_app
    command: rails s -b 0.0.0.0
```


```Gemfile
# Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 7.0.0'
```

```Gemfile.lock
# 空で作成
```

(4)
```
~/rails_api$ docker-compose run --no-deps web rails new . --api --force
~/rails_api$ docker-compose run web bundle install
```

(5)
```
echo $USER
sudo chown -R $USER:$USER ./
```
下記のようにファイル作成
```app/controllers/hello_controller.rb
class HelloController < ApplicationController
  def index
    render plain: "HelloWorld"
  end
end
```

```config/routes.rb
Rails.application.routes.draw do
  get 'hello', to: 'hello#index'
end
```

(6)
ビルドして起動する。
```shell
~/rails_api$docker-compose build
~/rails_api$docker-compose up
```

(7)
http://localhost:3000/hello にアクセスする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3508161/fcb17d63-4360-a4b4-5902-73937f31de14.png)
[ITパスポート] 合格までに行った勉強法

ええと、とりあえず前置きとしてちょうど本日試験に行って合格ラインであるそれぞれの分野(ストラテジ、マネジメント、テクノロジ)300点以上、総合得点600点以上を超えて多分受かりました。それで、今回はどのような勉強方法をして合格に至ったのかを解説したいと思います。まあ解説するほどでもないですけどね笑

- # 合格方法！
それはズバリ[このアプリ](https://play.google.com/store/apps/details?id=jp.co.trips.shikakuitpassport&hl=ja)です。ちなみにiOSにもあります。ただこれで解きまくるだけです。用語とその意味さえ知っていれば多分合格できます。ぶっちゃけ言ってしまえば計算問題なんかは捨てても問題ありません。これすぐにできるからスキマ時間にできるのが魅力なんですよね。このアプリの開発者は他にも色んなアプリ出しているので良く使わせてもらってます。またそれは別の記事で紹介するかもしれません。ってな感じで、ただこれだけです。時間にすると100時間くらい勉強すれば多分大丈夫だと思います。それが終わって試験3日前になったらその3日を使って全問題を一日5,6時間かけて一通り解いてください。ざっと見して解けばいいです。全体をパッと覚えておくためなので。当たり前ですが解けなかった問題はチェックを入れて再度解いてください。それを繰り返すだけです。これで試験に挑めば完璧です。それとこれは年度別で過去問が解くものがありますがこれは解かなくても全然いけます。それと2024年10月からは新しいシラバスになるのでその辺注意を入れておかないといけないかもしれません。新しいシラバスのバージョンに対応しているのかはご自身で調べてください。

- ### あとがき
別のITパスポート取得した人は参考書を買ってやっているのでその方法でも全然良いのかもしれません。やったことないのでわかりませんが。けどなんか20時間くらい勉強して合格している人を見ると悔しくてたまりません笑
それと試験の申し込みのやつ、かなり早めに申し込んでおかないと埋まってしまいますね。それと10月からシラバスのバージョンが変わるというのもあって私は勉強する時間増やすために9月28日のギリギリの時の試験申し込みしたかったんですが遅かったので埋まってしまいました（泣）
これを次回からは反面教師としておきます。
というわけで今日はかなり尺が短かったですがこのへんで終わりたいと思います。
ご視聴ありがとうございました。
Java の同期制御(Semaphore、CountDownLatch)

CountDownLatch と Semaphore はどちらも Java の同期制御 を行うためのツールですが、用途や動作は異なります。ここでは、それぞれの違いと使い方について説明します。

## 1. Semaphore とは
Semaphore は、指定した数の「許可（permits）」を管理し、スレッドが許可の数を超えて同時にリソースにアクセスできないようにするために使います。例えば、Semaphore(3) であれば、同時に3つのスレッドまでしかリソースにアクセスできません。ある意味で「スレッドの同時アクセス制限」に適したクラスです。

特徴
許可を取得する (acquire) と、許可の数が減少します。
許可を解放する (release) と、許可の数が増加します。
同時にアクセスできるスレッド数を制御するために使われます。
使用例
```java
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final Semaphore semaphore = new Semaphore(3);

    public void accessResource() throws InterruptedException {
        semaphore.acquire(); // 許可を取得
        try {
            // リソースへのアクセス
            System.out.println(Thread.currentThread().getName() + " is accessing resource.");
        } finally {
            semaphore.release(); // 許可を解放
        }
    }
}
```

## 2. CountDownLatch とは
CountDownLatch は、あるスレッドが複数のスレッドの作業が完了するのを待機するために使われます。指定したカウントがゼロになるまでスレッドを待機させ、そのカウントがすべて消費されたときに他のスレッドを進行させます。ある意味で「一連のスレッドが完了するのを待つ」ために使います。

特徴
CountDownLatch は、初期化時に指定したカウントが 0 になるまで他のスレッドを待機させます。
countDown() メソッドを呼び出すことでカウントが減少し、すべてのカウントが 0 になると await() していたスレッドが進行します。
一度しか使用できません（カウントがリセットされないため）。
使用例
```java
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    private static final CountDownLatch latch = new CountDownLatch(3);

    public void performTask() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + " is performing task.");
        latch.countDown(); // カウントを1つ減らす
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatchExample example = new CountDownLatchExample();

        // 3つのスレッドが実行され、各スレッドがカウントを減らす
        new Thread(example::performTask).start();
        new Thread(example::performTask).start();
        new Thread(example::performTask).start();

        // すべてのスレッドが完了するまで待機
        latch.await();
        System.out.println("All tasks are completed.");
    }
}
```

## 3. Semaphore と CountDownLatch の違い

| 特徴 | Semaphore |CountDownLatch |
| ---- | ---- |---- |
|目的  |同時にアクセスできるスレッド数を制御  |複数のスレッドの完了を待機 |
|許可の増減  |acquire() で許可を取得、release() で解放  |countDown() でカウント減少 |
|リセット  |リセット	許可は解放されるたびに再利用可能  |カウントがゼロになると再利用不可 |
|同時アクセス数  |許可の数に応じてアクセス制限  |カウントに基づいて動作 |
|使用例  |リソースへの同時アクセス数制限	  |一連のタスク完了を待つ |


#### どちらを使うべきか

同時接続数やアクセス数の制御を行いたい場合（たとえば、同時に3つのスレッドしか特定のリソースにアクセスさせたくない場合）には、Semaphore が適しています。
複数のタスクが完了するのを待って、その後で処理を進めたい場合（たとえば、全スレッドが完了するまで待機するシナリオ）には、CountDownLatch が適しています。

## 4. 具体的な用途の違い
Semaphore: 接続制限、スレッドプールのように同時アクセス数を制限したい場合に便利です。たとえば、Tomcat の同時接続数をアプリケーションレベルで制御したいときに使えます。

CountDownLatch: 全ての処理が完了してから次に進むといった、イベントの同期や一斉開始・終了のタイミングを合わせたい場合に有用です。たとえば、全てのスレッドが初期化された後に処理を開始するようなシナリオで使用します。

---

このように、Semaphore と CountDownLatch は異なる目的を持つ同期制御メカニズムです。どちらを使うかは、プロセスの同時実行制御が必要か、あるいはスレッドの完了を待機したいかによって判断します。
TSubclassOfをSpawnActor時に使用する理由について【UnrealC++】

# 結論
特別な理由が無くC++のコード内でBPクラスを扱いたいならTSubclassOfを使おう！
ただなぜUClassを使わないほうがいいのかについては今回のような理由があるからぐらいは知っておいた方がいいと思います!
# 経緯
現在視聴しているUnrealC++動画内で以下のような説明をされました
>UnrealC++内でBPクラスをスポーンするにはTSubclassOf < T > を使用します。
SubclassOf<T>はTを格納するクラスではなくUClassを格納するクラスです。

次にTSubclassOf < T > について調べてみると
>UClass型を型安全に扱うことができる

https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/CoreUObject/Templates/TSubclassOf

以上からわかるのは動画の説明は誤りでUClass型の変数であれば別にBPを扱えるということ。
ではなぜわざわざTSubclassOfを使うのか、型安全に扱えるって具体的にどういう影響があるのかと当然の疑問がわきました。

# 実際どうなるのか
今回は以下の三つの方法でどのような状態になるのかを見てみます。
```cpp
//ABasePawn.h
//AProjectileは自作クラス
    //UClass
    UPROPERTY(EditDefaultsOnly, Category = "Combat")
	UClass* UclassPointer;
    //TSubclassOf
	UPROPERTY(EditDefaultsOnly, Category = "Combat")
	TSubclassOf<class AProjectile> ProjectileClass;
	//普通の宣言
	UPROPERTY(EditDefaultsOnly, Category = "Combat")
	AProjectile* ProjectilePointer;
```
上からクラス参照、クラス参照、オブジェクト参照ですね。最後に関しては感覚で書くとこういう宣言しちゃうなと思って載せました。

結果
- UClass宣言
UClassを継承したクラスすべてが候補なので当然ですが大量の候補が出てきます。今回参照したいBPクラス以外にも選択できてしまうためエラーの原因になりそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/dc9b6c33-97dd-e0f0-0555-04d6abbddf33.png)
- TSubclassOf < T > 
型安全の正体がわかりました。UClassで宣言した場合AProjectileクラス以外を選択しないことを祈るしかありませんが、TSubclassOf < T > を使用すると参照したいクラスのみがドロップボックスに現れてくれました。どちらを選んでもAProjectileクラスの機能は持っているのでエラーの原因にはならないでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/1a34de92-d201-a72f-97e9-ff23a47ab374.png)
- 普通の宣言
オブジェクト参照なのでレベルにオブジェクトとして配置されたものしか参照できません。今回のような弾丸を発射する用途にはむきませんね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366802/4323dbf6-13e9-2c6d-7c92-ab108d6f1565.png)

# 参考

https://forums.unrealengine.com/t/why-use-tsubclassof-and-not-just-the-class-itself/365690/2

https://dev.epicgames.com/documentation/en-us/unreal-engine/tsubclassof?application_version=4.27
ubuntu ユーザを docker グループに追加する。

## 環境
EC2 ubuntu

## 説明
(1)
グループに追加した場合は、ログインし直すか(`exit`)、 `newgrp docker`を実行すれば、反映させることができる。
グループから削除した場合は、`newgrp docker`は機能せず、ログインし直すしかない。
```
$ groups
ubuntu adm cdrom sudo dip lxd
$ docker-compose down
permission denied ...
$ sudo gpasswd -a $USER docker
Adding user ubuntu to group docker
$ docker-compose down
permission denied ...
$ newgrp docker
$ groups
docker adm cdrom sudo dip lxd ubuntu
$ docker-compose down
$ sudo gpasswd -d $USER docker
Removing user ubuntu from group docker
$ groups 
docker adm cdrom sudo dip lxd ubuntu
$ newgrp docker
$ groups
docker adm cdrom sudo dip lxd ubuntu
$ docker-compose down
$ exit
exit
$ groups
ubuntu adm cdrom sudo dip lxd
$ docker-compose down
permission denied ... 
```
(2)
`/etc/group`ファイルで、ユーザとグループの対応がわかる。
```
$ cat /etc/group | grep docker
docker:x:113:
$ docker-compose down
permission denied ...
$ groups
ubuntu adm cdrom sudo dip lxd
$ sudo gpasswd -a $USER docker
Adding user ubuntu to group docker
$ groups
ubuntu adm cdrom sudo dip lxd
$ newgrp docker
$ groups 
docker adm cdrom sudo dip lxd ubuntu
$  cat /etc/group | grep docker
docker:x:113:ubuntu
$ docker-compose down
$
```

(3)
下記の二つのコマンドは同じ意味
```
$ sudo gpasswd -a $USER docker
$ sudo usermod -aG docker $USER
```
Vueのデータとデータバインディング

## Vueのデータ
***親のコンポーネントからデータを渡すやり方***
***子が自分でデータを持つことも可能(今回は、こちらを)***
###### 子コンポーネントでデータをしてみる
下の記載をしたら *const* で定義した文字列が表示されている!
```vue:TestComponent.vue
<script setup>
const dataTest = "これは、子コンポーネントです";
<script>

<template>
  <p> {{ dateTest }} </p>
</template>
```
```vue:App.vue
<template>
  <TestComponent />
</template>
```

## データバインディング
***HTMLの要素とVueのデータを結びつける機能、4つある***

* 1.テキストバインディング
HTML内にテキストとしてデータを表示させる
```
<!-- 一つ目が、{{}}...マスタッシュ構文 -->(Vue3では、こっちが一般的)
<template>
  <p>{{ dateTest }}</p>
</template>

<!-- 二つ目が、v-textを使う -->
<template>
  <p v-text="dataText"></p>
</template>
```

* 2.属性バインディング
HTML要素の属性にデータを割り当てる
***v-bind:属性名="データの名前"*** と書く
```
<script setup>
const imageUrl = "/sample.png"
</script>

<template>
  <img v-bind:src="imageUrl" />
  <img :src="imageUrl" /> この様にで省略した書き方ができる。
</template>
```

* 3.イベントバインディング
HTML要素のイベント(クリックなど)と
Vueのメソッドを結びつける
***v-on:イベントの種類='メソッド名'*** と書く。
```
<script setup>
function myMethod() {
  consol.log("メソッド実行");
}
<script>

<template>
  <button v-on:click="myMethod">メソッド実行</button>
  <button @:click="myMethod">メソッド実行</button> @で省略できる
</template>
```


* 4.双方性バインディング
HTMLのフォームの要素とデータを双方向に結び付ける。
片方が変わったら片方にも反映する様になる。
<input>要素に ***v-model='データの名前'*** と書く。
データの宣言は ***ref関数*** を使用し、 ***const データの名前 = ref('');*** と書く。

<details open><summary>ref関数で値を宣言</summary>

その値を常に監視し、データが反映されるとすぐに画面に反映される様になる。
v-modelとセットで使うと覚える
</details>

```
# script部分ではref関数を使ってデータを宣言
<script setup>
import { ref } from "vue";
const name = ref("");
<script>
```

```
<template>
  <div>
    <label for="name">名前</label>
    <input type="text" id="name" v-model="name">
    <p>入力された名前: {{ name }}</p>
  </div>
</template>
```
Azure Static Web AppのUIレンダリングリソースはどこからくるの？という話及びその問題

# これは
首題の通りAzure Static Web App(以下SWA)のUIレンダリングに必要なコンピューティングリソースと課金を巡る地を這い泥水をすするようなインフラエンジニア兼アーキテクトの戦いの記録。

これを読む人はSSRやユニバーサルレンダリング等の動的なページ作成について何かを知っていないと何書いてるのかわからないかも。

AzureでもAWS(Amplify, ECS, なんだったらEC2)でもいいので実際にこれらをデプロイして運用してみたことがあるのであれば理解ははやいとおもいます。

# SWAとは
機能としてはフロントとよばれるUIの開発や運用が楽になるための便利なサービス、のはず。
AWSでいうところのAmplifyのようなもの。

具体的には下記のような機能だと思います。

1. UI資材のホスティング
1. なんだったら動的なレンダリングに必要なコンピュートリソースのマネージメントもしますよ？
1. フロントから使うAPIも実装していかない？
1. 認証も仲介するよ？
1. 便利な開発ツールとかあるよ？
1. デプロイも面倒みるよ？

# ほんとうに？どうするの？

いたれりつくせりですね、お高いんでしょう？

いいえ、サーバレスでも安い部類ですよ！

言語的なフレームワークはnext.jsやnuxtjs(3)とかvueとかreactとかいろいろあるけれど、これらが目指すところはたぶん全部一緒の理想郷で作ってるひとたちとアプローチの仕方が少し違うだけ・・のようにみえる。

さて、これらをデプロイするときに、動的なレンダリングを選択するかどうかがある。

SSR, ゆにれん等の動的なレンダリングを選択しない場合はここから先の問題はおこらない。

動的なレンダリングをSWA上で選択したとき、めんどくさいことがはじまりました。

# 問題とは
SWAが提供する３つのコンピュートリソースについて下記。

1. 静的にビルドされたUIを配る
    * どこかのストレージにビルドされた静的なファイルを置いてからそれをHTTP(s)プロトコルで配るという機能。リクエストの数や送信容量的な従量課金スタイル。
    * これだけをやる常時動いてる何かがクラウド上にあり、そこにのっかっていると思いましょう
    * オンプレでいうところのApacheでもNginx
    * AWSでいうところのCloudFormation+S3
1. UIを動的にレンダリングする
    * なにかしらレンダリングするためのプログラムを起動、あるいは限定された生成コードをパートタイム的に実行して対応するもの
    * AWSでは後ろでLambdaかFargateで動いていると思う、どういう形で動いているかはよくしらない
1. 先述のフレームワークで実装されたAPIをホスティングする
    * AWSではたぶんFargateで、常時起動しているかどうかはしらない

さて..SWAでコンピュートリソースの管理をAzureに預けた場合問題がおこるとしたら２および３。
サービスプラン(SKU)は `Free` および `Standard`。

## 2のUIを動的にレンダリングする部分の問題
コールドスタートが発生する。
これは観察したところレンダリングサーバが起動する時間と近似
うちだと１０秒以上かかりますし、アクセスがあるかないかは関係がない。

１０秒待たされるようなサイト、また行きたいと思いますか？

## 3のAPIの問題
こちらもコールドスタートがひんぱんに発生する。

## 2と3を一気に解決する素敵なソリューションはあるのだが・・・
サービスプランに `Dedicated` というものがあり、Standardよりも固定費用が１万円近く跳ね上がるけど、常時起動のUIレンダリンとAPIのためのリソースを提供してくれる。

**だがしかし** それはプレビュー機能であり、１サブスクリプションに１個しか作成できなという結構どでかい制約がある。

複数このプランのフロントがほしいと思ったら詰む。
１サブスクにつきこれ１個でいいと言い切れるアーキテクチャであるのなら、最適解だろう。

# 結局こうした
APIは最初からそれ用のバックエンドを用意してくれと言われて用意していたので、Functon Appにレンダリング部分をぶちこんだ、常時起動のためプレミアムプラン以上が必要だけど。

具体的には nuxt3でnitroサーバをSWAかFunction Appに手軽にぶちこむ方法があるのでそうしたという話。
FunctionでかんたんにやれないならWeb Appsになるんじゃないかな・・

ただし・・・

インフラをCDKTF(Azurerm Provider)で作成しているけど SWAの `Dedicated` プラン、作れないじゃん？
また、SWAのレンダリング部分にApp Settingsの環境変数あたらないじゃん？

その他細かい地雷いくつかの地雷があり

正直SWAやめたいと思っていたのがスリーカウントを超えたので、一気にFunction Appやってしまった次第。

というのも、フロントエンドやAPIバックエンドよりもコンシューマ側にCDNとしてFrontdoor置いてるんだよねー
オリジンとか仕事すればなんでもいいというコンセプトが切り替えの、特に決断を容易にしたと思います。

# 最後に

（ラップ調）こんな濃い経験させてくれる御社に感謝

Azureエンジニアとしてなんか立って歩けるようになりつつあります（誰かいい開発経験させてくれるとこ雇ってくだしぁ・・）
【2024年9月時点】Servicenowの開発環境を個人で作成したら、全く理解できないUIで困惑したの巻

話題のServicenowについて、もう少しテクニカルな運用を知りたい・・・！
と思いWebを漁っていたらなんと！個人で開発環境を作成できるらしいじゃないか！

ということで早速入れてみて検証したら

**全然知らない画面なんだけど・・・？**

となった経験を紹介しますｗ

## とりあえず開発環境を準備
以下記事を参考に作成しました

https://mekeblog.com/servicenow_20210703/

## インスタンス払い出し後に気づく、違和感・・・
あれ？なんか掲載されている画像と違う・・・？
【掲載されている画像】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/263040ad-241b-6a5d-17e9-1c3a4a184cfb.png)

【実際のページ表示】
![2024-09-23_01h33_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/51b952e4-8edb-2a45-15d1-1e8b482f78d0.png)

**なにこれ？というか「Creator Studio」ってなに！？
(え、別のサービス入れちゃった感じ？ｗ)**

## 真相
実はServicenowのバージョンアップによって以前と全く違うUIになってしまっている、ということらしい

会社のVer.は把握していないが、この開発環境は「Xanadu」というバージョンとのこと
※過去、Slackも大規模バージョンアップしてUIが大幅変更されて使いづらい！となったことがあったが、あれより強烈すぎるぞ・・・

## せっかくなので開発環境の日本語化をご紹介
この記事を書く前に執筆時点で最新の日本語化手順を以下にご紹介します

参考までに旧手順はこちら

https://mekeblog.com/servicenow_20210627/

### とりあえず開発環境に入る
まずは「Start Building」をクリックしてインスタンスにアクセスする
（英語苦手なのでServicenowさん何とか日本語化導入してくれませんか・・・><）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/c55690ea-4ce8-64c6-e579-b65ac7e7bf07.png)

### Pluginをインストールするページにアクセス
以下画像の赤枠線を参考にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/914423d4-3e77-9a3c-6984-2dd2fbff81ee.png)

### pluginをインストール
検索ウィンドウに「jap」と入力
検索結果に「I18N: Japanese Translations」が表示されれば、それをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/3442ae2c-0497-02dd-672c-5c6e0f829eec.png)

次の画面で「Install」のボタンがあるので、これをクリック
※ちなみにインストールは20～40分掛かるらしい、ケースによっては３時間掛かっているらしいけど・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/b45c5e97-e2d8-c231-51d6-06afe15ea43e.png)

【Tips】
どうやら、プラグインはスケジュールしてインストールすることもできる様子
管理者的には負荷分散で夜間実行などが出来るのは大変助かる次第です・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/711c2b3a-8819-8cdf-c667-eda9268b5713.png)

## あとは待つ、それだけだ！
後はひたすら待つだけですｗ
個人的な感覚ですが、意外と早いかも？（キャプチャ撮った後、すぐに全体進捗が22％になっていた）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2499306/95e5f474-540d-5797-a038-53d12c118acb.png)

## まとめ
今回はServicenowの大規模UI変更による困惑についてご紹介しました。
SaaSあるあるですが、ここまで変更が大きいともはや「別のサービス間違えて入れちゃった！？」となるレベル・・・
お恥ずかしい話、今回その思考に陥ってインスタンスを２回消し飛ばしましたｗ

Servicenowについて、今後開発環境を色々触ってみようと思いますので、また紹介記事を執筆します！

本日も本記事をご覧いただき、ありがとうございました！
psコマンドで物理メモリ(rss/resident set sizes) と仮想メモリ(vsz/virtual memory)を学ぶ

RSS = 物理メモリ
VSZ = 仮想メモリ

配列を作ると仮想メモリを取得する。が、実際に値は入れないので物理メモリは消費されない。

それを確かめる。

```rb
[root@vbox ~]# cat vsz.c
#include <stdlib.h>
int large_array[10000000];
int main(int argc, char *argv[]){
  system("ps l"); /* note: letter l */
  return large_array[0];
}
[root@vbox ~]# gcc -o vsz vsz.c && ./vsz
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0    1222     684  20   0   4792  3584 do_sel Ss+  tty1       0:00 -bash
4     0    1259    1258  20   0   4800  3456 do_wai Ss   pts/0      0:00 -bash
0     0    1306    1305  20   0   4680  3584 do_sel Ss+  pts/1      0:00 -bash
0     0    1389    1259  20   0  41188   896 do_wai S+   pts/0      0:00 ./vsz   <---
4     0    1390    1389  20   0   7440  2688 -      R+   pts/0      0:00 ps l

配列を一桁増やす

[root@vbox ~]# grep large vsz.c
int large_array[100000000];
  return large_array[0];
[root@vbox ~]# gcc -o vsz vsz.c && ./vsz
F   UID     PID    PPID PRI  NI    VSZ   RSS WCHAN  STAT TTY        TIME COMMAND
4     0    1222     684  20   0   4792  3584 do_sel Ss+  tty1       0:00 -bash
4     0    1259    1258  20   0   4800  3456 do_wai Ss   pts/0      0:00 -bash
0     0    1306    1305  20   0   4680  3584 do_sel Ss+  pts/1      0:00 -bash
0     0    1398    1259  20   0 392752  1024 do_wai S+   pts/0      0:00 ./vsz   <---
4     0    1399    1398  20   0   7440  2688 -      R+   pts/0      0:00 ps l

さらに一桁増やす

[root@vbox ~]# grep large vsz.c
int large_array[1000000000];

[root@vbox ~]# gcc -o vsz vsz.c && ./vsz
Segmentation fault
```

ちゃんと仮想メモリをprocessが確保してる && 物理メモリは使われてないことがわかった。

# mac/linuxで使える、rss/vszを表示するコマンド

```rb
 ps -A -o rss= -o vsz= | awk '$2!=0 {printf "%s\n", $1/$2}' | sort -n
```
sudo コマンドを使うときの環境変数の挙動

## 目的
`sudo` コマンドを使うときは、オプションによって、環境変数が引き継がれたり引き継がれなかったりするので、重要な事項を抑える。

## 環境
EC2 ubuntu

## 具体例

`sudo` の環境変数は `ubuntu` ユーザの環境変数とは異なる。
`sudo` の環境変数は主に `/etc/sudoers` に定義され、PATH環境変数は `/etc/environment` に定義されている。
`sudo -i` は `root` としてログインし直すので、`sudo` のみの場合の環境変数に加えて、`/root/.bashrc`の環境変数もロードする。
`sudo -E` は、PATH以外の環境変数を引き継ぐ。

環境変数は `-E` や `--preserve-env` オプションによって引き継ぐことができる。
```
$ export MY_TEST_ENV='abcde'
$ printenv | grep MY_TEST_ENV
MY_TEST_ENV=abcde
$ sudo printenv  | grep MY_TEST_ENV
$ sudo -i printenv  | grep MY_TEST_ENV
$ sudo -E printenv  | grep MY_TEST_ENV
MY_TEST_ENV=abcde
$ sudo --preserve-env=MY_TEST_ENV printenv | grep MY_TEST_ENV
MY_TEST_ENV=abcde
$ sudo --preserve-env=PATH,MY_TEST_ENV printenv | grep MY_TEST_ENV
MY_TEST_ENV=abcde
```

PATH 環境変数は、`-E` オプションによって引き継げない場合がある。（`/etc/sudoers` の `Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"` という記述が原因）
`sudo` でも PATH 環境変数を引き継ぎたい場合は、下記のように `--preserve-env=PATH` を使うか、[この記事](https://genzouw.com/entry/2021/01/27/213700/2152/)で提案されている方法を使う。
```
$ printenv | grep PATH
PATH=/home/ubuntu/.vscode-server/cli/servers/Stable-38c31bc77e0dd6ae88a4e9cc93428cc27a56ba40/server/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ sudo printenv | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
$ sudo -i printenv | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
$ sudo -E printenv | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
$ sudo --preserve-env=PATH printenv | grep PATH
PATH=/home/ubuntu/.vscode-server/cli/servers/Stable-38c31bc77e0dd6ae88a4e9cc93428cc27a56ba40/server/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
$ sudo --preserve-env=MY_TEST_ENV,PATH printenv | grep PATH
PATH=/home/ubuntu/.vscode-server/cli/servers/Stable-38c31bc77e0dd6ae88a4e9cc93428cc27a56ba40/server/bin/remote-cli:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
```

## ついで
(1)
`echo` は先に環境変数が展開されるので、`sudo` コマンドは影響しない。
```
$ export MY_TEST_ENV='abcde'
$ echo $MY_TEST_ENV
abcde
$ sudo echo $MY_TEST_ENV
abcde
$ sudo -i echo $MY_TEST_ENV
abcde
$ sudo -E echo $MY_TEST_ENV
abcde
$ printenv | grep MY_TEST_ENV
MY_TEST_ENV=abcde
$ sudo printenv | grep MY_TEST_ENV
$ sudo -i printenv | grep MY_TEST_ENV
$ sudo -E printenv | grep MY_TEST_ENV
MY_TEST_ENV=abcde
```

(2)
```
$ whoami
ubuntu
$ sudo whoami
root
$ sudo -i whoami
root
$ sudo -E whoami
root
```
`sudo -i` は `root` としてログインし直すので、実行ディレクトリは下記のように `/root`となっていることにも注意されたい。
```
~/test$ pwd
/home/ubuntu/test
~/test$ sudo pwd
/home/ubuntu/test
~/test$ sudo -i pwd
/root
~/test$ sudo -E pwd
/home/ubuntu/test
```

## 参考

https://genzouw.com/entry/2021/01/27/213700/2152/

https://qiita.com/TsuyoshiUshio@github/items/041ef4840d4bc1546c06

https://tech.unifa-e.com/entry/2019/05/23/172424

https://blog.denet.co.jp/sudocommand-path-diff/?doing_wp_cron=1727019865.2604761123657226562500