OmniAICreator/Qiita-1.07M huggingface dataset:
Unity Vector3の便利な変数と関数

## 0.0 はじめに
Vector3の便利な関数と変数があります。よく使われるものをまとめました。






## 1.0 パラメータが(0,0,0)、(1,1,1)用のベクトル変数
static(スタティック)な変数なのでVector3.xxxxで使用できます。

```C# Test.cs
Vector3 vOne = Vector3.one; // ( 1, 1, 1)ベクトル
Vector3 vZero = Vector3.zero; // ( 0, 0, 0)ベクトル
```







## 2.0 上下左右前後の6方向ベクトルを表す変数
同様にstatic(スタティック)な変数なのでVector3.xxxxで使用できます。

```C# Test.cs
Vector3 vB = Vector3.back; // ( 0, 0,-1) 後方向
Vector3 vD = Vector3.down; // ( 0,-1, 0) 下方向
Vector3 vF = Vector3.forward; // ( 0, 0, 1) 前方向
Vector3 vL = Vector3.left; // (-1, 0, 0) 左方向
Vector3 vR = Vector3.right; // ( 1, 0, 0) 右方向
Vector3 vU = Vector3.up; // ( 0, 1, 0) 上方向
```







## 3.0 ベクトルの大きさにかかわる変数magnitudeとsqrMagnitude
大きさにかかわる変数です。Vector3.magnitudeを使うとベクトルの大きさをfloatで返してくれます。
尚、magnitudeは平方根の計算をするので比較的重い処理です。単純にベクトル大きさを比較する場合には平方根の計算をしないVector3.sqrMagnitudeを使用しましょう。

```C# Test.cs
Vector3 v = new Vector3(5, 0, 1);
float vMag = v.magnitude; // 5.09902　大きさ
float vSMag = v.sqrMagnitude; // 26　大きさの２乗

Vector3 vNor = v.normalized; // (1.0, 0.0, 0.2) 1の大きさ
```








## 4.0 ベクトルの回転を扱うQuaternion
Quaternion.Euler(x, y, z)を使ってVector3の回転ができます。回転させたい量(角度)をrotationにかけてあげます。
尚、回転では反時計回りが正の方向となります。

```C# Test.cs
// z軸で45度だけ反時計回りさせています。
transform.rotation *= Quaternion.Euler(0, 0, 45f);
```







## 5.0 線形補完Lerp
オブジェクトを滑らかに移動させるためによく使うLerpは2点間にある任意の点を表現できる線形補完を行う関数です。
始まりの点Vector3 aからbまでの間の点を0から1の間の割合tで補完します。例えば0は点a、1は点b、0.5はa点とb点のちょうど真ん中を示します。
Vector3.Lerp(a, b, t)の形で使用します。

```C# Test.cs
// fromから、fromからTo間の長さの4割(0.4f)の地点へ移動する
transform.position = Vector3.Lerp(from, to, 0.4f);
```










## 6.0 球面線形補間Slerp
Lerpと同じ補完を行いますがこちらは円を描くように補完します。
引数も同じくaからbまでの間の点を0から1の間の割合tで補完、Vector3.Slerp(a, b, t)の形で使用します。


```C# Test.cs
// fromから、fromからTo間の長さの6割(0.6f)の地点へ球面線形移動する
transform.position = Vector3.Slerp(from, to, 0.6f);
```



## 7.0 移動時に使用するMoveTowards
Lerpと同じく線形補完ですが、MoveTowardsは出発の地点currentから目的地targetに向けての距離を設定することができます。尚、距離は目的地を超えることはありません。

```C# Test.cs
// 下記をUpdate関数などに入れると時間とともに移動する
Vector3 current = Vector3.zero; //現在地
Vector3 target = Vector3.one*10; //目的地
float dist = Time.time; //現在地からの距離

// fromからToに向けての長さdistの地点へ移動する
transform.position = Vector3.MoveTowards(current, target, dist);
```

## 8.0 回転移動RotateTowards
現在地から目標値まで回転します。
maxRadiansDeltaの値で回転速度の調整ができます。
maxRadiansDeltaにマイナスの値を与えると逆方向に回転します。
```C# Test.cs
// 下記をUpdate関数などに入れると時間とともに回転する（上から右に回転）
Vector3 current = Vector3.up;//現在地
Vector3 target = Vector3.right;//目標値

float maxRadiansDelta = Time.time;//2点間におけるラジアンの差分の範囲内で設定する
float maxMagnitudeDelta = 0f;//1回で何度回転させるか。

transform.position = Vector3.RotateTowards(current, target, maxRadiansDelta, maxMagnitudeDelta);
```


## 9.0 距離 Distance
ベクトルab間の距離を取得出来ます。(a-b).magnitudeと同じ結果となります。
```C# Test.cs
Vector3 a = new Vector3(1, 1, 1);
Vector3 b = new Vector3(4, 5, 1);
float dist = Vector3.Distance(a, b); // dist = 5
```
【Linux】特定の行の前後に文字列を挿入する方法

## 文字列を挿入

### 特定の文字列を含む行の上に挿入

特定の文字列を含む行の上に指定した文字列を挿入するには以下のように実行します。  

```terminal
$ sed '/line3/i INSERT' sample.txt
line1
line2
INSERT
line3
line4
line5

```

### 特定の文字列を含む行の下に挿入

特定の文字列を含む行の下に指定した文字列を挿入するには以下のように実行します。  

```terminal
$ sed '/line3/a INSERT' sample.txt
line1
line2
line3
INSERT
line4
line5
```

## ファイルの内容を挿入

挿入する内容を記述した`insert.txt`を以下のように作成します。  

```insert.txt
==========
  INSERT
==========

```

### 特定の文字列を含む行の上に挿入

特定の文字列を含む行の上に指定したファイルの内容を挿入するには以下のように実行します。  

```terminal
$ sed '/line3/e cat insert.txt' sample.txt
line1
line2
==========
  INSERT
==========
line3
line4
line5

```

### 特定の文字列を含む行の下に挿入

特定の文字列を含む行の下に指定したファイルの内容を挿入するには以下のように実行します。

```terminal
$ sed '/line3/r insert.txt' sample.txt
line1
line2
line3
==========
  INSERT
==========
line4
line5

```
【Android】CoroutineのJobについて【Kotlin】

# はじめに
今回はCoroutineのJobという機能について調べたものを記事にします
箇条書きにしていてわかりにくいとは思いますが、使いながら理解を深めていこうと思っているのでご容赦ください

# まとめ内容
Jobのできることを箇条書きにしてまとめたものです
・親子階層で配置することができ、親が取り消されると　子のロジックも取り消される
・SupervisorJobを使用してカスタマイズできる機能で、CancellationException以外の例外で子が失敗するとその親がキャンセルされる（結果　全ての子がキャンセルされる）
・基本的にはJob を実行しても値を出すことはできない

・Jobの状態は　New,Active,Completing,Cancelling(キャンセル中),Cancelled (キャンセル済み),Completed　の６つの状態が存在する

・Jobはアクティブな状態で作成され開始されます。
・またstartまたはjoinを呼び出すことによってアクティブにすることもできます。
```
job.start()
job.join()
```
・コルーチンが動いている間、またはCompletableJobが完了するまで、または失敗するか取り消されるまで、Jobはアクティブな状態

・Jobはいつでもキャンセル可能
```
job.cancel()
```
・アクティブなCoroutineの本体が完了するか、CompletableJob.complete が呼び出されると、Jobが完了状態になる


# 参考資料
[kotlinx.coroutines 1.6.4](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/)

[Android デベロッパー](https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=ja#job)


# おわりに
Coroutineの一つの機能でJobについてまとめました
Coroutineは便利な機能ですがやはり、使いこなすにはもう少し知識が必要だと思いました
別の機能についてもまた、記事にしていこうと思います！
GitLab CIからSSHでデプロイ先サーバーへ接続し、デプロイ先サーバーでコマンドを実行するときの備忘録

# 概要
- GitLab CIからSSHでデプロイ先サーバーへ接続したい
- 接続した後、デプロイ先サーバーでコマンドを実行したい

# ローカルマシーンで秘密鍵と公開鍵を生成
```
# 鍵の生成
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa

# 公開鍵
cat ~/.ssh/id_rsa.pub

# 秘密鍵
cat ~/.ssh/id_rsa
```

# デプロイ先のサーバーマシンにSSH接続して authorized_keys に公開鍵を登録
```
cd .ssh
vi authorized_keys
```

# Gitlabで秘密鍵を登録
- プロジェクトの「Settings」→「CI/CD」→「Variable」から「Add variable」をクリック
- 先ほど生成した`秘密鍵`を登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684448/d73ffb47-90cd-81a0-d56a-aa1dc42017c5.png)

- `Key` は後に`.gitlab-ci.yml`で変数名として使用
- このとき、`Type` は`Variable`にすること！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684448/b63385a0-e1d9-43fe-f911-db694cebd63e.png)

# YAMLファイルを編集する
- プロジェクトの「CI/CD」→「Editor」からYAMLファイルを編集

パターン１
```yml
variables:
  # 先ほど登録したkeyの名前
  SSH_PRIVATE_KEY: $SSH_PRIVATE_KEY

stages:
  - deploy

deploy:
  stage: deploy
  before_script:
    - 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )'
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - ssh -tt host@10.10.20.20 -i ~/.ssh/id_rsa -C ". test_run.sh &"
```
パターン２
```yml
variables:
  # 先ほど登録したkeyの名前
  SSH_PRIVATE_KEY: $SSH_PRIVATE_KEY

stages:
  - deploy

deploy:
  stage: deploy
  before_script:
    - mkdir -p ~/.ssh
    - chmod 700 ~/.ssh
    - echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - eval "$(ssh-agent -s)"
    - ssh-add ~/.ssh/id_rsa
    - ssh-add -l
    - echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
  script:
    - ssh -tt host@10.10.20.20 -i ~/.ssh/id_rsa -C ". test_run.sh &"
```
※書き方を変えても結果はどちらも一緒

```
ssh -tt host@10.10.20.20 -i ~/.ssh/id_rsa -C ". test_run.sh &"
```

- `-C`を付けることで、サーバーにログインした後のコマンド操作を可能にする（今回はシェルスクリプトの中に実行したいコマンドを記載）
- gitlab ciのセッションは１時間で切れてしまうため、もしスクリプト実行に１時間以上かかる場合は、`&`を付けてプログラムをバックエンドで動かす
- のちログを見たい場合はスクリプト内にloggerを入れてファイル出力できるようにしておく
```python
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s | %(levelname)s | %(message)s')

stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
stdout_handler.setFormatter(formatter)

file_handler = logging.FileHandler('debug.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)

logger.addHandler(file_handler)
logger.addHandler(stdout_handler)
```

## 追記
`&`でうまくいかない場合は、`screen`コマンドを使うと良い
```
- ssh -tt host@10.10.20.20 -i ~/.ssh/id_rsa -C "screen -dmS perf bash test_run.sh" 
```

# 完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684448/1376657b-4456-b248-f40f-b0b42f4cd206.png)
Teachable Machineを使ってカフェイン量を判定するWebアプリを作りたかったが… #機械学習 #Webアプリ

#### Teachable Machineを使ってカフェイン量を判定するWebアプリを作りたかったが…

#### 1.減カフェイン生活を送りたい
皆さん、コーヒーは飲んでいますか？
私は、朝起きて勤務前やリフレッシュしたい時にコーヒーを飲みます。
事実、コーヒーの香りには **リラックス効果やリフレッシュ効果**があるので、
いろいろ煮詰まっているときに気分を変えるときにぴったりです。

https://mystyle.ucc.co.jp/magazine/a_1231/

ただ、コーヒーの飲みすぎも体にあまりよくありません。
夜眠れなくなったり胃を荒らすなどのデメリットもあります。
そのため、1日の摂取量は成人で約400㎎までの摂取が推奨されてます。
**※詳細はリンク先を参照ください。**

https://mystyle.ucc.co.jp/magazine/a_679/

https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000170477.html


#### 2.毎回調べるのは面倒くさい。。。なら。。。
カフェインを大量に摂取ことによるデメリットは理解できます。
ただ、コーヒーを飲む都度、製品毎にカフェイン量を調べるのは面倒です。
また、製品の成分表も100ml毎や商品単位などバラバラなので、
成分表の単位を確認し、換算するのはさらにめんどくさい。
**日常のめんどくささを軽減**するために、最近学んだTeachable Machineを使って、
コーヒーのカフェインを算出するアプリを作成してみました。

#### 3.Teachable Machine を使って機械学習させたが。。。
###### 3-1.Webアプリの動画
こちらが作成したWebアプリの動画です。

https://twitter.com/AYE7WvdouqRwaNp/status/1594283993452933121?s=20&t=UkIvwJSkrmrXQuRp-J-AKw

https://jolly-banoffee-82a325.netlify.app


###### 3-2.Webアプリのコード
作成したWebアプリのコードはCodePenで公開しています。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="oNyGVVL" data-user="kanakiku" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kanakiku/pen/oNyGVVL">
  コーヒー判別する？</a> by kana_xedge (<a href="https://codepen.io/kanakiku">@kanakiku</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


###### 3-3.Webアプリ使用方法
①「読み込み開始」ボタンを押下する
②「読み込み完了」メッセージが表示されたら、画面真ん中の「カフェインチェック」ボタンを押下する
③ボタンの下部に、画像から判定した商品情報をもとにカフェイン量を算出し表示

###### 3-4.環境
CodePen
Bootstrap
Teachable Machine

###### 3-5.判定できる商品
缶コーヒー3種類、大きめサイズ(400mlぐらい)の缶コーヒー1種類、チルドタイプのコーヒー1種類
コンビニのコーヒー3種類を使用して機械学習を実施しました。
※商品名を乗せるのはNGと聞いたので、ふわっとした感じで記載しています。

#### 4.苦労した点
 **Teachable Machineの精度があがらない**
缶コーヒーは形はほぼおなじであるものの、色が全然違うからなのか、うまく商品判定できました。
ただ、チルドタイプのコーヒーとコンビニのコーヒーは形や色もほぼ同じなため、
あまり商品判定精度があがりません。
機械学習に使用する画像を2倍まで増やしましたが、精度はほとんど上がりませんでした。

#### 5.まとめ
今回は、最近学んだTeachable Machineを使い、カフェイン量を算出するWebアプリを作成しました。
可能であれば、LINEbotへの通知なども検討しましたが、そもそも商品判定の精度があがらず苦戦しました。
Teachable Machine事態の向き不向きなのか、他に判定精度をあげる方法があるのか、
まだわからない部分も多いため、これからいろいろ試してみようと思います。
定時になったら超A&Gを再生する方法（Windows）

# 概要
突然ですが、私は小原好美さん（声優）のラジオが好きで、よく聞いています。番組は超A&Gで放送されている、小原好美のこころおきなくという番組です。

番組は日曜日の20時に放送されるので、ほぼ確実に在室しており聞けるのですが、風呂に入っていて忘れてしまうことも多い。録音用のバッチを書いていたのですが、コケることも多くうまくいかない....ということで、定刻になったらPC上から再生するようにすればいいじゃん！ということに。

# 定刻になったら超A&Gを再生するバッチ
## 前提条件
ffmpeg ffplayのパスが通っている必要があります。

# バッチ
Windows上で、下記の内容でバッチを作成する。

``` ffplay -nodisp "https://agcdn02.cdnext.stream.ne.jp/hls2/basic/data/prog_index.m3u8"```

※仕様変更前はこうでした。
``` ffplay -nodisp "https://fms2.uniqueradio.jp/agqr10/aandg1.m3u8" ```

# タスクスケジューラ登録
タスクスケジューラにこんな感じでバッチを登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134622/d3c9c9a1-ef10-8f35-e71c-05fdc74ade64.png)

ちょっと早めにしておくのがポイント。

# 日曜日20時を待つ
再生されるでしょうか？？

# まとめ
``` ffplay -nodisp "https://fms2.uniqueradio.jp/agqr10/aandg1.m3u8" ```　とコマンドを実行すると、超A&Gが再生できるので便利！！！！いろいろ応用できそうです。
【忘却録】Dockerで即席PHP環境を構築する方法

某案件で「Apache+PHP+MySQL」の環境が必要になったので、Dockerで作成する。

### 【PC情報】
・macOS Monterey(バージョン 12.5)

### 【ディレクトリ構成】
```ruby:ディレクトリ
Application
├── app
  └── index.php

├── docker-compose.yml

├── mysql

└── php

    ├── Dockerfile

    └── php.ini
```

### 【前提】
・dockerが入っていること

dockerが自分のPC環境に入っているかは、バージョンを確認する方法が手っ取り早いです。
下記、コマンドをたたいて色々でてきたらOK
```ruby:docker 確認方法
docker -v
```

あと、個人的にコマンドたたくの苦手な方は、「Docker Desktop」をインストールすると、コンテナの立ち上げ状況や「起動」「停止」といった操作が楽になるかも？です。
↓　↓
[Docker Desktop](https://www.docker.com/products/docker-desktop/ "Docker Desktop")

### 【手順】
1.Dockerfileを作成する。

phpフォルダ配下のDockerfileに以下を入力します。
※下記、「volumes:」以下で設定しているURLは、自分の開発環境に合わせてパスを変更して下さい。

```ruby:php/Dockerfile にて
FROM php:7.4-apache 

RUN apt-get update && apt-get install -y libonig-dev && \

  docker-php-ext-install pdo_mysql mysqli mbstring
```

2.docker-compose.ymlを作成する。

docker-compose.ymlファイルに下記の設定を記載していきます。
```ruby:php/Dockerfile にて
version: '3'
services:

#MySQL用コンテナ
  mysql:
    container_name: mysql
    image: mysql:5.7
    volumes:
      - /Users/****/Application/mysql:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=test
      - MYSQL_USER=test
      - MYSQL_PASSWORD=test

#phpMyAdmin用コンテナ
  phpmyadmin:
    container_name: phpMyAdmin
    depends_on:
      - mysql
    image: phpmyadmin/phpmyadmin
    environment:
      PMA_HOST: mysql
    restart: always
    ports:
      - "80:80"

#php用コンテナ
  php:
    container_name: php-apache
    build: ./php
    volumes:
      - /Users/****/Application:/var/www/html
    ports:
      - 8080:80
    depends_on:
      - mysql
```

3.コンテナ作成、動作確認

Dockerfileとdocker-compose.ymlファイルの作成が完了したら、lamp-dockerフォルダ直下で下記コマンドを実行してください。
```ruby:Application直下にて
docker-compose up -d
```

index.php追記に下記内容を追記
```
echo 'hello world';
```

保存できたら、ブラウザから下記リンクにアクセスしてください。
　※先程、index.phpで記載した「hello world」がでていればOK
```
http://localhost:8080/app/index.php
```

phpMyAdomin
下記リンクで、phpMyAdminのログイン画面を表示されることも確認。
```
http://localhost:80
```

完了！

### 参考サイト様
[XAMPPとは違う？DockerでのPHP環境構築方法を解説](https://and-engineer.com/articles/Ybx0hREAACEAgRY9#heading3-5 "XAMPPとは違う？DockerでのPHP環境構築方法を解説")
Nuxt3のscript setupでオートインポートされるフックを使用しているコンポーネントでのVitestの書き方


2022/11時点の情報です。
恐らく変わる可能性も高いと思われるので、暫定的な方法として。

Nuxt3で `useRoute()`, `useRouter()`, `useRuntimeConfig()` ... 等は、setup時にオートインポートされる。
これらが `vitest` 側で `ReferenceError` になってしまう問題の対策。


### コンポーネント側

オートインポートされるものを、`import { ... } from '#imports'` のような形で、明示的に読み込む。

```Sample.vue
<script setup lang="ts">
import {
  useRoute,
  useRouter,
  useRuntimeConfig,
  //...
} from '#imports' // 読み込む

const route = useRoute()
const router = useRouter()
const runtimeConfig = useRuntimeConfig()
// ...
</script>

<template>
  <div>...</div>
</template>
```

### vitest.config.ts 側

`vitest.config.ts` 側で、aliasを設定する。

```vitest.config.ts
/// <reference types="vitest" />

import path from 'path'
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [Vue()],
  test: {
    globals: true,
    environment: 'jsdom',
  },
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './'),
      '~': path.resolve(__dirname, './'),
      '#imports': path.resolve(__dirname, './.nuxt/imports.d.ts'), // 追加
    },
  },
})
```

### テスト側

テスト側では `vi.mock()` でその値をモックすればOK。

```Sample.spec.ts
vi.mock('#imports', () => {
  return {
    useRoute() {
      return {
        // ... 値をセット
      }
    },
    useRouter() {
      return {
        // ... 値をセット
      }
    },
    useRuntimeConfig() {
      return {
        // ... 値をセット
      }
    },
  }
})
```


## 参考

- https://stackoverflow.com/questions/72192874/testing-pinia-store-inside-nuxt3-with-vitest-throws-useruntimeconfig-not-defin
router.baseを設定したNuxt2をNuxt3へマイグレーションする際の方法(app.baseURL)


Nuxt2プロジェクトをrootディレクトリ以外にデプロイする際、 `nuxt.config.js` に `router.base` を設定しているケースのマイグレーションの書き換え方について。

## Nuxt2側

以下のような形で、appを `/sub-directory/` に公開しているケースを想定。

```nuxt.config.js
export default {
  // ...
  router: {
    base: '/sub-directory/',
  },
}
```

その際に、`router.base`を参照しているcomponentの例として、`OptionsApiItem.vue` と `CompositionApiItem.vue` を用意してみる。
画像は `/static/images/` に `cat.jpg`を配置しそれを参照。

```/components/OptionsApiItem.vue
<template>
  <div>
    <div>{{ count }}</div>
    <img :src="`${ $router.options.base }images/cat.jpg`" alt="🐈">
  </div>
</template>

<script lang="ts">
export default {
  data() {
    return {
      count: 99,
    },
  },
}
</script>
```

```/components/CompositionApiItem.vue
<template>
  <div>
    <div>{{ count }}</div>
    <img :src="`${ $router.options.base }images/cat.jpg`" alt="🐈">
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const count = ref<number>(99)

    return {
      count,
    }
  }
})
</script>
```

## Nuxt3側

Nuxt3ではアプリのベースURLの設定方法が異なる。（`app.baseURL`）

```nuxt.config.ts
export default {
  // ...
  app: {
    baseURL: '/sub-directory/',
  }
}
```


Nuxt3では `$router.options.base` にアクセスできない。
代わりに `$config.app.baseURL` 、もしくは`useRuntimeConfig()` を使って参照する。

Options APIからは `useRuntimeConfig()` が使えないので注意。
画像は `/static/images/` から `/public/images/` に変わる。


```/components/OptionsApiItem.vue
<template>
  <div>
    <div>{{ count }}</div>
    <img :src="`${ $config.app.baseURL }images/cat.jpg`" alt="🐈">
  </div>
</template>

<script lang="ts">
export default {
  data() {
    return {
      count: 99,
    },
  },
}
</script>
```

```/components/CompositionApiItem.vue
<template>
  <div>
    <div>{{ count }}</div>
　　   <img :src="`${ $config.app.baseURL }images/cat.jpg`" alt="🐈">
　　   <img :src="`${ baseURL }images/cat.jpg`" alt="🐈">
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const count = ref<number>(99)

    const runtimeConfig = useRuntimeConfig()
    const baseURL = runtimeConfig.app.baseURL

    return {
      count,
      baseURL,
    }
  }
})
</script>
```

```/components/ScriptSetupItem.vue
<script setup lang="ts">
import { ref } from 'vue'

const count = ref<number>(99)
const runtimeConfig = useRuntimeConfig()
const baseURL = runtimeConfig.app.baseURL
</script>

<template>
  <div>
    <div>{{ count }}</div>
    <img :src="`${ $config.app.baseURL }images/cat.jpg`" alt="🐈">
    <img :src="`${ baseURL }images/cat.jpg`" alt="🐈">
  </div>
</template>
```


## 参考

- https://nuxt.com/docs/guide/going-further/runtime-config/#runtime-config
CloudFormationテンプレートをJSONからYAML変換して保存する方法

# CloudFormationとは
CloudFormationはプログラミング言語やYAML,JSONを使用してAWSリソースを構築出来るサービスです。
AWS環境をテンプレート化しておくことで、同じ環境を作成する時間を削減することができます。

## テンプレートをYAMLからJSONに変換する方法
「`CloudFormation`」→「`スタックの作成`」→「`デザイナーで表示`」を選択。
![スクリーンショット 2022-11-20 19.43.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983197/2ddec1df-e6e2-6643-0d3e-edde50f50847.png)

`テンプレート言語の選択`があるので、JSONを選択。
![スクリーンショット 2022-11-20 19.50.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983197/aaf26215-b111-3396-342c-d93f1f306dc7.png)

次のような表示が出れば正常に変換されています。
![スクリーンショット 2022-11-20 19.56.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983197/a49dfd4d-9ba7-b619-b237-f52fb1e33522.png)

最後に左上から変換した`ファイルを保存`ができます。
![スクリーンショット 2022-11-20 19.58.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983197/b621f380-c4f3-0b1d-3798-bf5aabfc8f55.png)
ECCV2022の量子化論文 (3)

# 概要

この記事では、[ECCV2022](https://eccv2022.ecva.net/)の量子化論文を紹介します。[^1]
[その1](https://qiita.com/kyad/items/969db123c549ca308f39) [その2](https://qiita.com/kyad/items/f70f7ea51fb01ffdb55a)

[^1]: 画像や数式は論文から引用しています。


# Mixed-Precision Neural Network Quantization via Learned Layer-wise Importance

https://arxiv.org/abs/2203.08368

- 概要：量子化学習で、各レイヤのビット数を最適化し、かつQATであるもの。
- 新規性：HAWQv2はQAT的ではないが、本論文ではQAT的に探索できる。
- キモ：
  1. Imporance indicator (量子化の精度への寄与度)を学習する。
  2. 1を使ってビット最適化問題を整数計画問題として解く。
- 評価：MobileNet等で比較した。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/b7c42b2c-edd1-7073-d8c6-4cf02b0c1c8c.png)


# Non-Uniform Step Size Quantization for Accurate Post-Training Quantization

https://www.ecva.net/papers/eccv_2022/papers_ECCV/papers/136710657.pdf

- 概要：SQ. 対数量子化(ベル型に近い)によるPTQ。
- 新規性：線形量子化では、計算精度は表現精度と同じにするが、対数量子化では計算精度を表現精度より増やす。
- キモ：対数量子化では量子化の候補点が多いのでそこから最適な量子化点を取る。
- 評価：ImageNet, ResNet-18で評価した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/621a324b-74d9-bfcb-3d56-4b06336f5d71.png)


# Towards Accurate Network Quantization with Equivalent Smooth Regularizer

https://www.ecva.net/papers/eccv_2022/papers_ECCV/papers/136710726.pdf

- 概要：SQR, QSin. 量子化と等価な連続な正則化項。
- 研究機関：Huawei
- 新規性：量子化学習のうちQATではなく正則化項を使う方法において、MSQEの非連続な課題や、SinReQの範囲外の誤差が大きい課題を解決する。
- キモ：従来のMSQEと大小関係が近いかつ連続な指標QSimを提案した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/1ead2040-c1b5-e01f-13bc-c87192a49f35.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/54d1614f-ced4-75e4-3935-5cbb7d6ac701.png)
- 評価：ResNet-18, MobileNetV2, ImageNet, 4/8bitで実験した。
- 参考：Related worksでは、量子化の方法として、PTQ, QAT, 正則化による量子化学習の3つが挙げられている。


# Explicit Model Size Control and Relaxation via Smooth Regularization for Mixed-Precision Quantization

https://www.ecva.net/papers/eccv_2022/papers_ECCV/papers/136720001.pdf

- 概要：レイヤ毎に量子化精度を変える混合精度量子化で、連続的な正則化項で最適化するもの。
- 研究機関：Huawei
- 新規性：連続な正則化項によって最適化し、かつ、モデルの大きさに制約を明示的に入れられる。
- キモ：正則化項をこうする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/7ae7a486-cd1b-96db-d900-283d96c477ec.png)
- 評価：ResNet-20, ImageNetや超解像タスクで実験した。


# BASQ: Branch-wise Activation-clipping Search Quantization for Sub-4-bit Neural Networks

https://www.ecva.net/papers/eccv_2022/papers_ECCV/papers/136720017.pdf

- 概要：低bit(4bit以下)量子化で、クリップ値を最適化する方法。
- 新規性：量子化パラメータ学習で良いLSQの課題である、Separable Convolutionに不安定な課題を解決する。
- キモ：クリッピング値$\alpha$に対してweight decay (L2正則化) を入れる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2448931/3f3ac666-94a7-83fe-d331-b9e93293ca0f.png)
- 評価：MobileNetV1, V2, ImageNetで実験した。
【Unity】AudioSource の実装を簡潔に書けるメソッドチェーン

# 概要
Unity の AudioSource の実装を簡潔に書けるメソッドチェーンを作りました。

# サンプル

``` C#
    [SerializeField] AudioSource audioSource;
    [SerializeField] AudioClip[] clips;

    public void Play()
    {
        // 優先度と最大距離を変更
        audioSource.SetPriority(16).SetDistance(500)
            // クリップ・音量・ピッチをランダムに変更
            .SetClip(clips).SetVolume(0.95f, 0.05f).SetPitch(1f, 0.1f)
            // 1秒遅れで再生
            .Play(1f);

        // クリップ・音量・ピッチ・遅延　をまとめて設定して再生
        audioSource.Play(clips, 0.95f, 0.05f, 1f, 0.1f, 1f);
    }
```

# コード

https://github.com/yamara-mh/CodeStorage/blob/main/Codes/AudioSourceEx.cs
[PySimpleGUI] ボタンが押されるたびにInputボックスを追加していく

# 概要
何かしらボタンが押されたときにInputボックスが追加されるようなインターフェイスが欲しかったが、
ネット上に情報がなかったので備忘録としてあげさせていただく
(下画像はヘタクソなイメージ図)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983357/0549a988-0348-02ae-3563-6ae9e4aecb2b.jpeg" width = 50%>

例えば先にInputボックスを10個用意しておいて非表示にしておく　→　ボタンが押されるたびに非表示を解除
みたいなコードも可だが、やっぱり上限値は設定したくないのでがんばった

# 実行環境
・Windows10
・Python 3.11.0
・PySimpleGUI 4.60.4

# サンプルコード
~~~python:Add_Input.py
import PySimpleGUI as sg
import sys


num = 1     #Inputボックスの数
g_value = {0 :""}   #Inputボックスの初期値
g_window_pos = (None, None)     #WIndowの表示座標


def Window(num):
    layout = []
    for i in range(num - 1):
        layout.append([sg.Input(default_text=g_value[i], size=(100,1))])

    layout.append([sg.Input(size=(100,1))]) 
    layout.append([sg.Button("追加")])

    return sg.Window("TEST", layout, location=g_window_pos)


while True:
    boot_window = Window(num)

    while True:
        event, values = boot_window.read()

        if event == sg.WIN_CLOSED:
            sys.exit()

        if event == "追加":
            num += 1
            g_value = values
            g_window_pos = boot_window.current_location()

            boot_window.close()
            break
~~~~
あくまでInputボックスを増やす最低限しか書いていないので、その後の処理とかループ抜け処理などは各自で

# 解説
普通に考えたら、最初に生成するLayoutに追加のInputをappend　→　windowを再起動で動きそうだが、
通常、layoutにて記載した要素はIDが固定されてしまうようで、使いまわしができないらしい
~~~diff_python:Add_Input_Fail.py
-import PySimpleGUI as sg
-import sys
-
-
-layout = [[sg.Input(size=(100,1))]]
-layout.append([sg.Button("追加")])
-
-
-boot_window = sg.Window("TEST",layout)
-while True:
-    event , values = boot_window.read()
-
-    if event == sg.WIN_CLOSED:
-        sys.exit()
-
-    if event == "追加":
-        layout.append([sg.Input(size=(100,1))])
-        boot_window.close()
-        boot_window = sg.Window("TEST",layout)
~~~
↓上記実行後、"作成"ボタンを押した際に出るエラー
![input_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983357/4e82f580-71a0-d4e5-1828-3b6453445b41.png)

というわけでlayoutを使いまわす手段にてこずっていたところ
下のGithubの最後のコメントにPySimpleGUI様公式からやり方がかかれていたのでありがたく参考にさせていただいた
(Githubでの def make_window を 上コードでの def Window にて参考)

https://github.com/PySimpleGUI/PySimpleGUI/issues/362


また、本コードではInputボックスを追加するために一度現在出しているWindowを閉じ、再度開きなおす処理が行われる
この際、Windowが開いていた座標、Windowに入力されていた情報を変数に入れておくと使い勝手が向上する
(上コードでの "g_value" , "g_window_pos")


# あとがき
初投稿なので読み辛い点あるかと思いますがお手柔らかにお願いいたします


# 参考文献
https://github.com/PySimpleGUI/PySimpleGUI/issues/362

https://www.pysimplegui.org/en/latest/

https://qiita.com/Qiita/items/c686397e4a0f4f11683d#%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E3%81%AE%E5%9F%8B%E3%82%81%E8%BE%BC%E3%81%BF
Splunk: データ無しの場合でも値を表示したい

Splunk でたまに使用するのでメモ。

###### 実施環境： Splunk Free 8.2.2

Splunk でデータを加工する場合、通常先頭の部分でデータの検索条件を指定し、その後で統計処理を行ったり値の表示形式を加工したりします。

```Splunk:Splunk
source="/var/log/hawkey.log"
| stats avg(date_hour)
```

![スクリーンショット 2021-10-03 21.40.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/89564e34-e742-aa08-eae2-0af04d688149.png "データ有り")

この先頭の検索において条件にヒットするデータが存在しない場合、後続の処理によっては最終的な結果が出力されないことがあります。

```Splunk:Splunk
source=""
| stats avg(date_hour)
```

![スクリーンショット 2021-10-03 21.41.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/fc9183c8-f45d-bea3-d344-c6e22a6ec682.png "データ無し")

単発のサーチならこれでも問題ないかもしれませんが、視覚エフェクトも出力されないため、ダッシュボードで可視化している場合等は少々不都合なことがあります。

そのような場合にどうすればよいかというと、 makeresults コマンドでダミーデータを作成して、それを append コマンドで連結するという方法があります。

```Splunk:Splunk
source=""
| stats avg(date_hour) AS Avg
| append
    [ | makeresults
      | eval Avg = 0
      | fields - _time
    ]
```

![スクリーンショット 2021-10-03 21.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/cde4e0c8-19d1-28c7-bd1d-3b1ae3175b59.png "ダミーデータ付与")

無論、データ有りの場合はこのダミーデータは邪魔になりますので、ダミーデータ追加後の処理で適宜加工をする必要があります。

```Splunk:Splunk
source="/var/log/hawkey.log" 
| stats avg(date_hour) AS Avg
| append
    [ | makeresults
      | eval Avg = 0
      | fields - _time
    ]
| sort - Avg
| head 1
```

![スクリーンショット 2021-10-03 21.56.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/22557443-390a-e9f1-f360-aed6fcde8071.png "ダミーデータ排除")

特に先頭の単一値のみを使用する「Single Value」のような視覚エフェクトであれば、ソートしたりすることで容易にダミーデータの排除が可能な為、この方法が有用です。
『エクストリームプログラミング』感想

:::note warn
書籍の感想です。
:::

# 読んだ本

『エクストリームプログラミング』

著者：Kent Beck、Cynthia Andres
訳者：角 征典
発行所：オーム社

https://shop.ohmsha.co.jp/shopdetail/000000004303/

# 感想や学び

## XPはソーシャルチェンジ

> "エクストリームプログラミング（XP）は、ソーシャルチェンジである。[^1]

[^1]:第１章 XPとは何か

この「ソーシャルチェンジ」という表現がピンと来ないのですが、一番最後にある訳者のあとがき読むとイメージできました。

> "隣の席にいるプログラマーとうまくコミュニケーションしたり、顧客と密接にやりとりをしたり、ユーザーが安心して使えるソフトウェアを届けたりする。そうした「人間関係」を扱う活動こそが、エクストリームプログラミングである。"[^2]

[^2]:訳者あとがき

ソフトウェア開発は人間の活動であり、そこで活動する人々の関係も含めて改善していくのがエクストリームプログラミング、というイメージです。

## 価値、原則 > プラクティス

> "あらゆるソフトウェア開発の状況や文脈を網羅したプラクティスの一覧は存在しない。あなたも必要に応じて、新しいプラクティスを作ることになるだろう。"[^3]

[^3]:第５章 原則

プラクティスの中には、今やXPにかかわらず浸透しているものもあります。プラクティスは価値や原則よりも変化しやすいので、たびたび振り返って適切なプラクティスにアップデートする必要があると思います。

## テイラー主義の社会構造

> "ソフトウェア開発において、品質、アーキテクチャ、フレームワークが重要ではないと言っているわけではない。むしろ逆だ。あまりにも重要なので、テイラー主義の社会構造に委ねるべきではないのである。。" [^4]

[^4]:第１８章 テイラー主義とソフトウェア

ソフトウェア開発はそれに適する構造がある。私のイメージはスポーツチームに近いです。ソフトウェア開発のパフォーマンスを重視するのであれば、良いコミュニケーションとフィードバックを生む構造を模索する必要があります。

## 誰のためのXPか

> "私はプログラマーの生活をよくするためにXPを体系化した。" [^5]

[^5]:第２５章 結論

XPチームに含まれる人たちを見てみると、開発に近い人はもちろん、経営幹部や人事、さらにはユーザーも含まれています。[^6] チーム全体とって良い結果になって初めてプログラマーの生活もよくなるのだと思います。

[^6]:第１０章 XPチーム全体

## まとめ

私は剣道経験者なのですが、剣道は勝敗だけではなく立ち振る舞いも重視される武道です。XPも技術だけではなく、人間性も重視している点で近いものを感じました。

最後に一番印象に残っている言葉です。

> "あなたの肩書が何であれ、ソフトウェア開発との関係がどのようなものであれ、「ソフトウェア開発には現状よりずっと大きな可能性がある」ことを私はメッセージとして伝えたい。"[^7]

[^7]:第８章 始めてみよう

私が『エクストリームプログラミング』を読んだのも、この「可能性」を模索してのことなので、このメッセージには非常に共感できるものがあります。この書籍を読んだことで引き続きより良い環境、製品、そしてプログラマーを求めるモチベーションにもなりました。

# おまけ：イベント「XPエクストリームプログラミング入門」

ちょうど読み終わったタイミングで「現場から学ぶモデル駆動の設計」グループでXPのイベントが実施されました。

https://modeling-how-to-learn.connpass.com/event/261859/

## XPのメタファーは「車の運転」

チーム全体が一台の車を運転する一蓮托生の状態が表されていると思います。コミュニケーションとフィードバックがパフォーマンスにつながるイメージがしっくりきます。

## エクストリームまで行くとこうなる

「エクストリームか、そうでないか」の２極ではなく、駆け出しからエクストリームまで幅があるという見方が良いですね。
すぐにエクストリームに成れるわけではないし、エクストリームに至れてないから悪いわけではないと思います。
@shopify/shopify-api: Cannot read property 'initialize' of undefinedの解決方法

# はじめに
Shopifyの[公式ライブラリ](https://github.com/Shopify/shopify-api-node)を使いOAuth認証・認可→アクセストークン取得をしようとしたとき、***公式ドキュメント***通りでは動かなかったので、その対処法を残しておきます。

# 環境
- **実行環境**
    - OS：Windows 11 Home 21H2
    - 言語
        - Node.js
            - version: 16.11.1
        - npm
            - version: 8.0.0
    - 使用しているライブラリ・フレームワーク
        - Express
            - version: 4.18.1
        - @shopify/shopify-api (shopify-api-node Shopify公式のライブラリ)
            - version: ^5.0.1

# 解決法だけ知りたい方
  ```js:index.js
    // 下記の公式ドキュメントの書き方（エラーが起きる）
    // import Shopify, { ApiVersion } from '@shopify/shopify-api'
    // 下記だと動く
    import { Shopify, ApiVersion } from '@shopify/shopify-api'
  ```
# やろうとしたこと
- [公式ライブラリ](https://github.com/Shopify/shopify-api-node)を使って、OAuth認証を行いアクセストークンを取得する。
- 取得したアクセストークンでAdmin APIを叩く。

# エラーの発生原因
- 発生原因
[公式ライブラリ](https://github.com/Shopify/shopify-api-node)を使って、Shopify.Contextを初期化するメソッド(initialize)を呼ぼうとしたら、`unidefined`が返ってきてしまう。
→Shopifyオブジェクトの***インポート***が上手くできていない。

公式ドキュメントの[解説](https://github.com/Shopify/shopify-api-node/blob/main/docs/getting_started.md#set-up-context)では、`Shopify`オブジェクトを***デフォルトインポート***するようになっているが、これでは***動かなかった***。(以下コードとエラー画面)

***ソースコード***（公式ドキュメントから引用）
```js:index.js
    import express from 'express';
    import Shopify, { ApiVersion } from '@shopify/shopify-api'; // ここが間違っている
    require('dotenv').config();

    const app = express();

    const { API_KEY, API_SECRET_KEY, SCOPES, SHOP, HOST, HOST_SCHEME } = process.env;

    Shopify.Context.initialize({
      API_KEY,
      API_SECRET_KEY,
      SCOPES: [SCOPES],
      HOST_NAME: HOST.replace(/https?:\/\//, ""),
      HOST_SCHEME,
      IS_EMBEDDED_APP: {boolean},
      API_VERSION: ApiVersion.{version} // all supported versions are available, as well as "unstable" and "unversioned"
    });
```
***エラー画面***
```js
Shopify.Context.initialize({
                ^
TypeError: Cannot read property 'initialize' of undefined
```
# 解決方法
- デフォルトインポートから名前付きインポートに変えると動く。
    - [こちら](https://github.com/Shopify/shopify-api-node/issues/139)のGithub Issueを参考にしました。

***コード***
  ```js:index.js
    // 下記の公式ドキュメントの書き方（エラーが起きる）
    // import Shopify, { ApiVersion } from '@shopify/shopify-api'
    // 下記だと動く
    import { Shopify, ApiVersion } from '@shopify/shopify-api'
  ```
- ***名前付きインポート***でインポートすると動きました。
    - Githubの[コード](https://github.com/Shopify/shopify-api-node/blob/main/src/index.ts)を見てましたが、デフォルトエクスポートされていたので、なぜ公式ドキュメント通りだと動かないのかは分かっていません。
    - わかる方がいましたら、コメント欄で指摘していただけると幸いです。

# 参考資料
[参考にさせていただいたGithub Issue](https://github.com/Shopify/shopify-api-node/issues/139)
[ライブラリの公式Docs](https://github.com/Shopify/shopify-api-node/tree/main/docs)
[JavaScript(ES6)のインポート方法](https://jsprimer.net/basic/module/)
Jettyってなんだ、Nettyってなんだ。

### Jettyってなんだ、Nettyってなんだ。
Jetty も Netty も本質は同じですが、各所でいろいろな言葉で説明をされているようです。

> Jetty is a lightweight highly scalable java based web server and servlet engine.

[Jetty - Project description](https://github.com/eclipse/jetty.project#project-description)

> Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.

[Netty - Netty Project](https://github.com/netty/netty#netty-project)

私は、Jetty も Netty も Java 向け Web サーバーエンジンなのだと解釈をしています。

### Jetty と Netty の違い
Jetty と Netty の違いやパフォーマンス性に関しては各所で取り沙汰されているので、あえて詳しく書く必要はなさそうですね。

簡単に言うと、

- Jetty：軽量でミニマムな HTTP サーブレットコンテナを提供する
- Netty：ノンブロッキングに gRPC、Apache Spark、Cassandra などによる分散処理を行える

ものと整理をしました。

選択の場面があったなら、Jetty か Netty で選ぶというより、サービスのユースケースやフレームワーク選びに付随して決まってくるのかなと思います。
torchvision.modelsのpretrainedが非推奨になっていた


有名どころのモデルの実装と学習済みの重みを1行で取得できる`torchvision.models`モジュールは大変便利で、特に転移学習の際に重宝します。

https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html

上記チュートリアルではバックボーンネットワークとしてResNet18を使用しています。`pretrained`をTrueにすることで、自動で学習済みの重みがDLされ、そのまま使うもよし、最終層を弄って転移学習に用いるもよしです。

```python
from torchvision import models
model_ft = models.resnet18(pretrained=True)
```

ただし、torchvisionのバージョンが0.13以降の場合、以下のような警告が出るようになりました。

```
/usr/local/lib/python3.7/dist-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and will be removed in 0.15. The current behavior is equivalent to passing `weights=ResNet18_Weights.IMAGENET1K_V1`. You can also use `weights=ResNet18_Weights.DEFAULT` to get the most up-to-date weights.
  warnings.warn(msg)
```

`pretained`引数は0.13以降、非推奨になっており、0.15で削除される予定だそうです。
多くのサイトでは上記のコードで解説されていますので、そのうちアップデートが必要になるでしょう。新しいクラス仕様をチェックしたいと思います。

## まずは修正

親切な警告文の通りソースを修正しましょう。
アップデートに伴い、DLできる重みも細分化されました。

pretrainedと同じ結果を得たい場合は、`resnet18`の引数に`weights=ResNet18_Weights.IMAGENET1K_V1`または`weights=ResNet18_Weights.DEFAULT`を与えます。

非推奨の引数である`pretrained`を用いている場合、互換用のデコレータを介し、`weights=ResNet18_Weights.IMAGENET1K_V1`を引数にとった`resnet18`がインスタンス化されていました。
今後、この互換用のデコレータが除去されるハズですので、古い記述を見たら、以下の新しい書き方に脳内変換しましょう。

```python
from torchvision import models
# pretrained=Trueと同等のモデルを呼び出したい！
# 1. 明示的に重みを指定
model_ft = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1)
# 2. DEFAULTでもIMAGENET1K_V1を指す
model_ft = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
```

これで警告が消えました。
名称からもわかる通り、重みの中身はこれまで（~0.13）と同じくImageNetを用いたモノです。

## 定義済みの前処理（transforms）を利用する

学習済みモデルの利用に関する機能変更は、警告文で示されている内容以外にも存在します。

`ResNet18_Weights.IMAGENET1K_V1.transforms`で推論時に用いるtransformを呼び出すことができます。学習時の実装をのぞくことなく、学習時と同様の前処理を簡単かつ正確に行うことができるようになりました。

```python
from PIL import Image

trnsfrm = models.ResNet18_Weights.IMAGENET1K_V1.transforms()
img = Image.new("RGB", (320, 240), (0, 128, 255))
tnsr = trnsfrm(img)
```

## その他の学習済みモデル

全てのモデルを確認してはいませんが、他の学習済みモデルでも同様の仕様になっているようです。

例えば、転移学習でよく使用されるVGG16では`pretrained`に代わり、以下の引数が用意されています。

https://pytorch.org/vision/master/models/generated/torchvision.models.vgg16.html#torchvision.models.VGG16_Weights

* VGG16_Weights.DEFAULT: デフォルトを指定した場合は、`VGG16_Weights.IMAGENET1K_V1`を指します。
* VGG16_Weights.IMAGENET1K_V1: ImageNetを用いてトレーニングされた重みパラメータ
* VGG16_Weights.IMAGENET1K_FEATURES: classifierモジュール（全結合部分）の重みパラメータが無効値（nan）の重みパラメータ。分類問題には使用できません。

VGG16_Weights.IMAGENET1K_FEATURESは全結合部分の重みパラメータが存在しません。名前からしても、特徴量マップのみ使用したい場合に使うのでしょうか。


その他のモデルついては、使用するモデルのドキュメントを参照し、正確な引数を調べてみてください。

https://pytorch.org/vision/master/models.html
ApsaraVideo Liveを調べてみた　～SDK編～

前回の[API編](https://qiita.com/cube8080/items/d8c923b27f1f0d5331d7)に続いて、今回はApsaraVideo LiveのSDKについて調べてみました。

# SDKの種類
ApsaraVideo LiveのSDKは大きく分けて3種類あります。
* Server SDK
    * 4言語のSDKが準備されています
* Push SDK
    * 廃止予定のプッシュSDKがあるので注意が必要です
* ApsaraVideo Player SDK
    * さまざまなプラットフォームでのオーディオとビデオの再生をサポート
        * ライブストリーミング用のPlayer SDKとVOD用のPlayerSDKはApsaraVideo Player SDKに統合されました

# Server SDK
Server用SDKは4言語用意されています。
* Java
    * Alibaba Cloud Core SDKとApsaraVideo Live SDKに依存関係があります
        * インストール時に両者のバージョンを確認する必要があります
            * 2022/5/19時点
                * Alibaba Cloud Core SDK:4.4.6
                * ApsaraVideo Live SDK:3.9.0
* Python
    * Python2.7以上インストールされている必要があります
    * コマンドでAlibaba CLoud Core SDKとApsaraVideo Live SDKをインストールします
        * インストールはコマンドで実行しますが、pipが必要になるのであらかじめインストールされているか確認しましょう
            * Pythonのバージョンによっては標準で付いている場合があります
* PHP
    * PHP5.5.0以上インストールされている必要があります
    * コンポーザーとしてalibabacloud/liveが必要です
* .NET
    * .NET Framework4.5以上インストールされている必要がある

# Push SDK
* Push SDKはApsaraVideo Liveクライアント向けのストリームインジェスト開発ツール
    * CDNやオーディオ/ビデオリアルタイム通信技術がベースとなっている
    * Push SDK自体は無料
* Push SDKライセンス
    * Ver4.4.2以降のSDKを利用する場合はライセンスが必要
    * ライセンスはメールに必要事項を記入し申請する必要がある
        * 詳細は[こちら](https://www.alibabacloud.com/help/en/apsaravideo-live/latest/alilive-sdk-license#section-8tl-2ju-97v)
    * 対応しているOSはiOSとAndroid
        * それぞれのOSに対応したSDKが用意されている
* RTS(Real Time Streaming)プロトコルを利用したストリームの取り込み
    * RTSと標準ストリーミングの違いについては[こちら](https://www.alibabacloud.com/help/ja/apsaravideo-live/latest/differences-between-rts-and-standard-streaming)

# ApsaraVideo Player SDK
* 用意されているSDKの種類は5つ
    * Web用
        * HTML5プレーヤーやFlashプレーヤーで利用することを想定
            * IEなどHTML5プレーヤーに対応していないブラウザに対してFlashプレーヤーを利用する
        * 動作対応しているブラウザの種類とバージョンの確認が必要です
            * [HTML5プレーヤー](https://www.alibabacloud.com/help/en/apsaravideo-for-vod/latest/apsaravideo-player-sdk-for-web-overview#section-j37-fbq-tqk)
            * [Flashプレーヤー](https://www.alibabacloud.com/help/en/apsaravideo-for-vod/latest/apsaravideo-player-sdk-for-web-overview#section-r5y-n3p-o5e)
    * Android用
        * Android 4.3以降
        * 携帯電話プロセッサ
            * ARM v7
            * ARM64
        * 開発環境
            * Android Studio
    * iOS用
        * iOS 8.0以降
        * 開発環境
            * Xcode
    * Flutter用
        * Flutterバージョン：3.3.0
        * Dartバージョン：2.18.0
        * OSバージョン：Android5.0以降
        * 携帯電話プロセッサ
            * armeabi-v7a
            * arm64-v8a
        * 開発環境
            * Android StudioまたはVS Code
    * Windows用
        * 開発環境
            * Visual Studio2017以降
            * Qtプラグイン
                * バージョン5.12.9
                
# まとめ
ApsaraVideo Liveを利用する環境に対応したSDKが準備されています。
利用可能な言語も4種類用意されているので、様々なシーンを想定して開発しやすいかと思います。
しかし、.NETが.NET Coreではなく.NET Frameworkを利用しているので、.NET Coreへの移行など今後の課題として出てくるのではないかと感じました。

# 参考サイト
* [SDK Reference](https://www.alibabacloud.com/help/en/apsaravideo-live/latest/sdk-reference)
header関数でリダイレクトしてみる

# phpの「header」をつかってみた
header関数が優秀だったのでメモに残しておきます

# 使い方
※使う前に注意点↓
**headerを使うときは上にhtmlを書くことができない**

```php:sample.php
<?php
header("Location:./main.php");
    exit();
?>
```
と記述します。
これを実行するとmain.phpに飛ぶことができます。
`exit();`と記述することでこれ以降のコードを実行しないようにしています。
Phalcon（Volt）についてメモ（if、for、include）

## Voltの構文でよく使うもの
### if文
【使用例】
```
{% set fruit = 'lemon' %}

{% if fruit === 'apple' %}
    <p>アップル</p>
{% elseif fruit === 'ｌemon'%}
    <p>レモン</p>
{% else %}
    <p>グレープ</p>
{% endif %}
```

【結果】
```
レモン
```

### for文
【使用例】
```
{% set fruits = ['apple','grape','lemon'] %}

{% for key, fruit in fruits %}
    <p>{{ key }}：{{ fruit }}</p>
{% endfor %}
```
【結果】
```
0 ： apple
1 ： grape
2 ： lemon
```
ちなみに`key`はインデックスが必要なければ特になくてOK。
JavaScriptの`for...in`と同じような構文。

今のところif文、for文あれば大丈夫そう。

### 外部ファイルを読み込み
サイトの１ページの記述量が多い場合にはページ内のセクションごとにファイルを分けるなどしておくと、可読性がよく再利用や修正もしやすいですね。
また複数人で改修を加えた場合に、セクションで分けていればGitHubでコンフリクトなどもしづらいです。
【index.volt】
```
-- ヘッダー
{% include 'ファイルディレクトリ/ファイル名A.volt' %}
-- メイン
{% include 'ファイルディレクトリ/ファイル名B.volt' %}
-- フッター
{% include 'ファイルディレクトリ/ファイル名C.volt' %}
```
### 外部ファイル読み込み時に条件判定もやりたい
- with ['key':'value']でキーと値を渡して上げればよい
- ファイル呼び元

【index.volt】
```
{% include 'ファイルディレクトリ/ファイル名A' with ['key':'value'] %}

・記載例
{% include 'ファイルディレクトリ/ファイル名A' with ['color':'red'] %}
```
- ファイル呼び先(記載例)
【color.volt】
```
{% if color === 'red' %}
    <図形の色を赤にする>
{% elseif color === 'blue' %}
    <図形の色を青にする>
{% elseif color === 'yellow' %}
    <図形の色を黄色にする>
{% endif %}

```

ファイル読み込みに関して「partial文」、「include文」もあるので軽く触れておく。
- partial
    - Voltと他のテンプレートエンジンで作成されたテンプレートをインクルードすることができる
    - 他のビューのコンテンツを動的に含めることができる、変数のような式を渡すことができます
- include
    - コンパイルされたコンテンツをビューにコピーしてパフォーマンスを向上させる
    - Voltで作成したテンプレートのみインクルードできる
    
用途に応じて使い分けが必要

## メモを書いた背景
最近PhalconというPHPのフレームワークを使うプロジェクトに関わることになったため、
実務で使った構文をメモした。

ただし、フロント側の実装が現状メインでありPHP側の実装にはあまり触れてないため、
Voltについてがメイン（PHP側を触り始めたら書く）

## Phalconとは
とはいえPhalconについても調べて簡単に書いておく。
公式のGitHubのREADME.mdを読むと
```
Phalcon is an open source web framework delivered as a C extension for the PHP language providing high performance and lower resource consumption.
```

直訳すると、
PhalconはPHP言語のC拡張として提供されるオープンソースのWebフレームワークであり、高いパフォーマンスと低いリソース消費を提供します。
とある。
https://github.com/phalcon/cphalcon

バージョンとしては最近Phalcon5が発表され現時点で`v5.1.1`まである。
現場でもPhalcon4→Phalcon5へのアップデートを行なっている。
自分は他タスクでバージョンアップには携われていないので落ち着いたら整理したい。
namespaceなどが大きく変わった模様
アップグレードについてのドキュメントは以下参照
https://docs.phalcon.io/5.0/ja-jp/upgrade

## Voltについてのメモ
- そもそもVoltって？
    - PHPのためにCで記述された、とても早いテンプレート言語
    - 拡張子`.volt`ファイルにHTMLと混在し記述できる
    - Voltによるビューは純粋なPHPコードにコンパイルされるので、基本的には手でPHPコードを書く労力を節約することができる
     
Laravelでいう`blade`にあたるものなのでLaravelで`blade`を書いていればすんなり書けるかなと思います

今回はこのくらい。
PHP側の実装にしっかり着手したらそちらも整理したい。

## 関連サイト
- 公式GitHub
    - https://github.com/phalcon/cphalcon

- Phalcon5へのアップグレードについて
    - https://docs.phalcon.io/5.0/ja-jp/upgrade
- Voltテンプレートエンジン
    -https://phalcon-docs-ja.readthedocs.io/ja/stable/reference/volt.html
【AlmaLinux9】CentOS6や7からAlmaLinux9へ行くときに気をつける事

# はじめに
界隈がAdvent callenderで沸く中とある取引と引き換えに記事を書くことになった。(なお取引は不成立)
だがネタがなさすぎるので今回は「Centos6や7からAlmaLinux9にいきなり飛ぶ」という非常にニッチな層にむけた記事を書こうと思う。
とはいえCentOSのサポート終了後なんとなく後継OSが決まらずずるずる来ていて焦っている層は一定数いるはず。
もしこの記事を見てひとりでも「AlmaLinux9いってみるかー」となってもらえたら幸い。
なお本記事では初見でAlmaLinux9をいれて不自由なく通信ができる状態を目指して記載する。
また諸事情によりコンソールが使用できる環境を想定している。
(EC2用は別の記事にする予定)

# インストール
媒体にもよるが多少リッチになったくらいで特筆すべき変更は無し。

# 起動したらやること
### sshに設定を追加する
/etc/ssh/sshd_configに以下の設定を入れる。
これをいれないと他のCentOS6以下のサーバと通信できない。
インストールして「いざ踏み台からssh！」となったときにハマるやつ。
この設定はセキュリティを下げるので本来入れるべきではない。
が、実務として入れないはまず無理な環境のほうが多いはず。
こういうの頑張ると一行に導入がすすまなくなるので必要悪として入れる。
最終的には入れなくてよくなるといいよね(遠い目)

```ruby:ssh設定
update-crypto-policies --set DEFAULT:SHA1
echo "PubkeyAcceptedAlgorithms=+ssh-rsa" >> /etc/ssh/sshd_config
```

### selinuxを止めろ！
RHEL9ではselinuxのdisabledが無効化されたらしいがAlmalinux9ではいままでと同じ手順でdisableできる。
とりあえず止めておこう。用途に沿ってちゃんとするかはあとでいい。

```ruby:selinux設定
sed -i "s/=enforcing/=disabled/" /etc/selinux/config
```

### firewalldを止めろ！
皆様ご存じのとおりCentos7からfirewalldが導入されておりこいつが片っ端から通信を落としてくれる。
AlmaLinux9からiptablesが消えてnftablesに代わっているのでそっちを意識しているとハマりがち。
とりあえず意識して落とす、最終的にfirewalldを使うのかnftablesを使うのかはたまた両方使うのかは後で決めればいい。
なおchkconfigコマンドがなくなっているのでサービスのdisable/enableはsystemctlコマンドを使う事。
ちなみにserviceコマンドは残っているのでstop/startはそのまま使ってもいいお好みで。


```ruby:firewalld設定
systemctl disable firewalld
```

### 再起動
設定をすべて反映する為再起動する。
(shutdownコマンドはちゃんと残っている)

```ruby:再起動
shutdown -r now
```

あとは不自由なく使えるようになっているはず。

#### ちなみにこの環境はあくまで触り始めるための仮の環境であり本番運用に持ち込む際は各々セキュリティを落とすべきところに落としたうえで運用を開始すること！

# 質疑応答編
### yumコマンドないんでしょ？
ある。serviceコマンドと一緒でdnfコマンドにリダイレクトしてくれるのでyum使って大丈夫。
なれてきたら自然とdnfを使うようになるきっと。
あと正直新しくなったコマンドはいちいち勉強して覚える必要はないと個人的に思っている。
少なくとも私たちインフラを触る人間は新しいOSを導入してもCentOS6(場合によっては5とか4も)を触る機会は極端に減らないので。

### netstatないんだが
ある。「net-tools」をyumで入れれば実は使える
ただssコマンドはnetstatとオプション基本同じなので使ってみては。

### /etc/network-scripts配下なにもない・・・。
nmcliかnmtuiを使うことになった
どちらにせよconfigファイル作成してくれるわけでもないのでnmtuiのGUIでいいんじゃないだろうか。
(個人的にあまりいい方向の変更だとは思っていない)

### なんかよくわかんないけどCentosからAlmaLinuxって互換性が心配
本記事を見に来る層でこの質問をしてくる諸兄はいないと思うが一応書いておく。
私はRHELクローン同士の同一性について言及できる立場にはない。
ただ少なくとも私はmemcachedの置き換えは成功させたことがある。
(Centos6:memcached-1.4.22 → AlmaLinux9:memcached-1.6.9)



# Tips
### /etc/sysconfigにファイルはおくな！
いやおいてもいいのだが。
Centos7からサービス管理がsystemctlに変わったがAlmaLinux9でまた変更が加わっている。
/etc/sysconfig/XXXXXXに書いてある変数を読んでくれなくなった。

↓こんなやつ
```ruby:/etc/sysconfig/ntpd
# Dro root to id 'ntp:ntp' by default
OPTIONS="-u ntp:ntp -p /var/run/ntpd.pid -g"
```

詳細は確認予定だが「OPTIONS」という変数をちゃんと読んでくれないように見えている。
(おそらく歴史的経緯があるのだろうが正直そのあたり詳しくない。私/etc/sysconfigつかわない派なので)

ちなみにこの状態でサービスを起動するとプロセス上はコマンドラインオプションが指定されているのに実際は効いていない状態となる。
非常に悪質かつハマり所なので注意されたし。
(刺さる人少なそうだけど)

# あとがき
以前現場でCentos6をAlmaLinux9にしていくというプロジェクトがあり何件か対応したことがあるので記事にまとめた。
元々Centos8を触っていたのもありたかをくくっていたが、やはりメジャーバージョンを3つも飛び越えるとなるとなんだかんだちょくちょくハマる。(大体AlmaLinuxのせいではないが)
少なくとも今回記載した内容を参考にしてもらえればOSの違いに困ることはないはず。
そこから各rpmや動作の違いなど探してもらえればと思う。
冒頭にも書いたが本記事で一人でもAlmaLinux9を触ろうと思ってもらえれば幸い。

なお、今回はコンソールが使える環境(オンプレ)で書いたがEC2になるとまた勝手が違う。
これはまた別途記事にする予定。(予定は未定)
対話的にファジー検索

## fzfに劣る
劣るが、findコマンドだけで動くので、別途なにかコマンドなどを入れる必要がない。
この程度ならその場でさくっと作れるので、覚えておくと損はないと思う。

関連
[100行でfzf](https://qiita.com/neras_1215/items/5f58e10d3ba3b846b51b)

## 仕組み
inputdialogを使用する

①キーワードを入力させ
②find結果を表示し、選択させる

と2段階の対話になるので、普通に関数を用意するだけでは足りない。

```.vim
" fzf like
fu! FzfPatternExe() abort
  echo execute('pwd')
  let inarr = split(inputdialog("Enter [ext] [pattern]>>"), ' ')
  if len(inarr) !=  2
    echo 'break'
    retu
  endif
  let fzf_cmd = 'find ./* -iname "*' . inarr[1] . '*.' . inarr[0] . '"'
  echo 'searching ... [ ' . fzf_cmd . ' ]'
  let fzf_res = split(system(fzf_cmd), '\n')
  echo '_________________________'
  for v in fzf_res
    echo index(fzf_res, v) . ': ' . v
  endfor
  echo '_________________________'
  let ope = len(fzf_res) == 0 ? '' : inputdialog("choose >>")
  exe ope == '' ? 'echo "break"' : 'e' . fzf_res[ope]
endf

```

## 結果
地味に便利だが、fzfがあるならそれでいい。ない時に仕方なく使える技術
《ゴミbye-bye day》ゴミ・資源の曜日を教えられるツール(pc用)

### WHYこのプロトタイプ（企画）？
仕事や学校生活が忙しすぎて、外にゴミを出す曜日忘れてしまい経験、みなさんありますか？
ゴミ量が少なかった時には大丈夫ですが、多かった時にが迷惑になります。
燃えやすいゴミであれば、よく匂いがあります。
資源は匂いがないが、家の大きな角を占領されます。
また、陶ガ金を出す日は、１ヶ月２回しかいないので、自分はあまり覚えられません。
そのため、すぐに出す曜日・日を教えてくれるプロトタイプを制作しました！

### TeachableMachineについての紹介
Teachable Machineは、AI(人工知能)の機械学習ツールであります。
画像、音声、とポーズを学習させましたら、判別用のモデルを作成することができます！
 `https://teachablemachine.withgoogle.com/ `

### ゴミbye-bye dayの機能紹介
自分が住んでいる所のスケジュールはこんな感じです↓
| 分類      | 収集曜日　      | 
|:-----------|------------:|
| 燃やすごみ    | 火・金       |
| 陶ガ金 　  | 第2・4 月      |
| 資源       | 土        |

以上のスケジュールによる、ゴミbye-bye dayを作成しました。

### code-penのembed
最初の苦戦したのはJavaScriptの書き方でした。
カメラに映っても、分類と曜日が出てこませんでした。
結局はJavaScriptのcodeを修正でき、
分類と曜日がちゃんと出てくるようになりました！
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="vYrpqrY" data-user="3luulm" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/3luulm/pen/vYrpqrY">
  ゴミbyebye day-Teachable Machine + ml5.js2</a> by 3luulm (<a href="https://codepen.io/3luulm">@3luulm</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### (補足)Nelifyのリンク
`https://precious-tarsier-845ea1.netlify.app `
### (補足)実際に動く動画
<blockquote class="twitter-tweet"><p lang="qme" dir="ltr"><a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/teachablemachine?src=hash&amp;ref_src=twsrc%5Etfw">#teachablemachine</a> <a href="https://t.co/lex1aQJWq5">pic.twitter.com/lex1aQJWq5</a></p>&mdash; W. Hsu (@winniexedge) <a href="https://twitter.com/winniexedge/status/1595399146013601792?ref_src=twsrc%5Etfw">November 23, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 感想
###### Point 1
JavaScriptのcodeが長くないのに、一番時間かかりました。
より中身を理解できるため、オンライン授業を取りたいと思います。
###### Point 2
手元にあるゴミは限界がありますので、
これから、TeachableMachineによりゴミのサンプルを読み込みます。
そうしましたら、識別できる幅も広くなれると思います。
Vimで快適なgit生活を送る

# はじめに

gitを使いソフトウェアを管理することは多いです。
今回はVimに依存することで、git生活をより快適に送るTipsを紹介します。


## 1. git commit実行時のテンプレートにprefixを追加する

commitメッセージを書く際にprefixを先頭に書くことは多いです。
よく使うprefixなら、commitメッセージを書くときに逐一確認できる環境を作りたいですよね。
gitコマンドを使うことで、git commitを実行した際に特定の文字列をテンプレートとして挿入できます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278618/c0a89335-5f49-8de5-b1be-520f8bc3ef35.png)


コミットメッセージの書き方自体は、以下の記事を参考にしました。

> https://qiita.com/konatsu_p/items/dfe199ebe3a7d2010b3e

```txt

# feat: A new feature
# fix: A bug fix
# docs: Documentation only changes
# style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
# refactor: A code change that neither fixes a bug nor adds a feature
# perf: A code change that improves performance
# test: Adding missing or correcting existing tests
# chore: Changes to the build process or auxiliary tools and libraries such as documentation generation
```

上記のテンプレートを以下のコマンドによって、git commit実行時に追加できます。

```sh
git config --global commit.template ~/.gitmessage
```

see also:
> https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration

## 2. Vimでprefixを補完する環境を作成する

コミットメッセージを書くとき、先頭にprefixを書くことは少なくありません。
これらを毎回手動で入力するのは面倒ですし、ちょっとしたことでプラグインを入れるのも避けたいです。
そこで、Vimの標準機能だけで実現しましょう。

### 2-1. 辞書補完の環境を作成する

Vimには標準で補完機能が搭載されており、プラグインを入れずとも特定のタイミングで補完を使用できます。
今回は標準機能の一種である辞書補完を使い、commitメッセージを書くときのみprefixの補完を有効にします。

see also:
> https://vim-jp.org/vimdoc-ja/options.html#'dictionary'

まず最初に以下のようなファイルを用意しましょう。ここではcommit-prefixとします。

```txt:$HOME/.vim/dict/commit-prefix
feat
fix
docs
style
perf
test
chore
```

次に、辞書補完のリストにcommit-prefixを追加します。
ここでは、git commit時のみに追加したいのでftplugin/gitcommit.vimに以下の設定を記述します。

NOTE: git commit時にVimが立ち上がった場合、filetypeは`gitcommit`になっています。

see also:
https://vim-jp.org/vimdoc-ja/usr_43.html#filetype-plugin

```vim:ftplugin/gitcommit.vim
setlocal dictionary=$HOME/.vim/dict/commit-prefix
```

また、筆者は[gina.vim](https://github.com/lambdalisue/gina.vim)を使って、Vimからコミットメッセージを書きます。
そのため、以下のような設定も追加します。

```vim:ftplugin/gina-commit.vim
setlocal dictionary=$HOME/.vim/dict/commit-prefix
```

これで、prefixを辞書補完できるようになりました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278618/1121deb4-67ca-c75d-e523-a640d3bc842b.png)

ちなみに、辞書補完の入力が大変に感じた人は、以下のブログを参考にすると良いと思います。
> https://daisuzu.hatenablog.com/entry/2015/12/05/002129


## 3. git操作のキーストロークを激減させる

git操作をする際、

1. git status
1. git add
1. git commit
1. git push

とするのが基本の流れです。
しかし、上記の処理は繰り返すことが多いため、できるだけキーストロークは減らしたいです。
筆者は、[gina.vim](https://github.com/lambdalisue/gina.vim)に依存することでキーストロークを減らしています。

## 3-1. 使わないキーをgit操作に割り当てる

筆者の場合、カーソル移動の際に矢印キーを使いません。そのため、←↓↑→の4つのキーが余っています。
これをそのままgit操作に割り当てます。

```vimrc
nnoremap <Up> :Gina status<CR>
nnoremap <Down> :Gina commit<CR>
nnoremap <Left> :Gina diff<CR>
nnoremap <Right> :Gina grep<CR>
```

これにより、よく繰り返す操作をたった1回のキー入力で達成できます。

see also:
> https://twitter.com/get_me_power/status/1201516375103008769

## 最後に

興味のある方は是非試してみてください。