OmniAICreator/Qiita-1.07M huggingface dataset:
図で理解する循環参照〜視覚的に循環参照を理解しよう！〜

# 循環参照とは
2つのインスタンス同士がお互いを参照しあっている関係を循環参照と呼びます。インスタンス同士が循環参照を起こしていると、メモリを解放することができません。なぜなら、お互いを参照しあっているので参照カウンタが0にならず、ずっとを保持し続けてしまうからです。
この問題をメモリリークと言い、メモリ領域の圧迫によってパフォーマンスの低下や、場合によってはアプリケーションを終了させてしまいます。
# 循環参照の例
```swift:ViewController.swift
import UIKit
class ViewController: UIViewController {
    var closure: () -> Void = {}
    var value = 100
    
    override func viewDidLoad() {
        super.viewDidLoad()
        closure = { print(self.value)}
    }
}
```
ViewControllerがclosureを参照しており、closureがViewControllerのvalue変数を参照しているので循環参照が起こっています！

参考文献：selfが何が指しているかわからない場合は下記の記事を参考にしてみてください！

https://qiita.com/hinakko/items/201587d4c018f10a174e

### XcodeのDebug Memory Graphで参照関係を視覚的に確認してみましょう！
下記の画像からもわかるように、ViewControllerがclosure変数を参照しており、closure変数がViewControllerを参照している。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/242aaeed-f301-065d-fffe-d57802045931.png" width=700>

#### このように2つのインスタンス同士がお互いを参照しあっているので、循環参照が発生している！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/fbdc14a8-1e69-97b5-8aaf-ca8578d3ae58.png" width=700>

参考文献：XcodeのDebug Memory Graphの表示方法は下記の記事に載っています！

https://qiita.com/hinakko/items/48dd8e1867d3ef14d2ef



# 循環参照の解決

参照型は3つの参照方法がある！
#### 1.強参照
デフォルトはstrong
#### 2.弱参照
weak
参照先が存在しない場合に参照しようとされると自動でnilになってる
#### 3.非所有参照
unowned
参照先が存在しない場合に参照しようとされると解放済みへのアクセスとなりクラッシュする

循環参照をするためにweakとunonwnedを使うと強参照することなく、他のインスタンスを参照することができます。
強参照されないと参照カウンタからカウントされません。そのため、インスタンスは循環参照をせずにお互いを参照することができます。
#### 今回はweakによる循環参照の解決方法を詳しく見ていきます！

## 弱参照weakによる循環参照の解決


```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    var closure: () -> Void = {}
    var value = 100
    override func viewDidLoad() {
        super.viewDidLoad()
        closure = { [weak self] in
            if let strongSelf = self {
                print(strongSelf.value)
            }
        }
    }
}
```
[weak self]で弱参照にすることで、ViewController画面がないかもしれない場合を扱うことができる！つまり、画面が開放されていなければ、selfにViewControllerが入っている。
画面が解放されていれば、参照先が存在しないのに参照しようとされるので自動でnilになってくれる。

上記のコードのclosureスコープ内を詳しく見てみましょう！

```swift:ViewController.swift
        closure = { [weak self] in
            if let strongSelf = self {
                print(strongSelf.value)
            }
        }
```
このclosureが呼ばれた時にViewControllerの画面がない可能性があるので、if文を用いてself(ViewControllerのインスタンス)があるならば、value変数の値をプリントできます！
[weak self]で弱参照にすることで、if文内のselfも弱参照になるため、循環参照を解決できます。


XcodeのDebug Memory Graphで確認してみても循環参照になっていません。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/d9dd8d4d-6587-be83-b9ae-f7bfd2a62dde.png" width=700>

#### closureからViewControllerへの参照が弱参照になっています！
closureからViewControllerを参照する際、参照先が存在しない場合に参照しようとされると自動でnilになってくれるので循環参照を防ぐことができます！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090887/1bd5f23f-3d2b-9333-f2d8-ba2522af620d.png" width=700>

# 参考文献
https://swift.codelly.dev/guide/%E3%83%A1%E3%83%A2%E3%83%AA%E7%AE%A1%E7%90%86/#%E3%83%87%E3%82%A4%E3%83%8B%E3%82%B7%E3%83%A3%E3%83%A9%E3%82%A4%E3%82%B6

https://qiita.com/yimajo/items/892bd2fe1ccb808ffe49

https://gihyo.jp/book/2020/978-4-297-11213-4
Okta - サインイン時にリスク判定を追加する

# はじめに

今回は、以下の全5回のうち3回目になります。

- [サインインを自社拠点IPからのみに制限する](https://qiita.com/mtbRck/private/301e6d9b4badc02ba905)
- [サインイン時にMFAを求める](https://qiita.com/mtbRck/private/949ac045ebe7f46d631b)
- [サインイン時にMFAを求めないパターンを残す](https://qiita.com/mtbRck/private/38e87b1f67201bcbb90f)
- サインイン時にリスク判定を追加する
- 特定のアプリのみ自社拠点外からのサインインを許可する

デバイスやロケーションなど、サインイン時の情報が普段と異なる場合はセキュリティリスクが高い可能性があります。
Oktaではサインイン時にリスクレベルに応じた制御を加えることができます。

今回は、リスクレベルが高い場合にMFAを強制し、認証が成功してもセッションをすぐに切断するルールをGlobal Session Policyに追加していきます。

# 自社用デフォルトポリシーにルールを追加

Risk is で High を選択し、Users wiss be prompted for MFA で At every sign in を指定します。
これでリスクが高いと判定された場合は毎回MFAを求められるようになります。

また、セッション時間を life time/idle time ともに1分を設定します。
これでログインしても1分でセッションが切断されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/f0a18b45-a1f5-f898-2bb3-6b1e2b92a293.png)

ルールを追加すると例によって既存ルールの下に追加されるため、一番上に移動させます。
こんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/2e6f728b-e38b-ecc4-fbf2-f0086f028429.png)



# Number Challenge を有効にする

私は Okta Verify Push を使っていますが、例えば第三者によるサインインでリスクが高いと判定されても、意識せずにプッシュ通知を許可してしまっては意味がありません。

リスクが高いときにだけ Number Challenge を有効にすることで、画面に表示されている数字と同じ数字を選択しなければならなくなるので、プッシュ通知を許可しても即サインインされることはなくなります。

Security > Authenticators > Okta Verify > Actions:Edit > Number challenge for Okta Verify Push から Only for high risk sign-in attempts を指定することで設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/841b303a-7c90-740f-1f22-14958aa84fe4.png)

参考までに Number Challenge 時には以下の画面が表示されるようになります。
- PC側
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/5f7ee135-58ab-bdda-3e54-a790d99b6561.png)
- スマホ側
    - <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/b0f7b6c3-dffe-a8fa-9f18-0f0da9f0c6a7.png"  width=50%>


# Behavior Profile をリセットする

Number Challenge を設定した後に動作確認をしたいと思っても、すでにOkta側でサインイン時の情報を保持しているためなかなか意図的に確認することができません。

そんな時は、ユーザーを指定して More Actions > Reset Behavior Profile を実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350435/5f981624-3ca9-80f4-87e4-e40879593f6a.png)


# さいごに

今回はここまで。ありがとうございました。
次回は特定のアプリだけ自社拠点IP以外からでもアクセスできるようにします。
【ChatGPT無】で動物当てクイズしてみた。

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

　今回は、動物当てクイズを出してもらいます。当たるかな？

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　本題の前に。

　年賀状、
　　どうしていますか？

　私は、送る相手が少ないので、
　　コンビニやスーパーで購入して、
　　　宛名書きして送っています。

　ちなみに、
　　郵便局での
　　　年賀状引き受け開始は、
　　　　１２月１５日より、
　　　　　だそうです。
***
　自宅のプリンタを
　　使う際には、チェックしてから。

　使う頻度が
　　高ければ大丈夫ですが、
　　　そうでなければ、
　　　　印刷手順を確認して、
　　　　　実際に印刷して
　　　　　　みてください。

　最近のプリンタは、
　　インクジェットですから
　　　目詰まりを起こしている
　　　　可能性もあります。

　たいていは、
　　クリーニングで
　　　解決しますが、
　　　　場合によっては……
　　　　　ということも。
***
　枚数がそれなりにあって、
　　書き損じが気になる人は、
　　　ネットサービスを
　　　　利用するべきかも。

　デザインを選んで、
　　相手先住所・氏名を送って、
　　　郵便局への発送まで
　　　　やってくれるそうです。

　コンビニの
　　マルチコピー機でも
　　　できるとか。

　なお、
　　GoogleSGEによると、
***
***GoogleSGE***
セブンイレブンやローソンでは、店頭にあるマルチコピー機で年賀状を印刷できます。ファミリーマートにはマルチコピー機がありますが、はがきの印刷は対応していないため、年賀状の印刷はできません。﻿
印刷料金は、マルチコピー機の印刷料金（1枚60円）とはがき代（1枚63円）のみです。﻿
***
　なのだとか。

　意外とお金が掛かるものです。
　　ならば、楽に済ませましょう。
　　　お金で解決できるならば、
　　　　それで自分の自由時間を
　　　　　買ったのだ、と考えれば
　　　　　　割高感もそれほどの
　　　　　　　ものでもありません。
***
***
　さて、本題です。

　まずは、
　　Promptから。
```Text:
クイズを出してください。
ネタは、動物。
その特徴をユーザーに教えて、回答させて、回答が正しいかを判断する。
間違った回答ならば、不正解ということを伝え、正しい回答を表示する。
```

　一応、言いますと、
　　ハルシネーションを出しますが、
　　　逆にそれを楽しんでくださいw

　暇潰し程度が、
　　一番です。

　では、やり取り。
***
***ChatGPT***
もちろんです！始めましょう。

動物クイズ:

この動物は、黄金の毛皮と大きなほっぺたが特徴です。また、非常にユーモラスで、竹を食べることが好きです。この動物は何でしょうか？

***User***
コアラ？

***ChatGPT***
残念ながら、コアラではありません。正解は「パンダ」です！パンダは黒と白の毛皮を持ち、竹を主な食べ物としています。次のクイズを試してみましょう！

動物クイズ:

この動物は、長い首と脚を持ち、優雅に歩くことで知られています。さらに、柄のある模様が首に特徴的です。この動物は何でしょうか？

***User***
キリン

***ChatGPT***
正解です！そうです、キリンは長い首と脚を持ち、柄のある模様が首に特徴的な動物です。次のクイズを用意しましょう！

動物クイズ:

この動物は、水中で息をすることができ、特に大きな耳と象のような鼻を持っています。この動物は何でしょうか？

***User***
象

***ChatGPT***
その通りです！象は水中で息をすることができ、大きな耳と象のような鼻が特徴です。素晴らしいですね！次のクイズをお楽しみください。

動物クイズ:

この動物は、背中にコブを持ち、極端な気温に適応できる能力を持っています。砂漠地帯で暮らすことが多いです。この動物は何でしょうか？

***User***
ラクダ

***ChatGPT***
その通りです！ラクダは背中にコブを持ち、砂漠地帯で暮らす能力を持っています。素晴らしい知識ですね！次のクイズをお試しください。

動物クイズ:

この動物は、縄張り意識が強く、群れで生活します。メスが角を持っており、オスは華やかな羽根を持っています。また、優れたランナーで、速く走ることができます。この動物は何でしょうか？

***User***
ヒントは？

***ChatGPT***
もちろんです！この動物はアフリカに生息し、走ることが得意です。特にオスは華やかな羽根を持っています。また、サバンナでよく見られます。この動物は何でしょうか？

***User***
わかりません

***ChatGPT***
それは「アフリカのオオハシ」です！メスが角を持ち、オスは派手な羽根を持っています。次のクイズに挑戦しましょう！

動物クイズ:

この動物は、夜行性で、黒く光る目を持っています。また、独特な声で知られ、獲物を狩る際に静かに接近します。この動物は何でしょうか？

***User***
リュカオン

***ChatGPT***
その予想は素晴らしいですが、正解は「フクロウ」です！夜行性で、黒く光る目を持ち、静かに獲物に接近します。次のクイズにチャレンジしましょう！

動物クイズ:

この動物は、北極地域に生息し、白い毛皮と優れた泳ぎの能力を持っています。夏には水中で餌を探し、冬には厚い毛皮で暖かさを保ちます。この動物は何でしょうか？

***User***
シロクマ

***ChatGPT***
その通りです！シロクマは北極地域に生息し、白い毛皮と優れた泳ぎの能力を持っています。さすがですね！次のクイズに挑戦してみましょう。

動物クイズ:

この動物は、非常に速く走ることができ、樹上で暮らしています。特徴的な模様を持ち、しばしば木から木へと飛び移ります。この動物は何でしょうか？
***
　どうです？

　黄金のパンダって何？って
　　なりますよねぇw

　あと、象が答えなのに、
　　問題で言っているしw

　ほかにも
　　ツッコミどころ
　　　満載ですわw

　まぁ、
　　こんなので
　　　みなさんの息抜きになれば
　　　　うれしいです。

　今回は、ここまで。
PHPでのファイル書き込みが、権限的にどうしても出来ない場合の最終的な解決策

## やりたいこと
PHPからNode.jsのプログラムを実行して、実行結果をブラウザに表示したい。その際にnode.jsのプログラムの実行結果(console.logで出力させている文字列とか)をブラウザに表示したい。
※管理者用プログラムなので

あと、タイトルに「最終的な解決策」と勝手に言っているが個人開発だから言えるのであって業務だったらルール守らなきゃだが

## 背景
apacheでPHP導入しているが、ファイルの書き込み処理で権限的にエラーが出るのはよくあることで、解決先としてはフォルダやファイルの権限を変えたりapacheユーザーの権限変えたり色々あるが、それらはしたくない。
そのファイルは他のユーザーに見られないようにしたい。

## まず、出来ない方法
- shell_exec関数を使ってlinuxコマンドとしてnode.jsプログラムを実行する。sudoをつけているとはいえ、やはりapacheユーザーでは実行は出来てもログファイルの出力はできなかった。

## 解決方法
- 間にシェルを挟む
    - 「PHP→shell(sudoで)→Node.js」って流れにしてしまえばいい。(メインプログラムがPHPならこんなことしなくていいのにw)

- ★この時sudoつけないとうまくいかないのでつける。
```php:hoge.php
$cmd_shell = "sudo sh hoge.sh なんか引数";
shell_exec($cmd_shell);
```

- 上記PHPから呼ばれるシェル

```shell:hoge.sh
sudo node hoge.js $1 > hoge.txt 2> error.txt
```

- これでブラウザからNode.jsを実行した際にログが生成された。
- これをPHPから読み取って送信ボタン押すたびに実行ログがブラウザに表示されるようになった。2重送信防止でリダイレクトも毎回するので、フォーム送信後にリダイレクトを維持しつつファイルの中身を表示できるので自分の管理者画面が便利になった。
Amplify Boost Up #04 登壇の振り返り

先日、Amplify Boost Up #04で下記テーマで発表させていただきました。

https://github.com/aws-amplify-jp/amplify-meetup-cfp/issues/24

[発表資料](https://docs.google.com/presentation/d/1PMwbkOz5VohJsvpcYtZistO2Nc8ST1MzhXGF0fHYi_M/edit?usp=sharing)

**なぜ発表しようとおもったか**

最初にAWS Amplifyを利用し始めたのは
[Vue.jsとAWS Amplifyでプロジェクト譜のサービスを作った話](https://qiita.com/dyson-yamashita/items/6b0eacaa6a9653f4eeda)の記事を投稿したころで、3年ほど前になります。この時点では個人が勝手に作ったサービスでした。
その後、共同開発へと発展して登壇したサービスでAmplifyを引き続き利用してきました。

数年のAmplifyでのサービス開発を経て下記の思いが増してきました。

- エンジニアの自分がサービスを紹介したい
- 使い続けた技術について発信したい

**エンジニアがサービスを紹介したい**
キックプ譜というサービスですが、一般的なSaaSのようにガンガン売るようなサービスではなく、必要な人に自然と広まるようなサービスを目指しています。(個人的に)
ただ機能があれば理解され広まるものでなく、そのサービスの根っことなる考え方や世界観がセットになると気付きました。
システムの作り手のエンジニアがサービスだけでなく、根っことなる考え方も含めて伝えていきたいという気持ちが増してきたというのが理由のひとつです。

**使い続けた技術について発信したい**
システムを作り運用する私にとって、共に歩む技術に愛着が湧いてきますし、感謝の念を伝えたい気持ちになります。
その共に歩んだ技術一つがAmplifyでした。
自分なりに技術についてどう話すか考えた時に、大規模や最先端を持ち得ていない中で、長く運用利用したことが価値になるのではとなり、今回のテーマにしました。
仕事の中でも技術選定では運用するとどうなのか気になるところです。
もし技術選定で迷っている人がいれば運用の知見が参考になれば思っています。

また、発表に至った理由は上記の2つですが、発表準備する中でも得るものがありました。それは、**発表を通してサービスの理解が深まる**ことです。
限られた時間の中で、何を発表するかを考え、その過程で自分がそのサービスをどう捉えていたかが磨かれた気がします。

発表の機会を頂けたことは非常に学びを得られると思いますので、amplifyユーザーの発表が益々増えるといいなと感じます。

運営の皆様、事前準備&当日運営ありがとうございました❗️
Advent Calendar 2023ついに折返し地点にやってきた

# はじめに
Advent Calendar 2023に初挑戦し、ついに折返し地点にやってきたので、現在の所感などをまとめていければと思います。

# 所感
私がAdvent Calendar 2023に挑戦したきっかけは、開発チームの先輩がカレンダーに参戦されるとのことで、他の先輩と一緒にカレンダー一緒に挑戦してみましょう！とのノリで挑戦することになりました。
始めた当初はアドベントカレンダーが何かまだ詳細にわかっておらず、全体公開記事は11月以降の記事をカレンダーに紐づけ可能、限定共有記事は作成日時に無関係でカレンダーに紐づけ可能等というルールもわからず、分かっていたのは何かしたら景品がもらえるということ位でした。11月下旬に挑戦確定しルール等を確認して、実際に記事を作成し始めたのはほぼ12月頃だったと思います。
ストック記事もほぼなく12月に入ってからコツコツと記事を作成する生活が始まりました。心掛けていたことは、**質にこだわるのではなく小さな気づきで内容が少なくなってもいいからとにかく継続し続けること**でした。実際に記事を作成する日々を送るとやはり最初は慣れていないこともあり時間がかかったりして辛くなっていました。
しかし、一緒に始めた先輩や開発チームメンバーの方からいいねしてもらったり、作成した記事の内容のお話をしてもらったりして支えてもらったことでモチベーション高くなり心が折れることなく現在まで投稿し続けることができました。一人でカレンダーに挑戦してもおそらくここまで続けられていなかったなと感じているので、**一緒に頑張る仲間の存在は非常に大切**だなと感じています。

# おわりに
このままの勢いに乗って完走目指して頑張っていこうと思います！始める前と後でどのように変わったのか等の総評は完走記事として25日に投稿します！！！
[Next.js] Error: connect ECONNREFUSED or process.processTicksAndRejections

## 1. Countermeasures

### Issue: Not `localhost`

```bash
# Frontend server with Next.js
next dev
```

```bash
# Backend server with FastAPI and uvicorn
uvicorn app:app --reload
```

### Solution: Explicitly specify IP address.

```bash
# Frontend server with Next.js
next dev -H 192.168.11.2
```

```bash
# Backend server with FastAPI and uvicorn
uvicorn app:app --reload --host 192.168.11.2
```

It's necessary to explicitly specify the IP address for both.

## 2. Background
1. Trying to check the screen from a smartphone by connecting to the development server 192.168.11.2
2. The images stored on the backend server are not displayed
3. Change the URL of the backend server accessed by the Next.js frontend server from localhost to 192.168.11.2
4. An error occurs with `fetch`



## 3. Cause
Not very clear.

# 4. Related


* [【Next.js】getServerSideProps内で API実行するとError: connect ECONNREFUSEDになる - Zenn](https://zenn.dev/daiki_21/articles/4cb95a2fcfee4a)
コマンドでWindowsとLinuxのタイムゾーンを設定する

このシリーズの他の記事は、[オラクル・クラウドの個人ブログ一覧 ](https://qiita.com/letian/items/10152a4fec813c1b7d98)からご覧いただけます。

**検証済OS**
Windows 10, 11
Windows Server 2019,2022
Oracle Linux 7,8,9
Ubuntu 22

**目次**
- [Windowsの場合](#windowsの場合)
  - [コマンドプロンプトでの設定](#コマンドプロンプトでの設定)
  - [PowerShellでの設定](#powershellでの設定)
- [Linuxの場合](#linuxの場合)
- [付録 - 初期化スクリプト](#付録---初期化スクリプト)

# Windowsの場合
## コマンドプロンプトでの設定
タイムゾーンの確認には管理者権限は不要ですが、変更するには<strong>管理者権限</strong>が必要です。

現在のタイムゾーンを確認する：`tzutil /g`
すべてのタイムゾーンをリストする：`tzutil /l`
```
C:\Windows\system32> tzutil /g
UTC
C:\Windows\system32> tzutil /l
......
```

日本標準時（JST）を設定する：`tzutil /s "Tokyo Standard Time"`
```
C:\Windows\system32>tzutil /s "Tokyo Standard Time"
C:\Windows\system32>tzutil /g
Tokyo Standard Time
C:\Windows\system32>
```

## PowerShellでの設定
現在のタイムゾーンを確認する：`Get-TimeZone`
```powershell
PS C:\Windows\system32> Get-TimeZone


Id                         : UTC
DisplayName                : (UTC) Coordinated Universal Time
StandardName               : Coordinated Universal Time
DaylightName               : Coordinated Universal Time
BaseUtcOffset              : 00:00:00
SupportsDaylightSavingTime : False
```

すべてのタイムゾーンをリストする：
```powershell
Get-TimeZone -ListAvailable
```

日本標準時（JST）を設定する：
```powershell
Set-TimeZone -Id "Tokyo Standard Time"
```

# Linuxの場合
現在のタイムゾーンを確認する：`timedatectl`
OCI Computeインスタンスを新規作成すると、デフォルトのタイムゾーンは<strong>UTC</strong>です。
```
[opc@linux8 ~]$ timedatectl
               Local time: Thu 2022-07-28 03:09:35 UTC
           Universal time: Thu 2022-07-28 03:09:35 UTC
                 RTC time: Thu 2022-07-28 03:09:36
                Time zone: UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
[opc@linux8 ~]$
```
日本のタイムゾーンをリストする：`timedatectl list-timezones | grep Tokyo`
```
[opc@linux8 ~]$ timedatectl list-timezones | grep Tokyo
Asia/Tokyo
[opc@linux8 ~]$
```

日本標準時（JST）を設定する：`sudo timedatectl set-timezone Asia/Tokyo`
```
[opc@linux8 ~]$ sudo timedatectl set-timezone Asia/Tokyo
[opc@linux8 ~]$ timedatectl | grep zone
                Time zone: Asia/Tokyo (JST, +0900)
[opc@linux8 ~]$
```
※、タイムゾーンを設定するために、<strong>root</strong>権限が必要です。

# 付録 - 初期化スクリプト
OCI（オラクルクラウド）上でVMを作成する際に、次のコマンドをcloud-initスクリプトに追加すると、インスタンスの起動後にタイムゾーンが自動的に設定されます。

日本標準時（JST）を設定する例：

__Windows Server__
```powershell
#ps1_sysnative
Set-TimeZone -Id "Tokyo Standard Time"
```

__Oracle Linux, Ubuntu__
```
#!/bin/bash
timedatectl set-timezone Asia/Tokyo
```
----
__関連記事__  
[OCI Cloud-initスクリプト](https://qiita.com/letian/items/10152a4fec813c1b7d98#11-cloud-init%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88)
【Elixir アンチパターン】 戻り値の型が変化する関数


# はじめに

Elixirのドキュメントにanti patternsがあり、結構いい資料だと思います。

その中の一つ[alternative-return-types](https://hexdocs.pm/elixir/1.16.0-rc.0/design-anti-patterns.html#alternative-return-types)を読み解いてみます

# 戻り値の型が変化する関数

ああ～。いかにもダメそうな関数。
でも、例をみてみると、やってしまいそうなデザイン。

アンチパターンのコード例で使われてる、Integer.parse()の動作を復習しておきます。

```Elixir
iex(18)> Integer.parse("123")
{123, ""}
iex(19)> Integer.parse("123a")
{123, "a"}
iex(20)> Integer.parse("b123a") 
:error
iex(21)> Integer.parse("b123") 
:error
iex(22)> 
```
数字の後に文字がある場合、その文字も取得できるという関数です。

アンチパターンのコードは以下の通り。
```Elixir
defmodule AlternativeInteger do
  @spec parse(String.t(), keyword()) :: integer() | {integer(), String.t()} | :error
  def parse(string, options \\ []) when is_list(options) do
    if Keyword.get(options, :discard_rest, false) do
      Integer.parse(string)
    else
      case Integer.parse(string) do
        {int, _rest} -> int
        :error -> :error
      end
    end
  end
end
```

文字列をパースして値を取得する関数です
discard_restがtrueの場合は、整数値のみ。残りの文字列は返さない。
discard_restがfalseだったり指定されてない場合は、Integer.parse()の戻り値をそのまま返す。残りの文字も取得できる。

こんな関数作ってしまいそうです。

# 何が良くないのか？

まず、返り値の型が一定でないので、扱いずらいです。
この関数は次の二つの機能をもっています。
- 文字列を整数に変換して、整数と、残りの文字を返す
- 整数か、{整数,残りの文字}どちらにするか選択する

一つの関数に複数の機能を持たせている事も、関数を使う人に余計な知識を要求する事になります。

確か、達人プログラマーにflagの使用は良くないとかあったような気がします。
この観点からもアンチパターンですね。

# どうするのが良いか

二つの関数に分けます。
パースして整数を得る
パースして、{整数,残りの文字}を得る
だったら、それぞれ一つの機能と言えます。

```Elixir
defmodule AlternativeInteger do
  @spec parse(String.t()) :: {integer(), String.t()} | :error
  def parse(string) do
    Integer.parse(string)
  end

  @spec parse_discard_rest(String.t()) :: integer() | :error
  def parse_discard_rest(string) do
    case Integer.parse(string) do
      {int, _rest} -> int
      :error -> :error
    end
  end
end
```

parse_discard_restは、Integer.parseとcase文の複数の処理をしているじゃないか！という突っ込みがあるかもしれませんが、ここで問題にしている複数の機能とは、そいう事ではありません。
一つの機能を実現するために複数の処理を組み合わせる事は、必要な事で問題ではありません。
parse_discard_restは文字列を与えると、parse_discard_restが決めた形式の値を返すという単機能の関数になっています。

# 別の解決方法

この例は、parseの内容が単純なので、二種類のparse関数を作るので十分だと思いますが、こんな関数を用意する方法もあると思いました。

```Elixir
  def discard_rest(parsed_value) do
    case parsed_value do
      {int, _rest} -> int
      :error -> :error
    end
  end
```
[SwiftUI]TextFieldで複数行対応するには

# SwiftUIのTextFieldで複数行対応するには
axisでverticalを指定します。

```swift
struct TextCountView: View {
        @State private var text = ""

        var body: some View {
            VStack {
                TextField("ここにテキストを入力", text: $text, axis: .vertical)
         }
    }
}
```

指定することによって複数行対応できます！
C++で文字列をトリミングする

```c
std::string& ltrim(std::string &s)
{
    auto it = std::find_if(s.begin(), s.end(),
                    [](char c) {
                        return !std::isspace<char>(c, std::locale::classic());
                    });
    s.erase(s.begin(), it);
    return s;
}
 
std::string& rtrim(std::string &s)
{
    auto it = std::find_if(s.rbegin(), s.rend(),
                    [](char c) {
                        return !std::isspace<char>(c, std::locale::classic());
                    });
    s.erase(it.base(), s.end());
    return s;
}
 
std::string& trim(std::string &s) {
    return ltrim(rtrim(s));
}
```
日付計算について（ローン計算アプリ）

## Microsoft Power Apps Advent Calendar
この記事は、Microsoft Power Apps Advent Calendar 2023 20日目の記事です。

https://qiita.com/advent-calendar/2023/powerapps


## 自己紹介
　佐賀県の小売業で情シスをしています。
 
  2023年に社内のＤＸ事業の一つでPower Platformによる内製アプリ開発(Power Apps)とデータ分析(Power BI)が評価され、日本ＤＸ大賞を受賞することが出来ました。


 https://www.saga-smart.jp/2023/20230623.html 





## 内容

かなり前に外部依頼して作成したショッピングローン計算があったのですが、ＯＳのサポート期限切れで利用出来なくなっており、このアプリだったらPower Appsにて作成出来るかなと思い作成した際に日付計算のところで迷ったので記事にしてみました。



#### かなり前に外部依頼で作成したアプリ（iosは Apple Storeから削除されている）

https://play.google.com/store/apps/details?id=co.jp.suzuhana.LoanCalculator&hl=ja-JP


#### Power Appsにて今回作成したアプリ（アプリ名も一緒）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/709d0ce9-89fd-804b-cb3a-1a54a1170423.png)




## 各種日付計算

### 終了月計算
　ローンの終了月計算は、Power AppsのDateAdd関数で計算する。

```c#
DateAdd(
    Loan_s_date,
    Loan_number -1 ,
    TimeUnit.Months
    )
```
 
### ボーナス加算月の回数計算
支払期間中に指定した月が何回あるかを判断するのにPower Appsの関数のみで計算可能か考えてはみたが、良い案が見当たらず迷ったところ、Power BIで使用する日付テーブルがあれば、Power Appsでも使えるのではないかと思い試してみました。
 

https://learn.microsoft.com/ja-jp/power-bi/guidance/model-date-tables#generate-with-power-query


### 日付テーブルの作成方法
   日付テーブルとは、時系列計算を行う際に利用するテーブルになります。
   列名に会計年度・年・月・日や曜日等が入っており、時系列を計算する際に使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/07e5f474-9554-eb9a-7bc6-dfa6008d998b.png)

 
#### データソースがMicrosoft Dataverseの場合
 　　Power Appsでのデータフローにて、Power Query Onlineにて日付テーブルを作成後、Dataverseにインポートをする。


https://learn.microsoft.com/ja-jp/power-apps/maker/data-platform/create-and-use-dataflows


 
 #### データソースがSharepoint Listの場合
   
 ExcelのPower Queryにて日付テーブルを作成後、インポートする等があります。
 

### Filter関数でボーナス月の回数を取得
　 
 Power Appsのfilter関数にて、日付テーブルから開始日から終了日で日付が1日のデータをMonth_loandateに保存する。



 ```c#
///日付テーブルから月単位のテーブルを作成
 ClearCollect(
     Month_loandate,
        Filter(
            Date_tbl,
            Calender_date >= Loan_s_date,
            Calender_date <= Loan_e_date,
            Date_day = 1        
        )
    )

```

   #### ボーナス支払回数を計算

   日付テーブルを元に作成したMonth_loandate内にあるDate_monthがボーナス支払月と一致する件数をCountRowsで取得しボーナスの支払回数を計算します。

  

　
 ```c#
///ボーナス支払月（夏）の支払回数
CountRows(
    Filter(
    Month_loandate,
    Date_month = Bounus_summer
    )
)
 ```

#### 各支払金額を計算
　 
   ボーナス支払額（夏、冬）、月々支払額（100円未満切捨）、初回支払額の計算を行い表示
   

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/09bb4a02-f413-ffc2-6953-a581996e282f.png)
 

#### 月々のローン支払シミュレーションを作成
　
外部に依頼したアプリでは月々のローンシミュレーション機能が予算の関係で出来なかったが、Power Appsなら出来るかなと思い挑戦してみる。

日付テーブルやForAll関数を駆使しながら何とか作成
 

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/d845d831-90d5-d0e1-5b76-714d934bb8ce.png)



 ## まとめ

 日付計算についてPower Appsの関数のみに頼るのではなく日付テーブルを作成後、Filter関数を使うことにより、容易に日付計算を行うこともあります。
 
 日付は変わることはないのであらかじめ日付テーブルを作っていれば、日付計算が楽になるかもしれません。
NumPy【概要】

# NumPyとは
***NumPy（Numerical Python の略）*** は、Pythonで数値計算を効率的に行うためのライブラリ。

特に多次元配列を操作するための強力な機能と、さまざまな数値計算用の関数が提供されている。これにより、Pythonで機械学習のコーディングやデータ分析を行う際には欠かせないツールとなっている。

数値計算やディープラーニングの実装にも使われており、このライブラリを使うことによって、以下のようなメリットがある。

- NumPyを使うことで、時間がかかる計算を高速に処理できる
- 計算に必要な配列を簡単に作れる
- シンプルな書き方で配列の演算処理ができる
- AI や機械学習を実装する際に便利な関数が多く用意されている

NumPyを使うことで、演算処理時間の短縮、ソースコードをシンプルに記述できる。
このようなメリットから、データ分析、機械学習では特にNumPyが多く使われている。

# NumPyの機能
NumPyの主な機能は以下。
- 多次元配列を作る機能
- 機械学習と統計
- 数値計算
## 多次元配列を作る機能
NumPyでは、複数の一次元配列によって作られる ***「多次元配列」*** を簡単に書ける。

NumPyの多次元配列は、行列として扱え、データ分析や機械学習での計算をシンプルにできる。
ディープラーニングでは ***「テンソル」*** と呼ばれる多次元配列を入力することで、データ分析、機械学習の基礎になる。

## 機械学習と統計
NumPyは行列同士の演算はもちろんのこと、行列演算がもととなっている ***機械学習や統計*** にも使える。

例えば「最小二乗法」という機械学習におけるシンプルなアルゴリズムも、NumPyを使えば簡単に実装可能。

また、統計量も、合計、平均、分散などを求める関数を使用して算出できる。

## 数値計算
Numpyを使えば、データ分析や機械学習を構成する基礎にもなっている ***「数値計算」*** といわれる分野にも応用できる。

数値計算は簡単には解けない問題に対して、近い数値を答えとして求める手法を扱い、例えば、
- 最小二乗法
- ニュートン法
- 固有値計算
- フーリエ変換

など機械学習やディープラーニングではよく使われる手法を扱う。

# NumPyを利用するメリット
NumPyを利用するメリットは多くあるが、そのうちの2点を列挙。
- 高速な計算の仕組み
- ブロードキャスト

## 高速な計算の仕組み
NumPyは、Pythonだけで書くよりも処理を高速化できる。

NumPyのコアとなる部分は、主にC言語やC++言語という、Pythonと比べると高速に処理を実行できるプログラミング言語で作られているため、Pythonだけで書くよりも速くなる。

そのほかにも、NumPyはCPUの最適化やビルド時に利用する「BLAS」や「LAPACK」と呼ばれる機械学習に必要な行列演算を処理するライブラリを使った高速化も可能にしている。

## ブロードキャスト
通常、行列の足し算や掛け算は要素数と次元が同じでないとできず、多次元配列の場合、要素数が異なる多次元配列同士では計算が不可能。

NumPyには、このルールを緩和できるメリットがあり、それが ***「ブロードキャスト」*** という機能。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/887960/b4c3867b-7aa4-dfbc-8a01-693e11798395.png)

このように、本来はタブーである計算を有効にする機能であり、このブロードキャストのおかげで実装を直感的に行うことができる。

もちろん足し算だけではなく、引き算、掛け算などでも同様に機能する。

# まとめ
- NumPyはPythonで数値計算を効率的に行うためのライブラリ
- データ分析、機械学習では多く使われている
- 「多次元配列」「機械学習」「統計学」「数値計算」といった機能がある
- NumPyを使うことで計算の高速化、ブロードキャスト等のメリットがある

NumPyは機械学習だけでなく、画像処理、音声処理、他にも多くの問題に適用できる。
リハビリアプリを作ろう（その６）

こちらの続きです

https://qiita.com/t-yamanashi/items/bcc044ce173d1dfd39a8

1-25の数字押していくゲームを作りたいです
このコラムの範囲
- スタート
- 不要なヘッダを削除

# スタートを追加
自身をリロードで時間をリセットする

```diff_elixir:lib/num_web/live/user_live/index.html.heex
  <div  class="w-28 h-28 m-2 bg-red-200 text-center">
  <p class="pt-7 text-5xl text-red-700 "><%= @question %></p>
  </div>
+ /<.link href="/users" class="pt-7 text-5xl ">スタート</.link>
  <p class="pt-7 text-5xl text-red-700 "><%= @time %></p>
  <br>
  <%= for {s, i} <- Enum.with_index(@num, 1) do %>
    <%= if Enum.find_index(@ok_num, fn x -> Integer.to_string(s) == x end) == nil do %>
      <div phx-click="buttno" phx-value-no={s}  class="float-left w-28 h-28 m-2 bg-blue-200 text-center ">
        <p class="pt-7 text-5xl text-blue-700 "><%= s %></p>
    <  /div>
    <% else %>
      <div  class="float-left w-28 h-28 m-2 bg-blue-100 text-center ">
      </div>
    <% end %>
    <%= if rem(i, 5) == 0 do  %>
      <br>
    <% end %>
  <% end %>
```

# 不要なヘッダーを削除
```elixir:lib/num_web/components/layouts/app.html.heex
<main class="px-4 py-20 sm:px-6 lg:px-8">
  <div class="mx-auto max-w-2xl">
    <.flash_group flash={@flash} />
    <%= @inner_content %>
  </div>
</main>
```

# 現時点結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/295814/e06be98b-a39c-bdef-2b03-a9947bc951dc.png)


これで完成

ソース
https://github.com/t-yamanashi/num25
Microsoft Power Automate Desktop（無償版）でカッコよく定時実行をする！

# はじめに
この記事は、
Microsoft Power Automate Desktop(以下、PADと呼ぶ)の定時実行をお金をかけずにしたい人向けになります。
またスケジューラなど、PAD以外のツールを組み合わせて行うので、PADと他サービスをどう連携していけばいいかわからない方も見ていただくと参考になると思います。

# PADとは？
PADは、Microsoftが提供しているRPAツールです。
細かいPADのメリット、デメリットは以下の記事に記載したので参考にしてください。
・[Microsoft Power Automate DeskTopって何？ ～ここがすごいぞ！PAD～](https://qiita.com/caffeine1202/items/d71eb86250736a788ea6)

# 定時実行について
定時実行は、PADの有償版ではできます。しかし、「如何に安く、如何にカッコよく」で生きてる私としては無償版でやりたいと考えました。
先人に無償版で定時実行を行うチャレンジをやっている方がいましたので、共有します。
・[Power Automate Desktop無料版で定期実行を実現する](https://prtn-life.com/blog/pad_troubleshooting_autorun)
・[Power Automate Desktopの自動実行　Task Schedulerの力で！](https://qiita.com/mimicetacea/items/f066f491b0c323975c8f)
先人の方の方法をまとめると、
1. URLを指定してフローを実行する方法
1. 無限ループを回し続ける
1. タスクスケジューラで実行する

の3つを提唱しています。
それぞれ見ていくと、
1. PowerAutomate(Web版)を利用しないといけない(有料)
1. 無限ループを回し続ける
1. フローの外部実行が必要(PADの有償版限定の機能)

各々のやり方を見てみても有料の機能を使用していたり、処理がかなりダサかったりと、「如何に安く、如何にカッコよく」をモットーにしている私からすると物足りないやり方だと感じました。
そこで、自分なりに、無料で定期実行する方法はないか考えました。やり方を共有する前に、PADフローの実行方法についておさらいします。

# PADフローの実行方法
PAD(無償版)フローの実行方法は、3つあります。
1. 手動実行(ボタン押下)
1. ショートカットキー入力
1. 別フローからフロー呼び出し

各々の実行方法からわかる通り、PADを経由せずにフロー実行のトリガーがボタンを押すか、ショートカットキーを押すくらいしかありません。
先人たちのやり方同様に、うまく他サービスとの連携が必要になります。

# PADフローの定時実行方法
先人たちのやり方と、PADフローの実行方法を元に、自分なりの定期実行方法を考えていきます。
PADの機能として定期実行がないので、他サービスで定期実行をする必要があります。
無料で定期実行できるアプリといえば、**タスクスケジューラ**です。
ここからタスクスケジューラとPADをどのように連携するかを考えていきます。
PADを使わずに、PADフローの実行方法は、手動実行、ショートカットキー入力の2つしかありません。
この２つで、別アプリやライブラリで自動化できるのはショートカットキー入力です。
つまり、ショートカットキー入力を行うソースコードを作り、そのコードをタスクスケジューラで定期実行すれば、PADフローも定期実行出来るのでは？と考えられます。
よって私の考えたPADフローの定期実行方法の流れは、
1. PADフローにショートカットキーを付与する
1. ショートカットキーを入力するソースコード(PyAutoGUIなど)を作成
1. タイムスケジューラでソースコードを定期実行する
となります。

このようにPADフローの定期実行を無料の範囲で、かつ無理矢理な形ではなく、カッコよく行うことができます。

# おわりに
今回は、PADフローの定期実行を無料でカッコよくやる方法の紹介でした。
調べていてわかったことは、一つのアプリでは出来なくても、複数のアプリを掛け合わせることで再現可能であることです。
皆さんもこのアプリではこの機能がありませんを鵜呑みにせず、別のアプリと連携すれば再現出来るのではの精神で色々試してください。
最後にUNIX哲学で、私の好きな言葉を書いて終わろうと思います。
「**ソフトウェアを梃子(てこ)として利用せよ**」。
教える立場になって気づいたこと

## Power BI Advent Calendar2023
 この記事は、Microsoft Power BI Advent Calendar2023の19日目の記事です。

https://qiita.com/advent-calendar/2023/powerbi


## 内容
　佐賀県の小売業（和服）で情シスをしています。
　レポート開発者を増やすためPower BIの社内勉強会を実施をし、人に教える立場になって気づいたことをまとめました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/38f19aca-9b7d-4152-ef22-9fc55aac96e8.png)


## 人に教えることで気づいたこと

　前までは人に教えてもらう場面が多かったのですが、自分が教える立場になった際に、教えることがこんなに難しいことに気づきました。

### １．私自身の教えるのが苦手
　私自身が人に教えるがまだ慣れてないのと、「分かっているつもり」だった部分が多く、内容を正しく伝えきれないことが多い。
 
 またやる気を引き出すように教えるというのも難しい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/c04754af-4c68-a941-df43-a390ef4d793d.png)


  
  
### ２．新しいことを学ぼうとしない、現状維持の意識が強い
　保守的な企業なこともあり今のままでの業務のやり方を変えたくない部門が多い。
  業務システムからエクセル出力しデータを加工して資料作成するのが正しいと思っている。
   　
 日本ＤＸ大賞を受賞して何かしら興味を持つかと思ったのだが、まだ自分は関係ないと思っている人が多いので現状維持の打破はなかなか厳しい。

  
   
### ３．どこで躓いているかが分からない   
　 質問をしてくる人はどこで躓いているのかが分かるが、逆に質問がない場合に本当に理解していると勘違いしてしまうこともある。
  
  社内勉強会で質問がないのは、興味がないか私の教え方が間違っていると考えています。
 　    
　　
###  ４．応用から聞いてくる
　Power BIが誰でも簡単に可視化・分析出来ると思っている人が多く、最初から富士山の頂上を目指すような難しいメジャーやレポートを要求してくることがある。
　
 基礎を飛ばして応用から聞く人は、自分で学ぼうとする気がないと私は思っています。



### ５．システム関連は、全て情シス担当だと思っている
 　
社内で勉強会に参加はするが自身でレポート開発に挑戦もせず、後は「勉強会で○○できるならこのレポート作って」もあります。
業務データに詳しいのは業務部門なので、慣れれば私が作成するより業務に詳しい人がレポートを作る方が早いと思うのだが、そこまで行くのがなかなか難しい。




## 地域コミュニティで勉強会を行う
私自身も教える力をつけるのはもちろんのこと、「分かっているつもり」だった自分に出会うためにも、県のコミュニティ支援を受け、月１回オンラインでの勉強会を行うことにしました


https://www.saga-smart.jp/community/



### 勉強会を行うことで得られたもの　

地域コミュニティの代表者になったことで、コミュニティの運営が大変なことに気づき、県からのコミュニティ支援がなかったら続いていないと思います。
 
社外向けにPower BIオンライン勉強会を実施し、緊張はしましたが何とか無事に終わることが出来しました。
　
また最後に感謝され、社内勉強会では感謝されることがないためとても嬉しかったのと継続して続けようという気持ちになれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277732/d0f74fc3-6392-d690-d626-9a23de8f417a.png)

https://saga-hagakure.connpass.com/event/300074/

### 佐賀ITフェアで地域コミュニティをアピール
　１２月１２日の佐賀ＩＴフェア登壇の際に、地域コミュニティの紹介を行いメンバーを募集をしました。

佐賀県近隣でPower Platformに興味を持ち一緒に学ぶ人が増えていけば、オフラインでの勉強会実施も考えていきたいと考えてます。



## 結論・まとめ

　
　 
- 興味がない人には教えてもあまり意味がないので、興味がある人を集中して教える
- 応用から最初から聞いてくる人は無視して、基礎から順次教えていく
- 教える人数が少ないからこそ、相手に合わせた教え方を考える
- 根気よく勉強会を続けていき、勉強会参加者を増やして行く
 
 
#### そして感謝の気持ちを忘れないように勉強会を続けることが大事だと思いました。
[Python] print関数とreturn文の違い 

## print関数とreturn文の違いについて、備忘録としてここに記す。

### 環境
- MacOS Monterey
- Python3.11.1

### まとめ
- print関数:文字列や数値を出力
- return文:処理結果（戻り値）を他の関数で利用する際に使用

### コード比較
 ~~~Python:print
def number():
    print(1)
print(number())
 ~~~

 ~~~Python:実行結果
1             # print(1)の実行結果
None          # print(number())の実行結果
 ~~~

  ~~~Python:return_1
def number():
    return(1)
print(number())

  ~~~

 ~~~Python:実行結果_1
1             # print(number())の実行結果
 ~~~
 
   ~~~Python:return_2
def sum(a, b):
    c = a + b
    return(c)
print(sum(a, b))

  ~~~

 ~~~Python:実行結果_2
c             # print(sum(a, b))の実行結果
 ~~~


### 参考リンク
[プロセス視点の解説](https://note.com/mumyo__nn/n/n69ceb51c6e71)
[データ型視点の解説](https://1978works.com/2021/10/28/how-to-understand-differences-between-return-statement-and-print-function-in-python/)
【Rails】タグ登録、重複させないためにはコツがいる

:::note warn 
**注記**
この記事の投稿者はRuby on Rails初学者であり、自身の学習の備忘録目的で記事投稿を行なっております。
情報の正確さには最大限注意をしておりますが、もし誤り等がございましたらお知らせいただけますと幸いです。
:::

アクセスしていただきありがとうございます。
Rails初学者です。
学習の一環として記事投稿アプリを作成中です！
躓いたところについてアウトプットしていきたいと思います。
修正やご意見ありましたらどうぞお聞かせください。（何卒）

## 状況
- Ruby on Railsで記事投稿アプリを作成中。
- ユーザーが記事を投稿する際に、タグを入力し記事に反映させる機能を実装中である。
  - タグ同士を , (カンマ)で区切り、複数のタグを保存できる機能を作している。


## やりたいこと
登録しようとしているタグが重複している場合、重複して保存されないようにしたい

## 書いてみたコード
```ruby:post.rb
class Post < ApplicationRecord
    
  # ... (中略) ...

  # 入力フォームで入力されたタグを連結する
  def tag_list
    tags.map(&:name).join(', ')
  end

  # タグを保存する際に重複を削除する
  def tag_list=(names)
    self.tags = names.split(',').map do |name|
        Tag.where(name: name.strip).first_or_create!
    end
  end
  
end
```
**`Tag.where(name: name.strip).first_or_create!`** の部分で、
まずデータベースに対して **`name.strip`** という名前のタグを検索し、
見つからなければ新しく作成する処理。


### 実行結果
タグの保存自体はできたが、重複したタグはそのまま（複数）登録されてしまった。

## 修正後コード

```ruby:post.rb
class Post < ApplicationRecord
    
  # ... (中略) ...

  # 入力フォームで入力されたタグを連結する
  def tag_list
    tags.map(&:name).join(', ')
  end

  # タグを保存する際に重複を削除する(変更箇所)
  def tag_list=(tags)
    unique_tags = tags.split(',').map(&:strip).uniq
    self.tags = unique_tags.map { |tag_name| Tag.find_or_create_by(name: tag_name) }
  end
```

### 実行結果
タグが重複している場合、重複したタグは削除され、同名のタグ一つのみが登録されていることが確認できた。

## なぜ最初のコードではうまくいかなかったのか？
修正前のコードでは、最初の呼び出しで作成されたタグがデータベースに反映される前に、2回目以降の呼び出しが行われる可能性があった。(```do```ブロックの中)
そのため、同じ名前のタグに対して **`first_or_create!`** メソッドが複数回実行され、結果として同じ名前のタグが複数作成されていたと考えられる。

一方、修正したコードでは、まず最初に与えられたタグを適切に処理してからデータベースの検索や新規作成を行うため、同じ名前のタグに対して重複した処理が発生しないようになっている。

## まとめ
ロジック的に正しくても意図した挙動をするのか、実際に動かして検証する必要があると感じた。頑張る！
Spring Academy でSpring学習の第一歩を始める

この記事は TUNA Advent Calendar 2023 の 10 日目の記事です。

Java の基本的な文法は知っていて、Spring もちょっと触ってみたい、勉強してみたいという方にお勧めな教材である [**Spring Academy**](https://spring.academy/) について紹介します。

## Spring Academy とは
![Screenshot 2023-12-10 094457.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325577/e07b9e2a-5f5d-3085-40e0-9f488e94907f.png)

VMware が提供している Spring についての On-demand のコースが受講できるプラットフォームです。

無料コースと有料コースがありますが、無料コースでも基本的なコースは受講できるので、Spring の基本的な部分を整えられたテキストと付属するラボ環境でお手軽に学習できます。

### ちなみに spring とは
Spring Frameworkは、Javaプログラミング言語を使用した企業向けのアプリケーション開発をサポートするためのフレームワークです。Springは、アプリケーションの構築、テスト、デプロイメント、保守のさまざまな側面をサポートする広範な機能を提供しています。

## 使い方とおすすめコース
使い方としては、Login から VMware Customer Connect のアカウントを使用してログインして、コースを選択して受講を開始する形です。

受講した無料コースの中では以下のコースがおすすめでした。
**Building a REST API with Spring Boot**
コースの説明：
この初心者向けコースでは、Spring Bootを使用して最初から最後まで完全なREST APIを構築する方法を学びます。対話型のラボを使用して、Spring Initializrを使用したブートストラップからSpring Securityを使用した認証および承認まで、一連の手順ごとに実践的な経験を得ることができます。

おすすめポイント：
1\. インタラクティブな事前設定済みのラボがある
2\. ラボの作業に必要十分な内容の説明がある

個人的には学習を始める際にはラボの実施のための環境構築が手間に感じるので、
そこが準備されている点がとても良いと感じました。

:::note info
コースの内容では、Java の基本的な内容は知っていることが前提として進められます。
そのため Java の知識があやふやな場合はまず Java の勉強をしてからのほうが理解が深まると思います。

Java の勉強本としては、「スッキリわかるJava入門 」が説明とコードのバランスが良くて好きです。
:::

またコースは Test Driven Development(TDD) 形式で進められていくので、
TDD ってなんだ？とかなにが嬉しいの？というポイントも合わせて勉強的できて
とても有意義でした。

## まとめ
Spring の学習を始める際には、無料でインタラクティブな事前設定済みなラボが使用できる Spring Academy を是非触ってみてほしいと思っています。

プログラミング言語やフレームワークの勉強を始める際にはいろいろな始め方があると思いますが、
例：
- 公式ドキュメント読み込み & Quick Start を試す
- 本を買って読む
- トレーニングに参加する
- Youtubeを を見る

個人的には、よく整えられた教材でざっくり雰囲気を掴んでからドキュメントや本を読んで深めていくのが好きなので、Spring Academy はとても良い勉強教材だなと感じました。
Terminal上で文字を入力してるんだけど、文字が置き換わっちゃう問題についての対処法

# はじめに
Linuxの勉強をしていました。
Terminal上で入力しているときに、急に入力している文字が置き換わっちゃった。置換されてた。
どうにかして元に戻したい。
使いにくい。

# 原因
置換モードになっていたから。

# 前提
Window 11を使っています。

# 解決策
`Insert`キーをもう一回押す

注意事項：`Insert`キーはキーボード上で`Ins`と表示されていることがある。

Insertキーで入力モードを変更することが出来るようです。
詳しくは参考文献を見てください。

# おわりに
今日もよい一日を！
今回、解決策を探すにあたって、ChatCPTにいろいろ聞きました。
分からないことを根掘り葉掘り聞けて、人間と会話しているみたいにどんな質問にも答えてくれるChatCPTすげえ。

# 参考文献
[上書き入力モードをオンまたはオフにする](https://support.microsoft.com/ja-jp/topic/%E4%B8%8A%E6%9B%B8%E3%81%8D%E5%85%A5%E5%8A%9B%E3%83%A2%E3%83%BC%E3%83%89%E3%82%92%E3%82%AA%E3%83%B3%E3%81%BE%E3%81%9F%E3%81%AF%E3%82%AA%E3%83%95%E3%81%AB%E3%81%99%E3%82%8B-2fe125af-505f-4ce7-bbea-f0e64e381e75)
画像やCSSを先読み、"WebLink"

[Symfony Component Advent Calendar 2023](https://qiita.com/advent-calendar/2023/symfony-component)の13日目の記事です。

## 画像やCSSを先読み、"WebLink"

[WebLink](https://symfony.com/doc/current/web_link.html)は、HTTP/2 Server PushやResource 
 Hintsを使って、画像を事前にロードできるコンポーネントです。HTML部分に影響があるので[Twig](https://qiita.com/ippey_s/items/a81cf9980ed0f8c63a3e)が必要です。

※ [Resource Hints](https://qiita.com/ohakutsu/items/9b8d4ca39d23774c2e5a)について
※ [HTTP/2 Server Push](https://blog.redbox.ne.jp/http2-server-push-cdn.html)について

### インストール

```shell
composer require symfony/web-link
```

### Preload

WebLinkインストール前は`base.html.twig`で以下のようにCSSを読み込んでいます。

```twig
{% block stylesheets %}
    <link rel="stylesheet" href="{{ asset('styles/app.css') }}">
{% endblock %}
```

WebLinkをインストール後、上記部分をちょっと変えます。

```diff
{% block stylesheets %}
-    <link rel="stylesheet" href="{{ asset('styles/app.css') }}">
+    <link rel="preload" href="{{ preload(asset('styles/app.css'), {as: 'style'}) }}">
{% endblock %}
```

すると、レスポンスヘッダに`Link`が追加されます。

```
Link:
</assets/styles/app-4820de829a334adbb3ab0347b423073a.css>; rel="preload"; as="style",
```

このレスポンスヘッダがついている場合、HTTP/2に対応のサーバであれば該当のCSSはサーバ側からpushされます。イメージ的にはCSSのリクエスト分速くなる感じでしょうか。

通常
```plantuml
ブラウザ -> サーバ: GET /index
サーバ -> ブラウザ: レスポンス /index
ブラウザ -> サーバ: GET /styles/app.css
サーバ -> ブラウザ: レスポンス /app.css
```

WebLink利用時
```plantuml
ブラウザ -> サーバ: GET /index
サーバ -> ブラウザ: レスポンス /index
サーバ -> ブラウザ: レスポンス /app.css
```

Cloudflare, Fastly, Akamaiなどもこの機能を利用しているとのこと。

### Resource Hints

Resource Hintsはどのリソースを最初にダウンロードしたり、前処理・接続する必要があるかをブラウザに伝えます。Preloadと同じく、レスポンスヘッダの`Link`に記載されます。

| 関数 | 事前に行う処理 | 残処理 |
|---|---|---|
| dns_prefetch() | DNS lookupまで | 接続・リソース取得・レンダリング　|
| preconnect() | 接続まで | リソース取得・レンダリング |
| prefetch() | リソースの取得まで | レンダリング |
| prerender() | レンダリングまで | |

例えば、`prerender()`であれば、

```plantuml
ユーザ -> ブラウザ: /indexを開く
ブラウザ -> サーバ: GET /index
サーバ -> ブラウザ: レスポンス /index
ブラウザ -> ユーザ: /index表示
ブラウザ -> サーバ: GET /other-page （prerenderで事前取得）
ユーザ -> ブラウザ: /other-pageのリンクを踏む
ブラウザ -> ユーザ: /other-page表示
```

といった感じになり、`/other-page`を高速で表示することができます。

## まとめ

今回は`WebLink`でした。画像やCSS、JSは気付けば大きなサイズになっているので、うまく使ってサイトの高速化を図りたいですね。
プロダクトにVISIONがなぜ必要なのか？

この記事はZOZOアドベントカレンダー2023 Series1 10日目の記事です

今関わっているプロダクトには「VISION」はありますか？プロダクトには「VISION」の必要だということを今日はお話しします。

成功して、継続しているプロダクトほど「VISION」が必要です。

ユーザーからのフィードバックやKPIを活用し改善しているプロダクトは多いと思います。

一見成功し、社会にインパクトを与え続けているように見えますが、こういうケースは新規顧客の獲得するために営業や広告といったいわゆるPRによる獲得が主かと思います。

それが悪いわけではないですが、長い目で見れば、時代の変化に追いつけず衰退に向かう可能性も大きいです。

[「両利きの経営」](https://www.amazon.co.jp/dp/4492534083)ではそれを「サクセストラップ」と呼び、[「組織を芯からアジャイルにする」](https://www.amazon.co.jp/dp/4802512384)では「最適化の呪縛」、[「プロダクトマネジメント」](https://www.amazon.co.jp/dp/4873119251)では「プロダクトの死のサイクル」と呼び警鐘を鳴らしています。

それを防ぐには、既存の顧客や営業など外部から得られる情報から改善を続ける「アウトサイドイン」の策に加え我々が本当に顧客に提供したいと心から思えるものを作る「インサイドアウト」の策が必要になります。

VUCAの時代と言われるように、複雑化した社会でソフトウェアが適用できる分野もどんどん広がっていく中で、顧客が欲しいものは顧客自身もわからない時代となっています。

つまり我々は「未知の知」を探していく必要があり、そこから価値を提供しなければならないということです。

下記（出典：[プロダクトマネジメント ビルドトラップを避け顧客に価値を届ける](https://www.amazon.co.jp/dp/4873119251)）図でいえば、上半分は既に我々が提供しているプロダクト（事実）と営業やユーザーからのフィードバック、アンケートなどで得られる情報（疑問）いわゆるアウトサイドインの範囲です。

必要なのは下半分。我々がまだ知らないところを知りに行く作業。（直感）からの実験、仮説検証、（発見）のためのワークショップなど、そこから新しい策を探っていく必要があります。。

![未知_既知.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150455/469f852c-3be7-60e2-8c1f-5f70569e63c8.png)


さあ、「未知の知」を探しに行こう！と行きたいところですが、闇雲にアイデアを出しに行ってもそれは無理な話。霧の中どうやって前に進むのでしょう。

そこで必要なのが「VISION」です。

たとえば、[東大大学院情報学環特任助教の安斎勇樹先生が講演で話されていた事例](https://www.youtube.com/watch?v=cIlued-uVaE)。
AIを活用した新しいカーナビをどうするか？を企画検討していたある企業の話です。自動運転の技術が目の前に迫っている時代にカーナビ自体が売れなくなってくるのが見えている中でAIを活用した新しいカーナビをどうするか？UIをどうするか？AI？運転者目線？
なかなかいい案が出てこないなかで安斎先生から投げられた問い「なぜカーナビを作っているのですか？」
そこで発せられた答えは「カーナビを作っているのではない。自動運転社会になっても車で移動する時間は変わらない。その時間、搭乗者に快適に社内で過ごしてもらう。快適で豊かな時間にしたい」という答えが返ってきて、「それだ！！！」となってそこから議論が加速したそうです。
この「搭乗者に快適に社内で過ごしてもらう。快適で豊かな時間にしたい」がまさにVISIONであり、そこから本当に顧客に提供したいと心から思えるものを作るという「インサイドアウト」の案が出てくるという好例です。

「VISION」は我々が何者何かを提示するものになります。霧の中はっきり見えるもの、向かう先になります。ここから「未知の知」を探すのです。「未知の知」を探す過程で「VISION」を定めるということもあるかもしれません。

今回の話しの必要性を理解してもらうための問いを提示してみますので、自分のプロダクトと照らし合わせて考えてみるとよいと思います。

1. 今携わっているプロダクトの成長のためにしていることは？営業やユーザーからのフィードバック、アンケートからの改善に留まっていないだろうか？
2. 今携わっているプロダクトを通して、顧客にどうなってもらいたいのだろうか？社会を世界をどう変えたいのだろうか？

最後に、VISIONが持つ効果は他にもあるので紹介して終わります。

- ビジネス側・開発側で同じVISIONを持つことで共通の目的をもつことができ、同じチームとしてはたらくことができる。
- 企業の理念やVISIONと結び付けられるプロダクトVISIONを持つことで、新しい企画の方向性を違えないようにすることができる。
- インサイドアウトの企画とはすなわち、「未知の知」まだ自分たちも、顧客も知らない世界を探す旅。VISIONは発見した何かを一言で表すことができるツールとして活用できる。それが他社との差別化にもつながる
- 強固なVISIONはメンバーのモチベーションにつながる

今VISIONがなく闇雲に突き進んでいる渦中にある方々にこの記事が目にとまればと思います。
3桁以上の数字をカンマで区切りたい時はtoLocaleString()

## はじめに
みなさんは3桁以上の数字をカンマ(,)で区切りたいと思ったことはありますか？
私は頻繁にあります！

¥30650, 2030kg, 6792034回....読みづらくないですか？
¥30,650, 2,030kg, 6,792,034回とカンマを入れるだけで読みやすくなる。

## 以前はどうしていたか

以下のようなメソッドを作って使いまわしていました。

```ts:tsファイル
const addComma = (count: number) => {
  const s = String(count).split(".");
  let result = String(s[0]).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
  if (s.length > 1) {
    result += "." + s[1];
  }
  return result;
};
```

```vue:vueファイル
<script setup lang="ts">
const const = ref<number>(6792034)
</script>

<template>
.
.
<div>{{ addComma(count) }}</div>   // 出力値:　6,792,034
.
.
</template>
```


でもこんなメソッド作らなくてよかったんです。

```vue:vueファイル
<div>{{ count.toLocaleString() }}</div> // 出力値:　6,792,034
```

`.toLocaleString()`で3桁以上の数字をカンマ(,)で区切れました！！
RockyLinux 9.xとUbuntu22.xにOpenSSL 3.2.xをインストールする（ソースからビルド）

RockyLinux 9系では標準でOpenSSL 3系がインストールされていますが､あえて最新バージョンをソースからインストールしたい時に利用します。

## 環境

| ソフトウェア | バージョン |
|:-----------|------------:|
| OS  | rockyLinux 9.3 or Ubunt 22.04|
| OS  | OpenSSL 3.2.0|

## 事前準備

予め以下のPerlパッケージをインストールしておく

```
sudo dnf install perl-FindBin
sudo dnf install perl-IPC-Cmd
sudo dnf install perl-Pod-Html
```

### インストール

```
cd /usr/local/src
wget https://www.openssl.org/source/openssl-3.2.0.tar.gz
tar xvzf openssl-3.2.0.tar.gz
cd openssl-3.2.0
./config -fPIC --shared --prefix=/usr/local/ssl
make -j 4
make install
```

以上で、/usr/local/sslに、OpenSSL3.2.xがインストールされます。
「--prefix」を付与しないと、/usr/local配下に直接インストールされるため、デフォルトインストールのOpenSSLとパスの設定によっては競合を起こすので部ディレクトリにインストールすることが望ましいと思います。
StorybookでSWCを有効にして快適な開発を行う

Storybook7.6からSWCサポートの改善が行わられ、いくつかのwebpackを用いたフレームワークを用いた環境では、Babelで動く部分をSWCを用いてStorybookを起動できるようになりました。
`react-webpack5`、`next`、`vue-webpack5`などが対象です。

これによってStorybookの起動までの時間が50%ほど削減されます。
また、Nextjsはバージョン11ごろからBabelではなくSWCを使うようになっています。StorybookがSWCで動くようになることでよりNextjs側の動作に近い動作をします(このサポートはNext14以降で行われます)。

導入は`main.ts`、`main.mjs`を触るだけで済みます。
```ts
export default {
  framework: {
    name: '@storybook/nextjs',
    options: { builder: { useSWC: true } }
  }
};
```
`framework`の`options.builder`で`useSWR`を`true`に設定するだけです。
簡単に有効化できるので、ぜひ一度試してみてはいかがでしょうか。
【React(TypeScript)】子コンポーネントから親コンポーネントのStateを更新する

# 概要
子コンポーネントから親コンポーネントのStateを更新する場合、親コンポーネント側にStateを更新するFunctionを作って、これを子コンポーネントに渡す方法が一般的かと思います。が、この方法よりも簡単にできる方法がありましたので、マイベストプラクティスとして共有させていただきたいと思います。

# やり方
子コンポーネントに親コンポーネントで定義したStateのSetterメソッドを渡すようにします。子コンポーネント側ではこのSetterメソッドを使ってStateを更新するようにします。

## 子コンポーネント
propsでStateのSetterメソッドを受け取れるようにして、これを使ってStateを更新します。

```jsx
import { type Dispatch, useState } from 'react'

type Props = {
  setIsOpen: Dispatch<React.SetStateAction<boolean>>
}

const ChildComponent = ({ setIsOpen }: Props) => {
  function handleOkButton() {
    setIsOpen(true)
  }

　・・・（省略）
```


## 親コンポーネント
子コンポーネントにStateのSetterメソッドを渡します。

```jsx
const ParentComponent = () => {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <ChildComponent setIsOpen={setIsOpen} />
  )
}
```
EC2ステータスチェック起点のイベント駆動を考える

# はじめに
この記事はDevOps on AWS大全の一部です。
DevOps on AWS大全の一覧は[こちら](https://qiita.com/tech4anyone/items/b06f88035d27c6ef13b2)。

この記事ではEC2ステータスチェックに関連する内容を超詳細にまとめています。

具体的には以下流れで説明します。

- EC2ステータスチェックとは
- EC2ステータスチェックの活用

AWSの区分でいう「Level 200：トピックの入門知識を持っていることを前提に、ベストプラクティス、サービス機能を解説するレベル」の内容です。

# この記事を読んでほしい人
- EC2ステータスチェックがどういうサービスか説明できるようになりたい人
- EC2ステータスチェックを採用するときのベストプラクティスを説明できるようになりたい人
- AWS Certified DevOps Engineer Professionalを目指している人

# EC2ステータスチェックとは
EC2ステータスチェックは、EC2インスタンスの状態を監視するための機能です。
これにより、物理的なホストの問題やインスタンス内のソフトウェアの問題を検出し、迅速な対応が可能になります。

## システムステータスチェック
システムステータスチェックは、EC2インスタンスが実行されている物理的なホストに関連する問題を確認します。具体的なチェック項目には以下が含まれます。

**インスタンスの接続性の確認**:
インスタンスが正常に起動し、ネットワークに正常に接続されているかどうかを確認します。

**ネットワークパケットの損失の確認**:
インスタンスと物理ホストの間でパケットの損失が発生していないかどうかを確認します。

**物理ホストのハードディスクの利用可能な空き容量の確認**:
インスタンスが実行されている物理ホストのディスクに十分な空き容量があるかどうかを確認します。

**物理ホストのネットワークの問題の確認**:
物理ホストのネットワークが正常であるかどうかを確認します。

## インスタンスステータスチェック
インスタンスステータスチェックは、EC2インスタンス内で実行されているソフトウェアやOSに関連する問題を確認します。具体的なチェック項目には以下が含まれます。

**システムの正常な起動**:
インスタンスが正常に起動し、実行中であるかどうかを確認します。

**システムの正常な動作**:
インスタンス内のシステムが正常に動作しているかどうかを確認します。

# EC2ステータスチェックの活用
これらのステータスチェックはEC2コンソールやAWS CLI、SDKを通じて表示でき、自動修復などのアクションをトリガーすることができます。 

![](https://storage.googleapis.com/zenn-user-upload/b393834b4a9f-20231210.png)

## 自動修復機能の活用
EC2ステータスチェックは、物理的なホストに問題が検出された場合に自動的に対処する自動修復機能を提供します。
例えば、物理的なホストの障害やネットワークの問題が発生した場合でも、新しいホストに移動してサービスの中断を最小限に抑えます。

## カスタムステータスイベントの設定
ユーザーはEC2ステータスチェックの結果に基づいてカスタムステータスイベントを設定できます。
これにより、特定のイベントに対するアクションを事前に定義し、自動的に対応完了することができます。

## CloudWatchアラームの統合
EC2ステータスチェックの結果はAmazon CloudWatchにも連携されます。
ユーザーはこれを利用してカスタムアラームを設定し、問題が検出された際に通知を受け取る、あるいはリカバリアクションの自動化を実現することができます。

## EC2 Auto Recoveryの設定
EC2 Auto Recoveryを使用することで、ステータスチェックに合格しない場合に自動的に新しいインスタンスに置き換えられるように設定できます。

# まとめ
この記事ではEC2ステータスチェックに関連する内容を超詳細にまとめました。

- EC2ステータスチェックとは
- EC2ステータスチェックの活用

次回はCloudTrailについて超詳細解説します。
bra-ket(ブラケット記号)

### 由来
単語"bracket", "c"で分割すると、左が"bra"、右が"ket"
### 書き方
<φ|ψ>[^1]
- ψ：ket：column vector：a state
- φ：bra：row rector: where does the state can be found

### 同一行列φがketからbraに変換
```math
\Bra{φ} = \ket{φ}^{\dagger} =
\begin{pmatrix}
1 + 2i \\
3 + 4i \\
\end{pmatrix}^{\dagger} = 
\begin{pmatrix}
1 - 2i & 3-4i \\
\end{pmatrix}
```

<details><summary>latex</summary>

```
\Bra{φ} = \ket{φ}^{\dagger} =
\begin{pmatrix}
1 + 2i \\
3 + 4i \\
\end{pmatrix}^{\dagger} = 
\begin{pmatrix}
1 - 2i & 3-4i \\
\end{pmatrix}
```
</details>


:::note info
bra and ketは互いの随伴行列
:::






[^1]:ギリシャ文字。φ：phi(ファイ)、ψ：psi(プサイ)
http://www.ele.kochi-tech.ac.jp/tacibana/etc/analog-intro/greek-alpha.html
【React(TypeScript)】axiosのinterceptorsでuseNavigateを使う

# 概要
axiosでエラーが発生した時にエラー画面に遷移させるとか、axiosのインターセプターでuseNavigateを使いたい時ってありますよね。色々と試行錯誤して、比較的簡単に実現できる方法が分かりましたので、同じように困っている方に向けてマイベストプラクティスとして共有させていただきたいと思います。

# やり方
axiosのレスポンスインターセプターをコンポーネント化し、これをReact Routerで有効にします。

## axios.ts
axiosのインスタンスを作成し、必要に応じて共通の設定を入れてexportします。

※ここではextendsフォルダ配下に作ったとします。

```js
const axiosClient = axios.create({
  baseURL: process.env.REACT_APP_API_BASE_URL,
  timeout: 30000,
})

export default axiosClient
```

## AxiosResponseHandler.tsx
axiosのレスポンスインターセプター用にコンポーネントを作成します。（※コンポーネントなのでファイルの拡張子は.tsxにする必要があります）
useEffect()を使ってaxiosのレスポンスインターセプターを設定します。コンポーネントになっているのでuseNavigateなどのReact Hooksを自由に使うことができます。
useEffectの処理は非同期で行われるのでInterceptorがうまく設定できないことがあるためisSetというState変数を作って確実に設定されるように制御します。
returnは引数のchildrenをそのまま返すようにします。

```jsx
import axios from 'extends/axios'

type Props = {
  children: React.ReactNode
}

export const AxiosResponseHandler = ({ children }: Props) => {
  const navigate = useNavigate()
  const [isSet, setIsSet] = useState(false)

  useEffect(() => {
    // リクエストインターセプター
    const requestInterceptors = axios.interceptors.request.use((config) => {
      // 例：共通リクエストヘッダーを付ける
      config.headers['XXXXXXX'] = XXXXX
      return config
    })

    // レスポンスインターセプター
    const responseInterceptors = axios.interceptors.response.use(
      (response) => response,
      async (error) => {
        switch (error.response?.status) {
        
　　　　　(省略)

          case 500:
            navigate('error/500')
            break
          default:
            return await Promise.reject(error)
        }
      },
    )
  }, [])

  setIsSet(true)

  // クリーンアップ
  return () => {
    axios.interceptors.request.eject(requestInterceptors)
    axios.interceptors.response.eject(responseInterceptors)
  }

  return <>{isSet && children}</>
}
```

## Router.tsx
BrowserRouterとRoutesの間にAxiosResponseHandlerを入れます。これによりRoutes配下の画面でextends/axiosを使用すれば、AxiosResponseHandlerのaxiosレスポンスインターセプターが有効になります。

```jsx
const Router = () => (
  <BrowserRouter>
    <AxiosResponseHandler>
      <Routes>
        <Route path="signIn" element={<SingIn />} />

        (省略)
        
      </Routes>
    </AxiosResponseHandler>
  </BrowserRouter>
)

export default Router
```
## (参考) 直接axiosを使うのを禁止する
拡張したaxiosではなく、直接axiosを使ってしまうとインターセプターの処理を通らないので困ったことになります。これを防ぐためESLintを使って直接axiosをインポートするのを禁止します。
ESLintの導入方法についてはここでは触れませんので各自でググってください。

### .eslintrc.json
```json
{
  "rules": {
    "no-restricted-imports": [
      "error",
      {
        "paths": [
          {
            "name": "axios",
            "message": "Please import axios from 'extends/axios'."
          }
        ]
      }
    ]
  }
}
```
JavaScript でカタカナの全角・半角変換を行う関数

こちらの記事を読んで、

https://qiita.com/asakunotomohiro/items/3d9eb8d4ed39e1128dbd

以前私が作った以下のVBScript用の関数をJavaScriptに移植してみた

https://qiita.com/takahasinaoki/items/8e57b58e634a11c1a080


```javascript
/**
 * 全角カタカナを半角カタカナに変換する
 * @param {string} text - 変換対象文字列
 * @returns {string} - 変換後文字列
 */
 function zenKana2HanKana(text) {
  let result = "";
  for (let i = 0; i < text.length; i++) {
    const newChar = (char) => {
      const ZENKANA = "、。「」ー・゜゛アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ";
      const HANKANA = "､｡｢｣ｰ･ﾟﾞｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜｦﾝｧｨｩｪｫｬｭｮｯ";
      const ZENKANA2 = "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ";
      const HANKANA2 = "ｳﾞｶﾞｷﾞｸﾞｹﾞｺﾞｻﾞｼﾞｽﾞｾﾞｿﾞﾀﾞﾁﾞﾂﾞﾃﾞﾄﾞﾊﾞﾋﾞﾌﾞﾍﾞﾎﾞﾊﾟﾋﾟﾌﾟﾍﾟﾎﾟ";
      const x2 = ZENKANA2.indexOf(char);
      if (x2 >= 0) {
        // 例: ガ→ｶﾞ
        return HANKANA2.slice(x2 * 2, x2 * 2 + 2);
      }
      const x1 = ZENKANA.indexOf(char);
      if (x1 >= 0) {
        // 例: ア→ｱ
        return HANKANA.charAt(x1);
      }
      return char;
    }
    result += newChar(text[i]);
  }
  return result;
}

/**
 * 半角カタカナを全角カタカナに変換する
 * @param {string} text - 変換対象文字列
 * @returns {string} - 変換後文字列
 */
 function hanKana2ZenKana(text) {
  let result = "";
  for (let i = 0; i < text.length; i++) {
    const newChar = (char) => {
      const ZENKANA = "、。「」ー・゜゛アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ";
      const HANKANA = "､｡｢｣ｰ･ﾟﾞｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜｦﾝｧｨｩｪｫｬｭｮｯ";
      const ZENKANA2 = "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ";
      const HANKANA2 = "ｳﾞｶﾞｷﾞｸﾞｹﾞｺﾞｻﾞｼﾞｽﾞｾﾞｿﾞﾀﾞﾁﾞﾂﾞﾃﾞﾄﾞﾊﾞﾋﾞﾌﾞﾍﾞﾎﾞﾊﾟﾋﾟﾌﾟﾍﾟﾎﾟ";
      const x2 = HANKANA2.indexOf(char);
      // 偶数の時
      if (x2 >= 0 && x2 % 2 === 0) {
        i++; // 濁点分1文字進める
        // 例: ｶﾞ→ガ
        return ZENKANA2.charAt(x2 / 2);
      }
      const x1 = HANKANA.indexOf(char[0]);
      if (x1 >= 0) {
        // 例: ｱ→ア
        return ZENKANA.charAt(x1);
      }
      return char[0];
    }
    result += newChar(text[i] + text[i + 1]);
  }
  return result;
}
```