OmniAICreator/Qiita-1.07M huggingface dataset:
コピペで始める ComfyUI 導入

# はじめに

当方、長らく Stable Diffusion Web UI のお世話になっていたのですが、 ComfyUI のビジュアルがイケ過ぎているので、唐突に乗り換えてみたい気持ちに駆られた昨今。
乗り換えに際して、環境構築した時の手順を此処に残しておきます。
これから導入しようとしている各位の参考になれば幸いです。

# 想定読者

* ComfyUI を Linux に導入したい人
* 未来の自分

# 環境変数とか

この後のコピペコードで参照するので、環境変数に便利な変数入れておく。
ComfyUI を導入したい作業ディレクトリに移動して、以下のコマンドを実行。

```bash
export WORK_ROOT=${PWD}
```

# ComfyUI の導入

まずは本体を導入

```bash
cd ${WORK_ROOT}
git clone https://github.com/comfyanonymous/ComfyUI
cd ComfyUI
pip install xformers!=0.0.18 -r requirements.txt --extra-index-url https://download.pytorch.org/whl/cu118 --extra-index-url https://download.pytorch.org/whl/cu117
cd custom_nodes
git clone https://github.com/ltdrdata/ComfyUI-Manager
cd ComfyUI-Manager
pip install -r requirements.txt
pip install torchvision
```

# モデルの導入

お好きなモデルを入れましょう。

## Sudachi

2Dぽい絵を描こう

```bash
cd ${WORK_ROOT}
wget -c "https://civitai.com/api/download/models/92024?type=Model&format=SafeTensor&size=pruned&fp=fp16" -O ./ComfyUI/models/checkpoints/sudachi_v10.safetensors
```

## Hassaku

アニメ絵を描こう

```bash
cd ${WORK_ROOT}
wget -c "https://civitai.com/api/download/models/106922?type=Model&format=SafeTensor&size=pruned&fp=fp16" -O ./ComfyUI/models/checkpoints/hassaku_v13.safetensors
```

## VAE

```bash
cd ${WORK_ROOT}
wget -c https://huggingface.co/stabilityai/sd-vae-ft-mse-original/resolve/main/vae-ft-mse-840000-ema-pruned.safetensors -P ./ComfyUI/models/vae/
```

## ControlNet

構図を決めよう

```bash
cd ${WORK_ROOT}
wget -c https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_lineart.pth -P ./ComfyUI/models/controlnet/
wget -c https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11p_sd15_openpose.pth -P ./ComfyUI/models/controlnet/
wget -c https://huggingface.co/lllyasviel/ControlNet-v1-1/resolve/main/control_v11f1p_sd15_depth.pth -P ./ComfyUI/models/controlnet/
```

## ESRGAN upscale model

良い感じにアップスケールしよう

```bash
cd ${WORK_ROOT}
wget -c https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.5.0/realesr-animevideov3.pth -P ./ComfyUI/models/upscale_models/
wget -c https://huggingface.co/ai-forever/Real-ESRGAN/resolve/main/RealESRGAN_x2.pth -P ./ComfyUI/models/upscale_models/
```

# ComfyUI の起動

ComfyUI の起動方法

```bash
cd ${WORK_ROOT}
python ./ComfyUI/main.py
```

# その他

## AnimeDiff の準備

### AnimateDiff for ComfyUI の導入

```bash
cd ${WORK_ROOT}/ComfyUI/custom_nodes
git clone https://github.com/Kosinkadink/ComfyUI-AnimateDiff-Evolved.git
```

### AnimeDiff 用モデルの導入

```bash
cd ${WORK_ROOT}/ComfyUI/custom_nodes/ComfyUI-AnimateDiff-Evolved/
wget -c https://huggingface.co/guoyww/animatediff/resolve/main/mm_sd_v14.ckpt  -P ./models/
```

## VideoHelperSuite の導入

```bash
cd ${WORK_ROOT}/ComfyUI/custom_nodes
git clone https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite.git
cd ${WORK_ROOT}/ComfyUI/custom_nodes/ComfyUI-VideoHelperSuite/
pip install opencv-python-headless
pip install -r requirements.txt
```

# おわりに

ComfyUI、とっても便利。
Ubuntu でpnpm installできない。

# error
```
 WARN  GET https://registry.npmjs.org/@babel%2Fcore error (ERR_SOCKET_TIMEOUT). Will retry in 10 seconds. 2 retries left.
 ...
 ```
# 対応
## TerminalにてIPv６を無効化。
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1
Dockerについて

### 初めに
業務中にRancherDesktop(DockerDesktopの互換品)を使用しているが、あまりイメージがついていないまま使用していたため、改めて自己理解を深める目的で記事を作成します。

### 一言で言うとDockerとは
・Dockerとは仮想環境を提供するソフトウェアのこと
・Docker Desktopとは、WindowsやMacOS上でDockerを簡単に利用できるようにするためのツールのこと
→WindowsやMacOS上ではDockerを使用するために、DockerDesktopをインストールすることが推奨されている。

### なぜDockerを使うのか
Dockerを使う理由は、簡単に仮想環境をセッティングすることができるからです。
例えば複数人で開発を行っている場合、各々のPCでphpやApache、DBのバージョンの差異が生まれないようにしないといけません。そうしないと検証環境や本番に環境に移行する際に、上手く動作しない可能性があるからです。その際に誰のPCにも同じ環境を整える必要がありますが、そこで仮想環境を整える必要があるのです。そしてその仮想環境を簡単に作ることができるのがDockerです。

### Dockerfileとdocker-compose.yml
Dockerイメージを手に入れるにはDockerHubから入手することができますが、DockerHubに欲しいイメージがない場合(OSやバージョンなど)は、Dockerfileを作成し自分でイメージを作成することができます。
また仮想環境を使用する際は、phpやApache、DBなどのイメージからコンテナを作成・起動したり停止したりしますが、複数のイメージやコンテナを同時に操作するためにdocker-compose.ymlを作成します。docker-compose.ymlに複数のイメージの情報を記載することで一度にコンテナの立ち上げや停止が可能です。

### まとめ
・Dockerとは仮想環境を簡単に作成できるツール
・Dockerを使用するためにwindowsやMacではDockerDesktopやRancherDesktopをインストールする
・Dockerfileとは自分で任意のイメージを作るファイル
・docker-compose.ymlとは複数のイメージを一元管理するためのファイル


[参考サイト]
・https://youtu.be/VIzLh4BgKck
・https://knowledge.sakura.ad.jp/13265/
AlarmClockクラスのリファレンスがぺらぺらすぎるので補いたい

**AlarmClockクラス**はAndroidアプリケーションでアラームをセットするための便利なクラスです。特に、アラームを解除する際に使用する`ACTION_DISMISS_ALARM`アクションについて、具体的な実装例をご紹介します。

以下は、指定されたラベルに基づいてアラームを解除するKotlinの関数です。

```kotlin
/**
 * 指定されたラベルのアラームを解除します。
 *
 * @param context コンテキスト
 * @param label アラームのラベル
 */
fun dismissAlarmByLabel(context: Context, label: String) {
    val intent = Intent(AlarmClock.ACTION_DISMISS_ALARM).apply {
        setPackage(alarmPackageName) // アラームアプリのパッケージ名を指定
        putExtra(AlarmClock.EXTRA_ALARM_SEARCH_MODE, AlarmClock.ALARM_SEARCH_MODE_LABEL) // 完全一致検索モードしか選べない
        putExtra(AlarmClock.EXTRA_MESSAGE, label) // アラーム検索に使用するフレーズを指定
        putExtra(AlarmClock.EXTRA_SKIP_UI, true) // UIをスキップするオプションを指定
    }
    context.startActivity(intent)
}
```

この関数は、指定されたラベルのアラームを解除する際に使用できます。`setPackage`メソッドでアラームアプリのパッケージ名を指定し、`putExtra`メソッドで検索モードやラベルを設定しています。UIを表示せずにアラームを解除するために、`EXTRA_SKIP_UI`オプションを設定しています。


(1) AlarmClockクラスを使用してアラームをセットする | TechBooster. https://techbooster.org/android/2271/.
(2) java - Android AlarmClock search by label - Stack Overflow. https://stackoverflow.com/questions/42233249/android-alarmclock-search-by-label.
(3) AlarmClock | Android Developers. https://developer.android.com/reference/android/provider/AlarmClock.
【備忘録】Circleの通知をslackに送るためのリサーチ

## 【備忘録】Circleの通知をslackに送るためのリサーチ

### 背景

コミュニティ管理プラットフォーム[Circle](https://circle.so/ "Circle")を使用している中で、ウェブベースのためリアルタイムでの通知が届かず、コミュニティの活動が盛り上がりにくいという課題が浮上しました。
この問題を解決するために、サークル内の通知をより一般的に使用されているプラットフォーム、例えばSlackやLINEなどに転送する方法を模索しました。

### 試みた解決策

1. **Zapierを介した連携の試み**  
   最初にZapierを利用した連携を試みましたが、CircleのAPIに制限が多く、特定のポストへのコメントをターゲットにする必要がありました。これはコミュニティが成長するにつれて、設定の更新が頻繁に必要となり、管理が煩雑になるという問題があります

2. **Gmail通知をSlack/LINEに転送する方法**  
   次に、Gmailに届くコミュニティの通知をSlackやLINEに自動転送する方法を検討しました。これは有効な解決策でしたが、一般ユーザーのメールアドレスを連携する必要があり、認証の手続きが複雑であること、オンボーディングの際の説明負担が大きいことが課題でした。結果として、この方法は運営メンバー限定で実施し、一般ユーザーにはアプリのインストールを促して通知を確認してもらうことにしました

3. **カスタムAPIを用いた通知連携アプリの開発**  
   最後に、APIを用いてカスタムの通知連携アプリを開発することを検討しました
このアプローチでは、コミュニティ内の通知をLINEやSlackへ転送することが可能です。

しかし、リサーチの結果、サークルのAPIでは投稿やポストのコメントは取得可能ですが、フリートークやチャットスペースのような形式のコメントは取得できないことが明らかになりました。
この問題はAPIの機能制限によるものであり、APIの更新を待つ他ありません。

### 結論

解決策としては、現段階では第2の方法が最も現実的です。
つまり、運営側は通知を確実に受け取れるようにし、一般ユーザーはアプリをインストールして通知を確認するように促すことです。
将来的にサークルのAPIがアップデートされ、チャット型のコメントも取得できるようになれば、カスタムAPIを使用した通知連携アプリの開発（第3のアプローチ）への切り替えも検討可能です。

**注意事項**: 
本レポートでは具体的なAPIの詳細について言及していません。実際のAPIの仕様や機能については、[Circle公式ドキュメント](https://api.circle.so/ "Circle公式ドキュメント")またはAPI開発者ガイドを参照してください。また、本レポートで提案されている解決策の実装にあたっては、プライバシー保護やセキュリティ対策に十分注意し、関連する法規制を遵守することが重要です。


### Circle APIリクエスト一覧

#### コースレッスンの取得
- **URL**: `https://app.circle.so/api/v1/course_lessons?community_id=11111&space_id=700930&section_id=71814&status=published&page=1&per_page=10`
- **役割**: 特定のコミュニティID、スペースID、セクションIDに紐づく公開済みのコースレッスンをページ指定で取得します。

#### コミュニティ情報の取得 (1回目)
- **URL**: `https://app.circle.so/api/v1/communities`
- **役割**: 認証されたユーザーに関連するコミュニティの情報を取得します。

#### コメントの取得
- **URL**: `https://app.circle.so/api/v1/comments?community_id=75665&space_id=839962`
- **役割**: 特定のコミュニティIDとスペースIDに紐づくコメントを取得します。

#### スペース情報の取得 (活動中のもの、ページ2)
- **URL**: `https://app.circle.so/api/v1/spaces?community_id=11111&sort=active&per_page=4&page=2`
- **役割**: 特定のコミュニティIDに紐づく、活動中のスペースをページ指定で取得します。

#### 特定スペースの詳細情報の取得 (異なるスペースIDで)
- **URL**: `https://app.circle.so/api/v1/spaces/1?community_id=75665`
- **役割**: 特定のコミュニティIDに紐づく異なるスペースIDのスペースの詳細情報を取得します。

#### スペースグループの取得
- **URL**: `https://app.circle.so/api/v1/space_groups?community_id=75665`
- **役割**: 特定のコミュニティIDに紐づくスペースグループの情報を取得します。

#### コメントの取得 (スペースIDなしで)
- **URL**: `https://app.circle.so/api/v1/comments?community_id=75665`
- **役割**: 特定のコミュニティIDに紐づく全てのコメントを取得します。スペースIDが指定されていません。

#### 投稿の取得
- **URL**: `https://app.circle.so/api/v1/posts?community_id=75665&space_id=1010914`
- **役割**: 特定のコミュニティIDとスペースIDに紐づく投稿を取得します。

#### 特定スペースの詳細情報の取得 (異なるスペースIDで、再度)
- **URL**: `https://app.circle.so/api/v1/spaces/925624?community_id=75665`
- **役割**: 別のスペースIDに基づく、特定のコミュニティIDのスペースの詳細情報を取得します。
フロントエンドフレームワークについて

# はじめに

### 本記事を書いたきっかけ

今まで仕事で React、Vue.js、Angular など様々なフレームワークに触れてきました。  
ただ、それぞれのフレームワークがどのような特徴を持っているかなどは結構曖昧な部分があったなと思ったので、改めて備忘録がてらまとめてみようと思ったのがきっかけです。  
この記事では 0 章としてフロントエンドフレームワークについてを書いてみましたが、自分用のメモに近いです。  

# フロントエンドフレームワークとは

そもそもフロントエンドフレームワークとはなんぞや？と言うところですが、  
フロントエンドフレームワークとは、Web アプリケーションを開発する際の枠組みになります。  
おかげでコストが削減でき、より効率的に開発を行うことができるわけです。

## 主なフロントエンドフレームワーク

有名どころのフレームワークになりますが、ここでは本当にざっくりとした説明のみになります。  
（いくつか気になるものは細かく別記事にまとめてみようと思います。）

### React

React は、UI をコンポーネントベースで構築するための JavaScript ライブラリです。  
 The State of JS 2022 を見ると利用率は毎年 1 位のようです。

### Vue.js

Vue.js は、シンプルで柔軟な設計が特徴でフレームワークライブラリの中で特に UI 構築を得意とする JavaScript フレームワークです。

### Angular

Angular は、機能性が豊富でアプリ開発に必要な機能を網羅しています。  
また MVC（Model-View-Controller）アーキテクチャを採用しているため、アプリケーション設計がしやすいメリットがあります。

### Svelte

Svelte は、アプリケーションをビルドするための手法を提供しています。  
かつバンドルサイズやランタイムが小さいため高いパフォーマンスが期待できます。
ちなみに Svelte は UI ライブラリではなくコンパイラです。

## 比較表

| 特徴                                 | React              | Vue.js             | Angular      | Svelte             |
| ------------------------------------ | ------------------ | ------------------ | ------------ | ------------------ |
| **開発元**                           | Facebook           | Evan You           | Google       | Rich Harris        |
| **リリース**                         | 2013 年            | 2014 年            | 2010 年      | 2016 年            |
| **言語**                             | JavaScript, JSX    | JavaScript, Vue    | TypeScript   | JavaScript         |
| **アーキテクチャ**                   | コンポーネント指向 | コンポーネント指向 | MVC          | コンポーネント指向 |
| **仮想 DOM※**                        | あり               | あり               | あり         | なし               |
| **リアクティブデータバインディング** | あり               | あり               | あり         | あり               |
| **学習レベル**                       | 初級から中級       | 初級から中級       | 中級から上級 | 初級               |
| **パフォーマンス**                   | 高い               | 高い               | 中程度       | 非常に高い         |
| **コミュニティサポート**             | 大規模で活発       | 大規模で活発       | 大規模で活発 | 成長中             |

### ※仮想 DOM とは

こちらのサイトの以下がとてもわかりやすかったです。

https://www.commte.co.jp/learn-nextjs/Virtual-DOM

> あなたが建築家で、大きなビルを設計していると想像してみてください。そのビルを改装するたびに全体を壊して新しく作り直すのは、とんでもなく時間とコストがかかりますよね。そこであなたは、ビルの「模型」を作り、そこで改装の計画を試行錯誤することにしました。改装の計画が決まったら、それを元に実際のビルを改装します。  
> この例え話でいう「ビル」が実際の DOM、そして「模型」が「仮想 DOM」です。

仮想 DOM により、前回と比較してどのくらい差分があるのかを比較し、変更された部分だけを DOM に反映するためレンダリングコストが下がると言うことですね。  
実際開発する際はそこまで意識するものでもなさそうですが、あくまで理解として…

# まとめ

フロントエンドフレームワークは、Web 開発において必要不可欠なものになっていると思いますが、フレームワークによって特徴はそれぞれです。  
もちろんメリットデメリットと言うものが存在するわけですから、技術選定を行うための知識はしっかりつけておきたいなと改めて思いました。

本記事では「フロントエンドフレームワークについて」をざっっっっくりまとめただけなので、別の記事で何個か詳細をまとめたり、実際使ってみたりしたいと思います。

# 参考

https://2022.stateofjs.com/ja-JP/libraries/front-end-frameworks/

https://media.tricorn.co.jp/development/frontend/2098/

https://www.kagoya.jp/howto/it-glossary/develop/react/

https://www.kagoya.jp/howto/it-glossary/develop/vue-js/

https://www.wantedly.com/companies/company_3056942/post_articles/469989

https://www.commte.co.jp/learn-nextjs/Virtual-DOM

https://zenn.dev/aytsk_meow/articles/6a6a6688b52920
C#でアイコンファイルを保存する(手抜き)

　C#でアプリケーションを作っていて、アイコンを設定したかったが、アイコンファイルを作成するのに少し手間取った。例えばWindowsに付属するペイントや、あるいは普段使用しているpaint.netではICOファイルを保存できない。
　C#ではImage.SaveにImageFormatオプションでIconを指定できるが、この場合はPNGで保存されてしまう。

　ICOファイルは結構簡単なフォーマットらしいので、C#でICOファイルを保存してみた。

　流れとしては、外部のソフトウェア(適当なペイントソフトやドローソフト)で作成したアイコンの画像をC#で読み込み、それをICOのフォーマットに従って保存している。

```C#
static void ImagesToIcon(Image[] images, Stream dst)
{
    if (dst.Length != 0 ||
        images.Length < 1 ||
        short.MaxValue < images.Length ||
        images.Any(a => a.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        throw new InvalidOperationException();
    }

    ; void WriteInt(int x)
     => dst.Write(MemoryMarshal.Cast<int, byte>(new(ref x)));

    WriteInt(0x0001_0000);
    dst.Write(BitConverter.GetBytes((ushort)images.Length));

    dst.Write(new byte[images.Length * 16]);

    foreach (var (i, image) in images.Select((a, i) => (i, a)))
    {
        var offset = dst.Position;
        image.Save(dst, System.Drawing.Imaging.ImageFormat.Png);
        var size = dst.Position - offset;

        dst.Position = 6 + i * 16 + 8;
        WriteInt((int)size);
        WriteInt((int)offset);
        dst.Position = dst.Length;
    }
}
```

　一部のパラメーター(解像度とかビット深度とか)は0を設定している。一応動作していることを確認しているが、すべての環境で動作するとは限らない(今回は自分用に作ったツールを識別する目的なので、自分のPCで動けばOKとした)。

　ICOファイルにはいくつかのフォーマットで画像を埋め込むことができるらしいが、今回はPNGを埋め込んでいる。24bitPNGはだめらしく、32bitPNGが必要。読み込んだ画像が24bitだった場合は`using var bmp = tmp.Clone(new() { Size = tmp.Size }, PixelFormat.Format32bppArgb)`のような感じでフォーマットを変換しておく。もちろん透過を含む画像も扱える。
隣接行列の実装

この記事は以下の記事のリポストです。
https://takutori.blogspot.com/2018/04/blog-post_11.html

# Introduction
ここでは隣接行列の実装を行っていきます。Python3を使っています。OSはwindows10です。

# 実装例



```Graph_df.py
import numpy as np

class directed_Gragh():
    def __init__(self,E,V,gragh_map):
        self.edge = E;
        self.vertex = V;
        self.map = gragh_map;

    def Adjacency_matrix(self):
        adjacency_matrix = np.zeros((self.vertex.shape[0],self.vertex.shape[0]))
        for ed in self.edge:
            P_ = self.map(ed)
            start = P_[0]
            end = P_[1]
            row = np.where(self.vertex == start)
            column = np.where(self.vertex == end)
            adjacency_matrix[row,column] = 1
            adjacency_matrix[column,row] = 1
        return adjacency_matrix
```

mainファイル

```main.py

import numpy as np
from Gragh_def import directed_Gragh

def main():

    vertex = np.array(['house','station','school','hospital'])
    edge = np.array([1,2,3,4])

    def gragh_map(edge):
        if edge == 1:
            vertexs = np.array(['house','school'])
        elif edge == 2:
            vertexs = np.array(['school','station'])
        elif edge == 3:
            vertexs = np.array(['house','station'])
        else:
            vertexs = np.array(['station','hospital'])
        return vertexs

    test_gragh = directed_Gragh(edge,vertex,gragh_map)
    print('vertex is %s \n'%test_gragh.vertex)

    adjacency_matrix = test_gragh.Adjacency_matrix()

    print('adjacency_matrix = \n %s \n'%adjacency_matrix)

if __name__ == '__main__':
        main()
```

# References
https://ja.wikipedia.org/wiki/グラフ理論
ベイズの定理

この記事は以下の記事のリポストです。
https://takutori.blogspot.com/2018/04/bayes-theorem.html

# Introduction

今回はベイズの定理について書こうと思います。
ベイズの定理とは、イギリスのトーマス・ベイズによって発見された、条件付き確率に関する定理です。現在のベイズ推定で用いられる重要な定理です。どのような定理かを解説していこうと思います。

# ベイズの定理
ベイズの定理とは

確率P(B|A):事象Aが起こった後での事象Bの確率（事後確率）
確率P(B):事象Aが起こる前の事象Bの確率（事前確率）
とするとき以下が成り立つことを示しています。

$$P(B|A) = \frac{P(A|B) P(B)}{P(A)}$$

# 例
例えば、次のように事象A、事象Bwo定義します。

事象A:あるYoutuberが動画を投稿したとき、再生回数が100万回を超える
事象B:あるYoutuberがお金を50万円以上使う動画を投稿する


この時確率P(A|B)、つまり50万円以上を使った動画が再生回数100万回を超える確率は、youtube内の50万円以上使っている動画を根こそぎ集め、その再生回数を得ることによって推定できそうです。では確率P(A|B)がわかった時、確率P(B|A)もわかる。これがベイズの定理の強みです。（当然確率P(A)とP(B)がわかっている必要はあります。）

確率P(B|A)とはあるYoutuberの動画が再生回数100万回を超えたとき、その同がで50万円以上使っている確率となります。これがわかれば、100万回動画が再生される原因は本当に50万円以上お金を使うことなのかがわかります。

確率P(A|B)が低い時を考えてみましょう。
つまり、50万円以上使った動画は再生回数100万回を超える確率は高い。しかし、100万回再生回数を突破したとき、その動画が50万円以上使っている可能性は低い。この状況はベイズの定理の式を考えいると理解しやすいです。

ベイズの定理の式を見てみると、P(B|A)は低く、P(A|B)が高いということは、確率P(A)が著しく高い。もしくは、P(B)が著しく低い。この二つがあげられます。

つまり、あるYouruberが100万回再生を突破する確率がかなり、高い。もしくは、あるYoutuberが50万円以上使う動画を投稿すｒ確率がかなり、低い。このどちらかが考えられます。P(A)が高いとき、そのYouruberが単に大人気なのであって、動画の再生回数が100万回を超える原因が50万円以上お金を使ったことにあるとは限りません。また、P(B)が低いとき、つまり、50万円以上お金を使った動画が少ないときは、たまたま、100万円を超えただけで、本当の原因が50万円以上使ったことにあるとは限りません。

このようにベイズの定理では、結果から原因を推定する力があります。

# 式の導出
最後にベイズの定理の式を導出しようと思います。まず条件付き確率の式を確認します。ある事象Bが起こった時、事象Aが起こっている確率（条件付き確率）は
$$P(A|B) = \frac{P(A,B)}{P(B)}$$
ただし、P(A,B)はAとBの同時確率を表します。
この式をベイズの定理の式の右辺に代入します。
$$\frac{P(A|B)P(B)}{P(A)} = \frac{\frac{(P(A,B)}{P(B)} P(B)}{P(A)} = P(B|A)$$

References
https://ja.wikipedia.org/wiki/ベイズの定理
Kullback-Leibler divergence

# Introduction
今日がダイバージェンスについて書いていきます。
ちなみにエントロピーの知識を使うのでエントロピーの記事も見てあげてください。

エントロピーの記事はこちら



# Kullback-Leibler Divergence
二つの確率分布の平均エントロピーの差を表す値をKLダイバージェンスといいます。
式では次のように定義されます。

$$KL(P||Q) = \int_{-\infty}^{\infty} P(X) log \frac{P(X)}{Q(X)}$$
離散の場合は
$$KL(P||Q) = \sum_{i} P(X_i) log \frac{P(X_i)}{Q(X)}$$

なぜ二つの分布間の距離をこのように定義できるのでしょうか。

# 式の解釈
真の分布P(X)が存在するとします。しかし、有限のデータから真の分布P(X)を求めるのは難しいです。そこで、有限のデータから推定して得られた確率分布をQ(X）とします。では真の分布P(X）と推定した分布Q(X)はどれだけ違っているのでしょうか。

ここで登場するのがエントロピーです。エントロピーはその分布の不確実性を示す値でした。
エントロピーが高いほど不確かなことが起こるとゆうことです。

P(X)のエントロピーとは$-\int_{-\infty}^{\infty} logP(X)$でした。


では推定した確率分布Q(X）は確率分布P(X)に対してどれだけ不確実性を持っているのでしょうか。エントロピーとは情報量の期待値でした。確率分布Q(X）が持つ情報量は$-logQ(X)$です。この情報量を確率P(X)で期待値をとります。
式は以下のようになります。
$$-\int_{-\infty}^{\infty} P(X) logQ(X)$$
この値と真の分布のエントロピーとの差を二つの分布間の差として定義します。式では以下のようになります。
$$-\int_{-\infty}^{\infty} P(X) logQ(X) - (--\int_{-\infty}^{\infty} P(X) logP(X)))$$
これを式変形すると
$$-\int_{-\infty}^{\infty}(logQ(X)-logP(X)) =\int_{-\infty}^{\infty}(logP(X)-logQ(X)) = \int_{-\infty}^{\infty} log \frac{P(X)}{Q(X)}$$
となるわけです。


# Referece

https://ja.wikipedia.org/wiki/カルバック・ライブラー情報量
dependency-guardで依存関係をチェックする

gradleで依存するライブラリを書けば、自動的にその依存関係を解消してくれて便利なのですが、意図しないライブラリに依存してしまったり、意図せず利用ライブラリのバージョンが上がってしまったりという問題が発生してしまう場合もあります。

以下のように、実行時の依存関係をツリー表示させて、それを人力でチェックする……というのはきびしいですね。

```sh
./gradlew :app:dependencies --configuration releaseRuntimeClasspath 
```

# dependency-guard

dropboxがdependency-guardというgradle pluginを公開しており、これを使うことで簡単に依存関係の変化をチェックすることができます。

https://github.com/dropbox/dependency-guard

build.gradle.ktsのpluginsセクションにdependency-guardを記述し

```build.gradle.kts
plugins {
  id("com.dropbox.dependency-guard") version "0.5.0"
}
```

以下のようにチェックする構成を指定します。
Javaプロジェクト・ライブラリの場合 `runtimeClasspath`
Androidアプリ・ライブラリの場合 `releaseRuntimeClasspath` が対象になると思います。
Build Variantsを設定している場合はそれに合わせて構成名を変更します。

```build.gradle.kts
dependencyGuard {
    configuration("releaseRuntimeClasspath") 
}
```

こうすることで dependencyGuard / dependencyGuardBaseline のタスクが作られます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/30922086-e50a-70b5-7345-f92307cb1df7.png)

いずれかのタスクを実行すると、dependenciesディレクトリと、その中にテキストファイルが作成されます。
このテキストファイルには依存ライブラリの一覧が辞書順にリストアップされています。
このファイルはVCSにコミットしてバージョン管理しておきます。
dependencyGuardはこのファイルと現在の依存関係の変化を検出し、変化があればエラーとなります。（ファイルがなければ作成されます）

例えば、androidx.activityのバージョンが1.7.0から1.8.0に更新されると以下のようなエラーとなります。

```
Dependencies Changed in :app for configuration releaseRuntimeClasspath
- androidx.activity:activity:1.7.0
+ androidx.activity:activity:1.8.0
```

存在しない依存関係が増えた場合、

```
> Dependencies Changed in :app for configuration releaseRuntimeClasspath
  + androidx.activity:activity:1.8.0
```

既存の依存関係が消えた場合、

```
> Dependencies Changed in :app for configuration releaseRuntimeClasspath
  - hoge.fuga.piyo:piyo:1.0.0
```

いずれの場合も変化ががあるとエラーとなりますので、CIで実行するようにしておくと、意図しない変化が含まれてしまうのを防ぐことができます。

dependencyGuardBaselineを実行すると、ファイルが更新されます。
意図した依存関係の変化であれば、dependencyGuardBaselineを実行し、これをコミットに含めます。
これで、依存関係の変化を履歴として残すことができ、ライブラリの場合は利用者に依存ライブラリの一覧を示すことも容易にできますね。

## 特定の依存関係の混入をエラーとする

このプラグインにはいくつかのオプションが用意されています。そのうちの`allowedFilter`を使うことで、特定の依存関係の混入を一律エラーにすることができます

allowedFilterにはラムダを渡します、このラムダには`androidx.activity:activity:1.8.0`の様な、依存するライブラリ名が渡されますので、禁止したいライブラリだった場合にfalseを返すようにします。

以下の例では、"junit"を含む名前のライブラリが含まれていたらエラーとしています。

```build.gradle.kts
dependencyGuard {
    configuration("releaseRuntimeClasspath") {
        allowedFilter = { dependencyName ->  
            !it.contains("junit")
        }
    }
}
```

テスト用やデバッグ用のライブラリがリリースビルドに含まれてしまうのは良くないですよね。他にもビジネス的な観点や、ライブラリの方針的に、特定のライブラリに依存したくない場合というのは、そこそこあるのではないかと思います。
そういった混入しては困るライブラリがある場合は、このようなルールを書いておき、CIでチェックすることで、意図せず依存させてしまうという問題を防ぐことができます。
secure_file_privの設定

# Introduction
最近SQLを勉強し始めたので自分のメモ代わりに得た知識を書こうと思います。
OSはwindowsでMYSQL server 5.7を使っています。


# LOAD DATA INFILE
CSVファイルをLOAD DATA INFILEで取り込おうとしたらエラーが出ました。エラーメッセージではsecure_file_privがどうのこうの......
ではまずsecure_file_privとはなんなのか確認していきます。

## secure_file_priv
secure_file_privはデフォルトで設定される項目の一つです。
secure_file_privがデフォルトで設定されているときは、その設定されているディレクトリにあるファイルしか読み取れません。
secure_file_privの値の確認は

 mysql> SELECT @@global.secure_file_priv
で確認できます。

windowsの場合はProgramData/MySQL server 5.7/uploadsが指定されているようです。

# CSVファイルのIMPORT
では実際にuploadsの中にあるcsv fileをimportするcodeは以下です。取り込みたいファイルをselect@@global.secure_file_privで得られたディレクトリに置いておくのを忘れないでください。

C:/ProgramData/MySQL/MySQL server 5.7/Uploads/に入っているfile.csvをdbというデータベースのtabというtableにimportします。

 
DATA LOAD INFILE 'C:/ProgramData/MySQL/MySQL Server 5.7/Uploads/
file.csv' INTO TABLE db.table


selec @@global.secure_file_privで指定されているディレクトリ以外からファイルを取り込む方法は以下に記しておきます。

# secure_file_privの変更
secure_file_privを変更したい、もしくはどのディレクトリからもcsvファイルを取り込みたいときは以下のようなことをします。

C:/ProgramData/MySQL/MySQL server 5.7 のmy.iniというファイルを開く
125行目くらいにあるsecure_file_priv="C:/ProgramData/MySQL/MySQL server 5.7/Uploads/"の行を見つけます。
secure_file_priv="C:/ProgramData/MySQL/MySQL server 5.7/Uploads/"　の" "の間に指定したいディレクトリのpathを書きます。どのディレクトリからもimportしたいときは空白にしてください。


MySQLを再起動します。
SELECT @@global.secure_file_privを実行し、指定したディレクトリのpathが入っていればOKです。



ProgramdDataの場所がわからない場合は以下を参考にしてください。

# ProgramDataの場所
uploadsにファイルを入れなければいけないのは分かったが、そもそもProgramDataが見つからない。
ProgramDataは隠しファイルになっているのでデフォルトのままでは表示されないことになっています。
ですので、隠しファイルを表示するように設定する必要があります。
ファイルを開くところに行き、

表示 -> 隠しファイル　のところチェック！！


これだけです。(^▽^)/



# Reference
https://fisproject.jp/2016/03/mysql5-7-import-from-csv/
http://androidlover.net/android-emulator/bluestacks/windows-hidden-programdata-folder-appear.html
Linux で 確定申告 2023年度版

:::note

2024/03/17 追記

この記事の問題を解決した方法を別記事に書きました。

「Linux で 確定申告 2024年度版」
https://qiita.com/nanbuwks/items/3ceb0b3f8e15a8aa3dbf

:::

今まで Web ベースの「国税庁 確定申告書等作成コーナー」を10年以上使ってきました。

長らく IE 縛りでしたが、 pdf を印刷して提出という方法を使えば Linux においても UA 偽装して問題なく作成ができていました。

2023年、 インボイス番号を取得するために e-Tax を使いましたが、マイナンバーカード連携にスマホでQRコードを読み込ませる方法を使うことで、インボイス番号を取得できました。

同じようにして、確定申告もマイナンバーカードでできるのではないかな? 試した記録。

# 環境
- Ubuntu 22.04 LTS
- Google Chrome バージョン: 121.0.6167.160（Official Build） （64 ビット）


# 作ってみる

今年の確定申告書作成コーナーです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1030a886-f37a-c766-94f7-48bc2876ce96.png)

「スマートフォンを利用して  e-Tax 」を選ぶと・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0ed91db2-69a8-f642-c928-085e9b7d5a66.png)


なんてこった! 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/587e49ee-0015-3f9e-ca2f-24d8c5c12afd.png)

 推奨環境として、Windows だったとしても Firefox は×になっています。なぜかな・・・それはそれとして、 e-Tax で Linux 上の Google Chrome で QR コードは使えていますので仕組み的に使えないということはないはずです。単に何も考えずに OS でキックアウトしているだけっぽいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ea9c30ee-ee10-ff64-4552-bdddac068e24.png)

# 作戦変更

では、「印刷して提出」でデータを作り、それを Linux PC 以外のブラウザで提出することにします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8c9ad0d1-2a6d-9e0e-5a80-94e9559f97a6.png)

こっちも Windows 縛りは有りますが、無視して進めます。こちらは異なる環境でも通してくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/94525a02-b240-1a07-6dd4-aac444c36f40.png)

ここからデータを作っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1b77bf23-82cf-0267-8863-9cbd127ebf4c.png)

入力が終わり、最後の画面になったら一つ前の画面に戻ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d0a3a288-a348-90d0-b05e-32fec46e92ba.png)

1つ前の画面でデータを保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/faab0575-8e99-960e-1ae7-e3c251b545db.png)

ここで保存したデータをスマホで読ませたらどうかな・・・

# スマホで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/59ea00d7-e08b-201d-198a-93b3daf25dbb.png)

スマホで確定申告コーナーを開いて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/02aaebcb-f8e4-2898-abf3-da228c3d7d91.png)

保存データを利用しようとしたら・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1740bad8-7ae3-7dd5-f867-a72f5bc9bdbc.png)

なんと!!!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/825ea62f-f719-9aca-641f-4c188184d7c7.png)


# 負け

結局、データを WindowsPC に持っていって再開しました。
QRコード一発かと思ったら、何度も読まさないといけなくて結構煩雑。
そして Windows PC で提出だけのつもりだったのですが、医療費控除などが自動で追加修正されてなんとか提出を終えました
Robbins monroの実装

# イントロ

今回はRobbins monro の実装をしてみました。
Robbins monroは確率勾配降下法の学習率を入りテーション回数の逆数で割っていくものです。
使っているprogram言語はpython 3です。osはwindowsです。(macほしい...)


# アルゴリズム
確率勾配降下方とは目的関数の最適解を求めるアルゴリズムです。目的関数をf(X)とすると、手順は以下のようになっています。

初期学習率$n_0$を決めます。訓練データDを用意します。この訓練データは複数の初期値の集まりです。
訓練データから一つ初期値をランダムに取り出し、これを$x_0$とし、最初の予測値とします。
次の式に現在の予測値$x_0$を代入し、新たな予測値$x_{n+1}$を得ます。$$x_{n+1} = x_{n} - \frac{n_0}{n} grad f(X_n)$$
収束して入れば4へ、収束していなければ2で得られた値$x{n+1}$を新たに$x_n$としてもう一度2を行う。
訓練データを一周していなければ2へ、一周していれば各初期値から得られた解の中から目的関数を最も小さくするものを選ぶ。　　
実装例
以下の目的関数を最小化させてみましょう。
$$f(x,y) = (x-2)^2 + (y-3)^2 $$

コマンドラインでpythonを実行していきます。

# Robbins monro の実装
今回はRobbins monro の実装をしてみました。
Robbins monroは確率勾配降下法の学習率を入りテーション回数の逆数で割っていくものです。
使っているprogram言語はpython 3です。osはwindowsです。(macほしい...)


アルゴリズム
確率勾配降下方とは目的関数の最適解を求めるアルゴリズムです。目的関数をf(X)とすると、手順は以下のようになっています。

初期学習率$n_0$を決めます。訓練データDを用意します。この訓練データは複数の初期値の集まりです。
訓練データから一つ初期値をランダムに取り出し、これを$x_0$とし、最初の予測値とします。
次の式に現在の予測値$x_0$を代入し、新たな予測値$x_{n+1}$を得ます。$$x_{n+1} = x_{n} - \frac{n_0}{n} grad f(X_n)$$
収束して入れば4へ、収束していなければ2で得られた値$x{n+1}$を新たに$x_n$としてもう一度2を行う。
訓練データを一周していなければ2へ、一周していれば各初期値から得られた解の中から目的関数を最も小さくするものを選ぶ。　　
実装例
以下の目的関数を最小化させてみましょう。
$$f(x,y) = (x-2)^2 + (y-3)^2 $$

コマンドラインでpythonを実行していきます。

実行結果はこちら
https://takutori.blogspot.com/2018/01/implementation-of-robbins-monro.html






予想通り、（２，３）という解を導き出してくれました。目的関数が簡単だったので、初期値をどの値でとってもばっちり正解にたどり着いてくれました。

以下にRobbins monroの関数だけ置いておきます。こちらにすべてのコードを載せています。


```
def Robbins_monro(function,grad,number_variable_gradient):

    init_learning_rate = 1.5

    stepsize = 1000

    init_value = np.array([range(-1000,1020,20) for i in range(number_variable_gradient)])

    possibility_solution = np.zeros((number_variable_gradient,101))
    for n in range(len(init_value[0,:])):
        old_estimation = init_value[:,n]
        for step in np.arange(1,stepsize+1):
            n_step = init_learning_rate/step
            old_estimation_t = old_estimation

            new_estimation = old_estimation - n_step*grad(old_estimation)
            old_estimation = new_estimation

        if n % 10 == 0:
            print('%s taimes step is comlicated \n'%n)
        possibility_solution[:,n] = new_estimation

    estimation = possibility_solution[:,0]
    for j in range(len(possibility_solution[:,0])):
        if function(estimation) > function(possibility_solution[:,j]):
            estimation = possibility_solution[:,j]

    return estimation
```
serverless.ymlのfunctionsの論理IDに区切り文字は使わないこと

# はじめに
serverless.ymlで関数の論理IDをケバブケースやスネークケースなどの区切り文字を含むケースにはしないようにしましょう。
```yaml
# serverless.yml

functions:
  functionOne: ←これが論理ID
    handler: handler.functionOne
    description: optional description for your Lambda
  functionTwo:
    handler: handler.functionTwo
  functionThree:
    handler: handler.functionThree
```

# ケバブケースやスネークケースにするとどうなるか

下記の4つのケースで論理IDを命名した関数をデプロイした結果を見てみます。
- ケバブケース、
- スネークケース
- キャメルケース
- パスカルケース


```yaml
functions:
  kebab-case-sample:
    name: kebab-sample
    handler: functions.kebab_sample.lambda_handler
  snale_case_sample:
    name: snale-case-sample
    handler: functions.snale_case_sample.lambda_handler
  camelCaseSample:
    name: camel-case-sample
    handler: functions.camel_case_sample.lambda_handler
  PascalCaseSample:
    name: pascal-case-sample
    handler: functions.pascal_case_sample.lambda_handler
```

`sls deploy`実行後、CloudFormationのコンソールから関数の論理IDを確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703223/54f27dd4-07ab-b6ed-70f7-52f9e4a51ff5.png)

キャメルケースとパスカルケースは、serverless.ymlの論理IDがそのまま表示されていますが、ケバブケースは`-`→`Dash`、スネークケースは`_`→`Underscore`にそれぞれ区切り文字が変換されてしまうようで、かなり読みにくくなります。

公式ドキュメントではキャメルケースを使用しているので、素直にキャメルケースが良いと思います。


https://www.serverless.com/framework/docs/providers/aws/guide/functions
useStateのstateがundefined(初期値)のままで変わらない

# はじめに
Reactアプリを作っていた際にuseStateで躓いたことがあったので共有します。

# 問題
set関数を使って値を変更しようとしても初期値のまんま変わってくれない。

そのときの実際のコードと同じような例
```tsx
/* 省略 */
const [user, setUser] = useState("");

useEffect(() => {
    setUser("太郎");
    console.log(user); // => ""  　"太郎"と出力してほしいのに、、、
})

/* 省略 */
```

# 解決策
state変数は、set関数を呼び出している関数の外( 今回だとuseEffect )で使う。
```tsx
/* 省略 */
const [user, setUser] = useState("");

useEffect(() => {
    setUser("太郎");
})
console.log(user); // => "太郎"

/* 省略 */
```

# 原因
state変数が更新されるのはset関数が呼び出されたその瞬間ではないからです。公式ドキュメントに記述されている通り、set関数を呼び出したタイミングではレンダーのリクエスト・予約のようなものをしているにすぎません。

> これは、state がスナップショットのように振る舞うためです。state の更新は、新しい state の値での再レンダーをリクエストします。すでに実行中のイベントハンドラ内の count という JavaScript 変数には影響を与えません。

<font color="gray">公式ドキュメントより引用</font>

# 終わりに
Reactの基礎的な考えが欠けているのだなぁと感じました。使っていくうちに慣れていこうと思います。

# About Me
- X(Twitter)

https://twitter.com/shunii_hack
Refused to execute script from '(URL)' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.エラー対応

## 前書き
開発中に下記のエラーに遭遇したので、その対処法の備忘録です。
### エラー文
```error
Refused to execute script from  'http://localhost:8080/2ndPage/app.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
create:7 
Refused to apply style from 'http://localhost:8080/2ndPage/style.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
```
## 原因
このエラーが意味するところは
「ブラウザが'http://localhost:8080/2ndPage/app.js'からリソースを取得しようとしているけど、MINEタイプが違うよ！」
って感じです。

今回の場合、実はMINEタイプの問題ではなく、URLに問題がありました。
<details><summary>MIMEタイプとは？</summary>
サクっと一言で説明すると、ファイルの種類を表す情報、が「MIMEタイプ」
</details>

開発中のWebアプリのページ構成は
```
Page1
Page2
Page3
└2ndPage
```
といったようになっており、2ndPageへのアクセスの際にはPage3から遷移する必要があります。
2ndPageのリソースを取得したい場合、何の設定もしていないとリソースを取得する場所がおかしくなってしまう場合があります。

今回の例で説明します。
Reactでのリソースの取得は基本的に、ルートディレクトリの`app.js`から行いますが、エラー文を確認すると`http://localhost:8080/2ndPage/app.js`からリソースを取得しようとしてしまっていることがわかります。

そのため、正しいURLからリソースを取得するように修正する必要があります。

## 対処法
対処は至って簡単です。

`webpack.common.js`などの設定ファイルの`output`に`publicPath:"/";`を設定するだけです。

この設定追加によって、リソースの取得は常にルートディレクトリから行われるようになるため、常にapp.jsからのリソース取得が行われるようになります。

具体的にはこんな感じ。
```webpack.js
output:{
 path:path.resolve(__demame,"dist"),
 publicPath:"/",
}
 ```
Javaでファイル・パスを取得するサンプル

```java
import java.io.File;
import java.io.FileInputStream;

public class Main {
    public static void main(String[] args) {
        String pathname = "helloworld//src//main//resources//ValidationMessages.properties";
        try {
           File file = new File(pathname);

            System.out.println("[01] getPath():[" + file.getPath() + "]");
            System.out.println("[02] getAbsolutePath():[" + file.getAbsolutePath() + "]");
            System.out.println("[03] getParent():[" + file.getParent() + "]");
            System.out.println("[04] getName():[" + file.getName() + "]");
   
            FileInputStream fis = new FileInputStream(file);
            // ファイルの読み込み処理
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

出力例

```
[01] getPath():[helloworld\src\main\resources\ValidationMessages.properties]
[02] getAbsolutePath():[C:\Users\rurur\Downloads\sts-4.17.1.RELEASE\helloworld\src\main\resources\ValidationMessages.properties]
[03] getParent():[helloworld\src\main\resources]
[04] getName():[ValidationMessages.properties]
```
【ROS】tfを一度だけ受信（listen）する

# はじめに
tfを一度だけlistenする方法についてです。
`rospy.sleep()`を追加するだけです。以上。
# 環境
- Noetic
- rospy
- tf2_ros
# サンプルコード
`rospy.sleep()`がないと読み取れません。
```python
#!/usr/bin/env python3
import rospy
import tf2_ros

if __name__ == '__main__':
    rospy.init_node('tf2_test_listener')

    tfBuffer = tf2_ros.Buffer()
    listener = tf2_ros.TransformListener(tfBuffer)

    rospy.sleep(0.1)
    try:
        trans = tfBuffer.lookup_transform('world', 'carrot1', rospy.Time())
        print(trans)
    except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException):
        print("No tf")
```
【Unity】On-Screen Stick などの自作例

# 背景

Unity の InputSystem にある標準の On-Screen Stick では求める挙動を実現できなかったので、仮想入力できるジョイスティックを作ってみました。
またタップ,スワイプ,フリックした際に仮想入力するコンポーネントも作ってみました。
用途に合わせて改造してご利用ください。

# コード

### ジョイスティック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/308b28c6-e47c-a87b-4aac-4e04f6ce5538.png)
基本的にOn-Screen StickのExact Position With Dynamic Originですが、指を置いている間だけジョイスティックを表示し、指を置いた位置にスティックの可動範囲を表示するようにしました。

https://github.com/yamara-mh/GenericCodes/blob/main/Codes/OnScreenStickCustom.cs

### タップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/d86ffc1b-b10a-68bb-8bba-2c592b5df14a.png)
置いた指をMaxRangeより大きく動かさず、MaxDurationより前に離すと仮想入力します。

https://github.com/yamara-mh/GenericCodes/blob/main/Codes/OnScreenTap.cs

### フリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/5b735dd4-d5ab-dfdc-249a-35433f003f16.png)
置いた指をMaxRangeより大きく動かし、MaxDurationより前に離すと仮想入力します。
Vector2の入力に変更できるコメントも書いてあります。

https://github.com/yamara-mh/GenericCodes/blob/main/Codes/OnScreenFlick.cs

### スワイプ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/11bb7c23-3e65-fc80-6755-56891390019c.png)
DetectionDurationの間にMinRange以上ドラッグして指を離したときに仮想入力します。
Vector2の入力に変更できるコメントも書いてあります。

https://github.com/yamara-mh/GenericCodes/blob/main/Codes/OnScreenSwipe.cs
マルチモジュールプロジェクトではTYPESAFE_PROJECT_ACCESSORSを有効にしてtype-safeにモジュールを参照しよう

Gradle 7.0からの実験的機能として、 Type-safe project accessors が使えるようになっています。

https://docs.gradle.org/7.0/release-notes.html

https://docs.gradle.org/7.0/userguide/declaring_dependencies.html#sec:type-safe-project-accessors

　settings.gradle.kts にて以下のようにして機能を有効化します。

```settings.gradle.kts
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
```

マルチモジュール構成で他のモジュールを参照するとき以下のように文字列でモジュールを指定しますが、

```build.gradle.kts
implementation(project(":api"))
```

Type-safe project accessors を有効化するとRootProjectAccessorというクラスが生成され、このインスタンスに`projects`というシンボルを経由してアクセスできるようになります。これでモジュールをtype-safeに参照できるという仕組みです。
IDEの機能で補完されるため、正確なモジュール名が分からず迷ったり、typoしてしまったりというのを防ぐことができますね。

```build.gradle.kts
implementation(projects.api)
```

細かくモジュールを分割している場合など、ネストされている場合、同様のネストで参照できます。

```build.gradle.kts
implementation(project(":data:api"))
```

```build.gradle.kts
implementation(projects.data.api)
```

モジュール名がケバブケース(`foo-bar`)やスネークケース(`foo_bar`)の場合は、キャメルケースに変換された名前でアクセスすることになります。

```build.gradle.kts
implementation(project(":data:api-core")) // kebab case
implementation(project(":feature:permission_base")) // nake case
```

```build.gradle.kts
implementation(projects.data.apiCore)
implementation(projects.feature.permissionBase)
```

機能ごとにモジュールを分けている場合モジュール数も膨大になってきますので、type-safeにアクセスできるというのはなかなかに便利です。実験的機能ということで将来的に変更される可能性もありますが、積極的に利用して良いと思います。
ハッシュテーブル

ハッシュテーブルは、キーと値のマッピングであり、挿入、削除、検索（指定されたキーに関連付けられた値を探すこと）の操作を非常に高速で実行できます。 これらの操作の平均時間計算量はO(1)であり、これは定数時間です。

では、どのようにしてそれを達成するのでしょうか？

実装の詳細を見てみましょう。 キーは人の名前を表す文字列で、値は個人の情報を含むオブジェクトであると仮定します。 最初に、オブジェクト（値）を格納するための配列が必要です。

しかし、どのようにして、与えられた文字列（キー）から対応する配列インデックスを直接知ることができるでしょうか？

それがハッシュ関数の役割です。

ハッシュ関数は、キーをハッシュコードに変換し、それを配列インデックスにマッピングします。 関係は「キー → ハッシュコード → 配列インデックス」です。

そして、キーの可能性は無限ですが、ハッシュコードの可能性は有限であり、配列の長さを可能なハッシュコードの数と同じにするのは現実的ではありません。 したがって、可能なハッシュコードの数は可能なキーの数よりも少なく、可能な配列インデックスの数は可能なハッシュコードの数よりも少なくなります。

その結果、異なるキーが同じハッシュコードにマッピングされたり、異なるハッシュコードでも同じ配列インデックスに対応することがあります。

これがハッシュの衝突です。 複数のキーがハッシュテーブル内での同じ場所にマッピングされます。

では、この問題をどのように解決するのでしょうか？

解決方法の一つはチェイニングと呼ばれます。

チェイニングで使用されるアプローチは、単なる配列ではなく、連結リストの配列を使用することです。 したがって、キー「Peter」と「Fuzuki」がどちらも配列インデックス 0 にマップされる場合、以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555225/fc5c9f23-0e9e-5517-bb27-f325b05cfa77.png)

P0とP1は値としてPersonオブジェクトを表します。

重要なポイントとして、キーは対応する値と一緒に保存しておく必要があります。 そうでないと、検索操作時に「Peter」というキーが渡されたとしても、キーを追跡しないとどの値を返すのか分からなくなってしまいます。

参考文献:

1. [Data Structures: Hash Tables](https://www.youtube.com/watch?v=shs0KM3wKv8) by HackerRank
Chat-GPTのマトリクス的利用

# 目次
[1.はじめに](#1-はじめに)
[2.準備](#2-準備)
[3.作業](#3-作業)
[4.留意点](#4-留意点)
[5.おわりに](#5-おわりに)

# 1. はじめに
**アンケートのフリーコメントを生成AIで分析させたい**とのニーズがあります。そのニーズを解決する方法を考えてみました。なお、この記事は、自分自身の**メモ書き**として書いていますので、言葉足らずの箇所があります。ご容赦ください。

大きな流れとしては、以下の３点となります。
(1)準備
(2)作業
(3)留意点

# 2. 準備
まず、準備ですが、大きく、以下の２点となります。
### (1)OpenAIのAPI Keyの取得
まず、OpenAIのAPI Keyを取得します。最初は、フリー枠が用意されているようです。他の方が、親切に解説していますので、すみませんが、検索してみてください。

留意点としては、①フリー枠には期限あること、②クレジットで申し込むときは、まず、少額から始めること（5ドルから？）の２点となります。

### (2)Google Spread Sheetアドオンの設定
次に、Google Spread Sheetのアドオンを設定します。この点についても、他の方が、親切に解説していますので、すみませんが、検索してみてください。

留意点としては、アドオン設定後、先ほど取得したOpenAIのAPI Keyを入力する必要があります。


# 3. 作業
分析の対象とするダミーデータは、Chat-GPTで作成しました。

分析には、**GPT関数**を利用します。
GPT関数は、以下の通り、いろいろあります。
https://gptforwork.com/help/gpt-for-sheets/gpt-functions/all-available-functions

今回は最もベーシックな関数を使用して、B4のセルに以下のGPT関数を埋め込みます。

```
=GPT(A4 & "は肯定的、否定的、中立的？" )
```
B列の他のセルも、同様です。

実際に、作業した結果は、以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76072/cd4d0881-5cb6-f3c4-88f8-ec8139323f5e.png)

# 4. 留意点
以下に、留意点を３点、記載します。
### (1)使用するモデル
今回は、APIの利用料金を勘案し、GPT3.5 Turboを使用しました。ということで、B列の評価には、イマイチかな、という評価も交じっています。GPT4を使えば、より良い結果が得られると思います。
なお、GPT3.5 Turboのモデルでは、2021年までのデータしかありませんので、その点も留意が必要です。

### (2)ExcelやCopilotでの利用
今回、試行したChat-GPTのマトリクス的利用（２次元的利用）は、Google Spread Sheetを活用しましたが、Excelでも出来るようです。
また、Copilotでも出来るかと思いますので、別途、試行してみようと思います。

### (3)GPT関数
前述の通り、多様なGPT関数があります。用途に応じて、適切なGPT関数を使用することで、用途が広がるかもしれません。

# 5. おわりに
いままでは、Chat-GPTに質問を投げかけ、その回答を得て、また、質問する、という、言わば、**１次元的な利用**が中心でした。
しかし、今回の試行で、**マトリクス的**に、**２次元的な利用**も可能であることが分かりました。今回のように、２次元的な利用をすると、例えば、以下のような資料を、比較的簡単に作成することができます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76072/debd22c6-3d61-256d-cb1b-24d6e9dfe77a.png)

今後、さらに、研究を進めたいと思います。
【ChatGPT有＋DALL-E3】が思いどおりに描画してくれない話。


　どうも、カーブミラーです。

　今回は、思いどおりに描画してくれない話をしたい、と思います。最後にはとりあえずの画像ができましたけれど。

:::note info
本記事は、ChatGPT（有料版）
＋DALL-E3で行なっております。
画像はあります。　あしからず。
:::

　イオンシネマで
　　車椅子を女性スタッフに
　　　何回も担いでもらった人の
　　　　件について。

　私はテレビを見ていないので
　　細かい状況はわかりませんが、
　　　なぜ車イスに乗せたまま、
　　　　段差を乗り越えようと
　　　　　したのかわかりません。

　もちろん、
　　ちょっとした段差で
　　　本人が注意してだったり、
　　　　介助者が手伝ったりは
　　　　　ありえます。

　もし、それが
　　エスカレータや
　　　階段ならば、
　　　　車イスでの移動をやめ、
　　　　　介助者が抱えての
　　　　　　移動をするのが正しい
　　　　　　　のではないでしょうか。

　こんな風に↓
![1710644313510.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/ec7015f3-7dd8-37e4-1398-630ea5916409.jpeg)
***
　今回は、
　　この画像を
　　　作成する際の苦労を
　　　　書きたいと思います。

　この画像は
　　X-Twitterに
　　　メッセージとともに
　　　　ポストするために
　　　　　作成しました。

　でも
　　なかなか思った画像に
　　　なりませんでした。

　やり取りをどうぞ。
***
***user***
AさんBさんCさんがいる。
Aさんは、車椅子に座っている。
BさんとCさんは、車椅子の左右にいる。
描画

***ChatGPT***
（指示どおり）

***user***
リトライ。
Bさん（男性）が車椅子の男性を抱える。
Cさんが車椅子を畳んで、持つ。
これから階段を登る。

***ChatGPT***
（階段の途中。車イスに男性が座ったまま。介助者の男性が、その肩を掴み、手摺りで固定しようとしている。女性は要介助者の肩に手を置いてる）

***user***
リトライ。
Bさん（男性）が車椅子の男性を抱え上げる。
Cさんがカラになった車椅子を畳んで、持つ。
これけら階段を登る。

***ChatGPT***
（また階段途中。女性がハンドルを持つ。介助者が大きなバッグを持って、もう片方の手で要介助者を押すような画像）

***user***
リトライ。
Bさん（男性）が、Aさんを抱え上げる。
Cさんがカラになった車椅子を畳んで、持つ。
これけら階段を登る。

***ChatGPT***
（階段前で、車イスに要介助者を乗せたまま、介助者ふたりが前後から、車イスを持ち上げようとする）

***user***
リトライ。
Bさん（男性）が、車椅子から、Aさんを抱え上げる。
Cさんがカラになった車椅子を畳んで、持つ。
背景は、階段前。

***ChatGPT***
（階段前。男性が要介助者の肩を後ろから両手で押さえ、あとずさるように移動するところ）

***user***
リトライ。
Bさん（男性）が、Aさんを抱く。
Cさんが畳んだ車椅子を持つ。
背景は、階段前。

***ChatGPT***
（介助者男性に立ち上がって抱きつく要介助者。女性も反対側から同じように抱きつく）

***user***
リトライ。
Aさんはだらんとしている。
Aさんを抱くBさん（男性）。
Cさんが畳んだ車椅子を持つ。
背景は、階段前。

***ChatGPT***
（階段前で、要介助者をお姫様抱っこする介助者男性）

***user***（それでもいいけど）
リトライ

***ChatGPT***
（お姫様抱っこしたまま、車イスに座る介助者男性）

***user***（何やってんのw）
リトライ

***ChatGPT***
（ここで、ようやく意図した画像が）
***

　長かった(汗)

　でも
　　よくよく見たら、
　　　お姫様抱っこされてるのは
　　　　介助者女性だった(笑)

　まぁ、
　　狙った構図に
　　　なったので、良し👍
***
　とにかく
　　思ったのは
　　　“対象者を少なくすること”と
　　　　“複雑な状況にしない”という
　　　　　のが、良いように思います。

　それだけ
　　コントロールしやすく
　　　なりますからね。

　以上、私の苦労話でした。

　今回は、ここまで。
テストでモックを使用したら"TypeError: () is not a function"のエラーが出た

# はじめに
現在学習記録アプリのテストを書いているのですが、モックを使用した際に出たエラーの解決方法をまとめます。
# 問題
`getAllRecords`と`deleteRecords`の**２つの関数をモック化**したのですが、 "Failed to fetch records: TypeError: (0 , supabaseFunctions_1.getAllRecords) is not a function"のエラーが出ました。
これは 「getAllRecordsが関数ではない」と言われています。
```tsx:tsx
//モック化
const mockGetAllRecords = jest
.fn()
.mockResolvedValue([ new Record("1", "テスト", 3, "2024-03-16 09:30:48.200885")]  )
jest.mock("../utils/supabaseFunctions", ()=>{
    return{
        getAllRecords:()=>mockGetAllRecords(),
    }})

const mockDeleteRecords = jest
.fn()
.mockResolvedValue([]);
jest.mock("../utils/supabaseFunctions", () => {
    return{
        deleteRecords: () => mockDeleteRecords(),
    }});
```
# 解決方法
**`jest.mock`～の部分がダブっていました。**
**こちらは複数モックを作成する場合も、1回のみ使用するものです。**　
```tsx:tsx
//モック化
const mockGetAllRecords = jest
.fn()
.mockResolvedValue([ new Record("1", "テスト", 3, "2024-03-16 09:30:48.200885")]  )

const mockDeleteRecords = jest
.fn()
.mockResolvedValue([]);

//1つにまとめる
jest.mock("../utils/supabaseFunctions", () => {
    return{
        getAllRecords:()=>mockGetAllRecords(),
        deleteRecords: () => mockDeleteRecords(),
    }});
```
Unity Test Framework でテスト中に無限ループに陥ったときの対処

テスト対象の関数にバグがあり、無限ループに陥ったときの症状と、対処方法です。

## 症状

```c#:MyGameLogic.cs
public class MyGameLogic
{
    // テスト対象の関数。無限ループバグあり。
    // このサンプルではどの関数に問題があるかすぐわかるが、
    // 実際には「どの関数で止まっているかわからない!」はず。
    public static int InfLoop(int a)
    {
        int count = 0;
        while (count < a)
        {
            count = count + 0;//bug
        }
        return count;
    }
}
```

```c#:TestMyGameLogic.cs
using NUnit.Framework;

public class TestMyGameLogic
{
    // テストする側
    [Test]
    public void TestInfLoop()
    {
        Assert.AreEqual( MyGameLogic.InfLoop(9), 9 );
    }

}
```

これをうっかり実行すると、下のようなダイアログが出ます。プログレスバーは進まず、 Create New Scene から先に進みません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747648/940ae602-b91a-cc38-bb21-58d0d062e77c.png)

Cancel を押しても止めることはできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747648/621d05ad-de8c-0f16-0758-9f299698793b.png)


## 対処
(事前にこのUnityプロジェクトのソースを Visual Studio で開いていると仮定しています。テストを実行したあとで Visual Studio を開く方法もあると思いますが、私は試していません)

### デバッガを起動する
1. Visual Studio で「Unity にアタッチ」
1. デバッグ → すべて中断

### 問題箇所を特定する
1. 「呼び出し履歴」で「すべてのスレッドを表示」![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747648/1794b72f-4e0b-ad93-d3a4-f9d449a6c5b8.png)
1. 「並列スタック」ウィンドウが表示されるので、スクロールして怪しい関数を実行しているスレッド (自分が書いた関数が最も怪しい) を見つける。
1. その関数をダブルクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747648/f073c037-e0ba-e283-f81e-e1d697159eaa.png)



### デバッガを駆使して脱出する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3747648/cd69d910-0dec-b058-f670-ec47a19de5c1.png)

- ステップ実行して「なぜ無限ループに陥っているのか」を理解し、ウォッチやイミディエイト ウィンドウで変数を書き換えてループを抜けられるようにする。
- 左端の黄色矢印を return の行までドラッグして脱出する。

などの方法で関数を脱出してください。

関数やループ部分があまりにも短いと、脱出する方法がないこともあります。その場合、 Ctrl + Alt + Del で Unity ごと落とすしかないかもしれません。
【プラクティス紹介】1分でさらっと分かる「パーミッショントークン」

![per_token.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526800/de327b08-074e-0f71-b2be-091d9f2acc5f.jpeg)


## プラクティス名（別名）
パーミッショントークン

## プラクティスの目的・狙い
* チームの自律性の低さによるコストを可視化する

## どんな時に使うか
* チームのフロー効率を下げている要因を明確にしたい時
* チームと周囲の組織がお役所仕事的になっているように感じる時

## 実施手順
1. 透明の空きビンか容器を見つけて、チームの部屋に置く（SBLの近くがよい）
1. トークンとなる物を用意する（レゴブロック、ビー玉、マグネットなど何でもよい）
※種類分けするために5色程度あるとよい
1. スプリント中、チームの誰かがチーム外の誰かに許可を求める必要がある度にトークンをビンに入れる
1. スプリントレビューやレトロスペクティブなどで、溜まったトークンの数を数え、傾向や改善策について皆で話し合う（チームの自律性を高めるには？）

| トークンの色 | 許可の種類（例） |
|:-:|:--|
| 赤 | タスクの完了を外部の誰かに承認してもらう  |
| 黄 | POがステークホルダーやエンドユーザに確認する必要がある  |
| 緑 | 他チームの作業/回答待ち（QA部門によるテスト確認など）  |
| 青 | 外部の管理者に設定変更してもらう必要がある（ツールや環境など）  |
| 白 | 事務手続き、申請など（リリース許可、物品購買、契約など）  |

## アレンジ例
* トークンの色を依頼する人で分ける（＝誰が最も許可を必要としているか？）
* トークンの色を依頼される人/チームで分ける（＝誰に許可を求めることが多いか？）
* オンライン環境で実施する場合はホワイトボードなどに付箋を貼ることで代用
* 分析のため付箋に依頼から許可までに要した時間を追記する

## アンチパターン
* トークンの種類を増やしすぎる（あまり細かくしすぎると運用が大変）
* トークンの大きさが不揃い（視覚的にどの色が多かったかが分からなくなる）

## 参考情報
参考書籍『ゾンビスクラムサバイバルガイド』

https://www.maruzen-publishing.co.jp/item/b304740.html

## こぼれ話（私的コメント）
スクラムチームの理想は開発からリリースまでの作業を全て自己完結できることですが、現実問題として組織の中で仕事をする以上、その過程でチーム外の誰かから許可を得るという行為はゼロにはできません。となると、あとはその頻度が問題となるわけですが、どの程度「許可」が発生しているのかは可視化されていないケースがほとんどではないでしょうか？　そこでトークンがぎっしり詰まったビンをドン！と関係者の目の前に置いて、その量を体感してもらう、というのは話を始める上でとてもインパクトがあるように思います。
空きビンとビー玉など、少し重量のあるトークンで物理的にやってみたいプラクティスです。

---
　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
AtCoderの過去問100問解いて得たこと

はじめまして！CREとしてエンジニアをやってますkazuです🦌

AtCoderの問題を2023年12月から解き始めて、2024年3月で100問に到達したので、自分の振り返りも兼ねて中間報告をすることにしました。

![スクリーンショット 2024-03-16 19.30.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2597943/a3085edc-94d6-7f57-32b3-ea01c4afaab7.png)


# やり始めた経緯

CREというポジションは、コードをガッツリ書く事が少なく、顧客から上がってきた仕様の確認や調査の依頼などの対応が多いため、プライベートでコードを書く時間を増やしたいなと思い始めたのがAtCoderでした。

たまに、改修タスクをこなすのですが、実装する際の思いつく処理のパターンが少ないこと、処理を書く前の言語化があまりできていないこと、PHPの関数をそもそも知らないなどこういった課題もあったため、とりあえず始めてみました。

# やってみてよかったこと


上記で述べたように、コードを実務ではあまり書いていない、またPHP自体も今まで触っていない事もあり、レベルとしてはAとBから始めています。（Aでも解けない問題がちょくちょくあり、悔しすぎてAをやり込む流れに…）

まずは、自分のレベルに合った問題から解き始めることをお勧めします。徐々に少し上の問題を解くことは必要だと思いますが。

ちなみに、僕の場合、AtCoderのABC過去問をメインに解いています。（現段階ではレーティングなどは気にしてやっていない）

以下にやってみてよかったことを列挙しました！

- PHPの関数を知っている→使えるようになった
- 言語化の解像度が上がった
- 実装する際の処理のパターンを前より増やす事ができた

## PHPの関数を知っている→使えるようになった

これはやり始めて感じた事なのですが、いざ実装を始めると「あの関数を使おう」とか出て来ないんですよね。自分の頭の中にインプットできていないものから検索をかけてもそもそも、物を知らないため検索のしようがないわけです。もちろん、今はGoogleさんがいますからそこで検索を掛ければいいわけですが、実装する中で基本的な関数を毎回調べて使うのも面倒であり、時間もかかります。僕は新しい語彙を増やす際、「認知語彙」と「使用語彙」を意識するのですが、これと同じことがPHPの関数にも言えるわけです。使用語彙を増やすには、認知語彙を増やす必要があり、認知語彙を増やすには、そもそもの触れる機会を作る。このサイクルを繰り返すことにより、少しずつ認知語彙が増え、結果として使用語彙も増えるわけです。

![スクリーンショット 2024-03-17 11.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2597943/2c2df9ea-2ed4-eec7-aace-bfc0c0350869.png)

新しい問題を解く度に、知らなかった関数を知る事ができ、少しずつその過程を繰り返すことで使用関数が増えることを実感しました。

## 言語化の解像度が上がった

僕は処理を書く際、一度言語化してから処理を書き始めることを意識しています。理由は単純で、日本語で説明できないことはコードレベルに落とし込む事はできないからです。抽象→具体へ解像度を上げるのに、抽象の材料が抜け落ちてるとそもそも具体化できないよねって話です。

去年CREというポジションについてから、カスタマーサポートから上がってきた問い合わせ（エンジニア視点だと、抽象にあたる）から具体に落とし込んで挙動の確認や処理の流れなどの確認を行うわけですが、このとき必要な材料がないとそもそも具体に落とし込むことも難しくなります。（問題の切り分けが難しくなるため）

これと同じことが、処理を書く際もいえると思い、AtCoderの問題を解く際は、ひたすら言語化を繰り返しました。

面白いのが、AtCoderの問題は問題文を読解する力も必要なわけで、ここから解像度を上げるためには最初の読解で如何に必要な情報を正確に拾い上げ、理解することができるかが重要なわけです。ここで躓くと処理もうまくいきません。

こんな感じで、抽象⇄具体の訓練を繰り返し、少しずつ言語化もできるようになっていき、コードレベルに落とし込めるようになってきました。

## 実装する際の処理のパターンを前より増やす事ができた

AtCoderに限った話ではないかもしれませんが、自分が解いた問題を他の方も解いていることもあり、自分では思いつかない方法で解いてるコードもあります。それらを読み解き、理解し、次の実装で試すということを繰り返していると自然と自分のコードパターンが増えていきました。「この問題はこのパターンで解くこともできるけど、これはどうだろう」という感じで、思考パターンが増えたので、これを増やすことであらゆるテストケースにも対応できる力が身につくのかなと考えています。

# 改善点

やり始めて色々課題が見えてきたので、今後はその辺を意識しつつ、レベルアップしていこうかと思います。

- 言語化がまだまだ抽象的であるので、コードレベルに落とし込むために何が必要でどういった処理を書きたいのかを具体化していく
- 実装する際の処理パターンをもっと増やせるようにする

# 今後の方針

とりあえず、100問は達成したので、次は200問を目指していこうかなと思います。A問題に取り組みつつ、B問題にも取り組んでいく方針です。今年中にB問題は余裕で解ける、C問題は解けるものと解けないものがあるレベルにはなりたいなと思っています。
VSCodeを使ってる時といない時でコミットメッセージを書くエディタを切り替える

環境:Ubuntu22.04 (WSL2)

# 問題
自分はVSCodeの統合ターミナルから`git commit`する際も、コミットメッセージをそのままVSCodeで書けるように`core.editor`は`code --wait`にしています。

しかしながら、他の端末アプリケーションからgitを操作する時に、VSCodeのような重厚なエディタが起動するのは鬱陶しい上、開いていたディレクトリなども消えてしまうので、代わりにnanoを起動させたいと思いました。

# 解決策
次のようにするとよいです。

```:.gitconfig
[core]
	editor = "`[ \"$TERM_PROGRAM\" = vscode ] && echo code --wait || echo nano`"
```
`TERM_PROGRAM`を設定しない端末があるので、構文エラーを避けるために、ダブルクオートで囲っています。

自分の環境だとdashで実行されていました。恐らく/bin/shで実行するようになっている？