OmniAICreator/Qiita-1.07M huggingface dataset:
Reactで簡易ブログ①: react-markdownで記事を書く

[自分のサイト](https://huriko-poral.pages.dev/)でのブログページの構築方法についてのメモです。

ざっくり前提
- 環境はReact + Next.js + daisyUI
- 必要なファイルは全部public配下にぶち込む

1.  react-markdownの導入

    ```
    yarn add react-markdown
    ```
    <br>
1. .mdファイルを作る

    今回は`public/blog/md/`配下にmdファイルを書き溜めていきます。
    
    ~~~
    <!-- リンク -->
    [URL]()
    
    <!-- 画像 -->
    ![画像](/path.png)
    
    <!-- コードブロック -->
    ```
    <!-- 中身 -->
    ```
    
    ~~~
    
    
    [URL]()だったり
    ```
    コードブロックだったり
    ```
    
    ## H2
    ### H3 だったり
    基本的なところは使えそうです。
    <br>

1. ざっくり記事詳細ページを作る

    あまりパフォーマンス意識した記述が出来ていないかもしれません。
    一旦は妥協、将来的には外部から記事データ取得して動的にページ生成したいのでそこで改善かな?
    
    ```
    // blog/[blogid]/page.tsx
    import * as fs from 'fs';
    import ReactMarkdown from "react-markdown";
    import { BlogList, articleKey } from '../blogList';
    export const generateStaticParams = async () => {
        const blogList = new BlogList();
        const articles = blogList.getArticles();
    
        return articles.map((article: articleKey) => ({
            blogid: article.blogId
        }));
    };
    
    export default function BlogPage({ params }: { params: { blogid: string} }) {
    
        const path = "public/blog_md/" + params.blogid + ".md"
        const data = params.blogid !== null
            ? fs.readFileSync(path, 'utf-8')
            : "Not found"
            // 今後notFound()独自に作る?
        return (
            <>
                <article className="prose flex-1">
                    <ReactMarkdown>{data}</ReactMarkdown>
                </article>
            </>
        )
    }
    ```
    
    ```
    export const generateStaticParams = async () => {
        const blogList = new BlogList();
        const articles = blogList.getArticles();
    
        return articles.map((article: articleKey) => ({
            blogid: article.blogId
        }));
    };
    ```
    
    今回のサンプル作成時点では`BlogList`内にベタ書きした`blogid`を取得して`generateStaticParams`でのページ生成用paramsを作ってます。

    <br>

1. 見てみる
    
    この記事執筆中のスクショです。
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573970/7972debf-0e12-db39-f868-9a52410a7f98.png)
    
    細かい調整せずともそこそこいい感じになってくれるからありがたいですね。
    
    ```
            <>
                <article className="prose flex-1">
                    <ReactMarkdown>{data}</ReactMarkdown>
                </article>
            </>
    ```
    <br>

1. おわりに
自前でブログ記事ページを書いてみましたが、結局Qiitaに前記事移管予定です……
sector size

# references

## large block for I/O

https://lore.kernel.org/linux-block/03ebbc5f-2ff5-4f3c-8c5b-544413c55257@suse.de/

## Real life workloads allow more efficient data granularity and enable very large SSD capacities

https://www.storagenewsletter.com/2023/10/12/from-micron-real-life-workloads-allow-more-efficient-data-granularity-and-enable-large-ssd-capacities/

(https://www.micron.com/about/blog/2023/october/real-life-workloads-allow-more-efficient-data-granularity-and-enable-very-large-ssd-capacities)
PGP公開鍵で暗号化したファイルを送信する

# はじめに
平文で送信するべきではないファイルをPGP公開鍵を用いて送信する方法を紹介します。

# 手順
AさんからBさんへ `secure.txt` を送信するとします。

## BさんがPGP公開鍵を作成し、Aさんへ送信する
```bash
gpg --full-generate-key
```
作成する際のユーザー名は `bbbbb` 、メールアドレスは `bb@bb` 、パスフレーズは `b` としました。
以下のコマンドで公開鍵のファイルを生成します。
```bash
gpg --export -a "bbbbb" > b_public_key.asc
```
Bさんは作成した `b_public_key.asc` をAさんに送信します。公開鍵であるため、外部に公開しても問題ありません。
また、Bさんは以下のコマンドで表示される作成した鍵のfingerprintsも送信します。
```bash
gpg --list-keys --with-subkey-fingerprints
```
```bash
pub   rsa3072 2024-04-02 [SC] [expires: 2026-04-02]
      22A86D806EAB665CA9E7B88AC9CDA2F3FEA076A0
uid           [ultimate] bbbbb <bb@bb>
sub   rsa3072 2024-04-02 [E] [expires: 2026-04-02]
      CC940889A2A3637CDFCE7BCF0D024F6E42C9E782
```

## AさんはBさんの公開鍵を用いて暗号化する
まずはBさんから受け取った公開鍵をインポートします。
```bash
gpg --import b_public_key.asc
```
続いて公開鍵を用いて暗号化します。
```bash
gpg --encrypt --recipient bb@bb secret.txt
```
このときfingerprintsが表示されるので正しいことを確認し、実行します。

これにより、 `secret.txt.gpg` というファイルが生成されます。AさんはこれをBさんに送信します。

## Bさんが復号する
Bさんは秘密鍵を用いて復号します。
```bash
gpg --decrypt secret.txt.gpg
```
復号した結果が表示されます。
以上です。
【TypeScript】型ガードについて

## 型ガードとは

型ガードを使用するとifブロック内で特定の型に絞り込めます。これにより、その型のプロパティやメソッドに安全にアクセスできます。

以下に、`in`演算子、`instanceof`演算子、`typeof`演算子、ユーザー定義の型ガード関数を使用した型ガードの例を示します。

## `in`演算子

`in`演算子は、プロパティがオブジェクトに存在するかどうかをチェックするために使用されます。
型ガードとして使用すると、特定のプロパティが存在する場合にそのオブジェクトを特定の型に絞り込めます。
```ts
type Cat = {
  meow: string
}

type Dog = {
  bark: string
}

function speak(animal: Cat | Dog) {
  if ('meow' in animal) {
    console.log(animal.meow) // 'meow'キーが存在するのでCat
  } else {
    console.log(animal.bark) // 'meow'キーが存在しないためDog型
  }
}

```

## `instanceof`演算子

`instanceof`演算子は、オブジェクトが特定のクラスのインスタンスであるかどうかをチェックするために使用されます。
型ガードとして使用すると、特定のクラスのインスタンスである場合にそのオブジェクトを特定の型に絞り込めます。

```ts
class Cat {
  meow = 'meow'
}

class Dog {
  bark = 'bark'
}

function speak(animal: Cat | Dog) {
  if (animal instanceof Cat) {
    console.log(animal.meow)
  } else {
    console.log(animal.bark)
  }
}

```

## `typeof`演算子
`typeof`演算子は、変数の型をチェックするために使用されます。
型ガードとして使用すると、特定の型であると結論付けることができます。

```ts
function process(input: string | number) {
  if (typeof input === 'string') {
    console.log(input.toUpperCase())
  } else {
    console.log(input.toFixed(2))
  }
}

```

## ユーザー定義の型ガード関数

上記以外にもユーザー定義の型ガード関数を定義できます。

```ts
class Cat {
  meow = 'meow'
}

function isCat(animal: Animal): animal is Cat {
  return animal instanceof Cat
}

if (isCat(animal)) {
  console.log(animal.meow)
}

```

`animal instanceof Cat`が`true`の場合にifブロック内で`animal`がCat型として解釈されるようになります。

```ts
function isString(value: unknown): asserts value is string {
  if (typeof value !== "string") {
    throw new Error("Not a string!")
  }
}

```

上記のように記述すると`Error`が`throw`されない場合には、string型として解釈されます。
dockerで起動したCosmosDBのデータを永続化させる

# 概要
公式の手順に則ってDocker(Linux コンテナー)を起動する（windowsでWSLを使って起動した場合も同じ手順だと思う）が、環境変数だけではデータを永続化できない（docker downしたらデータが消える）ので消えない方法を調べました

#### 公式の手順
https://learn.microsoft.com/ja-jp/azure/cosmos-db/how-to-develop-emulator?tabs=docker-linux%2Ccsharp&pivots=api-nosql

# 結論
1. 環境変数「AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE」に何かしらを設定する
1. /tmp/cosmosにボリュームをマウントする

# dockerコマンドサンプル
```bash
docker run \
    --publish 8081:8081 \
    --publish 10250-10255:10250-10255 \
    --interactive \
    --tty \
    -env AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true
    -v ./db:/tmp/cosmos
    mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest  
```

# docker-compose.yml サンプル
```yaml
version: '3.8'

services:
  cosmos:
    container_name: cathy_cosmos
    image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
    tty: true
    stdin_open: true
    ports:
      - 8081:8081
      - 10250-10255:10250-10255
    environment:
      AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE: true
    volumes:
      - cosmos-volume:/tmp/cosmos

volumes:
  cosmos-volume:
```

# どうなっているのか
提供されているイメージでは `/usr/local/bin/cosmos/start.sh` を起動するようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192137/d81eae55-15ce-745e-34ab-4a6bedafc0e3.png)

`start.sh` をみると、以下のような箇所があり、/tmp/cosmosを利用していることと、環境変数によってDBの初期化処理を切り分けていることが分かります。
```bash
#!/bin/sh
～～略～～
COSMOS_APP_HOME=/tmp/cosmos


EMULATOR_DEFAULT_CERTIFICATE="default.sslcert.pfx"
EMULATOR_CERTIFICATE_OPTION="/exportcert=c:\\${EMULATOR_DEFAULT_CERTIFICATE}"

if [ -z "${AZURE_COSMOS_EMULATOR_CERTIFICATE}${AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE}" ]; then
    # Work around to remove old emulator data since restarting with existing data does not work at this time.
    if test -d "${COSMOS_APP_HOME}/appdata"; then
        rm -fr "${COSMOS_APP_HOME}/appdata"
    fi

    mkdir -p ${COSMOS_APP_HOME}/appdata
else
    if test -d "${COSMOS_APP_HOME}/appdata"; then
        rm -fr "${COSMOS_APP_HOME}/appdata/log"
        rm -fr "${COSMOS_APP_HOME}/appdata/var"
        rm -fr "${COSMOS_APP_HOME}/appdata/wfroot"
        rm -fr "${COSMOS_APP_HOME}/appdata/Packages"
        rm -fr "${COSMOS_APP_HOME}/appdata/gateway.log"
    else
        mkdir -p ${COSMOS_APP_HOME}/appdata
    fi
    
～～略～～
```

ということで、環境変数を設定し、/tmp/cosmosにマウントすることでデータを永続化することができます。

# 公式のマニュアルに書いてほしい
ここから依頼しましょう。依頼済みです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192137/1f92e885-051e-4eee-13c8-8aece7e2e7f9.png)
ベイズ学習1

# 確率モデル
未知パラメータ$\omega \in \mathcal{W}$、観測データ$\mathcal{D}$とする。
ベイズ学習では、以下の分布を用いる。

### モデル分布
```math
p(\mathcal{D};\omega)
```
### 事前分布
```math
p(\omega)
```
### 事後分布
```math
p(\omega|\mathcal{D})=\frac{p(\mathcal{D};\omega)p(\omega)}{p(\mathcal{D})}
```
### 周辺尤度
```math
p(\mathcal{D})=\int_{\mathcal{W}}{p(\mathcal{D},\omega)}dw=\int_{\mathcal{W}}{p(\mathcal{D};\omega)p(\omega)}d\omega
```

# MAP推定
あるデータが得られたときに、尤もらしいパラメータを事後分布の最大化によって決める。
これは、データの得られる確率が最も高くなるパラメータを推定することである。
```math
\hat{\omega}^{\mathrm{MAP}}=\mathrm{argmax}_{\omega}~p(\omega|\mathcal{D})
```
事前分布を一様分布としたのが最尤推定となる

# ベイズ学習
ここでは、予測分布のみ記す。
```math
p(\mathcal{D}_{new}|\mathcal{D})=\int_{\mathcal{W}}{p(\mathcal{D}_{new},\omega|\mathcal{D})}d\omega=\frac{1}{p(\mathcal{D})}\int_{\mathcal{W}}
{p(\mathcal{D}_{new},\omega,\mathcal{D})}d\omega=\frac{1}{p(\mathcal{D})}\int_{\mathcal{W}}
{p(\mathcal{D}_{new}|\omega,\mathcal{D})p(\omega,\mathcal{D})}d\omega
```
最後の式でデータ$\mathcal{D}$とパラメータ$\omega$が与えられている状況は、
パラメータ$\omega$のみが与えられる状況と等しい。したがって、
```math
p(\mathcal{D}_{new}|\mathcal{D})=\frac{1}{p(\mathcal{D})}\int_{\mathcal{W}}
{p(\mathcal{D}_{new};\omega)p(\omega,\mathcal{D})}d\omega
```

# 経験ベイズ学習
事前分布として、ハイパーパラメータ$\kappa$に依存する分布$p(\omega|\kappa)$を用いる。
これは、事前分布を複数のモデルから選択可能にすることで、より適したモデルを選ぶことが可能になるためである。
この時、ハイパーパラメータが与えられて直接データ$\mathcal{D}$を観測する確率（周辺尤度）は、
```math
p(\mathcal{D};\kappa)=\int_{\mathcal{W}}{p(\mathcal{D},\omega|\kappa)}d\omega=\int_{\mathcal{W}}{p(\mathcal{D}|\omega,\kappa)p(\omega|\kappa)}d\omega
```
最後の式でパラメータ$\omega$,$\kappa$が与えられている状況は、
パラメータ$\omega$のみが与えられる状況と等しい。したがって、
```math
p(\mathcal{D};\kappa)=\int_{\mathcal{W}}{p(\mathcal{D}|\omega)p(\omega|\kappa)}d\omega
```
これを$\kappa$について最大化すれば、ハイパーパラメータを推定できる。
Railsのフォーム送信時のname属性の設定

Railsアプリケーションでは、フォームから送信されるデータを処理する際に、`params`オブジェクトを介してパラメータを受け取ります。しかし、このパラメータが期待される形式でない場合、データの保存が失敗することがあります。今回は、`name`属性を適切に設定し、このような問題を解決する方法について解説します。

## 問題の発生

例えば、スタッフの選択と時間帯の選択を含むフォームから`TimeTable`モデルにデータを保存しようとしたとき、以下のようなログが出力されることがあります。

```
ActionController::ParameterMissing (param is missing or the value is empty: time_table):
```

このエラーは、期待されるパラメータ`time_table`が送信されていない、または空であることを示しています。

## 解決策: `name`属性の適切な設定

この問題を解決するためには、フォームの各フィールドで`name`属性を正しく設定する必要があります。特に、Railsではモデルに基づいたフォームを扱う際に、`name`属性を`モデル名[属性名]`の形式で指定することで、`params`オブジェクト内で期待される構造を保証することができます。

### 実装例

以下は、スタッフID(`staff_id`)と時間帯(`time_slot`)を選択するフォームの例です。

```erb
<%= form_with model: @time_table, local: true do |form| %>
  <%= form.collection_select :staff_id, @working_staffs, :id, :name, { include_blank: true }, { name: "time_table[staff_id]" } %>
  <%= form.select :time_slot, @time_slots, { include_blank: true }, { name: "time_table[time_slot]" } %>
  <%= form.submit "予約する" %>
<% end %>
```

このコードでは、`collection_select`と`select`ヘルパーの`name`オプションを`time_table[staff_id]`および`time_table[time_slot]`と指定することで、フォームから送信されるパラメータが`{ time_table: { staff_id: "選択されたスタッフID", time_slot: "選択された時間帯" } }`の形式になるようにしています。

## 結論

`name`属性を正しく設定することは、Railsでモデルに基づくデータの送信を扱う際に非常に重要です。この設定により、`params`オブジェクトを介したデータの処理が容易になり、エラーの発生を防ぐことができます。
「แม่อย่าเก็บไว้คนเดียว」をタイ語Universal Dependenciesで解析する

[昨日の記事](https://qiita.com/KoichiYasuoka/items/fca2185315e7ce5bc02a)の例文「แม่อย่าเก็บไว้คนเดียว」を、<a href="https://github.com/KoichiYasuoka/esupar">esupar</a>の助けを借りつつ、タイ語Universal Dependenciesで解析してみた。

```
# text = แม่อย่าเก็บไว้คนเดียว
1	แม่	แม่	NOUN	NN	_	3	vocative	_	SpaceAfter=No
2	อย่า	อย่า	AUX	AX	_	3	aux	_	SpaceAfter=No
3	เก็บ	เก็บ	VERB	VV	_	0	root	_	SpaceAfter=No
4	ไว้	ไว้	ADV	AV	_	3	advmod	_	SpaceAfter=No
5	คน	คน	NOUN	CL	_	3	obl	_	SpaceAfter=No
6	เดียว	เดียว	NUM	NU	_	5	nummod	_	SpaceAfter=No
```

![thai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/428317/157ab351-5967-44ae-ee91-c1c7cb83cf62.png)

「เดียว」は多重母音だが、他の単語は全て単音節なので、トークナイズの点では間違いようがない。むしろ、この文が難しいのは、最初の「แม่」がnsubj(主語)ではなく、vocative(呼称語)である点だろう。さて、どうしたものかな。
React公式ページで学んでみた⑦（備忘録）

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:
その中でもこれってどういう意味？とかつまづいたところを念入りに書いていこうかと思います。:fist:

# 今回の目的
前回の続きです。今回も「インタラクティビティの追加」。被る部分もあると思いますが、後で振りかえって深掘りするきっかけになるのが理想です。細かく書くと大変なのであっさりめ。

https://qiita.com/mr_noppo/items/66ffe2d745edf578fed7

# 使用したものや事前準備
・Macbook Pro
・Visual Studio Code

# 主に参考にさせていただいた記事
https://ja.react.dev/learn/updating-objects-in-state

# state内のオブジェクト更新
positon内のxとyを直接変更しているコード。本来ならstateに直接代入はできずset関数を使うのだがオブジェクト内の値は代入で変更可能である。
ただし、この場合、set関数を使用していないので再レンダは行われない。
```react
  const [position, setPosition] = useState({
    x: 0,
    y: 0
  });
  return (
    <div
      onPointerMove={e => {
        position.x = e.clientX; //このイベントハンドラが発火しても再レンダが行われることはない。
        position.y = e.clientY;
      }}
...
```

下記のように修正する

```react
      onPointerMove={e => {
        setPosition({
          x: e.clientX,
          y: e.clientY
        });
      }}
```

# スプレット構文を使用した部分的な更新
下記のようなオブジェクトを変更したいときset関数に書くのは一手間かかる。
```react
  const [person, setPerson] = useState({
    firstName: 'hoge',
    lastName: 'fuga',
    email: 'hogefuga@info.com'
  });
```
愚直に変更するなら
```react
setPerson({
  firstName: e.target.value,
  lastName: person.lastName,
  email: person.email
});
```

👆ただ上の書き方の場合、オブジェクト内の値が増えた時に書くのが面倒
オブジェクトスプレッド構文を使用する。
※スプレット構文は１レベル深いコピーのみのためオブジェクトの中にさらにオブジェクトがある場合は注意。
```react
setPerson({
  ...person, // ここで全ての値をコピー
  firstName: e.target.value // 更新する値を記述するとオーバーライドしてくれる
});

```

### オブジェクト内で参照されているオブジェクトの更新は？
下記のような構成なら
```react
const [person, setPerson] = useState({
  name: 'fuga',
  artwork: {
    title: 'hoge',
    city: 'tokyo',
    image: 'https://example.com,
  }
});
```

このようになる。（他の方法もある
つまり、深い階層を更新したいときはオブジェクトの階層ごとにスプレット構文を用意するといい。
```react
setPerson({
  ...person, 
  artwork: { 
    ...person.artwork, 
    city: 'New Delhi' 
  }
});
```
※スプレット構文が面倒な時はライブラリであるuseImmerを使うと簡潔にかける

# 終わりに
state内のオブジェクト更新にはスプレット構文を使用して間違いが起きないようにして、更新したい値だけオーバーロードする。
useImmerも使えるようになっていきたい。

# 次
https://qiita.com/mr_noppo/items/7baed5891572c308736d
ExpressにreCAPTCHAを埋め込む

BOT対策として、Expressで作成したフォームにGoogleのreCAPTCHA(v3)を埋め込みます。

## 1. GoogleのreCAPTCHAに登録する

Googleが提供するサービスなので、規約に同意して登録します。

https://www.google.com/recaptcha/about/

## 2. ドメインの設定

WebサイトのURLで使用しているドメインを追加します。
ローカルの開発環境でも動作させたいので、「localhost」も追加しておきます。

## 3. Viewの.ejsにHTMLタグを追記する

header部に.jsファイルのロードと送信関数を追記します。
次に、フォームの送信ボタンを置き換えます。
サイトキーはreCAPTCHAを登録するとGoogleから貰えます。

onSubmit関数でformタグのidを指定しているので、書き換えるのを忘れずに。

``` html
<header>
     <script src="https://www.google.com/recaptcha/api.js"></script>
     <script>
       function onSubmit(token) {
         document.getElementById("demo-form").submit();
       }
     </script>
</header>
<body>
    <form id="demo-form">
        <button class="g-recaptcha" 
            data-sitekey="ここにサイトキーを貼る" 
            data-callback='onSubmit' 
            data-action='submit'>Submit</button>
    </form>
</body>
```

## 4. express-recaptchaをインストールする

``` sh
npm install express-recaptcha
```

## 5. ルーティングにBOT判定を追加する

フォームからPOSTされたときのルーティングをにreCAPTCHAの判定処理を追加します。
Googleに問い合わせて返ってきたdataの中にscoreがあるので、任意の閾値で区切りします。1.0は人の可能性が高く、0.0はBOTの可能性が高いです。今回は間をとって0.5を閾値にしています。

Expressのミドルウェアの機能を使って、POSTされたときの処理とreCAPTCHAの判定処理を分けています。

``` app.js
const Recaptcha = require('express-recaptcha').RecaptchaV3;
const recaptcha = new Recaptcha('サイトキー', 'シークレットキー', {callback: 'cb'});
app.post('/form',
    function(req, res, next){
        recaptcha.verify(req, function(error, data){
            if(error){
                // エラー時の処理
            }
            else {
                if(data.score >= 0.5){
                    // 人として認識されたときの処理 OK
                    next();
                }
                else {
                    // BOTとして認識されたときの処理 NG
                }
            }
        });
    },
    function(req, res, next){
        // フォームの内容を処理する
    }
);
```

## まとめ

今回、View部分は自力で実装、ルーティング部分はexpress-recaptchaを使いました。
express-recaptchaの機能を使って、Viewを描画することもできるようです。
機械学習で阪神タイガースのホームラン予測してもた

今回、2022年度の打者のデータを阪神タイガースと阪神タイガース以外の11球団に分け機械学習を行いました。
その上で、2023年の結果と照らし合わし、精度を確認した後2024年シーズンの予測も行います。

# ①CSVファイルを取得（WEBスクレイピング）
```homerun.ipynb
# WEB上のデータ(HTML)にアクセス＆取得するために使用
import urllib

#HTMLからデータを抽出するために使用
from bs4 import BeautifulSoup

#表形式でデータ格納するために使用
import pandas as pandas

url = 'https://baseball-data.com/22/stats/hitter-all/tpa-2.html'
html = urllib.request.urlopen(url)
soup = BeautifulSoup(html, 'html.parser')

#HTMLから表（tableタグ）の部分を全て取得する
table = soup.find_all('table')[0]
#テーブルから行データを取得
rows = table.find_all('tr')

#データ格納用
headData = []
playerData = []

for i, row in enumerate(rows):
    #1行目
    if i == 0:
        #ヘッダ部取得
        for headerValue in row.find_all('th'):
            headData.append(headerValue.get_text())
    #2行目〜最終行未満
    elif(i > 0) and (i + 1 < len(rows)):
        #明細部取得
        playerRow = []
        for playerValue in row.find_all('td'):
            playerRow.append(playerValue.get_text())
        playerData.append(playerRow)

#DataFrameに変換
df = pd.DataFrame(data = playerData, columns = headData)

#CSV出力
df.to_csv('playerData2022.csv', sep = ',', header = True, index = False)
```

上記では、対象のURLより表形式で各打者のデータをDataFrame型に変換後、CSVファイルを取得しています。

# ②取得したCSVファイルを読み込みデータを抽出
```homerun.ipynb
# 表形式データを扱うライブラリ
import pandas as pd

# CSVデータ読み込み
df = pd.read_csv('playerData.csv', sep=',', encoding='utf-8')

# 阪神以外の11球団データを抽出
df11 = df[df['チーム'] != '阪神']
# 阪神のデータ
df_t = df[df['チーム'] == '阪神']

#本塁打との相関係数をDataFrameとして変数に保存
df.homerun = pd.DataFrame(df11.corr(numeric_only=True)['本塁打'])

#相関係数「0.7」以上の項目名を抽出
X_columns = df_homerun[df_homerun['本塁打'] >= 0.7].index.tolist()
#本塁打は目的変数のため除外
X_columns.remove('本塁打')

# 説明変数と目的変数をセット
X = df11[X_columns]
y = df11['本塁打']
```

上記では、取得したCSVファイルを読み込み、阪神の選手データとその他11球団のデータに分けています。
且つ、0.7以上のもの（ホームランに関係があるデータ）を抽出し、「Xにはそれを代入しています。

 # ③モデル作成・学習
```homerun.ipynb
#データ分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)

#モデルの箱の準備及び学習
lr_model = LR()
lr_model.fit(X_train, y_train)

#予測値の算出
y_pred_test = lr_model.predict(X_test)

#MSEの算出
mse_test = MSE(y_test, y_pred_test)

#RMSEの表示
rmse_test = np.sqrt(mse_test)

#阪神データ(説明変数)
X_t = df_t[X_columns]

#予測ホームラン数の算出
y_pred_t = lr_model.predict(X_t)

#予測本塁打列の追加
df_t['予測本塁打'] = np.round(y_pred_t).astype(np.int32)
---

print(df_t[['選手名', '本塁打', '予測本塁打']])
```
上記では、モデル（人間の脳みたいなの）のと、そのデータの評価用の学習させています。

# ④2023年シーズン予想結果（出力）
```
  選手名  本塁打  予測本塁打
3   中野　拓夢    6      2
7   佐藤　輝明   20     24
11  近本　光司    3     -1
28  大山　悠輔   23     24
32  糸原　健斗    3      0
```
上記は2022年シーズンのデータなので2023年シーズンのデータを確認したところ、中野選手と佐藤選手はドンピシャで精度の高い予測ができていました。ただホームラン数が少ない選手の予測本数がマイナスになっているので、今後の課題にしたいと思います。


## 2024年シーズンを大予想！！🐯🐯
以下で予想をしました！
```
 選手名  本塁打  予測本塁打
0   中野　拓夢    2      5
2   大山　悠輔   19     21
11  近本　光司    8     13
19  佐藤　輝明   24     29
23   ノイジー    9     12
40  木浪　聖也    1      4
```

なんと佐藤選手が29本！！
全体的に昨年より多い本数の予想結果となりました。
こればっかりは良い意味で大幅に裏切ってほしいですね🐯🐯
機械学習の精度を上げたい気持ちと、いっぱい打ってほしい気持ち半々です、、
今シーズンが終わった頃に、ここに戻ってきて答え合わせしてくださいね✌️
Terraformでオレオレ証明書をサクッと作りたいときのやつ

### 注意点
ACM Private Certificate Authorityを利用する場合、プライベートCAの料金は1つのプライベートCAごとに月額400ドル発生します。

### 本題
まずAWS Private Certificate Authorityを利用して、AWS Certificate Managerの証明書を作成する

```terraform
resource "aws_acmpca_certificate_authority" "main" {
  enabled                         = true
  key_storage_security_standard   = "FIPS_140_2_LEVEL_3_OR_HIGHER"
  permanent_deletion_time_in_days = 30
  type                            = "ROOT"
  usage_mode                      = "GENERAL_PURPOSE"

  certificate_authority_configuration {
    key_algorithm     = "RSA_2048"
    signing_algorithm = "SHA256WITHRSA"

    subject {
      common_name         = "yuukiyo"
      country             = "JP"
      locality            = "Meguro"
      organization        = "YoshidaCorp"
      organizational_unit = "ProServe"
      state               = "Tokyo"
    }
  }

  revocation_configuration {
    crl_configuration {
      enabled = false
    }
    ocsp_configuration {
      enabled = false
    }
  }
}

resource "aws_acmpca_certificate" "main_root" {
  certificate_authority_arn   = aws_acmpca_certificate_authority.main.arn
  certificate_signing_request = aws_acmpca_certificate_authority.main.certificate_signing_request
  signing_algorithm           = "SHA256WITHRSA"

  template_arn = "arn:aws:acm-pca:::template/RootCACertificate/V1"

  validity {
    type  = "YEARS"
    value = 10
  }
}

resource "aws_acmpca_certificate_authority_certificate" "main" {
  certificate_authority_arn = aws_acmpca_certificate_authority.main.arn
  certificate               = aws_acmpca_certificate.main_root.certificate
  certificate_chain         = aws_acmpca_certificate.main_root.certificate_chain
}

resource "aws_acm_certificate" "main" {
  domain_name               = "yuukiyo.com"
  certificate_authority_arn = aws_acmpca_certificate_authority.main.arn
}
```

その後は、このSSL証明書をどう利用してもいいが、一例としてALBで利用するためには以下のような設定を入れればOK

```terraform
resource "aws_lb_listener" "main" {
  load_balancer_arn = aws_lb.main.arn
  certificate_arn   = aws_acm_certificate.main.arn
  port              = "443"
  protocol          = "HTTPS"

  default_action {
    target_group_arn = aws_lb_target_group.main.arn
    type             = "forward"
  }
}
```
gridレイアウトの中にflexレイアウトの要素の幅が取れない

# 背景
カード要素をgridレイアウトで並べる。
カードのタイトルが幅よりも長くなったら省略表示を追加する。

![カードイメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689380/8ae118de-8309-10f5-ac6e-732e8c69b664.png)

↑ これをやろうとしたら、長いタイトルでカードが横に伸びてしまった。

# 原因
子要素の幅が親要素お幅になっていない。
カードのレイアウトはgridレイアウト、タイトル部分の「タグ」「タイトル」「moreボタン」のレイアウトをflexにしていた。

```
.titleContainer {
  display: flex;
  flex: 1 1 calc(100% - 32px);

  .titleLabel {
    display: flex;
    gap: 4px;
    align-items: center;
    width: calc(100% - 32px);

    .titleLabelText {
      flex: 0 auto;
      max-width: calc(100% - 60px);
      overflow: hidden;
      font: Roboto;
      color: white;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
   }
  }
```

# 解決策
タイトル部分ををgridレイアウトに変える。

```
  .roomLabelContainer {
    display: grid;
    grid-template-columns: auto 32px;
    gap: 4px;
    align-items: center;

    .roomLabel {
      display: grid;
      grid-template-columns: 60px auto;
      gap: 4px;
      align-items: center;
      width: 100%;

      .roomLabelText {
        max-width: 100%;
        overflow: hidden;
        font: Roboto;
        color: white;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
```

# 最後に
原因に気づくまで沼った。
gridレイアウトの子要素はgridレイアウトにしておくと良さそう。
Gapがやりやすいし、幅も高さもいい感じになってくれる。
React公式ページで学んでみた⑥（備忘録）

# はじめに
初めまして！
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい！自分が学んだ足跡を残していきたい！と思い記事を書きました！
最終的には自在に開発できるようになりたいと思っています。:triumph:
いろいろな記事を参考にさせてもらっています。:bow_tone2:
その中でもこれってどういう意味？とかつまづいたところを念入りに書いていこうかと思います。:fist:

# 今回の目的
前回の続きです。今回も「インタラクティビティの追加」。被る部分もあると思いますが、後で振りかえって深掘りするきっかけになるのが理想です。細かく書くと大変なのであっさりめ。

https://qiita.com/mr_noppo/items/5648128c5de10c40f12a

# 使用したものや事前準備
・Macbook Pro
・Visual Studio Code

# 主に参考にさせていただいた記事
https://ja.react.dev/learn/queueing-a-series-of-state-updates

# stateのバッチ処理
イベントハンドラおよびその中のコードが全て完了した後にUIを更新する。
setColor()というstateのset関数があって、イベントハンドラ内で赤→緑→青と変更しても、表示されるのは青だけ。

## スナップショットによりstateの値はレンダーされるまで変わらない
stateであるnumberは、レンダー後に同じ値が与えられるため、0の場合、１が常にsetされる。
```react
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(number + 1);
      }}>+3</button>
    </>
```


## 更新用関数
更新用関数を使うとcurrent値が取得される。
レンダー時にスナップショットされた値を使わないので8に更新できる。set関数の値は最後の値が採用される。
numberという値を混ぜ合わせても問題なく動作する。（numberは固定値だと解釈するとわかりやすくなる）
```react
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(number + 5); //5(numberは0)
        setNumber(n => n + 1); //6
        setNumber(n => n + 1); //7
        setNumber(n => n + 1); //8
      }}>+3</button>
    </>
```

ここまでが更新用関数と呼ばれる。
```react
n => n + 1
```
### 更新用関数の命名規則
set関数の大文字部分を取るのが一般的な慣習
```react
setEnabled(e => !e);
setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);
```


# 終わりに
イベントハンドラ内では、state+1のような書き方よりも更新用関数を使うことを癖づけておくほうがいいかもしれないですね。
絶対そっちの方がいいぞってコメントあればいただけると嬉しいです。

# 次
https://qiita.com/mr_noppo/items/fae25e7241febee4799f
【初心者】SpringフレームワークにおけるDIコンテナについて

## DIコンテナとは何か

DIコンテナは、**オブジェクト間の依存関係を管理する仕組み**です。

インスタンスの生成、オブジェクトへのインスタンスの注入、インスタンスのライフサイクルの管理の役割を担います。

## なぜDIコンテナを使うのか
### 従来

```java
public class UserService {
	public List<User> findAll() {
		UserRepository userRepository = new JdbcUserRepository();
		return userRepository.selectAll();
	}
}
```

問題点

JdbcUserRepositoryクラスをテスト用のTestUserRepositoryに変更したい場合、以下のように変更する必要があります。

```java
public class UserService {
	public List<User> findAll() {
		//JdbcUserRepository → TestUserRepository
		UserRepository userRepository = new TestUserRepository();
		return userRepository.selectAll();
	}
}
```

この状態では実行する状況に応じてコードを書き換える必要があり、保守性が低いコードとなってしまいます。

### DIを使った解決

※DIの方法は複数ありますが、今回はコンストラクタインジェクションを用います。

従来の書き方では、new 演算子で利用するオブジェクトを呼び出していましたが、DIを使用する場合、コンストラクタの引数で利用したいオブジェクトの型を指定することで、その型のオブジェクトをフィールドに代入しています。

このようにオブジェクトを型を指定して受け取ることで、従来の書き方のように本番用とテスト用でコードの書き換えの必要が無くなり、保守性を高めることができます。

```java
public class UserService {
	private final UserRepository userRepository;
	//UserRepositoryインターフェースの具象クラスであれば、JdbcUserRepositoryクラスでも、TestUserRepositoryでも注入することが可能
	public UserService(UserRepository userRepository) {
		this.userRepository = userRepository;
	}
	public List<User> findAll() {
		return userRepository.selectAll();
	}
}
```

## DIコンテナはどう動くか
1. コンポーネントスキャン
JavaConfigクラスに@ComponentScanアノテーションを記述し、アプリケーション起動時にステレオタイプアノテーション（@Component、@Service）のついたオブジェクトやJavaConfigクラス内の@Beanアノテーションのついたメソッドを探します。
2. Beanインスタンス生成
コンポーネントスキャンで見つけたステレオタイプアノテーションのついたオブジェクトや@Beanメソッドの戻り値となるオブジェクトのインスタンスを生成します。このDIコンテナが管理するインスタンスのことをBeanと言います。
3. 注入先の検索
@Autowiredアノテーションのついたフィールド、コンストラクタ、メソッドを探します。
※コンストラクタが1つしかないクラスの場合、@Autowiredアノテーションを省略可能です。
    ```java
    public class UserService {
    	private final UserRepository userRepository
    	@Autowired
    	public UserService(UserRepository userRepository) {
    		this.userRepository = userRepository;
    	}
    }
    ```
    
4. インジェクション（注入）の実行
見つけた注入先にBeanを渡します。
上記のコードでは、コンストラクタの引数に「UserRepository」型を指定しています。
DIコンテナはBean(DIコンテナが管理するオブジェクト)コンストからコンストラクタの引数の型のサブクラスや具象クラスを注入先に渡します。
AWS RDS mysql 5 と 8 のパラメーターグループの差分把握

## 何がしたいか

現行稼働の RDS(mysql) が 5 系なので、8 系に更新したい

手始めに、パラメーターグループについて

* mysql 5系(現行稼働)
* mysql 8系(デフォルト値)

の 2 種を txt 形式で出力し、パラメーター差分を把握可能としたい

## 作業環境

* [awscli v2](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)
* bash

## 現行稼働のパラメーターグループを取得

* DB インスタンス名は `DB_INSTANCE_NAME_X` とする

```bash
# 変数設定 >>>>> インスタンス名に合わせて変える <<<<<<
$ db_instance="DB_INSTANCE_NAME_X"

# 変数設定
$ current_parameter_group=$(aws rds describe-db-instances \
--db-instance-identifier $db_instance \
--query "DBInstances[].[DBParameterGroups[0].DBParameterGroupName]" \
--output text)

# txt 出力
$ aws rds describe-db-parameters \
--db-parameter-group-name  ${current_parameter_group} \
--query "Parameters[].[ParameterName,ParameterValue]" \
--output text > ${current_parameter_group}.txt

# 出力確認
$ cat DB_INSTANCE_NAME_X.txt | head -3
allow-suspicious-udfs	None
autocommit	None
auto_generate_certs	None
```

## mysql 8系 のデフォルトパラメーターグループを取得

* 一時的に `temp-paramg` というパラメーターグループを作成
  * mysql 8 系 デフォルトパラメーターが適用済
* `temp-paramg` を txt で出力
* 後始末で `temp-paramg` を削除

```bash
# temp-paramg という名の一時的なパラメーターグループを作成
$ parameter_group_family="mysql8.0"
$ aws rds create-db-parameter-group \
 --db-parameter-group-name temp-paramg \
 --db-parameter-group-family ${parameter_group_family} \
 --description default.${parameter_group_family}_tmp

# txt 形式で出力
$ aws rds describe-db-parameters \
 --db-parameter-group-name temp-paramg \
 --query "Parameters[].[ParameterName,ParameterValue]" \
 --output text > default-${parameter_group_family}.txt

# 出力確認
$ cat default-mysql8.0.txt | head -3
activate_all_roles_on_login	0
allow-suspicious-udfs	None
autocommit	None

# 後始末 <<<<<<<<<< 実施を忘れないこと
$ aws rds delete-db-parameter-group --db-parameter-group-name temp-paramg
```

## 差分把握

diff ツールを使って差分把握する

```
$ vimdiff default-mysql8.0.txt DB_INSTANCE_NAME_X.txt
```

![diff_5_8_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31223/e1948d08-8856-c782-2edc-8e228950a5ac.png)



# 参考

https://docs.aws.amazon.com/cli/latest/reference/rds/describe-db-instances.html
Aiscriptの実行環境を5分でつくる

# 概要
GitHubのCodeSpacesを使用して、Aiscirptの環境が爆速で構築できたので共有します。

## GitHubのアカウントを作成する
次のサイトにアクセスし、アカウントを作成します。

https://github.com/

## Aiscript公式リポジトリをforkする
1. 次のサイトにアクセスします
    https://github.com/aiscript-dev/aiscript
1. 「Fork」を押下します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/91b010ca-cbde-e4d2-80e9-04c91277ad00.png)
1. 下図の通り、Forkできたことを確認します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/fb547c5a-95de-0cae-ae96-3ba9e6bdf6a3.png)

## GitHubCodeSpacesを使って環境構築
2. Forkしたリポジトリから「<>Code」を押下します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/e58b5a99-3faa-1721-1daf-830806682c22.png)

2. 「Codespaces」タブを選択し、「Create codespace on master」を押下します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/7724f858-b8b7-0245-a912-62e28a8cd039.png)

2. タブが遷移し、VScodeライクな画面が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/ae5d1e78-e4cb-3a15-00f9-f2527edd3c38.png)

2. 「ターミナル」にて`npm install`を実行します
2. 「ターミナル」にて`npm run build`を実行します

ここまでエラーなく終了できれば、環境構築は終了です。

## 動作確認
3. 「ターミナル」にて`node console`を実行します
3. 下図のような対話画面になったことを確認します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/52508729-7be7-96d9-351f-c90837d0a997.png)
3. ハロワでもしてみましょうか `print("Hello World!!")`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/e2679b02-2fb1-e2b7-f8d6-d00cb5764ab0.png)
上手くいきましたね。

対話型ではなく、作成したスクリプトを実行したい場合は次のように実施します
1, 同じディレクトリ内にスクリプトファイルを作成します。
　例として`test.is`を作成します。
 ```test.is
 let string_value = "hello world"
 <: string_value
 ```
2, 「ターミナル」にて`npm start test.is`を実行します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3761830/4e42a4cf-43aa-b003-846c-52fb8e009c4d.png)

上手くいきましたね。
Microsoft Plannerの雰囲気だけを説明する（1分で読める）

# はじめに
今日、Microsoft Plannerというアプリがあることを初めて知ったので、とりあえず触ってみて、どんなアプリか超ざっくり理解しました。

なので、記事にしてみなさんにも共有しておきます（というか、自分の覚え書きです）。

## この記事の対象者
- Microsoft Plannerを聞いたことがない人
- Microsoft Plannerの雰囲気だけ知りたい人

## Microsoft Plannerとは
Microsoft Planner は、直感的で共同作業可能なタスク管理ツールであり、ユーザーはタスクカードを使用してかんばんボードのタスクを割り当て、管理します。

https://learn.microsoft.com/ja-jp/office365/servicedescriptions/project-online-service-description/microsoft-planner-service-description

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/370fba0e-10ae-fa0b-c2e0-036c78b68a39.png)

# 超ざっくり説明
チームのタスクをかんばんボードで管理するツールです。**Trelloです。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/8b9ce9bb-00e6-cc20-5999-17c3b32c07a5.png)

## 構成
プラン > バケット > タスク > チェックリストという階層構造で管理する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/932e194c-a1a7-7e46-5677-7ea75090807e.png)

タスクの中にはこんな感じの情報を入れられる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/062fb868-3f1f-d93d-0168-3ce59ee38580.png)

## ボードの見方（グループ化）
色んな括りでグループ化して表示できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/5e62a221-fbae-f305-a855-5b2779562377.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/fefb6580-2dd4-136f-430b-37d116c1280f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/fdc3d918-9c85-c971-7a6f-e902fb775f9b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/cfe51943-1ca6-75a5-1a52-1613cc5c28a8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/298c157a-441f-1977-8555-6c17b0ca1281.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/0670d6bb-517d-e256-407c-2276ae820b14.png)


## ボード以外の見方
かんばんボード以外でこんな表示もできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/2ee68449-2228-695f-65e8-167e89e983d3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/b187b7fa-27b5-3ed1-0cdd-4c9e25b52cfd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713212/326ba977-3314-6f0a-6c85-07696591b951.png)

# Microsoft Plannerを詳しく知りたい人へ
この人の説明がすごく分かりやすかったです。Udemyセールの時に買ってみてください。
基本機能の話は2時間で終わります。（その後にPowerAutomateとの連携の話が続きます）

https://www.udemy.com/share/105ZIQ3@XxTWr-sK1NITlkH3Nmsd8_2ei7qCKODQBkQcUUr5ApBI8upmWSkz5IYTD4cqb6FG7Q==/

# まとめ
Microsoft365を契約していても、Microsoft Plannerを知らない人は多いと思うので、とりあえずどんなアプリなのか？という概要だけを記事にしてみました。

Microsoft365を契約していれば、Microsoft Plannerは無料だし、Teamsの中に組み込んで気軽に使えるので、僕はひとまずチームのやることメモとして使ってみようと思います。

:::note info
記事を書いた後に気付いたのですが、今年中にMicrosoft Plannerが新しくなるみたいで、Premium Planを契約すれば、ガントチャートも使えるようになるみたいです👇
:::
https://techcommunity.microsoft.com/t5/planner-blog/the-new-microsoft-planner-a-unified-experience-bringing-together/ba-p/3977998
【VSCode】Goのテストで事前に環境変数をセットする

# はじめに
VSCodeのエディタ上からGoのテストを行う際に、事前に環境変数をセットする方法を共有します。

例えば、以下のようなテストコードを想定します。
```go
func TestEnvVar(t *testing.T) {
	// 環境変数から値を取得
	envVar := os.Getenv("MY_ENV_VAR")

	// 環境変数が設定されているかをチェック
	if envVar == "" {
		t.Error("Environment variable MY_ENV_VAR is not set")
	} else {
		fmt.Printf("MY_ENV_VAR value: %s\n", envVar)
	}
}
```
環境変数を取得し、値がセットされているかを確認するコードです。しかしながら、VSCodeの`run test`からテストを実行すると、環境変数がテスト実行時に存在しないため、このテストは失敗します。

本来であれば、以下のように環境変数がセットされた状態でテストが実行されてほしいです。
```bash
MY_ENV_VAR="helloworld" go test
```

# 解決策
VSCodeの設定ファイル`settings.json`に以下のように環境変数を記述することで解決されます。
```json
{
  "go.testEnvVars": {
    "MY_ENV_VAR": "helloworld"
  }
}
```

この設定により、`go test`実行時に`MY_ENV_VAR`環境変数が`helloworld`という値でセットされます。

また、`.env`ファイルなどのファイルから環境変数をセットしたい場合は、次のように記述します。

```json
{
  "go.testEnvFile": "${workspaceFolder}/.env"
}
```
この設定により、現在のワークスペースの`.env`ファイルから環境変数が読み込まれます。

# 参考

https://stackoverflow.com/questions/70254196/is-there-a-best-practice-to-setup-golang-unit-test-parameters
それ，numpy で書かない？--9--

それ，numpy で書かない？--9--

ただでさえ遅い選択ソート。
**リストでやると Numpy ndarray でやるより 100 倍以上遅い**。argmin を使って余計な for ループも使わずに済む。


```python
import random

# random.randint(1, 9)で1〜9の数値を生成、for文で80000回実行
numbers = [random.randint(1, 9) for _ in range(80000)]
```


```python
from time import time
def select_sort(data: list[int]) -> list[int]:
    len_data = len(data) # 配列の長さ
    for i in range(len_data): # リストの各位置に対して最小値を見つけ、その位置と交換するため
        min_index = i # 初期値
        for j in range(i + 1, len_data): # iより後ろの要素の中から最小値を見つけるため
            if data[j] < data[min_index]:
                min_index = j
        data[i], data[min_index] = data[min_index], data[i]

data = numbers.copy()
s = time()
select_sort(data)
print(time() - s)
```

    80.99239301681519



```python
import numpy as np

def selection_sort(arr):
    for i in range(len(arr)):
        min_idx = np.argmin(arr[i:])
        arr[i], arr[i+min_idx] = arr[i+min_idx], arr[i]

data2 = np.array(numbers.copy())
s = time()
selection_sort(data2)
print(time() - s)
```

    0.7172000408172607
型アサーションの回避と型安全性の向上: GraphQLとReactでuseFragmentを利用する

# はじめに
フロントエンド開発でGraphQLを使っているプロジェクトは多いと思いますが、以前はFragmentで定義された部分の型定義の方法がわからず、型アサーションを使用して無理やり型定義していました。しかし、GraphQLにはuseFragmentという機能があり、これを使うことで、型アサーションを用いるよりもずっと型安全にデータの型を定義できます。なので今回はuseFragmentについて記述していきます。

# そもそもuseFragmentとは
useFragmentは、Reactアプリケーション内でGraphQLフラグメントを効果的に利用するためのhookです。
そもそもGraphQLのFragmentとは、クエリ内で再利用可能なデータの塊を定義するための機能で、コードの重複を避け、データ要求をより明確に管理するのに役立ちます。難しいこと書いてるけど要は**共通化**ということです。
Fragmentを使用すると、異なるQueryやMutation間で同じデータ構造を要求する際に、その定義を一箇所にまとめることができ、結果としてアプリケーション全体での一貫性とメンテナンス性が向上します。

useFragmentを使用すると、Fragmentを通じて取得したデータをコンポーネント内で直接利用でき、TypeScriptと組み合わせることで、取得したデータの型を正確に推測し、型安全性を高めることができます。これにより、型アサーションに頼る必要がなくなります。

# なぜ型アサーションがよくないのか
型アサーションは、型システムの一部を一時的にオーバーライドする方法です。TypeScriptのような静的型付け言語では、型アサーションを使用して、ある変数が特定の型を持つと「断言」することができます。これは一見便利に思えますが、実際には型安全性を損ね、エラーを見逃す原因となることがあります。

### 型アサーションの問題点
例えば下記のようなコードがあったとします。

```typescript 
// GraphQLから取得したデータ
const userData = fetchUserData() as User;

// User型のオブジェクトとしてuserDataを扱う
// nameなんてfieldないのにコンパイル時にはエラーが出ないので気付けない
console.log(userData.name);
```

ここでfetchUserData関数が返すデータの型がUserと完全に一致しない場合、ランタイムでエラーが発生する可能性があります。しかし、型アサーションを使用することで、コンパイル時にはエラーが発生しないため、問題が見過ごされることになります。つまり、全く型が保証されていないということです。

型アサーションのもう一つの問題は、コードの可読性と保守性に影響を及ぼすことです。型アサーションを多用することで、実際の型と想定する型の間に齟齬が生じ、後からコードを読む人が混乱する原因となります。

### useFragmentを使うことの利点
useFragmentを使用する場合、GraphQLのフラグメントを通じてデータを取得し、その型を自動的に推論させることができます。これにより、型アサーションを避け、より型安全な方法でデータを扱うことが可能になります。以下はuseFragmentを使用した場合の例です。

```typescript
import { graphql, useFragment } from 'react-relay';

const userDataFragment = graphql`
  fragment UserData on User {
    name
    email
  }
`;

function UserProfile({ userDataRef }) {
  const userData = useFragment(userDataFragment, userDataRef);

  // userDataはUser型として正しく推論される
  console.log(userData.name, userData.email);
}
```
このように、useFragmentを使用することで、Fragmentの型を正確に推論し、型アサーションに頼ることなくデータを安全に扱うことができます。

# 最後に
型は優しくて丁寧に安全に定義しよう。
【備忘録】GitHubのOAuth認証を使って取得したアクセストークンでGitHub APIを叩く

# はじめに
この記事は **GitHub** の **OAuth認証** を用いて **GitHub REST API** で使える **アクセストークン** を取得する方法の備忘録です。

## Client ID と Client secrets を準備する
**OAuth認証** を利用するために必要な **Client ID** と 
**アクセストークン発行** に必要な **Client secrets** を取得します。

https://github.com/settings/applications/new

・**Application name** には **任意のアプリ名** を
・**Homepage URL** には **ホームページのURL** を
・**Authorization callback URL** には **認証ボタンをクリックした後に飛ばしたいURL** を
それぞれ入力します。

**Application name** と **Homepage URL** はなんでも良いと思います。

![OAuth_secret_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/9f4fdce2-c858-c916-aac0-6a435399a319.png)

・**Generate a new client secret** をクリックして **Client secret** を **生成** します。
・**Client secret** と **Client ID** をそれぞれ **メモ** しておきます。

## OAuth認証を使って code を取得する
アクセストークンを取得するまでの大まかな流れは

**1**.**GitHub認証ページ** の **GitHub認証** のボタンを **クリック** する。
**2**.設定した**Authorization callback URL** にくっついた **code** を取得する。
**3**.**code** を **Client ID** と **Client secrets** と共に **POST** する。
**4**.**POST** からの **レスポンス** に **アクセストークン** が詰まっている。

この流れのうち **1~2** の **code取得** までを **実装** していきます。

```html:index.html
<body>
    <a href="https://github.com/login/oauth/authorize?client_id=fc9dd0d1d25d185df5e8">GitHub認証ページへ遷移</a>
</body>
```
このように
**https\://github.com/login/oauth/authorize?client_id=${Client ID}** 
という **リンク** にユーザをアクセスさせます。
**${Client ID}** は **メモしたClient ID** を使います。

![OAuth_authBtn_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/452e997b-2c82-319d-bf86-819dcaaf3f1d.png)

ユーザは このようなページにアクセスします。
これは **GitHub認証ページ** なので **GitHub認証ボタン** を **クリック** します。

![OAuth_url_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/5f7b93cc-b386-e2cb-148f-31cbfe10d6b3.png)

**GitHub認証ボタン** を **クリック** すると 
設定した **Authorization callback URL** に **code** がくっついたURLに **リダイレクト** されます。

ここまでが **code取得** の流れです。

## 取得したcodeを使ってアクセストークンを取得する
**アクセストークン** は
**code** と **Client ID** と **Client secrets** を
**https\://github.com/login/oauth/access_token** に **POST** することで取得出来ます。

実装例を **Thunder Client** で示しますが、**POST送信** できればなんでも良いです。

・**リクエスト側**
![OAuth_post_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/ffc87bbf-7322-dcd1-d72b-148f44b74138.png)

・**レスポンス側**
![OAuth_response_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/8058e542-83f3-c29c-3bc0-af0c34abe089.png)


このようにして **アクセストークン** を取得します。

## 取得したアクセストークンを使ってGitHub APIを叩く
こちらも実装例を **Thunder Client** で示します。

・**リクエスト側**
![OAuth_GitHubRESTAPI_red.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/c3c0b40d-d999-0aee-0a1c-98dad847ab7a.png)

・**レスポンス側**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/8c637561-e8c4-d12e-922a-fc2dbb5c8988.png)

このようにして **GitHub API** を叩けます。

叩いたAPIの詳細はこちらです。

https://docs.github.com/ja/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-the-authenticated-user

認証時に **scope** を指定することで叩けるAPIが **増えたり** 追加で **データが返されたり** します。

指定する **scope** については こちらをご覧ください。

https://qiita.com/KEINOS/items/216d138b0fdf994b9582
VPNってどれが使いやすいの

VPNについて


○vpnってなんなの
→専用線を使った通信ぽいことをインターネットでやる。
https://network.yamaha.com/knowledge/vpn
https://www.techtarget.com/searchnetworking/definition/virtual-private-network
https://www.nttpc.co.jp/column/network/whats_vpn.html


○どんな種類があるの？(エントリーVPN、ip-vpn、広域イーサネットはここでは触れない)
LAN間接続、リモート接続方式がある
https://network.yamaha.com/knowledge/vpn/protocol
https://it-trend.jp/vpn/article/48-0067
https://www.itmanage.co.jp/column/vpn-setting-method-type/

○どのレイヤで暗号化するのか？
→レイヤ3かレイヤ5でトンネルする
https://wa3.i-3-i.info/word1539.html

○どんな方式で暗号化するの？
→主にipsec
　sslvpn


○どんなプロトコルがある？
→openvpn
 ike
 l2tp
 sstp
 pptp
 

○どんな接続方式があるの？どうやって暗号化するの
•拠点間接続（LAN間接続）
Ipsecの特徴
　→安全性が高い。IKEやESPプロトコルを使う。
　ESPは暗号化を行うプロトコル。ikeは暗号化に必要な鍵を管理する。
　lan間接続でike(v1とv2があるプロトコル)という鍵情報を使って暗号と複合を行う。共通鍵と呼ばれる。暗号と認証はフェーズによって色々使う。
　ESPは暗号化と複合を行うプロトコル。暗号化と複合をikeの鍵を使う。ikeは共通鍵、espは暗号化ということかな。
PPTPの特徴
　→ipsecと同じようなもんだけど安全性がipsecより低い。

•リモート接続　L2TP/IPsec、ssl-vpnなど
→L2TP/IPsec
　ssl-vpn ブラウザがあれば気軽に導入可能。Fortigateでは専用クライアントソフト使っていたけど機器によるのかな？
https://www.nttpc.co.jp/column/network/whats_vpn.html


○vpnの通信速度って遅いの？
わからない

○通信速度もまあまあで実用的なやつはどれ？
売れてる物でVPN機能ついてるならいいんじゃない！ipsec-VPNの方が安全！
中小規模ならヤマハとかFortigate
大規模ならIPCOMとかCisco
https://www.lrm.jp/security_magazine/ipsec_vpn/#:~:text=%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AA%E9%81%95%E3%81%84%E3%81%AF%E3%80%8C%20%E5%8B%95%E4%BD%9C%E3%81%99%E3%82%8B%E9%9A%8E%E5%B1%A4%20%E3%80%8D%E3%81%A8%E3%80%8C%20%E5%AE%89%E5%85%A8%E6%80%A7%20%E3%80%8D%E3%81%A7%E3%81%99%E3%80%82,IPSec-VPN%E3%81%AFOSI7%E9%9A%8E%E5%B1%A4%E3%81%AE%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E5%B1%A4%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%99%E3%82%8B%E3%81%AE%E3%81%AB%E5%AF%BE%E3%81%97%E3%80%81%20SSL-VPN%E3%81%AF%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E5%B1%A4%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%97%E3%81%BE%E3%81%99%20%E3%80%82%20%E5%8B%95%E4%BD%9C%E3%81%99%E3%82%8B%E9%9A%8E%E5%B1%A4%E3%81%8C%E6%B7%B1%E3%81%84%E3%81%BB%E3%81%A9%E3%80%81%E5%AE%89%E5%85%A8%E6%80%A7%E3%81%8C%E9%AB%98%E3%81%8F%E3%80%81%E5%BA%83%E3%81%84%E7%AF%84%E5%9B%B2%E3%81%AE%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%A7%E5%8B%95%E4%BD%9C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%9F%E3%82%81%E3%80%81%20IPSec-VPN%E3%81%AE%E3%81%BB%E3%81%86%E3%81%8C%E3%82%88%E3%82%8A%E5%AE%9F%E7%94%A8%E6%80%A7%E3%81%8C%E9%AB%98%E3%81%84%E3%81%A8%E3%81%84%E3%81%88%E3%82%8B%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%20%E3%80%82
https://news.mynavi.jp/siryou_hikaku/20201012-1368928/

○スループットとは
https://wa3.i-3-i.info/word12830.html
https://ramunememo.hatenablog.com/entry/2022/09/29/221639


〇その他
VPNパススルー。VPNで使うプロトコルがNATで止めるのを防ぐ。NAT設定でVPNに使っているプロトコルもpassするように書くのな？
https://network.yamaha.com/setting/router_firewall/vpn/connect/ipsec_pass_through-rtx_gui
LAN間接続とかする時に書くっぽいな
>ip filter 1040 pass * 192.168.0.1 udp * 500 # 注釈1
ip filter 1041 pass * 192.168.0.1 esp # 注釈1


https://business.ntt-east.co.jp/service/vpnwide/column/vpn_pass_through_connection5/index.html
#7 画像、テキスト、絵文字、枠線＆角丸を使用してカードを作成する

UIKitを使ったiOSアプリ開発では、画像、テキスト、絵文字、枠線、そして角の丸みを利用して、魅力的なカードを作成することができます。今回は、近所の道路を縄張りにする猫を主役に選び、この猫にピッタリのラベルを添えることにしました。直立したテキストがこの画像に最適だと考えたため、複数のラベルを使い、背景と組み合わせてダイアログボックスの雰囲気を出しました。

ステップ1: 画像ビューの作成
UIImage(named:)メソッドを使用して画像を読み込み、それをUIImageViewのインスタンスに設定します。

ステップ2: 画像ビューの外観カスタマイズ
cornerRadiusの設定とclipsToBoundsの有効化により、画像ビューに角の丸みを加えます。

ステップ3: ラベルの追加とカスタマイズ
UILabelインスタンスを作成し、そのframe、text、textColor、backgroundColor、fontを設定します。そして、cornerRadiusとmasksToBounds属性を使用して、ラベルに角の丸みを持った背景を追加します。

```swift
let textLabel = UILabel(frame: CGRect(x: 30, y: 20, width: 50, height: 50))
textLabel.text = "留"
textLabel.textColor = .white
textLabel.backgroundColor = .darkGray
textLabel.layer.cornerRadius = 10
textLabel.layer.masksToBounds = true
textLabel.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel)

let textLabel1 = UILabel(frame: CGRect(x: 30, y: 80, width: 50, height: 50))
textLabel1.text = "下"
textLabel1.textColor = .white
textLabel1.backgroundColor = .darkGray
textLabel1.layer.cornerRadius = 10
textLabel1.layer.masksToBounds = true
textLabel1.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel1)

let textLabel2 = UILabel(frame: CGRect(x: 30, y: 140, width: 50, height: 50))
textLabel2.text = "買"
textLabel2.textColor = .white
textLabel2.backgroundColor = .darkGray
textLabel2.layer.cornerRadius = 10
textLabel2.layer.masksToBounds = true
textLabel2.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel2)

let textLabel3 = UILabel(frame: CGRect(x: 30, y: 200, width: 50, height: 50))
textLabel3.text = "路"
textLabel3.textColor = .white
textLabel3.backgroundColor = .darkGray
textLabel3.layer.cornerRadius = 10
textLabel3.layer.masksToBounds = true
textLabel3.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel3)

let textLabel4 = UILabel(frame: CGRect(x: 30, y: 260, width: 50, height: 50))
textLabel4.text = "財"
textLabel4.textColor = .white
textLabel4.backgroundColor = .darkGray
textLabel4.layer.cornerRadius = 10
textLabel4.layer.masksToBounds = true
textLabel4.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel4)

let textLabel5 = UILabel(frame: CGRect(x: 30, y: 320, width: 50, height: 50))
textLabel5.text = "❗️"
textLabel5.backgroundColor = .darkGray
textLabel5.layer.cornerRadius = 10
textLabel5.layer.masksToBounds = true
textLabel5.font = UIFont.systemFont(ofSize: 50)
catImageView.addSubview(textLabel5)
```
成果

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3703986/70fff2d5-8353-d9c9-5e25-7c8e70dbc5e1.png)
pymongoの[SSL: CERTIFICATE_VERIFY_FAILED]を解決する

## エラー概要
FastAPIとMongoDBを接続しようとしたところ、以下のエラーが出ました。

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:1129)

SSL証明書の検証に失敗し、その結果としてMongoDBサーバーへの接続がタイムアウトしていました。

## 対処法
certifiをインストールし、AsyncIOMotorClientの第二引数にtlsCAFile=certifi.where()を渡します。
```
pip install certifi
```
```
client = motor.motor_asyncio.AsyncIOMotorClient('mongodb+srv://<user>:<password>@fastapi.eaqzx3y.mongodb.net/?retryWrites=true&w=majority&appName=<appnName>', tlsCAFile=certifi.where())
```

## 備考
証明書の期限切れでも同様のエラーが発生するようです。
筆者の場合は期限切れによるエラーではなかったのでcertifiを使い、PythonでSSL証明書の信頼性を検証するようにしました。
[Atcoder備忘録記事]AtCoder Beginner Contest 338 C問題

[AtCoder Beginner Contest 338 C問題](https://atcoder.jp/contests/abc338/tasks/abc338_c "Atcoder ")
こちらの問題です。

# 問題
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2374978/3bf2043a-9da8-f360-8cb6-09e6d5ba9928.png)

# 入出力例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2374978/f73316c8-b31a-0d0f-829e-6164a3bf99a0.png)

# 解法
片方の個数を決めてしまえばもう片方の個数も自動的に決まる性質を利用します。
Q,A,BがNの長さ分あるのでその中から最小を見つけたりといった部分が少し複雑で難しく感じました。
この手の問題にもなれなければいけませんね。

```
#include <iostream>
#include <vector>
#include <string>
#include <unordered_set>
#include <cmath> 
#include <algorithm>
using namespace std;

int main() {
    int N;
    int ans = 0;
    cin >> N;
    vector<int> Q(N);
    vector<int> A(N);
    vector<int> B(N);
    for(int i = 0; i < N; i++) cin >> Q[i];
    for(int i = 0; i < N; i++) cin >> A[i];
    for(int i = 0; i < N; i++) cin >> B[i];

//iの個数は確定しないので、無限ループで回す。
    for(int i = 0;; i++){
    //最小値の変数。とりあえずでかい値をいれておく
        int y = 10000000;
        //Q配列からAの数分材料を引いたときの残り
        vector<int> R(N);
        bool ok = true;
        //残りをR配列に格納。
        for(int j = 0; j < N; j++) R[j] = Q[j] - A[j] * i;
        //どれか一つでも0をしたまわったらループ離脱(その時点で考え得るAの個数は回し切っているはず)
        for(int j = 0; j < N; j++) if(R[j] < 0) ok = false;
        if(!ok) break;
        //Bの個数を考える。
        for(int j = 0; j < N; j++){
        //0の部分は考慮しない。
            if(B[j] == 0) continue;
            //Bの最小値を考える。
            y = min(y,R[j]/B[j]); 
        }
        //回答の更新
        ans = max(ans,i+y);
    }

    cout << ans << endl;
    return 0;
}

```