OmniAICreator/Qiita-1.07M huggingface dataset:
Salesforce Einstein 生成 AIでレコードの要約設定をしよう


本橋孝昭です。
今回はEinstein　生成AIでレコード要約をするための設定をします

今回はこちらのデモ環境を使います

https://sforce.co/41FRufz


まずはEinstein設定を有効にします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e83d3bc2-e90e-40d0-aca5-77aaab8d6697.png)


次にプロンプトビルダーを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/72f52ffd-1dca-4373-bb9a-1df9723cd4ef.png)

設定は項目生成とします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/12e96dda-ac0a-4118-b6be-ba2a1b3db582.png)

なお、ケースにはカスタム項目を作成しています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/0aaea36c-d53c-4e9c-a9af-abfe9f813fd9.png)

プロンプトはこちらにします。なおモデル種別はGPT 4 Omniとします


> {!$Input:Case.Comments} along withのコメント本文の　内容と、
 {!$Input:Case.Subject}　のテキスト、ケースの優先度である
 {!$Input:Case.Priority}　およびケース タイプである
 {!$Input:Case.Type}　を連結したものを要約します。
応答は 3つの 長い段落にまとめます。
最後に感想文を入れてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/20f09b8c-d4c5-46d3-82f4-153dfe49c90b.png)


このプロントビルダーを有効にします。

次にケースレコードページの設定変更をします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/2911a317-24a0-45ef-9622-da58a6b07d81.png)

「アップグレードに関するお問い合わせ」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/e2c421a8-51b3-4740-9d2f-da60cff15f1e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9af53c72-b1a7-4b42-b18b-aa74e40901b2.png)

完了とする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6bfd67dd-f1a1-42a2-bd89-f020d4ddaa3a.png)

プロントビルダーで先ほど設定したプロントビルダーを設定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f5b855bb-94a3-4749-a8c3-1e97367a8514.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5867f5d2-3258-42a7-b1fd-b3e5db03aa3d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/73c143ac-c770-47bb-9e7e-5ff45f7ec136.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/c5022229-459f-400b-8dc3-739d74cf7302.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/d9232197-3b93-443a-bac0-34712ce0e7fb.png)

こちらで要約がかのうになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/406d224a-56f8-4a72-a400-a2c0b01f82be.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/b811f6a3-184a-47e4-846c-c081c3ebb00f.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/f9b36d5f-8ec1-464e-83e1-c090c933dbdb.png)
Docker composeの使い方

# Docker Compose とは

Docker では、イメージの作成やコンテナの起動、ネットワーク接続などをコマンドで実行します。しかし、開発環境が複雑になると必要なコマンドが増え、チームでの共有が困難になります。

そこで、Docker Compose を使うと、すべての設定を docker-compose.yml に記述し、シンプルなコマンドで環境を構築できます。これにより、メンバーにファイルを渡すだけで、同じ開発環境を簡単に再現できます。
### 例
Nginx + PHP（Laravel） + MySQL の環境を構築する
```docker-compose.yml
version: '3.8'  # Docker Compose のバージョン

services:
  app:
    image: php:8.2-fpm
    container_name: laravel_app
    volumes:
      - .:/var/www/html
    depends_on:
      - db

  web:
    image: nginx:latest
    container_name: nginx_server
    ports:
      - "8080:80"
    volumes:
      - .:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - app

  db:
    image: mysql:8.0
    container_name: mysql_db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: laravel
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:
```

# Docker Compose の実行

以下のコマンドを実行すると、設定された環境が起動します。
```
docker compose up
```
バックグラウンドで実行する場合は、-d オプションを付けます。
```
docker compose up -d
```
docker composeを実行すると自動でカスタムネットワークを作成してくれる
# docker composeのいろいろなコマンド
docker composeのコンテナを停止するコマンド
```
docker compose down
```
新しくdocker composeのコンテナを作成させるときに使用するコマンド(`docker compose`だけだと今あるコンテナを再利用してしまうから)
```
docker compose up --build
```
例　ubuntuとnginxを起動させる方法
```yml:docker-compose.yml
version: '3.8'

services:
  yamada-ubuntu:
    build: .
    volumes:
      - ubuntu-vol:/app
    networks:
      - yamada-net
    stdin_open: true  # -i オプション相当
    tty: true         # -t オプション相当
    command: /bin/bash  # 起動時に Bash を開く

  yamada-nginx:
    image: nginx:latest
    ports:
      - "1234:80"
    volumes:
      - nginx-vol:/etc/nginx/conf.d
    networks:
      - yamada-net
    restart: unless-stopped  # バックグラウンドで常駐

volumes:
  ubuntu-vol:
  nginx-vol:

networks:
  yamada-net:

```
起動コマンド
```
docker-compose up -d yamada-nginx && docker-compose run yamada-ubuntu
```
# まとめ

Docker Compose を使うと、複雑な Docker コマンドを docker-compose.yml にまとめられる
チームメンバーと環境を簡単に共有できる
シンプルなコマンド (docker compose up) で環境を構築可能
これにより、開発作業が効率化され、統一された環境を簡単に再現できます。
配列の全要素を順番に処理する時 (foreach

改行の全要素を、1回1回区切り、改行して出力したい時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037410/c603664a-2419-41a2-8266-2fae3462ae22.png)

foreachの部分はforループで下記の様にも表す事ができる。
![2025-03-23_14h50_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4037410/d3f19206-847d-47a2-81f6-d886496597f1.png)
【C#エラー】「Webマークを削除してください」というエラーの解決法

Webからダウンロードしたプログラムを実行すると、

:::note alert
ファイル Form.resx を処理できませんでした。インターネットまたは制限付きゾーン内にあるか、ファイルに Web のマークがあるためです。これらのファイルを処理するには、Web のマークを削除してください。
:::

のようなエラーが表示される場合があります。

インストールしているセキュリティーソフトによっては、別のメッセージが表示される場合があります。

nortonの場合、**怪しいファイルを検出しました。** というメッセージが表示されます。
![2025-03-23_13h48_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3996436/0dba29ff-3405-48e4-ba4b-d607ca01485b.png)


## 原因
Webからダウンロードしたファイルがセキュリティーにより保護されるため

## 対策
プログラムファイルはzipファイルでダウンロードする場合が多いかと思いますが、**ZIPファイルを解凍する前に**セキュリティーの解除を行うようにします。

セキュリティーを解除する方法は、ZIPファイルを右クリックでプロパティを表示し、**許可する**の部分にチェックを入れ、**適用**をクリックします。

![2025-03-23_14h17_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3996436/4f7c9ee7-ea3e-42ee-9128-ba9a794ccc2d.png)

この状態で、ZIPファイルを解除すると、ZIPファイル内の*.resxファイルもセキュリティーが解除されます。

もっとも、ファイルは信頼できる場所から入手するようにしてください。


**関連リンク** 
https://faq-avaldata.dga.jp/faq_detail.html?id=386
AWS Route 53 でドメイン取得しようとして制限された話

# 忙しい人向けサマリー
- AWS Route 53 でドメイン取得できなかった
- サポートセンターへの問い合わせで、アカウントの制限を解除してもらうことができた
- 制限は、AWS利用状況により加えられる場合があるとのこと
    - AWSの利用経験は、簡単な個人開発のみがあった

# 具体的な経緯

「ドメインを登録」を選択して「開始する」をクリック

![スクリーンショット 2025-02-22 17.18.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661290/a1f02b92-fa0f-4615-83c4-1e8554fa02a0.png)

被っているドメインがないか検索し、確認画面からリクエスト

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661290/6ffbd9b2-e544-4950-9dec-affef2502f37.png)

リクエスト確認画面で、ステータスが `失敗` であることに気づいた

![スクリーンショット 2025-02-22 18.19.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661290/9611a795-aa0b-437f-a53f-b25dc536b16f.png)

# エラー内容

メールには以下のメッセージが届いていた

> Dear AWS customer,
>
> We recently received an online request from your AWS account to register the following domain name:
>
> [hogehoge].com
>
> We weren't able to register the domain name.
>
> This happened for the following reason(s):
>
> We can't finish registering your domain. Contact AWS Support at `https://console.aws.amazon.com/support/home#` for further information.
We apologize for the inconvenience. For more information, contact Amazon Web Services Customer Support.
>
> Regards,
> Amazon Route 53  

<details>
<summary>日本語訳バージョン</summary>

>AWSのお客様へ
>
> 最近、お客様の AWS アカウントから次のドメイン名を登録するためのオンラインリクエストを受け取りました:
>
>[hogehoge].com
>
>ドメイン名を登録できませんでした。
>
>これは次の理由で発生しました:
>
>ドメインの登録を完了できません。詳細については、AWS サポート`https://console.aws.amazon.com/support/home#` ) にお問い合わせください。
ご不便をおかけして申し訳ございません。詳細については、 Amazon Web Services カスタマーサポートにお問い合わせください。
>
>よろしくお願いいたします。
>アマゾンルート53

</details>

# サポートに問い合わせ後

エラーの指示通りに問い合わせたところ、5日後に以下の返答

>確認にお時間を要しており、ご不便をおかけしております。
海外にある担当部署から回答を得られましたので、下記にご案内いたします。
>
>確認したところドメイン登録の制限が加えられていたため、担当部署にて制限を解除させていただきました。
>(ご利用状況等により制限が加えられる場合がございます。)
>
>つきましては、お手数ではございますが、ドメインの登録を改めてお試しいただきますよう、お願い申し上げます。
>※ ドメイン登録の際の連絡先情報等は半角英数字でご入力いただきますよう、お願い申し上げます。
>
>もし、引き続きドメイン登録ができない場合は、改めて担当部署に申し送りいたしますので、
お手数ではございますが、本ケース上よりエラー画面のスクリーンショットをご提供いただきますよう、お願い申し上げます。
>
>ご案内は以上となります。お客様の一助となれば幸いです。


# ドメイン取得 再挑戦
できた！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661290/66fba33c-d5ca-406d-a2eb-7a38a2756c4d.png)

# まとめ
困ったことがあればネットで似たケースがないか調べて、解決しなければサポートに相談すべし！
個人アカウントなのでサポート対応は少し遅めですが、一人では解決できないケースだったので問い合わせてよかったです
ABC398回答メモ

# 0.はじめに
　先週緑にギリギリ上がったので、もう少し余裕を持ったレートにしたいと挑んだ今回。
　Ａ～Ｃは順調に解けましたが、Ｄがどうにも上手くいかない・・・。
　Ｅを見てみたら、インタラクティブで考え方自体は簡単で
　実装方法のみだな。という感じだったのでそちらにチャレンジし
　めでたく4問正解となりました。
　レートだいぶ上がるかなとおもいきや、まさかのレートマイナス１で
　世の中は甘くないことを知りました。


# 1.A - Doors in the Center
　最初ちょっと意味が分かりませんでしたが、問題名を見て
　=がドアでこれを真ん中に持ってくる感じなのねと気づきました。
　=が1個か2個なので、偶奇で場合分けをして、それぞれの
　壁(-)にドア(=)を挟む形で実装しました。

　https://atcoder.jp/contests/abc398/submissions/64030719


# 2.B - Full House 3
　まずはカウンター関数でリスト内の数字毎の個数を取得。
　数字内の個数で並べ替えても良かったのですが
　それも面倒だったので、単純に3枚以上あるフラグと
　2枚以上あるフラグを用意して、カウンター内の
　個数が3以上の要素があれば3フラグを立て
　2以上があれば2フラグを立てて
　最後にフラグが両方立っていればYesとしました。
　ポイントとして3枚3枚のケースを考え、3フラグが立っているときに
　3枚以上が来たときは2フラグを立てるようにしました。

　https://atcoder.jp/contests/abc398/submissions/64041730


# 3.C - Uniqueness
　こちらもカウンターを使う問題。
　まずリストをカウンター関数で数字毎の持っている人数に変換。
　カウンターの要素をすべて見ていき、持っている人が1人の数のうち
　一番大きい数Xを確定。
　最後にリストを端から見ていき、Xの位置を出力して終了。
　持っている人が1人の数が無ければ-1を出力して終了。

　https://atcoder.jp/contests/abc398/submissions/64050062


# 4.E - Tree Game
　インタラクティブはテストがむずかしいんだよな。
　とおもいつつもDが見込みなしなので挑戦。
　【考え方】
　　1.最初のインプットを読み込み木グラフに加える事の
　　　出来る辺を以下の条件で求める
　　　・追加順に関わらず一定
　　　・頂点i,jの組（i<j）のうち以下を共に満たす組
　　　　-距離が2以上（辺が張られていない）
　　　　-距離が奇数(つなげた時奇閉路にならない)
　　2.上記辺の組数が奇数ならFirstを出力し
　　　辺の組から一つ取出して出力
　　3.辺の組数が偶数ならSecondを出力
　　4.以下、相手のアウトプットが-1になるまで
　　　相手のアウトプット分を辺の組から消し、
　　　残った辺の組から任意の一つを出力していけば
　　　勝利できる。
　奇閉路等、聞きなれない言葉はありましたが
　実装してしまえば何とかなる問題でした。

　https://atcoder.jp/contests/abc398/submissions/64095802


以上
ESET Endpoint Antivirus for LinuxのWebアクセス保護

Linux版のESETにて、Webアクセス保護の機能が提供されています。
この機能の有効化を、強く推奨されています。

https://help.eset.com/eeau/11.1/ja-JP/web_access_protection.html

ただし、何かしらの理由で問題が発生している場合は、機能をOFFにしてインストールすることが可能です。

https://help.eset.com/eeau/11.1/ja-JP/installation_without_wap.html

※`ESET_DISABLE_WAP=1`の環境変数を指定してインストールする

すでにESETをインストール済の場合は、一度アンインストールする必要があります。

https://help.eset.com/eeau/11.1/ja-JP/installation_without_wap.html?uninstall.html

Webアクセスの有無は、「保護の状態」で確認可能です。

Webアクセス保護あり | Webアクセス保護なし
---|---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106949/00738e31-9cf2-47a1-a560-ed3540a4cd25.png) | ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106949/2ea01241-7e8c-4d80-a1bd-541e6d5a909d.png)


---


再インストールせずに、一時的に解除することも可能なようです。


以下のコマンドで、現在の設定をエクスポートできます。

```
sudo /opt/eset/eea/lib/cfg --export-xml=/tmp/eset.xml
```

この設定のうち、`WebProtectionEnabled`という項目を 1 から 0 に変更してインポートすると、解除が可能です。

```xml
<NODE NAME="WebProtectionEnabled" TYPE="number" VALUE="0" />
```

```
sudo /opt/eset/eea/lib/cfg --import-xml=/tmp/eset.xml
```

何か問題が発生したとき、特に通信時のパフォーマンス悪化が著しいなどの場合は、これで問題が解消するかを確認すると良いのかなと思います。

特に会社PCなどでWebアクセス保護を解除する場合、情シスの方に確認をとってから実施すると良いのかなと思います。

※私の場合はGoogle MeetでCPUが99%に張り付いていました
老後に役立つ情報

個人年金をもらっている期間と生命保険に加入している期間は、ずっと確定申告が必要とわかった。

# 住民税の控除額（国税との違い）
基礎控除　43万円
生命保険料　７万まで
配偶者特別控除　33万円

# 退職金にかかる税金

https://www.nta.go.jp/publication/pamph/koho/kurashi/html/02_3.htm

# 個人年金にかかる税金

https://www.hokennomadoguchi.com/columns/seimei/kojin/kakutei/need/

https://www.jili.or.jp/knows_learns/q_a/tax/568.html

・1年間に受取る年金　ー　必要経費は、雑所得
・その年の他の所得とあわせて総合課税となる
・雑所得が、25万円以上になると10.21％が源泉徴収される（３月に多額の税金を納めなくてよい仕組み？）
・源泉徴収されても、源泉分離課税ではないので、 `確定申告` をして精算が必要

なお、雑所得＋源泉徴収票の支払金額（引かれる前の給料）が900万円を超えると、配偶者（特別）控除が38万円ではなく、26万円、13万円と下がっていくので注意が必要。

https://www.nta.go.jp/taxes/shiraberu/taxanswer/shotoku/1191.htm

ライフプラン上、個人年金にかかる税金は、
・給与収入があるときは、所得税10%＋住民税10%
・給与収入も年金もない時は、`確定申告`して源泉徴収分を`還付`してもらいゼロに
・年金生活になったら、所得税５%＋住民税10%
くらいで計算しておけばいいだろう。

# 公的年金にかかる税金

私の場合、所得税５％、住民税10％と思っておけばいいだろう。

https://www.nta.go.jp/taxes/shiraberu/taxanswer/shotoku/2260.htm

### 公的年金等控除額

たぶん、サラリーマンの必要経費みたいなやつ
私の場合、110万円


https://www.nta.go.jp/taxes/shiraberu/taxanswer/shotoku/1600.htm

### 基礎控除

48万円（住民税計算時は43万円）

https://www.fp.au-financial.com/media/shisan/article-077.html

### 配偶者控除

38万円（住民税計算時は33万円）

### 生命保険料控除

確定申告したら、12万まで控除される
仮に10万円とすると、約15,000円還付される計算。

https://biz.moneyforward.com/tax_return/basic/41492/

# 社会保険料

https://www.city.hatsukaichi.hiroshima.jp/soshiki/9/10061.html

老後の社会保険料（医療＋後期高齢者支援金＋介護保険）は、夫婦二人で、年間、
７４歳まで、約４０万円
７５歳から、約３３万円
と判明
【JavaScript】ABC397感想（A~E）

AtCoder Beginner Contest 397

https://atcoder.jp/contests/abc397

こんにちは。昨日ABC398にrated参加しました。
その記事も書こうと思うのですが、それ以前にABC397のバチャを走ったのでまずはそれをまとめます。

結果、ABCの3完（25分0ペナ）でした。
unratedですが、AC predictorによると778perfらしいです。
ただの精進不足ではあるのですが、D問題が解けないのはいただけませんね。
今回はA~Eまでの感想を述べていきます。

# A - Thermometer
https://atcoder.jp/contests/abc397/tasks/abc397_a

整数部分は入力の1,2番目、小数部分は4番目です。
それぞれ受け取り、場合分けすれば良いですね。

# B - Ticket Gate Log
https://atcoder.jp/contests/abc397/tasks/abc397_b

現在「入場中」なのか、「入場していない」のかの状態管理をして、「入場中」（未処理の`i`がある）なのであれば次の文字は`o`でなければなりません。また、「入場していない」（未処理の`i`がない）なのであれば次の文字は`i`でなければなりません。
以上を念頭に置いて、条件に合致しない文字が来てしまったらその都度文字を挿入します。
この回数が求めるべき答えです。

# C - Variety Split Easy
https://atcoder.jp/contests/abc397/tasks/abc397_c

整数列を二分する位置を左端→右端に一つずつずらしていって、左側にある整数の個数と右側にある整数の個数を差分更新する方法で解きました。これは、各整数の右端のインデックスを事前に求めておくことによって計算できます。

# D - Cubes
https://atcoder.jp/contests/abc397/tasks/abc397_d

これは、`全探索`＋`二分探索`の典型ですね。
バチャ中は、うまいこと式変形すれば$x-y$が$\sqrt[3]{N}$で上から抑えられるということに気がつきませんでした。

# E - Path Decomposition of a Tree
https://atcoder.jp/contests/abc397/tasks/abc397_e

`dfs`（`木DP`）で部分木分解っぽいことをすればいいのはすぐ見えました。
部分木の頂点数が$K$より大きいか、同じか、小さいかでそれぞれ場合分けして、別々の処理をする感じです。
しかし、どうしても`WA`が取れずタイムアップしてしまいました。
部分木がパスになっていないといけない、という辺りの条件をきちんと反映できていないかもしれません。

# まとめ
D,Eは水を目指すのであれば解けなければいけない問題だと思うので、しっかり復習して解けるようにしていきます。
バチャでは解けませんでしたが、考えていくうちにだんだんと競プロの勘を取り戻してきました。
色々と忙しい最近ですが、なんとか実力を維持・向上していきたいものです。
Apple Silicon Mac + Zephyr SDK + Docker で nRF52 をビルドするまでの記録

Zephyr SDK (v2.8.0) を使って nRF52 向けファームウェア開発を進める中で、Apple Silicon Mac によるビルド停止・ハング問題に悩まされました。この記事では、その原因と対策、そして **Dockerを使って安定してビルドする手順** をすべて共有します。

---

## システム情報

- **MacBook Pro M2 (Apple Silicon)**
- **nRF52832 / nrf52dk**
- **nRF Connect SDK v2.8.0**
- **Zephyr SDK v0.16.3**
- **Docker Desktop v25.0.2 (GUI バージョン)**

---

## 発生した問題

### west build で止まる
```
-- Found GnuLd: ld.bfd
```
このメッセージの直後で west build が停止し、プロンプトが返ってこなくなる現象が発生する。これは、Apple Silicon 環境が Zephyr SDK に正式対応していないことが原因と考えられる。

---

## 解決策: Dockerを使ってビルド

### 1. Dockerが使えるか確認
```bash
docker --version
# Docker version 25.0.2, build 29cf629
```

使えない場合は Docker Desktop を開き、`Preferences > Resources > File Sharing`で `/Users/<yourname>` を指定することで CLI でも利用可能になります。

### 2. Dockerイメージ(nordic)のダウンロード
```bash
docker pull nordicplayground/nrfconnect-sdk:v2.9-branch
```

### 3. Dockerでビルド実行
```bash
docker run --rm -it \
  -v $HOME/nordic/v2.8.0:/workdir \
  -w /workdir/emg_sensor_firmware \
  nordicplayground/nrfconnect-sdk:v2.9-branch \
  west build -b nrf52dk/nrf52832 --pristine=always -- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
```

### 4. HEXファイルの作成を確認
```bash
ls -lh ~/nordic/v2.8.0/emg_sensor_firmware/build/emg_sensor_firmware/zephyr/zephyr.hex
```

---

## 実機へ書き込み
```bash
nrfjprog --eraseall
nrfjprog --program ~/nordic/v2.8.0/emg_sensor_firmware/build/emg_sensor_firmware/zephyr/zephyr.hex --chiperase --verify --reset
```

---

## ビルド成功ログ一部
```text
Memory region         Used Size  Region Size  %age Used
           FLASH:       18526 B       512 KB      3.53%
             RAM:        5632 B        64 KB      8.59%
        IDT_LIST:          0 GB        32 KB      0.00%
[10/10] Generating ../merged.hex
```

---

## ポイント
- Apple Silicon 環境で Zephyr SDK を使うと、`ld.bfd` でビルド停止することがある
- Docker の SDK イメージを使えば、依存性と対応バージョンに問題なくビルド可能
- VS Code ではなく CLI/ターミナル での実行が安定

---

## おわりに
Apple Silicon で Zephyr SDK を利用するのは現状体験としてハードルが高く、官方Dockerイメージを利用するのが最も確実な手段でした。
クイックコールのすすめ

世界一流エンジニアの思考法という書籍を読んだので、自分用メモ。

## クイックコールをするメリット
- 方向性を間違うリスクを下げることができる
→認識違いで、戻り作業になることがなく、結果的に効率化を図ることができる

## クイックコールをする上で
メンバー同士の関係性。気軽に聞ける、気軽に聞きに来られる関係性が重要
この関係性があることで、簡単な質問でも聞くことが可能。例えばAzureってなに？などの簡単な質問も行うことができる。

## 取り掛かる課題をレベル１～４に振り分ける
レベル1：ググらずにできるもの
レベル2：ググってできるもの
レベル3：解決策は知らないが、スパイクソリューションをすれば解決できるもの
レベル4：自分ひとりでは解決できないもの

優秀なエンジニアでも深い理解をするには時間がかかる
クイックコールで、レベル１の連続に落とし込む
laravelでDBの値を配列でキャッシュに保存、表示、削除する方法

laravelでDBデーターをキャッシュに保存表示削除する。ServicesでキャッシュとconfigにsetしProvidersに登録表示を設定しProviderをconfig>app.php>providerに設定する。blade.phpに{{config()}}でキャッシュに保存されたDBの値を呼ぶことができる。こんなに複雑な処理が必要なのか？
関数型プログラミングをかじってみた。

## 🏆 1. 導入 - fp-goで遊ぼうと考えたきっかけ

### **Goで関数型プログラミングに興味を持った背景**

- 数学が好きな自分にとって、プログラミングに数学を持ち込むという思想に興味が湧いた。
- 実際に遭遇した課題・悩み
    - **エラーハンドリングが煩雑**
    - **テストがしにくい**

### **fp-go を選んだ理由**

- 手っ取り早く関数型プログラミングを体験することができると考えたから



## 🔎 2. 実践 - 実際に何をやったか

### **基本概念**

- fp-goを活用して簡単なアプリを作成してみた
    - モナド三兄弟を積極的に活用した。

### **コード例**

- 通常のGoコードと `fp-go` コードの比較

### **Before: 通常のGoコード**

```go
func (s User) Login(authCode string) (dto.UserInformation, error) {
	// 認証APIからユーザー情報を取得
	user, err := s.authorizeAPI.GetUserInfo(authCode)
	if err != nil {
		return dto.UserInformation{}, err
	}

	// ユーザーのメールアドレスを取得
	email := user.GetEmailObject()

	// 重複チェック
	isDuplicate, err := domainservice.CheckDuplicate(s.userRepository, email)
	if err != nil {
		return dto.UserInformation{}, err
	}

	var userInfo user.User
	if isDuplicate {
		// 重複している場合、ユーザー情報を取得
		userInfo, err = s.userRepository.GetUserInformation(email)
		if err != nil {
			return dto.UserInformation{}, err
		}
	} else {
		// 重複していない場合、ユーザー情報を保存
		userInfo, err = s.userRepository.SetUserInformation(user)
		if err != nil {
			return dto.UserInformation{}, err
		}
	}

	// DTOに変換して返却
	return dto.NewUserInformation(userInfo), nil
}
```

### **After: fp-goでのGoコード**

```go
func (s User) Login(authCode string) E.Either[error, dto.UserInformation] {
	userE := s.authorizeAPI.GetUserInfo(authCode)
	idE := E.Map[error](
		func(user user.User) email.Email {
			return user.GetEmailObject()
		})(userE)

	return FP.Pipe4(
		E.Right[error](domainservice.CheckDuplicate(s.userRepository)),
		E.Ap[E.Either[error, bool]](idE),
		E.Flatten,
		E.Chain(
			func(duplicate bool) E.Either[error, user.User] {
				if duplicate {
					return E.Chain(s.userRepository.GetUserInformation)(idE)
				}
				return E.Chain(s.userRepository.SetUserInformation)(userE)
			}),
		E.Map[error](dto.NewUserInformaiton),
	)
}
```

✅ Either で成功/失敗を型で管理

## 🏆 3. 感想 - fp-go を使って感じたこと

### 🌟 **メリット**

✅ **コードの可読性が向上**

- `Either` を使うことで成功/失敗の分岐が一目でわかる
- パターンマッチにより、if文やswitch文を減らせる
- 場合によっては、記述量が少なくなり、すっきりした

✅ テスト容易性

- 例外処理がなくなったため、テストが容易
- 直感的なテストになった。（純粋関数のテストが多いため。）

---

### ⚠️ **デメリット**

❌ **記述量が増える**

- 型パラメータや `fp-go` のラップ処理でコードが冗長になりがち
- Goのシンプルなスタイルに慣れていると、コードが「難しく」見える可能性

❌ **学習コストが高い**

- `Option`, `Either`, `IO` などの概念に慣れる必要がある
- いきなりチームで導入するにはハードルが高い

❌ **Go標準ライブラリとの相性**

- Go の `error` 型との互換性が微妙


## 🎯 4. まとめと展望

### 🔥 **fp-go を導入して得られたこと**

- ✅ `Either` でエラーハンドリングを統一 → 可読性と保守性が向上
- ✅ 関数型のアプローチでコードの再利用性がアップ
- ✅ モナドと少しだけ仲良くなることができた
- 🟥 Goは関数型での実装に不向きであるこように感じた
    - 型推論が強い言語で勉強してみるべき
- ✅ 関数型プログラミングは楽しい！！


## 🔮 5. 参考リンク

- [fp-go GitHub](https://github.com/IBM/fp-go)
- [fp-go の公式ドキュメント](https://github.com/IBM/fp-go)


## 🤔 6. 最後に

- 関数型プログラミングの雰囲気を掴むには実際にアプリを作ってみるのが一番
    - 書いてみる→gpt等にレビューしてもらう→新しい概念を知るというループで少しずつ仲良くなろう
【ChatGPT】物品の店頭価格の現在と今後の見通しを出すPromptです。


　どうも、カーブミラーです。

　今回は、物品の店頭価格の現在と今後の見通しを出すPromptです。Web検索の結果を出すものです。

:::note info
本記事は、ChatGPT（Plus版）
で行なっております。
画像はありません。あしからず。
:::
　ChatGPT等の動作状況を知らせる
　　OpenAIのステータスページ。
　　　[OpenAIステータス](https://status.openai.com/)
***
　こちらも載せますね。
　　[ChatGPTが使えない？ログインできない・反応しない原因やエラー時の対処法を解説](https://aismiley.co.jp/ai_news/chatgpt-error-resolution-explanation/)
***
　まずは、ニュースです。

　動画生成AIのSoraですが、
　　なんと
　　　クレジット制を撤廃、
　　　　無制限利用に！！
![Screenshot_20250322-123309.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/35580f62-7bca-49af-b526-6f3219a107e8.png)

（本来は英語）

　・ChatGPT Plus, Team：
　　　720p・10秒まで無制限生成
　・Pro：
　　　1080p・20秒まで無制限生成、
　　　同時5本生成可、
　　　透かしなしDL対応

　※ Free、Enterprise、Eduは対象外。
***
　では、【本題】です。

　今回は、
　　物品の店頭価格の現在と
　　　今後の見通しを出すPromptです。

　このPromptは、
　　＊＊＊に物品を入力して、
　　　送信してください。
```Text:物品の価格の調査Prompt
「＊＊＊」に関して調査してください。

現在の店頭価格と、今後予想される価格について、信頼できる日本国内の情報源を基に示してください。項目分けした記事にしてください。

情報源は、ユーザー自身でも確認可能な安定したURL（PC／スマホ／OS問わずアクセス可能）であり、価格情報が明確に掲載されているページに限ります。動的または流動的なカテゴリページを情報源とする場合は、トップページからの明示的な誘導が確認できることが条件です。

スマートフォンでの閲覧にも問題がないことを事前に検証し、不確実な情報や信頼性の低い情報源は一切使用しないでください。調査結果には必ず確認可能なURLを記載してください。
```

　このPromptを使うと、
　　情報源をWeb検索して、
　　　現在の店頭価格や今後の見通しを
　　　　出してくれます。

　あくまでも
　　情報源からの抜粋であり、
　　　未来予測ではありません。
　　　　ご注意ください。

　Prompt中にある
　　“情報源は〜”以降は、
　　　示されるURLリンクが
　　　　見つからない場合が
　　　　　多々あったためのものです。

　　ハルシネーションではなく、
　　　Web検索では見つかるものの
　　　　ブラウザでアクセスすると
　　　　　ページが見つからないのです｡

　　原因はいくつか考えられますが、
　　　アクセスがパソコンかスマホかで
　　　　振り分けられ、スマホでは
　　　　　記事がなかった可能性が
　　　　　　あります。

　　とはいえ、
　　　そんなことが
　　　　あちこちであるというのも
　　　　　おかしな話なので、
　　　　　　ほかの原因も
　　　　　　　絡んでのものでしょう。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
Codility対策! PHPでコーディングテストを受けるときのポイント

# はじめに
前回Codilityでコーディングテストを受けたときの感想と、対策について簡単に書いたので、今回はPHPでテストを受けるときに知っておくと良さそうなポイントをまとめます。
Codilityはアルゴリズムとデータ構造の理解が問われます。特に時間計算量(O記法)を意識した最適なコードを意識することが重要です。

# Codilityの問題で求められる力 :muscle:
1. **正確性** : 全てのテストケースを正しく解けるか
2. **効率性** : 大きな入力サイズでも高速に処理できるか
3. **コードの可読性** : 可読性の高いコードになっているか


Codilityでは、提出後に受験者のコードの入力過程が確認できます。そのため、AIで生成したコードをそのままコピペした場合、簡単に判別可能です...

# コーディングテストで気をつけること :pencil: 
### 1. 時間計算量を意識する
`O(n^2)`のような時間のかかるアルゴリズムだと、大きいデータセットでは処理に時間がかかり、タイムアウトになってスコアが低なりがちです。

- `O(n)`や`O(n log n)`になるように意識する
- ループのネストが深くならないようにする
- 無駄な計算を省く (事前に配列をセット化するなど..)

```php
// 配列$arrに重複する要素がある場合trueを返す処理
// ex. $arr = [3, 2, 9, 5, 6, 8, 2]
// => return true (重複する要素 2)

// 非効率な方法（O(n^2)）
function hasDuplicateSlow($arr) {
    for ($i = 0; $i < count($arr); $i++) {
        for ($j = $i + 1; $j < count($arr); $j++) {
            if ($arr[$i] == $arr[$j]) {
                return true;
            }
        }
    }
    return false;
}

// 効率的な方法（O(n log n)）
function hasDuplicateFast($arr) {
    sort($arr); // O(n log n)
    for ($i = 0; $i < count($arr) - 1; $i++) {
        if ($arr[$i] == $arr[$i + 1]) {
            return true;
        }
    }
    return false;
}
```

### 2. 組み込み関数を利用する
PHPには便利な組み込み関数が用意されているので、これらを活用しましょう！
| 操作 | 関数 | 計算量 |
|:-:|:-:|:-:|
| 配列の要素をユニークにする  | `array_unique($arr)` | `O(n)` |
| 配列をセット(辞書型)に変換 | `array_flip($arr)` | `O(n)`  |
| 文字列の中に要素があるか確認 | `in_array($value, $arr)` | `O(n)`  |
| 配列内に要素が存在するか確認 | `isset($arr[$key])` | `O(1)`  |
| 文字列を分割する | `explode($delimiter, $string)` | `O(n)`  |

### 3. ハッシュセットを活用する
連続する数字の最大長を求める問題では、ハッシュセットを活用すると`O(n)`で解くことができます。
```php
// 最長の連続部分列の長さを求める
// ex. $arr = [100, 101, 102, 103, 104, 4, 200, 1, 3, 2]
// => return 5 (100, 101, 102, 103, 104)
function longestConsecutive($arr) {
    $set = array_flip($arr);
    $maxLength = 0;

    foreach ($arr as $num) {
        if (!isset($set[$num - 1])) {
            $currentNum = $num;
            $currentLength = 1;

            while (isset($set[$currentNum + 1])) {
                $currentNum++;
                $currentLength++;
            }

            $maxLength = max($maxLength, $currentLength);
        }
    }
    
    return $maxLength;
}
```

# まとめ
以下のポイントを押さえておくと、スコアアップにつながります。
:white_check_mark: `O(n log n)` 以下の解法を探す
:white_check_mark: PHPの組み込み関数を活用する
:white_check_mark: `isset($arr[$key])`や`array_flip()`で高速検索

次回は注意点についてまとめていきたいと思います。
参考になれば幸いです:apple:
session()->forget() の使い所と実践例まとめ

# はじめに

Laravelでセッションを使っていると、「セッションの中身を消したいな」と思う場面があります。  
そんなときに便利なのが、`session()->forget()` です。  

この記事では、`forget()` の基本的な使い方と、実務でどう使われるかを自分の備忘録としてまとめておきます。

---

# ①基本構文

```php
session()->forget('キー名');
```

または、複数キーをまとめて消す事も可能

```php
session()->forget(['キー1', 'キー2']);
```

# ②よくある使用例
**1.フォームの一時的な入力値をクリアしたいとき**

```php
session()->forget(['name', 'email']);
```

- ユーザーが入力した値をセッションに保存しておき、何かのタイミングでそれをリセットしたいときに使います。

**2.フラッシュメッセージを手動で消したいとき**

通常、フラッシュメッセージ（session()->flash()）は次のリクエストで消えますが、
自前で session()->put() しているときは、明示的に forget() で消すこともあります。

```php
// 例：成功メッセージを消す
session()->forget('success');
```

**3.ログアウト処理の際に、セッション情報をクリア**
```php
Auth::logout();
session()->forget(['user_name', 'login_time']);
```
- session()->flush() を使えば全削除できますが、一部だけ消したいときは forget() が便利です。

# ③forget() と flush() の違い

![IMG_7721.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/f8967cfa-e8a1-472e-a2de-c9c06a5d98b8.jpeg)

# ④セッションデータの確認・取得
```php
session()->get('key');    // セッションから値を取得
session()->has('key');    // 値が存在するか確認
session()->all();         // セッションの全データを見る（開発用）
```
# ⑤実務での使い所まとめ

![IMG_7722.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2246240/327f3817-2fc8-41d7-8368-9da679d92ad8.jpeg)

# ⑥まとめ
- session()->forget() は**セッションの一部だけを削除**したいときに便利

- フォーム処理やメッセージ管理、ログアウト処理など幅広い場面で活躍

- セッションまわりの挙動を理解しておくと、より安全で柔軟なアプリが作れます！
ハッキングの始め方　①環境構築　ーDockerを利用してkali-linux環境を構築ー

# 【初心者向け】WindowsでDockerを使ってKali Linux環境を構築する方法

【注意事項】ハッキングの違法性と価値観について
ハッキング技術は違法行為に使われる可能性がありますが、本記事は教育的目的で提供するものです。
技術は道徳を持って正しく利用しましょう。

 ## 【概要】Kali Linuxを安全に使う
 Kali LinuxはセキュリティテストやCTF練習で便利なLinuxディストリビューションですが、直接マシンにインストールするのは危険です。

セキュリティツールには強力な攻撃機能を持つものが多く、誤操作によりシステムを不安定にしたり、他のネットワーク機器へ影響を与えてしまう恐れがあります。
そのため、本番環境とは分離された仮想環境（今回はDockerを利用）が推奨です。

### 【Dockerについて】

Dockerは「コンテナ」と呼ばれる分離された仮想環境でアプリを実行できるシステムです。
仮想環境でアプリを実行できる手段はいくつかありますが、Dockerには以下のような明確なメリットがあります：

#### ✅ Dockerのメリット：

軽量で高速（仮想マシンより起動が速い）

システムに影響を与えずに環境構築ができる

再現性が高く、環境の共有も簡単

実際の環境構築については以下に記載します。

## 【Kaliを使うのに必要なスペック】

Kali Linuxを快適に動かすための推奨スペックは以下の通りです：

- CPU：6コア以上

- メモリ：16GB以上

- ストレージ：20GB以上の空き容量

- OS：Windows 10 / 11（64bit）

## 【必要なアプリのインストール手順】

#### 🔹 Docker Desktop for Windows

公式サイト：
https://www.docker.com/products/docker-desktop/

ダウンロード後、インストーラーを実行し、すべてデフォルトでインストール

完了後に以下で確認：
```bat
docker --version
```

#### 🔹 VcXsrv（GUI表示のためのXサーバ）

ダウンロード：
https://sourceforge.net/projects/vcxsrv/

インストール後、XLaunch を起動して以下を選択：

- Multiple windows

- Start no client

- Disable access control にチェック

#### 🔹 PulseAudio for Windows（音声出力用）

参考ページ：
https://www.freedesktop.org/wiki/Software/PulseAudio/Ports/Windows/Support/

上記からZIPファイルをダウンロードして解凍、pulseaudio.exe を起動しておく

### 【環境変数の設定（Windows専用）】

上記アプリのインストールと起動が完了したら、WindowsでGUIや音声を使うために環境変数を設定します。

#### 🔽 バッチファイルのダウンロード

setup.bat：
https://github.com/K4zushi0701/kali-linux/blob/main/setup.bat

⚙️ 実行手順

上記URLにアクセスし、右上の「Raw」をクリックして右クリック→名前を付けて保存

ダウンロードした setup.bat をダブルクリック

正常に実行されると「環境変数が設定されました」と表示されます

### 【Dockerfileの作成】

以下のDockerfileを使えば、ツールやワードリストが設定されたKali Linuxを簡単にビルドできます。

#### 🔽 ダウンロード

Dockerfile：
https://github.com/K4zushi0701/kali-linux/blob/main/dockerfile

📂 手順

任意のフォルダを作成（例：C:\Users\YourName\kali-docker）

上記URLから dockerfile をダウンロードしてその中に保存

フォルダ内でターミナルを開き、以下のコマンドでビルド：

```bat
docker build -t kali-linux_image .
```

※ 初回ビルドには数分かかります

【Kali Linuxコンテナの実行】

Dockerイメージのビルドが完了したら、以下のコマンドでKali Linuxを起動します。

```bat
docker run -it --network host --privileged --name kali-linux \
  -m 12g --memory-swap 16g --cpus=6.0 \
  -e DISPLAY=host.docker.internal:0.0 \
  -e PULSE_SERVER=tcp:host.docker.internal \
  -v /tmp/.X11-unix:/tmp/.X11-unix --device /dev/snd \
  kali-linux_image bash
  ```

このコマンドにより、GUIアプリ（例：Wireshark、Firefox）や音声出力が可能なKali環境が起動します。

# 【まとめ】

- Kali Linuxはハッキング演習に最適な環境

- Dockerを使えば、システムを汚さず安全に環境を構築できる

- Windows環境でもGUIや音声出力の設定が可能

- 必要なファイルはGitHubからダウンロードしてすぐに実行可能

この環境が構築できたら、TryHackMeやHack The Boxなどの実践演習に進むのがおすすめです
BIMIの検証環境を作成してみた

# はじめに
BIMIを実装するために、事前テストとして検証環境を作成した。このプロセスで学んだことを備忘録としてまとめておく。

# BIMIとは
BIMI（Brand Indicators for Message Identification）は、電子メール送信者がブランドロゴを認証済みの形でメール受信者に表示できる仕組みである。
こんな↓感じです。※例：Qiita

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/0758ff04-6b06-4017-8528-a9f91ffaad98.png)

# BIMI導入メリットの個人的見解
**ブランドロゴ表示による認知度向上**
ロゴを受信メールに表示することで、ブランドの視認性や認知度を向上させることができる。

**フィッシングメール対策**
正規送信者であることが一目で分かり、不正なフィッシングメールとの識別が容易になる。

# BIMIを実装するための対応
**DMARCレコードの設定**
”p=reject”または”p=quarantine”でDMARCレコードを設定する。（例：hoge.com ドメイン）
```DMARCレコード
_dmarc.hoge.com TXT "v=DMARC1; p=reject; aspf=r; adkim=r"
```
**SVG形式のファイルの準備**
表示させたいロゴをSVG（Scalable Vector Graphics）Tiny 1.2 P/S形式で用意する。
SVGとは、ベクター形式の画像を記述するためのXMLベースのファイルフォーマット。
SVGは数式で形状を定義するため、画質を損なうことなく自由に拡大・縮小することができる。
用意するSVGは以下の条件を満たす必要あり。
・32KB以下
・title要素の指定
・改行コードは"LF"で指定する（"CRLF"は不可）
・ラスタ形式の埋め込み画像（image要素）を指定しない

**TLS1.2以上に対応したWebサーバにSVGファイルを配置する**

**VMC（Verified Mark Certificate）を取得する**
Gmail等のメーラーで表示させるためには必須。
VMCの取得には、ロゴを商標登録している必要がある。
なお、一部のメーラー（例：Fastmail）ではVMCなしでも表示可能である。

**BIMIレコードの設定**
"hoge.com"ドメインで設定する場合はこんな感じである。
```BIMIレコード
  default._bimi.hoge.com TXT "v=BIMI1;l=https://hoge.com/test.svg ; a=https://hoge.com/test.pem"
```

lタグ・・・必須。svgファイルの配置パスを指定する。
aタグ・・・任意。VMCの配置パスを指定する。

# 検証環境構築手順

とりあえず、てっとり早く"さくら"で検証環境を構築した。

**①ドメイン取得（詳細割愛）**
**➁DMARCレコード設定（p=reject）**
**➂BIMIレコード設定**
設定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/331dd376-2755-4ec7-9afe-b699715bc685.png)

**④SVGファイルの作成**
Copilotで犬のイラストを作成して表示させます。

画像を作成しました。これをSVG Tiny 1.2 P/Sに変換します。
![DOG (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/ff0f8ee9-ac9e-4f2c-b8f2-83474845279b.jpeg)


1) "JPG → SVG" への変換
以下のサイトを利用させていただきました。
https://www.luft.co.jp/cgi/jpeg-svg.php

2) "SVG → SVG Tiny 1.2 P/S"に変換
以下のツールを利用させていただきました。
https://github.com/authindicators/svg-ps-converters

title要素も記述済です。
```test.svg
<title>Dog</title>
```

**⑤SVGファイルのホスティング**
作成したSVGファイルをWEBサーバにホスティングします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/010845a7-d090-4d8d-bda7-54a0b6332744.png)

**⑥表示確認**
Fastmailで表示できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/4169ca70-b927-44e9-afd5-adc0e0c4d123.png)

メールヘッダも”bimi=pass”となっているので問題なさそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513939/a1bc04cd-f20e-428b-bc93-8b88e2876a5b.png)

*ちなみに、yahoo.comでは表示されなかった。yahoo.comできるって書いてたのに。。。
https://bimigroup.org/understanding-bimi-certificate-types/

なお、エラーが発生した場合は、以下のメッセージがメールヘッダに表示される。
・**bimi=fail (SVG did not validate)** ・・・SVGファイルが不正の場合に表示される。
・**bimi=temperror (Could not fetch SVG)**・・・SVG取得失敗の場合に表示される。WAF（Web Application Firewall）とかでブロックされた場合によく出る。

# 参考サイト
参考になりました。ありがとうございます。

■BIMIを使ってメールにロゴを表示する方法 (送信者編)
https://qiita.com/hirachan/items/85d0983ebfa0e5034041

■RFC 4406
https://datatracker.ietf.org/doc/html/rfc4406
VueアプリをS3 + CloudFrontにデプロイするシェルスクリプト

## 概要
Vueの静的コンテンツをS3にアップロードし、CloudFrontで配信する環境において、ローカルで変更を加えた際にスムーズにデプロイできるようにする

## 環境
- S3: Vueの静的コンテンツを格納
- CloudFront: S3のコンテンツをキャッシュし、高速配信
- AWS CLI: デプロイスクリプトで使用
- Vue: `npm run build` で静的ファイルを生成

## デプロイの流れ
1. Vueプロジェクトをビルド
2. S3にアップロード
3. CloudFrontキャッシュを無効化

## デプロイスクリプト
以下のシェルスクリプトを作成し、ローカルからデプロイできるようにする

### `deploy.sh`
```sh
#!/bin/bash

# 設定
S3_BUCKET="your-s3-bucket-name"
DISTRIBUTION_ID="your-cloudfront-distribution-id"

# Vueプロジェクトのビルド
echo "Building Vue project..."
npm run build

# VueのリソースをS3へアップロード（dynmapフォルダは削除しない）
echo "Uploading Vue files to S3..."
aws s3 sync dist/ s3://$S3_BUCKET --delete --exclude "削除から除外したいディレクトリ"

# CloudFrontキャッシュ無効化
echo "Invalidating CloudFront cache..."
aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths "/*"

echo "Deployment completed!"
```

## 実行方法
1. `deploy.sh` に実行権限を付与
   ```sh
   chmod +x deploy.sh
   ```
2. スクリプトを実行
   ```sh
   ./deploy.sh
   ```

## 
- `aws s3 sync` は増分アップロードを行うため、無駄なデータ転送が発生しない
- `aws cloudfront create-invalidation` でキャッシュを即時無効化することで、最新のコンテンツを配信可能
プロダクトオーナー（PO）とは何か？役割と責任を整理する

## はじめに

社内でスクラム開発をする事になり、**「プロダクトオーナー（以下、PO）」** に任命されました。対応するのが久しぶりすぎたのでPOについて改めて理解を深めたいと思います。


## 1. POとは？

**プロダクトオーナー（Product Owner）** は、アジャイル開発の代表的な手法「スクラム」で定義されている、**とても重要な役割のひとつ**です。

ざっくり言うと

>  **「誰に、どんな価値を、どんな優先順位で届けるか」** を決める人です。

開発チームが **「どう作るか」** に集中できるように、  
POは **「何を作るか」** を明確にし、方向性を示します。

よくPM（プロジェクトマネージャー）と混同されがちですが、POは**プロダクト（製品）の価値に責任を持つ立場**で、開発の現場と非常に密接に関わるロールです。


## 2. スクラム開発とは？

スクラムは、アジャイル開発の中でも広く使われている開発フレームワークです。  
開発チームが短いサイクル（スプリント）で成果物を繰り返し改善していく手法です。

スクラムには、次の**3つのロール**が定義されています。

- **プロダクトオーナー（PO）**：プロダクトの価値を最大化する責任者  
- **スクラムマスター（SM）**：チームが円滑にスクラムを実践できるようサポート  
- **開発チーム（Developers）**：実際にプロダクトを設計・開発・テスト


## 3. POのミッション

POのミッションとしては、

> **限られたリソースで、最大限の価値を生み出すこと**

になります。

開発は時間・コスト・人に限りがあります。  
その中で **「今、何を優先して開発するべきか」** を判断し、開発チームに方向性を示すのがPOの役割です。

また、プロダクトのビジョンを定めたり、顧客（今回はないが）やステークホルダーと連携してプロダクトの目指すゴールを明確にするのもPOの責任です。


## 4. POのやること

POが担う主な業務は以下のとおりです。

### プロダクトバックログの管理

**「何を作るか」** を整理したリスト（プロダクトバックログ）を常に最新の状態に保ち、優先順位の高いものから開発できるようにします。

### リリース計画の策定

どのタイミングで何をリリースするのか、**短期・中期のロードマップ**を設計します。

### 市場調査・顧客調査

顧客インタビューやデータ分析などを通じて、**ユーザーのニーズを正確に把握**し、優先順位の判断材料とします。

### ステークホルダーとの調整

経営層、営業、マーケティングなど、さまざまな関係者と話し合い、**要望を吸い上げて整理**します。

### 開発チームとの対話

開発チームと一緒に**実現可能性の検討や仕様のすり合わせ**を行い、共通認識を持って開発を進めます。

### 予算の管理

開発のコストを意識し、**予算内で最大の価値を出せるように判断**を行います。

### スプリントレビューでの受け入れ判断

スクラム開発にはいくつかのスクラムイベントがあります。
その中でステークホルダーやPO向けに開催される**スプリントレビュー**なるものがあります。
「Doneの定義」に基づいて、開発された成果物が **目的を満たしているかを判断**し、受け入れを行います。


## 5. 注意点

POという役割には、注意点もあります。

### POを複数人で担当する場合

POは原則、1人で担当することが望ましいです。  
複数人で担当すると、**優先順位や判断の一貫性が失われる恐れ**があります。
やむを得ず複数人で行う場合は、**最終的な意思決定者を明確にしておくこと**が重要です。

### POが「要件定義者」に終始してしまう

POは「何を作るか」を決めるだけの人ではありません。  
**「なぜそれを作るのか」「どう価値を届けるのか」まで踏み込んで判断できる存在**であることが求められます。

現場によっては、単なる調整役や仕様担当にされがちですが、PO本来の役割に立ち返る意識が必要です。


## おわりに

POは、スクラム開発において**価値を最大化するための存在**です。  
何を作るべきかを判断し、チームと共に前に進んでいくためには、**ビジネス視点・ユーザー理解・技術的な調整力**がバランスよく求められます。

> **POは“何を作るか”を決めるだけでなく、“なぜ作るのか”を語れる人。**


# おまけ

弊社の紹介もさせてください！

### 「日本で一番エンジニアが成長できる会社を創る」

https://prum.jp/

弊社メンバーは日々学習した内容をアウトプットしております！
少しでもご興味を持たれた方は求人を見てみてください！
ご応募もお待ちしております！

### 最後までご覧いただき、ありがとうございました！
Cursor活用（v0.47）：Rules機能のアップデートについて

先日、Cursorが最新バージョン0.47にアップデートされ、多くの機能改善が行われました。私も新機能を早速試してみたところ、特に「Rules」と「MCP（Model Context Protocol）」の改良が非常に印象的でした。
なお、MCPについては近日中に別記事で詳しく解説する予定です。今回は、その中でも「Rules」に焦点を当ててご紹介します。

# 1. Rulesとは？

Rulesは、Cursorに搭載されているシステムプロンプトのような機能です。半年前に初めてこの機能を紹介したときから、コード作成時の細かなトラブルが大幅に軽減される効果を実感してきました。詳細は、以下のQiita記事もぜひご覧ください。

https://qiita.com/xxyc/items/cb03b678e20ab6a824fe



# 2. 新たなrulesの分類

今回のアップデートにより、Rulesは以下の4種類に分類されるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/d2a90b20-e47d-44e7-9722-42d47d3d537b.png)

**1. Always**
従来どおり、あらゆる状況で必ず適用されるルールです。

**2. Auto Attached**
ファイルの種類に応じて自動的に適用されるルールです。例えば、Python用やReact用など、フロントエンドとバックエンドで異なるルールを設定しておくと、各コード編集時に最適な処理が自動的に実行されます。

**3. Agent Requested**
ルールに記載されている内容に基づいて、LLMが必要なとき選択的に利用するルールです。たとえば、「backend」といったキーワードがあった場合のみ、このルールが発動するなど、エージェントのような動作を実現します。

**4. Manual**
ユーザーが「@」を使って手動で呼び出すルールです。
 
個人的には、「Auto Attached」が特におすすめです。現在Python用とReact用にそれぞれ2種類のルールを設定して活用しています。

# 3. おすすめのrules選び

Rulesに関する情報、もしくは他の人が作った良いRulesは下記サイトで紹介されています。（MCPもあります）

https://cursor.directory/

私自身もいくつか試してみましたが、特に下記のPython向けRulesは、FastAPIを使ったバックエンド開発において非常に効果的で、従来の記述方法と比べるとコードの品質が格段に向上するのを感じました。

https://cursor.directory/fastapi-python-cursor-rules


今回のアップデートの詳細については⇩ドキュメントをご確認ください（例えばclaude3.7 maxのアップデートなど）:

https://www.cursor.com/ja/changelog
jQuery UI と HTML5のカレンダー入力を試してみた

# はじめに
自宅の趣味管理システムで日付入力をしたく。
カレンダー入力を簡単に実装できないものかと調べて、jQuery-uiに辿り着きました。
その後、HTML5の type="date" の存在も知ったので記事に残そうと思います。

同じようにカレンダー入力を実装したい方の参考になれば幸いです。

# その１ jquery-ui
https://jqueryui.com/datepicker/

## バージョン
jquery-3.7.1
jquery-ui-1.14.1

## サンプル
※ Geminiにサンプルを作ってもらいました。
```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>jQuery UI Datepicker サンプル</title>
  <link rel="stylesheet" href="https://code.jquery.com/ui/1.14.1/themes/base/jquery-ui.css">
  <script src="https://code.jquery.com/jquery-3.7.1.js"></script>
  <script src="https://code.jquery.com/ui/1.14.1/jquery-ui.js"></script>
  <script>
  $(function() {
    $("#jsiDatepicker").datepicker({
      dateFormat: "yy-mm-dd"
    });
    
    $('#jsiDatepicker').datepicker('setDate', new Date());
  });
  </script>
</head>
<body>

<p>日付を選択してください: <input type="text" id="jsiDatepicker"></p>

</body>
</html>
```
## 入力イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206526/2b46ed7c-832b-4efd-bf2f-142ceb54046c.png)


# その２ HTML5のtype="date"

https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/date

## サンプル
※ Geminiにサンプルを作ってもらいました。

```html
<!DOCTYPE html>
<html>
<head>
    <title>日付入力のサンプル</title>
</head>
<body>
    <form>
        <label for="date">日付を選択してください:</label>
        <input type="date" id="date" name="date">
        <input type="submit" value="送信">
    </form>

    <script>
        // 現在の日付を取得し、YYYY-MM-DD形式に変換する関数
        function getToday() {
            const today = new Date();
            const year = today.getFullYear();
            const month = String(today.getMonth() + 1).padStart(2, '0'); // 月は0から始まるため+1、2桁になるように0埋め
            const day = String(today.getDate()).padStart(2, '0'); // 日を2桁になるように0埋め
            return `${year}-${month}-${day}`;
        }

        // input要素に現在の日付を設定
        document.getElementById('date').value = getToday();
    </script>
</body>
</html>
```

## 入力イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206526/c1aa4c59-f287-4a48-99eb-486782dd6b3b.png)
SwiftUI + Firebase使用時にPreviewが使えない悪魔的な罠

# 環境
Xcode: 16.2
Swift: 6.0
Firebase: 11.9.0

# 問題
レイアウトファイルを開いても下記のようにロードが終わらない。
時折、「クラッシュしました」のような旨のメッセージが表示されたりもする。
(下記はCanvasウィンドウの画像)

![スクリーンショット 2025-03-23 13.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355973/941e05bc-c9cb-4fae-979f-7d7d34c0b624.png)



# 原因
GoogleService-Info.plist(以降plistファイルと表記)が正しく配置されていない場合に起こり得る。
Firebaseを導入する際に、AppDelegateクラスにて下記のような記述を追記している。
```Swift
FirebaseApp.configure()
```
プレビュー時に上記処理が実行されるため、plistファイルが配置されていないことで正しく実行されない。

通常、Firebaseを使用しているにも関わらず、plistファイルを配置しないことは考えられない。
しかし、下記のような場合に直面しやすい。そして、プレビューとplistファイルの直接的な関係が見えにくいため気が付きにくい。
・GitHubへplistファイルをプッシュしていない(運用方針としては正しいです)
・clone直後、plistを配置する前に簡単にプレビュー内で画面のレイアウト感とかを確かめたい

# 解決策
## ケース1. plistファイルをリモートへプッシュ
無論、plistファイルのプッシュは非推奨です。
しかし、GitHubのプライベートリポジトリやGitLabなど無関係の第三者がアクセスできない環境であれば検討する余地はあります。

## ケース2. プレビュー時のみ処理を分岐
下記のように変更することで、プレビュー時のみFirebase初期化を回避することができます。
```Swift
#if DEBUG
    if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != "1" {
        FirebaseApp.configure()
    }
#else
    FirebaseApp.configure()
#endif
```

## ケース3. clone直後にplistファイルを配置する
こちらは通常通りに配置するだけですので割愛します。

# まとめ
解決に苦労しました....
特に、私の場合はiOS開発は初心者のため、プレビューの流れなどは全く意識していませんでした。
そのため、プレビューとplistファイルの間接的な関係性は全く想定出来ていませんでした。
Windows 11 24H2 更新時のトラブル

## 私の環境
かなり古い環境をごまかしながら使っているため、新しい環境では起こらないトラブルばかりだと思います。

* Windows 11 Pro
* ASUS TUF B450-PLUS GAMING
* Ryzen 5 3600

Windows インストール後にマザーボード交換を行っているため、Windows 環境自体はかなり古いです。

## BIOS 更新
普通に Windows アップデートしたら失敗したため、fTPM 関係かしらと思い、BIOS アップデートを実施しました。
TUF B450-PLUS GAMING BIOS 3802 -> TUF B450-PLUS GAMING BIOS 4604
fTPM がらみの警告が出ますが、ドライブの暗号化は行っていないので問題なし。
BIOS 更新により、Windows アップデートは成功。無事 24H2 で起動成功しました。

## AsIO.sys 削除
AsIO.sys が読み込めないというエラーが出たので、その対策を行いました。
AsIO.sys は ASUS のツールがらみのドライバーらしいです。
（オーディオで使われる ASIO とは無関係です）
ASUS の AI Suite 3 を最新のものにアップデートし、
https://www.reddit.com/r/pchelp/comments/1fylxt0/asiosys_driver_cannot_load_on_windows_11_pc/
を参考にして、AsIO.sys を削除。無事にエラーは出なくなりました。
（AsIO.sys は、かなり古いファイルだったので、過去のバージョンの遺物か？）

## OneDrive 修正
昔から使っている環境なので、OneDrive の参照するフォルダーが SkyDrive という名前になっていました。
https://qiita.com/Sego-don/items/1c53f61d37411d80e5db
を参考にして、
%localappdata%\Microsoft\OneDrive\settings\Personal\
以下の ini ファイルを修正。その後、サインインしなおして、%UserProfile% 以下のフォルダーを確認し、不要なフォルダーを削除しました。
（不要なフォルダーはそもそも存在しないこともあるかも）

## まとめ
BIOS 更新が最も重要です。fTPM 関係の理解が浅すぎてアップデートになぜ失敗するのかわかっていないのですが、BIOS 更新しないとアップデートできない環境というのは、そこそこ存在するのではないかと思います。
PDF.js で表示した PDF でクリックされたテキスト要素を判定

PDF.js で表示した PDF でクリックされたテキスト要素を判定する方法のメモ。

# 概要
「[PDF.js を利用したシンプルな PDF ビューワ](https://qiita.com/dakikd/items/27da27acf5abff97207e)」の SimplePdfViewer にクリックイベントを設定し、クリック時に console.log() でテキスト要素の情報を出力します。

# 処理内容
- クリックイベントからクリックされた座標（event.x, event.y）を取得します。
- page.getTextContent() でページ内のテキスト要素を取得して、各要素について以下を行います。
  - PDF のテキスト要素の座標（item['transform'][4], [5]）と幅・高さ（item['width'], ['height'}）を取得。
  - PDF のテキスト要素を viewport.convertToViewportRectangle() で viewport の座標に変換。
  - イベントの座標と viewport の座標を比較して、クリックされたテキストを判定。　※PDF はページ左下が (0, 0) で、x軸は右向き、y軸は上向き

# プログラム（改修部分）
SimplePdfViewer の全体は[こちら](https://qiita.com/dakikd/items/27da27acf5abff97207e)。
```javascript:
  render_page(page_num) {
    this.page_num = page_num;

    this.pdf.getPage(page_num).then((page) => {
      this.viewport = page.getViewport({scale: this.scale});
      this.canvas.height = this.viewport.height;
      this.canvas.width = this.viewport.width;

      const render_context = {
        canvasContext: this.canvas_context,
        viewport: this.viewport
      };

      page.render(render_context);

      // クリックされたテキスト要素の情報を表示　★追加部分はここから
      this.canvas.addEventListener('click', (event) => {
        // クリックされた座標を取得
        const x = event.offsetX;
        const y = event.offsetY;
        console.log(`x: ${x}, y: ${y}`);

        // テキスト要素
        page.getTextContent().then((textContent) => {
          for (const item of textContent.items) {
            // PDF の座標
            const left = item['transform'][4];
            const top = item['transform'][5];
            const width = item['width'];
            const height = item['height'];
            const text = item['str'];

            // viewport での座標
            const rect = [left, top, left+width, top+height];
            const view_rect = this.viewport.convertToViewportRectangle(rect);
            const view_left = Math.min(view_rect[0], view_rect[2]);
            const view_top = Math.min(view_rect[1], view_rect[3]);
            const view_right = Math.max(view_rect[0], view_rect[2]);
            const view_bottom = Math.max(view_rect[1], view_rect[3]);

            if ((view_left <= x && x <= view_right)
              && (view_top <= y && y <= view_bottom)) {
                console.log(`l: ${left}, t: ${top}, w: ${width}, h: ${height}, text: ${text}`);
            }
          }
        });
      });
    });
  }
```

# 実行例
クリック時にカーソルの座標と、クリックされた PDF のテキスト要素の情報が console.log() で出力されます。
```text:
x: 94, y: 78
l: 85.08000150000001, t: 729.96004475, w: 52.69627125, h: 10.560375, text: あああああ

x: 78, y: 119
l: 85.08000150000001, t: 675.96004475, w: 52.69627125, h: 10.560375, text: いいいいい
```
Dockerのトラブルシューティング用コマンド

## Dockerのトラブルシューティング用コマンド

### 1. コンテナの起動状態を確認する (`docker ps`)

```bash
docker ps
```

実行中のコンテナの一覧を表示し、起動状態を確認します。

### 2. コンテナのログを確認する (`docker logs`)

```bash
docker logs <コンテナIDまたはコンテナ名>
```

コンテナのログを表示し、エラーメッセージなどを確認します。

### 3. ネットワーク構成を確認する (`docker network ls`)

```bash
docker network ls
```

Dockerネットワークの一覧を表示し、ネットワーク構成を確認します。

### 4. コンテナのポートマッピングを確認する (`docker ps`)

```bash
docker ps
```

コンテナのポートマッピングを表示し、ポートの公開状態を確認します。

### 5. コンテナ内でコマンドを実行する (`docker exec`)

```bash
docker exec -it <コンテナIDまたはコンテナ名> <コマンド>
```

コンテナ内でコマンドを実行し、コンテナ内部の状態を確認します。

### 6. コンテナの統計情報を表示する (`docker stats`)

```bash
docker stats <コンテナIDまたはコンテナ名>
```

コンテナの統計情報を表示し、リソース使用状況を確認します。

### 7. コンテナのイメージを削除する (`docker rmi`)

```bash
docker rmi <イメージIDまたはイメージ名>
```

コンテナのイメージを削除し、ディスク容量を節約します。

### 8. コンテナを削除する (`docker rm`)

```bash
docker rm <コンテナIDまたはコンテナ名>
```

コンテナを削除し、不要なコンテナを整理します。

### 9. Dockerネットワークの詳細を確認する (`docker network inspect`)

```bash
docker network inspect <ネットワーク名>
```

Dockerネットワークの詳細な情報を表示し、ネットワーク設定を確認します。

### 10. コンテナのポートマッピングの詳細を確認する (`docker port`)

```bash
docker port <コンテナIDまたはコンテナ名>
```

コンテナのポートマッピングの詳細な情報を表示し、ポートの公開状態を確認します。

### 11. コンテナのIPアドレスを確認する (`docker inspect`)

```bash
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <コンテナIDまたはコンテナ名>
```

コンテナのIPアドレスを表示し、コンテナ間の通信を確認します。
EDGEのIEモードでもセレクトボックスのdisabledが効かない

以下のソースでEDGEのIEモードでもセレクトボックスのdisabledが設定できます。
```
<script>
function testAbc(objAbc){ 

    if(objAbc.checked == true){ 
        var tmpName = "pet" + objAbc.name.replace("chk", "");
        var trgtObj = document.getElementsByName(tmpName);
        for (var i = 0; i < trgtObj.length; i++) {
            trgtObj[i].disabled = false;
        }
    } else {
        var tmpName = "pet" + objAbc.name.replace("chk", "");
        var trgtObj = document.getElementsByName(tmpName);
        for (var i = 0; i < trgtObj.length; i++) {
            trgtObj[i].disabled = true;
        }
    }
} 
</script>
```
【Rails】フレンドリーフォワーディングとは


# はじめに
こんにちは。アメリカに住みながら独学でエンジニアを目指している taira です。
現在Ruby on Railsを使用して学習中ですが、そこで出てきたフレンドリーフォワーディングについて自分なりに整理してみました

## フレンドリーフォワーディングとは
フレンドリーフォワーディングとは、「ログインが必要なページ」にアクセスしようとした未ログインユーザーを一度ログインページに誘導した後、ログインが成功したら最初にアクセスしようとしたページへ自動的に戻す仕組みです。
ユーザー体験を向上するために取り入れる仕組みになっています。

例を挙げると、以下のような状況でフレンドリーフォワーディングを行います
1. 未ログインのユーザーが「プロフィール編集ページ」にアクセス。
2. ログインしていないのでログインページに強制リダイレクト。
3. ユーザーがログインすると、再び「プロフィール編集ページ」へと自動的に遷移する。

## 実装方法
Railsチュートリアルでは、コードの実装の前にテストコードを書いています。
テストコードはシンプルなので、詳しくは本編をご覧ください。

実装の手順としては以下の通りです。
1. `sessions_helper.rb`で`session`にログイン画面に飛ぶ前のリンクを保存する`store_location`メソッドを定義する
2. `users_controller.rb`で`store_location`を呼び出す
3. `sessions_controller.rb`の`create`メソッド(ログインボタンを押したときに呼び出される)に、`store_location`メソッドで保存した`URL`を呼び出し、リダイレクトする。

### 1. `sessions_helper.rb`で`session`にログイン画面に飛ぶ前のリンクを保存する`store_location`メソッドを定義する
```ruby
module SessionsHelper
 .
 .
 .
  #アクセスしようとしたURLを保存する
  def store_location
    session[:forwarding_url]= request.original_url if request.get?
  end
end
```
`request.original_url`を使用することで、ログイン画面にリダイレクトする前のURLを取得することができます。
`request.get?`としているのは、例えばDELETEリクエストのリンクを取得してしまったら、ログインしたのに情報が削除されるという予期しない動作をすることになるので、GETメソッドのみにしています

### 2. `users_controller.rb`で`store_location`を呼び出す
```ruby
#ログイン済みユーザーかどうか確認
def logged_in_user
  unless logged_in?
    store_location # 追加
    flash[:danger]= "Please login."
    redirect_to login_url, status: :see_other
  end
end
```

`redirect_to` でログイン画面にリダイレクトするので、その前に`store_location`メソッドで`session[:forwarding_url]`でリンクを保存しておきます

### 3. `sessions_controller.rb`の`create`メソッド(ログインボタンを押したときに呼び出される)に、`store_location`メソッドで保存した`URL`を呼び出し、リダイレクトする。

```ruby
def create
  user = User.find_by(email:params[:session][:email].downcase)
  if user && user.authenticate(params[:session][:password])
    forwarding_url = session[:forwarding_url] # 追加
    reset_session
    params[:session][:remember_me] == '1' ?remember(user) :forget(user)
    log_in user
    redirect_to forwarding_url || user # 追加
  else
    flash.now[:danger] = 'Invalid email/password combination'
    render 'new', status: :unprocessable_entity
  end
end
```

上記の`forwarding_url`の位置ですが、`reset_session`の後だとセッションがリセットされてしまった後になるので、その前にローカル変数に代入する必要があります。
`redirect_to`で`forwarding_url`に値が入っていれば、ログイン前に飛ぼうとしたリンクへリダイレクトします。

## リダイレクトでほかのページに飛ぶことはできないのか
`redirect_to edit_user_path(@user)`のように決まった場所にリダイレクトしてしまえば、わざわざURLを保存する必要はないのでは？と最初見たときは思いました。
実際にすることは可能ですが、わざわざ元のURLを一度保存してまでフレンドリーフォワーディングを使う主な理由は、**「ログインが必要なページがひとつではなく、たくさんあるため」**です。

例えば、次のような状況を考えます。

あなたのRailsアプリに以下のページがあるとします

- プロフィール編集ページ（`edit_user_path`）
- 投稿作成ページ（`new_post_path`）
- 設定変更ページ（`settings_path`）
- 特定の投稿の編集ページ（`edit_post_path(post)`）

上記すべてログインを要求するページである場合を想像してみましょう。

もしURLを保存しない方法を取った場合、どうなるでしょうか？

`edit_user_path` にアクセス → ログイン要求 → ログイン後に `redirect_to edit_user_path`でOK
しかし、`new_post_path`にアクセス → ログイン要求 → ログイン後、`edit_user_path`に戻される？
後者の場合、ユーザーが望んだページと異なるページへ遷移するため、ユーザーにとって混乱やストレスになります。
ページごとに決め打ちの`redirect_to`を設定していては、すべてのパターンを網羅する必要があり、コードも複雑化します。

## まとめ
フレンドリーフォワーディングによって、ユーザーはログイン後に元々アクセスしようとしていたページへスムーズに戻ることができます。これにより複数のページでログインを要求する場面でも、ユーザーの混乱や操作の手間を軽減することが可能です。実装方法は比較的シンプルであり、Railsチュートリアルを参考にしながら、自身のアプリケーションに合わせてカスタマイズしてみてください。