OmniAICreator/Qiita-1.07M huggingface dataset:
Vue.js入門　6.5　単一コンポーネントの動作

# はじめに

Vue.jsを学習するにあたり、以下の本を順番に進めています。

[技術評論社　「Vue.js入門 基礎から実践アプリケーション開発まで」(ISBN978-4-297-10091-9)](https://gihyo.jp/book/2018/978-4-297-10091-9)

https://gihyo.jp/book/2018/978-4-297-10091-9


# 古いツールなので動かない

第6章からおそらく、Vueを使う最大の利点である単一コンポーネントに触れていくのですが、VueCLIツールがその通り動いてくれないのです。

VueCLIは、基本的にVue2.0時代のツールで、メンテナンスモードになっています。つまり、これからは使わないでねということですね。

https://cli.vuejs.org/

今時はVue3.0で、Viteというツールを使うようです。

https://ja.vitejs.dev/

このツールは、Vue3以降の対応のため、使えません。


本書では、さらにVueCLIのバージョン指定が古くなっています。この通りのバージョンを入れておきます。
``` shell
@vue/cli@3.0.1 @vue/cli-service-global@3.0.1
```

## 問題となった個所

P.206のサンプルVueファイルを起動するコマンド
```shell
vue serve hello.vue --open
```
これをそのまま実行するとcompilerがないので止まってしまいます。

。。。困った。

## 解決策

しかし、プロジェクトから作っていくのが普通らしいです。
そこで、
```shell
sudo vue create <project name>
```

選択肢が出るので、今回は２番目のVue 2を選択
```shell
Vue CLI v3.0.1
? Please pick a preset: (Use arrow keys)
❯ Default ([Vue 3] babel, eslint) 
  Default ([Vue 2] babel, eslint) 
  Manually select features 
```

プロジェクトのひな型を作ってくれます。
```shell
✨  Creating project in /プロジェクトフォルダ名.
🗃  Initializing git repository...
⚙️  Installing CLI plugins. This might take a while...

(######⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂⠂) ⠋ idealTree:esrecurse: timing idealTree:node_modules/esrecurse Completed in 1ms
```


作成されるプロジェクトフォルダのツリー
```
./hello
├── README.md
├── babel.config.js
├── jsconfig.json
├── node_modules
│   ├── (any package folder)
│   │
│
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   └── index.html
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── components
│   │   └── HelloWorld.vue
│   └── main.js
└── vue.config.js

1297 directories, 3373 files

```

ここで、src内のApp.vueを編集します。
編集したらビルドする必要があります。
```shell
cd ./hello
sudo npm run build
```

起動
```
sudo npm run serve
```

これで進めていくことができます。

## 不思議なことに...

プロジェクトファイルが生成された後からは、以下のコマンドで起動します。
```
sudo vue serve ./src/App.vue --open
```
なお、@vue/cliのバージョンが違うと、また別の挙動になるので、素直に本の通りのバージョンで進めます。
【Atcoder】L - Deque【DP まとめコンテスト】

# Atcoder DP - L : Deque

問題 : https://atcoder.jp/contests/dp/tasks/dp_l

# 結論

`dp[left][right]` := 区間`Points[left, right)`を渡された先手のスコア

```python
def getInt():
    return int(input())

def getIntsArray():
    return [int(x) for x in input().split()]

N = getInt()
Points = getIntsArray()
INF = float("inf")

dp = [[0 if left >= right else -INF for right in range(N + 1)] for left in range(N + 1)]

for length in range(1, N + 1):
    # 0 <= left <= N - lenght
    for left in range(N - length + 1):
        right = left + length
        if left + 1 <= N - 1:
            dp[left][right] = max(dp[left][right], Points[left] - dp[left + 1][right])
        if right - 1 <= N:
            dp[left][right] = max(
                dp[left][right], Points[right - 1] - dp[left][right - 1]
            )

print(dp[0][N])
```

# 思考順序

## 愚直な実装

愚直に実装してみましょう。タイトルにあるようにdeque構造から取り出して評価していきます。

```python
def solve(n, points):
    dq = deque(points)
    scores = []
    while dq:
        left = dq[0]
        right = dq[-1]
        if left < right:
            scores.append(dq.pop())
        else:
            scores.append(dq.popleft())
				# このあとにscoresを先手後手に分ける
```

ここで手が止まりました。

left = rightであるときの処理が再帰的になるからです。

left = rightのとき、どちらをとってもよいということにはなりません。

ex) (1,2,3,1)というポイントの並びのとき
最初のプレイヤーは相手に3を取らせないために左の1を取るべきです。

つまり、内側の要素の大小比較をしなくてはいけません。計算量もさることながら、処理が面倒なのでやめましょう。

## 並びで先手のスコアは決まってる

ここで注目するのは、並びで先手のスコアが一意に決定することです。

例えば(1,2,3)であれば2ですし、(2,3,1)ならば0です。

これがわかっていると、(1,2,3,1)で最初にどちらを取るかは簡単です。後手のスコアが悪くなる(2,3,1)になるようにとればよいのです。

`dp[left][right]` := ポイント配列のうち、区間`[left, right)`を渡された先手のスコア
と定義して動的計画法を考えます。

## 漸化式

遷移は簡単です。

左から取るか、右から取るかです。

dp配列は先手のスコアを示しているので、取ったポイントから、残りの配列で後手が取るスコアを引いてやればよいとなります。

```python
dp[left][right] = max(points[left] - dp[left+1][right], points[right-1] - dp[left][right-1])
```

## ボトムアップで処理をする

では、どこからdpテーブルを埋めていくべきでしょうか？

注目するのは区間の長さです。区間が短いところからスコアの計算ができます。

あとは左端の`left`をループさせます。`right`は`left`と`length`で表現できます。

```python
for length in range(1, N + 1):
    # 0 <= left <= N - lenght
    for left in range(N - length + 1):
        right = left + length
```

### leftの範囲

leftにかかる制限は

- 0 ≤ left ≤ N-1
- 1 ≤ right ≤ N

です。これを整理すると`0 ≤ left ≤ N - length`となります。

### 初期化

ここが一番苦労しました。

このテーブルではleft ≥ rightとなる区間は空の区間になってしまうため、スコアを0として扱えばよいですね。

結局求めたいのは以下のようなテーブルです。

```python
[0, 10, 70, 20, 10]
[0, 0, 80, 10, 20]
[0, 0, 0, 90, 60]
[0, 0, 0, 0, 30]
[0, 0, 0, 0, 0]
```

対角線を挟んで上側だけ-infで初期化します
```python
dp = [[0 if left >= right else -INF for right in range(N + 1)] for left in range(N + 1)]
```
論理削除がダメな理由は漏れるリスクが半端なくでかいから

論理削除がアンチパターンとして語られているが、決して浸透してるとはいいがたい。

そこで論理削除がダメな理由の上位２点を挙げる。

## 1.漏れるリスク V.S. 失くすリスク

情報システムが管理する情報って、「失くしちゃダメ」の他に「漏らしちゃダメ」というのもある。消したはずの情報が見えちゃうというのが被害としては大きい。削除フラグを付けたシステムは削除フラグを常に気を配らないとうっかりすると消したはずのデータが見えちゃう。プログラムとしてはちょっとしたミスにしか感じないが、情報システムで「漏れる」というミスは「失う」よりも大きい。

## 2. 更新だって不可逆だ

「削除という不可逆なオペレーションで復活できないなんてけしからん！」というのが削除フラグの背景として上げてる人もみるが、更新だって不可逆だ。絡む単位では情報が消えている。バックアップから戻してもよし。何かしらのログからペタペタ戻してもよし。

## 3.本当にオペレーションミスを防ぎたいなら「削除まちステータス」

削除フラグはダメだけどステータスというフィールドはあり。Gmailなら「アーカイブ」というステータスで「受信箱からは消えるけどデータは残ってる」ということをユーザにも理解してもらう。これは削除ではない。さらにゴミ箱というステータスもある。つまり「削除まち」ステータス。時間差で物理削除する。

企業版のGmailにはGoogle Vaultという機能で監査が可能。ログとして全ての操作が追記される仕組み。ほら削除フラグなんて登場しなくてもまぁまぁの情報システムは構築できるし、そっちの方が安全。
【AWS RDS】RDSの冗長化構成

## 内容

RDSの冗長化構成時に取る手順を以下にまとめる。

## 目次
- [RDSの冗長化構成手段](#rdsの冗長化構成手段)
- [Auroraではない場合の設定](#auroraではない場合の設定)
- [Auroraの場合の設定](#auroraの場合の設定)

## RDSの冗長化構成手段

RDSの冗長化の手段には以下の２つがある。

- マルチAZ構成
- リードレプリカ

### マルチAZ構成

RDSインスタンスを複数のAZに配置することで、どれか１つのAZに障害が発生してもシステムの利用を継続できる「高可用性」を実現するための手段。
データは同期的に複製される。

### リードレプリカ

「データ読み取り専用」のRDSインスタンスを作成することで、「拡張性」を実現するための手段。
AWS公式によると「RDS リードレプリカは、マルチAZ配置を補完する」とあり、リードレプリカでも「高可用性」の実現は可能。
データは非同期的に複製される。

## Auroraではない場合の設定

### マルチAZ

マルチAZ構成にするかどうかは、RDS新規作成時の設定項目で設定ができる。

- RDSコンソール > 右上「データベースの作成」 > 「可用性と耐久性」項目
![スクリーンショット 2023-08-03 14.36.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/d7a4a17b-e3f9-7ff5-423c-0c4fa2d60c5c.png)


### リードレプリカ

RDSインスタンス作成後、データベース > アクション > リードレプリカの作成 より作成。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/1d0b608b-1234-1240-987d-39419db49651.png)


## Auroraの場合の設定

Auroraを利用する場合は、DBクラスターという単位で取り扱う。
また、プライマリーとなるDBインスタンスを作成後、最大15個の読み取り専用Auroraレプリカを作成することができる。
Auroraレプリカはリーダーインスタンスとも呼ばれる。

### Auroraの場合マルチAZはあまり考えなくて良い

Auroraの耐久性、可用性は以下
- 耐久性
    - プライマリーインスタンスのみでもデータを３つのAZにかけて６個のレプリケーション作成
- 可用性
    - プライマリーインスタンスのみの場合は10分未満でサービスが回復

耐久性はプライマリーインスタンスのみでも高い水準。
可用性は10分未満となり、マルチAZ構成と比較すると時間がかかるが、オンプレで予備機を待機させているのと同じ状況と言える。
またRDS for MySQLのフェイルオーバー先はスタンバイ機（使用できない）が、Auroraの場合はレプリカ（使用できる）なので、トータル台数はAuroraのほうが少ないのでコスト効率が良い。

したがってAuroraの場合はレプリカ作成の手順を取る。

### Auroraレプリカの作成

- RDS > データベース > 対象のクラスターを選択 > アクション > リーダーの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/6fc55908-8290-1fc0-912a-566a4b1b7b05.png)


- 設定項目の入力
AZはプライマリーと異なるAZを選択しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/4f23c635-31e5-039d-294b-2e26896a32dd.png)

これでAroraレプリカの作成完了。
2つの封筒問題（金額仮定版）の誤った解法

## 前提

以下を読んでいることを想定

https://qiita.com/mogamoga1337/items/be9c610f778dda223138

## よく見かける解法（誤り）

```math
(選択した封筒, もう片方の封筒) = (x, \frac{x}{2}), \: (x, 2x)
```
ではなく、
```math
(選択した封筒, もう片方の封筒) = (x, 2x), \: (2x, x)
```
が正しい。
このとき交換前と交換後で期待値は1.5xになり、パラドックスは発生しない。

## おかしい点

封筒の中身を確認しているなら値はひとつに確定しているはずだが、
この解法では何故か選択した封筒の値がxと2xの2つ存在している。
これは明らかに矛盾している。

```math
\begin{align}
&(選択した封筒, もう片方の封筒) = (x, 2x), \: (2x, x) \\
&\Rightarrow 選択した封筒 = x, 2x
\end{align}
```

$x = 0$の場合はひとつの値になるが、両方の期待値が0になるのが自明なのでどうでもいい。

## 参考

http://the-apon.com/coffeedonuts/envelopesomajinaiking.html

また、YouTubeで「2つの封筒問題」「two envelopes problem」でググるとこの解法を使った説明動画がそこそこの割合で出る。嘆かわしい。
youtube字幕入力をサポートするプラグインを作成しました。

# はじめに
youtubeの字幕入力エディターを使ってみて、わかったことは、字幕の作成は、結構、大変な作業だということです。テレビや、映画の字幕を製作している現場はかなり、大変な重労働なのかなと、思ったりしました。
youtubeでは、音声を字幕に落としている動画もありますが、これだと、自動変換ツールで苦労なく作成できるかと思いますが、ここでは、すでにある動画に字幕をいれることを想定しています。
## 字幕入力ポップ画面
![字幕入力ポップ画面](https://service-tag.tecoyan.net/images/字幕.png)
この「ポップ画面」は、youtubeプレーヤーの再生、一時停止ボタンをクリックすると
表示されます。

# youtubeの字幕ツールを使ってみて
まず、最初に気づいたことは、時刻の設定です。これが意外に面倒で、字幕が多い場合は、滅入ってしまいます。スタートとエンドの設定を間違えるとエラーになります。
字幕メッセージの入力に関しては特に、気になりませんでした。
動画を再生しながら、一時停止して字幕を入力する作業が大変です。
これらの大変さを少しでも解消したくて、このプラグインを作成しました。

# プラグインの特長
## 特長1
このプラグインは、動画の再生、一時停止ボタンを使って、字幕入力を行います。
動画を再生して、ここで、字幕を入れたいと思ったら、一時停止します。youtubeのこのボタンはトグルになっていて、押すたびに再生と一時停止が切り替ります。
その時に、同時に、字幕入力ポップ画面を表示します。ポップ画面には、時刻と字幕入力フィールドが表示されます。この特長の一つは、時刻の設定が、自動で、表示されることです。いちいち、入力する手間を省いています。時刻は、一時停止した時刻が自動的にセットされます。また、終了時刻も、自動で、停止した時刻にプラス1分した時刻がセットされます。この機能で、時刻の設定作業が必要なくなります。実は、この作業が一番大変だったので、このプラグインを開発しました。
## 特長2
つぎの特長は、再生、一時停止を繰り返し、入力した字幕データは、サーバーに保存されますが、そのデータをyoutubeの字幕データ形式に変換した字幕ファイルを作成します。
ここでは、.sbv形式を使います。
その変換したファイルは、のちに、youtubeツールでファイルのアップロードで使用するため、ローカルのPCへ保存します。これらの処理を「アップロードファイル作成」ボタンで行います。
以上が、このプラグインの特長になります。

# このプラグインの使い方
このプラグインは、先に、動画をyoutubeへアップロードしておきます。この時は、まだ、字幕は入っていません。つぎから、字幕の入力方法についての手順を示します。、
■(1)当然ですが、先に、プラグインをインストールしておいてください。(近日中に公開予定)
■(2)youtube再生ページで、字幕を設定する対象の動画を開きます。 
■(3)動画の再生がスタートすると同時に、サムネイルプレーヤーが表示されますが、ここで、非表示ボタンか、Ctrl+Zキーを押すと非表示にできます。
■(4)字幕を入れいたところに来たら、一時停止します。すると、字幕入力のポップ画面が
表示されます。
■(5)その時、自動で開始と終了の時刻がセットされます。終了時刻は、開始から1分になります。
(6)字幕を入力して、OKボタンを押します。そこで、サーバに保存されます。
(7)この繰り返し((4),(5),(6))を行います。
(8)終了したら、「アップロードファイルの作成」ボタンをクリックします。
(9)ローカルPCのフォルダーへ保存するダイヤログが表示されますので、ファイル名をセットして保存します。
(10)youtubeの字幕入力画面にある「ファイルのアップロード」で、今のファイルをアップロードすると、字幕が更新されます。

# その他
このプラグインは、「サムネイルプレーヤープラグインv5.0」で、リリース予定です。
youtubeページで再生しながら、字幕を入力でき、終了後は、ファイルのアップロードで作成した字幕ファイルをyoutubeへアップします。
## アップロードファイルでの修正
ローカルPCへ保存した「アップロードファイル」で、修正することもできます。
単なるテキストファイルのため、メモ帳などのエディターで編集ができます。
ただし、字幕形式がありますので、気を付けてください。この場合は、.sbv形式になります。
以下は、アップロードファイルの内容です。時刻の設定箇所の形式に注意してください。

![アップロードファイル形式](https://service-tag.tecoyan.net/images/アップロード.png)



時刻の設定が楽になりますので、今、しばらくお待ちください。


# 終わりに
公開は、近日を予定しています。
CostExplorerでパブリックIPv4アドレスの費用を試算してみた

# はじめに
[前回の記事](https://qiita.com/ksaga9/items/3b87fae46f8ff13fd3aa)と関連したものです。

[AWS におけるパブリック IPv4 アドレスの使用状況の特定と最適化](https://aws.amazon.com/jp/blogs/news/identify-and-optimize-public-ipv4-address-usage-on-aws/)でアナウンスされているAWSにおけるパブリックIPv4アドレスの料金改定の影響調査を行っています。
前回はIPAMを利用して関連するIPアドレス等のリソースを確認しましたが、Cost Explorerでも費用を試算できそうだったので、やってみました。
その手順を記録のために残します。

というか、試算だけだったらIPAMなど使わずCostExplorerだけで確認できそうでした…。

# 使用タイプの追加
上記ブログには、以下のように書かれています。

>本日より、デフォルトで、Cost and Usage Report (CUR) には、使用中のパブリックIPv4アドレスとアイドル状態のパブリックIPv4アドレスの両方に関連する包括的な使用状況データが含まれます

ということで、投稿日以降はCURにパブリックIPv4アドレスのデータが含まれるようになったようです。
まず、Cost Explorerで確認してみました、
**使用タイプ**のフィルターで確認してみると、 `PublicIPv4:IdleAddress` と `PublicIPv4:InUseAddress` が追加されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328969/ff7872aa-50f6-60d2-4c05-73f3d1c385b5.png)

なお、 当環境のCost Explorerでは7月5日のデータから反映されているようです。
追加された使用タイプでフィルターしてみます。

![スクリーンショット 2023-08-02 18.14.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328969/545290aa-0597-ccdc-9c69-8f3c099a7467.png)
コストと使用量を表示できました。
（わかりやすいようAPN1に絞ってフィルターしています。）

コストが0なのは、上記ブログにもあるとおり、
> これらの新しい使用タイプは、パブリック IPv4 関連の料金を見積もるのに役立つように、本日追加されましたが、 2024 年 2 月 1 日までは請求されません。

ということが理由のようです。
ただ、使用量が確認できますので、これが請求されるようになった場合の見積もりは可能です。

# 見積もり
上記ブログから、以下のような計算式が記載されています。

```
2024 年 2 月 1 日以降
従来のアイドル状態のパブリック IPv4 アドレスの合計使用量に対するコスト
  1つのIP x 1 時間 x $0.005/IP/時間
新しい使用中のパブリック IPv4 アドレスの合計使用量に対するコスト
  1つのIP x 1 時間 x $0.005/IP /時間
```

今回、手元の環境で確認できた7/31のデータは以下のとおりです。
```
アイドル状態のパブリック IPv4 アドレスの合計使用量: 1,704.00hrs
使用中のパブリック IPv4 アドレスの合計使用量: 33,496.32hrs
```

以下のような見積もりになります。
```
従来のアイドル状態のパブリック IPv4 アドレスの合計使用量に対するコスト
  1つのIP x 1,704.00hrs x $0.005/IP/時間 = $8.52
新しい使用中のパブリック IPv4 アドレスの合計使用量に対するコスト
  1つのIP x 33,496.32hrs x $0.005/IP /時間 = $167.4816

合計: $176.0016
```

約1日あたり`$176`ほどコストが発生する試算になりました。
アイドル状態のパブリックIPv4アドレスは既に課金対象なので、実際に増加するコストは`$167`となります。

これは直近の為替レートだと、約¥23,000/日となります。
これはインパクトがある数字になりました。

# おわりに
CURを使わずにCost Explorerで取得できる情報で見積もれたので、すぐに取り掛かることができました。
パブリックIPv4アドレスの使用を見直せるところは見直していく必要があるなと感じました。
Server ComponentsとClient Componentsの特徴をまとめたメモ書き

Server Componentsはページ全体を再レンダリングする代わりに、変更が必要な部分だけを効率的に更新することができる。

## Server Components

サーバーコンポーネントは、サーバー上でのみレンダリングされ、クライアントにはHTMLとして送信される。
 - コンポーネントは状態を持つことができない
 - データフェッチングを行ったり、サーバー上のリソースにアクセスしたりすることができる
 - ブラウザにJavaScriptを送信しないため、結果としてクライアント側のパフォーマンスが向上する

## Client Components
 - 従来のReactコンポーネントと同様に、クライアントサイドでレンダリングされ、状態を持つことができる
 - ユーザーのインタラクションに対して反応するために使用
     - 例えばクリックや入力などのユーザーイベントを処理します。

## SSR と Server Components の違い

#### SSR
 - 各リクエストでサーバー上で全体のページがレンダリングされ、HTMLがクライアントに送信される。
 - 一度ページがクライアントにロードされた後、それ以降の操作（リンククリックにより移動する等）はクライアントで処理
     - ページ全体が再度サーバー上でレンダリングされることはない。

#### Server Components
 - リクエストごとに特定のコンポーネントがサーバー上でレンダリングされる
 - その結果（生成されたHTMLではなく、特定のインストラクション）がクライアントにストリーミングされてレンダリングされる
     - クライアントサイドのJavaScriptの実行が減少してパフォーマンスが向上。
 - サーバー状態（例えば、データベースから直接データを取得するなど）にアクセス可能。これはSSRやクライアントサイドレンダリングのコンポーネントでは困難。

## Server Componentsのクライアントへのストリーミングとは
 - データがリアルタイムでクライアントに送信され、到着と同時に処理が始まることを指す。
 - サーバーコンポーネントがレンダリングされると、その結果がクライアントにストリーミングされる。
 - クライアントはサーバーからデータを待つことなく、到着したデータからすぐにレンダリングを開始できる
     - ユーザーが低速のネットワーク接続を使用している場合に有用
     - 初回レンダリング時間が大幅に削減される


https://nextjs.org/blog/next-13-4

次は動きも試していく
MVVMについて


　MVVMはソフトウェアを分割管理する方法です。

MVVMの目的は２つあります。

・UI分離（プレゼンテーションとドメインの分離）

　UIに関係ある部分
　UIに関係ない部分

　を分離する

・表示と表示データロジックの分離(Viewと状態の分離）

　UI表示は表示だけを担当
　表示するデータとロジックはUIデータロジック
　
　として分離する。


# 考え方１

ソフトウェアを

UI　と　UI以外 に分離する。

UI　を　UI表示　と　UIデータロジック　に分離する。

UI表示を　View
UIデータロジックを　ViewModel
UI以外を　Model

と呼びます。

上記の方針で分離したので、

Viewにはデータロジックはない。
ViewModelにUIのためのデータロジックはある。
ModelにはUIの関心事は存在しない。


# 考え方2

ソフトウェアをUI表示とビジネスロジックに分ける。

ビジネスロジックをUIロジックとドメインロジックにわける。

ソフトウェア　＝ UI表示　＋　UIロジック　＋　ドメインロジック

UI表示：View
UIロジック：ViewModel
ドメインロジック:　Model

Viewにはデータとロジックはない。
ViewModelに表示データとUIロジックはある。
ModelにはUIロジックはない。



# 依存方向

ViewはViewModelとやり取りを行い。
ViewModelはModelとやり取りを行い。
ViewとModelは直接やり取りを行わない。

View　->　ViewModel　->　Model　

の方向に依存する。逆の依存はない。

ViewはViewModelにアクセス可能
ViewModelからViewはアクセスできない。

ViewModelはModelにアクセス可能
ModelからViewModelにはアクセスできない。




# データバインディングについて

Viewの表示データをViewModelに保持して
Viewはデータバインディングを使用して表示を行う。
データバインディングはMVVM外のフレームワークが実行している。
(WPFの場合はWPFフレームワーク）

データバインディングはMVVMの本質ではない。実装の一手段にすぎない。
データバインディングの代わりにRxを使用する実装もある。
PyTorchでCUDAを使用する際の注意点（備忘録）

PyTorchでCUDAを使用したい！と思っていろいろ調べてみるが、どれも肝心な部分が「分かっている」前提で書かれていて役に立たない。
なので結局自分で試行錯誤してあれやこれややってみることになるのだが、どうやってもコンピュータちゃんがGPUを使ってくれない。。。
完全に積んだと思っていたのだが、やけくそでガチャガチャしていたら偶然使えるようになったのでここに備忘録として書きなぐっていこうと思う。
***
まず、PyTorchでCUDAを使用する際の参考サイトの例としては以下がある。
https://qiita.com/motoyuki1963/items/a334c9488c2f55a867cf
https://happy-shibusawake.com/windows_cuda-pytorch/909/
https://koubou-rei.com/entry/cuda_cudnn

基本的にはこれの通りやればいいのだが、**めちゃくちゃ重要な点**が抜け落ちているので追記する。

# グラボのCUDAバージョンを確認しろ！
コマンドプロンプトで`nvidia-smi`と打つとコンピュータに搭載されてるNVIDIAグラボの詳細情報が表示される。
```python:以下は例
> nvidia-smi
Thu Aug  10 11:45:14 1919       
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 536.67                 Driver Version: 536.67       CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                     TCC/WDDM  | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA GeForce GTX 1660 ...  WDDM  | 00000000:01:00.0  On |                  N/A |
| 38%   39C    P8              15W / 125W |    725MiB /  6144MiB |      5%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
~~省略~~
```

確認する箇所は`CUDA Version:`の項目

ここに記載のVersionにあったCUDA Toolkitを入れる必要がある。(これに気付くのに３日かかった...)

この場合は`12.2`なのでver12.2のやつを入れる。
＞12.2のDL↓
https://developer.nvidia.com/cuda-downloads

あとは上のサイトの通りにやって`print(torch.cuda.is_available())`で`True`が出ればOK
【PDF印刷】html2canvasとjsPDFでの複数ページ印刷時にautoTableを導入した話

# はじめに

「印刷」ボタンクリックでテーブルをPDF出力する機能を作ることになりました。
今回導入したautoTableに関する日本語のドキュメントが少なかったこともあり、
結構な時間試行錯誤したので、記録しておきます。

# 本題
## html2canvasとjsPDFだけでは複数ページに渡るテーブルの印刷はうまくいかなかった

このテーブル、ユーザ入力により行数が変動するので少ない時は
印刷時に１ページに収まってくれるのですが、多い時は2ページ以上になります。
この時、これらのライブラリだけだとどう頑張っても表示崩れが起きてしまいました。
表示崩れの調整で各種ドキュメントやstackoverflowなどを眺め、
試行錯誤していたら丸1日経過していました。
その上うまくいきませんでした。

## 試行錯誤の結果：autoTable導入
調査する中で知った[autoTable](https://github.com/simonbengtsson/jsPDF-AutoTable)という、テーブル描画に特化した
jsPDFのプラグインを導入してみることにしました。
すると少ないコード量で、美しいテーブルが印刷されたではありませんか。
（以下サイトより引用）

>This jsPDF plugin adds the ability to generate PDF tables either by parsing HTML tables or by using Javascript data directly. 

## 導入前後で変わったコードの量

これが（長いしうまくいかないやつ）↓

```javascript:qiita.js

  $(".print-btn").click(() => {
    screenshot(document.getElementById("print-area")).then((canvas) => {
        window.jsPDF = window.jspdf.jsPDF;
        var pdf = new jsPDF("p", "mm", "a4");
        var imgData = canvas.toDataURL("image/png");
        var imgWidth = 210;
        var pageHeight = 297;
        var imgHeight = (canvas.height * imgWidth);
        var heightLeft = imgHeight;
        position = heightLeft - imgHeight + 10;
        pdf.addImage(imgData, "PNG", 10, position, imgWidth, imgHeight);
        heightLeft -= pageHeight;

        while (heightLeft >= 0) {
            position += heightLeft - imgHeight;
            pdf.addPage();
            pdf.addImage(imgData, "PNG", 10, position, imgWidth, imgHeight);
            heightLeft -= pageHeight;
        }
        pdf.save("fileName.pdf");
    });
});

function screenshot(element, options) {
    let cropper = pdfument.createElement("canvas").getContext("2d");
    //　（中略）
    return html2canvas(element, options).then(function (c) {
        cropper.canvas.width = finalWidth;
        cropper.canvas.height = finalHeight;
        cropper.drawImage(c, -(+options.x || 0), -(+options.y || 0));
        return cropper.canvas;
    });
}
```

こうなりました。↓

```javascript:qiita2.js

$(".print-btn").click(function () {
    window.jsPDF = window.jspdf.jsPDF;
    var pdf = new jsPDF("p", "pt", "a4");
    pdf.autoTable({ // autoTable導入
        theme: "striped", // striped, gridなどから選択
        html: "#pdf-table",
        styles: {
            font: "Aフォント", // 任意のフォントファイルをjsに変換後使用
            fontStyle: "normal",
            fontSize: 10,
        },
    });
    pdf.save("fileName.pdf");
});
```

## 最後に

以上です。相当久しぶりに記事を書いて楽しかったけれど、アウトプットって難しい。
需要があれば日本語フォントの導入方法詳細やHTML側のソースも追記したいと思います。
お気軽にご指摘やコメントいただけたら幸いです。
また書けたらいいな。

#### 余談：元々候補だったライブラリたち
|  ライブラリ | ざっくり調べたこと |
|:-:|:-:|
| laravel-dompdf  | CSS対応が微妙  |
| laravel-snappy   |CSS対応はいい感じだが導入が大変<br>（※大変かどうかは未検証なので不明）   |
| ブラウザの印刷機能  |  簡単だけどブラウザによって表示崩れが起きそう |


色々と良し悪しあるのですが、、
ブラウザによらず、確実にこちらが意図したレイアウトで印刷できるのは
html2canvasとjsPDFの併用っぽい、ということで頑張ってみることになりました。
なお、今回はいずれのライブラリもCDNで導入しました。
xfs_info, xfs_fsr

```
[linuxstudy@xxxx ~]$ xfs_info /dev/sda1
meta-data=/dev/sda1              isize=512    agcount=4, agsize=65536 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=0 spinodes=0
data     =                       bsize=4096   blocks=262144, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal               bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[linuxstudy@xxxx ~]$ sudo xfs_fsr /dev/sda1    //デフラグ
[sudo] linuxstudy のパスワード:
/boot start inode=0
```
```
xfs_fsr(8)                          System Manager's Manual                          xfs_fsr(8)

NAME
       xfs_fsr - filesystem reorganizer for XFS

SYNOPSIS
       xfs_fsr [-vdg] [-t seconds] [-p passes] [-f leftoff] [-m mtab]
       xfs_fsr [-vdg] [xfsdev | file] ...
       xfs_fsr -V

DESCRIPTION
       xfs_fsr is applicable only to XFS filesystems.

       xfs_fsr  improves the organization of mounted filesystems.  The reorganization algorithm
       operates on one file at a time, compacting or otherwise improving the layout of the file
       extents (contiguous blocks of file data).

       The following options are accepted by xfs_fsr.  The -m, -t, and -f options have no mean‐
       ing if any filesystems or files are specified on the command line.

       -m mtab      Use this file for the list of filesystems to reorganize.  The default is to
```
備忘録：Nuitka

https://github.com/Nuitka/Nuitka

https://blog.tsukumijima.net/article/python-nuitka-usage/

https://qiita.com/yulily/items/b97dc34615eac2be7157

https://www.idnet.co.jp/column/page_245.html

https://pisuke-code.com/python-convert-to-exe-by-nuitka/#Nuitka_--plugin-enable_exe

https://github.com/Nuitka/Nuitka/issues/1025
mke2fs

```
MKE2FS(8)                           System Manager's Manual                           MKE2FS(8)

NAME
       mke2fs - create an ext2/ext3/ext4 filesystem

SYNOPSIS
       mke2fs  [  -c | -l filename ] [ -b block-size ] [ -D ] [ -f fragment-size ] [ -g blocks-
       per-group ] [ -G number-of-groups ] [ -i bytes-per-inode ] [ -I inode-size ] [ -j ] [ -J
       journal-options  ] [ -N number-of-inodes ] [ -n ] [ -m reserved-blocks-percentage ] [ -o
       creator-os ] [ -O feature[,...]  ] [ -q ] [ -r fs-revision-level ] [ -E extended-options
       ]  [ -v ] [ -F ] [ -L volume-label ] [ -M last-mounted-directory ] [ -S ] [ -t fs-type ]
       [ -T usage-type ] [ -U UUID ] [ -V ] device [ blocks-count ]

       mke2fs -O journal_dev [ -b block-size ] [ -L volume-label ] [ -n ] [ -q ] [ -v ]  exter‐
       nal-journal [ blocks-count ]

DESCRIPTION
       mke2fs is used to create an ext2, ext3, or ext4 filesystem, usually in a disk partition.
       device is the special file corresponding to the device (e.g /dev/hdXX).  blocks-count is
       the  number  of blocks on the device.  If omitted, mke2fs automagically figures the file
       system size.  If called as mkfs.ext3 a journal is created as if the -j option was speci‐
       fied.

       The  defaults  of  the parameters for the newly created filesystem, if not overridden by
       the options listed below, are controlled by  the  /etc/mke2fs.conf  configuration  file.
       See the mke2fs.conf(5) manual page for more details.

OPTIONS
       -b block-size
              Specify  the size of blocks in bytes.  Valid block-size values are 1024, 2048 and
              4096 bytes per block.  If omitted, block-size is heuristically determined by  the
              filesystem size and the expected usage of the filesystem (see the -T option).  If
              block-size is preceded by a negative sign ('-'), then mke2fs will use  heuristics
```
gdisk

```
[linuxstudy@xxxx ~]$ sudo gdisk
[sudo] linuxstudy のパスワード:
GPT fdisk (gdisk) version 0.8.10

Type device filename, or press <Enter> to exit: /dev/sda 
Partition table scan:
  MBR: MBR only
  BSD: not present
  APM: not present
  GPT: not present


***************************************************************
Found invalid GPT and valid MBR; converting MBR to GPT format
in memory. THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by
typing 'q' if you don't want to convert your MBR partitions
to GPT format!
***************************************************************


Warning! Secondary partition table overlaps the last partition by
33 blocks!
You will need to delete this partition or resize it in another utility.

Command (? for help): ?
b	back up GPT data to a file
c	change a partition's name
d	delete a partition
i	show detailed information on a partition
l	list known partition types
n	add a new partition
o	create a new empty GUID partition table (GPT)
p	print the partition table
q	quit without saving changes
r	recovery and transformation options (experts only)
s	sort partitions
t	change a partition's type code
v	verify disk
w	write table to disk and exit
x	extra functionality (experts only)
?	print this menu
```
parted

```
[linuxstudy@xxxx ~]$ sudo parted
GNU Parted 3.1
/dev/sda を使用
GNU Parted へようこそ！ コマンド一覧を見るには 'help' と入力してください。
(parted) help                                                             
  align-check TYPE N            パーティション N のアライメント(TYPE: min|opt)をチェックする
  help [コマンド]               ヘルプ表示。コマンド指定でそのヘルプを表示
  mklabel,mktable ラベルの種類  新しいラベル(パーティションテーブル)を作る
  mkpart パーティションの種類 [ファイルシステムの種類] 開始 終了
        　　　　　　　　　　　　パーティションを作る
  name NUMBER 名前              パーティションに名前をつける
  print [devices|free|list,all|NUMBER]
        　　　　　　　　　　　  パーティションテーブルや、利用可能なデバイス、空き領域、
        　　　　　　　　　　　  見つかった全てのパーティション、あるいは特定のパーティションについて表示する
  quit                          プログラムを終了する
  rescue 開始 終了              開始、終了で指定した範囲付近にあるパーティションを復活させる
  
  resizepart NUMBER END                    resize partition NUMBER
  rm NUMBER                     パーティションを削除する
  select デバイス               操作するデバイスを選択
  disk_set FLAG STATE           選択したデバイスの FLAG を変更
  disk_toggle [FLAG]            選択したデバイスの FLAG の状態をトグル
  set NUMBER フラグ 状態        ファイルシステムのフラグと状態を設定する
  toggle [NUMBER [FLAG]]        パーティションのフラグの状態を反転する
  unit UNIT                     デフォルトの単位を UNIT にする
  version                       GNU Parted のバージョンと著作権情報を表示
(parted) select /dev/sda                                                  
/dev/sda を使用
(parted) version                                                          

GNU Parted 3.1

Copyright (C) 1998 - 2006 Free Software Foundation, Inc.
このプログラムは GPL に基づいたフリーソフトウェアです。
日本語訳に関しては Hiroshi Takekawa <sian@big.or.jp> までおねがいします。

本プログラムは有用とは思いますが、頒布にあたっては、
市場性及び特定目的適合性についての暗黙の保証を含めて、
いかなる保証も行ないません。詳細についてはGNU 一般公有使用許諾書をお読みください。
(parted)                                                                 
```
Hamcrestとは

### Hamcrestとは

:::note
JUnitと一緒に使われることが多い**ライブラリ**である
**テスト結果の検証（アサーション）を行うときに便利**
:::

### Hamcrestの特徴

- 独自のマッチャーを使用してテスト結果を意味のある文章で表現できる
よって**テストコードの可読性が上がりテストの意図が明確となる**

### Hamcrestのマッチャーの例

- **文字列**
```java
String actualString = "Hello, World!";
assertThat(actualString, containsString("Hello")); // actualStringに"Hello"を含むか検証
assertThat(actualString, startsWith("Hello")); // actualStringが"Hello"で始まるか検証
assertThat(actualString, endsWith("World!")); // actualStringが"World!"で終わるか検証

```
- **数値**
```java
int actualNumber = 25;
assertThat(actualNumber, greaterThan(20)); // actualNumberが20より大きいか検証
assertThat(actualNumber, lessThanOrEqualTo(35)); // actualNumberが35以下か検証

```
- **コレクション**
```java
List<String> actualList = Arrays.asList("apple", "banana", "orange");
assertThat(actualList, hasSize(3)); // actualListのサイズが3か検証
assertThat(actualList, contains("apple", "banana", "orange")); // actualListが指定した順序で要素を含むか検証
assertThat(actualList, containsInAnyOrder("banana", "orange", "apple")); // actualListが指定した順序を無視して要素を含むか検証

```
- **オブジェクトのプロパティ**
```java
class Person {
    private String name;
    private int age;

    // コンストラクタ、ゲッター、セッターなど
}

Person actualPerson = new Person("Natsu", 25);
assertThat(actualPerson, hasProperty("name", equalTo("Natsu"))); // actualPersonのnameプロパティが"Natsu"か検証
assertThat(actualPerson, hasProperty("age", greaterThan(20))); // actualPersonのageプロパティが20より大きいか検証

```
</details>
Next.jsでURL遷移を検知して特定の関数を発火させる方法



こんにちは、皆さん。今日はNext.jsでURLが変更されたときに特定の関数を発火させる方法について話します。これは、ページ遷移だけでなく、ブラウザバックの際にも発火します。 

## 目次
1. [はじめに](#はじめに)
2. [Next.jsとは](#Next.jsとは)
3. [URL遷移の検知とは](#URL遷移の検知とは)
4. [URL遷移の検知方法](#URL遷移の検知方法)
5. [URLの変更判定について](#URLの変更判定について)
6. [まとめ](#まとめ)

## はじめに
Next.jsはReactのフレームワークで、サーバーサイドレンダリングや静的サイト生成など、多くの機能を提供しています。本記事では、Next.jsの`useRouter`フックとReactの`useEffect`フックを組み合わせることで、URLの遷移を検知し、特定の関数を発火させる方法を解説します。

## Next.jsとは
Next.jsは、ReactベースのJavaScriptフレームワークで、サーバーサイドレンダリング(SSR)や静的サイト生成(SSG)など、Reactの機能をさらに強化したものです。Next.jsには独自のルーティングシステムがあり、これを利用することでURLの遷移を検知することが可能です。

## URL遷移の検知とは
ユーザーがページを移動するとき、URLが変わります。この変化を検知して、特定の関数を発火させることを考えてみましょう。例えば、ユーザーが別のページに移動したときにサイドバーを閉じるなどの処理がこれに該当します。

## URL遷移の検知方法
Next.jsの`useRouter`フックとReactの`useEffect`フックを組み合わせてURLの遷移を検知し、特定の関数を発火させる方法を見てみましょう。

```typescript
import { useEffect, useRef } from 'react';
import { useRouter } from 'next/router';

const MyComponent = () => {
  const router = useRouter();
  const previousUrlRef = useRef(router.asPath);

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      if (url !== previousUrlRef.current) {
        // URLが実際に変更された場合のみ処理を行う
        console.log('URLが変わりました:', url);
        // ここに発火させたい関数を書く

        // 現在のURLを保存
        previousUrlRef.current = url;
      }
    };

    router.events.on('routeChangeComplete', handleRouteChange);

    // コンポーネントのアンマウント時にイベントリスナーを削除する
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
    };
  }, [router]);

  return <div>Your component here</div>;
};

export default MyComponent;
```

このコードでは、`useEffect`内で`router.events.on('routeChangeComplete', handleRouteChange);`を使用してURLの変化をリッスンしています。URLが変わると`handleRouteChange`関数が呼び出され、これによりURLの変化ごとに特定の関数を実行することができます。

## URLの変更判定について
このコードにおける `useRef` と `if (url !== previousUrlRef.current)` の判定は、URLが実際に変更された場合のみ特定の処理を行うために存在します。

`useRef` は、`previousUrlRef` という参照オブジェクトを作成します。このオブジェクトは、その `current` プロパティによって直前のURL（遷移前のURL）を保持します。

```typescript
const previousUrlRef = useRef(router.asPath);
```

次に `if (url !== previousUrlRef.current)` という条件式は、新たに遷移したURL（`url`）が直前のURL（`previousUrlRef.current`）と異なる場合にのみ処理を行うことを保証します。

```typescript
if (url !== previousUrlRef.current) {
  // URLが実際に変更された場合のみ処理を行う
  console.log('URLが変わりました:', url);
  // ここに発火させたい関数を書く

  // 現在のURLを保存
  previousUrlRef.current = url;
}
```

これにより、同じURLに対して複数回発火するという状況を避けることができます。また、この判定により、実際にURLが変更されたときだけ特定の処理（この例では `console.log` とその後の関数呼び出し）を行うことができます。

## まとめ
Next.jsの`useRouter`フックとReactの`useEffect`フックを組み合わせることで、URLの遷移を検知し、特定の関数を発火させることができます。さらに、`useRef`とURLの変更判定
[Python] 曜日を番号で取得する方法

以下の３つの取得が可能
| | 関数 |
|-|-|
|月曜0始まり 日曜6終わり|weekday()|
|月曜1始まり 日曜7終わり|isoweekday() <br>strftime('%u')|
|日曜0始まり 土曜6終わり|strftime('%w')|

ただしstrftimeは文字列のため数値として使う場合は変換が必要

```Python:
import datetime

week = [datetime.datetime.strptime(f'2023/7/{i+10} 12:00:00', '%Y/%m/%d %H:%M:%S') for i in range(7)]
for day in week:
    youbi_0 = day.strftime('%a')
    youbi_1 = day.weekday()
    youbi_2 = day.isoweekday()
    youbi_3 = int(day.strftime('%w'))
    youbi_4 = int(day.strftime('%u'))
    print(f"{youbi_0}: weekday= {youbi_1}, isoweekday= {youbi_2}, strftime_%w= {youbi_3}, strftimee_%u= {youbi_4}")
```

```:出力結果
Mon: weekday= 0, isoweekday= 1, strftime_%w= 1, strftimee_%u= 1
Tue: weekday= 1, isoweekday= 2, strftime_%w= 2, strftimee_%u= 2
Wed: weekday= 2, isoweekday= 3, strftime_%w= 3, strftimee_%u= 3
Thu: weekday= 3, isoweekday= 4, strftime_%w= 4, strftimee_%u= 4
Fri: weekday= 4, isoweekday= 5, strftime_%w= 5, strftimee_%u= 5
Sat: weekday= 5, isoweekday= 6, strftime_%w= 6, strftimee_%u= 6
Sun: weekday= 6, isoweekday= 7, strftime_%w= 0, strftimee_%u= 7
```
lsscsi

```
[linuxstudy@xxxx ~]$ lsscsi
[0:0:0:0]    disk    VMware,  VMware Virtual S 1.0   /dev/sda 
[0:0:1:0]    disk    VMware,  VMware Virtual S 1.0   /dev/sdb 
[2:0:0:0]    cd/dvd  NECVMWar VMware IDE CDR10 1.00  /dev/sr0 
```
```
lsscsi(8)                                    LSSCSI                                   lsscsi(8)

NAME
       lsscsi - list SCSI devices (or hosts) and their attributes

SYNOPSIS
       lsscsi  [--classic] [--device] [--generic] [--help] [--hosts] [--kname] [--list] [--lun‐
       hex]  [--long]  [--protection]  [--protmode]  [--scsi_id]  [--size]   [--sysfsroot=PATH]
       [--transport] [--verbose] [--version] [--wwn] [H:C:T:L]

DESCRIPTION
       Uses  information  in sysfs (Linux kernel series 2.6 and later) to list SCSI devices (or
       hosts) currently attached to the system. Options can be used to control the  amount  and
       form of information provided for each device.

```
【書評】1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術

# 概要
## 書籍詳細
### タイトル
1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術
### 著者
伊藤 羊一
### 出版社
SBクリエイティブ
### 発売日
2018/3/14
### カテゴリ
ビジネススキル・プレゼンテーション
### Amazonリンク
[1分で話せ 世界のトップが絶賛した大事なことだけシンプルに伝える技術](https://amzn.asia/d/gl6AfWr)
## この書籍を読もうと思った理由
- 課題を上司やメンバーに共有するときに完結でわかりやすい説明ができるようになりたいと思ったから。
- エンジニアをしていると咄嗟に説明を求められたり、複雑な仕様を非エンジニアに説明する場面があったりと説明能力が求められるので、そういったスキルへのインプットができる著書を探していたから。
- 書籍の説明や口コミを見て一番内容が解決したい自分の課題にマッチしていると思ったから。
# 要約

## 序章　そもそも「伝える」ために考えておくべきこと
「人は、相手の話の80%は聞いていない」という前提を元に、それを乗り越えて自分の伝えたいことを伝えるには「1分で話す」「1分の話にまとめる」ことだと著者は主張する。1分で伝わらないことは何時間説明しても伝わらないともいう。またその1分の話の中に「右脳」と「左脳」それぞれに働きかけるエッセンスを組み込むことで、人を動かす話ができると説く。
## 第1章　「伝える」ための基本事項
プレゼンなど相手に何かを伝える時のゴールは「相手に動いてもらうこと」であることが多いが、実際その中身が「相手に理解してもらうこと」で止まっているケースが多々ある。「綺麗に話すこと」は全く重要ではなく、相手に「自分は何をすればいいのか」が明確に伝わるような構成を意識して話を組み立てることが重要である。
## 第2章　1分で伝える
1分で話をわかりやすく伝えるために重要なことは話の構成がてっぺんを持つピラミッド型となっていることである。またよく言われることであるが「結論を先に」はこの話の中でも当てはまる。一つの結論＝主張に対して複数の根拠があることで主張が相手に伝わりやすくなる。根拠となるデータや事例はあくまで根拠であり結論ではないので、話を聞いた相手が「結局何？」とならないようにしっかりと結論を準備する。伝わりやすくするために「基本的に」のような不要な言葉は削除すべき。また「自分が頑張ったこと」は報告で伝えたくなってしまうが主張が伝わらなくなってしまう恐れがあるため話に組み込むべきでない。
## 第3章　相手を迷子にさせないために「スッキリ・カンタン」でいこう
自分の話やプレゼンに対して聞き手に集中力を向け続けてもらうために必要なことは内容を「スッキリ・カンタン」にすることである。使う文字・言葉を多くしない、文章をややこしくしないことが重要である。そのために複雑な表はグラフに置き換える、図は状況を位置に置き換える等の工夫を凝らしスライドであれば読まずに理解できることを目指すべき。また難しい言葉は必要以上に使わず、中学生でも理解できる言葉を使用するようにするのが説明をわかりやすくするのには効果的である。
## 第4章　1分でその気になってもらう
前章まででわかりやすい説明のテクニックについて述べられていたが、ロジカルに正しいことを言っても人は動かない。左脳にロジカルに訴えかけた後に、相手に動いてもらうために右脳に訴えかけるためにはどうすればいいかを解説する。まずイメージを相手にしてもらうためになるべく言葉ではなくビジュアルにして見せるというのがある。写真・絵・動画は効果的だが、「例えば」で具体例を示すのも該当する。また話の構成をピラミッドにするにあたり、結論-根拠の下に「例えば」という形で事実を置くことで相手に訴えかけやすい話の構造になる。「想像してみてください」という文言で相手にイメージを作る時間を作ることも効果的である。
## 第5章　1分で動いてもらう
左脳で理解させて右脳にイメージさせることで、聞き手を話の中に取り込むテクニックについて解説してきたが、それだけでは相手が目的となるゴールに向けて動いてくれるにはまだ不十分である可能性がある。実際に動かすにはどうすればいいのかについて解説する。効果的な点と挙げられるのはわかりやすい「超一言」で包み込むこと。超一言とは覚えやすくその一言でプレゼン全体を表すようなキャッチーな一言だ。あとはどうやって内容をデリバリーするかについて間合いや声のトーンなどで気を付けることについて解説。また伝えるために必要であれば根回し・アフターフォロー等もすることを厭わない貪欲さが必要だと著者は説く。
## 第6章　「伝え方」のパターンを知っておこう
伝え方のフレームワークについての解説。代表的なものに以下3点がある。
- SDS
- PREP
- PCSF

SDSは「Summary（まとめ）-Detail（詳細）-Summary」で、詳細を結論で挟むフレームワーク。
PREPは「Point（主張）-Reason（根拠）-Example（例示）-Point」で、主張と根拠のピラミッドで例示も示してイメージを湧かせつつ最後主張で締めるフレームワーク。
PCSFは「Problem（問題）-Change（変化）-Solution（解決策）-Future（未来）」で、新しい革新的なことを説明するのに効果的なフレームワーク。
## 第7章　実践編
会議・プレゼン・上司への提案・取引先との商談・ファシリテーションの5つの場面でそれぞれ本書に書かれている内容を実践するにはどうすれば良いかを解説。それぞれのシチュエーションで大切になる心構えが微妙に違うのでそれについても説明している。
# 書評
## 読んだ感想
物事をシンプルに伝える、かつ「相手を動かす」ために重要なことを体系的に説明しておりわかりやすく実践しやすい内容となっていた。割と世の中的に知られたテクニックもあるが、左脳で理解させて右脳に訴えかけるという一連の流れの中でそれがどういう効果を発揮するのかが理解できるので飲み込みやすい。特に「会議ではポジションと取る」というのが印象的であった。上司や偉い方がいる会議では議題に対する自分のポジションを曖昧にしてお伺いを立てるような感じになってしまいがちであるが、会議の目的である「結論を出す」ためには自分のポジションを明確にして議論を活性化させるのが大切というのは非常に納得できた。またエンジニアだと咄嗟に説明を求められたり、複雑なシステムの仕様の説明を求められたりする場面が多々あるが、そういったシチュエーションでも実践できる内容が含まれた著書であると思ったのでエンジニアにもおすすめできる。
## おすすめできる方
- 伝わる説明ができるようになりたい方
- 完結に説明ができるようになりたい方
- プレゼン能力を上げたい方
IBM i OSをバージョンアップする際の前提PTFなど

お客様からの質問メモです。

Q. IBM i 7.3を使用している。IBM i 7.4にOSバージョンアップしたいが前提のPTFはあるか？

A. 下記URLに各IBM i バージョンの前提PTF情報があります。
IBM Support : Updates & PTFs https://www.ibm.com/support/pages/node/1115985
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/44ccb936-73dc-62d7-1eaa-54fefd1d3502.png)


上記URLからIBM i 7.4の情報を探すと、下記にリンクしています。
IBM Support : Required PTFs for Upgrading to IBM i 7.4
https://www.ibm.com/support/pages/node/3032649

上記ページに具体的な前提PTF情報が記載されています。IBM i 7.3に事前に適用する必要があるPTF番号は下記になります。（執筆時点でのPTF番号です）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/0e3ed4be-b3a1-f964-8845-621c413ba43f.png)
※適用時のスペシャルインストラクションがある場合も。必ず確認しませう・・

※また、各IBM i バージョン間での変更点は MEMO TO USERS （プログラム資料説明書）に記載があります。一覧は下記にあります。が、英語版なので個別に　プログラム資料説明書　IBM i V7.5 のように検索したほうがいいかもしれません。
IBM Support : IBM i Installation Documentation
https://www.ibm.com/support/pages/node/1115991
【Unity】Photon Fusion の Interpolation にかかる時間だけイベントの発行を遅延するクラス

# 概要

Client 側で Network Rigidbody などの Interpolation Data Source を Snapshots にすると、Interpolation Target は Collider の後ろをなぞるような挙動になります。
その状態で衝突音を実装すると、見た目より早く音が鳴ってしまいます。
この問題を解決するために、イベントの発行を Interpolation にかかる時間だけ遅らせるクラス **InterpObservableQueue** を作りました。UniRx を使っています。
不具合や改善案、「その機能もうあるよ」といったコメントをいただけると助かります。

# コード

https://github.com/yamara-mh/CodeStorage/blob/main/Codes/InterpObservableQueue.cs

# 関数説明

|関数/プロパティ|説明|
|-|-|
|InterpObservableQueue\<T>()|コンストラクタです。<br>Spawned() 上で初期化してください。<br>第二引数でイベント発行の条件を決められます。|
|Enqueue()|イベントの発行で使う引数の情報を追加します。<br>本来呼びたかった関数を実行するタイミングでこの関数を呼んでください。|
|UpdateQueues()|保持している引数情報のうち、実行可能なイベント<br>FixedUpdateNetwork() で呼んでください。|
|Observable|購読先になる Observable です。<br>Spawned() で購読し、本来呼びたかった関数を実行するなどしてください。|
|ClearQueue()|保持している引数情報を空にします。|
|Kill()|全ての変数を null または空にして、利用不能にします。|

# 利用例

衝突したコライダーの名前をログに出す例です。

``` C#
using Fusion;
using UniRx;
using UnityEngine;
using Yamara;

public class InterpObservableQueueSample : NetworkBehaviour
{
    InterpObservableQueue<Collision> onCollisionEnterQueue;

    public override void Spawned()
    {
        base.Spawned();
        var isPredicted = InterpolationDataSource == InterpolationDataSources.Predicted;
        onCollisionEnterQueue = new(Runner, isPredicted, collision => collision != null);
        onCollisionEnterQueue.Observable.Subscribe(collision => Debug.Log(collision.gameObject.name)).AddTo(this);
    }

    public override void FixedUpdateNetwork()
    {
        base.FixedUpdateNetwork();

        if (Runner.IsForward) onCollisionEnterQueue.UpdateQueues();
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (Runner.IsForward) onCollisionEnterQueue.Enqueue(collision);
    }
}

```

```if (Runner.IsForward)```は無くても一応同じように動きますが、ぱっと見で実行タイミングが分かりやすくなるので加える事を推奨します。
connect ec2 by session manager

以下の条件を満たすことが必要
1. EC2 instance IAM role: policy AmazonSSMManagedInstanceCore とAmazonSSMPatchAssociation を追加
2. EC2 instance にSystem manager agent install
   - confirm the status: sudo systemctl status amazon-ssm-agent
3. 以下のどちらか
3-1. internet accessできること：public ip + internet gateway or NAT
3-2. VPC endpoint( ssm, ssmmessages)作成
⇒endpointに付与されているsecurity groupが443 portを開放する必要


上記の通りになっているに関わらず、session manager経由での接続ができていない場合、try rebooting the EC2 instance
Lightsailを作ってみる①～インスタンスの作成

# はじめに
WordPressでのサイトを作成する必要があり、それに伴ってAWS上でLightsailでサーバーを構築してみました。
その際の手順を特に難しいところなどはないですが、メモとして残しておきます。
初めから構築の際にWordPressを選択してインストールされた状態のものが提供されるので、ブログの運用だったりと目的がはっきりしているとかそこまでの高スペックは必要ない(もちろんLightsailでも高スペックのものは高くつくが。。)などのとりあえず構築してみたいなどがあれば、こちらを選択するのもありなのかなと考えています。

# Lightsailとは(EC2との違いなど)
LightsailはEC2と異なります。
EC2は主に仮想サーバーのみを提供するのに対して、Lightsailは仮想サーバー+αの状態を作成することができます。色々違いはありますが、初期の構築時にWordPressやらRedmineを選択することができるなど用途や目的に合わせての初期構築が行えます。
料金に関してはEC2が従量課金になるのに対して、Lightsailは月額料金になったりと料金体系からも異なるところがあります。
どちらかというとEC2コンピューティングのサービスを提供するのに対して、Lightsailはコンピューティングを含めAWSのサービスを統合したものを提供するという認識をしています。

:::note  warn
細かな違いや料金については公式サイトでご確認ください。
:::

https://aws.amazon.com/jp/lightsail/features/

https://aws.amazon.com/jp/lightsail/pricing/?pg=ln&sec=hs

# Lightsailの作成
1.コンソールの検索ボックスに「Lightsail」を入力すれば、サービスに表示されるのでそちらをクリックする。
![Lightsailの構築⓪.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375141/91953195-460c-5a46-bab3-4df3cd653eed.png)



2.Lightsailのホーム画面的なものが表示されるので、「インスタンスの作成」ボタンをクリックする。
※ちなみに画像では「おはようございます」と表示されているが、昼過ぎに開いたら「こんにちは」になってました。また、画面がawsコンソールっぽくない感じになります。
![LightSailの構築①.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375141/dea9caea-699d-54ff-d97f-5ceb6bcbcce1.png)

3.「インスタンスのロケーション」、「プラットフォーム」「設計図」を選択する。
※今回はWordPressを選択していますが、OSのみも選択可能です。
![LightSailの構築②.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375141/78371270-71d1-16dd-5e5f-0d6ced5fbe2f.png)

4.「起動スクリプトの追加」、「SSHキーペア」など設定があれば追加で設定することができる。

5.「インスタンスプランの選択」で任意のスペックを選択する。
![LightSailの構築③.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375141/74f75c44-eb8f-c958-8bb2-0110ed795b8b.png)

6.「インスタンスを確認」でリソース名を入力する。タグについてもこちらで設定する。
※こちらで入力したリソース名が作成後、ホーム画面で表示されるようになる。
![LightSailの構築④.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3375141/0109af84-e377-4791-39e5-6d0a5df1044a.png)

7.「インスタンスの作成」ボタンを押下する。

8.作成に少しだけ時間がかかるが、作成完了後、Lightsailのホーム画面に作成したインスタンスが表示される。

# 終わりに
この後はRoute53でドメインを取得し、CloudFrontを設定するところまで行いたいと思っています。こちらについてもLightsail内で設定することが可能なように思えますが、Route53やらCloudFrontやらの設定をあまりやったことがないので、今後のナレッジとしてLigthsail+Route53+CloudFrontという形で今後は設定してみようと考えています。
Lightsailは画面が他のawsのサービスと少し違い、とっつきやすい？ようになっているのかなと思いまいした。
個人的には画面のレイアウトがサービスごとに違うとちょっとわかりづらい気がするので、そこまでしなくてもいいのかなとか思ってしまうところです。。。
【Xcode・Swift エラー解決】Thread 1: signal SIGABRT

## はじめに
コレクションの実装の際にエラーが発生し、解決までに時間がかかったので解決方法をメモします。

## エラーの背景
私の場合は、collectionViewCellのインスタスを生成する際に``「Thread 1: signal SIGABRT」``というエラーが発生しました。

![スクリーンショット 2023-08-03 11.12.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072069/a7df6b2f-8b96-4fc6-794e-3e08b718d63b.png)

## 原因
インスタンス化するViewの**Custom Classにクラス名が設定されていなかった**ので、インスタンス化する際にViewの認識ができず、エラーで落ちていたと考えられます。

![スクリーンショット 2023-08-03 11.23.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072069/c575182f-6336-8a6d-dc13-dee4f2248c12.png)

## 解決方法
Custom Classのclassを設定してください。

![スクリーンショット 2023-08-03 11.31.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072069/4e2378b1-05a2-b610-3189-ce32739233a6.png)

:::note warn
**「Inherit Module From Target」には必ずチェックを入れてください**
:::

## 解決できない場合
もし上の手順で解決できない場合は、ストーリーボードの接続が正しくできているかを確認してください。
以下の記事がわかりやすいと思います！

https://rightcode.co.jp/blog/information-technology/swift-thread-1-signal-sigabrt-error-cause
WindowsのSourceTreeでShift-JISのデータを扱う

出来ればUTF-8統一が良いですが、案件ごとに事情が異なるため調査しました。


# コミット前のステージングの画面での文字化けを防ぐ場合
SourceTreeのアプリケーションを落としてから開始してください。

`.gitattributes`ファイルをプロジェクト直下に配置します。
文字コードを適用したい拡張子とdiff=の後に文字コードを設定して保存します。

    *.txt diff=sjis

git bash から下記の設定を入力します。

    git config --global diff.sjis.textconv "iconv -f sjis -t utf-8"

iconvという標準の変換機能を使ってSHIFT-JISファイルを変換します。
※cp932の場合は下記も入力してください。

    git config --global diff.cp932.textconv "iconv -f cp932 -t utf-8"
#### 補足
※上記コマンド実行でユーザ配下のgitconfigに設定が記述されます。

    [diff "sjis"]
	    textconv = iconv -f sjis -t utf-8
    [diff "cp932"]
	    textconv = iconv -f cp932 -t utf-8
#### 補足2
SourceTree上でファイルをステージしたときには文字化けしなくなるのですが
ステージする前の状態だと化けてしまう可能性があります。
コミットするときは変更を追加しますし、十分差分を見るのには使えるので、困らないとは思います。

# コミット後の履歴画面での文字化けを防ぐ場合

プロジェクト直下の`.gitattributes`に下記を追記します。
別の設定と合わせて追記する場合は半角スペースを空けて末尾に追加してください。

    *.txt text working-tree-encoding=sjis diff=sjis

既にShiftJIS のファイルをコミット済みの場合は、`.gitattributes` を編集した後の場合は
下記のコマンドで一括でSHIFT-JISを修正できます。

    git add --renormalize .
#### 補足
**`working-tree-encoding`は実際のコミットしたファイルのエンコードは変わらず
内部的に設定されたエンコードで変換して表示する設定です。**
WORDPRESSシリーズ！「環境関係なくテーマやプラグインがインストールできる環境構築」

![wordpress_setting.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633992/2634c691-5c7e-48a2-df08-2ea963b77682.jpeg)

エスプリフォートでは、WORDPRESSなどオープンソースを活用した請負開発やプロダクト（自社サービス）開発を長く行っており、オープンソースのカスタマイズもしております。

今回はエスプリフォートが長年扱ってきた一つであるWORDPRESSのアドオン開発に関することをご紹介していきます。

### 最初に

初期設定ではテーマやプラグインのインストールはFTP経由でインストールする設定となっています。
しかし、レンタルサーバなどによってはFTPまたはFTPS情報を入力しても接続できない場合があります。今回は環境関係なくダイレクトファイル I/O リクエストにてインストールする設定をご紹介いたします。

#### １、「wp-config.php」に「define('FS_METHOD', 'direct');」の記述を追加します。
```php:wp-config.php
if ( !defined('ABSPATH') )
     define('ABSPATH', dirname(__FILE__) . '/'); 

define('FS_METHOD', 'direct');
```

※「FS_METHOD」の設定は下記4つの中から設定できます。
|設定 | 説明 |
|:-:|---|
|direct  |PHP からダイレクトファイル I/O リクエストの使用を強制します。デフォルトではこのオプションが選択されます。これは、適切に構成されていないホストではセキュリティの問題を引き起こすことにつながります。 |
|ssh2  |インストールされていれば SSH PHP 拡張モジュールの使用を強制します。 |
|ftpext  |FTP アクセス用 FTP PHP 拡張モジュールの使用を強制します。 |
|ftpsockets  |FTPアクセス用 PHP ソケットクラスを使用します。 |

#### ２、インストールしたWORDPRES内のディレクトリ権限を変えます。
```console
$ chmod 0707 wp-content/**** 
$ chmod 0707 wp-content/upgrade 
$ chmod 0707 wp-content/themes
$ chmod 0707 wp-content/plugins
```
#### ３、wordpressのデータをすべて、所有者とグループを apacheに変更します。
```console
$ chown -R apache:apache [WORDPRESSインストールディレクトリ]
```

### 最後に
「direct」の設定にてテーマやプラグインをインストールできるようにするのが、一番良いわけではありません。
この設定は、テーマやプラグインの取得先が適切に構成されていないホストではセキュリティの問題を引き起こすことに繋がる事もありえます。
利用用途とセキュリティを検討した上で、適切な設定をすることをお勧めいたします。

https://www.esprit-fort.co.jp/


https://www.esprit-fort.co.jp/recruit/
Python最大桁から有効数字で丸める

Pythonである数字を有効桁数で丸めたい。

round関数を用いれば、小数点ある桁で丸められるが、今回は最大桁数から動的に丸めたい

例：　有効数字3桁
0.0012344 -> 0.00123
12344000 -> 12300000
123.44 -> 123

そのための関数を作成した。

# 関数本体
```Python
import math
from typing import Union
InputType = Union(float, int, list["InputType"])
def round_sigdig(val: InputType, sigdig: int) -> InputType:
    """最大桁からある桁数で丸める関数
    Args:
        val (any):
            number or list of number or array of number
            数値もしくは数値のlistもしくは数値のarray
        sigdig (int):
            significant digits
            有効桁数
    Returns:
        any: 
            number or list (same shape of val)
            丸められた数値もしくは入力と同じ形のlist
    """
    _sigdig = sigdig - 1
    def _round_sigdig(val):
        if isinstance(val, list):
            return list(map(_round_sigdig, val))
        d = int(-(math.floor(math.log10(abs(val)))-_sigdig))
        val = round(val, d)
        if val >= 10**(_sigdig):
            return int(val)
        else:
            return val
    return _round_sigdig(val)
```

# 使用例

```Python
print(1/7, round_sigdig(1/7, 5))
# 0.14285714285714285 0.14286
```

こちらの関数はlistに対応している。
```Python
array = [0.1, 1/3, math.sqrt(2), 120.3333, 99990000, 239200000, 0.0000000001234, 3, 45.000000000123]

print(array)
print(round_sigdig(array, 3))
# [0.1, 0.3333333333333333, 1.4142135623730951, 120.3333, 99990000, 239200000, 1.234e-10, 3, 45.000000000123]
# [0.1, 0.333, 1.41, 120, 100000000, 239000000, 1.23e-10, 3, 45.0]
```

もちろん多次元配列でも対応可能
```Python
array2 = [
    [0.1, 1/3, math.sqrt(2)],
    [120.3333, 99990000, 239200000],
    [0.0000000001234, 3, 45.000000000123]
]

print(array2)
print(round_sigdig(array2, 5))
# [[0.1, 0.3333333333333333, 1.4142135623730951], [120.3333, 99990000, 239200000], [1.234e-10, 3, 45.000000000123]]
# [[0.1, 0.33333, 1.4142], [120.33, 99990000, 239200000], [1.234e-10, 3, 45.0]]
```

# 注意点
有効桁数で丸めたときに整数になる場合はint型にキャスティングしている。
あくまでround関数なので、必ずしも四捨五入ではないことに注意
dbeaverでrole does not existとエラーが出た問題 Docker Postgresql

DBeaverで接続しようとすると`role does not exist`とエラーが出て、接続できず困っていました。

Dockerでpostgresqlを使用して、そのDBを接続しようとしたら怒られた。

以下の原因を考えましたが、どれも違い途方に暮れていました。
* 認証情報が違う
* 接続先が違う
* roleが存在していない


ただ、コンテナ内で以下のようにpsqlに入り、
```
psql \
--host=localhost \
--username=hogehoge \
--dbname=hogehoge

\l
```
以下を実行するとRolenameなどが表示される。
```
\ du
```

roleが存在している...



ということは、接続先が間違っているのか？と考え、以下で接続しようとしているポートを確認すると、なんと見知らぬpostgresqlが立ち上がっていた。。。。

```
lsof -i:5432
```
https://qiita.com/kooohei/items/9e3859e3d1d854c3d163


不要なものを以下で削除したら無事接続できました。
```
kill -9 PID
もしくは
brew services stop postgresql
```

つまり、Dockerで作成してDBに接続しているつもりが、全く見知らぬいつ起動したかも覚えていないDBに接続しようとしていたというオチ。そりゃroleが存在しないよな。
PNPM バージョンアップの方法

Nodeのパッケージマネージャであるpnpmのバージョンアップの手順をまとめました。

https://twitter.com/_adamof_/status/1686911188368752641?s=20

pnpmのバージョンは頻繁に更新するものでもないかと思いますが、いざ更新するときに「どうすればいいんだ」となって、数分〜数十分取られたりするかと思います。

pnpmのインストールの経路はいくつかあって、どれを選んだかによってバージョンアップの方法も変わってきます。

ここでは汎用的(pnpmに限らず)に使えそうだなと思った手順のみ記載しました。
他の方法も知りたい方は次のGitHubのDiscussionsを参考にしてください。

[Confusing about how to update pnpm itself ](https://github.com/orgs/pnpm/discussions/4383)


## pnpmバージョンアップ手順 
```
where pnpm
```
でインストールディレクトリを確認する。
```
rm -rf インストールディレクトリ
```
で削除する。
```
curl -fsSL https://get.pnpm.io/install.sh | sh -
```
で再インストールする。
[pnpm公式インストール方法]()

## 実際のコマンド


```bash
$ where pnpm        
/usr/local/bin/pnpm
/usr/local/bin/pnpm
  
  
$ rm -rf /usr/local/bin/pnpm
 
 
$ where pnpm
pnpm not found

 
$ curl -fsSL https://get.pnpm.io/install.sh | sh -
==> Downloading pnpm binaries 8.6.11
 WARN  using --force I sure hope you know what you are doing
Appended new lines to /Users/YOU/.zshrc

Next configuration changes were made:
export PNPM_HOME="/Users/YOU/Library/pnpm"
case ":$PATH:" in
  *":$PNPM_HOME:"*) ;;
  *) export PATH="$PNPM_HOME:$PATH" ;;
esac

To start using pnpm, run:
source /Users/YOU/.zshrc

 
$ source /Users/YOU/.zshrc

$ pnpm -v
8.6.11
```

今回の手順で私の場合は問題なくpnpmが使えるようになりました。しかし、実行ファイルのディレクトリをまるごと削除する方法ですので、注意して行ってください。

以上です！
wslでelixir その28

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
websocket echo serverやってみた。
clientは、neosvrでやってみた。

# 参考にしたページ。

https://qiita.com/tamanugi/items/40c0d2daf151f7cab3e4

# 写真

![2023-08-03 01.07.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a3ad8c2c-b04f-5f41-278c-c34a90ebc63c.jpeg)

# 実行結果

```
iex(1)> ElixirSocketTesting.Server.start

```

# 実験に使ったclient

https://qiita.com/ohisama@github/items/99d65ebc8e1498ee04db


以上。