OmniAICreator/Qiita-1.07M huggingface dataset:
デザインシステムを効果的に活用するために気をつけていること

デザインシステムを取り入れている企業、組織は多いと思います。
私は、エンジニアとして、日々デザインシステムを活用しており、その中で特に重要だと感じた点について書きます。
最低限これらを遵守することで、より良いデザインシステムの活用につながると思います。

デザインシステムの詳細については、以下の記事などを参考にしてみてください。
**参考**
[デザインシステムとは？基本概念とその重要性 - ajike](https://ajike.co.jp/blog/designsystem "デザインシステムとは？基本概念とその重要性")

:::note warn
組織ごとにデザインシステムは異なります。各組織のルールに従ってご利用ください。
:::

## 1. ガイドラインを必ず読む
ガイドラインは、デザインルール、使用ルール、目的などがまとめられた重要なドキュメントです。コンポーネントの見た目だけでなく、機能や目的についても理解し、適切なコンポーネントを選択することで、ユーザビリティの向上に繋がります。
ガイドラインを読んでもわからない、記載されていない場合はデザイナーに確認しています。

## 2. コンポーネントを直接オーバーライドしない
デザインによっては、複数のコンポーネントを組み合わせて利用する必要がある場合もあります。
その際、デフォルトのスタイルを変更したい場合は、コンポーネントのクラスを直接オーバーライドするのではなく、別途クラスを作成するか、コンポーネントを`div`などで囲んでスタイルを適用します。CSSの詳細度を上げたり、`!important`は使わないようにしています。
特に、コンポーネントの構造に関わるCSSのプロパティ（display、positionなど）は、直接変更しないようにしています。
これらのプロパティを直接変更すると、コンポーネントの再利用性が損なわれ、将来的なメンテナンス性が低下します。
### 構造に関わるようなCSSの一例
* `display`
* `position`
* `float`
* `flex`, `grid`

```scss
/* NG */
.button {
  // 変更内容...
  position: absolute;
  right: 0;
}

// 詳細度をあげてオーバーライドするのもNGにしています。
.foo {
  & .button {
    // 変更内容...
    position: absolute;
    right: 0;
  }
}

/* OK */
// クラス名を用意する
.bar {
  // 変更内容...
  position: absolute;
  right: 0;
}
```
:::note
明らかにバグと判明していて、その認識がチームに共有されている場合は許可しています。
:::

## 3. 他の役割を持たせない
クラス名、変数名に目的がわかるように命名するのは主流だと思います。
上記と似ていますが、その目的以外のスタイルを持たせるべきではありません。
```scss
/* NG */
// 例） paddingを調整するクラス
.pt-20 {
  padding-top: 20px;
}

// 他の役割を持たせる
.foo {
  & .pt-20 {
    color: red;
    padding-top: 20px;
  }
}
```
## 4. Utilityクラスのみでコンポーネントを作らない
ユーティリティクラスは便利ですが、それ自体でコンポーネントを作るモノではありません。あくまでコンポーネントやレイアウトを調整するために使います。
ユーティリティクラスだけでコンポーネントを作らず、別途クラスを命名しプロジェクト用のコンポーネントとするようにしています。

## まとめ
今回書いた内容は、実際にこのような使われ方をして問題が発生したケースを参考にしています。様々なバックグラウンドを持つメンバーと協力する中で、デザインシステムの利用について、より深く理解を深めることができました。

![sample-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84446/cb5bd3e3-e8a3-e603-bfd4-49b12c05cd87.png)
LTってどうやってすればいいの？資料の準備はどうするの？発表は？（スライドモード使用）

# LTスライドの作り方

---

## Qiita!
の、スライドモードがおすすめです。
この機会にマークダウン記法を覚えて、ついでにスライドも作れるという経験を積むと「アウトプットからのLT」がスムーズになります。

---

### Qiitaスライドを作るコツ
とりあえず、`##`でタイトルつけて、一つ改行して本文を書いていけばそれっぽくなります

---

### 絵を入れたい！
スライドを作ると、画像を入れたくなるシーンが多々ありますね。
こんな感じに

#### イラストデモ


---
# 文字を使って視覚効果を高める

---
## 文字を使って視覚効果を高める
h1の見出しタグだけ書いたスライドを用意するとできます
見た目を重視するとQiita本来の見出しやhtmlアウトラインとしては微妙な感じになっちゃうので、どちらを優先するかは悩ましいところです。

---

## 配置にこだわりたい
実際にQiitaでスライドを作るとすぐに出てくる要望が「配置をいい感じにいじりたい」ではないでしょうか？
Qiitaのスライドモードはあくまでマークダウンを簡単にスライドビューっぽく見せるものなので、いわゆる本格的なプレゼンツールのようにわかりやすさを突き詰めるものではありません。
書きやすさと見た目のわかりやすさは両立が難しいのです…

---

## そこで、Canvaがおすすめ！
なるべく書きやすさを保ちながら、見た目をいじりやすいツールの代表格としてCanvaをあげます
（もちろんMicrosoft PowerPointや、システム設計・デザインツールとしてCacoo等といった様々なツールはありますが、無料＋汎用性重視のため不採用としました…）

https://www.canva.com/

---

## 作りたいデザインイメージから描ける
他のプレゼンツールとの大きな違いはデザインからスライドを作るイメージ、作りやすさが圧倒的（個人の主観による）です。

---

### 筆者のやり方

1. 話す内容やテーマがあって、
1. テーマに合わせたデザインイメージを固めたところから、
1. 先にデザインを決めてから
1. 内容を反映していく

という順番でLT資料を作ることが多いため、特に3でいいスライドデザイン・イメージがないから妥協するか、の時点でややテンションが落ちやすいPowerpoint系と比べるとCanvaは「いや、俺は諦めない！」で理想を追求できるのでモチベーションが落ちにくいというメリットを感じています。
（ただし、時間は溶けます）

---

### とはいえ、内容が一番大事
内容が適当でもグラフなりイラストで湧かせる事は可能には可能ですが、やっぱりエンジニアたるもの、コードやデモがあってナンボみたいなところはありますし、そういった意味では、内容でしっかり勝負するなら変化球（デザイン）に頼らず、先に内容がためをするのは大事なことです。
特にLTの場合、時間をかけて凝ったスライドを作るより、テーマを決めたら内容は補足的に押さえて手早く作っちゃって、当日いいたいことを言うのが一番です。スライドをカンニングペーパー的に使うのであれば、多少の工夫は必要かもしれません。

---

### 発展：発表の順序や設計を考える
プレゼンの目的は「自分の主張を相手に分かりやすく伝える＜伝わるようにする」ことです。
主張の仕方が拙くても、相手にとって分かりやすいものであれば問題ないです。
逆に、どんなにすごいコンテンツ・見栄えが凄くても、何も伝わらなければ意味がありません。

今回はLTという事なので、LT話者ごとに相手に伝えることを目標にするのか、自分が話して気持ちよくなるのが目的なのかという事もありますので本項については詰めませんが、本番ではお忘れなく！

---

### 伝える技術を高めたいなら
- 営業トークを学ぶのがいいです。営業のトーク術にプレゼンのほとんどが詰まっています
  - なお、筆者は法人営業の実務経験は少なく、フリーランスエンジニアとして案件相談や人材紹介について少ない知見しかありません
- 伝えるより教えるにフォーカスする場合、伝わる前提で理解を促す必要もあります
  - 伝わらなくても理解を促す事自体は可能という考え方もあります
  - 筆者は講師経験から、こちらが専門です
  - 営業トークに近いプレゼン・トークスキルやフレームワークがありますが、目的に沿って使い分けましょう
- プレゼンを学ぼうとしてとりあえず心理学、はおすすめしません。心理学とトークスキルは関係ないから、です。

---

## 小ネタ：発表の仕方を工夫してみよう
私もですが、話し下手（うまく話せない人と、緊張して余計なことまで喋っちゃう人。筆者は後者）な人でも工夫次第でインパクトを残すことができます。
（ただし、先述した「伝わりやすさ」については疑問が残るものがあるので、乱用は厳禁です）

---

# たとえば

---

# 高橋メソッドだと

---

# あんまり怒られない

---

# 気がします

---

# とはいえ

---

# 飽きやすいので

---

# 多用は控えましょう

---

## 他のプレゼン技法
- もんたメソッド
  - 「<font color="red">◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️◼️</font>」に入る文字は？
  - 色はタグを使って変えています

---

## 他のプレゼン技法
- もんたメソッド
  - 「<font color="red">次のスライドで答えを書く</font>」に入る文字は？
  - 色はタグを使って変えています

---

## 次は、ルパン三世風表現（BGMは脳内でお願いします）
次からのスライドは高速でめくってください



---

# こ

---

# れ

---

# が

---

# ル

---

# パ

---

# ン

---

# 三

---

# 世

---

# 風

---

# 表

---

# 現

---

# だ

---

# これがルパン三世風表現だ

---

## これがルパン三世風表現だ
正式名称はわかりません。
高橋メソッドを極端にやるとこうなります、の例ですね。一発目のつかみとしては面白いけど、２回目は使えないやつです。

---

## まとめ
色々な話をしましたが、慣れないうちは

1. まずは発表内容を決める
1. その内容を伝わるようにする
1. 発表の方法を考える
1. 発表練習

を、上から順番に完成度を上げていきましょう！

---

## おねがい
他の人の話もぜひ聞きたいので「こういう方法あるよ！」というのがあれば、ぜひコミュニティのスレッド内で議論したいです！（Qiitaアカウントを持っていないメンバーがいる可能性も考えられるため、Qiitaコメントを採用しません）
mise-en-placeとuvでPython環境をセットアップする

これまで[pyenv](https://github.com/pyenv/pyenv)、[venv](https://docs.python.org/3/library/venv.html)、[direnv](https://direnv.net/)でPython環境を用意していたのだが、[mise-en-place](https://mise.jdx.dev/)と[uv](https://astral.sh/blog/uv)に乗り換えることにした。

そこで、プロジェクトで使用するPythonバージョンを指定し、仮想環境をセットアップする方法を記しておく。


```sh
# 使用するPythonバージョンの指定
mise use python@3.12

# 仮想環境の作成
uv venv

# venvディレクトリの登録
cat << EOF >> .mise.toml

[env]
_.python.venv = ".venv"
EOF

# 手動で更新した.mise.tomlの有効化
mise trust
```
Pythonでリストのインデックスと要素を同時に取り出せる便利な関数があった

## はじめに
Pythonを使ってプログラムを作成していると、リストやタプルなどのコレクションデータを扱うことがよくあります。その際、リストの要素をループで処理しながら、同時に各要素のインデックス（番号）も取得したいことはありませんか？実は、そんなときに非常に便利な関数がPythonには存在します。それが enumerate です。

この記事では、enumerate 関数を使ってリストのインデックスと要素を同時に取り出す方法について詳しく解説します。

### enumerate 関数とは？
enumerate はPythonの組み込み関数で、反復可能なオブジェクト（リストやタプル、文字列など）を取り込み、それにインデックスを付けてくれる関数です。通常、for ループを使ってリストを処理する場合、インデックスとその値を別々に管理するのは手間がかかります。しかし、enumerate を使えば、これを簡単に実現できます。

### 基本的な使い方
まずは、enumerate の基本的な使い方を見てみましょう。

```py
fruits = ['apple', 'banana', 'cherry']

for i, fruit in enumerate(fruits):
    print(i, fruit)
```    
このコードは、fruits リストの各要素に対して、そのインデックスと要素を同時に取得して表示します。出力結果は以下のようになります。
```
0 apple
1 banana
2 cherry
```
ここで重要なのは、enumerate がリスト fruits の各要素にインデックスを付けてくれている点です。i がインデックス、fruit がリストの各要素を表しています。

### enumerate の仕組み
enumerate は、リストのような反復可能なオブジェクトを引数に取り、タプル (インデックス, 要素) のペアを返します。例えば、以下のようにリストを直接指定してみます。

```py
for index, value in enumerate(['a', 'b', 'c']):
    print(index, value)
```    
このコードの出力は以下のようになります。

```
0 a
1 b
2 c
```
### インデックスを1から始めたい場合
enumerate のもう一つ便利な使い方として、インデックスを0ではなく1から始めたい場合があります。これも簡単に実現できます。

```py
for i, fruit in enumerate(fruits, start=1):
    print(i, fruit)
```
出力結果は次のようになります。

```
1 apple
2 banana
3 cherry
```
このように、enumerate に start 引数を指定することで、インデックスの開始番号を変更することができます。

### まとめ
Pythonの enumerate 関数を使えば、リストやタプルなどの反復処理時にインデックスと要素を同時に取得することができ、コードを簡潔に保つことができます。インデックスを1から始めるなどのカスタマイズも可能なので、非常に柔軟で便利な関数です。是非、自分のコードでも enumerate を活用してみてください！
nRFConnectSDKを基盤としたSesameの暗号通信 #7 使い慣れた開発環境-VSCode

![sesame](https://scontent-nrt1-2.xx.fbcdn.net/v/t39.30808-6/455351543_10221179101747407_5416202126013409076_n.jpg?_nc_cat=110&ccb=1-7&_nc_sid=127cfc&_nc_ohc=9Z5sM84MtREQ7kNvgH2zdxg&_nc_ht=scontent-nrt1-2.xx&oh=00_AYCuPE_YguRXdnaWUuaVnJ6VpwHOVwWTGZ8i2KciOMeSBg&oe=66C22520)


# 目的

量産を前提とした開発には注意すべき点が多く、開発環境は最低限以下の基準を満たす必要があります。

# 基準

- C言語では、すべてのハイパーリンクが適切にジャンプできる
- ショートカットキーで同時にコンパイルと書き込みができる
- 画面上で同時に出力、コンパイルの過程、そしてコードの編集ができ
- ターミナルでコマンドを入力してコンパイルおよび書き込みができる


# 雑談
私は多くの人の開発環境を見てきましたが、ほとんどがまずコンパイルを行い、その後手動で電源を切ったり、ボタンを押して電源を入れてから書き込みを行っています。この開発プロセスは非常に苦痛です。さらに恐ろしいのは、彼らがこのような開発環境に慣れてしまっていることです。このような妥協した開発環境では、量産時に問題が発生した際、最も微細なエラーを見つけることさえ面倒になります。したがって、使い勝手の良い開発環境は非常に重要です。実際には、このような開発環境でもまだ十分ではなく、今後さらに補充が必要です。


# 関連記事

- [nRFConnectSDKを基盤としたSesameの暗号通信](https://qiita.com/tse123321/items/c0fa105cd5b9f14c2a0c)
bit全探索って2進数じゃなくても行けるのでは？

# はじめに
みなさんbit全探索はご存じでしょうか？
bit全探索は2進数で状態を表していますが、
> 「別に2進数じゃなくても行けるのでは？」

と思ったのが、この記事を書くきっかけです。
bit全探索を拡張して、k進数でbit全探索を出来るようにしてみたいと思います。
# 本編
## bit全探索について
bit全探索は、競技プログラミングでは典型の全探索アルゴリズムです。
例えばこんな問題があったとします。
### bit全探索を使用する例題
> 8個の商品があります。
それぞれの値段は以下の通りで、在庫はそれぞれひとつずつです。
 1, 3, 4, 5, 6, 8, 10, 14
それぞれの商品について買うか買わないかを選ぶ時、支払う金額の種類は何種類ありますか？

この問題を見た時に、「各商品について選ぶか選ばないかを決め、選ぶと決めた商品の合計を出し、その合計の種類数を数えると解けそう」と思います。
こんな時に使えるのがbit全探索です。
各商品についての"選ぶ"か"選ばない"の2択を、数字を2進数で表した各桁の$0,1$に対応させて全探索をします。

### 例
例えば商品1,3,4,6を選ぶ時を考えます。
各商品を選ぶことを1、選ばないことを0と表現してこの状況を2進数で表すとこうなります
> 00101101

2進数の数字の各桁が右から商品1,2,...,8の状態を表しています。
今回は1,3,4,6桁目が1になっており、この場合の商品の金額の合計は18になります。
他の状態も考えると、`00000000 ~ 11111111(2進数)`の数字で全ての選ぶ選ばないを表現することができ、これがbit全探索です。

### 実際のコード
コードに書くとこんな感じでしょうか。言語はPythonです。
```python
N = int(input())
price = list(map(int, input().split()))

price_set = set()
for bi in range(1<<N):
    price_sum = 0
    for i in range(N):
        if bi>>i&1: price_sum += price[i]
    price_set.add(price_sum)
print(len(price_set))
```
計算量は$O(2^NN)$なので、問題にもよりますが$N\leq18$くらいなら現実的な制約になりそうです。
## 状態数は別に2つじゃなくても良いのでは？
これがbit全探索ですが、ここで思った方がいるかもしれません。
bit全探索は"選ぶ"、"選ばない"で状態が2つだったので2進数の各桁で状態を表したのでした。
### じゃあ、3進数なら状態を3つ表現できるのでは？
![maxresdefault.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/fd18d096-2405-ba6e-53dc-569eb97251a4.jpeg)
> 矢木に電流走る

bit全探索は数字を2進数で表して各桁$0,1$で状態を表現しています。
じゃあ、3進数なら各桁は$0,1,2$になって状態を3つ表現できるのでは？
さらに拡張して、k進数なら各桁は$0,1,...,k-1$になってk個状態を表現できるのでは？
そうは思いませんでしょうか。

## k進数に拡張したら解ける例題
bit全探索をk進数に拡張してこんな問題を解いてみます
### k進数bit全探索で解ける例題
> 8個の商品があります。
それぞれの値段は以下の通りで、在庫はそれぞれひとつずつです。
 1, 3, 4, 5, 6, 8, 10, 14
AさんとBさんはそれぞれの商品について買うか買わないかを選びます。
一方が選んだ商品はもう一方は選ぶことが出来ない時、それぞれが支払う金額の差の金額の種類は何種類ありますか？

前の問題では状態が"選ぶ"、"選ばない"の2種類でしたが、今回は各商品の状態を"Aが選ぶ"、"Bが選ぶ"、"選ばない"の3種類にすると解けそうです。bit全探索を3進数に拡張して解いてみます。
### 例
例えば、Aが商品1,4、Bが商品2,7,8を選ぶ時を考えてみます。
各桁の数字を`0: 選ばない, 1: Aが選ぶ, 2: Bが選ぶ`と対応させると状態を表す数字は3進数でこうなります。
> 22001021

他の状態も考えると`00000000 ~ 22222222(3進数)`の数字で全状態を表現できそうです。
### 実際のコード
コードに書くとこんな感じです。
```python
N = int(input())
price = list(map(int, input().split()))

price_set = set()
for bi in range(3**N):
    sum_A, sum_B = 0, 0
    for i in range(N):
        if bi//(3**i)%3 == 1: sum_A += price[i]
        elif bi//(3**i)%3 == 2: sum_B += price[i]
    price_set.add(abs(sum_A-sum_B))
print(len(price_set))
```
計算量は$O(3^NN)$です。$N\leq12$くらいなら現実的でしょうか。
## 4進数bit全探索で解けた問題
AtCoderの過去問を解いていてk進数bit全探索で解けた問題があったので紹介します。

https://atcoder.jp/contests/abc119/tasks/abc119_c

### 順列と仕切りを使用した解法
最初に提出した解法はこちらです。

https://atcoder.jp/contests/abc119/submissions/56672523

竹の並び順を全探索し、その並び順に挟む3つの仕切りを全探索する解法で解きました。
計算量は$O(N\times N!\times _{N-1}C_3) \fallingdotseq 1.1\times 10^7$です。
これでも十分間に合いました(0.800ms)
### k進数bit全探索を使用した解法
解説を読んだ後に4進数bit全探索でも提出してみました。

https://atcoder.jp/contests/abc119/submissions/56672600

4進数の各桁を`0: Aが選ぶ, 1: Bが選ぶ, 2: Cが選ぶ, 3: 選ばない`として全探索しています。
計算量は$O(4^N\times N) \fallingdotseq 5.2\times 10^5$となって、大幅に計算量が改善(0.228ms)しました。
# おわりに
### bit全探索は無駄なく全探索が出来る
bit全探索の良い所は、状態を表す数字に1増やすだけで次の状態に遷移出来る所です。
また、最初の方法では同じ状態を重複して数えてしまっていましたが、bit全探索なら各状態を重複なく数えることが出来ます。

k進数bit全探索を手段として持っておくと、状態が2つではない場合においてもbit全探索の良さを生かした全探索が出来るのではないかと考えます。
ぜひ、試してみてください。
【GithubActions】ワークフローを定期実行する

# はじめに
最近、HITOTSUではE2EテストをGithubActionsで自動実行させるということを行いました。
GithubActionsでは、cron式を書くことでスケジュール実行ができます。
スケジュール実行についてどのような指定方法があるか、備忘録も兼ねていくつか紹介できればと思います。

## cron構文
分、時、日、月、曜日の順で実行スケジュールを指定するフォーマット
```
*　  *　  *　  *　  *
分  時　 日　 月　 曜日
```
## 〇〇分おきに実行する
15分おきに実行したい場合
```
  schedule:
    - cron: "*/15 * * * *" 
```
## 時間指定して実行する
毎日12時に実行したい場合
日本標準時（JST）はUTCより9時間進んでいるため-9時間した値を設定する。
```
  schedule:
   - cron: "0 3 * * *” 
```
## 平日のみ実行する
0から6を指定できる。0が日曜日、6が土曜日。
```
  schedule:
   - cron: "0 0 * * 1-5” 
```
## 注意点
* 5分間隔より短い間隔でワークフローを定期実行することはできない
* 指定した時間ピッタリに動くことはない（大体数分遅れて実行されている印象）
* 定期実行は、デフォルトブランチ以外のブランチではできない
TMUXでクリップボードを有効にする方法

## はじめに

まず、reattach-to-user-namespaceプラグインをインストールする必要があります。
homebrewで簡単にインストールできます。

```zsh:zsh

brew install reattach-to-user-namespace

```

次に、設定ファイル~/.tmux.confを作成する必要がある。ここで、コピーしたテキスト・バッファをpbcopyにで共有するように設定を追加します。
設定ファイルは以下の通りです。

```tmux.conf

bind-key -T copy-mode-vi 'y' send -X copy-pipe-and-cancel 'reattach-to-user-namespace pbcopy'
bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'reattach-to-user-namespace pbcopy'

```

## コピーの方法
tmuxを実行してから、コピーモードに入ります。
コピーしたい箇所を選択し、”y”キーでコピーが完了します。

貼り付けは、 ”command + v”で貼り付けできます。
jqueryの is(":visible") をノーマルjsだけでサクっと判定する（※要素が表示されているか親／祖先要素の状態も加味して判定する）

jQueryでは、[is(":visible")](https://api.jquery.com/visible-selector/) で要素の表示状態が簡単に取れていた。親要素を辿って表示状態を見て１つでも非表示であれば子孫も見えないと判断してくれたのに、脱jQueryしたことで途端にparentElement追う面倒くさい再帰ロジックを書く羽目になっていた。

[getBoundingClientRect()](https://developer.mozilla.org/ja/docs/Web/API/Element/getBoundingClientRect) や [IntersectionObserver()](https://developer.mozilla.org/ja/docs/Web/API/IntersectionObserver) などは、今の画面上の可視領域上での要素の表示判定なので目的に適ってない。

結論から言うと調べ方が足りんかった。というか新機能のアップデート[^1]をウォッチしてなくて自分の脳みそもアップデートしていないだけだった。

んで、ついさっきデベロッパーコンソールで、要素 . で出てくる入力アシストのリスト見てたら、「なんだこれは！！」なメソッドを見つけた次第。

名前からしてそのもの！

[checkVisibility](https://developer.mozilla.org/ja/docs/Web/API/Element/checkVisibility)だと〜！！ これやーーーん！

しかもオプションでopacityの扱いも指定できる。[is(":visible")](https://api.jquery.com/visible-selector/)より優れてる。

[^1]: Chromeは2022/9/2から！ iOS Safari対応も2024/3に！
PlantUML構文まとめ

# PlantUML構文まとめ
個人的にPlantUML構文をまとめる。随時更新予定
ぱっと検索して、記述方法を参照できることを目的とする。

## 基本構文
### 一行コメント
``` PlantUML
' 一行コメント (行末まで)
```

### 複数行コメント(ブロックコメント)
```
/' 
 複数行のコメント
 '/
```

### 他ファイル読み込み
```
' ↓は同階層にあるファイルを参照
!include xxx.pu
```

### タイトル
```
title タイトル名
```


## クラス図(Class diagram)
### 宣言
| 要素                 | 説明                              |
| :------------------- | :-------------------------------- |
| abstract             | abstract
| abstract class       | "abstract class"
| annotation           | annotation
| circle               | circle
| ()                   | circle_short_form
| class                | class
| class                | class_stereo  <<stereotype>>
| diamond              | diamond
| <>                   | diamond_short_form
| entity               | entity
| enum                 | enum
| exception            | exception
| interface            | interface
| metaclass            | metaclass
| protocol             | protocol
| stereotype           | stereotype
| struct               | struct

### 可視性の定義
| 文字   | 可視性            |
| :----- | :---------------- |
| -      | private           |
| #      | protected         |
| ~      | package private   |
| +      | public            |

### クラス間の関係
| 記号                 | 説明                  |
| :-----               | :-------------------- |
| --                   | 実践
| ..                   | 波線
| : 関連名             | 関連名をつける
| "1" -- "*"           | 多重度
| <--                  | 関連
| <..                  | 依存(Dependency)
| <|--                 | 汎化(Generalization)
| <|..                 | 実現(Realization)
| *--                  | 構成(Composition)
| o--                  | 集約(Aggregation)
| +--                  | 内部クラス(Inner Class)
| ()-                  | ロリポップ

### その他
| 記号                                 | 説明                  |
| :-----                               | :-------------------- |
| Package 名前 {}                      | パッケージ化
| namespace 名前 {}                    | 名前空間(Namespaces)
| note top of クラス名 コメント        | クラスの上にノート
| note bottom of クラス名 コメント     | クラスの下にノート
| note left of クラス名 コメント       | クラスの左にノート
| note right of クラス名 コメント      | クラスの右にノート
| note 表示位置 クラス名::フィールド名 | フィールドにノート
| note 表示位置 クラス名::メソッド名   | メソッドにノート
| note 表示位置 on link                | 関連にノート
Java Gold 例題 nio copy

```java
public class FileCopyTest {
	public static void main(String[] args) {
		
        Path sp = Paths.get("food.jpg");
		Path dp = Paths.get("food_copy.jpg");
		
		try {
			if(Files.exists(dp)) {
				System.out.println("file already exists");
			} else {
				Files.copy(sp, dp, StandardCopyOption.REPLACE_EXISTING);
				System.out.println("copy sucucess");
			};
		} catch(IOException e) {
			System.out.println("IOException");
		}
      }
  }
```
food_copy.jpgは存在しない。
このコードを2回実行した時に表示される出力結果はどれでしょうか。
  
  A
  ```
  copy sucucess
  copy sucucess
  ```

  B
  
  ```
  copy sucucess
  file already exists
  ```

  C
  
  ```
  copy sucucess
  IOException
  ```

  D
  ```
  IOException
  IOException
  ```

  E
  
try-with-resourceなどでFileをcloseしていないためコンパイルエラー

F


try-with-resourceなどでFileをcloseしていないため実行時エラー
<details><summary>解答</summary>
B

1回目
`if(Files.exists(dp))`では「food_copy.jpg」が存在するか確認します。
food_copy.jpgは存在しない。とあるので、`false`になります。

`Files.copy(sp, dp, StandardCopyOption.REPLACE_EXISTING);`
ではnioのFilesを使ってjpgファイルをコピーしています。
オプションの`StandardCopyOption.REPLACE_EXISTING`はコピーが存在しても上書きします。
コピーが作成された後、「copy sucucess」が出力されます。

2回目
`if(Files.exists(dp))`では「food_copy.jpg」が存在するか確認します。
1回目の実行でコピーファイルが既に存在するので、`true`になります。
「file already exists」が出力されます。

補足
try-with-resources

try-with-resourcesは、`AutoCloseable`インターフェースを実装するリソース
（例: `InputStream`, `OutputStream`, `BufferedReader`, `BufferedWriter`など）を使用する場合に便利です。
リソースが自動的にクローズされるため、リソースリークを防ぐのに役立ちます。

`Files.copy()`メソッドは、ファイルシステムの操作を行うだけでリソースを管理するわけではないため`try`ブロック内で例外処理を行うだけで問題ありません。

仮に本コードのif文がなく以下の場合
```java
try {
    Files.copy(sp, dp, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("copy sucucess");
} catch(IOException e) {
    System.out.println("IOException");
}
```
コピーは上書きされるため、１回目、２回目ともに「copy sucucess」が出力されます。

```java
Files.copy(sp, dp);
```

ちなみに`StandardCopyOption.REPLACE_EXISTING`オプションを指定せずに実行すると
1回目はコピーが成功します。
2回目は`FileAlreadyExistsException`がスローされます。
「IOException」が出力されます。
</details>

---



https://qiita.com/T-ngtj/private/df254aacd05be698199a
SparkデータフレームのArrayTypeカラムの要素のカウント

結構悩みました。

**やりたいこと**

- Sparkデータフレームに含まれる[ArrayType](https://docs.databricks.com/en/sql/language-manual/data-types/array-type.html)のカラムに任意の要素が格納されている。
- このカラムの配列の要素をキーごとにカウントして、カウントを格納する新たなカラムとする。カラム名は要素名から構成する。

まず参考になったのはこちら

https://stackoverflow.com/questions/72600575/one-hot-encoding-to-a-list-feature-pyspark

```py
from pyspark.sql import SparkSession
from pyspark.sql import functions as F


spark = SparkSession.builder.getOrCreate()
df = spark.createDataFrame(
    [
        {"ID": 1, "tags": ["A", "B", "C"]},
        {"ID": 2, "tags": ["A", "D", "E"]},
        {"ID": 3, "tags": ["A", "C", "F"]},
    ]
)

tags = [
    x[0]
    for x in df.select(F.explode("tags").alias("tags"))
    .distinct()
    .orderBy("tags")
    .collect()
]

df = df.select(
    "*",
    *[
        F.array_contains("tags", tag).alias("tags{}".format(tag)).cast("integer")
        for tag in tags
    ]
)
```
![Screenshot 2024-08-14 at 12.50.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0e60d5a9-ac52-0805-029b-f492f196b2bf.png)

[array_contains](https://spark.apache.org/docs/3.1.2/api/python/reference/api/pyspark.sql.functions.array_contains.html)を使って、特定の要素を含む場合には要素名を含む列の値を1にしています(例: タグ`A`を含むかどうかは`tagsA`列で表現)。

要素数をカウントするような関数があれば良かったのですが見当たらず。[高階関数](https://qiita.com/taka_yayoi/items/7a8749bbc45c7fb1e2b1)と組み合わせるかとも思いましたが、最終的にはudfと組み合わせました。

```py
from pyspark.sql import functions as F

df = spark.createDataFrame(
    [
        {"ID": 1, "tags": ["A", "B", "C", "B", "D"]},
        {"ID": 2, "tags": ["A", "D", "E", "E", "A"]},
        {"ID": 3, "tags": ["A", "C", "F", "F", "F"]},
    ]
)
display(df)

unique_tags = [
    x[0]
    for x in df.select(F.explode("tags").alias("tags"))
    .distinct()
    .orderBy("tags")
    .collect()
]
print(unique_tags)

from pyspark.sql.functions import udf

# リストの特定の要素数をカウントするUDF
@udf("int")
def count_element_udf(target_list, element):
    return target_list.count(element)

df = df.select(
    "*",
    *[count_element_udf("tags", F.lit(tag)).alias(f"count_{tag}") for tag in unique_tags]
)
display(df)
```

UDFを呼び出す際の二つ目の引数で、`F.lit`を指定してリテラル値にしないと列名を参照しようとしてエラーになります。

![Screenshot 2024-08-14 at 13.05.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5f2e0d42-8ab2-8a3a-565c-8a3b666d605b.png)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Windows 11 IoT Enterpriseのストレージ要件

# はじめに
　MicrosoftのWindowsに「最小ハードウェア要件(Minimum hardware requirements)」というものが定められてことをご存知の方は多いと思います。私もこれまでに数回取り上げました（[この記事](https://qiita.com/ken-yossy/items/c65fceaf53665f7c5751)や[この記事](https://qiita.com/ken-yossy/items/8333ec62b77e98cadffd)）。

　これに関連して、Microsoftは今年（2024年）後半に投入予定のWindows 11 IoT Enterprise 24H2およびWindows 11 IoT Enterprise Long Term Servicing Channel (LTSC)について、それらの最小ハードウェア要件を発表しました<sup>[1]</sup>。

　この記事ではストレージに焦点をあててその要件を見ていきたいと思います。
 
# まとめ
* ストレージ容量要件は、Windows 11 IoT Enterprise (24H2)が64 GB、Windows 11 IoT Enterprise LTSCが最低16 GB、推奨64 GB
* Windows 11 IoT Enterprise LTSCはeMMCやSDカードまで含めた幅広いストレージドライブを対象としている
* NANDフラッシュメモリがメディアであればやはり容量は大きいほうが信頼性を期待できる

# ストレージ要件比較表
　まず、今回発表されたWindows 11 IoT EnterpriseおよびそのLTSCのハードウェア要件のうちストレージ容量要件を表1に示します。比較のために、素のWindows 11と、Windows 10 IoT Enterprise（LTSC含む）を示します。

_表1：Windows OSストレージ容量要件比較表_
|  | ストレージ容量要件 |
|:-:|:-:|
| Windows 10 IoT Enterprise（LTSC含む）<sup>[1]</sup> | 20 GB（64bit環境）、16 GB（32bit環境） |
| Windows 11<sup>[2]</sup>  | 64 GB |
| **Windows 11 IoT Enterprise (24H2)**<sup>[1]</sup> | 64 GB |
| **Windows 11 IoT Enterprise LTSC**<sup>[1]</sup> | 最低16 GB、推奨64 GB |

　表1を見ると、MicrosoftとしてはWindows 11での基本ストレージ容量を64 GBにしたいらしいことが読み取れます。

　一方で、IoT Enterprise LTSCのみ前世代(Windows 10)の同エディションの32bit環境相当まで最小構成（ハードル）を下げています。

　これは、Windows 10 IoT Enterprise LTSCを利用しているユーザやWindows 10 IoT Enterprise LTSCを対象OSとするPCやボードのメーカーがWindows 11 IoT Enterprise LTSCに対応するにあたり投資が必要な追加ハードウェアコストをできるだけ抑えられるようにするため、と推測できます。 

　MicrosoftのWebページ<sup>[1]</sup>を読むと、Windows 11 IoT Enterprise LTSCのストレージ種別としてはSolid State Drive (SSD)やHard Disk Drive (HDD)に加えてeMMCやSDカードそしてUSB接続のストレージまで認められており、確かに「ストレージ容量が16 GBのWindows機」を実現できそうです。

　街中などに設置されたキオスク端末やサイネージ装置などのOSがWindowsで起動ドライブがSDカード、なんてことも良くあるようですので、そのような機器の新機種やOS更新をターゲットにした定義とも考えられます。

# そんな容量で大丈夫か？
　記憶メディアがNANDフラッシュメモリであるならば、SDカードでも大容量であるほうが一般的にアクセス性能と信頼性は高くなります。

　もちろん、上に挙げたような装置で使用されるストレージは量販店の店頭で購入できるコンシューマ向け製品ではなく、信頼性の高いインダストリアル向け製品が使われているはずです。またアクセス性能はそれほど求められないことも多いです。
 
　ただそれを踏まえても、より高い信頼性や安定性を求めるのであれば制約が許す限り容量の大きい製品を選ぶことをお勧めします。

# まとめ
　この記事では、Microsoftが発表したWindows 11 IoT EnterpriseおよびそのLTSCエディションのストレージ容量要件について紹介しました。

　NANDフラッシュメモリベースのストレージは、用途が幅広くなるに伴い容量やアクセス性能の要件も多様化しています。一方で、NANDフラッシュメモリを使用しているがゆえに「容量は大きいほうが様々な点で良い」という基本的な性質からは逃れられません。

　今回示された要件はあくまで「最低(Minimum)」の要件であることに留意してストレージを選定していただければと思います。

# References
[1] Microsoft, _"[Minimum System Requirements for Windows IoT Enterprise](https://learn.microsoft.com/en-us/windows/iot/iot-enterprise/hardware/system_requirements?tabs=Windows11LTSC)"_, Retrieved on July 1, 2024
[2] Microsoft, _"[Windows 11 Minimum Hardware Requirements](https://download.microsoft.com/download/7/8/8/788bf5ab-0751-4928-a22c-dffdc23c27f2/Minimum%20Hardware%20Requirements%20for%20Windows%2011.pdf)"_[PDF], June 2021

# ライセンス表記
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="クリエイティブ・コモンズ・ライセンス" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />この記事は<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンス</a>の下に提供されています。
OpenCVで顔検出してみる

## はじめに
前回はRaspberry Pi 4にTensorFlow Liteを導入してみましたが、今回は画像の分析などを行うためにOpenCVを導入してみようと思います。

## OpenCVのインストール
OpenCVはpipを使ってインストールしますので、仮想環境に入って作業をします。
![0814_opencv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/33027e7e-b74f-bfb4-1409-fab937a4f266.png)
OpenCVのインストールの過程でNumPyが最新のv2.0.1にアップグレードされてしまったようです。
このままだとTensorFlow Liteが使えなくなってしまうので、NumPyのバージョンを1.23.2に戻します。
![0814_opencv_vererr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/65e72958-d7ce-ad0b-5504-fccf5751a6c0.png)
NumPyのバージョンは1.23.2に戻すことができましたが、エラーが赤文字で出ていますね。
OpenCVはNumPyのバージョンが1.23.5以上でないと動作しないようです。
なかなか互換性の関係でうまくいかないですね。NumPyのバージョンを1.23.5にします。
```
$ pip3 uninstall numpy
$ pip3 install numpy==1.23.5
```
## 顔検出結果
顔検出用のスクリプトを使って、顔検出できるか試してみました。
結果は以下の通り。試しにアイコン画像を使って顔検出してみましたが、イラストでも顔検出できるんですね。
![0814_opencv_faces.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3750854/47f0a539-117f-51d2-d7ca-f9c54dd590d3.png)
nodebrewを使用したnode.js(npm)のインストール方法(mac)

Reactの学習を始めるのあたり環境構築を行ったので、その流れを記録しておきます。
今回はmacのターミナル上でコマンドを実行しています(テキストエディタのターミナルではありません)。

## node.js(npm)のインストール手順
1, Homebrewのインストール
2, Homebrewコマンドを使用して、nodebrewをインストール
3, nodebrewコマンドを使用して、nodejsのインストール

各用語解説は最後に行うので、まずは手順を以下に記します。

## ①Homebrewのインストール画面からコマンドをコピペ
・以下のサイトにコピーできるコマンドが表示されているのでコピー

https://brew.sh/ja/

・コピーしたものをターミナルにペースト、実行
・インストールが完了されたことを確認するため以下のコマンドを実行
`brew -v`
・完了が確認できれば②へ以降
・コマンドが動作しなければ完了していないということなので、以下コマンドでパスが通っているか確認
`echo $PATH`
・`/opt/homebrew/bin` が含まれているか確認し、もし含まれていない場合は、以下のコマンドを実行してパスに追加
`echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
`
## ②nodebrewをインストールする
・`brew install nodebrew`を実行
・`nodebrew setup`を実行しセットアップを行う
・PATH情報が出力されるので、そのパス情報を.zshrc (bashを使用している場合は、.bash_profile）に追記して、変更を反映
(bashの場合は、zshrcをbash_profileに置き換え)
実行するコマンド
`echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc`
`source ~/.zshrc`

## ③node.jsのバージョンを指定して、node.js(npm)のインストール
・`nodebrew ls-remote`を実行しインストール可能なバージョンリストを確認
・任意のバージョンをインストールする
- バージョンを指定したインストール
`nodebrew install v16.16.0`
- 最新版をインストール
`nodebrew install latest`
- 安定版をインストール
`nodebrew install stable`

特別な理由がない限り安定版のインストールがオススメ。
最新版だとバグなどが発生する場合もあるため慣れないうちは安定版。

・`nodebrew list`を実行し正常にインストールされたことを確認

## ④使用するnodeのバージョンを設定・動作確認
・`nodebrew use v16.16.0`を実行しインストールされたnode.jsを有効化
(v16.16.0には先ほど自分でインストールした時のバージョンを入力)
・最後に以下二つのコマンドを実行し、それぞれのバージョンが表示されれば環境構築完了
` node -v`
`npm -v`

## 用語解説
- Homebrew
macOS用のパッケージ管理ツールで、これを使用すればnodebrewや、git、mysqlなどさまざまなソフトウェアを簡単にインストールおよび、管理できる
- nodebrew
node.js(npm)のバージョン管理ツールで、コマンドひとつで特定バージョンのインストールや、バージョンの切り替えが可能

## 補足
Homebrewのインストールや動作確認は、システムに一度設定すれば、各プロジェクトごとに再度行う必要はありません。HomebrewやNodebrewのインストールと設定は一度行えば、今後のプロジェクトでそのまま使用できます。新たなプロジェクトを開始する際には、必要なパッケージやライブラリをインストールするためにbrewやnodebrewコマンドを使用しますが、それらのインストールと動作確認は一度で十分です。
ubuntu 24.04 LTSで自宅サーバー構築（サーバーのタイムゾーンの設定）

<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www15.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
例として、東京に変更。
#タイムゾーン一覧を表示
taisuke@ubuntuserver:~$ sudo timedatectl list-timezones
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmara
Africa/Asmera
Africa/Bamako
Africa/Bangui
.....
.....
US/Samoa
UTC
Universal
W-SU
WET
Zulu
#タイムゾーン設定
taisuke@ubuntuserver:~$ sudo timedatectl set-timezone Asia/Tokyo
#設定確認
taisuke@ubuntuserver:~$ sudo timedatectl
               Local time: Wed 2024-05-08 13:59:17 JST
           Universal time: Wed 2024-05-08 04:59:17 UTC
                 RTC time: Wed 2024-05-08 04:59:17
                Time zone: Asia/Tokyo (JST, +0900)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www15.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
Symbolノード証明書作るやつNode.jsにした2

## 前回
Symbolの証明書を作成するCLIを紹介しました。

https://qiita.com/ccHarvestasya/items/d924c331200009a056b6

今回も、OpenSSLを使用して証明書生成しているパッケージの紹介をしている風の備忘録です。

## Simple Symbol Node Cert

### インストール
使用するプロジェクトにインストール。
```sh
npm install simple-symbol-node-cert
```

https://www.npmjs.com/package/simple-symbol-node-cert

基本的な機能はCLIと同じです。

### 証明書生成

`generate`で証明書を生成出来ます。
CAとNodeの秘密鍵は、`privatekeysFilePath`でしていたファイルに暗号化して保存され、CAの秘密鍵は削除します。なお、Node秘密鍵は`node.full.crt`と共にノード間通信に使用するので削除していません。

```typescript
import { SimpleSymbolNodeCert } from './SimpleSymbolNodeCert.js'

const ssnc = new SimpleSymbolNodeCert()
ssnc.generate(
  './cert',
  'my cool CA',
  'my cool node name',
  7300,
  375,
  false,
  './privatekeys.yaml',
  'testpasswd'
)
```

|№|引数|説明|
|:-:|:--|:-|
|1|certDirPath|証明書出力ディレクトリ|
|2|caName|CA名|
|3|nodeName|Node名|
|4|caCertDays|CA証明書有効日数|
|5|nodeCertDays|Node証明書有効日数|
|6|isForce|上書出力フラグ|
|7|privatekeysFilePath|privatekeysファイルパス|
|8|passwd|privatekeysファイル暗号化パスワード|


### 証明書更新

privatekeysファイルパスに書かれた秘密鍵を元に更新します、証明書の有効期限を更新します。

```typescript
import { SimpleSymbolNodeCert } from './SimpleSymbolNodeCert.js'

const ssnc = new SimpleSymbolNodeCert()
ssnc.renew('./cert', 7300, 375, './privatekeys.yaml', 'testpasswd')
```

|№|引数|説明|
|:-:|:--|:-|
|1|certDirPath|証明書出力ディレクトリ|
|2|caCertDays|CA証明書有効日数|
|3|nodeCertDays|Node証明書有効日数|
|4|privatekeysFilePath|privatekeysファイルパス|
|5|passwd|privatekeysファイル暗号化パスワード|
ubuntu 24.04 LTSで自宅サーバー構築（PostfixとDovecotのSSL/TLS の設定）

<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www15.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
事前に
https://qiita.com/sqoot610/items/e2a7b3ba8fa30df42d6f
を設定してください。
taisuke@ubuntuserver:~$ sudo vi /etc/postfix/main.cf
#最終行に追記
smtpd_tls_security_level = may
smtpd_tls_cert_file = /etc/letsencrypt/live/ご自身のサーバーのドメイン名/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/ご自身のサーバーのドメイン名/privkey.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
taisuke@ubuntuserver:~$ sudo vi /etc/postfix/master.cf
#19, 20, 22行目 : コメント解除
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
#-o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
#SMTPS (465) を使用する場合は 最終行に追記
smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes

taisuke@ubuntuserver:~$ sudo vi /etc/dovecot/conf.d/10-ssl.conf
#6行目 : 変更
ssl = yes
#12,13行目 : コメント解除して証明書/鍵ファイル指定
ssl_cert = </etc/letsencrypt/live/ご自身のサーバーのドメイン名/fullchain.pem
ssl_key = </etc/letsencrypt/live/ご自身のサーバーのドメイン名/privkey.pem
taisuke@ubuntuserver:~$ sudo systemctl restart postfix dovecot
クライアント側の設定です。
Mozilla Thunderbird の場合、以下のようにメールアカウントのプロパティを開き設定をします。
左メニューで [サーバー設定] を選択し、右ペインで [接続の保護] の項目を [STARTTLS] または [SSL/TLS] に変更します。
ポートは [STARTTLS] は [143], [SSL/TLS] ならば [993] です。
![thunderbird.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/e916a8a1-2a2e-1778-e11b-65738cccbd19.jpeg)
送信サーバーの設定も変更します。
左メニューで [送信 (SMTP) サーバー] を選択し、右ペインで [接続の保護] の項目を [STARTTLS] または [SSL/TLS] に変更します。
ポートは [STARTTLS] は [587], [SSL/TLS] ならば [465] です。
以上で設定 は OK です。
![thunderbird2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/4ffabf74-44fa-2558-3350-a1b091c7d8c1.jpeg)
メールの送受信を実行して正常に動作するか確認してください。
![thunderbird3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/17ad33a4-c993-4a26-f558-71f993d8c87b.jpeg)
<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www15.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
【Javascript】Symbol型について図解を用いて解説する

# はじめに

先日、動画にてJavascriptの勉強をしている中で、見慣れない型を見つけました。それが**Symbol**という型になります。
そもそもSymbolって何なのか？どういった場面で使えるのか？といったことについて気になったので、今回はSymbol値についてアウトプットしていこうと思います。

# Symbol型とは？

Symbol型は、文字列型(String型)や整数型(Int型)などが含まれるpremitive値の一種になります。そこで、String型との違いや実装方法、利点について下記で説明します。

### 全体観

String型とSymbol型の違いは下記のようになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661690/1fd1d648-373a-bacf-65df-2df927d46ab4.png" width="500">

上図のように、同じ値同士で比較する場合、String型は「true」になるのに対して、Symbol型は「false」になります。ソースコードの記載例は下記の通りです。

```js
// String型の場合
let string1 = "string";
let string2 = "string";
console.log(string1 == string2) // 「trueが出力」

// Symbol型の場合
let symbol1 = Symbol();
let symbol2 = Symbol();
console.log(symbol1 == symbol2) // 「falseが出力」
```

### なぜfalseと出力されるのか？

上記のように、Symbol型ではなぜ同じ値でもfalseと出力されるのでしょうか？
それは、Symbol型の値が **「ユニーク値(一意の値)」** となっているためです。
実際には、見た目では同じ`Symbol()`といった値でも、下記のようにユニーク値となるように値が隠れて格納されていることより、`false`の結果が出力されます。また、一回使われたユニーク値は再生成されないといった特徴があります。

```js
let symbol1 = Symbol(); // qwe123rty456
let symbol2 = Symbol(); // asd456fgh678
console.log(symbol1 == symbol2) // 「falseが出力」
```

一方で、一度生成されたユニーク値は再生成されないものの、`Symbol.for('文字列')`とすることによって、新しい変数に同じSymbol型の値を入れることができます。その場合、出力結果も`true`となります。

```js
let symbol1 = Symbol.for('symbol1'); // qwe123rty456
let symbol2 = Symbol.for('symbol1'); // qwe123rty456
console.log(symbol1 == symbol2) // 「trueが出力」
```

### どこで使うのか？

...ここまで説明はしたのですが、もともと互換性を維持したまま、オブジェクトに新たな機能やプロパティを追加するために考案されたメソッドなので、実際のアプリケーション開発ではほとんど使うケースはないみたいです。。笑
なので、こんな型があるんだな〜くらいの温度感で良いかなと思いました。
自分の顔を他人の顔と位置合わせ

# プロの技術はすごいなぁ in TEPIA

:::note info
Information
Regarding the English explanation, please refer to github bottom side link
:::

## 変幻灯の技術を用いて自分の顔の動きをバッハにシンクロさせる

https://www.youtube.com/watch?v=Jd0GQQ087ug

https://www.tepia.jp/

- ちょっとした技術の紹介があるものの、小さな子供には理解できず、遊び場と化してしまった。
- でも、これを気に少しでも興味を持ってくれれば
- もう少しお兄さんの超難関塾に通っていると子供はスラスラ課題をこなしていた（これは感心）
- TEPIAは予約制なので、激混みにならないみたいです（特に平日）
- Scratchもロクにこなさなかった息子はかなり苦労して、幼児用ロボット動かしていました（汗）

# 大きい子供に似たようなものをつくってとせがまれる

:::note warn
途中経過
- 現在は他人の顔の位置と自分のリアルタイムの位置合わせまでです
:::

## 作成工程
1. データを集める
1. ランドマークデータを集めて学習
1. 実際に自分の顔とポイントが一致するかを確認
1. 合成したい写真を用意する。その顔のポイントを把握

1. 最後に自分の映した顔のポイントがその顔のポイントに合うようにする

:::note info
インフォメーション
- ２０秒程度で５００枚の画像を取得するようにしてみました
- 学習の損失はなかなか下がらずにデータ量の割には時間をかけています
- これは修正ポイントですね

:::

# 結果

![landmark_YuiAragaki.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2155177/ee86b9b6-0e86-7e6b-4d81-3ebfa4f533b3.png)

− なんとか緑のポイントが自分の顔から超有名な新垣さんの顔に合わせてみた図

# 次への課題
- 表情を動かす（GANとか？）
- ノートPCで動く状態をキープ。
- まあ、すでにVtuberセットみたいなものが世にはでていますが、気にせず作成する

## 成果物

https://github.com/mi-kaneyon/face_point
もう迷わない。画像でイメージするbisect_left / bisect_right

# はじめに
### ~bisect_leftを使うたびに頭が爆発しているあなたへ~
`bisect_left` / `bisect_right` 関数は、`bisect`モジュールに用意されている、二分探索を用いて要素が配列の中の何番目かを取得することが出来る関数です。
競技プログラミングなどで、"○○以下の要素が何個か"などを高速に求めたい時、よく使用します。
ただ、**「この値を入れたらどんな値が返ってくるか」** や
 **「値が配列に含まれている時はどんな値が返ってくるか」** など
使うたびに頭が爆発していませんか？
この記事は、そんなあなたに向けた記事です。
これを見ればもう迷うことはないでしょう。
# この記事の対象読者
この記事を読んでいる段階は以下とします。
* 二分探索を理解していて、`bisect_left`も使ったことがある
* 問題の考察を終わらせて、あとは`bisect_left`を使うだけ
* `bisect_left`を使うたびに頭が爆発している

「二分探索って何？」って方は他の方の二分探索の記事をご覧ください。
二分探索は競技プログラミングにおける脱初心者のためのアルゴリズムなので、是非じっくり勉強してみてください。とても面白いアルゴリズムですよ。
# 本編
## bisect_leftで悩むシチュエーション（N回目）
コンテスト中に`bisect_left`を使うと良さそうというのが分かった。
しかし、あなたはこんな風に悩んでいるかもしれません。
具体例を上げましょう。このようなlistがあったとします。
```python
li = [0, 5, 10, 15]
```
ここで以下の関数の戻り値はいくつになるでしょうか？
考えてみてください。ぱっと見てわかるでしょうか？
```python
bisect_left(li, 3)
```
ぱっと見でわかる方はこの記事を読む必要はありません。
さっさとコンテストに戻って実装を進めて提出してください。
>「3は0より大きくて、5より小さいから...」
「0のindexが0だから...」

など考えたかもしれません。
それなら、これはどうでしょうか？
```python
bisect_left(li, 5)
```
> 「listの要素に含まれる値の場合はどうなるんだっけ？」
「5のindexが1だから1？」

引数の値が要素に含まれる場合もややこしいですね。
最後にこんなのはどうでしょうか？
```python
bisect_right(li, 3)
```
>「leftじゃなくてrightになったらどうなるんだっけ?」
「rightって何が右やねん...」

こうなるともうわからない。
こうしてボクのようにコンテスト中に頭が爆発し、ちまちま`print()`でテストして時間を無駄にするのです。
しかし、これを一発でわかる魔法のような図があります。
## bisect_leftが一発でわかるようになる図
最初に本質を伝えます。
`bisect_left`は**値のindex**を返す関数ではありません。
`bisect_left`は**値の間のindex** を返す関数です。
数直線を書いて考えてみましょう。
> li = [0, 5, 10, 15]

このlistを数直線上に表してみるとこうなります。
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/d80fcce2-c356-f87c-347d-cead7494374b.png)

ここで、値ではなく値の間の区間に番号を付けてみます
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/91c4a6ab-d2c0-59d2-f616-b4970dc086ef.png)

listの要素が4つなので、区間は5つになります。
実はこの図を見たあなたは、もう`bisect_left`に迷うことは無くなりました。
同じ問題を見てみましょう
```python
bisect_left(li, 3)
```
この関数が返す値は図を見れば一瞬でわかります。数直線上の紫の区間のうち、3はどの箇所にあるでしょうか？
そうです、区間1ですね。`bisect_left(li, 3)`も1を返します
さらに、`bisect_right(li, 3)`も戻り値は1です
```python
bisect_left(li, 3) # 1
bisect_right(li, 3) # 1
```
図をイメージした途端に、とても分かりやすくなったのではないでしょうか？
listの要素に含まれない値を検索した時は、`bisect_left`、`bisect_right`どちらも同じ値を返します
`bisect_left`と`bisect_right`の違いは、listに含まれる要素を検索した時に現れます
## bisect_leftとbisect_rightの違い
違いが表れる例を示します
```python
bisect_left(li, 5) # 1
bisect_right(li, 5) # 2
```
listに含まれる要素の5で検索すると違いが表れます。
もう一度図を見てみましょう。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/e41dd53c-b805-4db8-855c-d56ca63f4666.png)

この図を見ると区間１と区間２はどちらも5という数字を含んでいます。
`bisect_left`と`bisect_right`の違いは、含まれる区間が2つある時に
**どちらの区間に含まれることにするか**という違いになります。
`bisect_left`は、5の左の区間1。
`bisect_right`も同様に、5の右の区間2に含まれる判定をします。

関数名を考えた方は大変センスがありますね。
この図を元に関数名を付けたかは定かではありませんが、`left`と`right`の意味をこのように理解しておくと正しく実装できそうです。

また、`bisect_left`は区間を半開半閉区間、`bisect_right`は区間を半閉半開区間と捉えているとも言えるかもしれません。
# おわりに
一番大切なのは、`bisect_left`は値のindexを返すのではなく、**値の間の区間のindexを返す関数**だということです。
これを覚えておけばこれから先、`bisect_left`と`bisect_right`のどちらを使えば良いのかの見当をつけやすくなると思います。

~~さあ、理解出来たら早くコンテストに戻ってください。こんな文章を読んでいる間にコンテストの時間は進んでいますよ。~~
それでは、さようなら。あなたのお役に立てれば幸いです。
paiza Bランク問題「みんなでしりとり」を Elixir で解いてみた

## はじめに

paiza B ランク問題を Elixir で解いてみます

## みんなでしりとり

しりとりのルールに従って処理し、最後に残ったメンバーを出力します

https://paiza.jp/works/mondai/b_rank_skillcheck_archive/word_chain

```elixir
defmodule Paiza do
  def main do
    [n, k, _m] =
      :stdio
      |> IO.read(:line)
      |> String.trim()
      |> String.split(" ")
      |> Enum.map(&String.to_integer(&1))

    {d, s} =
      :stdio
      |> IO.read(:all)
      |> String.trim()
      |> String.split("\n")
      |> Enum.split(k)

    # 一つ前の単語
    p =
      s
      |> Enum.reverse()
      |> tl()
      |> Enum.reverse()
      |> then(fn x -> [x |> hd() |> String.first() | x] end)

    # {現在のプレイヤー, 現在のプレイヤーインデックス, 前のプレイヤーが敗退したか、 使用済の単語, 残っているプレイヤー}
    init = {1, 0, false, [], Enum.to_list(1..n)}

    {_player, _index, _pre_lose, _used, r} =
      [p, s]
      |> Enum.zip()
      |> Enum.reduce(init, fn {pre_word, word}, {player, index, pre_lose, used, r} ->
        if (!is_nil(Enum.find(d, fn x -> x == word end)) and
            (not String.ends_with?(word, "z")) and
            is_nil(Enum.find(used, fn x -> x == word end)) and
            (pre_lose or String.starts_with?(word, String.last(pre_word)))) do
          # ルール違反がなければ次の人へ
          next_index = if index + 1 == Enum.count(r), do: 0, else: index + 1
          next_player = Enum.at(r, next_index)
          {next_player, next_index, false, [word | used], r}
        else
          # ルール違反があった場合、プレイヤーを減らす
          new_r = List.delete(r, player)
          # プレイヤーが減った場合、インデックスはそのまま
          next_index = if index == Enum.count(new_r), do: 0, else: index
          next_player = Enum.at(new_r, next_index)
          {next_player, next_index, true, [word | used], new_r}
        end
      end)

    r |> Enum.count() |> IO.puts()
    Enum.map(r, &IO.puts(&1))
  end
end

Paiza.main()
```

## 解説

ルール違反をしているかどうかの判定は以下の四つ

- 単語リストにある単語を使っているか
  `!is_nil(Enum.find(d, fn x -> x == word end))`
- `z` で終わっていないか
  `not String.ends_with?(word, "z")`
- 使用済の単語を使っていないか
  `is_nil(Enum.find(used, fn x -> x == word end))`
- 一つ前の単語の末尾文字から始まっているか（ただし、前プレイヤーが敗退している場合は判断しない）
  `pre_lose or String.starts_with?(word, String.last(pre_word))`

`Enum.reduce` で回すため、必要な変数は全て `acc` に集めています

## まとめ

繰り返しながら状態を変化させていくため、結構ややこしくなりました

もっとシンプルにできそうな気もしますが、、、
nftablesでローカルホストからの通信を許可する設定例

```ruby:

sudo nft add rule ip filter input handle 5 tcp dport 8001 accept

```


```ruby:

table ip filter { # handle 3
        chain input { # handle 1
                type filter hook input priority filter; policy accept;
                tcp dport 22 accept # handle 2
                ct state established,related accept # handle 5
                tcp dport 8001 accept # handle 9
                tcp dport 22 accept # handle 8
                drop # handle 3
        }
}


```
ubuntu 24.04 LTSで自宅サーバー構築（ProFTPD を SSL/TLS に設定）

<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www16.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
事前に
https://qiita.com/sqoot610/items/e2a7b3ba8fa30df42d6f
を設定してください。
taisuke@ubuntuserver:~$ sudo apt -y install proftpd-mod-crypto
taisuke@ubuntuserver:~$ sudo vi /etc/proftpd/modules.conf
#21行目 : コメント解除
LoadModule mod_tls.c
taisuke@ubuntuserver:~$ sudo vi /etc/proftpd/proftpd.conf
#143行目 : コメント解除
Include /etc/proftpd/tls.conf
taisuke@ubuntuserver:~$ sudo vi /etc/proftpd/tls.conf
#10-12行目 : コメント解除して変更
TLSEngine               on
TLSLog                  /var/log/proftpd/tls.log
TLSProtocol             TLSv1.3
#27, 28行目 : コメント解除して変更
TLSRSACertificateFile                   /etc/ssl/private/proftpd.pem
TLSRSACertificateKeyFile                /etc/ssl/private/proftpd.pem
taisuke@ubuntuserver:~$ sudo systemctl restart proftpd
FTPクライアントソフトのFileZillaの設定は、
https://qiita.com/sqoot610/items/ce4cf9bc32ca422443d4
を参照してください。
[ファイル] - [サイトマネージャー] を開きます。
![filezilla.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/bbe9d859-b952-fe36-e226-ffa3d37703f1.jpeg)
以下のようにサーバーに接続する情報を入力して接続します。[暗号化] には [明示的な FTP over TLS を使用する] を選択します。
![filezilla2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/34434a1d-922e-e546-bd25-b9bd2aa6992a.jpeg)
接続ユーザーのパスワードを入力して認証します。
![filezilla3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/9906af5b-1c9a-6b66-0243-c21ea11146b6.jpeg)
自己署名の証明書の場合、以下のような警告が表示されますが、問題ないので [OK] ボタンをクリックして先へ進めます。（警告が出ない場合もあります）
![filezilla4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/2fa6ed53-3364-1ace-4e38-02f17aaa6db4.jpeg)
設定に問題なければ以下のように接続できます。問題なくファイル転送ができるか等々確認しておくとよいでしょう。
![filezilla5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858002/410c4a1f-d028-5362-1581-41de1ddf5596.jpeg)
<A HREF="https://px.a8.net/svt/ejp?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" rel="nofollow">月額99円から。WordPressも簡単にインストールできるレンタルサーバー</A>
<amp-pixel src="https://www16.a8.net/0.gif?a8mat=3ZDGSF+2S0ZT6+348+6PJZM" layout="nodisplay"></amp-pixel>
DIST.44 「管理画面から考えるUX　感想

## 概要
今まで友達に誘われて勉強会には行った事はあったのですが、能動的に行った事はありませんでした。
今回、初めて自分の意思で行こうと思い勉強会に行きました。その感想文のようなものです。


## 行った勉強会
[DIST.44 「管理画面から考えるUX」](https://dist.connpass.com/event/324180/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/3310d6ab-46be-e02d-a1c5-18a93e07196b.png)

> Webサービスやアプリを運用していくために、特定のユーザーが操作するための管理画面。このテーマで制作事例、ノウハウ、UX向上を学べる機会は、通常のWebコンテンツ制作より少ないと感じています。

> デザイナーやエンジニアといった作り手の視点だけでなく、使い手であるユーザー視点も含めて、使いやすく分かりやすい管理画面とはどういうものかを考えることで、情報設計、画面設計、デザインシステム、UX……など、管理画面以外に活かせる話も出てくるはずです。

私の職業が大体管理画面作成（業務アプリ）という事もあり、X(旧ツイッター)でこの勉強会の告知を見て「どんぴしゃじゃん！行きてえ！！」と思い行く事に決めました。

## 会場の雰囲気
行く前にはエンジニアが大半かな？と思ったんですが会場の雰囲気的に今回エンジニアとデザイナー半々な感じでした。

## 感想
めっちゃ良かった...やはり自分が興味を持って能動的に行く勉強会はめちゃくちゃ面白くて刺激になる。
- 普段自分が意識してやってる事の再確認が出来た（やっぱそうよね！これ大事よね！！という所）
- UXの改善の実例で感動
- UI/UXデザインの流れを知れた
- 作って終わりじゃなくて、改善して行きたい！という気持ちが更に強くなった
- 使うユーザーのリサーチの重要さを知れた

受託をやっていく上で、やはり一番業務を知っているのはお客さんなので、お客さんの要求通りに作るのが正解なのか、はたまたそうではないのかの塩梅が難しいなぁと思いました。



## 各スライドの概要

[今回発表に使用されたスライド一覧](https://dist.connpass.com/event/324180/presentation/)


### 効果的な管理画面を最短でデザインをするために避けるべき5つの罠と対策
管理画面を作っていく上でのTipsや陥りがちな罠と回避方法を解説
###  行政職員が「ふつうに使える」をめざした管理画面のUX設計とデザインシステム推進
- システムを使うユーザーのリサーチから設計までの工程を解説
###  Cosense(旧Scrapbox)で実現するコンテンツ管理画面
 - 改造が出来て別製品に発展できる自社製品の解説
###  管理画面における反復操作のUXを突き詰めた話
- 1人当たり90秒かかっていた繰り返し業務をどういうメソッドで30秒に短縮したのかを解説。
 
スライドが無かったのでページの一番下にメモを書きます。
### 管理画面の全体UXは利用時品質モデルで考える
- 理論的な目線でUI/UXを説明
    - 良い体験は提供できないが、価値のある体験はできる**価値のある体験→面倒なことが早く終わる**
### オペレーショナルエクセレンスの実現に向けた管理画面の改修
- 要望を受けてやるタイプで開発すると陥りがちな下請け問題に対して、開発チームがどう主体的に動けるようになったのかの説明


## 懇親会
懇親会なるものも初めて参加しました。居酒屋でのランダム配置だったのですが
- エンジニア4人
- デザイナー1人

というメンツになりました。各会社の話や個人のキャリアの話を聞けました。
皆自分の信念や思いを持って働いていて良い刺激になりました。



## PS
2ヶ月後に[youtube公開](https://www.youtube.com/c/distjp)もされるみたいです。

勉強会メモ

https://qiita.com/sgrs38/private/9928ce1e47d0c41758e5


## 管理画面における反復操作のUXを突き詰めた話 (スライド未公開なのでメモを添付します)
  - 在留カード就労資格期限確認管理画面を利用する際に、国が用意したシステムを右のモニターに表示させて、それを見ながら管理画面に内容を丸写しで記録していく運用。
  - フォーカスした理由
    - 利用頻度が高く
    - 利用時間が長い
  - 国のシステムを使って有効状況見て管理画面にてで反映していた
    - 1人当たり90秒→30秒に短縮したい
      - 同じ人に対して毎月1回はしないといけないので少なくしたい。
    - 負荷の大きい反復作業を減らす
      - 目線移動を極力減らし、キーボードのみで操作を完結できるように。
        - エンターキー連打でいい。クリックでも可
        - ９０秒→30秒まで低下できた
          - 誤操作するかと思いきや、取り返しのつかない操作に関しては、もう1人がOKしないと処理が確定しないようにしてある。
      - UXは中級者向け
        - 管理画面に新規ユーザーは少ない前提。**誰でも使える→いつも使う人が効率よく使える**
          - ショートカットを用意する（強要はしない）
友愛数を求めるプログラム

友愛数を求めるプログラムを作ったので簡単な解説と一緒に載せておきます。実行環境はVisual Studio Community 2022バージョン17.10.1です。

# 概要
友愛数とは、異なる2つの自然数の組で、自分自身を除いた約数の和が互いに等しい数のことです。例えば、
220の自分自身を除いた約数の和は
```math
1 + 2 + 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110 = 284
```
284の自分自身を除いた約数の和は
```math
1 + 2 + 4 + 71 + 142 = 220
```
なので互いに等しいため、220と284は友愛数となります。

# コード
友愛数を求めるC++20のコードを以下に記載しています。
```C++:Amicable.cpp
#include <iostream>

//自分自身を除いた約数の和を求める関数
long long sum_divisor(long long x)
{
	long long sum = 1; //約数の合計を入れる変数

	for (long long i = 2; i * i <= x; i++)
	{
        //余りが0なら約数なので加算する
		if (x % i == 0)
		{
			if (i * i == x)
			{
				sum += i;
			}
			else
			{
				sum += i;
				sum += x / i;
			}
		}
	}

	return sum;
}

int main()
{
	long long n; //nまでの友愛数を探す
	std::cin >> n; //nを入力

	for (long long i = 2; i <= n; i++)
	{
		long long j = sum_divisor(i); //整数iの約数の合計を求める

        //友愛数の判定を行う
		if (sum_divisor(j) == i && i < j)
		{
			std::cout << i << ", " << j << std::endl;
		}
	}
}
```

自然数$x$の約数の和を求める関数sum_divisorに関してですが、1は必ず約数に含まれるので合計値を入れる変数sumを1で初期化します。
次に自然数を2から順番に$x$を割り切ることができるか探索します。割り切れたら合計値sumに追加します。この時sumに約数と$x$をその約数で割った商を同時に加算します。こうすることでループの範囲を$x$の平方根以下までに抑えられます。
ここで気を付けないといけないのは$i × i = x$が成立する場合です。約数と商が等しいため、同じ約数が重複して加算されます。なのでif文を使って場合分けをしました。
main関数の中では入力した値$n$までの友愛数を求めます。
友愛数判定のif文の中でi < jを追加していますが、これがないと同じ数字の組が重複して出力されたりするので気を付けましょう。
以下が100000までの友愛数の出力の結果です。
```
220, 284
1184, 1210
2620, 2924
5020, 5564
6232, 6368
10744, 10856
12285, 14595
17296, 18416
63020, 76084
66928, 66992
67095, 71145
69615, 87633
79750, 88730
```

C#とPythonの友愛数を求めるコードも載せておきます。バージョンはそれぞれC#11とPython3.9です。

```C#:Amicable.cs
long sumDivisor(long x)
{
    long sum = 1;

    for (long i = 2; i * i <= x; i++)
    {
        if (x % i == 0)
        {
            if (i * i == x)
            {
                sum += i;
            }
            else
            {
                sum += i;
                sum += x / i;
            }
        }
    }

    return sum;
}

long n = long.Parse(Console.ReadLine());

for (long i = 2; i <= n; i++)
{
    long j = sumDivisor(i);

    if (sumDivisor(j) == i && i < j)
    {
        Console.Write(i);
        Console.Write(", ");
        Console.WriteLine(j);
    }
}
```

```Python:Amicable.py
import math

def sum_divisor(x):
    sum = 1
    
    for i in range(2, int(math.sqrt(x)) + 1):
        if x % i == 0:
            if i * i == x:
                sum += i
            else:
                sum += i
                sum += x / i
                
    return int(sum)

n = int(input())

for i in range(2, n + 1):
    j = sum_divisor(i)
    
    if sum_divisor(j) == i and i < j:
        print(str(i) + ', ' + str(j))
```

# 参考
https://ja.wikipedia.org/wiki/%E5%8F%8B%E6%84%9B%E6%95%B0
Google AI Essentials：生成 AI がタスクに適しているかどうかを判断する

# はじめに

本記事は、Google AI Essentialsのプログラムより、参照させて頂いています。興味を持った方は、是非受講してみてください。

https://www.coursera.org/learn/google-ai-essentials

# 生成 AI がタスクに適しているかどうかを判断する

自分の仕事にどのように 生成 AI を使うかを考えるとき、 AI に何ができて 何ができないかを理解することが重要です。 タスクに生成 AI を適用するかどうかを 評価する一つの方法として 指針となる次のような質問をすると よいでしょう。 

- 質問1: ***<font color="MediumVioletRed">タスクは生成的ですか？</font>***
- 質問2: ***<font color="Darkcyan">そのタスクを反復することで 最良の結果を得ることができますか？</font>***
- 質問3: ***<font color="MediumBlue">適切な監督を行うための 人的リソースはありますか？</font>***

これらの質問の答えをどうやって 生成 AI ツールを使う際の 判断に使うか、 シナリオを使って説明します。

### 質問1

あなたは新しいレストランの グランドオープンに向けて 準備をしているとします。 

AI ツールを使って イベントの宣伝広告を 作成することを 検討していますが、 画像の作成サポートが必要です。 

***<font color="MediumVioletRed">『その仕事は 生成的ですか？ 』</font>***

⇒　答えは「はい」です。 

生成 AI とは テキスト、画像、その他のメディアなどの 新しいコンテンツを生成できる AI の一種であることは既に学びました。 

- 生成 AI は新しいレストランを 宣伝するためのテキストや 画像などの販促資料を作成するのに役立ちます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/099af16d-9131-8f1b-25da-404f23dd4fd6.png" width="350">

### 質問2

***<font color="Darkcyan">『そのタスクを反復すると 最良の結果を得ることができますか？』</font>***
***<font color="Darkcyan">『AI が生成した出力を改善するために、 プロンプトを修正することができますか？ 』</font>***

⇒　答えは「はい」です。 

生成 AI ツールは、 望ましい結果を得るために プロンプトを何度でも編集し、 改良できます。 

- この場合、あなたのレストランが イタリア料理を提供していて AI ツールがパスタの写真を使った 広告を生成したとします。
- 出力を見直した結果、 薪窯から 焼きたてのピザを出すほうが 魅力的だと判断します。 最良の結果が得られるまで、 繰り返しプロンプトを改良します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/490319b8-0be2-bf69-bcfe-6f22a5c98000.png" width="500">

### 質問3

***<font color="MediumBlue">『適切な監督を行うための 人的リソースはありますか？』</font>***

⇒　答えは「はい」です。 

- レストランのオーナーであるあなたか、 従業員の誰かが AI が生成した広告を一般に公開する前に 確認する必要があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/bf9efcd0-a098-2c05-c206-fb07916d32b1.png" width="500">


AI ツールを使用する際は、 常に人間がループに入る ヒューマン イン ザ ループの アプローチを忘れないでください。 あなたかあなたのチームの 誰かが、出力を確認し 編集できるようにします。 
これらの指針となる質問を 自問することで、 特定のタスクに 生成 AI ツールを使用するかを判断できます。 

すべての質問に 「はい」と答えた場合、 生成 AI を使うのが 適切かもしれません。

### 1 つ以上の質問に 「いいえ」と答えた場合は？ 

例えば、レストランで使用する 食材の適正価格を得るために、 地元のサプライヤーと 交渉する必要があるとします。 質問は、 タスクは生成的ですか？です。 この状況での答えは「いいえ」です。 このような仕事はコミュニケーションや 人間関係の構築が必要であり、 人間味を必要とするスキルであるため、 生成的ではありません。

:::note info
仕事で AI を活用する 試みを続ける中で、 生成 AI がタスクを完了する 手助けになるかどうかを 判断するために このような指針になる質問を 自問してみましょう。
:::