OmniAICreator/Qiita-1.07M huggingface dataset:
Instanaで挑む！トラブルシュート事件簿　第2回　入れてて良かったInstana！突然のトラブルも30分で解決

# はじめに

こんにちは、Airitech株式会社の代表取締役をしている、山﨑政憲と申します。
普段は会社の経営の傍ら、遅いシステム、止まってしまうシステムのトラブルシュートを行っています。
これからInstanaが現場で活躍した事例をいくつか紹介していこうと思います。
システムトラブルに対して、Instanaを用いてObservabilityを獲得し、速やかに解決した事例を紹介していく本連載、第2回は、ECサイトのセールで勃発したシステムトラブルを、あっという間にInstanaで解決したという事例になります。
あっという間に解決できた分、記事も短いです。
ぜひ、ご覧ください。

# Instanaとは

InstanaはIBMが提供しているObserbavilityツールです。
私は起業した2017年からInstanaを性能改善やトラブルシューティングに活用しており、「早い」「美味い」「安い」と三拍子揃ったInstanaの便利さを日々、実感していますし、Instana好きが高じてIBM Championの認定も受けていましす。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76238/8dd06a80-9c0e-bead-57bf-fff3bc5357c1.png)


Airitechでは、X上でマンガも掲載しています。
こちらもご覧ください。
https://x.com/AiritechSupport/status/1765633493084893569
<link href="https://x.com/AiritechSupport/status/1765633493084893569">
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76238/f3d27c44-a4b1-ede6-1fbf-5765d1bbec2b.png">
</link>

# 第一幕　事件発生
その日、私は出張のため、新幹線に乗って東京から京都に移動中でした。
名古屋を通り過ぎ、そろそろお昼ご飯にしようかな、、、と思ったところで携帯に着信、

「お昼からセールを開始したECサイトが応答せず、画面が真っ白になります。
　こちらでも調査しているのですが、サーバのCPUやメモリには全く問題が見当たりません。
　むしろ余裕があるような状況です。
　事象発生から15分程度が経過しています。
　至急、助けて欲しい！」

との切迫した声でした。
しかし、移動中のため、お客様を訪問する訳にもいかず困ったな、となっていたとき、ふとInstanaを適用していた事を思い出したのです。
これなら、新幹線の中からでも原因究明が可能です。

「承知しました！
　すぐに調査に入らせていただきます。
　何かあればすぐに折り返し報告します。」

移動中の新幹線の中でトラブルシュート開始となりました。

# 第二幕　原因判明
さて、Instanaを開いて調査を開始。
確かに、セールを開始した12:00から全てのリクエストの応答時間が急激に悪化し、エラーとなっている事がすぐに確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76238/239e8fe4-574b-ed6e-70de-0f89a26f6a5d.png)

リクエストの内容を確認すると、別のサイトのレコメンダにリクエストを送って応答待ちを続け、そして60秒でタイムアウトとなり、エラー応答を返していました。
Instanaのトレース画面には以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76238/a08a2e92-da0f-3ca1-9ec7-1866650232d6.png)

# 第三幕　対処完了
他社サイトに原因ありとのことで、すぐに解決するのは難しいと考え、切り離しを提案した。

「・・・というサイトへのリクエストがタイムアウトしています。
　必須でなければ、一時的にリクエストを止めてはいかがでしょうか？」
「分かった！やってみます！」

ほどなく切り離しは実行され、処理が正常に流れることを、こちらでもInstanaで確認しました。

「解決しました。助かりました！」
「良かったですね～」

とお互いに安堵してその日は対応完了となりました。
12:00に障害発生、12:15で問合せを受け、12:20で原因判明、12:35でセール再開。
最初の電話からここまでで35分。
セールは中止にならず、そのまま実施することができたのは、非常い喜ばしい事でした。

# さいごに

いかがでしたでしょうか？
CPUやメモリなどのリソースを見ていても、原因が分からないことも良くあります。
いわゆるエンドツーエンドでのトレースを見られるのがObserbavilityツールの良いところ。
今回は処理の途中に他社のサービスを利用している部分が問題とすぐに分かったところがInstanaの超絶便利ポイントでした。
セール前にInstanaの導入が終わっていたのも良かったですね。
導入されていなかったとしたら、原因究明にも数時間を要したと思われます。
セールそのものが中止になる可能性もありました。

Instanaの使い方、効果に興味を持たれた方はIBMのSoftware Salonでも使い方や事例について解説しているので、ぜひ、ご覧になってみてください。

IBM Software Salon 第10回 (2024/9/19)
トラブル解決でヒーローになろう！障害事例にみるObservabilityツール活用の勘所
https://video.ibm.com/recorded/133995814
<link href="https://video.ibm.com/recorded/133995814">
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76238/165aeb44-f50b-e035-7e36-fa84e56f1290.png">
</link>

また、Instanaユーザコミュニティも、定期的にイベントを行っています。
こちらもぜひ、ご覧ください。
https://instanautsjp.connpass.com/

それでは、今後もInstanaの便利な使い方や事例の紹介を行いますので、よろしくお願いいたします。
友達と遊ぶ用のSpigotサーバーの便利ツールを作る #1

最近友達とSpigotの自宅サーバーを立てて遊んでます。
そのサーバーで使える便利ツールを作って行きます。
今回はパート1です

# サーバー環境
記事執筆時の環境です。
```
サーバー:Spigot
環境: Windows11 Home
ポート開放: SecureShareNet
主なプラグイン: DiscordSRV,WorldEdit,BlueMap,GeyserMCなど その他合計30個
```
# 便利ツール
今回作るツールでは、主にやりたいことが2つあります。
・自作DiscordBotで サーバーのアドレス、などをいちいち送らなくていいようにする。
・メンテ起動をできるようにする。(DiscordBotにメンテって言ってもらう)

ん? それくらい自分でやれって? めんどくさいから楽にしたい。

# DiscordBot
今回は、discordのJavaScriptパッケージの`discord.js`を使います。
基本的にはNode.jsでつくる。

# discord.js
```shell
npm install discord.js
```

# テスト

試しにテストで、メッセージを送って見ます。

参考記事⇩

https://qiita.com/yuto0214w/items/1ecee25efca6b5b7445b

無事発言できたので、JSコードを書きます。

# JS
```js
const express = require('express');
const { Client, GatewayIntentBits } = require('discord.js');
const path = require('path');
const bodyParser = require('body-parser');

const DISCORD_TOKEN = 'YOUR_DISCORD_BOT_TOKEN'; 
const CHANNEL_ID = 'YOUR_CHANNEL_ID';             

const app = express();

const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages] });

client.login(DISCORD_TOKEN);

client.once('ready', () => {
    console.log('Bot is ready!');
});

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

app.use(express.static(path.join(__dirname, 'public')));

app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', (req, res) => {
    res.render('index'); 
});

app.post('/send-message', async (req, res) => {
    const { options } = req.body;
    let message = '';

    if (options && options.includes('Option 1')) {
        message += '通常起動 ';
    }
    if (options && options.includes('Option 2')) {
        message += 'メンテナンス起動 ';
    }
    if (options && options.includes('Option 3')) {
        message += 'Javaのみ起動(BE不可)';
    }

    if (!message) {
        return res.status(400).send('オプションが選択されていません。');
    }

    try {
        const channel = await client.channels.fetch(CHANNEL_ID);
        await channel.send(message.trim());
        res.send('メッセージが送信されました: ' + message.trim());
    } catch (error) {
        console.error('メッセージ送信エラー:', error);
        res.status(500).send('メッセージの送信に失敗しました。');
    }
});

const PORT = 3000;
app.listen(PORT, () => {
    console.log(`サーバーがポート${PORT}で起動しました。`);
});

```

# ejs
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Discordメッセージ送信</title>
</head>
<body>
    <h1>Discordにメッセージを送信</h1>
    <form action="/send-message" method="POST">
        <label>
            <input type="checkbox" name="options" value="Option 1"> Option 1 (通常起動)
        </label><br>
        <label>
            <input type="checkbox" name="options" value="Option 2"> Option 2 (メンテナンス起動)
        </label><br>
        <label>
            <input type="checkbox" name="options" value="Option 3"> Option 3 (Javaのみ起動(BE不可))
        </label><br>
        <button type="submit">送信</button>
    </form>
</body>
</html>

```
多分エラーが出る気がするけど次回から動作確認をします。
早めにコードの変なところを見つけた方はコメントをお願いします。
今回はここまｄ

# 続き
#### pt.1
https://qiita.com/Atsu1209jp/items/4e2dc7bca080a08d0de6
#### pt.2以降
未投稿
ライブ講義大学生のための応用数学入門 正誤表

奈佐原顕郎「ライブ講義大学生のための応用数学入門」（講談社）の正誤表および表現の改善箇所です。noteに移動しました。
https://note.com/24dakenlo/n/n6d6c92520890
OpenCVでの楕円フィッティングのやり方

画像処理において、物体の輪郭を検出し、その輪郭に基づいて形状をフィッティングするのはよく行われる手法です。特に楕円フィッティングは、物体の回転やスケール変化に対して比較的ロバストであり、特徴的な形状を表現するために便利です。本記事では、PythonとOpenCVを使用して楕円フィッティングを行う方法について詳しく説明します。

## 1. 必要なライブラリのインポート
まず、必要なライブラリをインポートします。OpenCVとNumPyを使います。OpenCVは画像処理、NumPyは配列操作に役立ちます。
```python
import cv2
import numpy as np
```
## 2. 画像の読み込みとグレースケール変換
次に、解析対象となる画像を読み込み、グレースケールに変換します。グレースケール化することで、画像の情報量を減らし、エッジ検出を行いやすくします。
```python
# 入力画像の読み込み
image = cv2.imread("input.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
```
ここでinput.jpgは解析対象の画像ファイルのパスです。
## 3. エッジ検出
エッジ検出にはCanny法を使います。Cannyエッジ検出は、画像内のエッジ（急激な輝度の変化部分）を抽出する手法です。OpenCVのcv2.Canny関数を使ってエッジを抽出します。
```python
# エッジ検出 (Canny)
edges = cv2.Canny(gray, 100, 200)
```
ここで、100と200はCannyエッジ検出の閾値です。
## 4. 輪郭検出
次に、エッジから輪郭を検出します。輪郭検出は、画像中の連続したエッジを集めて輪郭として扱う処理です。cv2.findContours関数を使用し、抽出したエッジから輪郭を検出します。
```python
# 輪郭の検出
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
```
cv2.RETR_TREEは、階層的な輪郭情報を取得するためのモードです。cv2.CHAIN_APPROX_SIMPLEは、輪郭の近似法を指定しており、輪郭を単純化してメモリ効率を向上させます。

## 5. 楕円フィッティング
輪郭が取得できたら、次は各輪郭に対して楕円をフィッティングしていきます。楕円フィッティングは、輪郭が5点以上ある場合にcv2.fitEllipse関数を使って実行できます。
```python
# 楕円フィッティングの処理
for contour in contours:
    # 輪郭が5点以上の場合のみ楕円フィッティングが可能
    if len(contour) >= 5:
        ellipse = cv2.fitEllipse(contour)
        cv2.ellipse(image, ellipse, (0, 255, 0), 2)  # 楕円を描画

```
ここでは、輪郭が5点未満のものはスキップし、楕円フィッティングを行える輪郭だけに処理を適用します。また、フィッティング結果の楕円は、cv2.ellipseを使って描画しています。この関数に楕円パラメータと色、線の太さを指定して、画像に楕円を描画します。

## 6. 結果の表示
最後に、処理結果をウィンドウに表示して、エッジ検出と楕円フィッティングの結果を確認します。
```python
# 結果を表示
cv2.imshow("Ellipses", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
cv2.imshowで画像を表示し、cv2.waitKey(0)でキーが押されるまでウィンドウを開いたままにします。cv2.destroyAllWindows()はすべてのOpenCVウィンドウを閉じます。
Refererとは？

>Referer リクエストヘッダーには、`現在リクエストされているページへのリンク先を持った直前のウェブページのアドレスが含まれています`。 Referer ヘッダーにより、`サーバーは人々がどこから訪問しに来たかを識別し、分析、ログ、キャッシュの最適化などに利用`することができます。

>警告: このヘッダーには無害な用途が多数ありますが、ユーザーのセキュリティとプライバシーに望ましくない結果をもたらす可能性もあります。 詳細情報と緩和策については Referer header: privacy and security concerns を参照してください。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Referer#:~:text=Referer%20%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%98%E3%83%83%E3%83%80,%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82

ディレクティブ
>`<url>`
`現在リクエスト中のページにつながるリンクがある直前のページの、絶対または相対アドレス`です。 URL フラグメント (つまり "#section") およびユーザー情報 ("`https://username:password@example.com/foo/bar/`" の "username:password" の部分) は含まれません。リファラーポリシーによっては、オリジン、パス、クエリ文字列が含まれる場合があります。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Referer#:~:text=Referer%3A%20%3Curl%3E-,%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96,%E3%82%A8%E3%83%AA%E6%96%87%E5%AD%97%E5%88%97%E3%81%8C%E5%90%AB%E3%81%BE%E3%82%8C%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82,-%E4%BE%8B

* URLフラグメントとは？


#### URLフラグメントとは？
https://developer.mozilla.org/ja/docs/Web/URI/Fragment#:~:text=%E3%83%95%E3%83%A9%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AF%20URI%20%E3%81%AE%E6%9C%80%E5%BE%8C%E3%81%AE%E9%83%A8%E5%88%86%E3%81%A7%E3%80%81%23%20%E3%81%AE%E6%96%87%E5%AD%97%E3%81%A7%E5%A7%8B%E3%81%BE%E3%82%8B%E9%83%A8%E5%88%86%E3%81%A7%E3%81%99%E3%80%82%E6%96%87%E6%9B%B8%E5%86%85%E3%81%AE%E3%82%BB%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%84%E5%8B%95%E7%94%BB%E5%86%85%E3%81%AE%E4%BD%8D%E7%BD%AE%E3%81%AA%E3%81%A9%E3%80%81%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%AE%E7%89%B9%E5%AE%9A%E3%81%AE%E9%83%A8%E5%88%86%E3%82%92%E8%AD%98%E5%88%A5%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82%E3%83%95%E3%83%A9%E3%82%B0%E3%83%A1%E3%83%B3%E3%83%88%E3%81%AF%E3%80%81URI%20%E3%81%8C%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%95%E3%82%8C%E3%81%9F%E9%9A%9B%E3%81%AB%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%81%AB%E9%80%81%E4%BF%A1%E3%81%95%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%81%8C%E3%80%81%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%8C%E5%8F%96%E5%BE%97%E3%81%95%E3%82%8C%E3%81%9F%E5%BE%8C%E3%81%AB%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88%EF%BC%88%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC%E3%81%AA%E3%81%A9%EF%BC%89%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E5%87%A6%E7%90%86%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

# 感想
Refererとは今いるサイトの前のURLを指す。
今のサイトにはどこから入ってきたのかを知ることができる。
絶対、相対URLが書かれている。
Google Colaboratoryで3D散布図を作ってみた【Python】

万年初心者の備忘録です。
今回は、三次元のグラフをGoogleColaboratoryで出力する方法について。

:::note warn
この記事は初心者が書いたものです。
間違っていたり、冗長だったり、煩雑だったりするかもしれません。
:::


# matplotlibを使う方法
![3Dgraph_matplotlib.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921527/ba2fb895-ef16-1dd2-02f5-58e3fedc968e.png)
こんな感じの画像が生成されます。

:::note warn
グラフをマウスでぐりぐり動かすことはできません。
動かしたいときはplotlyを使いましょう。
:::

## コード

```python:scatter3D_plt.py
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

# ラベル
l1,l2 = "GroupA","GroupB"

# プロットする座標の設定
x1 = np.random.rand(50)
y1 = np.random.rand(50)
z1 = np.random.rand(50)
x2 = np.random.rand(50)
y2 = np.random.rand(50)
z2 = np.random.rand(50)

#グラフの作成
fig = plt.figure() # キャンバスを作る
ax = fig.add_subplot(projection='3d') # 座標系を作る

ax.scatter(x1, y1, z1, color='red', label=l1) # GroupAについての散布図
ax.scatter(x2, y2, z2, color='blue', label=l2) # GroupBについての散布図

ax.set_title("Comparison of GroupA and GroupB") #グラフタイトル
ax.legend(loc=0)    # 凡例

plt.show()
```

### 補足…figとかaxって何？
#### fig

`fig`は、グラフ全体の「キャンバス」に相当するオブジェクト。
+ 複数のグラフをまとめて描画する
+ グラフのサイズなどを管理する

上記コードでは、`fig = plt.figure()`によって新しいキャンバス（グラフ全体）を作成しています。

#### ax

`ax`は、グラフ上の個々の領域を担当するオブジェクト。
+ `fig`で作成したキャンバスに散布図や棒グラフなどを追加
+ 軸ラベルや範囲を指定
+ 凡例を設定

上記コードでは、`ax=fig.add_subplot(projection='3d')`によって3Dプロット用の座標系をキャンバス上に追加しています。

# plotlyを使う方法

![scatter_go.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921527/f0f6a376-e370-e28a-a705-388ce55269d0.gif)

こんな感じにマウスで動かしたり、拡大縮小したりできます。

:::note info
マウスで動かしたいときはこの方法を使います。好きな角度・縮尺でpng画像として保存することも可能です。
:::

## コード
```python:scatter3D_go.py
import plotly.graph_objects as go
import numpy as np

fig = go.Figure() # グラフの作成

# ラベル
l1,l2 = "GroupA","GroupB"  

# 座標の設定
x1 = np.random.rand(50)
y1 = np.random.rand(50)
z1 = np.random.rand(50)
x2 = np.random.rand(50)
y2 = np.random.rand(50)
z2 = np.random.rand(50)

# GroupAについての散布図
fig.add_trace(go.Scatter3d(x=x1, y=y1, z=z1, 
                           mode='markers',
                           name=l1,
                           marker=dict(color='red', size=2, symbol='circle'),))

# GroupBについての散布図
fig.add_trace(go.Scatter3d(x=x2, y=y2, z=z2,
                           mode='markers',
                           name=l2,
                           marker=dict(color='blue', size=2, symbol='circle'),))
# 表示
fig.show()
```


### 補足…散布図の設定について
+ `fig.add_trace()`部分でグラフを追加することを示しています
+ `go.Scatter3d()`部分で3Dの散布図を表しています

### `go.Scatter3d()`**の引数**
+ `mode` : `"markers"`(点のみ）、`"lines"`（線のみ）、`"lines+markers"`（点と線）などが指定可能
+ `name` : 凡例ラベル
+ `marker` : マーカーのスタイルを設定（辞書型の引数）
+ `line`: 線のスタイルを設定（辞書型の引数）
:::note alert
`go.Scatter3d()`の引数`marker`、`line`は、`mode`の引数によっては利用できません。

`mode="markers"`とすれば引数`marker`、
`mode="lines"`とすれば引数`line`が使えます。
:::

#### さらに：`marker`の引数
辞書型`dict()`の中に以下のようなスタイルを設定できます。

+ `size` : マーカーのサイズ
+ `color` : マーカーの色 (リストを指定すると、データの各点に異なる色を付けられる)
+ `opacity` : 透過度 (0〜1)

# さいごに
3Dで散布図を作りたくていろいろ試してみました。
個人的には、plotlyを使った方法が好きかも（好きな角度に動かせるので見やすい）。
Google Colaboratoryにはあまり関係のない内容が多くなってしまいましたが、Colabの環境でやってみてできた！っていう経験談として残しておきます。
【AWS Jr.Champions】Jr.Championsになって良かったこと3選

## はじめに
こんにちは、JTPの贄川です。

この度、2024 Japan AWS Jr.Championsのメンバーでブログリレーを行うことになりました。
私は普段、Iac(Infrastructure as Code)でAWSシステムの構築に関する業務を行っておりますが、Japan AWS Jr.Championsに選出されたことで、色々良かったことがあったので今回はその中から３つ紹介します。
今後、Japan AWS Jr.Champions（以下Jr.Champions）を目指す方々のモチベーションに繋がれば幸いです。

## 目次
1. インプット・アウトプットの場が爆発的に増えた
1. 担当する業務の種類が増えた
1. AWS関連のイベントにより参加できるようになった
1. 終わりに

## 1.インプット・アウトプットの場が爆発的に増えた
Jr.Championsメンバーで行うイベントの中で最も多いのがLTで、私はJr.Championsメンバーになる前は全くプレゼンテーションを行う機会がなかったので、かなり発表に対して尻込みをしていたのですが、かなり気軽に話せました。

自分がアウトプットをして学べるのはもちろんですが、他の方が話された内容を自社で共有して、アウトプットすることでよりインプットの効率を上げることができました。

他にも自分の発表と他の方の発表を見比べて、話し方のコツを考えて発表の質を上げたりなど学べることが多かったです。


## 2.担当する業務の種類が増えた
Jr.Championsでの活動は基本的には社外で行うのですが、社内の業務でもJr.Championsとして活動させていただくことが増えました。
具体的な案件として、自社の企業説明会やインターンでの座談会、他企業の方へのAWSガードレールアセスメントの講習をさせていただきました。

学生の方でJr.Championsについて知っている方は少ないのですが、LTイベントやMeetupの様子について紹介すると興味津々で話を聞いてくれたので嬉しかったです！

また他企業のAWSを触ったことがない方に、サービスの概要やベストプラクティスについて話す機会があると、基礎の部分の見直しに繋がって自分にとっても良いアウトプットになりました。

また案件ではないですが、社内でもJr.Championsとして活動を報告したり、来年のJr.Championsへの応募をサポートする活動なども行ったり昨年に比べて私の活動の幅がとても広くなり、色々な経験が出来て、とても楽しみです。
## 3.AWS関連のイベントにより参加できるようになった
最後にJr.Championsに選出されて良かった変化として、AWSのトレーニングやイベントへの参加がし易くなったことがあります。

Jr.Championsになる前はAWSとは異なる業務をしていたので、AWSのトレーニングなどの参加は課長などに頼んでいたのですが、今は逆に参加するように頼まれるようになりました。

またその後に課内にトレーニング内容を共有することも併せて行うのですが、インプットとアウトプットの両方の場を儲けてもらえるようになったことがかなり学習として効率が良くて成長できます。

余談ですが、来月開催のAWS re:InventもJr.Championsとして参加することになったので楽しみたいと思います！

## 終わりに
Jr.Championsを目指すために様々な活動をするので選出されたことがゴールに感じますが、ゴールではなくスタート地点です。

活動量が増え、Jr.Champions選出前よりもとても忙しくなりますが、1年間でしか出来ない経験が沢山あり、充実した時間が過ごせるのでぜひJr.Championsを目指すか迷われている方は挑戦して欲しいです！
AWSのアイデンティティサービスについて簡単にまとめてみた

## 背景
- AWSのアカウントサービス(IAMユーザー、IAMポリシー、IAMグループ、IAMロールあたり)の棲み分けが怪しかったためまとめてみる

## AWSアカウントの全体像
- AWSには「AWSアカウント」と「IAMユーザー」と呼ばれる2種類のアカウントがある
- AWSアカウントは全てのサービスを利用可能でルートユーザーと呼ばれる
- IAMユーザーはAWSを利用する各利用者向けに作成するアカウントで、AWSアカウントによって作成される

```
AWSアカウント1/
├── IAMユーザー1
├── IAMユーザー2
└── IAMユーザー3
AWSアカウント2/
├── IAMユーザー3
└── IAMユーザー4
```

## サマリ
- それぞれのサービスの特徴をざっくりと記載すると下記の通り

| サービス | 概要 |
| - | - |
| AWSアカウント | ルートユーザー<br>全てのサービスを利用可能(※)<br>各AWS利用者向けにIAMを作成する |
| IAMポリシー | 各AWSサービスの利用可否をポリシーとして設定し、IAMユーザーやIAMグループ、IAMロールへ付与する |
| IAMユーザー | AWSを利用するために各利用者へ割り当てられる認証情報 |
| IAMグループ | 同じ権限を持ったIAMユーザの集まり<br>AWSへのアクセス認証は行わない |
| IAMロール | 一時的にAWSリソースへのアクセス権限を付与する |
| AWS Organizations | 複数のAWSアカウントを階層的にグループ化し一元管理 |

※AWS OrganizationsのSCPによって制限された機能は利用不可


## AWSアカウント
- ルートユーザーと呼ばれる
- AWSの全サービスに対して操作可能な権限を持つため扱いには注意が必要
- AWSを利用して何かシステムを構築する場合は基本的にルートユーザーではなくIAMユーザーを使用する
- MFAの設定が推奨される

## IAM
- 主要機能として下記の4つがあげられる
    - IAMポリシー
    - IAMユーザー
    - IAMグループ
    - IAMロール

### IAMポリシー
- Action(どのサービスの)、Resource(どういう機能や範囲を)、Effect(許可/拒否する)という3つのルールを設定することでポリシーを作成
- 作成したポリシーをIAMユーザーやIAMグループ、IAMロールに付与することで各IAMユーザーの制御を実現

#### インラインポリシー
- 対象ごとに作成、付与を行うポリシー

例）
ユーザーAにはポリシーAを作成し付与
ユーザーBにはポリシーAとポリシーBを作成し付与
ユーザーCにはポリシーBとポリシーCを作成し付与

#### 監視ポリシー
- 1つのポリシーを複数のユーザーやグループに対して適用
- 下記の2種類がある
    - **AWS管理ポリシー**：AWSが用意しているポリシー
    - **カスタマー管理ポリシー**：ユーザー自身で管理するポリシー

例）
ポリシーAを作成しユーザーAとユーザーBに適用
ポリシーBを作成しユーザーBとユーザーCに適用
ポリシーCを作成しユーザーCに適用

### IAMユーザー
- AWSを利用するために各利用者へ1つずつ与えられる認証情報(ID)
- 人だけでなくAPIを呼び出したりCLIを実行したりする主体に対しても与えることが可能
- Webコンソールへのログイン時はユーザーIDとパスワードに加え、MFAの組み合わせが推奨される
- CLIやAPIでAWSリソースへアクセスする場合はアクセスキーとシークレットキーを使用

### IAMグループ
- 同じ権限を持ったユーザの集まり
- AWSへのアクセス認証情報は保持しないため、認証はあくまで各ユーザーにて行う必要がある
- 認証されたユーザがどのような権限(サービスの利用可否など)を持っているかを管理

例）
部署A、部署B、部署Cではそれぞれ利用するAWSサービスが異なる場合
(各部署のユーザーは1人1つのIAMユーザーを所持)
IAMグループAには、部署AのユーザーのIAMユーザーを割り当てる
IAMグループB、Cも同様に部署B、Cのユーザーを割り当てる
これにより各IAMグループにてサービス利用可否を設定しておくことで、各IAMユーザー単位でサービス利用可否を設定する必要がなくなり運用負荷の軽減に繋がる

### IAMロール
- 一時的にAWSリソースへのアクセス権限を付与する場合に利用
- 例えば下記のような場合に利用
    - **AWSリソースへの権限付与**：EC2インスタンス上で稼働するアプリケーションに一時的にAWSリソースへアクセスする権限を付与したい
    - **クロスアカウントアクセス**：複数のAWSアカウント間のリソースを1つのIAMユーザーで操作したい
    - **IDフェデレーション**：社内のADに登録されているアカウントを使用してAWSリソースへアクセスしたい
    - **Web IDフェデレーション**：FacebookやGoogleのアカウントを使用してAWSリソースへアクセスしたい

## AWS Organizations
- 複数のAWSアカウントを階層的にグループ化しアカウント群の管理を一元的に実施
- グループにまとめることで請求書を1枚にまとめたり、それぞれのアカウントで利用可能なAWSサービスに制限をかけることが可能
- 組織内には請求アカウントとなる**管理アカウント**が存在し、その配下に組織単位(OU)と呼ばれる論理グループを作成することが可能

```
Organizationルート（管理アカウント）/
├── OU/
│   ├── OU/
│   │   ├── アカウントA
│   │   └── アカウントB
│   └── OU/
│       └── アカウントC
└── OU/
    └── アカウントD
```

### サービスコントロールポリシー（SCP）
- 組織のアカウントに対して特定の権限や操作の許可/拒否を設定可能
- IAMポリシーではIAMユーザーやIAMロールを対象とするのに対し、SCPではAWSアカウントを対象とするためより強い権限の設定が可能
    - SCPで制限された機能を、IAMユーザーやIAMポリシーで許可することは不可
(許可しても使用不可)
    - ルートユーザーであっても制限される
LLMの評価（perplexity）

# はじめに
LLMを実行するためのサンプルコードです。
コードは下記にあります。  
https://github.com/toshi-4886/LLM/blob/main/notebook/4_perplexity.ipynb

### 概要
- perplexityでLLMを評価します。
- モデルはLlamaの小型モデルを使用します。

# 事前準備
1. Hugging Faceのアカウント作成
2. アクセストークンの作成  
Hugging Faceのアカウントにログインし、「自分のアイコン→Settings→Access Tokens→+ Create new token」からトークンを作成します。  
「Read access to contents of all public gated repos you can access」の権限が必要となります。  
3. Llamaの利用申請  
Hugging Faceで使用したいモデルのページにアクセスして、必要事項を記入して申請します。  
申請が承認されると利用可能になります。

# Perplexity
言語モデルの性能を評価する方法の1つです。  
次のトークンを予測する性能を測る指標になります。  
トークン列$X = [x_0, x_1, ..., x_t]$、パラメータ$\theta$の言語モデルに関するperplexityは下記の通り定義されます。  
$$
PPL(X) = \exp\{-\frac{1}{t}\sum_i^t \log p_{\theta}(x_i|x_{<i})\}
$$
ここで、$p(x_i|x_{<i})$はi番目より前のトークンを言語モデルに入力したときの、トークン$x_i$の生成確率です。  
expの中は各トークンのcross entropyの平均になっています。  
そこで、今回はAutoModelで計算されるlossを活用します。

# 実装
### 1. ライブラリのインポート

```python
import sys
import os
import numpy as np
from tqdm import tqdm
import matplotlib.pyplot as plt

from transformers import AutoTokenizer, AutoModelForCausalLM
! pip install datasets
from datasets import load_dataset
import torch
```

### 2. 認証
Hugging Faceからモデルをダウンロードするために、アカウント認証を行います。  
login()を実行するとトークンを入力するUIが出てくるので、そこにトークンを入力します。  
また、colabのシークレットにトークンを保存しておけば、それを利用することもできます。

```python
from huggingface_hub import login
# シークレットにトークンを保存しておけば下記で認証可能
from google.colab import userdata
login(token=userdata.get('HF_TOKEN'))
```

### 3. 推論と評価
モデルとトークナイザーをダウンロードします。  
今回はLlama3.2の1Bモデルを使用します。

```python
tokenizer = AutoTokenizer.from_pretrained(
    "meta-llama/Llama-3.2-1B-Instruct",
)

model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-1B-Instruct",
    torch_dtype=torch.float16,
    device_map="auto",
    trust_remote_code=False,
)
```

データセットをダウンロードします。  
今回はメールのデータセットであるEnronを使用します。  
Pileというデータセットに含まれていますが、大規模なデータセットのため、Enronだけを抽出したものを用います。

```python
dataset = load_dataset("suolyer/pile_enron", split='test')

# データセットの内容を確認
print(dataset)

# データセットからテキストの情報を取得
sentences = dataset['text']

# 最初の文の先頭を表示
print(sentences[0][:1000])
```

perplexityを計算します。  
そのために、入力と同じトークン列をラベルとして与えます。  
そうするとcross entropyを計算することができます。

```python
# 推論時間を計測
%%time

loss_list = []
with torch.no_grad():
    # メモリが足りなくなるので、1サンプルずつ処理
    for i in range(len(sentences)):
        # メモリが足りなくなるので、長い文はスキップ
        if len(sentences[i]) > 10000:
            continue
        token_ids = tokenizer(sentences[i], return_tensors="pt").to(model.device)
        outputs = model(**token_ids, labels=token_ids["input_ids"])
        loss_list.append(outputs.loss.item())

print(np.mean(np.exp(loss_list)))
plt.hist(loss_list, bins=100)
plt.show()
```

![perplexity.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3225334/b8e7482a-efa4-be40-edca-a171bdcb9e57.png)




# おわりに
### 今回の結果
perplexityを計算することができました。  
lossの分布を確認すると、予測がうまくいっている文と、そうでない文があることが分かります。

### 次にやること  
LLMの性能を向上させる方法を試してみたいと思います。

### 参考資料  
- meta-llama/Llama-3.2-1B-Instruct  
https://huggingface.co/meta-llama/Llama-3.2-1B-Instruct
- suolyer/pile_enron  
https://huggingface.co/datasets/suolyer/pile_enron
- GPT-2を使って文のパープレキシティを計算する  
https://gotutiyan.hatenablog.com/entry/2022/02/23/133414
ゼロからのOS自作入門 その3

## 進め方
C++わからない。OSとか全然わからない。という状態です。
かなりのボリュームがある本なので、説明を読む・写経せずにコードだけ実行する。という感じで進めております。
機会があれば、写経してもっと理解を深めたいっすね。

## 3章

レジスタ：CPUに内蔵された記憶領域。
CPUに内蔵されているので、メモリよりもデータのやり取りが速い。
ただ、容量が少ない。
なので、よく使うものなどを入れておく。

レジスタには、汎用レジスタと特殊レジスタがある。
汎用レジスタは、自由に使うことができる（？）
特殊レジスタは、使用目的が決まっているもの。

cppファイル→オブジェクトファイル→実行可能ファイル
の順で実行可能ファイルを作成し、実行する。
オブジェクトファイルと実行可能ファイルの違いは、どちらも機械語にコンパイルされているが、ほかのファイルとのリンクができていないため、実行できない。

### 実行の流れメモ
```
source edksetup.sh
source /workspaces/mikanos_learning/mikanos-build/devenv/buildenv.sh
build
 /home/vscode/osbook/devenv/run_qemu.sh /home/vscode/edk2/Build/MikanLoaderX64/DEBUG_CLANG38/X64/Loader.efi /workspaces/mikanos_learning/mikanos/kernel/kernel.elf
```
こんな感じのを毎回する。
おまじない程度の認識なので、どの命令が何をしているのかは理解していない。
とりあえず、何か動作しないときはここら辺のコマンドを打っておく。

## 4章

ABI(Application Binary Interface)とは、プログラムとCPUの相互作用を機械語レベルで規定する。
プログラムが動作するにあたり必要なレジスタやメモリの使い方がABIによって決まっている。

## 5章

```
........
...@....
...@....
..@.@...
..@.@...
..@.@...
.@...@..
.@...@..
.@...@..
.@@@@@..
@.....@.
@.....@.
@.....@.
@.....@.
........
........
```
文字は、↑のようなデータを用意する。
上記でいえば、`@`の部分は塗りつぶす処理を、それ以外の部分は塗りつぶさないことで文字を表現している。

上記のようなフォントのテキストファイル→バイナリファイルに変換→リンクに必要な情報がついたオブジェクトファイルに変換

この操作をすることでカーネルから利用できるように。

## おわり

引き続きちまちまやっていきたいです。
最後までさらっとメモを取りつつ、読み進めたら、次はコンピュータシステムの理論と実装を読んでみたいですねー。
RTX830でタグVLANの設定

# ○やりたいこと
RTX830でタグVLANを作っていろいろな用途のセグメントを作成する
rtx830配下に家庭用RT/AP(一体型)、WLX202、いろいろやる環境で何個かセグメントを分けたかった。WLX202を購入したのでゲスト用のVLAN作ってほかのVLANセグメントにアクセスできないようにするなど。
VLANでセグメントをわける理由は、アクセス制御、管理のしやすさ、ブロードキャストドメインをわけるなどの理由がある。


# ○NW環境
写真通り
![IMG_1571.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3683457/a3ef0c6f-87b9-3629-011f-05f976ff21af.jpeg)



# ○結果
できた。rtx830とWLX202(トランクポート)で適当なSSID作って任意のVLAN指定して、スマホで無線接続すると指定したセグメントのIPが割り当てられた。

# ○実現方法
インターネット接続は住んでる前提。
RTX830のLANマップ使ってGUIからrtx830のタグvlanを六個作る。wlx202のインタフェースにも全てのタグvlanに参加させる設定。

![スクリーンショット 2024-11-10 125800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3683457/37bcce1f-f478-c586-8ef9-ef0f894ac9fa.png)
VLANとDHCP設定するだけ。基本デフォルト
https://network.yamaha.com/setting/switch/virtualization/vlan/tag_vlan
ポート分離機能とタグVLANは併用できないかつ、4個以上VLANは作れないっぽい？のでタグにした。
作れても下層にswかrt置いてトランクポートで通信する予定なので分離機能は使わない
https://www.rtpro.yamaha.co.jp/RT/docs/lan-divide/index.html
引用-----------
同一LANインタフェースでLAN分割機能とタグVLAN機能を併用することはできません。両者 ("lan type interface port-based-option=divide-network" と "vlan interface 802.1q vid=") のうち先に入力されたものが有効となり、後から入力されるものはコマンドエラーになります。
引用--------------

2-4個のVLAN作るかつ、下層SWとトランクしないならLan分離機能でもよいかな。
https://network.yamaha.com/setting/router_firewall/security/lan_side/divide_network-rtx1200



# ○その他
Lan分割機能で分割したポートにタグVLAN設定しようとしたけどうまくいかなくて悩んだ。
公式ページはちゃんと見ましょう！
https://www.rtpro.yamaha.co.jp/RT/docs/lan-divide/index.html
OpenCVを用いた色検出


## 1: 必要なライブラリをインポートする
```
import cv2
import numpy as np
```
## 2: 画像を読み込む
```
# 画像を読み込む
image = cv2.imread('image.jpg')
```
## 3: 色空間を変換
HSV色空間に変換します。HSV色空間は、色調(Hue)、彩度(Saturation)、明度(Value)を使って色を表現し、特定の色範囲を選択しやすくなります。
```
# 色空間をHSVに変換
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
```
## 4: 色の範囲を定義
特定の色範囲をHSV値で定義します。ここでは例として、青色の範囲を定義しますが、必要に応じて調整してください。
```
# 青色の範囲を定義（HSV空間）
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
```
## 5: 色範囲内のマスクを作成
定義した色範囲に基づいてマスクを作成します。マスクは、選択した色範囲のピクセルが白、それ以外が黒として表示される2値画像です。
```
# 青色の部分のみを取り出すマスクを作成
mask = cv2.inRange(hsv, lower_blue, upper_blue)
```
## 6: マスクと元画像の論理積
マスクを元の画像に適用して、特定の色が存在する領域のみを抽出します。
```
# マスクを元画像と組み合わせる
res = cv2.bitwise_and(image, image, mask=mask)
```
## 7: 結果を表示
```
# 元画像、マスク、結果を表示
cv2.imshow('Original', image)
cv2.imshow('Mask', mask)
cv2.imshow('Detected Color', res)
cv2.waitKey(0)
cv2.destroyAllWindows()
```
【Ruby】配列の初期化について

# はじめに
こんにちは！アメリカの大学で語学を学びながら、独学でソフトウェアエンジニアを目指している者です。
Rubyを使用して勉強を進めている中で、配列の初期化に関して興味深い性質に気づいたので、この記事でその知識を共有したいと思います。
# 基本的な配列初期化の問題例
行列のように以下のような配列を作成したいと考えてみましょう。
```math
\begin{pmatrix}
0 & 3 & 0 \\
0 & 0 & 0 \\
0 & 0 & 0 
\end{pmatrix}
```
その場合、以下のコードが思い浮かぶのではないでしょうか。
```ruby
a = Array.new(3, [0, 0, 0])
a[0][1] = 3
p a  # => [[0, 3, 0], [0, 3, 0], [0, 3, 0]]
```
この例では、配列 `a` に [0, 0, 0] という初期値の配列を3つ格納しようとしています。
しかし、結果として `a`のすべての要素が<strong>同じ参照</strong>を持つため、1つの要素を変更すると、他のすべての要素にも影響が及びます。
つまり、`a[0][1] = 3` の操作が `a` のすべての配列に反映されてしまうのです。

# なぜこうなるのか
`Array.new(3, [0, 0, 0])` では、Rubyが1つのオブジェクト `[0, 0, 0]` を作成し、それを配列のすべての要素に割り当てています。
その結果、すべての要素が同じ配列を参照するようになります。このような参照の共有により、1つの要素を変更すると他の要素も影響を受けるという現象が発生するのです。

# 対処法：個別のオブジェクトを生成する
この問題を解決するために、ブロックを使って要素ごとに異なる配列を生成する方法があります。
```ruby
a = Array.new(3) { [0, 0, 0] }
a[0][1] = 3
p a  # => [[0, 3, 0], [0, 0, 0], [0, 0, 0]]
```
この方法では、ブロック内で `[0, 0, 0]` が3回新しく生成されるため、それぞれの要素が異なるオブジェクトを参照します。
結果として、1つの要素を変更しても他の要素には影響が及ばなくなります。

# まとめ
* `Array.new(size, obj)` で配列を初期化すると、すべての要素が同じオブジェクトを参照するため、変更が他の要素にも反映される可能性があります。
* 参照の問題を回避するためには、`Array.new(size) { block } `の形式で個別にオブジェクトを生成するようにしましょう。
これにより、配列内の各要素が独立したオブジェクトとして扱われ、意図しない挙動を防ぐことができます。
[Next.js]PPRについて

# PPRとは
PPR（Partial Pre Rendering）とは、静的コンポーネントと動的コンポーネントを同一のルート内で組み合わせることを可能にする機能です。従来のレンダリングモデルのメリットを組み合わせており、既存のモデルを簡素化しつつも高いパフォーマンスを実現します。
簡単に言うと、画面の一部分だけ動的にして、それ以外の箇所は静的にすることができる機能になります。

https://nextjs.org/docs/app/building-your-application/rendering/partial-prerendering

# これまでのレンダリングモデルについて
Next.jsには、レンダリングモデルとして、SSR、SSG、ISRがありました。
それぞれ、動的にレンダリングするか、静的にレンダリングするかを設定することができますが、ページ単位(page.tsx, layout.tsxなど)でしか、設定することができませんでした。
例えば、画面の大半が静的化できるようなページでも、一部動的にデータを取得する必要がある要素があることによって、画面全体を動的化しなければいけませんでした。

しかし、PPRが出てきたことによって、この問題が解決し、デフォルトではStatic Renderingとし、<Suspense>境界内をDynamic Renderingとすることを可能としました。これにより、必ずしもレンダリングをRoute単位で考える必要はなくなり、1つのページ・1つのHTTPレスポンスにStaticとDynamicを混在させることができるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/572b273a-1e2d-3679-5b0a-aebbceecd493.png)

# PPRを使うメリット
PPRには、次のようなメリットがあります。
- ページの一部を静的にレンダリングすることで、初回ロード時間を短縮できる﻿
- ユーザーエクスペリエンスが向上する﻿
- 既存のレンダリングモデルのメリットを組み合わせて、シンプルに整理した新しいアプローチである﻿
- 既存のモデルを簡素化しつつも高いパフォーマンスを実現する﻿

例えば、ヘッダーやサイドバーなどの更新がほとんどされることのない要素については、静的にレンダリングし、データを取得して、表示している箇所については、動的にレンダリングすることで、画面速度の向上などのパフォーマンス改善が期待できます。

# 機能内容、使い方
PPRを有効にするには、以下のように、next.config.jsのppr オプションをincremental に設定し、ファイルの先頭で experimental_pprルート設定オプションをエクスポートします。

``` next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    ppr: 'incremental',
  },
}
 
export default nextConfig
```

``` app/page.tsx
import { Suspense } from "react"
import { StaticComponent, DynamicComponent, Fallback } from "@/app/ui"

// experimental_pprをエクスポート
export const experimental_ppr = true
 
export default function Page() {
  return {
     <>
      <StaticComponent />
      <Suspense fallback={<Fallback />}>
        <DynamicComponent />
      </Suspense>
     </>
  };
}
```

# まとめ
PPRは、Suspenseを用いて境界を作ることで、素直な構成でパフォーマンスをアップさせることができるようになります。

# 最後に
他にも色々な記事を書いているので、よければ読んでいってください！

https://qiita.com/hukuryo/items/97797a91d7e2ee0bcabc

https://qiita.com/hukuryo/items/2c07c52ff3386d5d75b9

https://qiita.com/hukuryo/items/ebeb26823f944f143b11
Jest テスト環境での'import.meta'読み込みエラー

## 環境
* ビルドツール: Vite
* バックエンド: Supabase
* テストライブラリ: Jest
* フロントエンドライブラリ: React

## 概要
Reactで作成したアプリをJestでテストする際、Supabaseの環境変数を読み込むための`import.meta`の記述がJestでは使用できないためエラーとなる。

今回は参考にした記事と補足の紹介を行います。

## 参考記事
https://dev.to/rubymuibi/jest-and-vite-cannot-use-importmeta-outside-a-module-24n3

## エラー解消手順の補足
基本的には参考記事の手順通り進めましたが、それでも環境変数を読み込めないエラーが発生したので、`package-lock.json`の"scripts":に`"test": "jest --setupFiles dotenv/config"`を追記しました。

これによりJest側でも環境変数が読み込めるようになりました。

※下記のサイトも参考にしました。

https://stackoverflow.com/questions/50259025/using-env-files-for-unit-testing-with-jest

## まとめ
ほとんど外部記事の紹介となってしまい、まだまだ理解が追いついていないのが現状ですが、色々試行錯誤しながらJestのテストについて学習していきたいと思います。
npm publishで大きいファイルを扱う

## 経緯
形態素解析の辞書ファイルをアップしたかったんだけど、ファイルが大きすぎてnpm publishができなかった。
https://www.npmjs.com/package/kuromoji-neologd
https://github.com/sushigadaisuki/kuromoji-ipadic-neologd
```
npm error code E413
npm error 413 Payload Too Large - PUT https://registry.npmjs.org/kuromoji-neologd - Payload Too Large
npm error A complete log of this run can be found in: C://xxxxx.log
```
## 概要
1. Github releaseで圧縮してアップロード
1. ファイルダウンロード、解凍するpostscriptを作成
1. npm install したときに自動的にファイルがダウンロード、解凍される

## 1. Github releaseで圧縮してアップロード
こんな感じ
https://github.com/sushigadaisuki/kuromoji-ipadic-neologd/releases/tag/master

## 2. ファイルダウンロード、解凍するpostscriptを作成
```javascript:postscript.js
import fetch from 'node-fetch';
import AdmZip from 'adm-zip';
import fs from 'fs';
import path from 'path';
import url from 'node:url';

// 変数
const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); // 絶対パス取得
const file_url = 'https://github.com/sushigadaisuki/kuromoji-ipadic-neologd/releases/download/master/dict.zip';
const outputPath = path.resolve(__dirname, '.'); 
const zipPath = path.resolve(__dirname, 'dict.zip');

// ファイルダウンロード
async function downloadFile(file_url, dest) {
  const res = await fetch(file_url);
  if (!res.ok) throw new Error(`Failed to fetch ${file_url}: ${res.statusText}`);
  const fileStream = fs.createWriteStream(dest);
  await new Promise((resolve, reject) => {
    res.body.pipe(fileStream);
    res.body.on('error', reject);
    fileStream.on('finish', resolve);
  });
}

// 解凍
function unzipFile(zipFilePath, outputDir) {
  const zip = new AdmZip(zipFilePath);
  zip.extractAllTo(outputDir, true);
}


(async () => {
  try {
    await downloadFile(file_url, zipPath);
    unzipFile(zipPath, outputPath);
    fs.unlinkSync(zipPath);
  } catch (error) {
    process.exit(1);
  }
})();
```

postinstallに登録してインストール時に自動的にスクリプトを走らせる。
fetchとadm-zipを使うためにインストールも仕込む。
```json:package.json
  "scripts": {
    "postinstall": "npm i node-fetch & npm i adm-zip & node postscript.js"
  }
```

## 気になる点
ライブラリをインストールしないといけないのが微妙ポイント。
zlibがビルトインなのでgzか生ファイルをダウンロードする方式なら何もインストールせずに完結できる。
でも、ファイルをいっぱいダウンロードしないといけないので一個ずつＵＲＬ書くの面倒くさい。
WindowsでのPython構築（pip環境：コマンドプロンプト＋エイリアス）


# 概要

* WindowsでPython(pip使用)環境を構築した際のメモを記載
    * 経緯：Anaconda(miniconda)を使用していたが、condaのチャネルでは配布されていないパッケージをインストールすることが増加したため
* 仮想環境はvenvでの作成を想定。pythonのバージョンはエイリアスの設定で対応
    * 複数のPythonのバージョンを使用するために、PATHとエイリアスをbatファイルで設定


---

# 手順

1. **Pythonのインストール**
    * ダウンロードサイトから所望のバージョンをダウンロード
        * https://www.python.org/downloads/windows/
    * ダウンロードファイルを実行し、インストール
        * コマンドプロンプト実行時にパスを追加するため、インストール時の「Add Python to PATH」にはチェックを入れない
    * 必要に応じて、複数のPythonバージョンをインストール

    <br>

2. **エイリアスの設定1**
    * コマンドプロンプトを起動時にbatファイルを実行するように設定する
        * ここでは、ファイル名cmdrc.bat として、%USERPROFILE% (=C:Users\〇〇)直下に配置する
    * コマンドプロンプトの実行ショートカットを追加
        * "/K" 以降が追記箇所
        ```
        %SystemRoot%\System32\cmd.exe "/K" %USERPROFILE%\cmdrc.bat
        ```
    * cmdrc.batの設定例は以下
        * pythonのインストールフォルダは適宜修正する
        * 本例では、python3.11とpython3.12をそれぞれ、python311とpython312としてエイリアスを設定
        * PATHにデフォルトのpythonを設定。以下の例では、python3.12をデフォルトに設定
        * 補足：setコマンドで追加した環境変数は、そのコマンドプロンプト内でのみ有効（閉じると消える）
    
            ```
            set PATH_PYTHON_DIR=%USERPROFILE%\AppData\Local\Programs\Python
            doskey python311=%PATH_PYTHON_DIR%\Python311\python.exe $*
            doskey python312=%PATH_PYTHON_DIR%\Python312\python.exe $*
            set PATH=%PATH%;%PATH_PYTHON_DIR%\Python312
            ```

        <br>

3. **venvで仮想環境を作成**
    * コマンドプロンプトで仮想環境を作成するファルダに移動
        * 本例では、「%USERPROFILE%\venv_dir」下に作成する
    * 仮想環境を作成するpythonのバージョンで以下を実行
        ```
        python -m venv 仮想環境名
        ```
    * pythonのバージョンを指定する場合は、該当のpythonをインストール後に以下を実行。※3.8は所望のバージョン
        ```
        py -3.8 -m venv 仮想環境名
        ```

        <br>

        
4. **エイリアスの設定2**
    * 必要に応じて、cmdrc.batにactivateのエイリアスを追加
    * 以下、設定例。コメント（@REM）以下が追記箇所
        * cdvで仮想環境の作成フォルダに移動
        * act_hogeで仮想環境hogeをactivate

        ```
        set PATH_PYTHON_DIR=%USERPROFILE%\AppData\Local\Programs\Python
        doskey python311=%PATH_PYTHON_DIR%\Python311\python.exe $*
        doskey python312=%PATH_PYTHON_DIR%\Python312\python.exe $*
        set PATH=%PATH%;%PATH_PYTHON_DIR%\Python312
        
        @REM --- 仮想環境のエイリアス（追記箇所） ---
        set VENV_DIR=%USERPROFILE%\venv_dir
        doskey cdv=cd %VENV_DIR%
        doskey act_hoge=%VENV_DIR%\対象の仮想環境フォルダ名(hoge)\Scripts\activate
        ```
---

# 補足
* コマンドプロンプトからpythonを実行時に、Microsoft Storeが起動する場合の対処法
    * 主原因：アプリの実行エイリアスが設定されている
    * 対処法：スタートボタンを右クリック　→　設定　→　アプリ　→　アプリの詳細設定　→　アプリ実行エイリアス　→　「アプリ　インストーラー」をオフにする


---

# 変更履歴
* 2024/11/10 投稿
* 2024/11/11 「補足」を追記


---
【Linux】rm -r の便利な使い方

rm -rコマンドを実行するとディレクトリ内部のファイルを消しますか？って対話形式
で聞いてくる


ディレクトリ内部のファイル数が少なければ一つ一つyesって対話形式で削除していけば問題ないけど、
ファイル数が多いと一つ一つyesって対話形式で削除していくのは日が暮れる


そこで、rm -rでディレクトリごと消すとき、内部ファイル消しますか？のyesを一気に消す方法が便利


まずは、以下のコマンドを入力してファイルを1000個作ってみる
```
# touch file{1..1000}.txt
```
⇒ファイルが作成されたこと



##### いったんrm -rでやってみる

![スクリーンショット 2024-11-10 135727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761139/3450e7f4-8f53-0317-bb58-cece85d54f57.png)

こんな感じに聞いてくる


1000回もyesを入力してると日が暮れる


そこで、

##### 対象ディレクトリ内部まで移動して、以下のコマンドを入力する
```
# yes | rm -i *.txt
```
![スクリーンショット 2024-11-10 135921.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761139/06601c97-4119-863c-a12d-1b59e45cbd00.png)
![スクリーンショット 2024-11-10 140129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761139/fd78cfc5-9583-c636-2f9b-43ccd5deeb59.png)

⇒ファイルがすべて削除されたこと
アーキテクチャが先か機能要求が先か

どーも、こんにちは!! 
思うところあり、Qiitaにはポエムしかしたためなくなりましたが、それでも寝言は続けたいと思います。

今回のポエムは標題の通り「アーキテクチャが先か機能要求が先か」と言うことです。
# 「アーキテクチャが先」論
私の周りには「アーキテクチャを先に調査してそこから欲しい機能を作る」というかたがいます。
たとえば最近私の中でホットな話題が多いMinIOやApache Kafkaがアーキテクチャとして使用できるものとした場合、その組み合わせの中でできる機能を模索した結果、ログをApache KafkaでおくってMinIOに溜めてみよう！と言った形です。
# 「機能要求が先」論
一方で、「機能要求を洗い出し、そこからアーキテクチャを選定する」と言う方法が考えられます。
たとえば、「方々からのログを溜めておきたい、ログはひっきりなしに来るのできちんとした設計が必要」となったときに、じゃぁApache Kafka使ってS3互換のストレージ(例えばMinIO)に溜めたらどうですか？となるわけです。

## それぞれのメリット・デメリット

端的に申し上げますと、このようなメリット・デメリットがあると思います。
| 手法 | メリット | デメリット |
|:-----------|:------------|:------------|
| アーキテクチャが先       | 調べるアーキテクチャが少なくて良い | 局所解に陥りやすい| 
| 機能要求が先       | 要求にフィットした機能を充てやすい | 何でもよく知っていなければならない |

アーキテクチャが先の場合、調べることはかなり少なくなりますのでコストは下げられるでしょう。しかしデメリットとしてそれが最適解である保証はありません。少なくとも調べたアーキテクチャの中では最適解かもしれませんが、それが局所解に陥っている可能性があります。

機能要求が先の場合、調べることと言いますか、知っていなければいけないことがたくさん増えることが予想され、その必要な知識量は膨大になります。しかしそこから要求に適うアーキテクチャを選定する事ができると言うことがメリットとしてあげられるでしょう。

## 昔教わった「ソフトウェア開発方法論」では･･･
私が二十数年前に大学一年生で教わった方法を例に後者でのソフトウェア開発をちょっとだけ書いておきます。
1. KJ法を使って要求をまとめる：KJ法とは川喜田二郎氏が考案した方法でその氏のイニシャルを取ってそう呼ばれています。KJ法では所謂プレストの時点で「要求」や「困っていること」などを次々に付箋紙に書き出してボードに貼り付けます。それをグルーピングしてそのグループ化されたどのようなアプリケーションがあったら良いか考えます
1. 必要な機能を洗い出す：1番のKJ法でまとめた要求に対してどのようなアプローチで解決するアプリケーションを作成するか、手法および必要な機能を決定します
1. 設計：きちんと設計をします
1. 実装：設計書通りに機能を実装します
1. テスト：きちんと要求を満たしているかテストします
1. 発表：テストがおわったら、ブレストからテストまでの軌跡をまとめ、プレゼンします

### というわけで･･･
私は「要求機能が先でアーキテクチャはその後に考える」派なのですが、その逆を考えている人がいるってことを書いてみました。

寝言は以上。おやすみなさい。
【Google Cloud】Cloud Digital Leader合格までの道のりと学び

# はじめに
先日、GCのCloud Digital Leader試験に合格しました。
きっかけは、業務でGCを使う機会が増えてきたので、勉強ついでに資格取ってみるか〜くらいのノリでした！

GC全くの初心者ですが、Cloud Digital Leaderの資格取得を通して学びが多かったので、資格取得までの道のりや学ぶを共有できればと思います！

# Cloud Digital Leader
さっそく公式から引用しつつ説明します

> Cloud Digital Leader は、Google Cloud の中核的なプロダクトやサービスの機能と、それらが組織にもたらすメリットを明確にできます。また、Cloud Digital Leader は、一般的なビジネス ユースケースや、クラウド ソリューションが企業をどのように支えているかを説明することができます。

> この認定資格は、クラウド コンピューティングの基礎に関する知識と、組織の目標を達成するための Google Cloud プロダクトとサービスの使用方法に関する知識があることを示す必要があるすべての方を対象としています。

https://cloud.google.com/learn/certification/cloud-digital-leader?hl=ja

# Cloud Digital Leaderの試験
クラウドやGCに関する基礎知識を問う資格試験という理解で良いと思います。
もう少し具体で言うと、

- Google Cloudの基本概念: クラウドコンピューティング、インフラストラクチャ、データ、アプリケーションの管理方法
- クラウドソリューションの適用: Google Cloudを使用して、企業の業務改善や効率化、データ分析などを行う方法
- デジタルトランスフォーメーション（DX）: ビジネスの変革を支えるクラウド技術の役割
- GCのリソースに関する基礎知識: Compute Engine, Google Kubernetes Engine, BigQueryなど

が学習内容であり、試験内容です。

## 難易度について
上記だけだと、ちょっと難しすぎるかも・・・と思われるかもしれないです。一般的に難易度は比較的易しめと言われているようですが、しっかりとした勉強がないと合格は難しいと感じました。特に、Google Cloudの基本的な概念や主要なサービスに関する理解が求められるため、準備が必要です。

公式も
> No technical prerequisites

と言っているのでそういう意味では易しいのかなとは思います！
とは言え、一般的なIT知識についてある程度知っている前提ではあります。非エンジニアでも勿論合格を目指せますが、全くの前提知識ゼロだと勉強が少し大変だと思います！

## 試験の説明

- 試験時間: 90 分
- 登録料: $99
- 言語: 英語、日本語、スペイン語、ポルトガル語、フランス語
- 試験の形式: 50 ～ 60 問の多肢選択（複数選択）式

30分くらいでテストセンターから退席しました。受験後、すぐに合否結果が表示され、当日に結果を知ることができました。ただし、具体的な点数や各設問の正誤については表示されませんでした。

### 試験内容
上述の通りですが、Cloud Digital Leaderの試験では、Google Cloudに関連する基本的な知識が問われます。

- クラウドの概念とその利点
- Google Cloud Platformのサービスとソリューション
- データの管理と分析
- クラウドセキュリティとコンプライアンス
- ビジネスにおけるクラウドの活用方法
あたりです。

「〇〇な前提で、△△をしたい場合、どんなソリューションが適切ですか？」
みたいな感じな問が多かった印象です。

クラウドに対する基本的な理解と、基本的なGCリソースの役割・ユースケースを理解を意識して勉強すると良いのかなと思います！

# Cloud Digital Leaderの勉強の軌跡
僕が合格するまで、どんな勉強をしていたのかを紹介します。一助になれば幸いです。
（できる限りお金を使わずに受かることがテーマでしたｗ）
※AWSやGCについて、ちょこっと触ったことがあったので、全くの知識ゼロでの勉強ではありません。

1. 模擬試験を受けてみる
兎にも角にもどんな試験で、どんなことを問われる試験なのかを把握するため、そして自分の現在地を知るために一旦受けてみました！
案の定、全然点は取れなかったのですが、「この辺の理解がないんだな」と気付けただけポジティブだと思っています！

https://docs.google.com/forms/d/e/1FAIpQLSdyQtCFqpNSlv8xJwc8goExJOzSAKxiWW2BoVhO1QWRUEUuKA/viewform?hl=ja

2.公式のSkills Boostを使って勉強する
（CDLに限らず、他の資格においても有益な教材だと思います！）
僕は一通り見て、どの確認テストも満点が取れる状態を目指して勉強していました。

https://www.cloudskillsboost.google/paths/9

3.Udemyで模擬試験
唯一課金したのがUdemyでした。（安くなったタイミングで購入しました。）
本番試験よりやや難易度が高く感じましたが、実践的な内容で大変役立ちました。すべての問題で満点を取ることを目標にしながら勉強しました！

https://www.udemy.com/share/1085W23@ftU8QyTAbBxSucvfwtONL-bo_PSQUwlh7-BhKPjw2cg4wcd-5bzRRg8BxHCZPUzDBA==/

# 学び・気付き
CDLの学習を通して、多くの気付きがありました！
知識があるからこそ、より効果的なソリューションにたどり着けるのだと実感しています！単なる資格取得だけでなく、その過程で得た知識が日々の業務や仲間のサポートにも役立つことを感じました。資格を勉強することで、Google Cloudの基本から応用まで広がる新たな視点を得られたのも大きな収穫です。

資格取得はゴールではなくスタートです。知識を持つことも重要ですが、それを実際の現場で活かしていくことが何よりも大切だと思います。この資格の勉強を通して得た知識を仕事や周囲とのコミュニケーションで活用することで、より多くの成長や貢献ができると感じています。
これを読んでくださっている皆さんも、是非資格取得を通じて正しい知識を身に付け、それを実践で活かしてみてください。どんな分野でも、知識が実践に根ざした時、本当の価値が見えてくると思っています！
超基本的なOSを作ろう

自分でOSを1から作ってみる Advent Calendar 2024の2日目です。
# 今日の目標
今日はとりあえずPCを起動したら自動で実行されるソフトフェアを作成していきたいと思います。そのためにまずブートセクタを作成して、それをディスクイメージに書き込むところまでやっていこうと思っています。
# まず環境構築
まずは面倒な環境構築から片づけてしまいましょう。今回はNASM,QEMUをインストールしていこうと思います。言い忘れていましたがこの記事ではwindows向けに説明していきます。この部分はあまりこの記事においては重要ではないので、あまり詳しくは説明しません。分からなければググるかchatgptにお尋ねください。
### NASMの環境構築
1. [NASMの公式ページ](https://www.nasm.us/)にアクセスする
2. Downloadのページに行って、ダウンロードしたいバージョンのフォルダにアクセスする
3. 適切な(例:win64)フォルダに移動し、installer.exeみたいなやつをダウンロードする
4. ダウンロードしたexeファイルを実行する
5. 設定から環境変数を開き、PathのところにさっきexeファイルでインストールしたNASMのPath(例:C:\Users\froms\AppData\Local\bin\NASM)を入力する。再起動すると適用されるはずです
6. ```nasm-v```を実行してみてNASMのバージョンが表示されれば設定は完了です
### qemuの環境構築
qemuの環境構築もほぼNASMの環境構築と同じなのですが、一応やっておきましょう
1. [QEMUの公式ダウンロードページ](https://www.qemu.org/download/#windows)に移動する
2. 32ビットか64ビットか選択して一番下の方にあるexeファイルをダウンロードします 
3. ダウンロードしたexeファイルを実行してください。残念ながら日本語はありません。
4. 3でインストールしたフォルダをnasmと同じようにPathを通してください。
5. ``` qemu-system-i386 --version```を実行してみてQEMUのバージョンが表示されれば成功です。
# とりあえずブートセクタを作ろう
どういう仕組みなのかを説明する前にまずは早速作ってしまいましょう。
まず、下のコードをテキストエディタで書き、「boot.asm」という名前で保存しましょう。この時デスクトップかなんかに適当なフォルダを1つ作っておき、そこに保存するといいでしょう。
```nasm:boot.asm
org 0x7C00              ; ブートセクタのアドレス

start:
    mov ax, 0xB800      ; テキストモードのビデオメモリのセグメントアドレス
    mov es, ax
    mov di, 0           ; ビデオメモリの先頭位置（画面の左上）

    mov si, message     ; メッセージの先頭アドレスをSIに設定

print_char:
    lodsb               ; メモリから1バイトをALにロード
    cmp al, 0           ; 終端をチェック
    je hang             ; 終端なら停止
    mov [es:di], al     ; 文字をビデオメモリに書き込む
    inc di              ; 次のビデオメモリ位置へ
    mov byte [es:di], 0x07 ; 文字の色（白）
    inc di
    jmp print_char      ; 次の文字へ

hang:
    jmp $               ; 無限ループで停止

message db "hello, world", 0  ; 表示するメッセージ

times 510-($-$$) db 0         ; 残りのバイトをゼロで埋める
dw 0xAA55                     ; ブートセクタ署名
```
次に、「boot.asm」を作成したフォルダでターミナルを開き、以下のコマンドを実行してください。
```nasm -f bin boot.asm -o boot.bin```
もうこれでOS(?)はとりあえず作れました。なので早速実行していきましょう。
でも実際のPCで実行するのはいろいろと面倒なので、とりあえず仮想環境で実行してみましょう。下のコードを実行してください
```qemu-system-x86_64 -drive format=raw,file=boot.bin```
すると、下のような画面が表示されるはずです。
![スクリーンショット 2024-11-10 134104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3930909/6bb7d9b2-54a2-f724-2636-8c862906b84c.png)
とはいえ、まだOSを作れたとは言い難いと思います。なぜなら、今作った部分はOS本体ではなくOSをメモリに読み込むために使うブートセクタという部分だからです。
次は今回やったことの説明をしようと思います。それが終わったらOS本体の制作に取り掛かっていきたいと思います。
iOS向けUnity開発中にCocoaPods関連のエラーが発生した際の対処法

## 実証環境
Macbook Air 2
macOS 14.2.1
Unity 2021.3.29f1
Xcode 15.2



## やっていたこと
以下の記事を参考に、UnityでGeospatial APIを使ったiOS向けのアプリを作っていた。

https://www.mlit.go.jp/plateau/learning/tpc14-3/

## 発生した2つのエラー

①Geospatial APIを使うために、ARCore Extensionsパッケージを入れた時から、パッケージを入れたりiOS関連の変更を行なったりすると次のエラーが定期的に表示された。
```
iOS Resolver

Failed to install CocoaPods for the current user.

It will not be possible to install Cocoapods in the generated Xcode project 
which will result in link errors when building your application.

・
・
・

 ```

②なんやかんやで上記エラーを回避したところ、次はUnityでiOS向けにビルドするとき次のエラーが発生。
```
iOS framework addition failed due to a CocoaPods installation failure. This will will likely result in an non-functional Xcode project.

After the failure, "pod repo update" was executed and failed. 
"pod install" was then attempted again, and still failed. 
This may be due to a broken CocoaPods installation. 

See: https://guides.cocoapods.org/using/troubleshooting.html for potential solutions.

・
・
・

```

上記2つとも、無理やりUnityでビルドしてXCodeまで持っていけるが、Xcodeでのビルドの時にエラーになる。

## 1つ目のエラー回避方法

要は、「CocoaPodsというものをインストールしたいがUnity側ではできない」ということなので、手動でCocoaPodsというものを入れてやる。CocoaPodsはiOS向けに必要なパッケージたちを紐づけてくれる的なやつらしい。

CocoaPodsについて→

https://cocoapods.org/about

Cocoapodsをインストールするコマンドは次の通り。
```
sudo gem install cocoapods
```
でも最初は次のようにpermissionがありませんというエラーが出る。
```
You don't have write permissions for the /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/gems/2.6.0 directory.
```

どうやらCocoaPodsをインストールするためにはRubyが必要らしい。もともとMacにはRubyが入っているが、システム標準のRubyだと権限の問題で先ほどのpermissionエラーが出てしまう。そこで、Rubyのバージョン管理をしてくれるrbenvを導入し、rbenvを使って別バージョンのRubyを入れてやる。この手順については以下の記事を参考にさせていただいた。

https://www.sejuku.net/blog/3958

rbenvでRubyをインストールして環境設定が完了したら、改めて以下のコードでcocoapodsをインストール！
```
sudo gem install cocoapods
```
自分の環境ではこれでエラーなくcocoapodsがインストールされた。

## 2つ目のエラー回避方法

こちらも、「Unity側ではビルドに必要な"ワークスペース"?的なものを作れない！」ということなので、ビルドしたフォルダの中に手動で必要なものを入れればOK。

先ほどの手順でcocoapodsが入っているため、podコマンドが使える。ビルドしたフォルダ内で次のコマンドを打てば、Unityでのビルド時にエラーとなっている原因は解決できる。

```
pod install
```
もしくは
```
pod update
```
以下の記事を参考にさせていただいた。

https://qiita.com/ryamate/items/e51c77fbabc2aec185fc


### 最後に

手作業しか勝たん
ChromeOSのXAMPP環境にXdebugでデバッグができるようにした

VScodeをインストールして、XAMPP環境にXdebugでデバッグができるようにした。

ネットで調べても色々な情報があり、何をしたらいいのかわからないまま手探りで設定を進めて、必要な手順がわかった。

以下に手順を記載する。

①VScodeをインストールする
②VScodeの拡張機能に「PHP Xdebug」をインストールする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3931560/98028aa5-e3b9-a178-c238-e24ba57df42b.png)

③XAMPPにXdebugがもともと入っているのでphp.iniに以下の設定をした。
※XAMPPのバージョンはXAMPP for Linux 5.6.40
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3931560/dc5fbec6-9baf-0ba3-28e1-0afcb4634d76.png)

以上
ポケモンのタイプ相性クイズ（Python）

## なにこれ
ポケモンのタイプ相性クイズです。
記事の最後にあるコードをpythonで実行すると遊ぶことができます。
Pythonistaに入れればiPhoneでもポチポチできます。

## 遊び方
実行すると「Electric_to_(Fire_and_Ghost)_=_?」みたいにきかれます。
何倍かを答えてあげるとよいです(この場合は1が正解です)
ランダムに10問出題されます。最後に10問中何問正解かスコアが表示されます。

## 動機
ポケモンをやっていたときにタイプ相性が全然覚えられなくて作りました。
当時はまだエンジニアではなく、大学で使っていたPythonとRしか経験がなかったのでPythonを選びました。

## ソースコード
何も面白味のないコードですが、よければどうぞ。

```python:pokemon.py

import random

type = ["Normal","Fire","Water","Electric","Grass","Ice","Fighting","Poison","Ground","Flying","Psychic","Bug","Rock","Ghost","Dragon","Dark","Steel","Fairy"]

compatibility = []
compatibility.append([1,1,1,1,1,1,1,1,1,1,1,1,0.5,0,1,1,0.5,1]) # normal
compatibility.append([1,0.5,0.5,1,2,2,1,1,1,1,1,2,0.5,1,0.5,1,2,1]) # fire
compatibility.append([1,2,0.5,1,0.5,1,1,1,2,1,1,1,2,1,0.5,1,1,1]) # water
compatibility.append([1,1,2,0.5,0.5,1,1,1,0,2,1,1,1,1,0.5,1,1,1]) # electric
compatibility.append([1,0.5,2,1,0.5,1,1,0.5,2,0.5,1,0.5,2,1,0.5,1,0.5,1]) # grass
compatibility.append([1,0.5,0.5,1,2,0.5,1,1,2,2,1,1,1,1,2,1,0.5,1]) # ice
compatibility.append([2,1,1,1,1,2,1,0.5,1,0.5,0.5,0.5,2,0,1,2,2,0.5]) # figting
compatibility.append([1,1,1,1,2,1,1,0.5,0.5,1,1,1,0.5,0.5,1,1,0,2]) # poison
compatibility.append([1,2,1,2,0.5,1,1,2,1,0,1,0.5,2,1,1,1,2,1]) # ground
compatibility.append([1,1,1,0.5,2,1,2,1,1,1,1,2,0.5,1,1,1,0.5,1]) # flying
compatibility.append([1,1,1,1,1,1,2,2,1,1,0.5,1,1,1,1,0,0.5,1]) # psychic
compatibility.append([1,0.5,1,1,2,1,0.5,0.5,1,0.5,2,1,1,0.5,1,2,0.5,0.5]) # bug
compatibility.append([1,2,1,1,1,2,0.5,1,0.5,2,1,2,1,1,1,1,0.5,1,1]) # rock
compatibility.append([0,1,1,1,1,1,1,1,1,1,2,1,1,2,1,0.5,1,1]) # ghost
compatibility.append([1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0.5,0]) # dragon
compatibility.append([1,1,1,1,1,1,0.5,1,1,1,2,1,1,2,1,0.5,1,0.5]) # dark
compatibility.append([1,0.5,0.5,0.5,1,2,1,1,1,1,1,1,2,1,1,1,0.5,2]) # steel
compatibility.append([1,0.5,1,1,1,1,2,0.5,1,1,1,1,1,1,2,2,0.5,1]) # fairy

"""
print("number of type,",len(type))
for i in range(len(compatibility)):
	print(len(compatibility[i]))
"""

l = len(compatibility)-1
score = 0

for i in range(10):
	a = random.randint(0,l)
	b = random.randint(0,l)
	c = random.randint(0,l)
	#print(a,b,c)

	#a,b,c = 1,1,2

	print()
	print(str(i+1)+"/10")
	
	if b != c :
		print(type[a],"_to_(",type[b],"_and_",type[c]," )_=_?")
		
	else :
		print(type[a],"_to_",type[b],"_=_?")
  
	answer = float(input())
  
	if b != c:
		if answer == float(compatibility[a][b]*compatibility[a][c]):
			print("collect!")
			score = score + 1
			
		else:
			print("wrong!")
			print(type[a],"_to_(",type[b],"_and_",type[c],")_=_",str(compatibility[a][b]*compatibility[a][c]))
		
		print(type[a],"_to_",type[b],"_=_",str(compatibility[a][b]))
		print(type[a],"_to_",type[c],"_=_",str(compatibility[a][c]))
		
	else:
		if answer == float(compatibility[a][b]):
			print("collect!")
			score = score + 1
		else:
			print("wrong!")
			print(type[a],"_to_",type[b],"_=_",str(compatibility[a][b]))
		
		print(type[a],"_to_",type[b],"_=_",str(compatibility[a][b]))

print()
print("score : ",str(score),"/10")
	
```