OmniAICreator/Qiita-1.07M huggingface dataset:
ブートアンロック ってなに？

## 勉強前イメージ

rebootするのを防止する機能？
rootでもロックできるとかってこと？

## 調査

### ブートアンロック とは

スマートフォンやタブレットで電源をつけた際に元々インストールされているOSを起動させないようにすることです。
root化を行うときに使用されることが多いです。

※root化 とはスマートフォンなどシステムでは元々管理者権限(root権限)はユーザが使えないようにしています。
その管理者権限を使えるようにして通常では出来ない機能の拡張やファイルシステムのアクセス権の変更などを行うことが出来ます。

ブートはブートローダーのことで、スマホやPCなどのシステムで最初に起動するプログラムです。
ブートローダーがOSの起動を行います。
このブートローダーをロックします。

ブートローダーをあんロックすると、セキュリティ上のリスクが増えるのでAndroidでは強制的に初期化が走ります。

## 勉強後イメージ

なるほど、root化するときのやつか。
あれってブートローダーでデフォルトのOSを起動させないってことだったのね。
正直良くわかってなかった。

## 参考

- [【TIPS】ブートローダーアンロックしたらどうなるの？｜ディープなAndroidの世界を楽しむ](https://gaddet.com/bootloaderunlock/)
独自形式の実験データファイルをpandasで読み込む

[公式ドキュメント](https://pandas.pydata.org/docs/reference/api/pandas.read_table.html)をちゃんと読めばわかる話だったのだが，探し方が悪くなかなか見つからなかったので備忘録としてまとめる．

## 実験データを読み込む

Pythonでテーブルデータを扱うときはpandasのDataFrameとして読み込むことが多い．

測定機器が吐き出した実験データはちゃんとしたCSVにはなっているとは限らず，機器ごとに様々な形式を取っている．
「最初の5行にだけ余分なことが書いてあって6行目からテーブルデータになっている」のように要らない箇所が予めわかっていれば`header=6`のようにすれば良いが，状況によって行数が変わる場合はいちいち行数を確認するのは面倒である．

以下のように実験データの前後に一定の行頭符号が付いた付加情報が加わったファイルを読み込むときは，`comment`に行頭文字を指定すればその行は飛ばして読み込まれる．

```text:実験データ
*RAS_DATA_START
*RAS_HEADER_START
*DISP_FMT_X "%.4f"
......
*MEAS_SCAN_UNIT_Y "counts"
*RAS_HEADER_END
*RAS_INT_START
10.0000 7.3333 1.0000
10.0100 6.3333 1.0000
......
79.9900 3.5834 1.0000
80.0000 4.7499 1.0000
*RAS_INT_END
*RAS_DATA_END

```



```python
# import pandas as pd

df = pd.read_table(
    file_name,
    comment="*",          # コメント開始の文字を1文字で指定
    encoding="shift-jis", # encoding は毎度明示的に指定したほうが良い
    sep="\s+",            # 空白区切りならこのように指定する
    header=None
)
```

※1 `read_table`と`read_csv`はデフォルト引数が違う以外は同じ動作をする（はず）のでどちらでも良い．テーブルデータなので`read_table`の方がわかりやすい気もする．
※2 このデータはXRDの測定データ．

参考： [pandasで#行を無視して読み込む](https://qiita.com/illumination-k/items/d76c5a80a796839908af) 

## 文字列オブジェクトを直接読み込む

Python上のstringオブジェクトを直接pandasに読み込ませたい場合は`io.StringIO`でラップするとできる．

例えばREPL環境で直接データをコピペしたとか(※3)，テーブルデータが`"[Start Data]"`と`"[End Data]"`の間に記述されているのでこの間を取ってきたという(※4)文字列がある場合は

```python
# import io
# import pandas as pd

# ファイルから読み込んで文字列として保持
with open(file_name, mode="r", encoding="shift-jis") as file:
    s = file.read()

# START_STR から END_STR までを clip する
START_STR = "[Start Data]"
END_STR = "[End Data]"
t = s[s.find(START_STR)+len(START_STR)+1: s.find(END_STR)]

# 文字列を DataFrame に変換
df = pd.read_table(
    io.StringIO(t),
    sep="\s+",
    header=None
)
```

のようにすれば良い．

※3 クリップボードから直接読み込む `pandas.read_clipboard` が存在するのでそれだけならこれを使ったほうが良い．
※4 単純にclipしたいだけなら無視する行番号を`skiprows`で指定できるが，skipする行を全部渡す必要があるしファイルに2度アクセスすることになるのでどちらが早いかは微妙．
※5 CSVは意外とコーナーケースがある（クォーテーションや区切り文字を含むデータなど）ので置換などを行う場合は注意が必要．

参考： [<Python, pandas> pd.read_csv() でコメントアウトの行を読み込まない](https://nekoyukimmm.hatenablog.com/entry/2015/12/24/155429)
nuxt.jsで特定のページでのリロード対策

## コード

```js
<script>
export default {
  destroyed () {
    window.removeEventListener('beforeunload', this.confirmReload)
    window.removeEventListener('unload', this.confirmAfterReload)
  },
  mounted () {
    window.addEventListener('beforeunload', this.confirmReload)
    window.addEventListener('unload', this.confirmAfterReload)
  },
  created() {
    if(localStorage.getItem('reload-flg')) {
      localStorage.removeItem('reload-flg')
      this.$router.push('/dummyUrl') → ここに遷移させたいURLを記載
      return
    }
  },
  methods: {
    confirmReload (event) {
      event.returnValue = 'このサイトを再読み込みしますか？'
    },
    confirmAfterReload () {
      localStorage.setItem("reload-flg", true)
    }
  }
}
</script>

```

localstrageを使用して力技で、画面遷移させました。。！
(ちなみにモードはSPAです)

vuexで状態管理していたらリロードされた場合に、
画面遷移させたいケースって結構ある気がしますが、
みなさんどうしているのだろうか？？
サイバー犯罪条約 とは

## 勉強前イメージ

条約ってどっかの国と結ぶイメージがある。。。。
日本がどっかと結んでるのかな？

## 調査

### サイバー犯罪条約 とは

ブタペストで署名されたので通称ブダペスト条約とも言われます。
この条約は日本語の正式名称では `サイバー犯罪に関する条約` で
国境を超えた、コンピュータやサイバー攻撃による犯罪に対応する国際条約になります。
日本は2012年に正式加盟しました。
ヨーロッパ諸国・アメリカ・オーストラリアなどが加盟している。

この条約はサイバー犯罪から社会を保護することを目的としていて全48カ条あります。
違法アクセスやオンラインの詐欺などサイバー犯罪の刑事化や
データの保全・傍受などの手続き、また国際的な捜査協力や犯罪者引き渡しなどのことが記載されています。

## 勉強後イメージ

とりあえず、

- 国際的なサイバー犯罪とかあったら協力していこうね
- サイバー犯罪とか刑事事件化できるようにしようね

みたいなことが書かれてるってことかな？
今は66カ国が締結国みたい。多いくらいなのかな？

## 参考

- [国際組織犯罪に対する国際社会と日本の取組](https://www.mofa.go.jp/mofaj/gaiko/soshiki/cyber/index.html)
- [サイバー犯罪条約](https://kotobank.jp/word/%E3%82%B5%E3%82%A4%E3%83%90%E3%83%BC%E7%8A%AF%E7%BD%AA%E6%9D%A1%E7%B4%84-508298)
ModelDebugOptionsComponent メモ

### ModelDebugOptionsComponetとは
割と新しくできたRealityKitの新機能。

HasModelプロトコルに準拠したオブジェクトなら全て使用できる。
これはレンダリングのデバックを可視化するもの。
さまざまな種類でレンダリングのレイヤーを可視化することができる。


デバッグの種類
あんまり全てを理解できてないけど、3Dモデルをインポートしたときに意図してないテキスチャになったりするときに
ここで細かく設定してデバックするっぽい。

```swift
case none
// ビジュアライゼーションを表示しないモード。
case normal
// 法線ベクトルを色で表示するモード。
case tangent
//表面の接線ベクトルを色で表示するモード.
case bitangent
//表面のビタンジェントベクトルを色で表示するモード.
case baseColor
//ライティングやマテリアルプロパティが適用されていないエンティティのベースカラーを表示するモード。
case textureCoordinates
//テクスチャ座標を色で表示するモード。
case finalColor
//透明度を無視して、エンティティの計算された色を表示するモード。
case finalAlpha
//エンティティの計算された透明度をその表面色として表示するモード。
case roughness
//素材のツヤを表面色として表示するモード。
case metallic
//エンティティの反射率を表面の色として表示するモード。
case ambientOcclusion
//計算されたアンビエントオクルージョン値をサーフェスカラーとして表示するモード。
case specular
//エンティティの光沢を表面色として表示するモード。
case emissive
//マテリアルの発光チャネルを表面色として表示するモード。
case clearcoat
//マテリアルのクリアコートチャネルを表面色として表示するモード。
case clearcoatRoughness
//材料のクリアコート粗さチャネルを表面色として表示するモード。
case lightingDiffuse
//エンティティに当たる間接光の強度を表面の色として表示するモード。
case lightingSpecular
//エンティティに当たる直接光の強度を表面の色として表示するモード。
```
Google Spread SheetとBigQueryの同期（スプレッドシート→BQ）

# はじめに
Googleドライブに作ったGoogleスプレッドシートをBigQueryに同期させて、スプレッドシートが更新されるとBQにも反映されるという状態を作ります。

## 注意：BigQueryから更新はできない
この方法で作ったBigQueryのテーブルは、クエリで更新できません。Selectのみです。
↓こういうエラーが出ます。
> DML statements are only supported over tables that have data stored in BigQuery. Unsupported table: bigquery-nlp:spread_sheet_test.sp_sync

BigQueryにあるものしか更新できませんよ、ということ。つまりBigQueryとしては、Googleドライブ上にあるデータのショートカット的なイメージ。

ちなみにSelectするときの見積もりもよく見ると、、、費用かからないのかも。これって、そこそこのシステムだったらGoogleドライブを利用すれば、BQ料金をかけずにBQを使えるということか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/f5aac941-30fb-3501-569b-b9700ac376d8.png)

スプレッドシートは更新できますよ。

# 手順

## 1. Googleドライブにスプレッドシートを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/aa8c9c33-aa87-45b8-8722-4736522f0496.png)
適当ですみませんｗ

ここで、URLをコピーしておきます。

## 2. BigQueryでテーブル作成

テーブルを作成するときに、「ソース」をドライブ、「ドライブのURI」にスプレッドシートのURL、「ファイル形式」にGoogleスプレッドシートを入れます。
テーブル名は適当に、あとスキーマは自動検出でもいけるし、指定もできます。

詳細オプションで、「スキップするヘッダー行」は、`1`とかに変更します。これはデータの始まりの行、と読み替えてもいいです。データに使わない行をスキップするという意味で、これをデフォルトの`0`のままにしておくと、列名としている`id`とかもデータとして入っちゃいます。

## 3. 完成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/199913a1-ebb8-251a-f6c9-0c62048883bc.png)

クエリも普通に書けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/cfa321fb-a453-1c37-a37f-17fabb02e8a4.png)

スプレッドシートを更新すると、勝手にBigQueryのテーブルも更新されます。というか、二重に持っているわけではなく、スプレッドシートのデータをBigQueryが見に行っているから、当たり前なんですが。

スピードはわかりません。さすがにBigQueryにある状態よりは遅いんじゃないかなぁ。


# おわりに
わかってれば特に難しいことはないです。

## 注意点①：BigQueryで更新できない

最初に書いた通り、このテーブルをSQLで更新することはできません。スプレッドシートからBigQueryの一方通行です。

まったく別の方法ですが反対に、BigQueryのデータをGoogleスプレッドシートで表示することはできます。これも一方通行です。

## 注意点②：遅いかも
スピードは遅いかもしれません。でもスプレッドシートで管理するようなデータ量なので、スピードは求めるようなものではないとは思います。
ZFXY を使った静岡ボクセルタイル: データ処理の構造

[三次元空間ID候補ZFXY](https://github.com/unvt/zfxy-spec)を使って静岡県点群データをボクセルタイルに変換する処理の構造についてメモをしたものです。
[![social preview image](https://repository-images.githubusercontent.com/486959106/bca54707-85e8-4b0f-bb0e-93814d3eea61)](https://x.optgeo.org/blocks/#18.32/35.100454/138.858969/-39/72)

# リポジトリ
https://github.com/optgeo/blocks

# 基本的な生産の流れ
1. las データの各点を
1. MAZXOOMでのZFXYコードに変換し
1. それをMINZOOMまでのZFXYコードに換算し
1. 重複は取り除けるようにSetにpushした上で、
1. それぞれのZFXYコードについてGeoJSONに変換し
1. うまい具合にモジュール分割しながらTippecanoeに名前付きパイプで繋ぎ、
1. 全データをpushご、名前付きパイプを順次閉じることで、Tippecanoeの後段処理を順次起動してMBTilesファイルのセットを作る。

# 主要なパラメータ
DZ: ZFXYと、それを週のするタイルとのズームレベルのシフト量
MZ: モジュールのズームレベル

# パラメータチューンの履歴
- DZ は 6 にしてちょうど良い感じである。
- MZ は 10 から初めてみたが、12 にした。10 ではモジュールのサイズが大きくなりすぎる印象があった。
kerasでカスタムレイヤ内に重みを複数追加する場合は名前を指定した方が良い


# はじめに
タイトル通り。
研究しているときに遭遇した問題とその直し方について共有。


# なぜ必要なのか
kerasでカスタムレイヤを作ったとき、`tf.Variable`あるいは`self.add_weight`をつかって重みを追加し、`model.save_weights`で`h5`を指定すると次のようなエラーが発生する。


```py
import tensorflow as tf

class Preprocess(tf.keras.layers.Layer):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.mean = tf.Variable(tf.reshape([0.485, 0.456, 0.406], (1, 1, 1, -1)),
                                dtype=tf.float32, trainable=False)
        self.std = tf.Variable(tf.reshape([0.229, 0.224, 0.225], (1, 1, 1, -1)),
                               dtype=tf.float32, trainable=False)

    def call(self, inputs):
        return (inputs - self.mean) / self.std
    

def gen_model():
    inputs = tf.keras.Input(shape=(None, None, 3), name='vgg_input')
    x = Preprocess(name='preprocess_layer')(inputs)
    output = x = tf.keras.layers.Conv2D(32, (3, 3), padding='same',activation='relu')(x)
    model = tf.keras.Model(inputs, output)
    return model
    
gen_model().save_weights('bad_model.h5')
```

```text
ValueError: Unable to create dataset (name already exists)
```

# 原因
kerasがやっているhdf5の保存方法はシンプルで、各レイヤの名前を元にh5のkeyを決めて保存している。
例えば、vggのh5の中身を見るとこんな感じで保存されている。

```text
block1_conv1
block1_conv1/block1_conv1
block1_conv1/block1_conv1/bias:0 (64,)
block1_conv1/block1_conv1/kernel:0 (3, 3, 3, 64)
block1_conv2
block1_conv2/block1_conv2
block1_conv2/block1_conv2/bias:0 (64,)
block1_conv2/block1_conv2/kernel:0 (3, 3, 64, 64)
block1_pool
...
```

`kernel`と`bias`は`Conv2D`の重み。それぞれに`bias:0`の名前と`kernel:0`という名前が割り当てられている。
どこで付けられているかは、[githubを参照](https://github.com/keras-team/keras/blob/0bba5b1349f56f74f936f3447f4b4a5cc2c9a250/keras/layers/convolutional/base_conv.py#L220)。

では、上で紹介したモデルでは、どうなっているかというと

```python
print(gen_model().get_layer('preprocess_layer').weights)
```

```text
[<tf.Variable 'preprocess_layer/Variable:0' shape=(1, 1, 1, 3) dtype=float32, numpy=array([[[[0.485, 0.456, 0.406]]]], dtype=float32)>,
 <tf.Variable 'preprocess_layer/Variable:0' shape=(1, 1, 1, 3) dtype=float32, numpy=array([[[[0.229, 0.224, 0.225]]]], dtype=float32)>]
```

つまり、**異なる重みに対して同じ名前が割り当てられる**ため、nameが重複してh5が保存できなくなってしまっている。

# 解決策
nameを指定すればok。

```python
class Preprocess(tf.keras.layers.Layer):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.mean = tf.Variable(tf.reshape([0.485, 0.456, 0.406], (1, 1, 1, -1)),
                                dtype=tf.float32, trainable=False, name='mean')
        self.std = tf.Variable(tf.reshape([0.229, 0.224, 0.225], (1, 1, 1, -1)),
                               dtype=tf.float32, trainable=False, name='std')
...
```

```text
[<tf.Variable 'preprocess_layer/mean:0' shape=(1, 1, 1, 3) dtype=float32, numpy=array([[[[0.485, 0.456, 0.406]]]], dtype=float32)>,
 <tf.Variable 'preprocess_layer/std:0' shape=(1, 1, 1, 3) dtype=float32, numpy=array([[[[0.229, 0.224, 0.225]]]], dtype=float32)>]
```

# おわりに
ちなみに、h5指定ではなくckpt指定にすると上のエラーは出ずに保存できます。
ただckptは複数ロードするとエラーが出まくるので、デバッグとか含めてh5の方がやりやすいです。
いいね(lgtm)せずにfollowする人の行動を分類

followしてくださる方のFollower数が３１人の方がすごい確率がいて、なんでってなった。

followしている順番が、ほとんど同じ人がいて、なんでってなった。

こんなにfollow順番が似てるのってどういう現象＝偽識別子

https://qiita.com/kaizen_nagoya/items/ea0de85a2e5fbcbdd06e

どういう組織が、何を目的で、Qiitaの本来の目的でIDを作成するのではない事態が進行しているらしい

# いいね(lgtm)せずにfollowする人の行動を分類

ちょうど、followしてくださるのはありがたいのですが、
どの記事にもいいね（lgtm）せずに、followしてくださる方の行動が読めずにいて、
なんだろうって何年か前から思っていた。

今回は、新たな分類かもしれないし、以前からそういうIDを確保している方はそれなりにいたのかもしれない。
あるいは、Qiitaが何をするところかわからないが、SNS系のIDをいろいろ蓄えて、何か行動を起こそうと思われている人たちがいるのかもしれない。


35000通知で、300人近くのfollowerで、70人ほどをブロックさせていただいた。

何人かは、他の方にはいいねを押されていたり、タグをいくつかいいねされていたりしていて、Qiitaの本来の目的に沿った行動をされているようにもお見受けした。

31という数字と、followする順番が似ているので、申し訳ないがブロックさせていただいた。

## 記事を書くのは手間だ。

比率として50%までは、どんな集合でもROM(read only member)がいても困らないというのが経験則。一人のWom(write only member)で、一人のROMが対応してもかまわないから。

ROMが３分の２を超えたあたりから、集団の健全性に疑問符をつけたくなる（個人の仮装です）。ROMが9割りを超えたら、身の回りの人は書き込む人を半分程度になるように働きかけ、自分の周りだけは、自分の想定する集合の性格を保持させようと努力するかもしれない。

## いいねするのは面倒だ

じゃ、followするのは面倒じゃないのがなぜかがわかっていない。

## followはしたい。
ああ、他のSNSでの行動経験を踏襲しているのかもしれない。
いいねは目立つがfollowはめだたないSNSがあったような気がする。知らんけど。


# その他

順番に思いついたり、思い出したりしたら書かせてください。
背景となる心理に踏み込む余裕はありません。行動分類に専念します。

心理学の本を読むよりはコンパイラ書いた方がよくね。仮説（34）

https://qiita.com/kaizen_nagoya/items/fa715732cc148e48880e

空気読まない・空気読みたくない・空気読むの？・空気読めない・空気読もうとも思わない。仮説(75)

https://qiita.com/kaizen_nagoya/items/8cb7a81950ed23737e79

プログラマが違和感を感じたときにするとよいこと。仮説（148）

https://qiita.com/kaizen_nagoya/items/f32ae742655621b309fb

プログラマはどれくらい人付き合いしないといけないか。仮説（47）

https://qiita.com/kaizen_nagoya/items/88e73104370cfd5eeb6c


人間が計算機に勝てる３つのこと。忘れる、あきらめる、やめる

https://qiita.com/kaizen_nagoya/items/49dc709d289d22846044
デジタル一眼をPCで制御

PCにカメラがなかったので、使っていないEOS M3をwebカメラとして使えないか実験中。

# 計算環境

|項目|値|
|---|---|
|CPU|Intel Core i5-3320M|
|Ubuntu|20.04|
|ROS|noetic|
|Camera|Canon EOS M3|

#カメラとの接続
EOS購入時についてきた付属のコードでPCとカメラを接続し、電源ON

# コード
```
#gphoto2のインストール
sudo apt  install gphoto2
```
```
#接続されているカメラの確認
gphoto2 --auto-detect
```
下記のように表示され、認識されていそう
```
型式                         ポート                                            
----------------------------------------------------------
Canon EOS M3                   usb:003,004    
```

まずは撮影しようとすると
```
#カメラ撮影
gphoto2 --capture-image
```
下記エラーが発生。
```
*** エラー ***             
An error occurred in the io-library ('Could not claim the USB device'): Could not claim interface 0 (デバイスもしくはリソースがビジー状態です). Make sure no other program (gvfs-gphoto2-volume-monitor) or kernel module (such as sdc2xx, stv680, spca50x) is using the device and you have read/write access to the device.
エラー: Could not capture image.
エラー: 取り込みできませんでした。
*** エラー (-53: 'Could not claim the USB device') *** 
```

gvfs-gphoto2-volume-monitorが問題ということで、現在実行中のプロセスを表示
```
ps aux | grep gphoto
```

```
name         977  0.0  0.2 255084 22644 ?        Ssl  09:49   0:00 /usr/libexec/gvfs-gphoto2-volume-monitor
name       17166  0.0  0.1 435440 13704 ?        Sl   19:20   0:00 /usr/libexec/gvfsd-gphoto2 --spawner :1.3 /org/gtk/gvfs/exec_spaw/8
name       18013  0.0  0.0  10092   720 pts/0    S+   19:25   0:00 grep --color=auto gphoto
```
ということで、問題のプロセスを停止
```
kill -9 977
```

無事に撮影できました。
```
gphoto2 --capture-image-and-download
```
【manコマンド】英語から日本語へ

# 目標
```
$ man echo
```
を実行したとき写真のように **日本語** で出力されるようにする
![スクリーンショット 2022-06-04 18.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693266/4927c78b-f722-2e1a-2e8b-5395d53cbbdb.png)

# 環境
```
$ sw_vers
ProductName:	macOS
ProductVersion:	12.4
BuildVersion:	21F79
```

# やり方
#### 1.groffをインストール
Macには最初から入っているので[Homebrew](https://brew.sh/index_ja)で最新版 にする
```
$ groff -v
GNU groff version 1.19.2

$ which groff
/usr/bin/groff
```
```
$ brew install groff

$ groff -v
GNU groff version 1.22.4

$ which groff
/opt/homebrew/bin/groff
```

#### 2.manの設定を変更
```
$ sudo vim /etc/man.conf

96行目をコメントアウトし、代わりに追加
# JNROFF        /usr/bin/groff -Tnippon -mandocj -c
JNROFF          /opt/homebrew/bin/groff -Dutf8 -Tutf8 -mandoc -mja -E

107~108をコメントアウトし、代わりに追加
# PAGER         /usr/bin/less -is
# BROWSER       /usr/bin/less -is
PAGER           /usr/bin/less -isr
BROWSER         /usr/bin/less -isr
```
:::note warn
行数がわからない時
```
:set number
```
と打ち込む
:::

#### 3.[JM Project](http://linuxjm.osdn.jp/download.html)から日本語manページをダウンロードし、解凍

最新版のチェック（写真の場合: man-pages-ja-20220515.tar.gz）
![スクリーンショット 2022-06-04 19.05.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693266/7c02d669-3308-fa3b-9e4b-852bb4bcbf15.png)
ダウンロード
```
$ cd ~/Downloads
$ curl -O http://linuxjm.osdn.jp/man-pages-ja-20220515.tar.gz
```
解凍
```
$ tar xfz man-pages-ja-20220515.tar.gz
```
#### 4.解凍したディレクトリに移動し、makeを実行
(打ち込むところが多いので見比べながらやる)
```
$ cd man-pages-ja-20220515
$ make config
perl -w script/configure.perl
[INSTALLATION INFORMATION]
(just Return if you accept default)
   Install directory   [/usr/share/man/ja_JP.UTF-8] ?: /usr/local/share/man/ja_JP.UTF-8
   compress manual with..
      0: none
      1: gzip
      2: bzip2
      3: compress
   select [0..3] : 0
   uname of page owner [root] ?: Macのユーザー名
   group of page owner [root] ?: admin

   Directory:    /usr/local/share/man/ja_JP.UTF-8
   Compression:  none
   Page uid/gid: Macのユーザー名/admin

All OK? (Yes, [C]ontinue / No, [R]eselect) : c


[INSTALL PACKAGE SELECTION]
(just Return if you accept default choice)
(you can change the default by editing script/pkgs.list)

ここ全部 y を入力

All OK? (Yes, [C]ontinue / No, [R]eselect) :　c


[RESOLVE CONFLICTS]
(just Return if you accept item 0)
   [0/163] There are 2 pages for basename.1:
    0: in GNU_coreutils
    1: in gnumaniak

ここ全部 0 を入力

All OK? (Yes, [C]ontinue / No, [R]eselect) : c


creating installation script...done
now you can "make install" as user Macのユーザー名.
```
スーパーユーザーになり、インストールする

```
$ su
Password:🗝
sh-3.2# make install
```
:::note warn
Sorry とでる時
```
$ su
Password:🗝
su: Sorry
```
新規パスワードを設定
```
$ sudo passwd root
Password:
Changing password for root.
New password:
Retype new password:
```
:::

#### 5.環境変数LANGを確認
```
$ echo $LANG
ja_JP.UTF-8
```
ja_JP.UTF-8 じゃない時
```
$ LANG="ja_JP.UTF-8"
```

# 確認
写真のとおりになったよーって方はLGTMお願いします
```
$ man echo
```
![スクリーンショット 2022-06-04 18.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2693266/5c3448ce-ea95-1e54-5b26-903450274c43.png)

# 参考
https://zenn.dev/kumamoto/articles/d536ac6df8a544

https://izumii19.hatenablog.com/entry/2018/11/27/171545
Expressのリダイレクト

# Expressのリダイレクトでハマった
ExpressのアプリケーションでSEO対策のため、リダイレクト処理を実装する必要があった。
ページのリダイレクトをするために`res.redirect('http://example.com')`と書いたら、
ステータスコードが302でリダイレクトされた。

## デフォルトのステータスコードが302
Expressでは、`res.redirect`で指定しないとデフォルトで302になる。
もし、301でリダイレクトしたい場合は、`res.redirect(301, 'http://example.com')`と指定する必要がある。

## 気になったこと
他のRailsの`redirect_to`やLarabelの`Route::redirect`でもデフォルトが302でリダイレクトされていた。
自分の感覚では、リダイレクトは301がデフォルトというなんとなくのイメージがあり、確認不足であった。

ちなみに、
* 301 : 恒久的な転送
* 302 : 一時的な転送

であるため、それを考えると確かにアプリケーションの中で使うリダイレクト処理は、
一時的な転送が多いと思ったので、納得したという初歩的なメモです。


https://expressjs.com/ja/4x/api.html#res.redirect
https://api.rubyonrails.org/classes/ActionController/Redirecting.html
https://readouble.com/laravel/8.x/ja/routing.html
BigQueryで分かち書き

# はじめに
BigQueryだけで自然言語系の処理をしたいケースがあって、その最小限の方法を調べました。一般的な形態素解析というののちょっと手前の、分かち書きまでです。品詞の特定とか、単語の原型を出さない。
品詞を特定するのは、辞書ファイルが必要で、BigQueryではライブラリから外部のファイルを読むことができなさそうだったので、ひとまず分かち書きまで。

[TinySegmenter](http://chasen.org/~taku/software/TinySegmenter/)というライブラリを使用しました。

# 最初に結果
分かち書きの結果
> 入力：明日は天気が良さそうなので買い物に行きたい
> TinySegmenterの結果：明日 / は / 天気 / が / 良さ / そう / な / の / で / 買い物 / に / 行き / たい

学校ではこの分野は超絶 ~~嫌い~~ 苦手だったので正解はわかりませんｗ
ただ以前、こちらの記事（[kuromojiを使ったJavaScriptだけの形態素解析](https://qiita.com/yo16/items/8800735fef1b267166ef)）で、kuromojiというライブラリで[品詞分解を試せる環境](https://nlp-kuromoji-js.herokuapp.com/)を作ったので、そこに入れてみました。その結果がこれ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/2b3a0e2d-241b-f34d-1293-29db0222177e.png)

分かち書きだけで比較すると、これ↓。まぁまぁいいんじゃないですかね。やっぱ基本形はほしくなるけど。
> 入力：明日は天気が良さそうなので買い物に行きたい
> TinySegmenter：明日 / は / 天気 / が / 良さ / そう / な / の / で / 買い物 / に / 行き / たい
> kuromoji：明日 / は / 天気 / が / 良 / さ / そう / な / ので / 買い物 / に / 行き / たい

# 方法
概要はこうです。
- [BigQueryのユーザー定義関数（UDF）をJavaScriptで定義](https://qiita.com/yo16/items/88addc4779e3c774df8d)で実施したユーザー定義関数で、分かち書きする。
- そのとき、外部のライブラリ（[TinySegmenter](http://chasen.org/~taku/software/TinySegmenter/)）を使う。

## 1. GCSにJavaScriptファイルを置く
[TinySegmenter](http://chasen.org/~taku/software/TinySegmenter/)はダウンロードしておきます。
自分のユーザー定義関数として、下記を作ります。

```javascript:mol_ana.js
const tinySegmenter = new TinySegmenter();

function wakachigaki(sentence){
    return tinySegmenter.segment(sentence);
}
```
グローバルな領域で`TinySegmenter`をインスタンス化しておいて、`wakachigaki()`関数が呼ばれたらそれを使う、というだけ。
この２つのファイルを、GCSへ格納します。

## 2. BigQueryで使う
BigQueryのいつものクエリの画面に入力します。

```sql:クエリ
create temporary function keitaiso1(x string)
returns array<string>
language js as """
    return wakachigaki(x);
"""
options(
    library=["gs://for_bq/tiny_segmenter-0.2.js", "gs://for_bq/mol_ana.js"]
);

select keitaiso1(val)
from UNNEST(['明日は天気が良さそうなので買い物に行きたい']) as val;
```
以前の記事（[BigQueryのユーザー定義関数（UDF）をJavaScriptで定義](https://qiita.com/yo16/items/88addc4779e3c774df8d)）では、ちらっとしか書きませんでしたが、`options()`で、分かち書きライブラリと、自分のコードの２つを呼び出してます。

これだけで、いつもの画面に出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/521b7eb7-bbc8-f67c-6df4-46219e33e392.png)

# おわりに
コードも多くないし、作業量も少なくてさらっとできます。

TinySegmenterは、機械学習で品詞分解をやっているそうで、その再学習をすることもできるようです。

# 参考
- [TinySegmenter](http://chasen.org/~taku/software/TinySegmenter/)
- [TinySegmenterの学習ツールを作ってみた](https://shogo82148.github.io/blog/2012/11/23/tinysegmentermaker/)
- [SQLで始める自然言語処理](https://ymym3412.hatenablog.com/entry/2020/12/24/001923)
忘れ物をした場所が画像判別できるLINE Botを作ってみた

![スクリーンショット (65).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/b8c950d1-9a77-2597-d2b4-9b65babc73a6.png)


こんにちは:grinning:
スーパーマーケット事業で働く会社員です。
普段は教育に携わる仕事をしています。
2回目の投稿となります。うまく伝わるかな・・・。

今回は**Teachable Machine**という画像判別ツールを用いて
何か業務に役立てることはできないかといろいろ考えてみました。

最近はオンラインの研修をする機会がかなり増えてきていますが
**『たまには顔を合わせて交流したい！！』**
私を含めた受講者の思いに応えるべく
少しづつ集合研修も実施しています。
顔を合わせて交流を深めるって大事ですよね。
上機嫌で研修が進み、最後のコマ！
**『研修お疲れさまでした。忘れ物のないようにお帰りくださ～い。』**
実はけっこうな頻度で**忘れ物**ってあるんです:scream:
とりあえず回収して保管しますがどこの会場の忘れ物だったか・・・。
というわけで今回は『**忘れ物をした場所が画像判別できるLINE Bot**』に挑戦！
_____
## 使用ツール　
**■[Teachable Machine](https://teachablemachine.withgoogle.com/)**
**■LINE**
**■[enebular](https://www.enebular.com/ja)**


## こちらが完成品です。
https://twitter.com/Maepon517/status/1532975486070321152

_____
## 使用方法
1.**Teachable Machine**を立ち上げ、会場の画像を取り込む。
（今回は自宅で3方向の画像を取り込み、研修会場を想定しました。）

**会議室1**
![会議室1 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/efd15cd1-a56e-6c50-0493-e50c4dd28c81.png)
**会議室2**
![会議室2 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/15c636e3-f303-576a-7f87-177af031b6d5.png)
**会議室3**
![会議室3 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/035467e4-b45c-42b4-73b7-8999acb95012.png)


2.取り込んだデータを**トレーニング**で学習させて
**モデルをエクスポートする**を選択。

3.生成されたURLをLINE BotのWebhookに貼り付ける。
![スクリーンショット (63).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/ec8d8f41-5d81-0f83-0239-11bb1d9b61f3.png)

4.**enebular**を立ち上げてフローを作成
※仕様はNode Redとほぼ同じです。

![スクリーンショット (56).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670703/c241cde0-7580-a4d1-cc90-ec158857529c.png)

使用ノード（順番にワイヤーで繋ぐ）
　**ネットワーク**　`「http in」`
　**機能**　　　　　`「function」`
　**ネットワーク**　`「http request」`
　**追加ノード**　　`「teachable machine」`
　**機能**　　　　　`「function」`
　**追加ノード**　　`「ReplyMessage」`

5.繋いだら『デプロイ』をお忘れなく！
以上で完了です。

今回作成にあたっては「がおまるさん」の資料
を参考にさせていただきました。

https://atlabo-handson-08.netlify.app/#0

______
## あとがき
研修会場がほぼ決まっている場合は会場の数だけ**Teachable Machine**で
事前に画像を取り込んでおけばLINE Botが返信・記録してくれて便利ですね。
なにより、**Teachable Machine**の画像判別能力の高さに驚きです。
早速、実務で使ってみたいと思います。
とは言いながら忘れ物がないのが一番ですが・・・:sweat_smile:
セレクトボックスの一部の項目を選択できなくする

# 見出し1
JavaScriptでセレクトボックスの一部を動的に選択できなくする方法を記載します。

# コード

```HTML
<select name="selectbox" id="selectbox">
<option value="item1" data-val="0">アイテム1</option>
<option value="item2" data-val="1">アイテム2</option>
<option value="item3" data-val="1">アイテム3</option>
</select>
```


```JavaScript
let items = Array.from(document.querySelectorAll('#selectbox option[data-val="1"]'));
items.forEach(option => option.disabled = true);
```

これでセレクトボックスのdata-valが1の項目が選択できなくなります。
Rails モデルの作成方法メモ

Railsのモデル作成方法の備忘録です。

## 環境
macOS Monterey 12.3.1
ruby 3.1.2
rails 6.1.6

## モデルとは
MVC構造のM。DBとのデータの連携を担当する。

## モデル作成コマンド
```bash:ターミナル
rails g model モデル名 カラム名1:データ型 カラム名2:データ型 ...
```

`g`は`generate`の略。

例: Userモデルを作成する

```bash:ターミナル
rails g model User name:string email:string
```

コマンドにより`app/models`ディレクトリ下にモデルファイル、`db/migrate`ディレクトリ以下にマイグレーションファイルが作成される。

## マイグレーションファイルの確認、修正

コマンドにより作成されたマイグレーションファイルを確認する。

```ruby:(タイムスタンプ)_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end
```
ここでカラム名やデータ型、デフォルト値、NULLを許容するか等を修正する。

```ruby:(タイムスタンプ)_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      t.string :name, :null => false　 #追加
      t.string :email, :null => false　 #追加

      t.timestamps
    end
  end
end
```

:::note warn
カラムの制約はバリデーションと合わせて設定した方が良い。

バリデーションを設定していても `save(validate: false)` などでバリデーションスキップし、予期せぬ値が入ることがあるため、データベースレベルで制約しておくと安全。

参考：https://qiita.com/rockettetsu/items/4d0fc754ab2e2aca7c13
:::

外部キーの設定方法：

https://qiita.com/ryouzi/items/2682e7e8a86fd2b1ae47

## マイグレーションの実行

確認と修正が終わったらマイグレーションを実行する。

```bash:ターミナル
rails db:migrate
```

DBにUserテーブルが作成される。

```bash:ターミナル
== (タイムスタンプ) CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0499s
== (タイムスタンプ) CreateUsers: migrated (0.0510s) =============================
```
Julia の SymPy で連立方程式の解を求めたあとにその値を取り出す

## 環境

- Julia 1.7.2
- SymPy 1.1.4

## 背景

SymPy を使って連立方程式の解を求めたところまでは良かったのですが、その値を取り出すのに苦労したので自分のやりかたを書いておきます。

:::note
コメントで WolfMoon 様に[ご教示いただいた](https://qiita.com/fibered_alto/items/2b8ca5684354772b69d6#comment-b2c32814165dd519454e)のですが、連立方程式を解く際に linsolve ではなく solve を用いれば結果が Dict で戻ってくるようです。その場合は以下のような手順を踏まずとも、もっと楽に結果が取得できます。
:::

以下のようにそのまま取り出そうとするとうまく行きません。

```julia
julia> using SymPy;
julia> @vars x y;
julia> f = x + y - 1;
julia> g = x - y - 3;
julia> results = sympy.linsolve([f, g], (x, y))
{(2, -1)}

julia > results[1]
{(2, -1)}
```

## 方法

results が SymPy の Set なので SymPy で用意されている elements 関数を使うと取り出せます。ただ各要素は Sym 型なので pyobject を取得してから値を取り出すようにします。

```julia
julia> elements(results)
1-element Vector{Sym}:
 (2, -1)

julia> pytuple = first(elements(results)).__pyobject__
PyObject (2, -1)

julia> pytuple[1]
2
```

PyObject のタプルまで変換すればイテレータも使えるようになるので関数への代入も簡単です。

```julia
julia> pairs = Tuple(zip((x, y), pytuple))
((x, 2), (y, -1))

julia> f.subs(pairs)
0
```

もっとスマートな方法があれば是非ご教示ください。
IBM Cloudの新認定試験IBM Cloud Advocate v2を受けてみた

# IBM Cloud Advocate v2とは

IBM Cloudの認定技術者試験の1つで、クラウドコンピューティングとIBM Cloudの基礎を学んだ人向けの最も入門的な試験です。従来はv1でしたが、2022年5月頃にv2がリリースされました。

IBM Cloud Advocate v2に合格すると、IBM Certified Advocate - IBM Cloud v2の認定資格を得ることができます。もちろんOpen Badgeももらえます。

<img width="160" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/6ee80ccd-7ad4-5373-093d-2d4b8dac319d.png">


認定資格および試験の概要はこちらです。

> https://www.ibm.com/training/certification/C9003700

# 学習方法

最も入門レベルということもあって、難易度は低かったです。一応公式ラーニングパスは下記サイトです。

> https://www.ibm.com/training/path/ibmcloudadvocate2022

# 受験方法

PearsonVUE社のサイトで予約して受験してください。

https://www.pearsonvue.co.jp/Clients/IBM.aspx

以前は最寄りのテストセンターでしか受験できなかったのですが、最近はカメラ付きPCがあれば自宅でも受験可能になりました。こういうご時世ですので、可能であれば自宅での受験をお勧めします。ただし部屋の片づけはきちんとしておいてください。私はいつも気分転換を兼ねてテストセンターで受けるようにしています。

# 合格点

65問中39問以上の正解で合格です。正答率は60%です。非常に低めの設定ですので、受験する方はあまり心配する必要はないでしょう。

# 出題内容

試験規約により具体的な問題文は書けませんので、雰囲気になりますが、次のことは理解しておくといいでしょう。

* IaaS,PaaS,SaaSの違い、略語
* Public CloudとPrivate Cloudの違い
* リージョン、ゾーンの意味
* Multi Zone Regionの意味、具体的にどこか
* IBM Cloudサポートプランの違い
* IBM Cloud課金方法の違い
* IBM Cloudコンソールの使い方
* ストレージの種類と用途
* 仮想サーバ、ベアメタルの使い分け
* VPCの特徴、メリット
* SCCは何をしてくれるものか
* Cloud Architect、Cloud Developerの役割
* 利用料の見方
* 予定していた利用料をオーバーした場合の挙動
* Watson Assistant、Knowledge Catalog、Studioは何をするものか
* API Connectの開発コンポーネント
* コンテナとは

# 感想

クラウドコンピューティングやIBM Cloudは全くわからないという人でない限り、わずかな勉強時間で合格できるレベルだと思います。
【やってみた】Shellスクリプトの開発をテスト駆動開発で進めてみよう。

# そびえ立つウォーターフォール

なんだか、ウォーターフォールってイナズマイレブンの技っぽいですよね。

最近、WBSをつくる際に脳死でウォーターフォールっぽく線を引いていることに気づきました。
アジャイルでやるべき！とかウォーターフォールでやるべき！とか、
そういう議論は置いておいて、
流行りの手法にせよレガシーな手法にせよ、一長一短あって、
まだまだ新米の私は、兎に角、理論を経験に昇華させ、その特性を味わっていくしかないよなぁと
ぼんやりと考え、少しウォーターフォールから離れてスケジュールを作成してみました。

具体的には、
V字モデル(詳細設計→プログラミング→単体テスト→結合テスト)を採用していたところを、

① 結合テスト計画を詳細設計の直後へ
② テスト駆動開発(TDD)でプログラミングと単体テストを並行実施

というような考え方で以下の流れに変えてみました。

**詳細設計→結合テスト計画→単体テスト/プログラミング→結合テスト**

（といいつつも、大きな変更ではない気もしますが）
V字モデルでは詳細設計書があればIT仕様書はいらないとかいってますしね、

色々と恩恵とリスクを見つけたので、メモしておこうと思います。

# ① 結合テストの計画を前倒しした効果

これは、恩恵が半端なかったです。

テストケースを作成するところまで実施するのですが、
詳細設計書の抜け漏れの検知はもちろん、
発生しそうなリスクに対応するために設計自体に柔軟性のある設計を意識することができ、
セルフウォークスルー的なQA活動ができました。

[オライリーのDesign it!](https://www.oreilly.co.jp/books/9784873118956/)でも、曖昧性の原則として
最低限の設計をしてFeedback Loopを回す中で、アーキテクチャを成長させていくべきと述べられていますが、
がちがちに縛った設計を回避することができたのは、詳細設計と結合テスト計画を近づけた効果でした。

とはいえ、リスクがないわけではないです。
テストケースをあれこれ掲げすぎると、テストケースに依存した設計になってしまいますし、
意図した効果と正反対のリスクを抱える危険性もあります。この辺はバランスが大切ですね。


# ② テスト駆動開発(TDD)でプログラミングと単体テストを並行実施

ただテスト駆動開発を実践しただけなんで、わざわざ書くのも恐縮ですが。。。笑

とはいえ、シェルはオブジェクト言語たちと違って少し特異なコードの書き方になります。
（変数のスコープとかまじでわかりにくいし。。長くなるし。。）

私は、テスト用スクリプトと開発コードのそれぞれを準備し、
テスト用スクリプトで開発コードを読み込み、開発コード上の関数を呼び出す形で単体テストを実施し、TDDっぽく進めました。

良かった点を列挙すると。。。

**・テストする機能毎でテストケースを書くことで、関数が定義しやすかった。**
→ 関数作成すると、あれも関数化したい！これも関数化できる！とか迷った結果、可読性の失われたコードができがちなんですが、機能ごとにテストすることを決めてプログラミングに入ったので、それに合わせた関数を作成するだけでいいので、切り分けやすかったです。可読性もそこそこ担保で来ている気がします。（過去のものよりは圧倒的に読みやすい。。）

**・テストコードが出来上がり、リグレッションテストを行いやすくなった。**
→ テスト用スクリプトを残しながらワークが進んでいくので、最終的にはテストコードが残ります。出力された結果も比較可能な形にしておくことで、リファクタリングや仕様変更でコード修正があった際にテスト用スクリプトを実施して、結果比較すればリグレッションが完了するようになりました。将来的な工数削減が有難い。。

**・ 新人用の勉強スクリプトができた。**
→ これは完全な副産物です。（笑）
一気にすべてのコードを渡すよりも、レベルに合わせて関数とテストコードを切り出して渡すことで、段階的にシェルの書き方やコマンドを学習していってもらえるなぁと思っています。特に、テストスクリプトがあれば、それをいじりながらハンズオンで進められますしね。（小さい関数のリファクタリングなんかもいいかもですね。）

リスクの方は、TDDでよく語られているものを意識していただきたいです。
特に、テストを書くことが目的になってしまいそうな危険性はあります。
入出力を意識して、テスト設計にできるといいかなぁなんて思います。


# 全体を振り返って

全体を通して、ウォーターフォールで線を引いた時と比較して、
スケジュールが10日くらい前倒しできました。

結合テストの計画を事前に実施しておいたおかげで、
スケジュール自体の見通しが明るくなったことと、テストの準備をちょこちょこ進められたのも、
全体のワークロードを通して負荷を減らすことができたなぁと思います。

とはいえ、前述したようにリスクもありますし、検討しきれていない部分も多々あります。
これから先も、経験していく中で自分の中の成功ファクターとして昇華できるようにしたいなと思います。
SONY Spresense用 TFT LCDドライバーボード

少し前に[Sony Spresense で TFT LCD を動かしてみた](https://qiita.com/kaz19610303/items/7e18d34b29b8f6405916)という記事を書きましたが
今回S**presense拡張ボード**を必要としない、Spresense本体だけでカラーTFT LCDを使えるようにドライバーボードを作りました。
小型のカラーTFT LCDもずいぶん安くなり1000円前後から購入できるようになりました。
今までは安いOLEDを使っていましたが、ほとんどが単色表示しか出来ませんでしたが、これでフルカラー表示が出来るようになりました。

今回作ったボードは **スタッキングピンヘッダ** を実装していますので、通信用のボード等をスタック出来るようになっています。
以下の写真は今回作った**LCDドライバーボード**と **LTE-M通信ボード** **CO2センサー**の組み合わせです。
このセットでCO2濃度、温度・相対湿度を測定してデータをCloudにアップロード出来ます。
かなりの小型化が実現できていると思います。

**Spresense本体にTFT LCDドライバーボードをセット**
![LCD_Dirver_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99249/21ab04fc-b958-3f4e-0376-a3aca6411684.png)

**次にLTE-M通信ボードとCO2センサーボードを追加**
![LCD_Dirver_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99249/c67840d7-dead-7ed7-f4d6-163048f0a507.png)

**横から見たイメージ**
![LCD_Dirver_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99249/43eb6039-e8a3-cdee-a535-04dc87993b6c.png)

**全体像**
![LCD_Dirver_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99249/f468109f-4c5e-c587-0d75-8081198623fe.png)

回路図は[GITHUB](https://github.com/kaz19610303/SPRESENSE_LCD)にアップしています。
サンプルプログラムは「Sony Spresense で TFT LCD を動かしてみた」と同じく
Adafruit-ST7735-Library を使いました。
(今回はST7735を使った表示器でテストしました)

小型TFT LCDは数多く販売されていますが、ピンの配置に統一性が無いので複数の基板を作っています。(現在3種類)
今後もパターンを増やして行く予定です。

短いですが表示サンプルです。
https://www.youtube.com/shorts/MdkEY4RHE2g

現在 Spresense SDK でTFT LCD を使うプログラムに悪戦苦闘中です。
元々Nuttx の知識がないのが原因ですが(泣)
上手く行ったら記事をアップします。
一元配置分散分析の基礎

# 一元配置分散分析の前提条件

一元配置分散分析は、多群の平均値がすべて等しいかどうかを判定する検定法であり、一つの要因のみが群間で変わる場合を扱います。データからF値を計算し、F値とF分布からp値を計算し、p値が十分に小さいとき、平均値がすべて等しいとする帰無仮説が棄却され、平均値が異なるとする対立仮説が採択されます。

一元配置分散分析は以下を仮定しています。
・観測値は独立
・各群は正規分布に従う
・全ての群の分散は等しい
ここで観測値が独立とは無作為標本であることをいいます。

# 具体的な計算手順

一元配置分散分析を行うには、まず群間平方和SFと残差平方和SEを計算します。
```math 
SF = N\sum_i ( \bar X_i - \bar{\bar X})^2 \\
SE = \sum_i \sum_j ( X_{ji} - \bar{ X_i} )^2
```
ここでNは、各群のサンプルの数です。$X_{ji}$は、各列に各群のサンプルが入った行列です。群の数はM、各群のサンプルの数はNです。このとき群間の自由度は(M-1)です。残差の自由度は(NM-M)です。この自由度を用いてF値を計算します。
```math 
F値 ={SF / (M-1) \over SE / (NM-M)}
```
このF値は各群の平均が等しいとき自由度((M-1),(NM-M))のF分布に従います。平均が異なるとF値は大きくなります。
以上のF分布とF値から上側のCDFを計算してP値とします。P値が十分小さいとき各群の平均が等しいとする帰無仮説が棄却されます。

# 一元配置分散分析のmatlabのコード

上記の手順で一元配置分散分析を行うmatlabのコードです。
matlabの関数anova1の結果と一致しています。

```matlab
clear all; close all;

%テストデータを生成します。
N = 20; % データの数
M = 3; % 水準の数
X = zeros( N, M );
for i = 1:M
    X(:,i) = randn( N, 1 ) + i;
end

% 各群の平均を計算します。
xbar = mean( X, 1 );

% 総平均を計算します。
xbarbar = mean( xbar, 2 );

% 総変動を計算します。
ts = 0;
for i = 1:M
    ts = ts + sum( (X(:,i)-xbarbar).^2, 1 );
end

% 群間変動を計算します。
fs = N * sum( ( xbarbar - xbar(1,:)).^2, 2 );

% 群内変動を計算します。
es = 0;
for i = 1:M
    es = es + sum( ( xbar(1,i)-X(:,i)).^2, 1 );
end

fprintf( ' 総変動　%f　群間変動 %f　群内変動 %f　群間変動 + 群内変動 %f \n', ts, fs, es, fs+es );

fs = fs / ( M-1);
es = es / ( (N * M)-(M) );

fvalue = fs/es;
pv = fcdf( fvalue, (M-1), (N * M)-(M), 'upper' );
fprintf( ' 一元配置分散分析のp値 %f \n', pv );

anova1( X )
```

# 総変動と群間変動、残差変動の関係

総変動と群間変動、残差変動の間には以下の関係があります。
```math 
\sum_i \sum_j (X_{ji} - \bar{\bar X})^2 = SF+SE
```
一元配置分散分析は、総変動がどの程度群間変動で説明するか調べる方法であると言えます。
access2000の作法 その23

# 概要
access2000の作法、調べてみた。
テーブルにリレーションシップを設定してみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/1a9f3ee3-86c6-7869-c270-b4a8c103d447.png)

# リレーションシップボタンを作る手順。
- menuフォームを右クリック。
- デザインビューを開く
- ボタンを設置
- ウィザードが開く  キャンセル
- プロパティシートを開く
- イベントを開く
- クリック時、コードビルダーを開く
```

Private Sub コマンド17_Click()
    relation "会派", "議員", "ID", "会派コード", "relation1"
End Sub

Sub relation(T_main As String, T_sub As String, K_main As String, K_sub As String, K_name As String)
    Dim db As DAO.Database
    Dim rel As DAO.relation
    Dim fld As DAO.Field
    Set db = CurrentDb
    Set rel = db.CreateRelation(K_name, T_main, T_sub)
    rel.Attributes = dbRelationDeleteCascade + dbRelationUpdateCascade + dbRelationLeft
    Set fld = rel.CreateField(K_main)
    fld.ForeignName = K_sub
    rel.Fields.Append fld
    db.Relations.Append rel
    Set db = Nothing
    MsgBox "ok"
End Sub
```
- フォームを閉じる
- 保存する


以上。
TECH CAMP 0日目

# はじめに
アパレル企業からIT企業に転職するために、テックキャンプの受講を決めました。
私は第127期（2022/06/06~2022/8/14）ですので、同期の方や、すでに卒業されている方、受講を考えている方と繋がれれば良いなと思います。よろしくお願いします。

## 投稿内容
1. 学習内容、１日の振り返り
1. 苦労した点-改善
1. （月曜日）今週の目標
1. （金曜日）今週の振り返り
Vue.jsの開発メモ#1

# 今日のメモ
- homebrew, nodebrew, node.js のアップデート
- Githubで remote repogitoryの作成
- Terminalでvue-cliのインストール (npm install -g @vue/cli)
- vue create ファイル名
- vue-class-component, vue-property-decoratorとは
- Nuxt.jsについて
- Universal mode(SSR), SPA mode, 

# vue-class-componentとは
TypeScript（.tsファイル）でコンポーネントが書けるようになる。
Componentデコレータをつけて，Vueを継承したクラスとして書く

# SSRとは
SSRとは,従来のブラウザ側（クライアント側）で実行されHTMLを描画するJavaScriptをサーバー内部で実行し,HTMLを描画するもの. また、UniversalはSPAでもあるため、ページ遷移などに関しても申し分がなく、爆速.

# Nuxtプロジェクトの立ち上げ

　To create nuxt project:

        npx create-nuxt-app nuxt-test
To get started:

        cd nuxt-test
        npm run dev

  To build & start for production:

        cd nuxt-test
        npm run build
        npm run start

  To test:

        cd nuxt-test
        npm run test
[画像処理] 画像に枠線を付ける

# はじめに

画像に枠線を付ける方法を整理します。

# やりたいこと

下記のように単純に画像に枠線を付けることです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/c7490db9-6dab-efeb-793a-cb18eb43d2d9.png)

用途ですが、画像の中の物体の輪郭を取るとき、白い枠線があると上手く行くケースがあります。


# 方式
Numpyのスライスを使います。

例えば、(128, 128, 3)サイズの画像があって、一番下の部分に幅10pxの白いラインを書きたいとします。
すると下記のようなコードになります。

``` python

img[128 - 10 : 128 , : , : ] = 255

```

チャンネルごとに値を入れることをお勧めします。
この方式だとカラーの枠線を入れることが可能です。OpenCVで画像を開いた場合、チャンネル順序が(B,G,R)になっていることには注意してください。

``` python

img[128 - 10 : 128 , : , : ] = [255, 255, 255]

```

このような処理を4辺に繰り返し行います。
draw_white_edge()の関数を使います。

引数として、下記の二つを指定します。

band_width : 枠線の幅、単位はピクセル
color : [B,G,R] 範囲 0~255 整数　


# 全体コード
簡単ですね。コードを掲示します。

``` python
import cv2


def draw_white_edge(img, band_width=10, color = [255, 255, 255]):
    # Image is aligned in BGR order.
    # color or Gray Scale
    if len(img.shape) < 3:  # gray scale
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    else:
        pass

    # Check the image size
    height, width, channel = img.shape[0], img.shape[1], img.shape[2]

    # Image copy
    img_test = img.copy()

    # Image process
    # 1. bottom line
    img_test[height - band_width:height, :, :] = color
    # 2. top line
    img_test[0: band_width, :, :] = color
    # 3. left line
    img_test[:, 0:band_width, :] = color
    # 4. right line
    img_test[:, width - band_width:width, :] = color

    return img_test


def main():
    print('Welcome to my program!')
    img_array = cv2.imread('./images/apple.jpg')

    img_result = draw_white_edge(img=img_array, band_width= 50, color= [255, 0, 255])
    cv2.imshow('original', img_array)
    cv2.imshow('result', img_result)
    cv2.waitKey(0)


if __name__ == '__main__':
    main()


```

#結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/7acf5642-8929-80fa-b967-3eca4065fa81.png)
Django+Reactで学ぶプログラミング基礎(1): ゴールと概要

## はじめに

`Django+React`のアプリ開発を、手を動かして体験しながら、
`プログラミング基礎`も楽しく身につける、を目指しています。

## 構築予定のWebアプリ

カンバン方式のタスク管理アプリを作成します。
以下機能を実現します。

- カンバンボードで、リストとカードを使ってタスク進捗を可視化
    - ボードに付箋を貼るようにカードを並べ
    - 進捗状況に合わせ、`Todo`、`Doing`、`Done`リストに振り分ける
- ボード上で可能な操作
    - リスト/カードの作成/編集
    - リスト内でカード移動
    - リスト間でカード移動
- ユーザーログイン/管理

## プログラミング基礎の内容

- 要件定義
- 基本設計
- フローチャート
- シーケンス図
- ER図
- オブジェクト指向(クラス)

## 使用する開発言語やツール

- 開発言語
    - Python
    - JavaScript
    - HTML
    - CSS
- Webアプリケーションフレームワーク
    - Django(バックエンド) 
    - React(フロントエンド)
    - Redux(フロントエンド)
- データベース
    - MySQL
- その他開発ツール
    - Python関連コマンド
    - OS関連コマンド
    - Visual Studio Code

## Djangoとは

Wikipediaから、[Django(ジャンゴ)](https://ja.wikipedia.org/wiki/Django)とは

- Pythonで実装されたWebアプリケーションフレームワーク
    - Webアプリケーション開発に必要な機能が予め用意された骨組み
    - 目的は、Web開発で用いられる共通した作業に伴う労力の軽減
- MVCデザインパターンに緩やかに従う
    - Model-View-Controller(MVC、モデル・ビュー・コントローラ)とは
        - UIを持つソフトウェアに適用されるソフトウェアアーキテクチャの一種
        ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/3cd25391-bf6f-9342-9b32-e5570241e1f4.png)
- Djangoの目的
    - 複雑なウェブサイト構築を簡単に
- Djangoの機能
    - コンポーネントの再利用性
    - プラガビリティ(pluggability)
        - 外部ライブラリ/フレームワーク/追加機能を組み込むこと
    - 素早い開発
    - DRY原則(Don't repeat yourself)
- データベース管理の`CRUD`インターフェイスを提供
    - CRUDとは、Create/Read/Update/Delete
    - インタフェースは動的生成され、データモデル定義により完全構成可能
- Djangoのコンポーネント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/e360f294-68ba-275c-80a3-c5c0519c9ba5.png)
※ 引用元: https://djangobook.com/django-tutorials/beginner-lesson-2-how-django-works/
    - Djangoフレームワークのコア部分
        - O/Rマッピング(O/Rマッパー/ORM)
            - データモデル(Pythonクラス)とリレーショナルデータベースの間を仲介
        - 正規表現に基づくURLディスパッチャ
        - リクエストを処理するビューシステム
        - テンプレートシステム
- バンドルされるアプリケーション
    - 拡張可能な認証機構
    - 動的な管理インターフェイス
    - RSSとAtom配信用フィードの生成ツール
    - 柔軟なコメントシステム
    - Sitemapsを生成するツール
    - クロスサイトリクエストフォージェリ(CSRF)の防止ツール
    - TextileやMarkdownなど軽量マークアップ言語を使用可能なテンプレートライブラリ
- 公式サポートされるデータベース
    - PostgreSQL
    - MySQL
    - SQLite
    - Oracle

## Reactとは

Wikipediaから、[React(リアクト)](https://ja.wikipedia.org/wiki/React)とは

- ユーザインタフェース構築のためのJavaScriptライブラリ
- SPA(シングルページアプリケーション)やモバイルアプリケーション開発のベースとして使用
    - SPAとは、単一Webページのみから構成することで
        - デスクトップアプリケーションのようなユーザ体験を提供
        - 必要コードの読み込み方法
            - 最初にまとめて読み込む
            - または、ユーザ操作に応じて動的にサーバと通信し、必要なものだけ読み込む
- 複雑なReactアプリケーションでは、`状態管理・ルーティング・API`との対話のため追加ライブラリが必要
    - 例えば、Reduxを状態管理に使用
        - アプリケーションの状態管理のためのオープンソースのJavaScriptライブラリ
        - ユーザーインターフェイスを構築するため、ReactやAngularなどのライブラリで最もよく使用される
- Reactの機能
    - 宣言的UI(テンプレーティング)
        - JSX & ReactDOM
    - データバインディング(data ⇒ UI)
        - state hook
    - コンポーネント化
        - 関数コンポーネント/React.Componentクラス
    - 高効率レンダリング
        - 仮想DOM


## おわりに

本記事のゴールと概要を説明しました。
次回から、実践スタートします。お楽しみに。

##### [次回] [Django+Reactで学ぶプログラミング基礎(2): 開発環境構築(Django/VS Code)](https://qiita.com/mingchun_zhao/items/36adb0243ea27c637053)
Rubyのspawnで生成したプロセスを終了できない罠と解決策

## 概要

Ruby言語から、コマンドラインツールを呼び出すときには、`system` や `open3` を使うが、非同期的に呼び出したい場合は`spawn` を使うことが多い。しかし、引数のコマンドに空白などの文字が入ると、シェル経由の実行になってしまい、プロセスIDを記録してプログラムを終了しようとしても、思ったように終了できないことがある。これを防ぐためには、コマンドに空白などの文字を入れず、引数を分割する。

```ruby
pid = spawn("command which you want to execute")
```

↓

```ruby
pid = spawn("command", "which", "you", "want", "to", "execute")
```

## もう少し詳しく

Rubyでコマンドを非同期的に実行するためには、spawnを利用して、

```ruby
pid = spawn("command which you want to execute")
```

`detach` を呼び出せばいい。

```ruby
thr = Process.detach(pid)
```

これで非同期的にコマンドを実行してくれる。
さらに、Threadの状態をみることで、実行が継続しているかその様子をうかがうこともできる。

```
thr.alive?
```

プロセスを終了するときには、

```ruby
Process.kill(:TERM, pid)
```

とすればいい。ところが、これを実行して、`spawn` したプロセスを終了させたにも関わらず、ゾンビが残ってしまうことがある。
調べたところ次のことが判明した。


https://docs.ruby-lang.org/ja/latest/method/Kernel/m/spawn.html

> command が shell のメタ文字
>
> ```
>  * ? {} [] <> () ~ & | \ $ ; ' ` " \n
> ```
> を含む場合、shell 経由で実行されます。そうでなければインタプリタから直接実行されます。 

どういうことかというと、空白などのメタ文字が含まれている場合は、

```
sh -c 'command which you want to execute'
```

みたいに感じで実行されてしまうのである。こうなってしまうと、pid を記録して、`Process.kill(:TERM, pid)` しても、`sh -c "command"` が終了するだけで、肝心の `"command"` は別のプロセスIDで動いているので終了しない。
これを防ぐためには

```ruby
pid = spawn("command", "which", "you", "want", "to", "execute")
```

のようにスペースを入れる変わりに、引数を分割すればいい。これでシェル経由での実行を防ぐことができため、得られたプロセスIDをkillすれば無事に標的のプログラムを終了させることができる。spawnは便利だけどこんな罠があることを知ったので注意したい。

この記事は以上です。

## プロセスグループを作成するという方法もある

別の解決策として、起動する子プロセスのプロセスグループを作成するという方法がある。

```ruby
pid = spawn("command which you want to execute", pgroup: true)
```

この場合、プロセスグループをキルすれば、子プロセスまで削除することができる。

```ruby
pgid = Process.getpgid(pid)
Process.kill(:TERM, -pgid) # マイナス値でプロセスグループを指定できる
```
matplotlib-cppをCMakeでビルドする

# matplotlib-cppについて

matplotlib-cppはC++でmatplotlibを使用するためのライブラリです。
https://github.com/lava/matplotlib-cpp

このライブラリを使用するためにCMakeでビルドを試みたときに、生じたエラーと解決方法です。

環境 : Ubuntu 22.04

# ビルドのためのCMakeLists.txt

前提 : matplotlibcpp.hをCMakeLists.txtと同一フォルダにロード済みとしています。
https://github.com/lava/matplotlib-cpp/blob/master/matplotlibcpp.h


CMakeLists.txtはgithubレポジトリにあるものを参考に記述しました。
https://github.com/lava/matplotlib-cpp/blob/master/CMakeLists.txt


```cmake:CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(lib_test CXX)

include(GNUInstallDirs)
set(PACKAGE_NAME lib_test)

# library target
add_library(lib_test INTERFACE)
find_package(Python3 COMPONENTS Development.Embed REQUIRED)
target_link_libraries(lib_test INTERFACE
    Python3::Python
    Python3::Module
)
find_package(Python3 COMPONENTS NumPy REQURIED)
target_link_libraries(lib_test INTERFACE
    Python3::NumPy
)

add_executable(TestCode TestCode.cpp)
target_link_libraries(TestCode PRIVATE lib_test)
set_target_properties(TestCode PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
```

# エラー

cmakeを実行すると、次のエラーが発生しました。

```bash
CMake Error at /usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
  Could NOT find Python3 (missing: Python3_INCLUDE_DIRS Development.Embed)
  (found version "3.10.4")
```

# 原因と解決

`python3-dev`がインストールされていなかったことが原因でした。

次のコマンドで`python3-dev`をインストールして、再度 cmakeを実行すると無事にビルドできました。

```bash
sudo apt-get install python3-dev
```
vue3 vue.blade から 子 vueにデータを送る

vue.blade.php のヘッダに 検索ボタンを付ける。
等という事案で使える。

親の変数を子要素でwatchして、子要素の処理をする。
といった流れ。

# vue.blade.php

```.js
<div @click="$root.searchFormVisible = true">検索ボタン</div>
```

# app.js

色々略

```js
    data () {
        return {
            searchBtnVisible:false,
            searchFormVisible:false,
        }
    },
```

これを子要素で察知したい。

# UserShow.vue

```js
watch: {
    //移動する度に動作させる
    //親メソッドの変更を察知する
    '$root.searchFormVisible'(data) {
        console.log(data);
    },
},
```

これで
1. vue.blade.php のボタンを押せば
2. app.js の searchFormVisible が発火
3. UserShow.vueで取得できるので、フォームを表示などの処理が可能
Markovモデルでロケットリーグ大会(RLCS)でのレートを求める。

# はじめに
この記事では、レーティングシステムである、Markovモデルを紹介する。

そして、この方法を使ってロケットリーグのレーティングを求めてみる。
# Markovモデル
Markovモデルは名前の通り、Markov連鎖をもとに考えられたモデルである。

まず初めに、自分の利用したい試合結果からの統計量$V_{ij}$を考える。
例えば次のようなものが考えられる。
- チームiがチームjから取った総得点
- チームiがチームjに勝利した回数
- チームiがチームjより多くとった点差

そして、統計量をnormalizationした行列$N_{ij}$を作成する。
``` math
N_{ij} = \frac{V_{ij}} {\Sigma_j V_{ij}}
```

行列Nに次のような行が残っている場合は、行列の大きさnを利用して次のように変換する。
``` math
\text{if } N_{ij} = 0 (j=1..n) \text{ then } N_{ij} \rightarrow \frac{1}{n}
```

このようにしてできた行列を$S_{\alpha_0}$とする。そのほかの統計量に関しても同様に$S_{\alpha_1}$、$S_{\alpha_2}$...という風に導出し、それぞれの線形結合を次のように取る。
``` math
S = \Sigma_j \alpha_j S_{\alpha_j} 
```
この時、
``` math
\Sigma_j \alpha_j = 1 (\alpha_j > 0) 
```

また、Sがirreducibleではない場合には、次のような変換を施すことでSをirreducibleにする事ができる。
``` math
S \rightarrow \beta S + \frac{1 - \beta}{n} E (0\le\beta\le1)
```

ここまで出来たらあとは、
``` math
S^{T} \vec{r} = \vec{r}
```

という固有値問題を解けば、レート$\vec{r}$が求まる。
# 例題(RLCS)
いつもの通り、ロケットリーグチャンピオンシリーズの[データ](https://liquipedia.net/rocketleague/Rocket_League_Championship_Series/Season_X/Spring/North_America/3)(シーズンX North America GroupA)を使ってレートを導出してみる。

今回はこれらの統計量を利用することにした。
- 試合での得点数
- ショットを打った数
- ボールの支配率

これらのデータを用いてレートを算出すると次のようになった。

|  order  | team name  |    rate    |
| ------- | ---------- | ---------- |
|    1    |    RGE     |   0.240    |
|    2    |     SQ     |   0.217    |
|    3    |     V1     |   0.215    |
|    4    |    OXG     |   0.201    |
|    5    |    VOLT    |   0.126    |

これまでのモデル([Massey](https://qiita.com/takenakadx/items/d06921bc9e5741e1a1d6)や[Elo](https://qiita.com/takenakadx/items/6a0c8f856db45a194349)など)のレートと順位が大きく違っているのが見て取れる。
例えば、SQはこれまでのレートでは4位にランクインしていたが、このレート導出方法では2位となっている。これは、SQはボールの支配率もよくシュートを打つチャンスが多くあるが、決定打にかける為試合に勝てていない事が分かる。このように、レートの導出だけでもいろいろ考察できそうである。
# おわりに
今回のMarkovの方法は、自分の好きな統計量を組み合わせることができるので、とても汎用的であると感じた。
次回は、このMarkovの方法の一種であるPage Rankのモデルについて触れようと思う。
PyQt6およびSIPを入れる際に詰まったのでメモ

# 経緯とか
PyQt6事始めを行うべくSIPをインストールしようとしたらエラーが発生した。数分悩んだので備忘録としてメモ。
どうやらscipyをインストールしたときも同様の事象が発生するっぽい。

# 結論
pipをアップデートしたら成功した。
```:sh
pip3 install --upgrade pip
```

# インストール成功時の環境
```:sh
Python 3.9.1
pip 22.1.2
```

```:sh
$ pip freeze
packaging==21.3
ply==3.11
pyparsing==3.0.9
PyQt6==6.3.0
PyQt6-Qt6==6.3.0
PyQt6-sip==13.3.1
sip==6.6.1
toml==0.10.2
```


## エラーについて
なぜバージョンアップでインストールできたのかはまだ分かっていないです。

- エラー文的には、PEP517を使っているSIPをビルドできないからインストールできないぞと怒っている。
- お試しでアップグレード前のpipでPEP517を入れて実行してみたけど同様のエラーが発生していた。

```:sh
ERROR: Could not build wheels for sip which use PEP 517 and cannot be installed directly
WARNING: You are using pip version 20.2.3; however, version 22.1.2 is available.
You should consider upgrading via the 'test_code/python/pyQtTest/testenv/bin/python3 -m pip install --upgrade pip' command.
```

エラー文でググると下記のStackoverflowに行き当たって、今に至る。
https://stackoverflow.com/questions/61365790/error-could-not-build-wheels-for-scipy-which-use-pep-517-and-cannot-be-installe


# 参考:インストール成功時のログ
ちなみにシェルは[oh my zsh](https://ohmyz.sh/)を使ってる。

```:sh
(testenv) ➜  pyQtTest pip3 install --upgrade pip
Collecting pip
  Downloading pip-22.1.2-py3-none-any.whl (2.1 MB)
     |████████████████████████████████| 2.1 MB 4.9 MB/s 
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 20.2.3
    Uninstalling pip-20.2.3:
      Successfully uninstalled pip-20.2.3
Successfully installed pip-22.1.2
(testenv) ➜  pyQtTest pip install sip           
Collecting sip
  Downloading sip-6.6.1-cp37-abi3-macosx_10_9_universal2.whl (700 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 700.4/700.4 kB 6.6 MB/s eta 0:00:00
Collecting packaging
  Using cached packaging-21.3-py3-none-any.whl (40 kB)
Collecting toml
  Using cached toml-0.10.2-py2.py3-none-any.whl (16 kB)
Requirement already satisfied: setuptools in ./testenv/lib/python3.9/site-packages (from sip) (49.2.1)
Collecting ply
  Using cached ply-3.11-py2.py3-none-any.whl (49 kB)
Collecting pyparsing!=3.0.5,>=2.0.2
  Using cached pyparsing-3.0.9-py3-none-any.whl (98 kB)
Installing collected packages: ply, toml, pyparsing, packaging, sip
Successfully installed packaging-21.3 ply-3.11 pyparsing-3.0.9 sip-6.6.1 toml-0.10.2
(testenv) ➜  pyQtTest vscode
zsh: command not found: vscode
(testenv) ➜  pyQtTest pip -V
pip 22.1.2 from /test_code/python/pyQtTest/testenv/lib/python3.9/site-packages/pip (python 3.9)
(testenv) ➜  pyQtTest pip install pyqt6
Collecting pyqt6
  Downloading PyQt6-6.3.0-cp37-abi3-macosx_10_14_universal2.whl (11.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.6/11.6 MB 14.0 MB/s eta 0:00:00
Collecting PyQt6-sip<14,>=13.2
  Downloading PyQt6_sip-13.3.1-cp39-cp39-macosx_10_9_x86_64.whl (76 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 76.5/76.5 kB 2.9 MB/s eta 0:00:00
Collecting PyQt6-Qt6>=6.3.0
  Downloading PyQt6_Qt6-6.3.0-py3-none-macosx_10_14_x86_64.whl (34.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 34.6/34.6 MB 15.1 MB/s eta 0:00:00
Installing collected packages: PyQt6-Qt6, PyQt6-sip, pyqt6
Successfully installed PyQt6-Qt6-6.3.0 PyQt6-sip-13.3.1 pyqt6-6.3.0
```