OmniAICreator/Qiita-1.07M huggingface dataset:
議論の構造

# 議論のテーマの種類	
- 施策の検討、事実の認定、価値の判断	
- 施策の検討は、ある施策を実行するか否かを決めること。施策によるメリットとデメリットを洗い出し、それぞれの影響の大きさも検討する。これはビジネスの議論の主なテーマである。
- 論理的な議論に適しているのは施策の検討のみ。事実の認定は言葉の定義論争になったり、信頼できるデータを入手しにくかったりして、結論が出にくい。そのため、論理的な議論には向いていない。さらに、価値の判断も論理的な議論に向いていない。価値の判断は各々の価値観が主張の根拠になる。だが、価値観を論理的な議論で変えることが難しい。そのため、結論がまとまりにくい可能性がある。	
# 議論の目的	
- 現状のものより良い結論に到達するためである。ビジネスの場面におけるよりよい結論とは、当事者すべてが満足できるWin-Winのソリューションである。	
- 間違えてはならないのは、議論の相手に勝つことではないということだ。むしろ、勝ち負けを目指すと、負けた方が感情的にイヤな気分になる。関係性も悪化し、仕事においてネガティブな影響を及ぼすリスクがある。

# どう議論するのか
- 参加者の主張の根拠を検証しあう。より具体的には、最適な結論に到達するために、原案や反論の根拠、さらに論証を検証する。論証とは、事実と主張が飛躍なく、ちゃんとリンクしていること。結論が論理的に到達したものならば、ビジネスもその論理通りに進み、結論に到達する。
- 対比の例は、駆け引きや妥協である。駆け引きや根回しは、結論を決めるために論証の検証をせずに、譲歩や戦略を使う。	
- 検証することで、論点が深いレベルに落とし込まれ、当初は見えなかった解決策に到達できる。イメージは以下の図を参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/8a2fb5e0-73e6-3b8a-e105-a5a446ed1f1b.png)
	

### 余談：論理の限界	
- 価値観は論理で変えにくい。例えば、「ビールは苦い。だから好き」という人もいれば、「ビールは苦い。だから嫌い。」という人もいる。苦いから好きな人を、嫌い、に変えるのは難しい。	
- 論理的でない人に論理的な議論をするのは無駄。	
論理的でない人とは、根拠の検証をしない人。そういう人には、信頼関係を構築するなど別のアプローチを使い、自分の主張を支持してもらう。
- 論理的な主張より固定された習慣と整合する主張の方が正しいとされる。もしも習慣を論理的な議論で変更するならば、周到な準備が必要だ。理論武装とデータ、人間関係により主張の味方を集める必要がある。	

# 議論の構造	
- 議論における主張は、**想定される反対意見への反論も含意**している。すなわち、一番最初の主張も、反対論者を説得する意図を暗に含んでいるのだ。たとえば、「A氏の意見に賛成です」という主張は「反対です」という意見を想定し、それに先手を打って賛同を表明していることになる。	
イメージは以下の図。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/ec816a38-a8a2-3343-4339-70bfe8824b74.png)

- 主張は、対抗する意見より自分の主張の方が正しいことを説得する行為。それゆえ、主張には根拠が必要である。そして、根拠は具体的で詳細であるほど、論理性が生まれる。根拠には、理由とデータがある。理由とは、主張を導き出す前提である。データとは、主張または理由を裏打ちする具体的な事実である。概念図と実例は以下の図を参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/29869193-4029-f3a7-882c-2df3667e92ce.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/4fc0ff9e-056a-b769-4bf8-b73fd6d023a8.png)

- 理由にさらなる根拠が必要な場合がある。理由も一種の主張であるからだ。それゆえ、主張に**小さな主張がリンク**した構造を持つ。このリンクが欠落しないようにチェックをする必要がある。そして、根拠が当たり前(自明)になった時、それ以上根拠を深める必要がなくなる。各理由のステップに、データがあると説得力が上がる。ちなみに、他人に説明する時は、AならばB, BならばC...という順序で説明する方が分かりやすい。
議論の構造の概念図と具体例は以下を参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/e4491dc0-f77d-6ffa-9aa1-ebdc913255c2.png)

	
# 議論の要素	
- 原案には、**問題解決型**と**施策提案型**がある。問題解決型は、現状と理想のギャップを埋めるための施策を主張する。施策提案型は、理想とのギャップとは関係なく現状を改善する施策を主張する。
- 原案への反論には、**主張型反論**と**論証型反論**がある。主張型は、原案の主張に反対する主張だけを述べる。ここで、相手の原案の根拠は検証しない。それに対して論証型は原案の根拠が十分に原案をサポートしていない、あるいは原案そのものが正しくないことを述べる。それにより反論する。
- 反論には、両方が必要だ。論点を進化させるために必要なのは論証型反論である。一方、「すべき」という原案のデメリットも議論の対象になるようにするためには、主張型反論が必要。論証型反論だけだと、「すべき」の原案の中のメリットだけが議論の焦点になってしまうからだ。
- 原案への一番最初の反論の論点は3種類になる。
・メリットは生じない
・メリットは重要ではない
・デメリットが生じる
さらに、その最初の反論へのさらなる反論の論点は以下の2種類になる。
・メリット/デメリットは生じるか
・メリット/デメリットは大きいか

上記の議論の要素と構造を踏まえた概念図と具体例は以下の図を参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/32622552-249a-12a3-504d-eb49fa48d0b1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1081780/190d45fe-20ff-d8e3-e28c-fea913346492.png)

# 参考資料
論理が伝わる 世界標準の「議論の技術」 Win-Winへと導く5つの技法 (ブルーバックス 1914)

https://www.amazon.co.jp/dp/4062579146
Rubyでランダムにグループ分けするプログラムを作成する

## はじめに
[前回](https://qiita.com/at-sacai/private/9d46b20adf89e10e7f81)に引き続き、Ruby学習のアウトプットとして今回はランダムにグループ分けをするプログラムを作成しました。

上記の内容について、備忘のためにメモ書きを残しておくことにします。

## 仕様
- 前提
    - A、B、C、D、E、Fという6人のグループがあった
    - 定期的に、6人でLINEのグループ通話をしている
- 課題
    - 6人でLINEのグループ通話は会話しづらい
- 要件
    - 3人と3人、または2人と4人にランダムにグループ分けを行いたい
- 補足
    - 本プログラムは実行するたびに、結果が変わるようにすること
    - 表示結果はアルファベット順に並び替えること

## アウトプットイメージ

アウトプットイメージは、以下の通りです。

``` plaintext
$ ruby random.rb
["B", "C"]
["A", "D", "E", "F"]
```

## 検討

まずは、プログラムの処理の流れを言語化します。

1. 6人グループの配列を作成する
1. 1.で作成した配列をランダムに並び替えて、3-3 または 4-2 に分割する
1. 2.の結果をアルファベット順に並び替えて出力する

上記をコードで書くと、次のようになります。

``` ruby:random.rb
arr = %w[A B C D E F].shuffle!
num = rand(2)

if num == 0
  result = arr.each_slice(3).to_a
  p result[0].sort, result[1].sort
elsif num == 1
  result = arr.each_slice(4).to_a
  p result[0].sort, result[1].sort
end
```

出力結果もアウトプットイメージと同じであるため、問題なさそうです。

![スクリーンショット 2024-06-30 22.05.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290540/759b5629-860d-2393-b31a-b94626093e49.png)


### リファクタリングする

以下の部分について、`num`に3か4が入るようにすれば条件分岐が不要そうです。

``` ruby
arr.each_slice(num).to_a
```

リファクタリングすると、コードが少し短くなりました。

``` ruby:random.rb
arr = %w[A B C D E F].shuffle!
num = rand(3..4)

result = arr.each_slice(num).to_a

p result[0].sort, result[1].sort
```

### 出力系メソッドの違い（puts、print、p）

今回は出力のために`p`メソッドを利用しましたが、出力系のメソッドは複数あり混乱しやすいため表で整理しておきます。

補足となりますが、`p`メソッドを利用した理由は以下2点となります。

- 出力後に改行があるため
- 配列の要素ごとに改行して表示されないため

|メソッド名  |出力後の改行  |配列の表示  |文字列変換  |戻り値  |
|---|---|---|---|---|
|puts  |あり  |要素ごとに改行  |to_s  |nil  |
|print  |なし  |改行しない  |to_s  |nil  |
|p  |あり  |改行しない  |inspect  |引数のオブジェクト  |

引用：[プロを目指す人のためのRuby入門[改訂2版] 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plus)](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E6%94%B9%E8%A8%822%E7%89%88-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design/dp/4297124378/ref=sr_1_2_sspa?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2QOIZK1A9QF3Q&dib=eyJ2IjoiMSJ9.2LfTLqfglMz6c1N_gAH2KIu5RnH0zLD_-RYWo6EdQpuakdkq13d6EOoLqNRP3iFI8AEwE6BEEroU8muu3yebS7iIv8wapdrI1YzOeaNdJXvEAPeOZEQrz88RNcpi0ZlUfJ2uQ74O6g9JZerngAsFKk9i2uIwuMUYHivDWuxi1ZQuvUpX3o8Jwu26pQUQr-G3_3AaUtqFoMhKvwHO144ghhvhwS0nR8fqR_QWozR_wXQsI53VYx5U0I42Xy3Sip5xY5iUkyKrPdKWtT78RK7hYR_2kOhkWnphL4-rMeprMQA.PkhmosY2MB0yuGVyOSpuqM3d70IyFElSUSAI57oCEB8&dib_tag=se&keywords=ruby&qid=1719724264&sprefix=ruby%2Caps%2C303&sr=8-2-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1)

## おわりに

本課題に取りかかる前は、一見簡単そうに見えましたが実際にやってみると難しかったです。

コードの行数は少ないですが、多くの学びがありました。
大規模言語モデル（LLM）のソフトウェア統合：最新分類法の提案と評価

# 大規模言語モデル（LLM）をソフトウェアコンポーネントとして活用するための分類法


## はじめに
この記事は、私の論文のキャッチアップの一環として、大規模言語モデル（LLM）をソフトウェアコンポーネントとして活用するための最新の分類法について紹介するものです。研究者や開発者の皆さんにとって、有用な情報を提供できれば幸いです。

## 概要
この論文「Large Language Models as Software Components: A Taxonomy for LLM-Integrated Applications」では、大規模言語モデル（LLM）をソフトウェアコンポーネントとして統合するための分類法を提案しています。LLMは、単独のエージェントやソフトウェア開発のツールとして広く利用されていますが、LLMを活用するソフトウェアシステム（LLM統合アプリケーション）の工学は新たな分野として台頭しています。この論文は、LLM統合アプリケーションの体系的な分析と記述を行うための枠組みを提供し、さまざまなLLMの利用方法と統合の選択肢を示しています。

## 論文の情報
- **タイトル**: Large Language Models as Software Components: A Taxonomy for LLM-Integrated Applications
- **リンク**: [https://arxiv.org/pdf/2406.10300v1](https://arxiv.org/pdf/2406.10300v1)
- **発表日**: 2024年6月18日
- **著者**: Irene Weber
- **所属**: Kempten University of Applied Sciences, Germany
- **メール**: irene.weber@hs-kempten.de

## イントロダクション
大規模言語モデル（LLM）は、テキスト理解、創造的作業、コミュニケーション、知識作業、コード作成において優れた能力を発揮し、医療、法務、マーケティング、教育など多くの分野で採用されています。本論文では、LLMをソフトウェアコンポーネントとして統合する可能性と、その際の用語、概念、方法について詳述します。

## 分類法の開発
分類法の開発には、以下のステップを経ました：
1. 既存のLLM統合アプリケーションを分析し、関連する次元を特定。
2. 分類法を追加のケースに適用し、評価。
3. 13の次元を特定し、LLMコンポーネントを特徴付け。

## LLMコンポーネントの次元
LLMコンポーネントは以下の次元に沿って特徴付けられます：
- **Invocation（呼び出し）**: ユーザーがLLMとどのようにやり取りするか。
- **Function（機能）**: アプリケーションがLLMをどのように利用するか。
- **Prompt（プロンプト）**: LLMに入力されるプロンプトの生成方法。
- **Skills（スキル）**: LLMが提供する機能。
- **Output（出力）**: LLMの出力形式とその消費方法。

## 結論
この分類法は、LLM統合アプリケーションの記述に効果的であり、理論構築やシステム開発に貢献します。多くのクリエイティブな方法でLLMを活用することが可能ですが、課題も依然として存在します。それにもかかわらず、LLMの統合はソフトウェアシステムの構築方法に革命をもたらす可能性があります。

## ブログ筆者の賛否両論

### 賛成意見
- **LLMの活用方法について体系的な枠組みを提供している**:
  - この論文は、LLMをどのようにソフトウェアに組み込むかについての詳細なガイドラインを提供しています。研究者や開発者にとって、非常に実用的で役立つ内容です。
- **理論構築や実務において有用である**:
  - 提案された分類法は、新しい理論の構築や実務での応用をサポートし、LLMの統合に関する理解を深めるのに役立ちます。
- **多様な分野での応用が示されており、LLMの可能性を広げている**:
  - 具体的な応用例が豊富に紹介されており、医療、法務、マーケティング、教育など、さまざまな分野でのLLMの活用方法が示されています。

### 反対意見
- **実際の実装例が限られており、理論に偏りがちである**:
  - 理論的には非常に有用ですが、実際の実装例が少ないため、具体的な適用方法や現実の問題に対する解決策が不足しています。より多くの実世界のケーススタディが必要ですね。
- **LLMの倫理的問題や事実誤認（ハルシネーション）についての議論が不足している**:
  - LLMがバイアスを含む可能性や、事実誤認を引き起こすリスクについての詳細な議論が足りません。これらの問題に対する対策やガイドラインを提供することで、LLMの信頼性を高める必要があります。
- **一部のLLM統合アプリケーションの技術的詳細が不明瞭である**:
  - 論文内で言及されているいくつかのアプリケーションについて、技術的な詳細や具体的な実装方法が十分に説明されていない点が気になります。再現性や他の開発者による応用を容易にするために、より詳細な技術的説明やコード例の提供が望まれます。
Azure: azd メモ

# 背景

azd コマンドを使う際の基本をメモ

# 前提

az コマンドは、サブスク依存なので、サブスク切り替えつつ動作
az account list -o tabledefault
az account set -s {subscription name/id}
コマンドによっては、 -s {subscription name/id} があるので切り替え不要の場合も

対して、
azd コマンドは、デフォルト環境を元に実行される

環境設定は以下に保存される

```powershell: 環境構成
.azure/
├── {env name}/
│   ├── .env
│   └── config.json
├── {env name2}
└── ...
```

[上記構成図はここで](https://tree.nathanfriend.io/?s=\(%27options!\(%27fancy!true~fullPath!false~trailingSlash!true~rootDot!false\)~3\(%273%27.azure-\)*0.env*0config.json-2\)*...%27\)~version!%271%27\)*%5Cn0-*\(env%20name0%20%203source!%0130-*)

https://tree.nathanfriend.io

# よく使うコマンド

## azd env

環境関連

### azd env new: 環境作成

環境名を指定して作成。これで、Defaultも変わっている筈

> azd env new {env name}

.azure　の下に、<code>{env name}</code> フォルダと、<code>.env</code>, <code>config.json</code> が生成される

### azd env list: 環境一覧表示

今ってどれが default だっけ？と探すときに使う感じ

> azd env list

```
NAME                           DEFAULT   LOCAL     REMOTE
{env name}                      true      true      false
```

### azd env get-values: 環境変数の一覧取得

.env 見るようになるとあんまり使わない

> azd env get-values

### azd env select: 環境のDefault切り替え

心配性で、<code>--environment</code> 指定するようになると、使わなくなる :sweat_smile: 

> azd env select {env name}

default 変更後の確認の為に、 list で表示したほうが、とか思っちゃうし・・

## azd provision: インフラのみのデプロイ

bicep からのインフラ生成のみを行う。

## azd deploy: アプリデプロイ

App Service へのデプロイのみを行う。

## azd up: インフラ＆アプリ　デプロイ

provision + deploy 
ただ、なんか up が失敗することが合って、よく deploy を再度することがある印象
今度起きたら調査しないと

## azd down: リソース解放

provision/up で展開した bicep でのリソース群の解放。
Yes/No を聞かれたくない場合は、以下のように<code>--force</code> <code>--purge</code> を付けて実施 

```powershell
azd down --environment {env name} --force --purge
```

## azd config: region/subscription の設定と確認

- Azure は、サブスクリプションに対してコマンド実行をするので、 config で設定する必要がある

デフォルトは以下に保存されている <code> $HOME/.azd </code>

> azd config list

> azd config show

```
{
  "defaults": {
    "location": "japaneast",
    "subscription": "aec74d9f-56b4-418a-b41e-0a59b13bd0ce"
  }
}
```

# documents

[Azure Developer CLI リファレンス](https://learn.microsoft.com/ja-jp/azure/developer/azure-developer-cli/reference)

# あとがき

節約の為にも不要なものは <code>az down</code> で解放しておこう。
Livebook で現在のノートブックに接続されているノードを確認する

## はじめに

Livebook のバージョン 0.13 が先日リリースされました

https://github.com/livebook-dev/livebook/releases

その中で、接続されたノードの一覧表示という機能が追加されていたので紹介します

## 接続されたノードの一覧

ノートブックを開いているときの左メニュー、 CPU アイコンをクリックすると RUNTIME パネルが開きます

その最下部に "CONNECTED NODES" が追加されました

![スクリーンショット 2024-06-30 21.35.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/d663c499-55ec-c0ae-489d-cb0cb6661d28.png)

当然、デフォルトでは何にも接続されていないので "No connected nodes" と表示されています

## ノードの接続

2 つノートブックを開いて確認してみましょう

- ノードA: 接続される側
- ノードB: 接続する側

ノードAで以下のコードを実行します

```elixir
{Node.self(), Node.get_cookie()}
```

実行結果は以下のようになります

```elixir
{:"livebook_c4yiboev--3w6pfpcp@127.0.0.1",
 :"c_aDpdBhZVT68qbrtvZcNyiNKHfEno6NGBRGFlubse-UVquu6Tl0xs"}
```

これはノードAのノード名とクッキーです

ノードBで以下のコードを実行します

```elixir
Node.set_cookie(
  :"livebook_c4yiboev--3w6pfpcp@127.0.0.1",
  :"c_aDpdBhZVT68qbrtvZcNyiNKHfEno6NGBRGFlubse-UVquu6Tl0xs"
)
Node.connect(:"livebook_c4yiboev--3w6pfpcp@127.0.0.1")
```

`set_cookie` にはノードAのノード名、クッキーを指定しています

`connect` にはノードAのノード名を指定しています

これを実行した時点でノードAとノードBは接続されます

ノードBの "CONNECTED NODES" にノードAが追加されています

![スクリーンショット 2024-06-30 21.41.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/dca4b16f-624c-f877-3648-b5aaf0596f9b.png)

ノード名の末尾が省略されていますが、マウスオーバーすると全体が確認できます

![スクリーンショット 2024-06-30 21.41.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/7f37bd27-2ccc-e3ab-2b7b-5c3720c87c30.png)

この時点ではノードAの "CONNECTED NODES" は "No connected nodes" のままですが、次に何らかのセルを実行した段階でノードBが表示されます

## まとめ

接続先ノードは `Node.list(:connected)` というようにコードを実行して確認していましたが、 Livebook の機能として確認できるようになりました

分散処理が得意な Elixir らしい機能ですね
Windows Server 2022 のリモートデスクトップ環境で Explorer 関連の動作が不安定な事象が発生した際の対処方法(tabtip関連）

# 概要

Windows Server 2022 のリモートデスクトップ環境で Explorer 関連で下記のような障害が発生した場合の対処方法となります。

・ エクスプローラーがフリーズする
・ タスクバーをクリックした際の応答が遅い
・ スタート メニューが反応しない

また エクスプローラーに限定せず、パフォーマンス低下が発生する場合にも有効な場合があります。

# 確認と対処

1． 事象が起きる接続先サーバーで下記レジストリを展開します。

HKEY\_LOCAL\_MACHINE\SYSTEM\Software\Microsoft\TIP\TestResults

2\. 配下にキーが存在しているか確認を行い、キーが存在する場合には念のためエクスポートを行いバックアップします。

3\. HKEY\_LOCAL\_MACHINE\SYSTEM\Software\Microsoft\TIP\TestResults 配下のキーを削除します。

※ TestResults キー自体は残します。
多数のキーがある場合にはコマンド プロンプトを管理者として開き、下記コマンドを実行することで一括削除します。

Reg Delete HKEY\_LOCAL\_MACHINE\SYSTEM\Software\Microsoft\TIP\TestResults\ /f


4\. 接続先サーバーを再起動します。

5\. 事象が解消したか確認をします。


# 補足

Microsoft オフィシャルといえる情報がないのですが、海外サイトには本事象並びに対処策についての情報が複数あり、レジストリの削除とともに tabtip.exe ならびに tabtip32.exe のリネームと  TabletInputService service (Touch Keyboard and Handwriting Panel Service)を無効にする手順で解消するとの情報が複数あります。

[ Windows Server 2019/2022： Terminal Server / RDS with laggy or freezing Taskbar - tomaskalabis.com](https://tomaskalabis.com/wordpress/windows-server-2019-2022-terminal-server-rds-with-laggy-or-freezing-taskbar/)

[ Server 2022 and Teams Bloats HKEY_LOCAL_MACHINE\SYSTEM\Software\Microsoft\TIP\TestResults\ - Microsoft Q&A](https://learn.microsoft.com/en-us/answers/questions/752491/server-2022-and-teams-bloats-hkey-local-machinesys?page=1)

ただし、下記のように IME に問題が発生する可能性があるようなので、定期的にレジストリを削除するにとどめておいたほうが良いように思われます。

[ そのサービスを止めないで！～タッチ キーボードを無効化する正しい方法～ - Windows Blog for Japan](https://blogs.windows.com/japan/2020/10/19/dont-stop-the-service-or-how-to-disable-touch-keyboard-correctly/)

なお、品質更新プログラムの修正内容には本事象に関連する情報はないものの、記載がないまま問題が修正されている場合もあるので、品質更新プログラムを適用するこも検討してください。
BinarySearchで特定値の頻度を見つける方法

# Intro
upperBoundとlowerBoundはバイナリ探索(binary search)に基づく二つの関数で、整列された配列またはリストから特定の値の位置を探すのに使われます。 この二つの関数の違いと役割は次のとおりです。
> ここでBinary Searchをする前に、arrayは整列されていなければなりません。

## LowerBound
lowerBound関数は、特定の値targetが配列またはリストに初めて現れる位置を探します。 もし、targetが配列に存在しない場合、targetより大きい値が初めて現れる位置を返します。 つまり、target以上の最初の位置を探します。

例:
並べ替えられた配列 arr = [1、2、4、4、5、6] があると仮定します。

lowerBound(arr, 4) は2 を返します。 (配列で4が初めて現れる位置)
lowerBound(arr, 3) は2 を返します。 （3は配列にないので、3より大きい値が初めて現れる位置）

## UpperBound
upperBound関数は、特定の値targetが配列またはリストで初めて超過する位置を探します。 つまり、targetより大きい値が初めて現れる位置を返します。

例:
並べ替えられた配列 arr = [1、2、4、4、5、6] があると仮定します。

upperBound(arr, 4) は4 を返します。 (配列で4より大きい値が初めて現れる位置)
upperBound(arr, 3)は2を返します。 (3より大きい値が初めて現れる位置)

## Difference
lowerBoundは配列でtargetが初めて現れる位置を返すか、targetが配列にない場合はtargetより大きい値が初めて現れる位置を返します。
upperBoundは配列でtargetより大きい値が初めて現れる位置を返します。
2つの関数の違いは次のような例で要約できます:

整列された配列 arr = [1、2、4、4、5、6] において target = 4 のとき:

lowerBound(arr, 4) は2 を返します。 (4が初めて現れる位置)
upperBound(arr, 4) は4 を返します。 (4より大きい値が初めて現れる位置)

``` java

import java.util.ArrayList;
import java.util.Collections;

public class Main {

    public static void main(String[] args) {
        ArrayList<Long> array = new ArrayList<>();
        // Array should be sorted!
        Collections.addAll(array, 1L, 2L, 4L, 4L, 5L, 6L);

        long target = 4;

        long lower = lowerBound(array, target);
        long upper = upperBound(array, target);

        System.out.println("Lower Bound of " + target + ": " + lower); // Should print 2 index
        System.out.println("Upper Bound of " + target + ": " + upper); // Should print 4 index
        System.out.println("Occurrences of " + target + ": " + (upper - lower)); // 2 counts 
    }

    public static long lowerBound(ArrayList<Long> array, long target) {
        int left = 0;
        int right = array.size();
        while (left < right) {
            int mid = (left + right) / 2;
            if (array.get(mid) < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }

    public static long upperBound(ArrayList<Long> array, long target) {
        int left = 0;
        int right = array.size();
        while (left < right) {
            int mid = (left + right) / 2;
            if (array.get(mid) <= target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}

```

# Summary
lowerBoundは、target値が最初に現れる位置を探します。
upperBoundは、target値より大きい値が最初に現れる位置を探します。

upperBound-lowerBoundは配列からtarget値の出現回数を計算します。

この結果は、並べ替えられた配列やリストから特定の値の頻度を計算するのに非常に役立ちます。 特に、特定の条件を満たす部分配列の和を見つける問題で活用できます。

> 個人的にはずっと忘れてしまう部分なので、この機会にまとめて作成してみます。 気になることがありましたら、コメントは歓迎します。
系統抽出法の定義が理解しにくい

# 目的
統計検定2級の受験に向けてのんびり議事録です。
今回は第1回です。

# 意義
受験者の理解を助けるような内容であること。

# 統計検定2級のテーマ整理
1．１変数，２変数の記述統計の分野
2．データ収集，確率，分布の分野
3．推定，検定，線形モデルの分野

## 2．データ収集，確率，分布の分野
標本抽出法は、以下の4つに分類されます。

・系統抽出法
・層化抽出法
・集落（クラスター）抽出法
・二段抽出法

今回は系統抽出法について見ていきます。

## 系統抽出法の一般的な定義
引用：[統計用語集](https://bellcurve.jp/statistics/glossary/1283.html)

>系統抽出法
systematic sampling
母集団に通し番号をつけ、それ以下の通し番号を持つ点から無作為に一点目の標本を抽出する。その点から等間隔で（抽出間隔ごとに）標本を抽出するような方法。

最初にこの定義を見た際に、以下のような疑問が生まれた。

### 疑問
母集団N=1~100のとき、無作為に選んだ1点がN=70になるとき、N=1~69は標本抽出されないのか？

### 仮説
等間隔で標本取得を行い、N=100まで到達したらN=0へ、と循環するように取得するという理解でいいかもしれない。

## python：一般的な実装

※ここでいう一般的な実装とは、よく検索に引っ掛かるので目にするという意味です。
参考文献：[github_Sampling-in-Python_index[409]](https://github.com/Mishu-Dhar10/Sampling-in-Python)

```Keito_Chushutsuho_general.py
import random
import matplotlib.pyplot as plt

def systematic_sampling(population, sample_size):
    N = len(population)
    k = N // sample_size
    start = random.randint(0, k - 1)
    sample_indices = [start + i * k for i in range(sample_size)]
    sample = [population[i] for i in sample_indices]

    return sample_indices, sample

# Example population
population = list(range(1, 101))
sample_size = 10

# Perform systematic sampling
sample_indices, sample = systematic_sampling(population, sample_size)
print("抽出された標本:", sample)

```

出力結果
```output
抽出された標本: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
```

この実装では、予め全体のN=100をサンプルサイズで割った値（100 ÷ sample_size = 10）を計算しているため、初期位置は1～10の間で決定される。これは定義に従った「無作為に最初の標本を抽出する」方法と言えるのだろうか？

## python：定義に従った実装

```Keito_Chushutsuho_defined.py
import random
import matplotlib.pyplot as plt

def systematic_sampling(population, sample_size):
    N = len(population)
    k = N // sample_size
    # 1からkまでの間で初期位置を無作為に選択
    start = random.randint(0, N - 1)
    # 系統抽出の標本インデックスを計算
    sample_indices = [(start + i * k) % N for i in range(sample_size)]
    sample = [population[i] for i in sample_indices]

    return sample_indices, sample

# Example population
population = list(range(1, 101))
sample_size = 10

# Perform systematic sampling 10 times
results = []
for trial in range(10):
    sample_indices, sample = systematic_sampling(population, sample_size)
    results.append(sample)

# Print results
for i, sample in enumerate(results):
    print(f"試行 {i+1}: 抽出された標本: {sample}")
```

出力結果
```output
試行 1: 抽出された標本: [12, 22, 32, 42, 52, 62, 72, 82, 92, 2]
試行 2: 抽出された標本: [54, 64, 74, 84, 94, 4, 14, 24, 34, 44]
試行 3: 抽出された標本: [18, 28, 38, 48, 58, 68, 78, 88, 98, 8]
試行 4: 抽出された標本: [95, 5, 15, 25, 35, 45, 55, 65, 75, 85]
試行 5: 抽出された標本: [82, 92, 2, 12, 22, 32, 42, 52, 62, 72]
試行 6: 抽出された標本: [74, 84, 94, 4, 14, 24, 34, 44, 54, 64]
試行 7: 抽出された標本: [36, 46, 56, 66, 76, 86, 96, 6, 16, 26]
試行 8: 抽出された標本: [35, 45, 55, 65, 75, 85, 95, 5, 15, 25]
試行 9: 抽出された標本: [90, 100, 10, 20, 30, 40, 50, 60, 70, 80]
試行 10: 抽出された標本: [96, 6, 16, 26, 36, 46, 56, 66, 76, 86]
```

###結論
今回の議事録では、統計検定2級の学習に向けて、特に「データ収集、確率、分布の分野」の中から「系統抽出法」に焦点を当てました。系統抽出法の定義と実装方法を詳しく見ていく中で、統計学の基礎的な概念をしっかりと理解することの重要性を再確認しました。

Pythonを使った実装例では、一般的な方法と定義に忠実な方法の違いを具体的に示すことで、理論と実践の結びつきを体感できました。このようなアプローチは、ただ知識を得るだけでなく、実際のデータ分析に応用する力を養う上で非常に有効です。


引き続き、統計検定2級の合格を目指して、皆さんと一緒に学びを深めていきたいと思います。これからも一緒に頑張りましょう！
Squidのアクセスログに記録される情報をカスタマイズする

# 環境

- Ubuntu 24.04 LTS (WSL)
- Squid 6.6

# デフォルトのログを読み解く

デフォルトのsquid.confの設定で出力されるアクセスログは以下のようになります。
```
1719738851.889    642 ::1 TCP_MISS/200 23771 GET http://www.squid-cache.org/Doc/config/ - HIER_DIRECT/104.130.201.120 text/html
```
アクセスログに記録する情報はlogformatで定義することができ、デフォルトの場合は `squid` という既定のフォーマットになるようです。

>The default formats available (which do not need re-defining) are:
>
>logformat squid      %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt
logformat common     %>a - %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st %Ss:%Sh
logformat combined   %>a - %[un [%tl] "%rm %ru HTTP/%rv" %>Hs %<st "%{Referer}>h" "%{User-Agent}>h" %Ss:%Sh
logformat referrer   %ts.%03tu %>a %{Referer}>h %ru
logformat useragent  %>a [%tl] "%{User-Agent}>h"
[squid : logformat configuration directive](http://www.squid-cache.org/Doc/config/logformat/)

## logformat squidの内容

squidの定義は以下のようになっています。
```
logformat squid %ts.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %m
```
実際のログと突き合わせてみます。
| 1 | 2 | 3 | 4 | 5 |
|:-|:-|:-|:-|:-|
| 1719738851.889 | 642 | ::1 | TCP_MISS/200 | 23771 |
| %ts.%03tu | %6tr | %>a | %Ss/%03>Hs | %<st |

| 6 | 7 | 8 | 9 | 10 |
|:-|:-|:-|:-|:-|
| GET | http://www.squid-cache.org/Doc/config/ | - | HIER_DIRECT/104.130.201.120 | text/html |
| %rm | %ru | %[un | %Sh/%<a | %mt |

1. エポック秒.ミリ秒
2. レスポンスタイム（単位はミリ秒）
3. 接続元IP
4. Squidリクエストステータス/HTTPステータスコード
5. リクエストサイズ
6. リクエストメソッド
7. リクエストURL
8. %エンコードされたuser name
9. Squid階層ステータス/接続先IP
10. MIMEタイプ

# 別の定義済みlogformatに変更する

いくつかのlogformatは既に定義済みのようなので、試しにcombinedに変更してみます。`squid.conf` に下記の行を追加します。
```conf:squid.conf
...
access_log daemon:/var/log/squid/access.log combined
```
[squid : access_log configuration directive](http://www.squid-cache.org/Doc/config/access_log/)
```
~$ sudo systemctl restart squid
```
```text:access.log
::1 - - [30/Jun/2024:18:03:11 +0900] "GET http://www.squid-cache.org/Doc/config/ HTTP/1.1" 200 23771 "http://www.squid-cache.org/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0" TCP_MISS:HIER_DIRECT
```
アクセスログの形式が変わり、User Agent等が表示されるようになりました。

# 独自のlogformatに変更する

「squid」をベースに、時刻を人間に読みやすい形式に変更したいと思います。localtimeという名前のlogformatを定義し、access_logで指定します。
- `%6` は桁指定で6桁
- `%03` は桁指定3桁かつ3桁未満の場合は先頭を0埋め
```conf:squid.conf
...
logformat localtime %{%Y-%m-%d %H:%M:%S}tl.%03tu %6tr %>a %Ss/%03>Hs %<st %rm %ru %[un %Sh/%<a %mt
access_log daemon:/var/log/squid/access.log localtime
```
```
~$ sudo systemctl restart squid
```
```text:access.log
2024-06-30 18:42:23.396    775 ::1 TCP_MISS/200 23771 GET http://www.squid-cache.org/Doc/config/ - HIER_DIRECT/104.130.201.120 text/html
```

# 参考資料

- [squid : logformat configuration directive](http://www.squid-cache.org/Doc/config/logformat/)
- [squid : access_log configuration directive](http://www.squid-cache.org/Doc/config/access_log/)
- [Squidのログフォーマット設定 - じゅのぶろ](https://jnox.hatenablog.com/entry/squid/log-format)
画像認識プログラム作成に向けて(windows)

今回は機械学習に関する書籍を用いて学習を行った、環境設定で非常に苦労した。
私のような初心者がまず陥る課題は何かしらのアプリケーションが入ってり、事前に実行する必要があるプロンプトを実行しておらず、書籍に記載の通りコマンドプロンプトの記号を入れてもエラーが頻発することです。私が発生させたエラー例をざっくりとまとめます。

1.git cloneを実行してもエラーが発生する

サンプルコードなどをダウンロードする際にgit cloneでダウンロードさせる書籍も多いが、
何もしないまま、このコマンドを実行してもエラーが出てしまいます。
事前に、「git for windows」というアプリケーションをダウンロードする必要があります。

![キャプチャsadadadss.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/92e8b83a-10cf-95e5-816e-8cdb05e94952.png)

2.書籍に記載しているsudo〇〇でエラーが発生する
 sudoはLinux向けのコマンドです。windowsでは通常は使用できません。windowsでsudoを使用出来るようにする設定を行うか、別の方法を調べましょう。


3.書籍に記載している通り、＄ 〇〇で実行したらエラーが発生する 
　＄は抜いてください。


何でエラーが起きた際は、悩まずにエラー内容をコピペしてgoole先生やchatgptを用いて調べると簡単に分かる場合が多いです。初心者は悩まず調べましょう。
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827595/2d0d1ae1-6975-26fa-186f-c707c4f3a69d.png)
【prisma】Next.js (TypeScript)+MongoDBでmongooseからprismaへ切り替える

# きっかけ
Udemyで[Next.js](https://www.udemy.com/course/nextjs-fullstack/)のコースで勉強した際に、DBレイヤーがMongoDB+mongooseでの実装で後々、RDBやgraphqlに書き換えたいと思ったので、DBはMongoDBのままでprismaへまず書き換えてみました。

# How to do (基本はPrisma公式に準拠)
1. Prisma　CLI, Prisma Clientのインストール
    ```
    npm install prisma --save-dev
    npm install @prisma/client
    ```

1. Prismaの初期化
    ```
    npx prisma init --datasource-provider mongodb
    ```
1. .envにDATABASE_URLの追加
1. データベースからスキーマ情報の取り込み
    ```
    npx prisma db pull
    ```
1. スキーマ情報の調整（リレーションや項目など）
    - スキーマ書き換えたら以下コマンドでクライアントの更新を実施 
        ```
        npx prisma generate
        ```
1. Prisma Clientへの置き換え
    - Prisma Clientの定義
        ```src/prisma.ts
        import { PrismaClient } from '@prisma/client'

        const prisma = new PrismaClient({
            log: ["query"],
        })

        export default prisma
        ```
    - Prisma Clientのインポート
        ```
        import  prisma from '@/prisma';
        ```
    - クエリの書き換え
        https://www.prisma.io/docs/orm/prisma-client/queries/crud
    - スキーマ情報のインポート
         ```
        import type { tasks } from "@prisma/client";
        ```       


# Ref
- Prisma公式 - Migrate from Mongoose -

https://www.prisma.io/docs/orm/more/migrating-to-prisma/migrate-from-mongoose
社内で嬉しかった出来事n選！

# はじめに
社内で遭遇して嬉しかった出来事をまとめてみました。自分も見習っています。


# エラー発生時に真っ先に問題の切り分けをしてくれる
「この箇所では異常ないみたいです。こちらについてはどうですか？」

# 困っているとこちらから呼びかける前にzoomに入ってくれる

「大丈夫そうですか？」

# 遅くまで作業したら必ずお礼を伝えてくれる

「遅くまでご対応いただきありがとうございました！」

# 急な休みでも理解してくれる

「午前中だけで大丈夫ですか？」「お互い様です！」

# チャットルームで必ずレスポンスがある

「メッセージでなくても絵文字とかで」

# 新しい取り組みに賛同してくれる

「とりあえずやってみますか」


# おわりに
自分がされて嬉しかったことは他の人にもしよう！
【EC2/Cron】実装したAPIを活用して「Qiitaの公式更新情報」を月初にSlack通知

## はじめに
Qiita/RSSシリーズです。前回までの記事を振り返ります。

### 記事①では…。
「Qiita/RSS」を題材にPHPでXMLの解析を行いました。

https://qiita.com/umekikazuya/items/c20ac26b59670a72ca7b

### 記事②では…。
「Qiita/RSS」を題材にDrupalでAPI化をしてみました。

https://qiita.com/umekikazuya/items/6379e3785b385bceabb3

### 記事③では…。
Next.js でAPIデータにFetchしてみました。

https://qiita.com/umekikazuya/items/54b6ada9024f17499aa5

## 今回は…。
EC2のCron設定で、Qiitaの更新情報を毎月1日にSlack通知してみたいと思います。

ちょっとこれだけだと情報不足...。

1. 実装したAPIを利用して、Qiita公式更新情報を取得
2. 取得したデータをPHPの関数でSlack通知機能を実装
3. 月初に通知を行うよう、Jobの設定

って感じです。

一応…。完成イメージ。こんな感じでBotからメッセージが送信されます。

![スクリーンショット 2024-06-29 20.20.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334980/6af640b2-4633-ba65-03fc-23428c4e9321.png)

## 設計
シリーズが長くなってきたので一旦整理します。

| 環境 | 用途 |
|:-:|:-:|
| Qiita公式  | RSS配信  |
| Drupal環境  | RSSデータをAPI化（キャッシュ実装込）  |
| Next.js環境  | フロントエンドからAPIを取得、レンダリング  |
| EC2(Drupal)環境  | Cron設定でSlackに通知を送る |

今回は、APIにアクセスしてEC2(Drupal環境)からSlackにQiita公式更新情報を送ってみます。


APIには 8h のキャッシュが効いているので、直接RSSにHTTP通信するよりはマシだと思っています。

## SlackのBotについて
SlackのBotの導入については本記事では割愛します。

私は、以下の記事のやり方でBotを導入しています。（Webhookが簡単だと思うのでそちらでも全然いいかと）

https://techblog.gmo-ap.jp/2022/11/30/send_message_to_slack_with_php/

気が向けば記事書きます。

## 実装
### 001. スクリプトの実装
まずは、Cronで発動するPHPの関数を実装します。

実装の流れはこんな感じ.
1. APIからデータを取得
1. データをメッセージ用に加工
1. Slackに送信

```php

/**
 * Notice slack.
 */
function notice_qiita() {
  // APIからデータを取得.
  $client = new Client();
  // 定数 'ENDPOINT' には実際のAPIのURLを設定してください。
  $data = $client->get(ENDPOINT)->getBody()->getContents();
  $data = json_decode($data, TRUE);

  // Slackに送信するメッセージを構築.
  $blocks = [
    [
      "type" => "section",
      "text" => [
        "type" => "mrkdwn",
        "text" => "*<{$data['link']}|{$data['title']}>*",
      ],
    ],
  ];
  foreach ($data['data'] as $item) {
    $blocks[] = [
      "type" => "section",
      "text" => [
        "type" => "mrkdwn",
        "text" => "<{$item['link']}|{$item['title']}> - {$item['published']}",
      ],
    ];
  }
  $slack_message = [
    "blocks" => $blocks,
  ];

  // 環境変数.
  $token = getenv('slack_token');
  $channel_id = getenv('slack_channel_id');

  // 送信.
  $client->post('https://slack.com/api/chat.postMessage', [
    'headers' => [
      'Authorization' => "Bearer {$token}",
      'Content-Type' => 'application/json',
    ],
    'json' => [
      'channel' => $channel_id,
      'blocks' => $slack_message['blocks'],
    ],
  ]);
  echo "Slackに送信しました。";
}

// 記事内では例外処理は省略.
```
この時点で送信にこけないか、テストで関数を実行してみてください。

### 002. Cronの設定
毎月1日にスクリプトを実行します。
#### Crontabを開く
```shell-session
crontab -e
```
#### 毎月1日に発動するよう設定
```
// 私はPHPスクリプトを実行するShellを実装しました。
0 0 1 * * bash script/batch/notice-slack.bash
```

Cron設定は以上です。
月初を待ってられないので、テストでいろいろ試してみてください。

## まとめ
いかがでしたか？
今回のやり方だと、自身のサーバーがないと試せないですが、CronでSlackにいろいろ送ることができます。

AWSだったら無料利用枠でかなりのことできますので、使ってみてもいいかもですね。
rails generators 制限設定

### rails g コマンドで生成されるファイルを制限する
- [ドキュメント](https://api.rubyonrails.org/classes/Rails/Generators.html)

#### `config/application.rb`内に下記のように設定する
```ruby
config.generators do |g|
  g.jbuilder       false
end
① # p config.generators
```
- 各種設定項目はドキュメント内で確認できた `Rails::Generators`
[![Image from Gyazo](https://i.gyazo.com/6ba8469df8413ab6db83a2e7b4a2328b.png)](https://gyazo.com/6ba8469df8413ab6db83a2e7b4a2328b)
- コード①を有効化して、サーバログを確認すると下記のように設定項目を確認できる
![Screenshot 0006-06-30 at 20.52.13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760024/00d5c88b-3f61-b550-4c2b-3f5af5e853bc.jpeg)


#### ドキュメントに記述されていない項目...
- [skip_routesソース](https://github.com/rails/rails/blob/d5b9618da1ac60c674e8a27c3ab4e33742e9aa9b/railties/lib/rails/generators/rails/controller/controller_generator.rb)

##### わからなかったこと
- ルーティング生成の有無の設定項目である`skip_routes`は、`railsガイド`、`APIドキュメント`、`その他の公式と思われるリソース`を調べたが見つからず`個人ブログ`などの2次、3次などのリソースでしか知ることができなかった。

##### 分かったこと
`rails`のリポジトリにて、`Rails::ControllerGenerator::ControllerGenerator`オブジェクト`class_option`の引数に`skip_routes`が記述されていることを確認できた。上記のコードとどのように絡んでくるかはわかっていないが、`skip_routes true or false`を記述することで、`rails g controller`実行の際に設定を読み込み、`config.generators.skip_routes false`ならば、ルーティング生成を無効にするという動きをすると思われる。

##### 感想
`APIドキュメント`などの公式リソースから情報を読み取っているが、もし公式リソースに情報がない、もしくは見つけられない時の調べ方に課題を感じた。
【Ruby】バージョンを2.6.6に変更する

# はじめに

## 目的
既にRuby`3.1.1`をインストールしている状態ですが、Rails6の環境構築を行う上で互換性を維持する為に、`2.6.6`にバージョンを変更します。
[※Rails6.0.3の環境構築はこちら](https://qiita.com/royal_straight_flush/items/001bcdca3d7186380306)。

## 環境
- チップ：`Apple M1`
- MacOS：`Sonoma 14.2.1`

# 手順
## Homebrewをアップデート

```terminal
brew update
```


## ruby-buildをアップグレード
```terminal
brew upgrade ruby-build
```


## インストール可能なバージョンが存在するかどうかを確認
```terminal
rbenv install --list-all
```



## Ruby2.6.6 をインストール
```terminal
arch -x86_64 rbenv install 2.6.6
```
```terminal
arch -arm64 rbenv install 2.6.6
```
:::note
ご自身の環境に合わせて、上記のいずれかのコマンドを実行してください。
:::

:::note warn
```terminal
uname -m
```
Rubyのインストール手順にもよりますが、上記のコマンドの結果が`arm64`でも、rbenvがRosettaを介してIntelアーキテクチャ（`x86_64`）で動作している場合があります。
:::


## rbenvのバージョンを確認①
```terminal
rbenv versions
```

```terminal
(base) test@TestnoMBP ~ % rbenv versions
  system
  2.6.6
* 3.1.1 (set by /Users/test/.ruby-version)
```
まだ、バージョン`2.6.6`はシステムに反映されていません。



## `.ruby-version` を書き換える
```terminal
echo '2.6.6' > .ruby-version
```

## rbenvのバージョンを確認②
```terminal
rbenv versions
```
```terminal
(base) test@TestnoMBP ~ % rbenv versions
  system
* 2.6.6 (set by /Users/test/.ruby-version)
  3.1.1
```

## システム全体に反映する
```terminal
rbenv global 2.6.6
```

## bundlerをインストール
```terminal
RBENV_VERSION=2.6.6 gem install bundler --version '~> 1'
```


## Rubyバージョンを確認
```terminal
ruby -v
```

```terminal
(base) test@TestnoMBP ~ % ruby -v
 ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin23]
```

:::note
完了
:::
MacでGit環境構築の注意点

# 経緯
自端末のMacからGitHub連携して開発したいので初めて環境構築してみたけど、自端末からGitHubへプッシュできなかったので備忘録として記録しておく。

# エラーになったところ（その１）
まず、git cloneしようとしたところ、認証に失敗しているよう。
Command Line Tools for Xcodeをインストールしないといけないみたいです。
統合開発環境とコマンドラインツールのようですね。
今回は実行しようとした時にポップアップが表示されたのでそのままインストールしちゃいました。
![スクリーンショット 2024-06-30 20.29.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/0222b0b8-04f3-6773-c4e3-b76bee4ebe01.png)

# エラーになったところ（その２）
git pushしようとしたところ、こちらも認証に失敗しているよう。
GitHub側でPersonal Access Tokenを設定していないといけないみたいです。
GitHubのリモートリポジトリへコマンドラインやAPIを使って認証を行うときに、
パスワードの代わりに使うみたい。
しかも、有効期限があって切れると実行のたびに再設定をしないといけないので都度調べることになりそうですね。
コマンドラインでトークン発行できるならスクリプト化したいね。
![スクリーンショット 2024-06-30 20.36.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/75e8eb2d-2bb1-08af-a992-9a41b5618298.png)

### トークンを発行してみる
まず、Settingsをクリック
![スクリーンショット 2024-06-30 20.46.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/6799cb5a-d21e-e7be-559f-a6401e7d02b9.png)

次に、Developer settingsをクリック
![スクリーンショット 2024-06-30 20.48.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/b533618e-d63d-fe3a-2409-903a20aae82b.png)

Personal access tokenのところで今回はクラシックを選択する。
画面上ではすでに発行ずみなのでこのような表示になっていますが、Generate new tokenをクリックする。
もし、iPhoneなどにGitHubアプリをインストールしてて、２要素認証を設定しているのであれば、アプリ上で番号入力を求められるかもしれません。
![スクリーンショット 2024-06-30 20.49.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/fde36dd8-84fa-9f92-a837-ece183358794.png)

### 再度gitプッシュしてみる
Passwordのところをパスワードではなく、発行したトークンを入れます。
パスワードと紛らわしいですね。
ってことで、gitプッシュができました。
お疲れ様でした！
![スクリーンショット 2024-06-30 20.53.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/364f23c1-52e9-5c91-7095-9aa51a3ddb30.png)
Rust の命名規則

# 命名規則
**命名規則**とは、プログラム内で使用される名前（変数名や関数名など）に一貫性を持たせるためのルールです。これにより、コードの可読性や保守性が向上し、他の開発者がコードを理解しやすくなります。

命名規則は、プログラミング言語ごとに異なることがありますが、多くの言語で一般的に使用される命名規則には、**スネークケース**(snake_case)、**キャメルケース**(UpperCamelCase または lowerCamelCase)、**ケバブケース**(kebab-case)などがあります。


- **スネークケース** (snake_case)
  単語の間に**アンダースコア** (`_`) を入れる形式。例: `example_variable`
  全て大文字の場合は特に SCREAMING_SNAKE_CASE と呼ばれる。
- **キャメルケース** (CamelCase)
  **単語の先頭を大文字**にする形式
  - UpperCamelCase (PascalCase)
    最初の単語の先頭文字は**小文字**。例: `ExampleVariable`
  - lowerCamelCase
    最初の単語の先頭文字は**大文字**。例: `exampleVariable`
- **ケバブケース** (kebab-case)
  単語の間に**ハイフン** (-) を入れる形式。例: `example-variable`

## Rust の命名規則
Rust では、**スネークケース**と**アッパーキャメルケース**を採用しています。

Rust の命名規則は [RFC 430](https://github.com/rust-lang/rfcs/blob/master/text/0430-finalizing-naming-conventions.md) にまとめられています。

| アイテム | 命名規則 |
| ---- | ---------- |
| クレート | `snake_case` (ただし、単一の単語を優先する) |
| モジュール | `snake_case` |
| 型 | `UpperCamelCase` |
| トレイト | `UpperCamelCase` |
| 列挙型のバリアント | `UpperCamelCase` |
| 関数 | `snake_case` |
| メソッド | `snake_case` |
| 一般的なコンストラクタ | `new` もしくは `with_more_details` |
| 変換コンストラクタ | `from_some_other_type` |
| ローカル変数 | `snake_case` |
| 静的変数 | `SCREAMING_SNAKE_CASE` |
| 定数 | `SCREAMING_SNAKE_CASE` |
| 型パラメータ | 簡潔に `UpperCamelCase`, 通常は大文字 1 文字: `T` |
| ライフタイム | 短く、小文字: `'a` |

### 頭字語の扱い
`UpperCamelCase` では、**頭字語**（`USA` や `IT` など）は 1 つの単語としてカウントされます。`UUID` ではなく `Uuid` とします。 `Snake_case` では、頭字語は**小文字**になります。`is_XID_start` ではなく `is_xid_start` とします。


### 数字の扱い
`UpperCamelCase` の名前では、わかりやすくするために複数の数字を `_` で区切ることができます (`Windows101709` ではなく `Windows10_1709`)。

### 単一文字の扱い
`Snake_case` または `SCREAMING_SNAKE_CASE` では、最後の「単語」でない限り、「単語」は単一の文字で構成されてはなりません。 したがって、`b_tree_map` ではなく `btree_map` が使用されますが、`PI2` ではなく `PI_2` が使用されます。


# 具体例
## 型名
`Vec` (ベクター型)、`HashMap` (ハッシュマップ型)
```rust
// 型名は UpperCamelCase
struct MyStruct {
    field: i32,
}
```
## トレイト名
```rust
// トレイト名はUpperCamelCase
trait MyTrait {
    fn do_something(&self);
}
```

## 列挙型のバリアント
```rust
// 列挙型のバリアントは UpperCamelCase
enum MyEnum {
    VariantOne,
    VariantTwo,
}
```
## 関数名
```rust
// 関数名は snake_case
fn my_function() {
    // 函数の内容
}
```
## メソッド名
```rust
impl MyStruct {
    // メソッド名は snake_case
    fn my_method(&self) {
        // メソッドの内容
    }
}
```
## 一般的なコンストラクタ
```rust
impl MyStruct {
    // 一般的なコンストラクタ
    fn new() -> Self {
        Self { field: 0 }
    }

    fn with_more_details(field: i32) -> Self {
        Self { field }
    }
}
```
## 変換コンストラクタ
```rust
impl From<OtherType> for MyStruct {
    // 変換コンストラクタは from_some_other_type
    fn from(other: OtherType) -> Self {
        Self { field: other.field }
    }
}
```

## ローカル変数
```rust
fn main() {
    // ローカル変数は snake_case
    let my_variable = 10;
}
```

## 静的変数と定数
```rust
// 静的変数と定数は SCREAMING_SNAKE_CASE
static MAX_VALUE: i32 = 100;
const PI: f64 = 3.141592653589793;
```
## 型パラメータ
```rust
// 型パラメータは UpperCamelCase、通常は大文字 1 文字
fn generic_function<T>(value: T) {
    // 関数の内容
}
```

## ライフタイム
```rust
// ライフタイムは短く、小文字
fn lifetime_example<'a>(value: &'a str) {
    // 関数の内容
}
```


# おわりに
これらの命名規則に従うことで、Rustのコードは一貫性があり、読みやすく、理解しやすくなります。命名規則は、チーム開発や長期的なプロジェクトにおいて特に重要です。
[Mac版] VSCodeでの作業効率を上げるショートカット

VSCodeのショートカットキーを使用すれば、作業の効率を大幅に向上させ、時間を節約しながら、コーディングの生産性を最大限に引き出すことができます。
使用率が高いVSCodeのショートカットキーを厳選し、記録しておきます。

## 全般

* ***Shift + Cmd + P*** : コマンドパレットを表示する
* ***Cmd + P*** : ファイル名で検索しファイルを開く
* ***Shift + Cmd + N*** : 新しいウィンドウを開く
* ***Cmd + N*** : 新しいファイル
* ***Cmd + O*** : ファイルを開く
* ***Cmd + S*** : 保存する
* ***Shift + Cmd + S*** : 名前をつけて保存する
* ***Cmd + W*** : ファイルを閉じる（開いていない場合はウィンドウを閉じる）
* ***Cmd + B*** : サイドバー表示を切り替える
* ***Cmd + ,*** : 設定を開く

## 編集

* ***Cmd + X*** : 行をカットする（未選択状態）
* ***Cmd + C*** : 行をコピーする（未選択状態）
* ***Option + ↑ / Option + ↓*** : 行を上下に移動する
* ***Shift + Option + ↑ / Shift + Option + ↓*** : 行を上下にコピーする
* ***Shift + Cmd + K*** : 行を削除する
* ***Shift + Cmd + Enter / Cmd + Enter*** : 新しい行を上下に挿入する
* ***Cmd + ] / Cmd + [*** : インデント/アウトデント
* ***Cmd + K Cmd + 0 / Cmd + K Cmd + J*** : 全ての領域を折り畳む/展開する
* ***Cmd + /*** : 行コメントに切り替える
* ***Shift + Option + A*** : ブロックコメントに切り替える（選択状態）

## 移動

* ***Cmd + ↑ / Cmd + ↓*** : ファイルの先頭/最後に移動する
* ***Cmd + ← / Cmd + →*** : 行の先頭/最後に移動する
* ***Ctrl + PageUp / Ctrl + PageDown*** 上/下へスクロールする
* ***Ctrl + G*** : 行番号を指定して移動する
* ***Shift + Cmd + ¥*** : 一致するカッコに移動する
* ***Shift + Cmd + [ / Shift + Cmd + ]*** : 左/右のタブに移動する
* ***Ctrl + Tab*** : タブのリストで選んで移動する

## マルチカーソル

* ***Option + Click*** : カーソルを挿入する
* ***Shift + Cmd + L*** : 現在の選択の全ての出現箇所を選択する

## 検索・置換

* ***Cmd + F*** : 検索する
* ***Option + Cmd + F*** : 置換する
* ***Cmd + G / Shift + Cmd + G*** : 次/前を検索する
* ***Option + Enter*** : 一致する全てを選択する（マルチカーソル）

## 参考情報

* [キーボードショートカットformacOS](https://assets.ctfassets.net/pppgbgujcovf/3q68zvoziYjKB13sEVMXeR/a86035aac73812d010d63d9c88a76a4d/VSCode_______________________macOS.pdf)
* [【Mac版】 VisualStudioCode キーボードショートカット](https://qiita.com/naru0504/items/99495c4482cd158ddca8)
Scala3で型に対して中置演算子を定義して使ってみる

# 概要

Scala3では、型に対する中置演算子（infix operator）を簡単に定義できます。
これにより、コードが直感的で読みやすくなります。以下に、その方法と使用例を示します。

## 中置演算子の定義と使用例

以下のコードでは、`or`という中置演算子を定義し、`String`または`Int`型を表現しています。

### サンプルコード

```scala
scala> infix type or[X, Y] = X | Y
// defined alias type or[X,Y] = X | Y

scala> val x: String or Int = 10
val x: String or Int = 10

scala> val x: String or Int = "str"
val x: String or Int = str
```

### 解説

1. **中置演算子の定義**: `infix type or[X, Y] = X | Y`で、`or`を中置演算子として定義しています。
2. **使用例**: `val x: String or Int = 10`や`val x: String or Int = "str"`で、`or`を使って異なる型の値を持つ変数を定義しています。

このように、中置演算子を使うことで、型の選択をより直感的に表現できます。
java.lang.NullPointerException: uriStringというエラーの対応


https://qiita.com/usayuki/items/9083136819cf33147887

こちらの記事を参考に実装したところ以下のエラーが出ました。

```
java.lang.NullPointerException: uriString
```


こちらを解決した際の内容をかるく紹介しておき、
今後のために記事に残しておきます。

# 解決方法

``` diff

for (int i = 0; i < count; i++) {

 val bytes = ByteArrayOutputStream()
 bitmapImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
-  val path = MediaStore.Images.Media.insertImage(context.getContentResolver(), 
+  val path = MediaStore.Images.Media.insertImage(context.getContentResolver(), 
 bitmapImage, "Title + i", null)
 val uri = Uri.parse(path)
}
```
MediaStoreへinsertImageする際にtitleが同じだとエラーになるようで、そこを毎回違う値が入るようにしたらエラーが出なくなりました。

今回はfor文で回していたので、回した回数をtitleに含めて渡すことにしました。
社内DXが進まない企業に届け！！！DXを拡げるための市民開発とコミュニティ活用術【CMC_Central 2024参戦レポ】

# はじめに
こんにちわ、まとっちです。

この前、CMC_Central 2024に参加して、色んなコミュニティマーケティングについて学ぶことができました。

その中でも<b>今の自分に一番重要だと思ったセッション</b>を記事に残しておきます。（ただの自分の備忘録！）

### CMC_Central 2024とは
CMC_Meetup（コミュニティマーケティングについて考えるコミュニティ）の全国集結バージョンの祭典です。

https://cmc-central.com/

### CMC_Central 2024に参加した背景
仕事でkintoneやPowerPlatformの導入支援を行っていると、ユーザー企業内のDXをどのように推進してもらうか、どのように社内で普及させるか、悩むことが多いです。

例えば、先日、前職の友人にノーコードツールをオススメしてみたのですが、「今のエクセルの方が良い」「覚えるのが大変」「あんまり興味ない」といった感じで、変化に対する抵抗だったり、自分事として捉えてくれないことがありました。

ユーザー企業内のPowerPlatform市民開発コミュニティ運営で成功されてる、りなたむさんとトヨタ永田さんのセッションがあるということで、これ目当てでCMC_Central 2024に参加しました。

:::note info
市民開発 ＝ 非IT人材がノーコードツール等でシステムを開発すること
:::


# DXを拡げるためのコミュニティ活用相談会
本セッションのアジェンダは下記２つです。
- 【前半】りなたむさん「DX拡大のために、なぜ市民開発とコミュニティが必要か」
- 【後半】参加者からの相談に対する、りなたむさんとトヨタ永田さんからのアドバイス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/ee5755bf-7699-0628-b9c2-c7b0c67ec987.png)

## 【前半】りなたむさん「DX拡大のために、なぜ市民開発とコミュニティが必要か」
りなたむさんが説明したプレゼン資料はこちら👇

https://www.docswell.com/s/rinatamu/KYWYLN-CMCCentral2024

超ざっくり概要を下記に書いておきます。

### ①なぜ「市民開発」が必要なのか
<b>👉日本は特に業務効率の向上が必要</b>
- 生産年齢人口の低下で人材確保が困難
- 他国に比べ、ビジネス効率性が顕著に低下
- 定型業務自動化で一人あたりの業務効率アップ

<b>👉ITベンダーによるシステム化の問題点</b>
- 業務課題をITベンダーにきちんと伝えるのが大変
- 各部署が異なるITベンダー依頼でシステム複雑化
- せっかくデータ蓄積しても全社横断利活用が困難

<b>👉社内のデジタル人材が少ないので創出する</b>
- 業務部門からIT部門への伝達コストもったいない
- 高度な技術の部分ははプロ開発者に任せる
- それ以外は業務部門がノーコードで市民開発

<b>👉市民開発者とは</b>
- プロ開発者の簡易版みたいな甘いものではない
- 業務が分かるので、多くの課題・改善が思い付く
- でも最初から完璧な城を作らず、簡単なものから

### ②なぜ「コミュニティ」が必要なのか
<b>👉実際にアウトプットするのは大事</b>
- 自分の理解し易い形で置き換え ⇒ 再インプット
- 作る/学ぶ ⇒ 他者に発表 ⇒ 結果を反映の循環
- 褒められて成功体験 ⇒ モチベーションアップ

<b>👉コミュニティとは</b>
- 互いに尊重し合う ⇒ アウトプットの場に最適
- 多くのアイデアや気付きで、業務改善力アップ
- 会社の価値向上（ダイキンものづくり白書掲載）

:::note info
ちなみに、８月にアップグレードした完全版のプレゼンをやるらしいので、参加できなかった人はりなたむさんの動向を要チェックだぁぁぁ！！！
:::


https://x.com/Rinatamu_ITDR/status/1807072279551160663


## 【後半】参加者からの相談に対する、りなたむさんとトヨタ永田さんからのアドバイス

### 相談①：勉強会をやってもそこから何も生まれなかった
- 何かをアウトプットする場は必要。受け身で勉強しても自発的なイノベーションは起きない
- まずは、参加者が困ってることをアウトプットしてもらえば、そこから建設的な話が出る
- 部活と称して、業務時間外でやってしまえば、本当にやりたい人（自発的な人）だけが参加する

### 相談②：業務部門がやる気にならない
- 業務部門の中にも市民開発が好きな人がたまにいるので、その人を見つけ出してリーダーにして、業務部門に主体性を持たせることで、自発的にやる人が増えていく
- 自分事と考えてもらうために、残業するのイヤでしょ？このままだと業務回らなくなるよって感じで煽る

### 相談③：コミュニティが盛り上がっても、すぐ会社のビジネスに繋がらないし、遊んでるように見えてしまう
- 人材の確保が困難になってるのだから、仕事を楽しくやるって言うのは大事で、仕事が楽しいのを悪だと考えていると人材を雇えなくなる
- コミュニティの盛り上がりに対して、すぐにビジネスとしての成果が出ないのは普通
- 業務改善のKPIを時間ではなく、具体的な金額に換算することで、ビジネスに繋がっていることを示す

### 相談④：アウトプットとして社外に発信すると情報漏洩と言われる
- コミュニティが拡大していき、コミュニティが力を持ってくると、そういうことは言われなくなる
- そうなってくると、むしろ会社側がコミュニティの対外活動をブランドとして利用してくるようになる

# おわりに
今の自分にすごく刺さる良い話だった。
本当に良かった。めっちゃ良かった。

※語彙力無いから、これ以上表現できない…(´;ω;｀)
Scala3で中置演算子を定義して使ってみる

# 概要

Scala3では、中置演算子（infix operator）を簡単に定義することができます。
中置演算子は、通常のメソッド呼び出しと異なり、オペランドの間に演算子を置く形式で呼び出します。

この記事では、Int型とカスタムクラスを用いて、中置演算子を定義し使用する方法について取り上げます。

## Int型に対する中置演算子の定義

まずは、Int型に対して中置演算子を定義してみます。以下のコードでは、`infixAdd`という中置演算子を定義しています。

```scala
scala> extension (x: Int)
     |   infix def infixAdd(y: Int): Int = x + y
     |   def add(y: Int): Int = x + y
     | 
def infixAdd(x: Int)(y: Int): Int
def add(x: Int)(y: Int): Int
```

`extension`キーワードを使用することで、既存の型に対して新しいメソッドを追加できます。`infix`修飾子を付けることで、そのメソッドが中置演算子として使用できることを示します。

この定義をもとに、次のように中置演算子を使用することができます。

```scala
scala> 1 infixAdd 2
val res0: Int = 3
```

`infixAdd`を中置演算子として使用した場合、`1 infixAdd 2`という形になります。これに対して、通常のメソッド呼び出しも可能ですが、警告が表示されます。

```scala
scala> 1 add 2
1 warning found
-- Warning: --------------------------------------------------------------------
1 |1 add 2
  |  ^^^
  |Alphanumeric method add is not declared infix; it should not be used as infix operator.
  |Instead, use method syntax .add(...) or backticked identifier `add`.
val res1: Int = 3
```

この警告は、`add`メソッドが中置演算子として定義されていないために表示されます。そのため、通常のメソッド呼び出しとして使用するべきです。

## カスタムクラスに対する中置演算子の定義

次に、カスタムクラスに対して中置演算子を定義してみます。以下のコードでは、`Num`クラスに対して`infixAdd`という中置演算子を定義しています。

```scala
scala> case class Num(v: Int):
     |   infix def infixAdd(other: Num): Num = Num(v + other.v)
     |   def add(other: Num): Num = Num(v + other.v)
     |
// defined case class Num
```

`Num`クラスには、二つのメソッドが定義されています。一つは中置演算子として使用できる`infixAdd`、もう一つは通常のメソッド呼び出しとして使用する`add`です。

この定義をもとに、次のように中置演算子を使用することができます。

```scala
scala> Num(1) infixAdd Num(2)
val res0: Num = Num(3)
```

`Num(1) infixAdd Num(2)`という形で中置演算子を使用することができます。一方で、通常のメソッド呼び出しも可能ですが、こちらも警告が表示されます。

```scala
scala> Num(1) add Num(2)
1 warning found
-- Warning: --------------------------------------------------------------------
1 |Num(1) add Num(2)
  |       ^^^
  |Alphanumeric method add is not declared infix; it should not be used as infix operator.
  |Instead, use method syntax .add(...) or backticked identifier `add`.
val res1: Num = Num(3)
```

## まとめ

Scala3では、`extension`キーワードと`infix`修飾子を使用することで、簡単に中置演算子を定義することができました。
Create.ai を使って生成AIでWEBサイト作成



# 始め方

公式サイトから
https://create-xyz-fyi.webflow.io/internal-tools

無料ではじめます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/972f7211-ffc9-b884-a5dc-ca7f42120cc0.png)


メールアドレスを入力すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/343aa0fc-4a66-bceb-8911-e3ff4d00e905.png)

急にこの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/b64bc7bd-00a7-c836-9a90-6e5453ee27bd.png)

## 入力

ちょっと癖があるｗ

画面右がプロンプト入力エリア
画面左が出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/6616588c-e057-b448-b5c5-cc3adb128dcc.png)

プロンプトは、Ctrl+Enterまたは画面下部Generateボタン

## 要望を伝える

依頼しただけでこのクオリティ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/b8f8b708-5de8-d04a-02cd-d9c8ba5c9d9c.png)

デモページを表示しながら挙動を追加していく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/f028c75c-83e7-e20c-6d16-6ab041d97723.png)

webページを動かすには「share」ボタンから
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/9b125239-6563-f61b-1b37-c98084a0f4db.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/6d66da1e-f27c-2147-95b9-5ed4458fbe26.png)

## 感想

ノーコーディングってこれのことであってます？
すごいな～

# おまけ

仕事でへこむ事があるので、犬が一斉にほめてくれるサイトを作りました。

柴犬：GPT
コーギー：Gemini
シュナウザー：Claude 3.5 Sonnet

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/8b251ba2-7c2b-7650-a5b1-0ed3b2040948.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778585/5f8367f6-ef70-750c-220b-8b0b40c594e5.png)
#FFFFFFってなんで白色なの？

## 結論
赤＋緑＋青＝白 だからです。
ですがこれではちょっと説明不足ですね。

本記事では
- カラーコードは16進数
- RGB表色系について

この2つのポイントをおさえて説明しようと思います。

## カラーコードは16進数
まずはじめに、#FFFFFFとは6桁にみえますが、実際は
**FF ＋ FF ＋ FF** の2桁×3の組み合わせです。

16進数は0〜255の256通りを表す数値パターンです。
以下は10進数と16進数の対応テーブルの一部を示しています。

|10進数  |16進数  |
|---|---|
|0  |0  |
|9  |9  |
|10  |a  |
|16  |f  |
|17  |10  |
|31  |1f  |
|32  |20  |
|240  |f0  |
|255  |ff  |


つまり、「FF」とは16進数の最大値を表す256番目の数値。
R（赤）がFF、他の2つが00なら、混じりけのない赤となります。
R, G, Bのそれぞれの色が純度100％の場合のコードは以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348975/d420d2d6-759a-59bd-48ed-0c835b2f1697.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348975/17557ee5-5bf4-834c-9b41-f9a5c47b3821.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348975/1109bc2e-e9a4-c13a-d0ad-fe449a22f075.png)


## RGB表色系について
どうして赤＋緑＋青＝白になるのでしょうか？
これには「光の三原色」という色の法則が関係しています。

![スクリーンショット 2024-06-06 22.23.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348975/b6a7054f-f22b-ef49-0ccb-bea9e615baa2.png)
[ＦＮの高校物理　光と絵の具の三原色（色とは何か）](http://fnorio.com/0074trichromatism1/trichromatism1.html)より引用

この図が示すとおり、
**R（赤）、G（緑）、青（B）がすべて混じりけなく均等に交わるとき、
その結果は白**になります。
つまり、Rの最大値＝FF、Gの最大値＝FF、Bの最大値＝FFを足すことで、
**FFFFFF＝白**になるということでした。

## さいごに
お恥ずかしながら、つい最近まで16進数どころか2進数も知りませんでした。
説明をしてくれた同僚の説明がとても分かりやすかったので、備忘録として残します。
本記事を書いたことで、カラーコードがただの文字列から意味のあるものとして理解できるようになって良かったです。