OmniAICreator/Qiita-1.07M huggingface dataset:
離散数学(超入門) - 論理学 - 3

論理学第3回です.
[前回](https://qiita.com/minyuqiaoben/items/90de6007a6f1f02a28a4)は**論理演算**と**条件命題**を学習しました.
今回は**推論**を学習します.

論理演算を出来る前提で進めます. 分からない場合は前回の記事が参考になります.

# 推論

　「**前提**」である命題 `p1, p2, p3, ...` と, 「**結論**」である命題`q`の関係を「**推論**」として次のように表します.
 
![スクリーンショット 2025-02-11 18.56.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670178/4a99cff6-3f71-18dc-d868-da6058e60852.png)

　`p1, p2, p3, ...`の並んだ命題は連言(and)になります. なので, `p1 ∧ p2 ∧ p3 ...`というふうに考えられます. 
 　推論を日本語で表すと「p1 かつ, p2 かつ, p3 かつ, ...である. ゆえに q である.」というふうになります. もっと数学的に言い換えると「命題 p1, p2, p3, ... が全て真である **ならば**, 必ず`命題q`が真である」となります.
  よって, 推論は前回説明した**条件命題**を用いて表すと次のように表すことが出来ます.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670178/77403d72-ceec-ff70-f5bf-8f9bd2e80433.png)
　これは, 推論を言い換えただけのものである というのが重要です.

 # 推論の妥当性
推論行なった後, 結果を評価する必要があります. それが論理的に有効であるのか, それとも誤った推論であるのかを判断することが必要です.
  例えば, 以下のような条件で推論を考えます.


```
p1, p2 ⇒ q
```
p1: 鍵がある
p2: 鍵があるならばドアを開くことが出来る
q: ドアを開くことが出来る

　これは論理的に有効な推論であり, このような推論のことを **有効(または妥当)** といいます(こちらは後で真理値表を用いて解説します.) 
　もし, qが「ドアを開くことが出来ない」となっていた場合は論理的に矛盾しており, このような推論のことを **謬論(びゅうろん)** と言います.

 # 推論を真理値表を使って機械的にとく
　先ほど**有効**と**謬論**をについてお話ししましたが, 実際にどのように判定するのでしょうか. これは, 論理演算を行い, 真理値表を作って使ってこの推論が有効なのか謬論なのかを判断することが出来ます. 先ほどの例を使って解説します.

例を再掲します.

```
p1, p2 ⇒ q
```
p1: 鍵がある
p2: 鍵があるならばドアを開くことが出来る
q: ドアを開くことが出来る

上の推論の説明でもあった通り, 
```
p1, p2 ⇒ q
```
という**推論**は
```
p1 ∧ p2 → q
```
上で説明した通り, **条件命題**に置き換えることが出来ます. 条件命題であれば, 前回の記事で説明した論理演算で解くことが出来ます.
　さらに, ここで前提p2に注目してください. 実はp2も「ならば」とあることから読み取れる通り, 条件命題です. よって, 最終的に推論は以下のような論理式に置き換えることが出来ます.

 
ここで p2: `p1 → q`に置き換えると
```
p1 ∧ (p1 → q) → q
```
となります.

この推論の結果がどうなるか論理演算を行い, 真理値表を使って解いてみます.

![スクリーンショット 2025-02-11 21.44.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670178/c5022b5a-8352-c948-6624-3527e34e2952.png)

真理値表より, 推論`p1 ∧ (p1 → q) → q`が常に真であることから, この推論は**有効**だと判断できます.

もし, 推論`p1 ∧ (p1 → q) → q`が常に真でなかった場合は, **謬論**となります.

# おわりに

　今回は推論について学びました. 条件命題や論理演算が曖昧な方は少し難しかったのではないでしょうか. 
　推論は誰もが日常的に行っています. 例えば「今日は空が暗いから雨が降るかもしれない」と考えるのも推論の一つです. また, 「友人の返事が遅いから忙しいのかもしれない」と推測するのもそうです. このくらいであれば少し考えるだけで答えに辿りつけますが, 探偵のように多くの前提から結論を導き出すのは容易ではありません.
　そのような時はやはり, 論理学が役に立ちます. 頭だけで考えると煮詰まってきそうな推論を演算によって機械的に解けるのです. そういう意味では, 論理学は人間の理解を超えた解釈を可能にするツールともいえるかもしれません.

 今回, 少し複雑な推論については触れられなかったので, また, 後日補足として記事を出すかもしれません. また, 論理演算についての補足も考えています.

次回からは論理学は一旦終了し"関係"の学習へ進みます. 様々な数学の根幹になっている考えであり, その次の学習である代数学にも繋がってきます.
JavaScriptで配列を90度回転させる方法

Progateのmosyaで配列を90度回転させる問題があり、なかなか歯ごたえがあったのでメモ。

### 問題
> N x N の配列を90度右に回転させる関数 rotateMatrix を実装してください。
> 例えば、次のような配列が与えられた場合、

```javascript
[
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];
```
> 次のような配列に変えてください。

```javascript
[
  [7, 4, 1],
  [8, 5, 2],
  [9, 6, 3],
];
```

### 回答に必要な知識
- 行列の長さ（length）の考え方👇

| 配列の長さ | 取得方法 | 意味 |
|:-:|:-:|:-:|
| 行数  |  matrix.length | 外側の配列の要素数  |
| 列数  | matrix[0].length  | 各行の要素数  |

- n × n 行列の作り方
fromメソッドを使う。
 ##### fromメソッド
```javascript
let arr = Array.from({ length: 3 });
console.log(arr); // [undefined, undefined, undefined]
```
fromメソッドは上記のように要素数を指定して配列を作ることができる。
上の例ではundefined が3個入った配列ができる。
これだとまだ行列にはなっていないが、第二引数に配列を渡してあげることで、行列を作ることができる。
 ```javascript
 let matrix = Array.from({ length: 3 }, () => Array(3).fill(0));
```
Array(N).fill(0）は 長さ N の配列を作って、全部 0 にする という意味。

- mapメソッド
配列内のすべての要素に同じ処理を適用することができる

```javascript
const array = [1, 4, 9, 16];
const map = array.map((x) => x * 2);

console.log(map);
// 予想結果: Array [2, 8, 18, 32]
```
上記の例では、mapを使ってすべての要素を2倍している。

- reverseメソッド
配列の要素を逆順に並び替えることができる。
```javascript
let favorite = ['curry', 'money', 'sunny'];
console.log(favorite.reverse); // sunny, money ,curry
```

### 解答コード
```javascript
function rotateMatrix(matrix) {
  // この関数の続きを書いてください
  // まず行列を反転させる
  const n = matrix.length; // nに配列の行数を代入
  let transposed = Array.from({length:n}, () => Array(n).fill(0)); // 長さn、要素数nの配列を作りすべて0にする
    for (let i = 0; i < n; i++) {
      for(let j = 0; j < n; j++) {
        transposed[i][j] = matrix[j][i]; // 0をmatrixの反転させた値で上書きする
      }
  } // 行列を操作する際の定型文
  // 次に各行の要素を反転させる
  return transposed.map(row => (
    row.reverse())
    );
}

const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

console.log(rotateMatrix(matrix));
// [
//     [7, 4, 1],
//     [8, 5, 2],
//     [9, 6, 3]
// ]
```

### 感想
ChatGPTさまさまで何とか解けました。
ただ、自分で1からコードを思いつくということは到底不可能…
ま、知らないことが多すぎるからしょうがないね！
数学のパズルを解いているみたいで楽しかったです。
#0045（2024/02/12）memo「良いコード/悪いコードで学ぶ設計入門」第5章~低凝集~

# 「良いコード/悪いコードで学ぶ設計入門」第5章~低集性~　を読んで

## アクティブリコール
- プリミティブ型を多用すると、変数が多くなる→データ型を使う方が好ましい
- staticメソッドはクラス変数を使わないため、変数が多くなり、凝集度が大きくなる
- common関数やutil関数もスコープが大きい→共通系はloggerとかで、スコープが明らかなcommon関数は別途用意する

## 再読
- staticメソッドの使い方→loggerやフォーマット変換などの中身に依存しないメソッド
- staticメソッドはインスタンス化せずに使えるため、インスタンスの状態に依存しない処理を明確にできる（C言語などの手続き型言語の影響らしい）
- メソッドチェインを使って、インスタンスの奥深い要素を使うと、低凝集に陥りがち→ **デルメルの法則**
- 「尋ねるな命じろ」
- 初期化を分散させるには、ファクトリメソッドを使う
santa2024 16th-place Hikari30 part 

おはようございます。Hikari30です。

先日kaggleで開催されたsanta-2024に参加し16位を獲得したので、備忘録用に記事を書いておこうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3626970/5a99dccf-7b18-cfb8-cff1-cf12f43f995e.png)

## 自己紹介

大阪大学2回生です。

普段、atcoderもしていて、ヒューリスティックレーティングは青色です。
アルゴリズムは水色です。

## コンテストに参加したきっかけ
大阪大学のPython会の先輩からおすすめしていただいたのをきっかけに興味を持ちました。
初めてコンペの概要を見たときはLLMとヒューリスティックの融合問題でLLMが得意ではなかったため敬遠していました。
しかし、Xで盛り上がっていたことや、LLMに関する知識がそこまでウェイトを占めないということがわかり本腰を入れて参加するようになりました。

結果的には12月の中盤からの参加になりました。

## コンテストの取り組み

初めは以下の公開コードを参考にして自分でコードを回していました。

https://www.kaggle.com/code/utm529fg/eng-tutorial-7-consideration-of-improvement

日本語で解説がかかれているので非常に理解しやすかったです。

それ以降、近傍の作成方法を変更したり、温度管理などを独自で工夫していました。その結果、50位前後までLB順位を上げることに成功しました。

そして、ある日ディスカッションで話していた外国人から一緒にチームを組まないか？という連絡がありました。とてもうれしかったです。

その後、メンバーが徐々に増えて最終的には5人になりました。

私はチームの中でのSAのアルゴリズム管理や温度調整などを行っていました。

特にid5でのSAでは解空間が非常に膨大でSAを使えるように調整するのが難しかったです。

私たちのチームでは初期解を人手で探してSAに突っ込むということをしていました。

おそらく、これが敗因になってしまったと思っています。

というのも、本コンペでは"最適解"（現在判明している局所最適解のことを指します）を見つけなければ金メダルが取れないコンペであったため、やみくもに探索していたのは無理があったと思います。

途中アルファベット順の解がスコアが低くなる傾向が存在しているということに気づくことができましたが、それ以上探索することができなかったのが悔やまれます。

また、計算資源のリソース勝負になっていた側面があるので、その面でも厳しかったです。

上位の方はキック付きのBeamSearchが多かった記憶です。

来年もリベンジしたいと思っています。

## 最後に

最後まで5人全員熱意を持って取り組みました。

これはリーダーのマネジメントがうまかったと思います。

チームメイト全員にも感謝しています。

ここで得られた知見に関しては業務やAHCで生かしていきたいと思います。


また、私たちのチームのコードが終了一週間前に事故で公開状態になってしまい。それをうまく実行することである程度の解が得られる状況になってしまったことにお詫びします。
TOEIC単語は量とイメージで覚える


# はじめに
TOEICのスコアを効率よく向上させるために、AIを活用した学習法を紹介します。特に、単語の意味を画像でイメージしながら覚えたり、単語の複数の意味を調べる方法について解説します。Chatgptだと無料で制限がある中で勉強はちょっとストレスですよね。
今回、MarkdownAIで作ってみました。


https://mdown.ai/content/482b3f85-18cc-4c94-8cfb-827ad427fa59

Youtube　↓

[![YouTube動画](https://img.youtube.com/vi/UpWd1JNrQTY/hqdefault.jpg)](https://youtube.com/shorts/UpWd1JNrQTY?feature=share)





# 単語はイメージで覚える

### 1. AIで単語の意味を画像でイメージする

英単語を覚える際に、文字情報だけでなく視覚的な情報を活用すると記憶に定着しやすくなります。以下の方法で、AIを活用したイメージ学習が可能です。


#### 画像生成AIを活用する

例えば「apple」という単語を入力すると、AIがリンゴの画像を生成してくれます。

抽象的な単語（例えば"success"）も、イメージしやすいビジュアルに変換できます。

画像検索と組み合わせる

単語を入力すると、その意味に関連する画像が自動表示されるツールを使う。

Google画像検索や、AIが生成するビジュアルデータを活用する。



<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/84d2befe-7c26-487d-9d76-68204403855d.png" width=70%>





### 2. AIで単語の複数の意味を調べる

英単語には、1つの意味だけでなく文脈によって異なる意味を持つものが多くあります。AIを使うことで、効率的に単語の多義性を理解できます。

AI辞書を活用する

例えば「bank」は「銀行」だけでなく「川の土手」という意味もあります。

AIが文脈に応じた最適な意味を提示してくれます。

#### 例文生成AIを使う

「run」という単語の例文をAIに生成させると、「彼は毎朝走る（run）」「会社を経営する（run a company）」など異なる使い方がわかる。


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/306f7b8d-48d3-4d8a-8288-8b6699b174e7.png" width=70%>




## まとめ

AIを活用すると、単語の学習がより直感的で効果的になります。MarkdownAIは無料で使えるところがとてもすばらしい。
つい先日までは画像の生成AIは使えなかったが、いつの間にか使えるようになり機能も充実しています。HTMLの勉強のためにTOEICの勉強もできる。とても素晴らしいサイトです✨



## MarkdownAI - Prompt 

####  -- サイト --　gpt-4o-mini
![スクリーンショット 2025-02-12 21.48.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/ff227d20-f304-45c4-891c-f7f500a1aaf2.png)

#### -- 画像 --　　dall-e-3
![スクリーンショット 2025-02-12 21.50.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3636287/a5c5c84e-a674-4a58-b05b-6fc250e0a676.png)
AIのレベルを理解する：ANI、AGI、ASIの比較

Siriのようなパーソナルアシスタントから高度な学習システムまで、AIは私たちの生活や仕事のあり方を日々変革し続けています。しかし、AIにはさまざまな種類があり、それぞれ独自の能力を持っていることをご存じでしょうか？ これらの違いを理解することは、AIが私たちの生活に与える影響や可能性を正しく把握する上で非常に重要です。

このブログでは、AIの主要な3つの種類である人工狭義知能（ANI：Artificial Narrow Intelligence）、人工汎用知能（[AGI：Artificial General Intelligence](https://arbisoft.com/blogs/agi-explained-future-of-artificial-intelligence)）、**人工超知能（ASI：Artificial Superintelligence）**について詳しく解説し、それぞれの能力を比較します。これにより、現在のAIの立ち位置と、未来に何が待っているのかを明確に理解できるようになります。

# 人工知能（AI）の簡単な概要
種類について詳しく見る前に、まずAIとは何かを簡単に理解しておきましょう。シンプルに言えば、AIとは機械が人間の知能を模倣できるようにする技術のことです。機械学習アルゴリズムを活用することで、コンピュータはすべての動作を明示的に指示されなくても、タスクを遂行できるようになります。つまり、機械が独自の方法で「賢くなる」ように教える技術なのです。

非技術者の視点から見ると、AIはロボットが複雑な作業をこなす技術のように思えるかもしれません。しかし、実際にはデータから学習し、意思決定を行うスマートシステムのことを指します。企業がAIの能力を最大限に活用するには、[適切なソフトウェア開発パートナー](https://arbisoft.com/services/software-development/custom)を見つけることが成功の鍵となります。例えば、AIはメールのフィルタリング、車の自動運転、病気の診断など、私たちの生活のさまざまな場面で活用されています。専門家は、AIを「人間の介入なしで動作し、経験を通じて継続的に向上する一連の指示（アルゴリズム）」と定義しています。

では、AIの3つのカテゴリについて見ていき、それぞれの違いを詳しく解説していきましょう。

# 人工知能（AI）の種類
AIはその能力に基づいて、主に次の3つのカテゴリに分類されます：

1. 人工狭義知能（ANI：Artificial Narrow Intelligence）
2. 人工汎用知能（AGI：Artificial General Intelligence）
3. 人工超知能（ASI：Artificial Superintelligence）

これらのカテゴリは、知能レベル、能力、世界に与える影響の観点から異なります。それでは、それぞれを詳しく見ていきましょう。

## 人工狭義知能（ANI：Artificial Narrow Intelligence）
ANI（弱いAI）とは、特定のタスクを実行するように設計されたAIシステムのことを指します。これらのシステムは特定の分野では非常に優れたパフォーマンスを発揮しますが、プログラムされた範囲を超えることはできません。

#### ANIの限界：

1つのタスクに特化しているため、新しい仕事に適応できない
コンテキストや意味を理解せず、決められたアルゴリズムの範囲内でしか動作できない
それでも、ANIは私たちの日常生活において効率性と生産性を向上させる重要な役割を果たしています。

#### 代表的なANIの例：
1. AlphaGo（囲碁AI）
2. Siri（バーチャルアシスタント）
3. ChatGPT（自然言語処理AI）

## 人工汎用知能（AGI：Artificial General Intelligence）
**AGI（強いAI）**は、人間の知能を完全に再現することを目指すAIです。単にタスクを実行するだけでなく、学習し、思考し、人間のように理解する能力を持ちます。

AGIが実現すれば、複雑な問題を解決し、感情を理解し、現実世界のコンテキストに基づいて意思決定を行うことが可能になります。つまり、人間ができるほぼすべての仕事をAIが担うことができるようになります。

現在、私たちはANIの発展段階にあり、AGIはまだ実現していません。 しかし、多くの研究者やテック企業がAGIの開発に巨額の投資を行っています。

#### AGIの開発に取り組んでいる企業の例：

1. Microsoft（AGIの研究に数十億ドルを投資）
2. OpenAI（高度な言語モデルの開発）

現時点では、一部の大規模言語モデルが「チューリングテスト」（AIが人間のように振る舞えるかどうかを判断するテスト）を通過するケースもありますが、本当の意味での自己認識や推論力はまだ持っていません。


# 人工超知能（ASI：Artificial Superintelligence）
ASI（超知能）とは、AIが人間の知能をあらゆる面で超える状態を指します。論理的思考、推論力、創造性、さらには感情知能においても人間以上の能力を持つAIのことを意味します。

現在、ASIはまだ理論的な概念にすぎません。しかし、多くの研究者は、AGIが実現すれば、やがてASIに進化する可能性が高いと考えています。

#### ASIの期待されるメリット：

地球規模の課題解決（気候変動、医療、宇宙探査など）
科学技術の飛躍的な発展（新しい物理法則の発見など）
経済や産業の劇的な効率化

# AIの未来へ
私たちは現在、人工狭義知能（ANI）の時代に生きています。この段階では、AIは特定のタスクにおいて卓越した能力を発揮します。しかし、研究が進むにつれ、人工汎用知能（AGI）の実現が近づき、最終的には人工超知能（ASI）に到達する可能性もあります。

この進化は、AIの制御、倫理、社会全体への影響といった重要な課題を提起します。AIの発展によって得られるメリットは計り知れませんが、同時に慎重な対応が求められます。これらの技術が私たちの価値観や目標と調和する形で発展することが不可欠です。

では、AGIの到来はすぐそこまで来ているのでしょうか？ それとも、まだその実現には長い道のりがあるのでしょうか？ あなたはどう思いますか？
VUEのMount

# マウントの利用について：

Mountは、ユーザーとVueを繋ぐAPI、つまりマウントである。

## 単一プロジェクトにおけるMount

Vueの公式サイトを読むと、アプリケーションの作成の項目で、マウントの使用方法が簡単に紹介されている。例として、`app.mount("#app")`のようにDOMをマウントすることで、ページを構築する、これは最も一般的なやり方だ。

## 複数Mount

上記項目を少し読み進めると、複数のMountをどのように利用するかの説明がある。複数の`Mount`を宣言し、それぞれにパラメータを設定することで、複数のコンポーネントを管理できる。

しかし、それよりも、複数のVueフレームワークを構築する方が良いのではないか？この疑問を踏まえ、下記の場面を検討してみよう。

## マイクロフロントエンド

プロジェクトが複雑化しすぎる場合、様々な解決策があるが、現在よく利用されているのはマイクロフロントエンドだ。マイクロフロントエンドとは、データ間の関係性の結合度を**疎結合**にすることである。結合度の高いコンポーネントやデータを分離し、それぞれの担当者が管理する。しかし、それならば、なぜ新しいVueフレームワークを作成しないのか？下記のポイントを考慮する必要がある：

1.  パフォーマンス：複数のフレームワークを起動すると、PCやシステムの負荷が高くなる。
2.  値の受け渡し：`app.Mount`を使用するよりも、異なるプロジェクト間で値を渡すのは困難である。
3.  ルーティング管理：上記2と同様、異なるプロジェクト間での画面遷移は困難である。
4.  コスト：複数プロジェクトと単一プロジェクト管理では、管理コストが異なる。

### ReactとVueの混用

何らかの理由で、例えばReactからVueへの移行期間、あるいはチーム間の技術的な都合で、ReactとVueを混用する必要がある場合、同じ疑問が生じる。ReactとVueでそれぞれ別のプロジェクトを作成して管理するのではなく、なぜ混用するのか？

以下の点が考慮される：

1.  コスト： Web Componentsの形式で各ページを管理する場合、ReactとVueをそれぞれ管理するよりもコストを抑えられる。
2.  パフォーマンス： 複数のアプリケーションを管理するよりも、単一のアプリケーションを管理する方が効率的である。
PMBOK原理・原則：複雑性の管理

プロジェクトの複雑性管理について整理してみました🤔

特に意識したポイント：
・複雑性と複雑さの違い
・早期発見の重要性
・適応型アプローチの活用

実務で役立てば幸いです。

![マインドマップ (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/7bb589a3-5053-fa94-a3f0-7263658ea93c.png)


## プロジェクトにおける複雑性を認識し、適切に対処する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/0cf054c3-345b-db45-c885-a3beaa04cc2c.png)

## 複雑性と複雑さの違い

![complexity-comparison-simple.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/b65d1178-078c-4e6b-bb63-5b21328879dd.png)

- **複雑性（Complexity）**: 多数の要素やステークホルダーが関与し、それらの相互作用が予測困難な状態。
- **複雑さ（Complication）**: 難易度は高いが要素間の関係は比較的予測可能な状態。組み合わせや作業量が多いために難易度が上がっているが、原理上は論理的に解明できる。

たとえば、大規模ITシステムの要件定義は、さまざまな部署や外部システムとの連携が絡むため複雑性が高くなりがちです。一方、各システムの移行手順が決まっていて手順数が多いだけの場合は複雑さ（Complication）が高い状態であり、手順や計画を整理すれば対応可能です。

## 複雑性の管理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/6e61a802-4710-96d3-5391-3cad754a8a5a.png)

「12の原則」の中で複雑性に対処するための考え方が重視されています。特に、「システム思考」や「ステークホルダーとの協働」といった原則が、プロジェクトの複雑性を管理するうえで重要な役割を果たします。

- **ステークホルダーとの協働**: 多様な利害関係者を巻き込み、複雑な状況で調整・合意形成を行う
- **リーダーシップ行動**: プロジェクトのビジョンやゴールを明確化し、チームが柔軟に動けるようにリーダーとして支援する
- **システム思考**: 前回紹介したように、プロジェクト全体を俯瞰し、要素間の相互作用を理解する

こうした他の原則と組み合わせることで、複雑性をより効果的にコントロールできるとされています。

## 複雑性を早期に察知し、管理するポイント

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/658fe5d1-9ced-aeee-1a02-7e1a33bd9164.png)

### 1. 複雑性を早期に察知する
- **システム思考**を用いて相互影響を俯瞰する。
- **ステークホルダー分析**や**リスクアセスメント**を実施。

### 2. 複雑性を分解・整理する
- **WBS（Work Breakdown Structure）**を活用し、作業を細分化。
- **影響範囲**や**相互依存関係**を明確化。

### 3. コミュニケーションとリーダーシップ
- ステークホルダー間の**情報共有と意思疎通**を強化。
- プロジェクトマネージャーは**ビジョンと目的**を明示。

### 4. 変化への柔軟性と適応力
- **アジャイル型**や**イテレーティブなアプローチ**を採用。
- 変化マネジメントプロセスを明確化し、迅速に対応。

### 5. 継続的なリスク評価と対応策
- **リスクマネジメント**を継続的に実施。
- **教訓学習**を活用し、再発防止策を講じる。

### 6. 適応型アプローチと反復型計画策定
複雑性の高いプロジェクトでは、プロセスを一度で決め切らずに短いサイクルを繰り返す**適応型アプローチ**や**反復型計画策定**を取り入れることが効果的です。

- **短いイテレーション**: 一度の計画サイクルを短く区切り、実行と検証を繰り返す。変化を取り込む余地を常に残しておく。
- **頻繁なフィードバック**: チームやステークホルダーからのフィードバックをこまめに受け取り、次のサイクルの計画に活かす。
- **優先度の見直し**: イテレーションごとに要求や課題の優先度を再評価し、リソース配分やスケジュールを柔軟に調整する。
- **リスク低減**: 不確実性が高い領域や技術的難易度の高い部分を先に検証することで、リスクを早期に顕在化させる。

このような反復型計画策定により、プロジェクト環境の変化に迅速に対応でき、複雑性に含まれる不確実性を段階的に解消・軽減していくことが可能になります。

### 7. 具体的な事例
- **大規模システム移行プロジェクト**: 新しい基盤への移行には多種多様なステークホルダーが存在し、要件変更や外部システムとの連携調整など、相互作用が多岐にわたる。そのため、システム思考と複雑性管理が不可欠。
- **複数部署を横断する組織改革プロジェクト**: 人事制度や評価制度などが絡み合い、影響範囲が組織全体に及ぶ。関係者の合意形成には、リスクや不確実性を踏まえた丁寧なコミュニケーションが求められる。

## まとめ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648069/acbe228c-6502-6a4b-fa85-4c7faa572902.png)

プロジェクトマネジメントにおける複雑性の管理は、プロジェクトの成功確率を高めるカギです。ただし、複雑性と複雑さを区別し、複雑性に対しては不確実性や相互作用をしっかりと見据えたうえで、早期発見と分解・整理、継続的なリスク管理、コミュニケーション強化などのアプローチを組み合わせる必要があります。

特に**システム思考**や**リーダーシップ**との相乗効果が重要とされています。また、**適応型アプローチ**や**反復型計画策定**を活用することで、不確実性の高い状況でも柔軟に計画を更新し、複雑なプロジェクトを着実に前進させることが可能です。今後の実務でプロジェクトを進める際には、この複雑性管理を意識して取り組むことで、想定外のリスクや混乱を最小化できるでしょう。
対話が必要なsftp通信を自動化する

# はじめに
パスフレーズ付きの秘密鍵を使ったsftp処理をLinuxのシェルスクリプトで実装する際に、対話を自動化する必要がありました。
その時に、検証した結果などを簡単にまとめてみました。

# 解決策1-expectコマンド
対話を自動化することができるexpectコマンドを使う方法です。
ただ、expectの記法はちょっと独特で、わかりにくいかもしれません。

expectコマンドがインストールされていない場合は、dnf等でインストールを。
```
dnf install expect
```
以下シェルで記載した場合の例です。
※sftp接続時にプロキシを経由させる必要があったので、sftp接続時のオプションで指定しています。
```
## expectコマンドの処理開始
expect -c "
## expectコマンドのタイムアウト秒設定
set timeout 10
## sftpコマンド実行
spawn sftp -o \"ProxyCommand nc --proxy-type http --proxy "プロキシ" %h %p\" -o "StrictHostKeyChecking=no" -i "秘密鍵のファイルパス" ユーザ名@ホスト名
## "Enter passphrase for key"が返ってきたら、処理を継続
expect {
        default {exit 1}
        \"Enter passphrase for key\"
}
send \"パスフレーズをここに記載\"
expect {
        default {exit 1}
        \"sftp>\"
}
send \"cd 移動先ディレクトリ\r\"
expect {
        default {exit 1}
        \"sftp>\"
}
send \"put ファイル名\r\"
expect {
        default {exit 1}
        \"sftp>\"
}
exit
"
```

下記は補足事項です。

・expectのエラーハンドリング
expectの処理は、正常でも異常でも「exit 0」で終わってしまうようなので、正常に実行できなかった場合は、「exit 1」を返すように記載しています。
```
expect {
        default {exit 1}
        \"sftp>\"
}
```
・send行のエラー確認ができない
expect行と同じように、エラーコードを指定できないみたいでした。
(もしかしてできるやり方もあるのかもしれませんが、今回はできませんでした。。)
そのため、sftp処理が正常に実施されたかどうかは別途ログ等から確認する必要がありそうです。
(ログに正常終了を認められる文字列が出力されていなければ、アラートとするみたいな。)

# 解決策2-sshpass&scpコマンド
パスワード入力を自動化するsshpassコマンドとscpコマンドを組み合わせることで、ワンライナーで記載ができるようでした。
こちらの方がエラー制御も簡単だし、可読性も高そうです。コマンドにこだわりがないなら、こちらの方がベターかもしれません。
```
sshpass -p 'パスフレーズ' -P "Enter passphrase for key " scp -o \"ProxyCommand nc --proxy-type http --proxy "proxyサーバ" %h %p\" -o "StrictHostKeyChecking=no" -i "秘密鍵のファイルパス" ユーザ名@ホスト名
```


# 参考
下記の記事を参考にさせていただきました。ありがとうございました。

https://qiita.com/ine1127/items/cd6bc91174635016db9b

https://qiita.com/komeiy/items/11ac7ed2a0027d549764

https://qiita.com/ysd_marrrr/items/5cc395abd2c0b99d1138
Streamlitに認証機能が追加された！

# はじめに
Streamlitのバージョン1.42.0からOpenID Connect(OIDC)によるユーザー認証が追加されました。

https://docs.streamlit.io/develop/concepts/connections/authentication

さっそく試してみました。

# OIDCプロバイダーの準備
Google IdentityやMicrosoft Entra IDが有名ですが、今回はAuth0で試してみます。

ローカルで開発しているので、OIDCプロバイダーのAllowed Callback URLsに`http://localhost:8501/oauth2callback`を追加しておきます。

# 実装
## OIDCプロバイダーの設定
`.streamlit/secrets.toml`に使用するIDプロバイダーの設定を記載します。
今回はAuth0の例です。
```toml
[auth]
redirect_uri = "http://localhost:8501/oauth2callback"
cookie_secret = "xxx"

[auth.auth0]
client_id = "xxx"
client_secret = "xxx"
server_metadata_url = (
    "https://{account}.{region}.auth0.com/.well-known/openid-configuration"
)
client_kwargs = { "prompt" = "login" }
```

`redirect_uri`や`client_id`などを設定します。
複数プロバイダーを設定することも可能です。

https://docs.streamlit.io/develop/concepts/connections/authentication#using-multiple-oidc-providers


## Streamlitのコード

```python:main.py
import streamlit as st

if not st.experimental_user.is_logged_in:
    if st.button("Login with Auth0"):
        st.login("auth0")
else:
    st.write(f"Hello, {st.experimental_user.name}!")
    st.button("Log out", on_click=st.logout)
```

 - `st.login()`
     - ユーザーをIDプロバイダーにリダイレクト
 - `st.experimental_user`
     - `is_logged_in`属性でログイン状態を確認できる
 - `st.logout()`
     - ユーザーのブラウザからIDクッキーを削除

# テスト
`main.py`を実行して、ブラウザにアクセスすると設定したログインボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3968617/8afcf406-6d06-428e-b54f-f7d6f0179e2f.png)

このボタンをクリックすると、Auth0のログイン画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3968617/faf1dffb-bcd8-4873-935c-2dcdcf85ed33.png)

Auth0でユーザー管理しているユーザーでログインすると、成功して画面が遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3968617/e9657076-162d-44c0-ab63-ab8574f1cb2d.png)

当たり前ですが、ユーザー管理していないアカウントでログインしようとすると失敗し後続の処理に行けません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3968617/49aefabc-5c32-480c-bda0-ab8cf15df550.png)

ちゃんとユーザー認証が機能していることが確認できました！

# おわりに
Streamlitに追加された認証機能を試してみました。
標準機能として認証が追加されたので、開発しやすくなったのではないでしょうか。
ユーザー認証機能によって、ユーザーに合わせてアプリをパーソナライズすることで可能になります。
セッション間の履歴が保存されるチャットボットなど、様々なユースケースで利用できそうです！
Windowsコマンドプロンプトでファイル一覧を表示する


Windowsのコマンドプロンプトで、任意のディレクトリ下のフォルダとファイルの一覧を表示する方法です。

```
> dir /S /B
```
オプションの意味は以下の通り。

/B : 指定されたディレクトリおよびそのサブディレクトリのすべてのファイルを表示します。
/S : 指定されたディレクトリおよびそのサブディレクトリのすべてのファイルを表示します。

表示結果例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703624/d05d48b0-5798-7d90-4b5a-433df9aefd28.png)

フルパス＋ファイル名を表示してくれるので、なかなか便利です。
【JavaScript】コールバック関数について

## まずはコールバックとは？

**コールバックとは！？** 関数の引数に別の関数を指定する処理をいいます。

Aという関数が実行のあと、引数で指定したBという関数を実行するということが可能になります。

例えば、サーバからデータを取得したあとに次の処理を実行したい場合によく使います。

サーバへのアクセスは時間がかかるので、処理を待たないで実行すると不具合の原因にもつながります。

## コールバックの構文の書き方

```JavaScript

function 関数名(別の関数名(コールバック)) {

	処理を記述する
	
	引数に指定した関数を実行
	callback();
}

```

通常の関数を記述する感覚で処理を実行します。
ここで、ミソなのは引数に指定しているのが関数なので処理の最後にその関数を実行することです。

## コールバック関数の実行方法例

実際のプログラミングの方法を書いてみます。

コールバックの処理がわかりやすいように **setTimeout()** を記述してみます。

```JavaScript

function test(callback) {

	setTimeout(function() {
		console.log("testのfunctionが実行されました");
		callback();
		},1000);
}
```

この例では、**test()** という関数を作って10秒の時間を費やす処理を記述します。
引数には **callback** と記述しています。

ここで大切なものは、**処理の最後に引数で指定した関数を実行する** ということです。

### 実行方法は？

では上記プログラムを実行する方法を記述します。

```JavaScript
function callbackTest() {
	console.log("callbackTestが実行されました");
}
```

こちらは、簡単な文字列をコンソールログへ出力するだけの簡単な関数です。
そして、コールバックを使って処理を実行するためにはこのように記述します。

```JavaScript
test(callbackTest);
```

実行すると

実行結果
>testのfunctionが実行されました
callbackTestが実行されました

最初にした**test()**　の引数に関数をしていることがわかります。」
**test()は10秒** かかる処理を行っているので、**calbackTest()** 関数をコールバックして実行します。

実行結果を見ると順番に関数が実行されているのがわかります。
[Python]前進差分・後退差分・中心差分で数値微分を求める方法

# はじめに
数値微分は、数字や数値解析で重要な手法です。特に前進差分(Forward Difference)、後退差分(Backward Difference)、中心差分(Central Difference)は。数値的に導関数を近似する際に使われます。今回Pythonを用いて、これら3つの差分法を実装し、導関数の近似と誤差を計算する方法を紹介します。
# 差分法の概要
1. 前進差分(Forward Difference)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951071/2d8c5caa-c05f-0c9d-5317-9fdf20199274.png)

1. 後退差分(Backward Difference)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951071/6381cf51-0099-a5b8-bec7-7c938d923628.png)

1. 中心差分(Central Difference)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3951071/33199f75-fbf1-eb9c-66f8-79dacc11f66c.png)

中心差分は精度が高く、誤差が前進差分や後退差分よりも小さくなることが多いです。これらをPythonで実装し、結果を比較します。
# 実装コード
```py:differential.py
import numpy as np

# 関数 f(x) を定義
def f(x):
    return -x**3 + 3*x + 2

# 前進差分
def forward_difference(x, h):
    return (f(x + h) - f(x)) / h

# 後退差分
def backward_difference(x, h):
    return (f(x) - f(x - h)) / h

# 中心差分
def central_difference(x, h):
    return (f(x + h) - f(x - h)) / (2 * h)

# 相対誤差を計算
def relative_error(estimated, exact):
    return abs(estimated - exact) / abs(exact)

# 定数
h = 0.1  # 微小量 h
x = 0.5  # 微分点 x
exact_derivative = -3 * x**2 + 3  # 正確な微分値 f'(x)

# 差分法の計算
forward = forward_difference(x, h)
backward = backward_difference(x, h)
central = central_difference(x, h)

# 相対誤差の計算
forward_error = relative_error(forward, exact_derivative)
backward_error = relative_error(backward, exact_derivative)
central_error = relative_error(central, exact_derivative)

# 結果を丸める
forward_rounded = round(forward, 2)
backward_rounded = round(backward, 2)
central_rounded = round(central, 2)
forward_error_rounded = round(forward_error, 3)
backward_error_rounded = round(backward_error, 3)
central_error_rounded = round(central_error, 3)

# 結果の表示
print("(1) 前進差分 f'(0.5):", forward_rounded)
print("(2) 前進差分 ε(0.5):", forward_error_rounded)
print("(3) 後退差分 f'(0.5):", backward_rounded)
print("(4) 後退差分 ε(0.5):", backward_error_rounded)
print("(5) 中心差分 f'(0.5):", central_rounded)
print("(6) 中心差分 ε(0.5):", central_error_rounded)
```
# 実行結果
```
(1) 前進差分 f'(0.5): 2.09  
(2) 前進差分 ε(0.5): 0.071  
(3) 後退差分 f'(0.5): 2.39  
(4) 後退差分 ε(0.5): 0.062  
(5) 中心差分 f'(0.5): 2.24  
(6) 中心差分 ε(0.5): 0.004  
```
# 結果の考察
- 前進差分と後退差分の相対誤差はそれぞれ0.071,0.062であり、比較的小さいですが、まだ精度の向上が可能
- 中心差分は誤差が0.004と非常に小さく、精度の高い結果を提供
これらの結果から、精度が重要な場合は中心差分を使用することが推奨されます。
# まとめ
本記事では、Pythonを使った数値微分の3つの差分法を実装し、誤差の比較を行いました。これらの微分方程式を解く際にも重要な基礎知識となりますので、ぜひ他の関数でも試してみてください。最後まで読んでくださり、ありがとうございました。もし改善点や質問があれば、ぜひコメントしてください！
【備忘録】EC2インスタンスのインバウンドルールのソースにセキュリティグループを指定した時はパブリックIPで疎通出来ない

# はじめに
`踏み台サーバ`を作って`Webサーバ`への`SSH`を基本閉じておくことでセキュアにしたい。

# 問題点
`Webサーバ`側のインバウンドルールの`SSH`に踏み台サーバのセキュリティグループを指定した場合、`踏み台サーバ`から`Webサーバ`の`プライベートIP`を指定すると`SSH`接続が出来るが、`パブリックIP`を指定すると`SSH`接続が出来ない。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/553db4fa-9e45-47bc-ad5c-905dd1a39e95.png)
**↑Webサーバのインバウンドルール**

# 解決のための仮説
**Q.EC2インスタンス**から**パブリックIP**に対して`SSH`すると、インターネットを通った上で`SSH`することになっているのでは？
(つまり**SSH元IP**は**踏み台サーバのパブリックIP**になっているという意味)

**1.Webサーバのインバウンドルールに踏み台サーバのパブリックIPからのSSHを許可する**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/b134f808-ee9c-41f1-8d5e-cd0ef9214193.png)
**2.パブリックIPを指定してSSHする**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/c74c9d37-993f-4079-b084-8e0d9dc91c39.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/d1c38e44-f19f-44ed-88e0-40b10a4d0465.png)

通ったため、恐らく仮説は正しかった。

# 最後に
インバウンドルールにセキュリティグループを指定すると、そのセキュリティグループを持つ **EC2インスタンスのローカルIPからの通信(VPC内に閉じた通信)** を許可するという意味合いになっていると思います。
プログラマのための文字コード技術入門

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3976844/b86a0013-29d3-32a1-44a9-668573a93ab9.png">


読書記録

## 読者プロフィール
文字コードはShift_JISとUTF-8くらいしか知らない。全部UTF-8でいいんじゃない？くらいの雑な理解。￥マークと\の表記違いは認識していたがShift_JISはASCII互換があると思ってた。本書を読んで誤解だったと知った。

## 雑感
本書は複数の技術系の書籍の参考文献に載っていて、「文字コードについてこれを読めばOK」と書かれていて気になっていた本。

文字そのものの難しさ、各国の歴史、ネットワークの発展などが絡み合い、一見すると単純にも思える文字の扱いが難解なものになっていることがよくわかる。日本語をベースに話が進むが、256文字以上を持つ言語ではどこも同じような話がありそうなので日本語に特化した話ではない。アジア圏の文字の複雑さがある一方で、アメリカさんのASCIIはシンプルすぎて不思議・・・。

アイヌ文化が文字を持たないことや、閉音節、変体仮名といった恥ずかしながら今まで知らなかった日本語について知ることもできた。文字コードに対して確かな理解が得られる良書と思う。

# あらすじ


# 代表的な符号化文字集合
符号化文字集合とは、文字集合ひとつひとつに一意な値を割り振ったものを指す。
## ASCII派生（1バイト文字集合）
最もシンプルな文字集合。ASCIIをベースに各国にローカライズされたものが多数発生している。日本版（JIS X 0201）は片仮名を含んでいる。
|符号化文字集合  | サイズ |メモ  |
|---|---|---|
|ASCII (ISO/IEC 646) |7bit  |0x5Cは\(バックスラッシュ)  |
|ISO/IEC 8859-1(Latin-1)|1byte|ACCII互換あり。0x80~0xFFに西欧言語を収録|
|JIS X 0201  |1byte  |ASCII互換ありだが、0x5Cは￥  |

## 日本語文字集合
日本語に特化した文字集合。多数の漢字を収録している。
|符号化文字集合  | サイズ | メモ|
|---|---|---|
|JIS X 0208  |2byte  | 全て2byteなのでaや2といった文字も2byte |
|JIS X 0212|2byte|JIS X 0208を前提とし、捕捉するもの|
|JIS X 0213|2byte|JIS X 0208の上位互換|

## 国際符号化文字集合
世界中の文字を含める。文字空間が広大すぎて古代文字なども収録されているらしい。
|符号化文字集合  | サイズ | メモ |
|---|---|---|
|Unicode|4byte||


# 代表的な符号化方式
符号化方式とは符号化文字集合を実際にデータとして実現する方法を指す。本書では数多くの符号化方式が紹介されているが、個人的にはあまり見かけないものもあると感じた。主観で重要だと思う符号化方式についてまとめる。

## Shift_JIS
JIS X 0201とJIS X 0208を用いる符号化方式。
1バイト部分としてはJIS X 0201をそのまま利用する。そのため大部分はASCIIと一致するが、￥記号など一部固有となる。

２バイト文字の１バイト目にJIS X 0201の文字を置いてしまうと１バイトか２バイトであるかの区別がつかないため、１バイト目としてはJIS X 0201で使用していない、0x81～0x9Fと0xE0～0xEFが使用できる。ASCIIやJIS X 0201と互換する符号化方式はASCII範囲の文字が二重に存在することになるが、そのような文字はASCII側で扱う約束とのこと。

## EUC-JP（Extended Unix Code）
ASCIIとJIS X 0208を用いる符号化方式。
1バイト部分としてはASCIIを利用する。（0x7F以下）
それ以外は0xA1～0xFE(ASCIIを含まない領域)の2バイトで1文字を表現する。符号化文字集合としては基本的にJIS X 0208を用いる。

特殊な制御文字（シングルシフト）を用いることで、直後の文字にJIS X 0212などを使うことができる。

## UTF-8
Unicodeの符号化方式。
ASCII互換がある。
ASCII以外の文字に関しては2～4バイトで符号化する。


## UTF-16
Unicodeの符号化方式。
ASCII互換は無い。（Aの符号は0x0041と2バイトになるため）

基本多言語面（BMP）と呼ばれる多様な言語の基本表現に関する文字が含まれる2バイトのセットに関しては、そのままその値を符号とする。つまりBMPの文字はそのまま符号化される。

BMP以外の文字に関しては２つの符号（2バイトが２つ）を用いて表す。分割された領域は上位サロゲート、下位サロゲートと呼ばれる。分割して配置し、1文字を表す仕組みをサロゲートペアと呼ぶ。



# 理解し辛かったところメモ
## 7bit符号化
あまり理解できずに読み進めていたこともあって最初意味が分からなかった。
ある漢字（2バイトの番号で表現）を7bitで符号化するとき、元の番号が0x0000～0xFFFFまですべて使う場合は7bit符号化すると3バイトで表現できる。
例えば0xFFFFであれば 0b0-------という型に当て込んでしまうことで0x7F,0x7F,0x03 と7bit×3バイトで表現できる。

元の番号の幅が狭ければ7bit符号化後も2バイトで表現できる。理解してしまえば何も難しい話ではなくただそれだけの話だった。

## GL,GR
GL,GRという表現があるが、これは単純に1バイトのうち
GL 0x00～0x7F
GR 0x80～0xFF
というだけのもの。ASCIIやASCII派生の符号化方式で現れる考え方。UTF-16など1バイト文字の登場しない符号化方式では現れない。

### GRに呼び出す/固定する
この場合GL(0x00～0x7F)はASCII(派生含む)用に予約されていることが多いはず。
* GRに呼び出すとは、
特殊文字（シフトやエスケープ）によってGR(0x80～0xFF)の使い方を変える。エスケープ後の1文字をドイツ版で符号化したりフランス版で符号化したりさせることを指す。
* GRに呼び出した状態で固定
ASCII以外の文字は1バイト毎は0x80以上とし、複数バイトで符号化する、という意味。

### GLに固定（GR不使用）
0x00～0x7Fの範囲の符号のみ使うということ。
7bit符号化で用いる。なお7bit符号化とは1文字を7bit×n（通常はn=2）で表現することを指す。
useEffectが２回実行される

## エラー内容
`useEffect` を使用してエラー時の表示を実装したところ、エラーの警告が２回表示された
![スクリーンショット 2025-02-06 17.36.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3927903/6d78063e-1c77-77ce-93b9-ba774569c976.png)
## 環境
・React: 18.3.1
・chakra ui: 2.10.5
・axios: 1.7.9
## 原因
React18のStrictModeによって２回実行されることが原因

## StrictModeを削除する（非推奨）

StrictModeを削除すれば２回実行されなくなるので原因はこれだが、
本番環境でのバグ検出に役立つため **削除は推奨しない**
```diff_javascript
createRoot(document.getElementById("root")!).render(
-  <StrictMode>
     <App />
-  </StrictMode>
);
```
## `useEffect` の依存配列を指定する（未解決）
依存配列を指定すると 1回だけ実行されるとあったので試したが、解決しなかった
```react
useEffect(() => getUsers(), [getUsers]);
```

:::note warn
注意
`getUsers` が `useCallback` でメモ化されていることを確認する
していない場合はレンダリングのたびに `useEffect` が発火する可能性がある
:::
参考

https://qiita.com/honey32/items/62edf5165aced7d0c4bf


## `useRef` を使う（解決策）
`useRef`を使い、初回のみ実行されるようにすることで解決した
```react
  const connectionRef = useRef(false);
  useEffect(() => {
    if (!connectionRef.current) {
      getUsers();
      connectionRef.current = true;
    }
  }, []);
```

https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development


## 解決策は正しいのか？
`useRef`で 2回の実行を防ぐことで解決したが、これが正しい解決策なのかを考えてみると、少し自信がない。
もっと良い方法があるのではと思うので、今後より良い方法を見つけたら改善したい
【React】フォームに値を入力しても表示されない（useState）

# はじめに
フォームに文字を入力しようとしても表示されなかった（同じ過ちを何度もしている）ため、備忘録で残します。

# 問題
フォームに値を入力しようとしても、表示されない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/39870061-d376-2a13-3bcd-18e789c1ea59.png)

```react
function App() {
  const [text, setText] = useState('');
  const onChange = () => setText(text);

  return (
    <>
      <input value={text} onChange={onChange} />
      <br />
      <p>{text}</p>
    </>
  );
}
```

# 解決方法
setTextで設定している値が誤っていた。
onChange関数実行時のイベントからオブジェクト・プロパティ(e.target.value)を設定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3993509/fd030281-8791-8af2-05e5-4e88c3e87586.png)

```react
function App() {
  const [text, setText] = useState('');
  const onChange = (e) => setText(e.target.value);

  return (
    <>
      <input value={text} onChange={onChange} />
      <br />
      <p>{text}</p>
    </>
  );
}
```

# おわりに
onChangeイベントが発火した際に、なぜ引数にイベント(e)を設定、e.target.valueで指定しないといけないのか、根本的な理解をしたいです。
一番最初に知りたかった、Next.jsのセットアップ

# はじめに
Next.js の環境構築をしようとするときに、「なんだかんだ毎回調べてるし、まとめておけば後で楽なんじゃ！」とひらめいたので、備忘録もかねて書き始めます。

# Next.jsのインストール
これだけで自動インストールしてくれます。めっちゃ楽です！
```shell
npx create-next-app@latest <Project Name>
```

いろいろ選ぶところありますが、僕はこんな感じです。
（そろそろ AppRooterを使ってみたいを、一年間繰り返してますw）
```shell
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … No
✔ Would you like to use Turbopack for `next dev`? … Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No
```

# (とりあえず) 開発サーバに火を灯してみる！
作成されたディレクトリで、開発サーバーを起動してみる。
```shell
npm run dev
```

以下のURLに接続すると...。
```shell
http://localhost:3000
```

こんな感じになれば成功です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3722068/9de6a9ec-0041-4a60-bf6f-7e43fac6762a.png)

# いろいろな必要なライブラリを入れていく。
ここら辺はご自身で取捨選択しちゃってください！

- headless-ui (UIライブラリ)
```shell
npm install @headlessui/react
```

- heroicons (便利なアイコンライブラリ)
```shell
npm install @heroicons/react
```

- next-themes (ダークモード対応)
```shell
npm install next-themes
```

# さいごに
ご覧いただきありがとうございました！
もしお気づきの点があれば、ぜひコメントで教えていただければ幸いです！
modernbert-ja-130mは『雪国』の冒頭をどうトークナイズするのか

日本語ModernBERTモデル「[modernbert-ja-130m](https://huggingface.co/sbintuitions/modernbert-ja-130m)」がリリースされたので、とりあえずトークナイザを試してみた。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("sbintuitions/modernbert-ja-130m")
>>> tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"])
['
', '国境', 'の長い', 'トンネル', 'を抜け', 'ると', '雪', '国', 'であった', '。', '
', '
', '夜の', '底', 'が', '白', 'くなった', '。', '
']
```

「の長い」や「を抜け」や「ると」が1トークンになってしまっていて、日本語トークナイザとしてはマズイことになっている。これでは、私(安岡孝一)が『[青空文庫ModernBERTモデルによる国語研長単位係り受け解析](http://hdl.handle.net/2433/291645)』で示した手法が、この「modernbert-ja-130m」には乗らないので、[2月9日の記事](https://qiita.com/KoichiYasuoka/items/6b6ecb5361a8fdae6481)と比較できない。それどころか、品詞付与のModernBertForTokenClassificationすら実装が困難なので、[1月3日の記事](https://qiita.com/KoichiYasuoka/items/a89b85e7962665eef93b)とも比較できない。うーん、せっかく3.51兆トークンで鍛えた日本語モデルなのに、うまく使えないよう。
【イベントレポート】【増席】TOKIUM x YUMEMI.grow 若手エンジニアLT勉強会「成長を感じた瞬間発表会」 #yumemi_grow

いつも記事を読んでいただきありがとうございます！
モブエンジニア（[@mob-engineer](https://qiita.com/mob_engineer))です！

今回は2025.02.12（水）に開催したTOKIUM x YUMEMI.grow 若手エンジニアLT勉強会「成長を感じた瞬間発表会」へ参加しましたので、アウトプットとしてイベントレポートを執筆しました。

初学者でもサクッと読めるように平易な表現で執筆しておりますので、お気軽に読んでいただければ幸いです。

:::note info
誤字脱字、分かりづらい表現に関して極力なくすように心がけていますが、リアルタイムで執筆しておりますので、誤字脱字があるかもしれません。
:::

#### イベントページ

https://yumemi.connpass.com/event/338840/

#### TOKIUMページ

https://www.keihi.com/

# 目次
- LT
    - モバイルエンジニア3ヶ月目で感じたこと TOP 5
    - SQLチューニング成長記 - スロークエリと共に歩み、戦った半年間
    - マネージャーが休職して、自分がやるしかなかった時期（フリーランス編）
    - 記事投稿マラソンを2回完走した感想
- まとめ

## LT

### モバイルエンジニア3ヶ月目で感じたこと TOP 5
- 自己紹介
    - ゆめみ所属の23新卒の方
    - 現在はモバイルアプリ開発を担当されている
- 第5位：プルリクを出せた
    - 自己開発ではプルリクを出す経験が無い
    - プルリクが通ったことで自分のコードがアプリに反映される
- 第4位：資格取得
    - 技術力が足りなくても人権を持てた
    - ゆめみあるある？？
- 第3位：技術書を理解できる
    - 今まで読めなかった書籍を理解できるのは凄い
- 第2位：リファクタリングできる
    - 過去の自分のコードを批評できる
- 第1位：私が作ったモノが見える化出来る
    - 他の人へエンジニアとしてプロダクトを説明できる
- 質疑応答
    - 一番力を入れた資格試験は
        - 応用試験が一番時間が買った

### SQLチューニング成長記 - スロークエリと共に歩み、戦った半年間
- 自己紹介
    - TOKIUM所属の23新卒の方
    - SQLチューニングが好きになった
- 今まで
    - 基本構文は一通り理解しているが、N＋1問題レベルでとどまっている
    - トラブルをきっかけにチューニングを理解し、楽しさを覚えた
- スロークエリ対策PJ
    - PJ前から無駄なクエリ文が散乱していた
    - 自身のコーディングがスロークエリにつながってしまった
    - スロークエリ対策を講じて、事なきを得た
- トラブル方得た知見
    - 大規模なSQL文を修正していく
        - Exist（ループ処理）が重複している
        - 全レコードをチェックしている処理を修正
    - スロークエリが高速化したことの爽快感を得られる
- まとめ
    - SQLチューニングの魅力を知り、成長することが出来た
    - 非効率なSQL文はユーザ数増加に応じて発火していく
        - スロークエリを見つけたらチューニングしていこう

### マネージャーが休職して、自分がやるしかなかった時期（フリーランス編）
- 自己紹介
    - 東北大出身⇒人材系メガベンチャーを得てフリーランスを行っている
    - 現在はWebエンジニア・不動産仲介業の立ち上げを行っている
- 成長した瞬間
    - 新卒3年目に決めたフリーランス
    - ITエージェント事業部にいたフリーランスの年収を知って衝撃を受けた
- 独立に向けたアクション
    - 会社上層部とコミュニケーションを図る
        - 雇用する側が何を期待しているのかを知る
    - 会社以外で学ぶ場に行く
        - 様々な人たちとコミュニケーションを図る
- フリーランスとしての心構え
    - 契約先がいらないと感じたら即契約解除
- 独立後に意識したこと
    - 常に顧客満足を考えた仕事
    - 自身の成長を考えてアウトプットしていく
- まとめ
    - 成長はあくまで手段と考えてみる
    - 新しい領域への挑戦、危機感ある環境で働くのが重要

### 記事投稿マラソンを2回完走した感想
- 自己紹介
    - 夢見所属の24新卒の方
    - Qiita記事投稿マラソンを2回完走した
        - 夏イベント・冬イベント
- 今日伝えたいこと
    - 背伸びの先に真の成長はない
    - 規則正しい生活が重要
- マラソンに取り組んだ理由
    - 新卒として目立ちたかったから
        - 今なら体力があるのでチャレンジできる
    - マラソンを通じて得られたのはQiitaのグッズのみ
- 取り組んでみて
    - 質より量で取り組んだため、クォリティが下がってしまう
    - いいねが付かない状況
    - 終盤にまとめて投稿していたため時間確保が
        - 最終日は有休取得をしていた
- 気づき
    - 無理に背伸びをしても、成長できるわけではない
        - 無理を押し通しても、自分が持っている力以上は出来ない
        - 余裕がないと悪影響が出てしまう
    - 余剰体力で取り組むことが重要
        - 自分が持っている強み・バリューを常に発揮した方がいい
- まとめ
    - 規則正しい生活をしつつ、アウトプットすることが真の成長につながる

## まとめ

若手エンジニアの挑戦話を聞いて、私ももっと頑張っていけるなと思いました。私ももっとアウトプットとキャッチアップを頑張っていきます～！！

最後まで読んでいただきありがとうございました！！
【開発作業効率化】GitHub Copilot Business をエンジニア4名でトライアルしてみた

今まで弊社ではツールの導入があまり進んでいない状況でしたが、AI-TFでの活動で、ついに経費の申請がおり、GitHub Copilot Businessを4名でトライアルすることが決まりました。

## 計画
何かしらAIツールを導入し、効率を上げたり、作業をやりやすくしたいというイメージが
TFのメンバー内にあることがわかったので、製品のリストアップを開始しました。
その中で、GitHub Copilotが第一候補に上がりました。
理由としては、
- Freeプランも最近登場し、業務外で試したところ、今後も継続的に利用する価値の高そうと感じた
- TFのメンバーの前職でも利用していた
ためです。

ただ、全エンジニアに導入するとか、どんなことはやってはいけないとかの判断軸は会社や組織ごとに異なり、
客観性がないため、複数人でトライアルを行い、これ以降の導入計画をまとめるという流れとしました。
### メンバー
トライアルメンバーは業務カバーを網羅させるべく、下記としました。
- Flutterメイン x 1名
- E2EなどのTypeScriptがメイン x 1名
- LaravelなどPHPがメイン x 2名

TF外のメンバーだったり、新卒入社だったり、中途だったりと色々なメンバーを巻き込めると良さそうです。

### 期間
1ヶ月

あまり長くしても、使わない期間などが発生するため、短めに設定しました。

### 費用
19ドル x 4名 = 76ドル(約12,000円)

金額によって承認フローに違いがあったり、インパクトが違うという場合は、
人数調整などが必要かもしれません。

### 期待効果
AIを活用した開発効率、品質の向上
各プログラミング言語やタスクにおける適用可能性の評価
求職者やステークフォルダーへのアピール

## 準備
経費申請までに必要だった準備について触れます。

### 製品理由
数ある製品の中でGitHub Copilotを選定した理由は下記です。
- VSCodeやAndroidStudioのプラグインとして利用可能
- 元々GitHubを利用していたため、同じエコシステムでの利用でリスクが低減される

この理由が合致する、AIに限らず、役に立ちそうなツールが、
他には無さそうという判断ができたのも大きいです。

### プラン選定理由
料金プランを確認すると、候補となる3つのプランがありました。
1. Free
1. Pro
1. Business

Freeプランでもトライアルはできますが、実際のプロダクトや開発工程でどのような感触なのかを知りたいため、除外されました。
Proプランは指定したファイルを Copilot から除外するという機能がなく、セキュリティーや品質の観点から除外されました。
Businessは製品での利用も問題ないことから、こちらをトライアルの対象に決めました。

## 申請の例
あくまでも例ですが、下記が申請の内容となっています。

目的:
技術開発本部としてAI技術の活用を促進するため、GitHub Copilotのトライアル導入を実施します。これにより、利用の必要性や投資対効果を検証し、社内展開の可能性を評価します。

背景:
GitHub CopilotはVSCodeに統合可能で、エンジニアが最も使用する環境に適しているため選定しました。セキュリティ面の懸念については、既存で利用中のGitHub製品と同じエコシステム内で運用されるため、リスクが低減できると判断しています。

プラン選定:
GitHub CopilotにはPro、Business、Enterpriseのプランが存在しますが、Businessプランは管理機能が含まれており、社内での利用に最適であると判断しました。本プランの利用料金は1人あたり月額19ドルです。
AI-TF内でGitHub Copilotを利用されていたのがEさんだけで、前職でもBusinessプランを利用されていたそうです。

導入計画:
以下の4名が、言語やタスクの違いを考慮してトライアルを実施します。それぞれのフィードバックを基に評価を行います。

Aさん: PHP（製品X・製品Y開発）
Bさん: Dart（製品X・製品Z開発）
Cさん: TypeScript（製品X・E2Eテスト開発）
Dさん: PHP・Dart（製品X・製品Z開発）
費用:
月額19ドル × 4名 = 76ドル/月 (1ヶ月間のトライアルを予定)
約11,867.70 円 (156円/ドル換算)

期待効果:
AIを活用した開発効率、品質の向上
各プログラミング言語やタスクにおける適用可能性の評価
求職者やステークフォルダーへのアピール

## 次回以降
トライアル2週目に入ったので、評価やフィードバックを集め、実際に導入の計画を考えていきます。
【Supabase×react×typescript】保存したTODOをすぐ削除しようとするとエラーになる

# はじめに
初歩的なことですが、詰まったので書きます

# 問題
保存したTODOアプリをリロードかけず、そのままTODOを削除しようとしたら
エラーが出ました。

開発ツールのコンソール上でのエラーはこんな感じ

```console
DELETE https://shxhvlouxxdfkbszgsto.supabase.co/rest/v1/study-record?id=eq.6 400 (Bad Request)
~~~~~~
App.tsx:32 {code: '22P02', details: null, hint: null, message: 'invalid input syntax for type uuid: "6"'}
```

読み解くと、

・"id=eq.6"が有効なUUIDとして認識されていない。多分だが、ユーザーがUUID型として扱うべきカラムに整数の"6"を渡している。
・エラーメッセージはUUID型を期待するカラムに整数"6"を渡していて、正しいIDをURLパラメータに挿入する必要があることを示している。

っていうことがわかった。


なんじゃそりゃと思い見てみると、supabaseはuuid型になっているのに対し、
`console.log`で見てみると、6とか7とかの整数で返ってきていることがわかりました。

# 原因のコード
実際にコードを見返すとどうやら格好つけて作った`hook`がおかしいっぽく、
確認していくとその予想は当たっていました。
```react
const addTodo = async (text: string, time: number) => {
    try {
      setIsLoading(true);
      await AddTodo(text, time);
      const newId = records.length + 1;
      setRecords([...records, { id: String(newId), text, time }]);
      setOpen(false);
    } catch (error) {
      console.error(error);
    } finally {
      setIsLoading(false);
    }
  };

```

ここの部分です。
```react
const newId = records.length + 1;
setRecords([...records, { id: String(newId), text, time }]);
```

なんやこれ、、、

AddでTODOを追加し、一覧に表示させる時に勝手に整数に整形されていました。

なぜ自分がそんなコードを書いたのか覚えていないのですが、
型がちゃんと決まっていない状態で開発を進めていたので、
おそらく回避するために書いたのだろうと思います。

コメントを残さなかった過去の自分を恨みました。

# 解決方法
なんやなんや触って最後のコードはこちら。

```react
 const addTodo = async (text: string, time: number) => {
    try {
      setIsLoading(true);
      const data = await AddTodo(text, time);

      if (data && data.length > 0) {
        const newTodo = new Todo(data[0].id, text, time);
        setRecords([...records, newTodo]);
      }
      setOpen(false);
    } catch (error) {
      console.error(error);
    } finally {
      setIsLoading(false);
    }
  };
```
`if`でnullとundefinedを避けて、
`new Todo(data[0].id, text, time)`で、新しく作成された TODO を Todo クラスのインスタンスとして作成するようにしました

# おわりに
時間が空いたので、後々に影響があるよねって場所は
コメントを残した方がいいなと改めて強く思いました。
S3オブジェクトロックが有効になっているオブジェクトの削除権限について

# 最初に
AWS S3のオブジェクトロックは、データを誤って削除・上書きしないように保護するための機能です。本記事では、S3オブジェクトロックの種類や、AWS CLIとコンソールでの削除権限の違いについて解説し、実際に試した結果を共有します。

## 1. オブジェクトロックの種類と説明
S3オブジェクトロックには以下の2種類があります。

### 1.1 ガバナンスモード
- 指定されたユーザー（rootアカウントまたは特定のIAMユーザー）がオブジェクトの削除・変更を制御できる。
- 権限を持つユーザーはロックを解除し、オブジェクトの変更・削除が可能。

### 1.2 コンプライアンスモード
- 設定された保持期間が経過するまで、どのユーザーもオブジェクトを削除・変更できない。
- AWSアカウントのrootユーザーでさえ変更不可。

## 2. オブジェクトロックの削除権限について
S3のオブジェクトロックを操作するには、以下のIAM権限が必要です。

### 必要なIAMポリシー例
```json
{
    "Effect": "Allow",
    "Action": [
        "s3:GetObjectRetention",
        "s3:PutObjectRetention",
        "s3:BypassGovernanceRetention",
        "s3:DeleteObject"
    ],
    "Resource": "*"
}
```
- `s3:GetObjectRetention`：オブジェクトの保持ルールを取得。
- `s3:PutObjectRetention`：オブジェクトの保持ルールを設定。
- `s3:BypassGovernanceRetention`：ガバナンスモードのロックを解除して削除可能にする。
- `s3:DeleteObject`：オブジェクトを削除。

## 3. オブジェクトの削除の権限はAWS CLIとコンソール上では違う
AWS CLIとS3マネジメントコンソールでは、オブジェクトロックが有効な場合の削除の挙動に違いがあります。

### AWS CLIでの削除
CLIでは `s3:BypassGovernanceRetention` の権限を付与し、`--bypass-governance-retention` オプションを指定することで、ガバナンスモードのオブジェクトを削除できます。
```sh
aws s3 rm s3://objectlock-test-hoge/my-object --bypass-governance-retention
```

### コンソールでの削除
S3管理コンソールでは、ガバナンスモードが有効なオブジェクトの削除を試みると、`s3:BypassGovernanceRetention` の権限が付与されていても、デフォルトでは削除ができません。

## 4. その理由
AWS CLIでは明示的に `--bypass-governance-retention` を指定することで、ガバナンスモードを解除して削除できます。しかし、S3コンソールでは、削除前にオブジェクトの保持ルールを変更する操作が必要です。

この違いは、GUIを通じた誤操作を防ぐためのAWSの設計意図によるものと考えられます。

## 5. CLIとコンソール上からやってみた
### 5.1 バケットとオブジェクトの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4006403/ebc210c2-db8a-0f30-e611-618120d00e27.png)


### 5.2 AWS CLIでの削除試行
ガバナンスモードでは `--bypass-governance-retention` を指定しないと削除できません。
```sh
aws s3 rm s3://objectlock-test-hoge/test.cli.txt
```
`An error occurred (AccessDenied) when calling the DeleteObject operation` というエラーが発生。

`--bypass-governance-retention` をつけると削除可能。
```sh
aws s3 rm s3://objectlock-test-hoge/test.cli.txt --bypass-governance-retention
```

### 5.3 コンソール上での削除試行
CLIと同様の権限では削除できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4006403/670ed699-4d49-3ecf-3d6c-9708e7a30a06.png)

IAMポリシーに`s3:GetBucketObjectLockConfiguration` を追加すると削除可能。
```json
{
    "Effect": "Allow",
    "Action": [
        "s3:GetObjectRetention",
        "s3:PutObjectRetention",
        "s3:BypassGovernanceRetention",
        "s3:GetBucketObjectLockConfiguration",
        "s3:DeleteObject"
    ],
    "Resource": "*"
}
```



## 6. まとめ
- S3オブジェクトロックには「ガバナンスモード」と「コンプライアンスモード」がある。
- オブジェクトの削除には適切なIAM権限が必要。
- AWS CLIとコンソールでは削除の挙動が異なる。
- AWS CLIでは `--bypass-governance-retention` を明示的に指定すると削除可能。
- コンソール上での削除には、`s3:GetBucketObjectLockConfiguration`の権限が必要。

S3オブジェクトロックを正しく理解し、安全に運用しましょう！
AIマネタイズ– AI技術で収益化を目指すための情報とノウハウ –

AI技術を活用して収益化する方法に関する情報を提供します。コンテンツ制作、プラットフォーム選び、効率的な運営方法など、AIを活用したマネタイズのアイデアを網羅しています。

https://kaede-aibeauty.com/category/ai-monetization/
【LeetCode】15. 3Sum 解いてみた【Medium】

<!--quiita leet code テンプレ-->

<!--

## 技術記事のタイトル

【LeetCode】〇〇 解いてみた【Medium】

### 【 】(墨付き括弧)

タグ

LeetCode 競技プログラミング Python 

-->

## 問題の概要

与えられた配列から3つたしたら0になる組み合わせを全て返す

Example 1:

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]

Example 2:

Input: nums = [0,1,1]
Output: []


## 最初に考えた解き方
・組み合わせは--+,++-,-+0の3種類
これはコードにいれてない

```
class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        l, r = 0, len(nums)-1
        res = []
        while l <= r-2:
            start = l
            m = l+1
            while l <= r-2:
                while m < r:
                    lNum = nums[l]
                    mNum = nums[m]
                    rNum = nums[r]
                    if lNum + mNum + rNum == 0:
                        res.append([lNum, mNum, rNum])
                    m += 1
                r -= 1
                l = start
        return res
```

## 何がよくなかったか？

いろいろとあるが、重複をリストにしてからチェックしようと考えていたが、ソートすれば計算する前にはじけた


## 解き方

### Two Pointers

```
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        res = []
        nums.sort()

        for i, a in enumerate(nums):
            if a > 0:
                break

            if i > 0 and a == nums[i - 1]:
                continue

            l, r = i + 1, len(nums) - 1
            while l < r:
                threeSum = a + nums[l] + nums[r]
                if threeSum > 0:
                    r -= 1
                elif threeSum < 0:
                    l += 1
                else:
                    res.append([a, nums[l], nums[r]])
                    l += 1
                    r -= 1
                    while nums[l] == nums[l - 1] and l < r:
                        l += 1
                        
        return res
```



#### できたきがする

前にやったことが応用できていれば


## 参考資料

https://leetcode.com/problems/3sum/description/

## おわりに

つかえそうだと思ったら使おう
Next.js+StoryBoookでTailwindCSSが反映されない時の注意点

Next.js(v15)+TailwindCSSを使ったプロジェクトにStoryBookを導入してみよう〜と思い、初めて見たもののチュートリアルを進めても、TailwindCSSが反映されず、解決できたので共有しておきます。


# tailwind.confing.tsのcontentに追加していない
```ts:tailwind.config.ts
import type { Config } from "tailwindcss";

export default {
  content: [
    "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
    "./src/stories/**/*.{js,ts,jsx,tsx,mdx}", //ここにstoriesのパスを追加しました
  ],
  theme: {
    extend: {
      colors: {
        background: "var(--background)",
        foreground: "var(--foreground)",
      },
    },
  },
  plugins: [],
} satisfies Config;
```

# .storybook/previewにcssをインポートしていない
```ts:.storybook/preview.ts
import type { Preview } from "@storybook/react";
import "../src/app/globals.css";//cssを追加しました

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

export default preview;

```

# Tailwind CSS の `content` 設定について

TailwindCSSでは、指定したファイルをスキャンし、**実際に使用されているクラスだけを生成** します。

具体的には「未使用のスタイルを削除する (Purging)」のようなことで、最適なスタイルシートを作成するそうです。そのため、content に対象のファイルを指定し、Tailwind がどのクラスを使っているのかを判断できるようにします。

そのため、どこで使用されているかを監視する必要があり、反映させるには今回のように適応する必要がありそうでs。
PHP学習メモ④

# 定数
・途中で中身を変更できない入れ物のことを「定数」を指す
・スクリプトの中で何等かの意味を持つ値にあらかじめに名前を付けておく仕組み

```ruby:定数の良くない例文
<?php
$price = 1000 ;
$sum   = $price * 1.1 ; 
```
└この例分で、1.1の定義が曖昧である
└値の修正に弱い、1.1が変わる場合、全部のコードで数字の上書き修正が必要

そこで、以下のように書き換えることで、識別がしやすくて変化があったときに便利
```ruby:定数の例文
<?php
const Tax = 1.1 ; // 定数は大文字で命名
$price = 1000 ;
$sum   = $price * TAX ; 
print $sum ;
```
**const**は定数を宣言するための命令で、ここでは定数TAXに1.1という値を設定

```ruby:constの構文
const 定数名 = 値
```

# 定数のルール
**（1）名前の先頭に＄は付けない**
**（2）名前は、PHPで意味を持つ予約語でないこと**
**（3）すべて大文字で命名する**
└複雑の単語を含むように名前を付けたい場合は、「EXAMPLE_TAX」のようにアンダースコアで区切る
**（4）利用できる型は限定される**
└整数（int）、少数（float）、文字列（string）、true/false(bool)、null

# 定義済みの定数
constで宣言することなく、無条件で利用できる定数がある
<table>
  <caption>変数の命名規則</caption>
  <thead>
    <tr>
      <th>定数</th> <th>概要</th>
    </tr>
  </thead>
  <tr>
    <td> _ _FILE_ _ </td> <td>実行中のファイル名（絶対パス）</td>
  </tr>
  <tr>
    <td> _ _DIR_ _ </td> <td>実行中のファイルが存在するフォルダー</td>
  </tr>
  <tr>
    <td> _ _LINE_ _ </td> <td>実行中の行番号</td>
  </tr>
  <tr>
    <td> _ _FUNCTION_ _ </td> <td>実行中の関数名</td>
  </tr>
  <tr>
    <td> _ _CLASS_ _ </td> <td>実行中のフクラス名（所属する空間を含む）</td>
  </tr>
　<tr>
    <td> _ _METHOD_ _ </td> <td>実行中のメソッド</td>
  </tr>
  <tr>
    <td> _ _TRAIT_ _ </td> <td>実行中のトレイト名（所属する空間を含む）</td>
  </tr>
  <tr>
    <td> _ _NAMESPACE_ _ </td> <td>現在の名前空間</td>
  </tr>
  <tr>
    <td> DIRECTORY_SEPARATOR</td> <td>フォルダーの区切り文字</td>
  </tr>
  <tr>
    <td> PATH_SEPARATOR</td> <td>パスの区切り文字</td>
  </tr>
  <tr>
    <td> PHP_VERSION</td> <td>使用しているPHPのバージョン</td>
  </tr>
</table>
文字のSVGストロークアニメーション

# SVGアニメーションを復習しよう！

## SVGとは

SVG（Scalable Vector Graphics)
ベクター形式の画像をXMLで記述するファイルフォーマット。
SVGのメリットとして以下が挙げられる。

:::note info
①解像度に依存せず、拡大縮小しても劣化しない
②JPGやPNGに比べ軽い
③CSS、JavaScriptと組み合わせて動かせる
④SEO可読性あり
:::
特に③は手軽にアニメーションが作れて、使いこなせると非常に凡庸性が高い
今回は、SVGアニメーションで頻出のテキストロゴアニメーションを作ろうと思う


## 文字をアウトライン化

SVG内でテキストをそのまま使うと、フォントが環境で崩れる可能性があるらしい。
テキストは必ず**アウトライン化（パス変換）** をする。

### アウトライン化（Illustrator）
1. 文字を選択
2. **[書式] > [アウトラインを作成]** をクリック
3. **[ファイル] > [書き出し] > [SVG]** で保存


## Figmaはストロークアニメーションに適さない？

Figmaでアウトライン化したSVGをエクスポートすると、**`fill`（塗り）情報のみが適用され、`stroke`（線）情報が欠落することがある**。そのため、CSSやJavaScriptを使ってストロークアニメーションを適用しようとしても、適切に動作しない場合があるらしい。


### Illustratorの方が適している理由
- Illustratorでは **`stroke` を保持したままSVGを書き出せる**
- `stroke-dasharray` などのプロパティを適用しやすい
- Figmaでは `fill="black"` になりやすく、アニメーション制御しづらい

**ストロークアニメーションを適用する場合は、Illustratorを使うのがベター**
Figmaから書き出したSVGを使うためには少しファイル自体に加工が必要になってくる、Illustratorからの書き出しの方が良さそう。

---

## ストロークアニメーションを作成

### 1. SVGの準備
Illustratorでアウトライン化したSVGを用意し、`stroke` が適用されていることを確認。


```xml
<svg width="200" height="100" viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
  <path d="M10,50 H190" stroke="black" stroke-width="4" fill="none" />
</svg>
```

### 2. CSSでストロークアニメーションを適用
```css
@keyframes draw {
  from {
    stroke-dasharray: 300;
    stroke-dashoffset: 300;
  }
  to {
    stroke-dashoffset: 0;
  }
}

path {
  stroke: black;
  stroke-width: 4;
  fill: none;
  stroke-dasharray: 300;
  stroke-dashoffset: 300;
  animation: draw 2s ease-out forwards;
}
```

### 3. アニメーションの仕組み
- **`stroke-dasharray`**：点線の長さを指定（線を見えなくする）
- **`stroke-dashoffset`**：アニメーションで徐々に線を描画
- **`animation`**：`draw` のアニメーションを2秒間適用

---

以上を応用して文字のストロークアニメを作成してみた
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="MYWYjmp" data-pen-title="ロゴのストロークアニメーション" data-user="moco2-design" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/moco2-design/pen/MYWYjmp">
  ロゴのストロークアニメーション</a> by ヤマサキ (<a href="https://codepen.io/moco2-design">@moco2-design</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://public.codepenassets.com/embed/index.js"></script>

## まとめ
:::note info

　
✅SVGは解像度非依存のベクター形式で、アニメーションに適している
✅ ストロークアニメーションを適用するなら Illustrator で SVG を作成するのがベスト
✅ `stroke-dasharray` と `stroke-dashoffset` を活用して線の描画アニメーションを実装
:::