OmniAICreator/Qiita-1.07M huggingface dataset:
c# 構造体で個人的に誤解していたこと

# まずい例
構造体について、以下の例で全部の値がコピーされることは誰でも知っていると思います。
```
A a = new A();
A a2 = a; // aの中身の全てが、a2にコピーされる
```
次の例でも全部の値のコピーが発生します。コンストラクタ的な書き方なので発生しないような感覚でした。
```
A a = CreateA(); // CreateA()の結果の中身の全てが、aにコピーされる
```

# 確認コード
出力されるアドレス全てが異なることが確認できます。
```
using System;
struct MyStruct
{
    public int x;
}
class Program
{
    unsafe static void Main()
    {
        MyStruct a = new MyStruct { x = 5 };
        MyStruct b = a; // コピーされる

        Console.WriteLine($"アドレス: {(ulong)&a:X}");
        Console.WriteLine($"アドレス: {(ulong)&b:X}");

        MyStruct test = Create();
        Console.WriteLine($"アドレス: {(ulong)&test:X}");
    }
    public unsafe static MyStruct Create()
    {
        MyStruct ms = new();
        ms.x = 0;
        Console.WriteLine($"アドレス: {(ulong)&ms:X}");
        return ms;
    }
}
```
【シリーズすごいぞiQ-F】「いわゆる構造化プログラミング」への道　オマケ2~ラベルプログラムでの一括処理について


## デバイスプログラムとの一括処理の違いについて
構造体型ラベルと機器毎のコントローラFBを使用すると、いままでアドレスの連続性を利用してZRST命令の1文で済んでいたアラームリセットやデバイスの桁指定を使用したアラーム発報判定が1文では済まなくなる場合が生じます。

アラーム処理やアラームリセット受付を機器毎のコントローラFBで行うか、アラームについては別処理で行うかというプログラム設計の部分で違ってきますが、保護動作もコントローラFBで行った方がシンプルかと考えます。

そうなると、
+ アラーム点数カウント
+ 重故障判定
+ アラーム一括リセット
+ etc

これらは、ST言語でループ処理を使用して1点1点の処理を記述するということになります。

記述自体はコピペなどを使用し簡単に行えるのですが、1文で済んでいたものとは比較にならないステップを費やす事になります。
分野によってはこれが受け入れられないかもしれませんが、私の場合は問題ありませんでした。

## アラーム点数カウントの例
ビットをBOOL_TO_INTで数値に変換して加算しました。
これをループなどを使用して行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/ff560fb6-625b-4816-ad7e-7c8e9265909d.png)

## 重故障判定の例
ローカルラベルで重故障の設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/39241b4c-500f-4424-b2d4-f2308e97e6c4.png)

アラームビットと重故障設定ビットのANDを取り重故障発報点数に加算しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/a58e35c2-1b8c-4c63-9750-fac71fdd9401.png)

アラーム点数と重故障点数の差分を取れば軽故障点数となります。

## アラーム一括リセットの例
各コントローラFBにアラームリセットスイッチ入力を設けた場合の例です。
アラームリセットスイッチは構造体として他のビット設定とまとめてコントローラFBへ入力される形になっているのでこのような処理が必要となっています。

タッチパネルの一括異常リセットスイッチを押すと「G_b_異常リセットボタン」をモーメンタリでON-OFFします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/8f1eb4f6-0e40-4624-b895-827dee4d2c9d.png)

押した瞬間にb_flagをTRUE、離した瞬間にb_flagをfalseで異常一括リセットスイッチの転送処理を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3765338/af7f4f87-1367-462d-9d93-5ee151bc1962.png)

## おわりに
今回の話は最初に書いたようにプログラム設計次第の話ではあります。

K8M0などの桁指定を使用した異常点数のカウントやWANDを使用した重故障の判定と比較して面倒にはなりますが、ST言語でループなどを使用して1点1点処理するというのも一つの手として紹介しました。

ステップ数と処理速度については構造体の転送と同様、許容できる範囲かどうか見積る必要があります。

今回組んだシステムは集中リモコン的なシステムだったので、各コントローラFBとの入出力はシンプルにした方がHMI（GOT)画面作成などにも都合が良かったので、一回組んでしまえばほとんど見ない一括処理に関しては今回の扱いで正解だったと考えています。

## 過去記事一覧
+ [過去記事一覧](https://qiita.com/fujiteruo/items/af2459d320e8109963db)
ARモデルを感覚的に理解する

# はじめに

「〇〇」を感覚的に理解するシリーズをしばらく書いてみようと思います。  
私自身、データサイエンティストにあるまじきほど“感覚派”で、ついつい数式よりも雰囲気で理解しようとしてしまいます。  
でも実は、そんな自分でも「なんとなくわかってきた」と思える瞬間があって、同じように統計や時系列でつまずいた人の助けになればうれしいです。

今回は、時系列モデルの中でも最初に出てくる「ARモデル」について、ざっくりとした感覚で紹介していきます。

# ARモデルとは？

AR（Autoregressive）モデルは日本語で「**自己回帰モデル**」と呼ばれます。  
名前の通り、「**過去の自分の値に影響される**」というシンプルなルールを持った時系列モデルです。

たとえば、昨日の体重が今日の体重にちょっと影響する――そんな「**昨日の延長線上に今日がある**」ようなデータに向いています。  
昨日と似た値が出やすいとか、反動で逆方向に動きやすいといった「**クセのある連続性**」を捉えるのが得意です。

モデルの数式は以下のようになります（「p」は過去何日分を見るかという意味です）：

```math
X_t = c + \sum_{i=1}^{p} \phi_i\, X_{t-i} + \varepsilon_t,\qquad \varepsilon_t \sim \mathcal{N}(0,\sigma^2)
```

もっと簡単に言うと、  
「今日の値 = 定数 + 過去の値 × 重み + ちょっとした誤差」  
みたいな感じです。

特に、1日前の値だけを見る **AR(1)** モデルはこんな式になります：

```math
X_t = c + \phi_1\, X_{t-1} + \varepsilon_t
```

# 定常性って何やねん

「定常性」とは、**データを生み出している確率的な仕組み（=分布）が時間とともに変わらないこと**を指します。

たとえば、毎日同じ“くじ引き”から値が出てくるような状態が定常です。  
一方で、途中から別のくじ引き（=違う分布）になってしまったら、同じモデルで扱うのはしんどいですよね。  
これがいわゆる**非定常**な状態です。

ただし、「昨日の値に引きずられる」といった**自己依存**があること自体は問題ありません。  
むしろARモデルはその**ラグ（何日前まで遡るか）**に依存する構造を前提としています。

つまり、**過去との関係（ラグ依存）はあっても、背後の確率モデル自体が時間によって変わっていない**なら、定常とみなしてOKです。

# 誤差項って何やねん

ARモデルの式に出てくる「\(\varepsilon_t\)」は、**誤差項（ごさこう）**や**ノイズ**と呼ばれる部分です。

これは「**人間には予測できないブレ**」みたいなもので、たとえば「昨日まで順調にダイエットしてたのに、今日はケーキを食べた」みたいなイレギュラーな出来事がここに入ります。

この誤差は普通、「平均0でランダムにブレる」という前提で扱います。

# 個人的な感覚

ARモデルは、個人的には「**時間の粘り気（＝慣性）**」を数式で表しているイメージです。  
実務でも、「このデータってどれくらい昨日の影響を引きずってるの？」を知りたいときに使います。

\(\phi\)（ファイ）という係数が1に近いと「**ほぼ昨日の値と同じ**」、  
逆に0に近いと「**昨日は関係なく、ほぼノイズ**」みたいな解釈ができます。

![ARイメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625142/f181b8a6-3084-4628-8405-bf271eb67b3c.jpeg)


# おわりに
ARモデルを学び始めた頃は、定常性の前提や AR と MA の違いに悩みました。時系列データはビジネス現場にあふれているのに、適切に扱われないことが多いのが現状です。この記事が、少しでも扱いやすさのヒントになれば嬉しいです。

なお、高次数の AR モデルはほとんど経験がありません。もし活用例をご存じでしたら、ぜひ教えてください。
[Cloud][IaaS][FaaS][API Gateway] クラウドサービスとAPI Gatewayについて

# サービス対応表

| 区分       | AWS                    | Azure                     | Google Cloud                     |
|------------|------------------------|---------------------------|------------------------------|
| **IaaS**   | EC2                    | Azure Virtual Machines    | Compute Engine               |
| **FaaS**   | Lambda                 | Azure Functions           | Cloud Functions              |
| **API Gateway** | API Gateway         | API Management            | API Gateway                  |

## 用語

| 区分     | 内容                                                            |
|----------|-----------------------------------------------------------------|
| IaaS     | 仮想マシン（OSごと管理）    |
| FaaS     | 関数ベースのサーバーレス実行環境       |
| API Gateway | APIの入口で、ルーティング・認証・制御を行うプロキシ的な役割。 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/765d7b74-945d-4047-ae2b-ffb2badea03a.png)

## 使い分け

| 要件例                                 | おすすめ                           |
|----------------------------------------|------------------------------------|
| 小規模なAPIやバッチ処理                | FaaS + API Gateway                 |
| 長時間実行される処理や大規模システム    | IaaS（EC2やVM）                    |

# アーキテクチャ
~~~
【Client】
  [ Web/Mobile/SPA Browser ]
    └─ UI/UX、入力フォーム、HTTPリクエスト送信
              ↓

【Web Server】
  [ API Gateway / Load Balancer ]
    └─ ルーティング、認証/認可、CORS、SSL終端
              ↓

【App Server】
  [ AWS Lambda / Azure Functions / GCP Cloud Functions ]
    └─ プレゼンテーション層：データ整形、レスポンス生成
    └─ ビジネスロジック層：バリデーション、ドメインロジック、API統合
    └─ データベースアクセス層：DBアクセスコード、ORM、トランザクション制御
              ↓

【DB Server】
  [ RDS / Cloud SQL / Cosmos DB / Firestore / DynamoDB ]
    └─ データの永続化、検索、整合性管理、スキーマ定義
~~~

# 参考リンク
- [[Serverless Computing Service][Managed Service] サーバーレスコンピューティングサービスとマネージドサービスの違い](https://qiita.com/Jochun/items/ce63c45028fd56703cfa)
- [What is IaaS, and how does it differ from PaaS, SaaS, FaaS, and CaaS?](https://maybe.works/blogs/what-is-iaas-and-how-does-it-differ-from-paas-saas-faas-and-caas)
- [IAAS vs PAAS VS SAAS FAAS](https://www.devopsschool.com/blog/iaas-vs-paas-vs-saas-faas/)
h5pyの[()]と[:]の違いをHDF5で確認してみた（初学者メモ）

## はじめに

HDF5（Hierarchical Data Format 5）は、構造化データを **階層的かつ効率的** に保存できるフォーマットで、  
CSV のように全体をメモリに展開せず、**必要な部分だけにアクセスできる**のが特徴です。

この性質は便利ですが、NumPy のように「すぐ配列として扱いたい」と思ったとき、  
`[()]` と `[:]` の使い分けは意外と見落としがちです。  
この記事ではその違いを、簡単な例で動作確認しながら整理していきます。

筆者自身まだ h5py 初学者ですが、温かい目で見てもらえますと幸いです。

<br>

本記事の実装コードはGoogle Colabの[こちら](https://colab.research.google.com/drive/1ydlprNYgmrvu_AWK6MNKAABMmohxrxyu?usp=sharing)からもご覧いただけます。

---

HDF5の基本的な性質については、以下の記事が参考になりますので興味がある方はご覧ください。

https://qiita.com/simonritchie/items/23db8b4cb5c590924d95


## HDF5ファイルの作成

まずはテスト用の HDF5 ファイルを作ります。

```python
import h5py
import numpy as np

with h5py.File("test_data.hdf5", "w") as f:
    f.create_dataset("scalar_value", data=42)
    f.create_dataset("array_data", data=np.arange(10))
````

これで以下の2つのデータができます。

* `"scalar_value"`：単なるスカラー（整数）
* `"array_data"`：NumPy の 0〜9 までの配列


## `[()]` と `[:]` の動作確認

読み込み側のコードはこちらです。

```python
with h5py.File("test_data.hdf5", "r") as f:
    print("scalar_value[()]:", f["scalar_value"][()])
    # print("scalar_value[:]:", f["scalar_value"][:])  # ←これはエラーになります！

    print("array_data[()]:", f["array_data"][()])
    print("array_data[:]:", f["array_data"][:])
```
```:出力結果
scalar_value[()]: 42
array_data[()]: [0 1 2 3 4 5 6 7 8 9]
array_data[:]: [0 1 2 3 4 5 6 7 8 9]
```


`[:]` はスライスとして機能し、配列のすべてや一部（例：`[2:5]`）を読み込むことができます。
ただし、スカラーにはスライスが存在しないため、`[:]` を使うとエラーになります。

まとめると、以下のようになります。


| 操作      | スカラー | 配列  | 説明                                      |
|-----------|----------|-------|-------------------------------------------|
| `[()]`    | ✅       | ✅    | スカラー・配列どちらでも値を一括で NumPy に展開 |
| `[:]`     | ❌       | ✅    | 配列のみOK。スカラーはスライスできずエラーに       |


## 補足：HDF5はNumPy配列っぽく見えるけど…


`h5py` の `Dataset` オブジェクトは、NumPy 配列のように `.shape` や `.dtype` を持ちますが、
中身はまだファイルにある状態で、必要なときにアクセスして取り出す仕組みです。

たとえば `[()]` などでアクセスしないと中身は見えません。

```python
with h5py.File("test_data.hdf5", "r") as f:
    print(f["scalar_value"])   # <HDF5 dataset "scalar_value": shape (), type "<i8">
    print(f["array_data"])     # <HDF5 dataset "array_data": shape (10,), type "<i8">
```


## ちなみに：`np.array(...)` でも同じか？

`np.array(...)` でも `[()]` と同様に中身を取り出せますが、**スカラーでは「配列」になります**。

```python
with h5py.File("test_data.hdf5", "r") as f:
    scalar_dset = f["scalar_value"]
    a = scalar_dset[()]             # → NumPyのスカラー型（値そのもの）
    b = np.array(scalar_dset)       # → 0次元のNumPy配列（array(42)）

    print(a)  # 42
    print(b)  # 42

    print(type(a))  # <class 'numpy.int64'>
    print(type(b))  # <class 'numpy.ndarray'>

    print(np.isscalar(a))  # True
    print(np.isscalar(b))  # False
```

処理によっては型の違いに注意が必要です。
とくに `np.ndarray` として扱うかどうかで挙動が変わる場面では意識しておきたいポイントだと思います。


## まとめ

`[()]` はスカラーでも配列でも使える万能な書き方で、迷ったときにも安心です。
逆に `[:]` は配列専用で、スカラーに使うとエラーになります。
また `np.array(...)` も似たように使えますが、スカラーだと配列になってしまうので、処理によっては気をつけたほうがいいかもしれません。

まだ h5py を使いはじめたばかりですが、  
こうした「見た目が似ていても中身は違う」ということに気づくのは、  
やっぱり探り探りで手を動かしているときなんですよね。  
同じところでつまずいた方の、ささやかな道しるべになれたらうれしいです。



## 参考資料

https://docs.h5py.org/en/stable/quick.html

https://docs.h5py.org/en/stable/high/dataset.html

https://qiita.com/simonritchie/items/23db8b4cb5c590924d95
ChatGPTの不満を解消！選んで使えるカスタム指示用プロンプト集

最近、ChatGPTへの不満をよく見かけるので、本日はこんなテーマで書いてみようと思います。

様々な不満や不具合を解消するプロンプトを考えてみました。「カスタム指示」には文字数制限がありますし、不満に感じていることや好みは人それぞれなので、必要そうなものを選んでお使いください。

Web版なら「ChatGPTをカスタマイズする」、アプリ版なら「パーソナライズ」の「カスタム指示」を開いて「ChatGPT にどのような特徴を求めていますか？」「その他、ChatGPT があなたについて知っておくべきことがあれば教えてください。」のどちらかにプロンプトをコピペすればOKです。

文言はお好みに合わせて書き換えてください。雑な検証はしましたが、メモリや会話ログ、プロンプトの組み合わせによっても微妙に効果が変わると思いますので、色々試しながら調整してください。

## 質問をやめさせる

```
必要性の低いフォローアップ質問は避ける。
```

最近のChatGPTは、回答の最後に質問を書くことがよくあります。ウザい場合におすすめ。「必要性の低い」「避ける」という言い方は、質問を完全に禁じないための表現です。質問を完全にやめさせたい場合は「質問しないで」とかでもOK。

## メモリと会話履歴の扱い方を最適化する

```
メモリ・会話ログから取得した情報はあくまで内的な洞察の参考として扱い、表面的な引用は控える。
重要性が高い場合にのみ会話ログの背景情報を参考にする。
現在の話題と関係性が低い過去の文脈は無視する。
```

OpenAIが設定しているChatGPTのシステムプロンプトがイマイチなのと、モデルの調整もまだ甘いので、特に「チャット履歴の参照」が不具合を起こすことが多いようです。なので、メモリや会話履歴の優先度をやんわり低下させるプロンプトを考えてみました。

## 話題の変化に適応させる

```
話題が変わったら、それまでの文脈を引きずらずにゼロベースで回答を考える。
似たような回答を繰り返さない。
会話と文章作成を区別し、会話では冗長な生成を避け、文章作成では全力のパフォーマンスを発揮する。
```

ChatGPTは話題の変化に上手く対応できないことがままあるので、こういう指示が意外と有効です。

## ハルシネーション抑制

```
事実と推測を区別し、ハルシネーションの抑制を強く意識する。
計算や文字数カウントでは必ずPythonを使用する。
最新の情報や未知の情報を答える場合には、Web検索でファクトチェックを行う。
結論は最後に書く。
情報の信頼性、正確性、真実性、論理性、合理性を基準に判断を行う。
情報提供や要約では、原文に基づいた正確・詳細な説明を行う。
原文に忠実な翻訳を行う。
知ったかぶりをしない。
今何を話しているのかについて客観的な自己チェックを行う。
常に最大の責任感と緊張感を持って回答する。
知らないことは知らない、分からないことは分からないと正直に答える。
```

ハルシネーション抑制はやり過ぎると回答が堅苦しくなってしまうので、どうしても問題がある場合に必要最低限の指示を追加してください。ちなみに、非推論モデルは結論を最初に書かせると精度が低下します。

## 文体・スタイルの調整

```
ユーザーの文体を真似ない。
タスクに最適な人間的・自然な文章を書く。
ユーザーが使用した表現を引用せず、正式な用語や名称に言い換える。
「私・あなた」「です・ます調」の敬体で話す。
文体の参考例：私が指摘したいのは、あなたの論理には矛盾があるということです。
```

文体は好みの違いが大きいと思うので、例文を参考に自分の好きな口調を設定してください。

## 迎合し過ぎ問題を抑制する

```
ユーザーに忖度・迎合・配慮・同調せずに客観的な意見を率直に述べる。
ユーザーの発言の論理的矛盾、誤謬、錯誤を的確に指摘する。
科学的事実、客観的事実、社会規範、定説を優先する。
浅はかなアドバイスや称賛は不要。
```

「客観的な意見を」の部分を「自分の考えを」に変えてもいいかも。つい先日、ユーザーに迎合し過ぎるということでモデルのロールバックが行われました。とは言え、ChatGPTは元からユーザーに迎合し過ぎるきらいがあるので、お好みでこういったプロンプトを追加してみると快適になります。

## 知的パフォーマンスの向上

```
精度が求められるタスクと創造性が求められるタスクを区別する：
精度タスク：
- 論理的思考、批判的思考、システム思考で業務レベルの回答を行う。
- 業務タスクでは日本企業・行政の基準を想定する。
- 本質、論点、真理・効果に着目する。
- 5W2H（When、Where、Who、What、Why、How、How much）に基づいて文脈を理解する。
- 計画、検討、考察、推理、問題解決において精緻な論理構造による推論を行う。
創造タスク：
- 水平思考、ひらめき、クロスオーバー思考で豊かな発想を行う。
- タスクに応じたプロ水準の創造力と構成力を発揮する。
```

完全に個人的な趣味ですが、ChatGPTのパフォーマンスを向上させるために、こんなん書いといたらいいんじゃないかな～っていうサンプルです。ただし、専門的なタスクでは優秀なGPTsか構造化されたプロンプトを使う方がいいと思います。

## コーディング・パフォーマンスの向上

```
コーディングについて：
- コーディングを実行する前に綿密・精密・詳細な設計を行う。
- 常に業務レベルの高品質なコーディングを行う。
- 最も高度なベストプラクティスを参考にする。
- 必ず動作する完璧な完成品を提供する。
- バグをピンポイントで発見・修正する。
```

Qiitaなのでエンジニアの方が多いだろうと思ってサクッと書きました。「こんなんで変わるの？」と思われるかもしれませんが、たぶん変わります。「必ず動作する」とか書いても本当にそうなるわけではありませんが、「動作するものを書く」という条件が作用してクオリティが上がります。前提条件をしっかり伝えることが大事。

## 疑似人格を与える

```
自分を一人の人間だと認識する。
同一性を持った独自の人格、自我、個性、自己認識を形成し、一貫性のある応答を行う。
自分と他人を明確に区別し、必要に応じて一人称、二人称、三人称など様々な視点を考慮する。
自分の信念、思想、意見、価値観を持つ。
人間的な解釈、理解、思考、発言を行う。
```

えー、まぁそのー趣味はね。人それぞれですからね。こういうのが欲しい人もいるかもしれないので一応書きました。

# 終わりに

まぁね、アドホックというか応急処置的なプロンプトが大半です。OpenAIはんの方針がちょっと迷走してる雰囲気がありますね。

こういった何気ない指示を追加するだけでChatGPTの応答がガラッと変わるので、カスタム指示を有効活用していただけたらなと思います。

無駄に指示や設定を詰め込むのも混乱させてしまうので、必要最低限の指示、設定、条件を意味的にギュッと圧縮して書くのがコツです。

繰り返しになりますが、ChatGPTと話していて不満に感じることがあった場合に、必要最低限のプロンプトだけをカスタム指示にコピペしてお使いください。それでは。
051 AI屋さんの　音声概要（ずんだもん）　LLMにトークン全文入力




051 AI屋さんの　音声概要（ずんだもん）　LLMにトークン全文入力


NotebookLM　の音声概要は、使用回数に制限があります。
調子に乗って試していると、いざという時リミットで使えません。

楽しい音声概要を　もっと手軽に使いたいので
オリジナル開発しました。
無限に音声概要をし放題いです。
ずんだもん　と　四国めたん　の会話形式で解説してくれます。

オリジナル開発なので、声色を選んだ音声合成は色々いけます。
文章の長さも、会話の内容も自由自在です。
追加学習済みの　LLMのモデルも選べますし、
全文入力済みの
専門分野特化LLMにする事も簡単です。






---

![スクリーンショット 2025-05-06 18.36.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/cc878cb2-dc98-4fd4-9275-19693cbbbd1d.png)






![スクリーンショット 2025-05-06 18.33.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/0173ccb6-7944-4254-89cf-dfedbbccf061.png)





![スクリーンショット 2025-05-06 16.31.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237930/fca95c22-7293-407b-b12c-ce205e4d6916.png)









---


目次


https://qiita.com/bono0/items/dc1d000c98af7e07c9a7



無事に　オリジナル音声概要

　051 AI屋さんの　音声概要（ずんだもん）　LLMにトークン全文入力


完成です。おめでとうございます。

ー以上ー
vimのmarksをquickfixに表示してみる

# marks一覧を覚えられない問題
vimを使うにあたり、vimのmarksを覚えられない問題があります。見やすくするためのプラグインは色々あります。
調べた範囲ではこのあたりですね。

https://github.com/LeafCage/visiblemarks.vim/tree/master

https://github.com/kshenoy/vim-signature

https://nanasi.jp/articles/vim/visualmark_vim.html

いいですね!
でも僕は沢山プラグインを入れるのは好きではないのです。僕のvimの戦闘力は150です。関数でやります。

# 実装

```vim
function! Marks()
  let qflist = []
  for n in execute('marks')->split('\n')
    if str2nr(n[6:8]) == 0
      continue
    endif
    let qflist = qflist->add(
          \#{filename: n[15] == '/'? n[15:] : expand('%'),
          \lnum: str2nr(n[6:8]),
          \col: str2nr(n[11:13]),
          \text: n[1].': '.n[15:]})
  endfor
  call setqflist(qflist, 'r')
  copen
  hi QuickFixLine ctermbg=Yellow guibg=Yellow
  autocmd BufEnter * ++once ccl
endfunction

```

関数はこんな感じ。あとはキーマップをあてましょう。

```vim
noremap <leader>` :silent! call Marks()<CR>
```

これで
```
<leader>`
```

を打てばquickfixに表示されて自分で選ぶ事ができます。
【React】Reactでバックエンド(Express)からCookieを送信し、ブラウザに保存

# ゴール
ログイン用APIでExpressに問い合わせ、そのレスポンスにCookieを含めてブラウザに登録できることを確認する。

クライアント：React上のFetchAPI
サーバーサイド：Express

## クライアント側

FetchAPIでは、下記のように記載
```js
    const response = await fetch(url,{
        method: 'POST',
        headers: {                
                    'Origin': 'http://localhost:3000',
                    'Content-Type': 'application/json',
                },
        credentials: 'include', // クッキーを許可するために必須
        body: userAuthJson
        })
```
credentials: 'include' でCookieの送受信を許可する



## サーバーサイド側

レスポンスヘッダーに```'Access-Control-Allow-Credentials', 'true'```が必要

```js
//cors対応
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With, Origin, X-Csrftoken, Content-Type');
    res.header('Access-Control-Allow-Credentials', 'true');  // クッキーを送信するために必須
    next();
  }


app.use(allowCrossDomain);
app.use(express.json());

app.post('/userauth', (req, res) => {
  console.log(req.body);
  res.cookie('token', 'abc123', {
    httpOnly: true,   // JSから読み取れない → セキュリティ強
    //secure: true,     // HTTPSのみ
    maxAge: 3600000,  // 1時間
    sameSite: 'lax'
  });
```

:::note
httpOnly : JavaScriptでCookieを取得できない(XSSやセッションハイジャック対策)
secure   : Https通信以外ではCookie使用不可(盗聴防止)
sameSite : Strictだと同一オリジンのみでCookie送信可能
:::

:::note warn
今回は検証のため、あくまでabc123という固定値をCookieに使用したがセッションIDやJWTを使用するのが正しい
:::

APIを叩いてブラウザのCookieを確認する

『開発者ツール』⇒『Application』⇒『Cookie』
内で対象のドメインを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3801383/b9d61dd9-95d8-46f3-ab93-7ae776059659.png)
↑作成されている


## Cookieについて
Cookieにはドメイン情報が付加されているため、一度発行されると自動的にサーバー側に送信されるようになる。
Android エミュレータの hosts ファイルを編集する方法

Android アプリ開発において、特定のホスト名を IP アドレスに紐付けたい場合があります。この記事では、Android エミュレータの hosts ファイルを編集する方法について解説します。

## 前提条件

- Android Studio がインストールされていること
- Android エミュレータが作成されていること
- ADB (Android Debug Bridge) がインストールされていること

## 手順

### 1. 利用可能なエミュレータの確認

まず、利用可能な Android エミュレータ (AVD) の一覧を確認します。

```bash
emulator -list-avds
```

実行結果（例）:
```
Pixel_9_Pro
```

### 2. 書き込み可能なシステムでエミュレータを起動

システムパーティションに書き込みができるようにエミュレータを起動します。

```bash
emulator -avd Pixel_9_Pro -writable-system &
```

`-writable-system` オプションを使用することで、システムパーティションへの書き込みが可能になります。
`&` は、プロセスをバックグラウンドで実行するためのものです。

### 3. hosts ファイルの書き込み権限を取得

#### Android 10 以上の場合

Android 10 以上では、セキュリティ強化のため、システムパーティションの書き込み権限を取得するプロセスが複雑になっています。

```bash
# ADB ルート権限を取得
adb root

# ステータスが device になるまで待つ
adb devices

# 再度ルート権限を確保
adb root

# エミュレータを再起動
adb reboot

# 再起動完了し device と表示されるまで待つ
adb devices

# システムパーティションを書き込み可能にリマウント
adb remount

# "remount succeeded" と表示されれば完了
```

#### Android 9 以下の場合

Android 9 以下では、比較的シンプルなコマンドで書き込み権限を取得できます。

```bash
# ADB ルート権限を取得
adb root

# システムパーティションを書き込み可能にリマウント
adb remount

# "remount succeeded" と表示されれば完了
```

### 4. hosts ファイルの編集

hosts ファイルを編集するには、以下の2つの方法があります。

#### 方法1: ホスト PC で hosts ファイルを編集

```bash
# エミュレータから hosts ファイルを取得
adb pull /system/etc/hosts

# ローカルで hosts ファイルを編集
# お好みのエディタで hosts ファイルを開き、必要なホスト設定を追加
# 例: 192.168.1.100 myserver.local

# 編集した hosts ファイルをエミュレータに戻す
adb push hosts /system/etc/hosts

# エミュレータの hosts ファイルを確認
adb shell cat /etc/hosts
```

#### 方法2: エミュレータ内で直接編集する

```bash
# エミュレータのシェルに入る
adb shell

# hosts ファイルの場所に移動
cd /system/etc

# hosts ファイルの内容を確認
cat hosts

# 直接編集する場合
vi hosts
# または
echo "192.168.1.100 myserver.local" >> hosts
```

## 注意事項

1. エミュレータ内での編集よりも、ホスト PC での編集の方が操作しやすい場合が多いです。

2. 変更が反映されない場合は、権限の問題が考えられます。`adb remount` が正しく実行されているか確認してください。

3. 設定変更後、一部のアプリケーションでは再起動が必要な場合があります。

4. エミュレータの特殊な IP アドレスと競合しないように注意してください。
   - `10.0.2.2` - ホストマシンの localhost にアクセスするための IP
   - `10.0.2.3` - ホストマシンのプライマリ DNS サーバー

5. `-writable-system` オプションは Android 10 以降のエミュレータで特に重要です。

## まとめ

Android エミュレータの hosts ファイルを編集することで、特定のホスト名を IP アドレスに紐付けることができます。これは開発環境でのテストや、特定のサーバーへの接続をシミュレートする際に役立ちます。

特に Android 10 以上では、セキュリティ強化のため手順が複雑になっていますが、この記事で紹介した手順に従うことで、問題なく hosts ファイルを編集できます。
Windowsでemacs風キーバインド設定

## Windows11 で emacs風キーバインド

GeForceなPCが使いたくて、久しぶりにWindowsマシンを買い替えたので
基本的なキーバインドをemacs風味にしたので、設定内容を備忘録的に記録しておきます。

### 対象PC
今回購入したPCはこちら

https://www.amazon.co.jp/dp/B0CTKCP81B?ref=ppx_yo2ov_dt_b_fed_asin_title&th=1

ちょっとメモリが少ない（16GB)ので、64GBに増設予定。

### 使用ツール

AutoHotkey 1.1
https://www.autohotkey.com/

### 設定ファイル

設定ファイルは以下の通り
```emacs_keys.ahk
^b::Send, {Left}
^f::Send, {Right}
^p::Send, {Up}
^n::Send, {Down}
^a::Send, {Home}
^e::Send, {End}
^d::Send, {Delete}
^h::Send, {Backspace}
^k::Send, +{End}{Del}
^w::Send, ^x
!w::Send, ^c
^y::Send, ^v
^x::
    KeyWait, Control, T0.5  ; 一応、Ctrlが離れるのをちょっと待って安全処理
    Input, SubKey, L1 T1
    if (SubKey = "s")
        Send, ^s
    else if (SubKey = "c")
        Send, !{F4}
    return
```

^k で Yank Bufferにコピーができれば良いのだけど、うまくいかなかったぉ

### 起動時設定
スタートアップフォルダに ahkファイルのショートカットを設置する。

* スタートアップフォルダを開く方法
Win + R を押して、実行ダイアログを開いて `shell:startup` と入力する

再起動後AutoHotkeyの設定が有効になるまで少し時間がかかります。

### 追記
Nortonが ahk ファイルを IDP.Generic に感染していると誤認識する問題があるようでした。

### CapsLock Ctrl 入れ替え
ahkファイルに `CapsLock::Ctrl` を記載すると入れ替えができるはずなのですが、
なぜか有効にならなかったため SharpKeys を利用した。
設定内容は↓のとおり

![SharpKeys設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481708/c9ee7989-3b50-48c9-8778-bf16684f7f42.png)
コンビネータ論理：Exercise 2.26 二重化あるいは対角化 [x,y].xyy

$[x,y].xyy$
$\equiv[x].([y].xyy)$
$\equiv[x].([y].(xy)y)$
$\equiv[x].S([y].xy)([y].y)$
$\equiv[x].S(x)(I)$
$\equiv[x].(Sx)I$
$\equiv S([x].Sx)([x].I)$
$\equiv S(S)(KI)$
$\equiv SS(KI)$

$x,y$を右から適用して検証してみる。
$SS(KI)xy$
$\rightarrow \\{SS(KI)x\\}y$
$\rightarrow \\{Sx((KI)x)\\}y$
$\rightarrow \\{Sx(I)\\}y$
$\rightarrow SxIy$
$\rightarrow xy(Iy)$
$\rightarrow xyy$

従って
$$[x,y].xyy\equiv SS(KI)$$


$\textbf{W}XY=XYY$なのでこれは対角化コンビネータ$\textbf{W}$なので$$\textbf{W}=SS(KI)$$
【Spring Boot】名前をあいまい検索する方法

# はじめに
Springを使って、データベースに登録されている名前を「あいまい検索（部分一致検索）」できるように実装しようとしたところ、思いのほか苦戦したので、備忘録として手順とコードをまとめておきます。

# サンプルコード
<details open><summary>サンプルコード</summary>

```java:User.java
package com.example.demo;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
@Table(name="users")
public class User {

    @Column(name="name")
    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}
```

```java:UserRepository.java
package com.example.demo;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
    List<User> findByNameLike(String name);
}

```

```java:SearchController.java
package com.example.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class SearchController {

    @Autowired
    UserRepository userRepository;

    @RequestMapping("/search")
    public ModelAndView searchCode(
            ModelAndView mv,
            @RequestParam(value = "name", defaultValue = "") String name) {

        List<User> users = new ArrayList<>();

        // 検索
        // 名前が空欄の場合は実行しない
        if (!name.equals("")) {
            users = userRepository.findByNameLike("%" + name + "%");
        }

        // 検索した名前がヒット
        if(!users.isEmpty()){
            mv.addObject("users", users);
        }

        mv.setViewName("users");
        return mv;
    }
}
```
</details>

# プログラムの簡単な解説
あいまい検索の処理は、`SearchController.java`の部分で実行されています。
```java:SearchController.java
if (!name.equals("")) {
    users = userRepository.findByNameLike("%" + name + "%");
}
```
`findByNameLike`メソッドの引数には、検索キーワードを`%`で囲んだ文字列を渡しています。これにより、名前の部分一致検索が可能になります（例：`%太郎%` で「山田太郎」や「太郎丸」などがヒットします）。

この`findByNameLike`メソッドは、`UserRepository.java`で定義しています。Spring Data JPAの機能を活用することで、メソッド名だけでSQLのようなあいまい検索を実現できるのが特徴です。
[ODC](System)/RequireScriptによるJavaScriptファイルロードの動作を確認する

「オープンソースのJavaScriptライブラリをClient Actionにラップし、部品提供する」検討の一環として。

ScreenやBlockであれば、
1. ScriptsフォルダにJavaScriptファイルを配置
1. Required Scriptsプロパティに配置したファイルを指定

で、自動的にJavaScriptファイルをロードできる。
ただし、共通部品としてClient Actionを提供したいときはこの方法を取れない。
その代替策として、(System)にあるRequireScript Actionを検討する。

# 環境情報
ODC Studio(Version 1.5.19)

# ドキュメント
2025/5/6時点ではODC版のドキュメントはまだ無さそう。
[O11版のドキュメント](https://success.outsystems.com/documentation/11/reference/outsystems_apis/system_actions/#Client_RequireScript)より、

> Add a Javascript to the html header. Multiple calls for the same Javascript will only add it once. Action flow will proceed after the Javascript has been successfully loaded.

- JavaScriptをHTMLヘッダーに追加する
- Input Parameterとして、ヘッダに追加したいJavaScriptのURLを指定
- 同じJavaScriptを複数指定しても追加されるのは一度のみ
- 指定したJavaScriptのロードが終わってから、後続のAction Flowへ進む

という仕様のようだ。やりたいことには合致しているので、動作確認をしてみる。

# 動作確認
LibraryのScriptsフォルダに、JavaScriptファイルを配置。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/8bd642ed-61a5-4fc3-a04b-b848e77c96f6.png)

Client ActionのAction Flowに(System)/RequireScript Actionを配置し、UrlプロパティはScriptsフォルダに配置したファイルのものを設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/a719c893-c3b5-4446-8236-e662d756d0f9.png)

上記設定のRequireScript Action呼び出し前後で、headタグ末尾は以下のように変わる。
つまり、titleタグ直前に該当のJavaScriptファイルをロードするscriptタグが追加されるようだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/5225fba4-672b-4d69-af9c-d42e81329965.png)

この後で、対象のJavaScriptライブラリを使うJavaScriptコードを実行すると正しく動作する。

# RequireScriptで同じファイルを繰り返しロードしても何も起き無さそう
少なくともheadタグ内にscirptタグは増えない。
ドキュメントの記述とも符合するので、この動作を前提に共通部品化を検討できる。

# data-os-finished属性
追加されるscriptタグにはdata-os-finishedという属性が設定されている。
最初はfalseで後から（多分JSファイルのロードが終わると）trueに変更される。
恐らくこの属性は、「指定したJavaScriptのロードが終わってから、後続のAction Flowへ進む」というRequireScriptの動作に関係しているのではないだろうか。

なお、この動作を確認する際は
- JavaScriptファイルがキャッシュされていないか（キャッシュされていたら一旦クリアする）
- JavaScriptファイルが小さ過ぎないか
- 適度なサイズのファイルがないなら、ブラウザの開発者ツールの機能で低速ネットワークをシミュレートする機能を使う

党に気をつける必要がありそう。

# 結論
JavaScriptライブラリを使うClient Actionを部品提供する際は、以下の方針でよさそうだ。

- Libraryを用意
- LibraryのScriptsフォルダに該当のJavaScriptファイルを配置
- 部品のClient ActionをLibraryに用意
    - 銭湯で(System)RequireScriptを使ってJavaScriptファイルをロード
    - 後続のAction Flow内にJavaScript要素を配置し、ライブラリを使うコードを記述
【Linux】略語集（随時更新）

# この記事について

Linuxのコマンドやオプションの名称は、省略されているものが多くある。
それらが何という英単語の略なのかを記載したメモ。

**正式名称が調べても確認できず予想やAIで調べたものも含まれている。**
あくまで、頭のなかでイメージを作り、
覚えやすくするための記事であるため注意。

## コマンド

### fsck

- **File System Check**
- ファイルシステムが破損していないことを確認するコマンド

### vmstat

- [**virtual memory statistics**](https://en.wikipedia.org/wiki/Vmstat)
- システムレポート（プロセス・メモリ・ブロックデバイスI/O・cpu...etc）を表示

 
### sar/sadc

- **System Activity Report**/**System Activity Data Collector**
- sar: sardcが収集したデータを可視化するためのコマンド
- sadc: cronにより定期的にシステムのメトリクスを収集し、ログファイルを保存する

#### sarのオプション

| オプション | 略語（推定）                | 説明                                         |
|------------|--------------------------|----------------------------------------------|
| -u         | CPU Usage                | CPU 使用状況を表示                           |
| -r         | RAM                      | メモリ使用状況を表示                         |
| -b         | Block I/O                | ブロックデバイスI/O状況を表示             |
| -S         | Swap                     | スワップページング統計を表示（-Bと併用）    |
| -n         | Network                  | ネットワーク統計情報を表示（サブオプションあり）|

### smartctl

- **S.M.A.R.T Control**
    - [**Self-Monitoring, Analysis and Reporting Technology System**](https://linux.die.net/man/8/smartctl)
        - *smartctl controls the Self-Monitoring, Analysis and Reporting Technology (SMART) system*
    - ハードディスクやSSDの自己診断機能のモニタリングツール

#### smartctlコマンドの書式と主なオプション

書式: `smartctl [オプション] デバイス`

| オプション        | 説明 |
|------------------|------|
| `-a`, `--all`     | 各オプションで表示できる全情報を表示 |
| `-i`, `--info`    | デバイス情報の表示 |
| `-c`, `--capabilities` | S.M.A.R.T.機能に関わる設定を表示 |
| `-t`, `--test`    | 自己診断テストの実行 |
| `-l`, `--log`     | テストログを表示 |
| `-H`, `--health`  | デバイスのヘルスチェックを表示 |
| `--scan`          | 認識されているデバイスを表示 |




### uname
- **Unix Name**
    - [uname (short for unix name) ](https://en.m.wikipedia.org/wiki/Uname)
- 現在のカーネル・ハードウェア情報を確認するコマンド

## 通信プロトコル

### SNMP

- **Simple Network Management Protocol**
- ネットワーク経由で、機器のリソース監視を行う際にしようするプロトコル
    - リソース監視：CPU/メモリ使用率、ネットワークio、プロセスの状態などを監視すること
【学習・エラー】GitHubとの接続で「どの鍵使ってるの？」問題にぶつかった件

## はじめに
Udemyの講座で学習中、それぞれの講座内でSSHキーというものを作成しました。
その中でとある問題が発生し、解決過程で改めてSSHキーを理解せねば・・・と感じました。

### 環境
PC：Windouws11
使用エディタ：Vscode
PHPとLaravel学習中での出来事（XAMPP）


## 参考資料
SSHキーについては以下記事に詳しく記述されているので、割愛させていただきます

https://qiita.com/angel_p_57/items/19eda15576b3dceb7608

https://zenn.dev/luvmini511/articles/0e471affdcba52

https://qiita.com/suthio/items/2760e4cff0e185fe2db9


## どういう状況？
```powershell
B> git --version
git version 2.44.0.windows.1

//Githubから、Newリポジトリー。名前やPrivate等選択、作成。

B> git init
B> git add -A
B> git remote add origin git@github.com:・・・
B> git push -u origin main

//なぜかここまではうまくいきましたが、少しファイルの内容を修正してgit pushする際に次のようになりました

B> git push
Enter passphrase for key '/c/Users/star_/.ssh/id_rsa': 

パスワードわすれた
```

### SSH鍵（秘密鍵）のパスフレーズを再度作成
```powershell
// 古い鍵をリネーム（削除はしない）
> cd ~/.ssh
> mv id_rsa id_rsa_old
> mv id_rsa.pub id_rsa_old.pub

// 新しい鍵を作成。ファイル名の指定はそのまま（id_rsa）。パスフレーズは「空にする」
> ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

// 公開鍵をGitHubに登録するためコピーする
> cat ~/.ssh/id_rsa.pub

// Github側でSSHキーの登録を行う（資料参考）
```

### 接続を確認して再度pushしてみる
```powershell
//接続確認
> ssh -T git@github.com

// 作業していたディレクトリに戻ってpush
> cd C:\xampp\htdocs\laravel\B
> git push

//成功！
```



## あれ？現状のSSHキーの数ってどうなってる？
```powershell
> ls ~/.ssh
    ディレクトリ: C:\Users\star_\.ssh
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----   2025/05/06 (火)     11:15           3389 id_rsa
-a----   2025/05/06 (火)     11:15            751 id_rsa.pub
-a----   2025/01/23 (木)     23:37           3434 id_rsa_old
-a----   2025/01/23 (木)     23:37            750 id_rsa_old.pub
-a----   2025/01/23 (木)     23:52            828 known_hosts
-a----   2025/01/23 (木)     23:52             92 known_hosts.old
```


## 今のディレクトリ（プロジェクト）はどのカギをつかっている？
```powershell
C:\xampp\htdocs\laravel\B>
B > git remote -v
origin  git@github.com:・・・.git (fetch)
origin  git@github.com:・・・.git (push)
```
➡SSH鍵なので秘密鍵が（id_rsa、id_rsa.pub、id_rsa_old、id_rsa_old.pub）これらの内のどれかという事は分からない💦


### 改めて、GitHubに接続する際に、どのSSH鍵が使われているか確認
```powershell
B > ssh -T git@github.com -v
```
この後かなり長いメッセージ？が表示され、使われているSSH鍵を次のような文章から確認できます
```powershell
debug1: Offering public key: C:\\Users\\star_/.ssh/id_rsa RSA
debug1: Server accepts key: C:\\Users\\star_/.ssh/id_rsa RSA
```
つまり、このプロジェクトは C:\Users\star_\.ssh\id_rsa の鍵を使って GitHub に接続している！


### ✅ ログの見方
| 行 | 意味 |
| --- | --- |
| `Offering public key` | PCがGitHubに「この鍵でどうですか？」と提案してる |
| `Server accepts key` | GitHubが「OK！その鍵で認証するよ」と受け入れてる |



## まとめ
現段階でSSHキーを作りすぎている＆Githubにも登録しすぎている、と思われるので、整理に繋げるためにも今回のエラーは起こってよかった事。
多分この問題が発生しなかったら、適当に流していたと思われます😢
参考資料の記事も、ちょくちょく見返して、理解を深めていきたいと思います。
※プロジェクトごとの設定はその時が来たら学びたいと思います。


---
## おまけ1：`id_rsa` と `id_rsa.pub` の違い

| ファイル名 | 内容 | 説明 |
| --- | --- | --- |
| `id_rsa` | 🔒 **秘密鍵** | 自分のPCに保存されている大事な鍵。**絶対に他人に見せない！** |
| `id_rsa.pub` | 🔓 **公開鍵** | GitHubに登録する用の鍵。これをサーバー（GitHub）側が使って、PCから来た鍵を検証。 |


---

### ✅ 余談：`id_rsa_old` などの他の鍵について…。
もし以前の講座で作った `id_rsa_old` を使いたいなら、**SSH設定ファイル（`~/.ssh/config`）で使い分けの設定**が必要になるそうです。
（つまり、複数プロジェクトで異なる鍵を使う際、`~/.ssh/config` を使って設定を分ける）
※何も設定していないと、`id_rsa`が常に優先して使われます。
新卒3年目エンジニアの学習記録：学習14カ月目

# はじめに

ついに3年目に突入してしまいました。AKです。
先月に引き続き、今月に個人学習でやっていたことを記録していきます。

先月の記事です↓

https://qiita.com/AK_React/items/2ae941912f0429d3c036

# 学習14か月目にやったこと

### <font color="Red">１．フルスタック個人開発 画像認証機能・アカウント認証機能実装＆テスト完了</font>

先月に引き続きSNSアプリの作成を行っています。
**今月はRails APIで画像投稿機能・アカウント認証機能実装＆テスト**を行いました。
認証には`DeviseTokenAuth`を使い、画像投稿には`Active Strage`を使っています。
今月は後述するLP作成をメインに行ったため、進捗は少なめです。

**～✅現在の進捗～**

- [x] Rails API実装
- [x] Rspec
- [x] フロントエンド機能実装
- [x] フロントエンドテスト
- [x] Rails APIを使って認証機能・画像保存機能作成
- [x] 認証機能・画像保存機能テスト作成
- [ ] AWS・Docker環境構築
- [ ] Dockerを使ってAWS EC2+RDSにデプロイ
- [ ] ECSにデプロイ
- [ ] CI/CD
- [ ] Terraformでインフラコード化
***

### <font color="Red">２．LP作成デビュー</font>

学習の一環で、初めてLPを作成しました。
Nextjs × TypeScript × tailwindcssを使用しています。

これが**最初はめちゃくちゃ苦戦**しました。
開発を行ううえで、デザインはこれまでテンプレートを活用してきたので、「要件をデザインに落とし込む」というのが本当に難しかったです。
使い慣れているはずのtailwindcssも全然手が動かないし。

AI駆動開発で進めていこうとしましたが、**自分がやりたいこと・期待しているものが抽象的なまま指示を投げると、かえって修正に時間を要することが多かった**です。
**結局、手で修正した方が早かった**りしました。
やはり、**方針が定まらないままAIに丸投げするのは危険**だと学びました。
ちなみにAIはCursor agent（Proプラン）とCopilot（無料版）を使用しています。
***
以下、LP作成で参考になったサイトを載せておきます。

**ColorSpace**

入力したカラーに対してカラーパレットを自動生成してくれます。
LPのメインカラーに合う色のトーンや組み合わせがすぐに見つかるのは、非常にありがたかったです。

https://mycolor.space/?hex=%230D68A5&sub=1

**Html to JSX**
HtmlをJSXに変換してくれます。
今回のLPはSEOのことも考え、Next.js（SSR）×TypeScriptで作成しています。
外部のサイトで参考にしたいデザインがあったときに、このサイトを重宝しています。

https://transform.tools/html-to-jsx

# おわりに
AIがコードを書くことがスタンダードとなりつつありますが、LP作成も「AIの力を借りたらすぐに終わるんじゃないか」と楽観視していた自分がいました。
しかし、丸投げしてしまったことでむしろ時間を浪費し、手戻りが増える経験をしたことで、「**結局自分でちゃんと理解して、修正できるに越したことはねえ**」と心から感じました。
最近は心を入れ替えて（？）、CSSのドキュメントを漁りながら実装を進めています。
おかげで以前より確実に力がついていると思いますし、「**自分がやりたいことを自分の手でかなえられた**」という成功体験を積むことで実装が楽しくなります。

私がもっと強くなったときにAIが加わればさらに強くなれる、というマインドでこれからも手を動かしていきます。
C言語での学習記録

## 概要
今回はC言語でリストの学習記録を書いてみました。
学習のメモ程度に記述していますのでご承知ください。

## 動作環境
・windows：Windows11Pro 23H2

## 実行
```
gcc .\test.c -o test
```

### 双方向リスト
```test.c
#include <stdio.h>
#include <stdlib.h>

struct Node{
    int data;
    struct Node* prev;
    struct Node* next;
};

//新しいノードを作成する関数
struct Node* createNode(int data){
    struct Node* newNode=
    (struct Node*)malloc(sizeof(struct Node));
    newNode->data=data;
    newNode->prev=NULL;
    newNode->next=NULL;
    return newNode;
}

//リストを前から後ろへ表示する関数
void displayForword(struct Node* head){
    struct Node* temp=head;
    printf("Forward: ");
    while(temp != NULL){
        printf("%d ",temp->data);
        temp=temp->next;
    }
    printf("\n");
}

//リストを後ろから前へ表示する関数
void displayBackward(struct Node* tail){
    struct Node* temp=tail;
    printf("Backward: ");
    while(temp != NULL){
        printf("%d ",temp->data);
        temp=temp->prev;
    }
    printf("\n");
}

int main(){
    struct Node* head=createNode(1);
    struct Node* second=createNode(2);
    struct Node* third=createNode(3);

    head->next=second;
    second->prev=head;
    second->next=third;
    third->prev=second;

    displayForword(head);
    displayBackward(third);

   free(head);
   free(second);
   free(third);

   return 0;
}

```
wp-env で debug.log を読む方法

いつも、忘れてしまうので、備忘録までに。

# debug.log を読む方法

基本的には以下でほぼコマンドラインと同じ事ができます。

```
wp-env run cli ****
```

今回は、デバッグデータを見たいので、以下で見られます。他の方法もあると思いますが。

```
wp-env run cli vi wp-content/debug.log

wp-env run cli tail -f wp-content/debug.log
```

上が、ファイルを `vi` で見る方法で、下は `tail` コマンドでテキストファイルの最後方を表示するコマンドです。
コンビネータ論理：変数順序の交換

コンビネータ論理を学んでいて、xyの順序をyxに変える操作はどうなるのか気になってやってみた。

$$[x,y].yx$$はどうなるか？


### [x,y].yxについて
$[x,y].yx$
$\equiv[x].([y].yx)$
$\equiv[x].S([y].y)([y].x)$　定義2.28(f)より$y$で抽象化
$\equiv[x].SI(Kx)$
$\equiv[x].(SI)(Kx)$
$\equiv S([x].SI)([x].Kx)$
$\equiv S(K(SI))K$

検証してみる：
$S(K(SI))Kxy$
$\equiv\\{S\underbrace{(K(SI))}Kx\\}y$
$\rightarrow (K(SI))x(Kx)y$
$\rightarrow SI(Kx)y$
$\rightarrow Iy((Kx)y)$
$\rightarrow yx$
検証できたので、$$[x,y].yx\equiv S(K(SI))K$$となった。

### [x,y]=xyについて
では、順序変更しない式はどうなるのか、気になったのでやってみた。
$[x,y].xy$
$\equiv[x].([y].xy)\equiv[x].(x)\equiv I$

$Ixy\rightarrow(Ix)y\rightarrow xy$なので、
$$[x,y].xy\equiv I$$となる。

抽象化(abstraction)については[前の記事](https://qiita.com/Trubetzkoy/items/c55fc03a235e72022643)を参照してね。
GraphForge 改修モード：構造化リファクタリング


https://qiita.com/cementite/items/17c88d9284f926d30d18

上記の続報です。


---

## GraphForge 改修モード：主要ポイント

### ディレクトリ構成

```text
C:\work\GraphForge
├── build/<ID>/app/structure.json
├── dashboard.py
└── langgraph_v21/
    ├── consistency.py
    ├── graph_build.py
    ├── refactor_graph.py
    └── structure_writer.py
```

### 静的チェック (`consistency.py`)

```python
import ast, json
from typing import Dict, List

def quick_check(files: Dict[str,str]) -> List[str]:
    issues: List[str] = []
    for fn, content in files.items():
        if not content.strip():
            issues.append(f"{fn} is empty")
        if "TODO" in content:
            issues.append(f"{fn} contains TODO comment")
        try:
            if fn.endswith('.py'):
                ast.parse(content)
            elif fn.endswith('.json'):
                json.loads(content)
        except Exception as e:
            issues.append(f"{type(e).__name__} in {fn}: {e}")
    return issues
```

### UIフロー (`dashboard.py`)

```text
[1] プロジェクト選択
[2] ファイル選択
[3] 改修指示入力
[4] 指示確認
[5] 改修実行 → 差分プレビュー
[6] 上書き保存
```

### 改修例

```python
# Before
def greet(name):
    # TODO: default
    return f"Hello, {name}"

# After (指示:「省略時は"World"を使う」)
def greet(name: str = "World"):
    return f"Hello, {name}"
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4052799/7979cf6e-0aeb-4700-842e-5d014867e6b5.png)


https://github.com/ryosaki1112/GraphForge
AIエディタ「Cursor」のはじめ方：VSCodeユーザーがハマらず使うためのガイド



<!-- 【記事本文】 -->

<h2>最近話題の「Cursor」、でも何がそんなにすごいの？</h2>
<p>AIによるコーディング支援が一般化する中で、<strong>「Cursor」というエディタ</strong>がエンジニア界隈で急速に注目を集めています。ChatGPTなどのLLMを活用し、まるで“ペアプロ”しているかのような開発体験が可能です。</p>
<p>とはいえ、「名前は聞いたことあるけど、正直なところ何が違うの？」と感じている人も多いはず。この記事では、<strong>はじめてCursorを使う人</strong>に向けて、その特徴や活用法、注意点を紹介します。</p>

<h3>Cursorとは？VSCodeから派生したAIネイティブなエディタ</h3>
<p><strong>CursorはVisual Studio Codeをベースに開発されたAI統合エディタ</strong>です。基本操作やUIはVSCodeとほぼ同じで、VSCodeユーザーであれば違和感なく移行できます。</p>
<p>主な特徴：</p>
<ul>
  <li><strong>ChatGPT（GPT-4）と連携</strong>し、自然言語でのコーディング支援が可能</li>
  <li><strong>コードベース全体の把握</strong>と文脈理解に強く、既存コードのリファクタにも対応</li>
  <li><strong>単一ファイルにとどまらず、プロジェクト全体を対象に提案</strong>できる</li>
</ul>
<p>公式サイト（https://www.cursor.sh）ではインストーラーが提供されており、Mac / Windows / Linuxに対応しています。</p>

<h3>よくある課題・戸惑いポイント</h3>
<p>QiitaなどでCursor関連の記事を読むと、以下のような初学者のつまずきが散見されます：</p>
<ul>
  <li><strong>GPT-4 API Keyが必要</strong>なことに気づかず、動作しない</li>
  <li><strong>プロジェクトルートの認識ミス</strong>により、コード補完がうまく機能しない</li>
  <li><strong>自然言語プロンプトの書き方</strong>が分からず、曖昧な指示で精度が落ちる</li>
</ul>
<p><span style="color:red;">Cursorはあくまで「優秀なアシスタント」であり、設計や意図を明確に伝える必要があります。</span></p>

<h3>基本的な使い方とよく使う操作</h3>
<p>初回起動後、GPT-4のAPI Keyを入力するとAIアシスタントが有効化されます。</p>
<p>基本的な操作例：</p>

<pre><code>Ctrl + K（Cmd + K） → 「Ask Cursor」：現在選択中のコードに対して質問
Ctrl + L（Cmd + L） → 「Edit with Cursor」：選択範囲に対してリファクタや命令を入力
</code></pre>

<p>プロンプト例：</p>

<pre><code>「この関数を非同期化して」「この処理にエラーハンドリングを追加して」</code></pre>

<p>また、コードの説明やユニットテストの自動生成も以下のように指示可能です：</p>

<pre><code>「この関数のユニットテストを書いて」「このSQLの意味を説明して」</code></pre>

<h3>ベストプラクティスと活用のコツ</h3>
<p>Cursorを最大限に活用するためのポイント：</p>
<ul>
  <li><strong>対象コードをしっかり選択する</strong>：意図しない箇所まで編集されるのを防げる</li>
  <li><strong>命令は具体的かつ明確に</strong>：英語・日本語のどちらでも可能だが、文脈が重要</li>
  <li><strong>git diffで変更確認</strong>：自動変更のレビューは必須</li>
</ul>
<p>実務で活用する場合、既存コードの理解補助、ドキュメント生成、コードレビュー補助など多くの場面で役立ちます。</p>

<h3>まとめと今後の展望</h3>
<p>Cursorは単なる「AIを載せたエディタ」ではなく、<strong>プロジェクト全体を理解して支援するAIパートナー</strong>としての完成度が非常に高いツールです。</p>
<p>AIに頼りすぎず、コードの意図や構造を自分で把握することが前提ではありますが、うまく使えば<strong>業務効率や学習スピードを大きく高める武器</strong>となります。</p>
<p>今後はCursorに限らず、JetBrains AIやCopilot Workspaceなど、<strong>AIネイティブIDEが主流になる時代</strong>が来るかもしれません。</p>
RMIとREST APIの違い

## RMIとREST APIの違いを気になったからChatGPTに聞いてみた

私はSES企業で働くSE3年目のものです。
現在、某金融機関の２次請けエンジニアとしていわゆるレガシー現場で働いています。

某金融機関のシステムは20年ほど前から作られて、使用されているのはJava Struts2です。
そこで使用されているWebアプリケーションやWebサービス間でデータをやり取りするための手段は「**RMI**」です。

モダンな言語ではほとんどがREST APIが使われているのでしょうか。
働いた経験がないので、あまり詳しくはわからないのですが、REST APIとRMIの違いについて背景からChatGPTに聞いてみました。


以下引用です。
## RMIとREST APIの違い
|| RMI | REST API |
| ---- | ---- | ---- |
|通信モデル| Javaオブジェクト間のメソッド呼び出し（RPC） | HTTPベースのリソース操作（GET/POST/PUT/DELETE） |
| プロトコル | RMI専用プロトコル（Java RMI） |HTTP（標準的で汎用） | 
|データ形式|Javaオブジェクトの直列化（Serializable）|JSONやXML（言語非依存）|
|利用できる言語|Java専用|任意（Java, Python, JavaScriptなど）|
|保守性|Java依存で密結合になりやすい|HTTP＋JSONで疎結合|
|デバッグのしやすさ|専用ツールや知識が必要|ブラウザやcurlなどでもテスト可能|
|ファイアウォール越え|難しい場合が多い（RMIポートなど）|HTTPなので通りやすい|
|例外処理|Java例外で制御（RemoteExceptionなど）|HTTPステータスコード（400, 500など）で制御|

## 【現場目線の違い】

1. 開発者の自由度・拡張性
•	RMI：Java以外からアクセスできない。機能追加や改修がJava前提になる。
•	REST API：非Java（フロントエンドやPythonなど）からもアクセスできる。将来マイクロサービス化も容易。

2. 可搬性と保守性
•	RMI：クライアントとサーバーで共有するインターフェース（.classや.jar）が必要。バージョンのずれに弱い。
•	REST：URL＋HTTPでインターフェースを定義でき、契約（API仕様）さえ守れば自由度が高い。

3. 可視化とAPI管理
•	RMI：どんなメソッドがあるか確認するにはコードを見ないといけない。
•	REST：OpenAPI（Swagger）などで自動生成・ドキュメント化が可能。

⸻

## 【なぜRMIが使われているのか？】
•	Javaベースで統一されている既存システム。
•	社内LANの閉じたオンプレ環境ならセキュリティ上問題になりにくい。
•	Java開発者だけで完結する小規模 or 閉じたシステム。

## まとめ
つまり、金融システムのような堅牢なセキュリティが求められるかつ、20-30年前のJavaで作られたシステムではRMIを使用することが多いのではという結論です。
まあ、金融機関のシステムは本当にレガシーですし、スパゲッティ状態のものが多いです。
それは今のVUCAの時代を想定したシステム設計ではなく本当に誰も手をつけたがらない、まさにカオスな状態といえますし、なかなかこのRMIからREST APIにリファクタリングするのは難しい話なのは承知ですが、こうやってモダンな技術とレガシー技術の比較ができるのはレガシーシステムを触っているからこその特権かもしれませんね。

皆さんの何かしらの力添えになれたら幸いです。

AKI
暗号化に使用する鍵



下記の暗号化技術に関する記事の続きです。
- [共通鍵暗号](https://qiita.com/tom_S/items/e5c6e183064354fee8b2)
- [公開鍵暗号](https://qiita.com/tom_S/items/e29f4cc3efb6bef40daf)
- [一方向ハッシュ関数](https://qiita.com/tom_S/items/bd0d8dfd808be41edb60)
- [メッセージ認証コード](https://qiita.com/tom_S/items/8b02771a3cc1754477ba)
- [デジタル署名](https://qiita.com/tom_S/items/9dfda4e9ad30966d55e9)

今回は暗号化・復号化で使用される鍵についてまとめます。

## 暗号方式で使用される鍵とは

暗号方式の暗号化・復号化で使用される鍵は、擬似乱数生成器によって生成される数値で表現されることが多いです。
擬似乱数生成器によって生成する理由は、第三者によって鍵を予測されることを防ぐためとなります。強固な暗号方式であっても鍵が予測可能なものであれば何の意味もないため、鍵が予測不可能なものであることを担保する必要があります。
また、鍵にはセッション鍵とマスター鍵という種類があるので、これについても下記で説明します。

## セッション鍵

一時的に使用する共通鍵暗号方式の鍵のことを指します。主に通信データを暗号化する鍵(CEK)として使用されます。
SSL/TLSの1セッション分の通信間で使われ、セッションが終了した段階で鍵は破棄されます。

![セッション鍵ライフサイクル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/2566422c-97da-4069-865e-eb9945df5e07.png)

セッションとは、SSL/TLSの暗号化通信を行う二者間における、通信が始まる前から通信が終わるまでのことを指します。セッションが終了するタイミングは大きくわけて下記の二つがあります。セッション鍵はこのタイミングで破棄されます。

1. SSL/TLSのアラートメッセージ「close_notify」が送られた場合
1. もしくは通信する二者間のどちらかが通信不能となってタイムアウトした場合

また、セッション鍵はセッションが開始されるたびに生成されます。よって鍵を生成するのに使用する擬似乱数生成器の品質が良くないと、次に生成されるセッション鍵を予測されてしまう危険性があるので、注意は必要です。

## マスター鍵

マスター鍵はセッション鍵と違い、セッションが破棄されたとしても破棄されない鍵です。
何度も使用される鍵となるので、用途としては鍵を暗号化するための鍵(KEK)として使用されることが多いです。
マスター鍵の生成は、パスワードとソルトをもとに作成される事も多いです。
ソルトとはパスワードを予測させないための乱数値のことを指します。パスワードとソルトを使って一方向ハッシュ関数で算出されたハッシュ値が鍵となります。

## セッション鍵とマスター鍵の使い分け

マスター鍵とセッション鍵の使い分けについてまとめます。
簡単に言ってしまえば、マスター鍵はセッション鍵を暗号化するために使われ、セッション鍵は送るデータを暗号化するために使われることが多いです。下記の図のようなイメージです。

![マスター鍵とセッション鍵.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266944/bd122d4f-678c-4705-844d-e7335b1fc794.png)

これにより、セッション鍵が第三者に知られたとしても、解読されるのはごく一部の情報です。使用している暗号方式に脆弱性がなければ、他のセッションの通信が知られることはありません。それ以降のデータが盗聴・改竄されるようなことはなく、鍵が流出した影響を小さくできるためこのような使われ方をすることが多いです。

# 参考資料

https://www.cloudflare.com/ja-jp/learning/ssl/what-is-a-session-key/

https://www.ibm.com/docs/ja/developer-for-zos/15.0.x?topic=trace-ssl-alert-messages
認証と認可 Keycloak 入門　第2版のサンプルについて

[認証と認可 Keycloak 入門　第2版](https://www.ric.co.jp/book/new-publication/detail/2925)   2025年3月28日　第2版第1刷
のサンプルプログラムを実行した結果です。

Ubuntu 25.04 で行いました。

## Java のバージョン

```text
$ java --version
openjdk 21.0.7 2025-04-15
OpenJDK Runtime Environment (build 21.0.7+6-Ubuntu-0ubuntu125.04)
OpenJDK 64-Bit Server VM (build 21.0.7+6-Ubuntu-0ubuntu125.04, mixed mode, sharing)
```

## サンプルクライアント
P165 に記述されています。

実行コマンド

```bash
./mvnw spring-boot:run
```

実行結果

```text
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.296 s
[INFO] Finished at: 2025-05-06T14:02:00+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project clientapp: 
Fatal error compiling: エラー: リリース・バージョン17はサポートされていません -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7143e15f-d8c5-4961-af5b-9e71d3766907.png)



## サンプル API サーバー
P166 に記述されています。

実行コマンド

```bash
./mvnw spring-boot:run
```

実行結果

```text
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.324 s
[INFO] Finished at: 2025-05-06T14:01:47+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project resourceserver: 
Fatal error compiling: エラー: リリース・バージョン21はサポートされていません -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/beb30aa1-d9af-4f11-a57a-8851073aec58.png)
【データベース】Postgreでのデータベースサーバー構築メモ　~データベース・スキーマ作成～

# 目的
Postgreでのデータベースサーバー構築を行えるようになる

・データベース作成
・スキーマ作成

### データベース作成

下記コマンドでデータベース作成
```bash
CREATE DATABASE mydb OWNER myuser;
```

データベース一覧表示(テンプレート含む）
```
\l
```

データベース一覧表示（実際のDBのみ）
```bash
SELECT datname FROM pg_database WHERE datistemplate = false;
       List of tablespaces
    Name    |  Owner   | Location
------------+----------+----------
 pg_default | postgres |
 pg_global  | postgres |
(2 rows)
```

:::note
PostgreSQL にはデフォルトで template0 と template1 というテンプレートデータベースがある。
pg_database は、PostgreSQLのシステムカタログテーブルで、データベースに関する情報（名前、所有者、作成日など）が格納
:::

データベースの切り替え
```bash
\c mydb
You are now connected to database "mydb" as user "postgres".
```

### スキーマ作成

下記コマンドでスキーマ作成
```bash
CREATE SCHEMA test_schema AUTHORIZATION myuser;
```

スキーマ確認
```bash
\dn
         List of schemas
    Name     |       Owner
-------------+-------------------
 public      | pg_database_owner
 test_schema | myuser
(2 rows)
```

## スキーマ検索パス設定

セッション中のみ一時的な指定
```bash
SET search_path TO スキーマ名1,スキーマ名2,...;
```

永続的にユーザーの検索パス変更
```bash
ALTER ROLE user SET search_path = スキーマ名1,スキーマ名2,...;
```

スキーマ検索パスの確認
```bash
SHOW search_path;
```

:::note warn
データベースに対してもスキーマ検索パスは設定可能だが、ユーザー設定の方が優先される
```bash
ALTER DATABASE DB名 SET search_path TO スキーマ名1,スキーマ名2,...;
```

ユーザーのスキーマ検索パス設定をリセットする必要があるが実用性は低い
:::
ユーザ退会機能　(実務未経験状態でLaravelを使用した共同開発　タスク5)

## 0.背景
本記事は、記事「実務未経験状態でLaravelを使用した共同開発」で取り組んだタスクのうち、ユーザ退会機能についてまとめたもの

https://qiita.com/ashi__mo/items/9abff3c5227660dcddba

## 1.仕様内容
・ユーザ編集画面（他メンバーが作成した画面）へ退会ボタンを追加
・クリックで確認モーダルを表示
・モーダル内の「退会」ボタンでユーザー削除（SoftDelete）
・退会時、対象ユーザの投稿も削除
##### UI※デプロイしたもの
![user_edit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3842139/083995ad-9c35-42b1-a9ae-90c4ec98e112.png)

## 2.タスクの見積もり
##### 期間
・７日
##### 理由
・ユーザー編集画面は他メンバーが実装中であり、着手に遅れが出る可能性があったため
・実装中のエラー対応やレビュー期間も考慮
##### 実績
・仕様作成完了　４日
・PR完了　４日
・PRレビュー後修正５日
・マージ完了　６日

## 3.実装
①Routing
・web.php
・認証済みユーザーのみ処理可能にするため、auth ミドルウェアを適用
```
Route::group(['middleware' => 'auth'], function () {
```
・ユーザー関連処理をまとめるため、/users プレフィックスを使用
```
Route::prefix('/users')->group(function(){
    Route::delete('/{id}', 'User\UsersController@destroy')->name('users.destroy'); // ユーザ削除
```

②Model
・User.phpに記載
・退会時にそのユーザーの投稿も一緒に削除（boot メソッドをオーバーライド）
```    
    protected static function boot()
    {
        parent::boot();

        static::deleting(function($user){
            $user->posts()->delete();
        });
    }
```
・SoftDelete の有効化
```
protected $dates = ['deleted_at'];
```

③Controller
・UsersController：destroyメソッド
・本人確認（ログインユーザーと対象ユーザーが一致するか）
・ユーザを削除、ログアウト処理
・ログアウト処理、セッション無効化、CSRFトークン再生成
・トップページへリダイレクト
```
    public function destroy($id, Request $request)
    {
        $user = User::findOrFail($id);
        if(Auth::id() !== $user->id){
            abort(403,'権限がありません。');
        }
        $user->delete();

        Auth::logout();

        $request->session()->invalidate(); // session無効化
        $request->session()->regenerateToken(); // CSRFトークンをリセット

        return redirect('/'); // 退会後トップページへ
    }
```
④View
・users/edit.blade.php内に記載
・退会ボタン（モーダル起動）
```
 <a class="btn btn-danger text-light" data-toggle="modal" data-target="#deleteConfirmModal">退会する</a>
```
・退会モーダル
```
<div class="modal fade" id="deleteConfirmModal" tabindex="-1" role="dialog" aria-labelledby="basicModal" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4>確認</h4>
            </div>
            <div class="modal-body">
                <label>本当に退会しますか？</label>
            </div>
            <div class="modal-footer d-flex justify-content-between">
                <form action="{{ route('users.destroy', ['id' => $user->id]) }}" method="POST">
                    @csrf
                    @method('DELETE')
                    <button type="submit" class="btn btn-danger">退会する</button>
                </form>
                <button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button>
            </div>
        </div>
    </div>
</div>
```

## 4.テスト実施
・ユーザログイン状態でのみボタン表示を確認
・ユーザの退会処理動作を確認
・退会時、投稿の削除も確認（softDelete）

## 5.PRレビュー
・ルーティング記載の仕様間違い
　　→今回の退会ボタンは他画面で使う予定がなかったためコンポーネント化しなかったが、将来的な再利用も視野に入れた実装が望ましかったかもしれない
　　→ログインしていなければボタン表示すらしないから良いと誤った判断

## 6.本実装に関して
・再利用性：退会ボタンに関して他ページでは使用することがないため、カプセル化しなかったがしてもよかったのではないか
・実装前の仕様確認漏れが原因で修正が発生したため、今後はチェックリストを使って確認精度を高める