OmniAICreator/Qiita-1.07M huggingface dataset:
【自分用】Homebrew 一括インストールコマンド覚書【Apple silicon macOS用】

新しく環境をセットアップするときには、全体をコピペして使います。

```bash
brew tap heroku/brew
brew tap adoptopenjdk/openjdk
brew tap gcenx/wine
brew install heroku git 7zip composer wget pandoc ffmpeg node mkcert 
brew install --cask google-chrome visual-studio-code vlc libreoffice brave-browser \
      discord gimp　inkscape dbeaver-community vnc-viewer virtualbox vagrant \ 
      veracrypt xmind zoom microsoft-edge microsoft-teams google-japanese-ime \
      amorphousdiskmark  obs barrier adoptopenjdk8 diffmerge skitch wine-crossover \
      background-music
```

[【自分用】VS Code拡張機能一括インストールコマンド覚書【Win/Mac/Linux兼用】 - Qiita](https://qiita.com/hidao/items/3f253d279c925218feab)もあります。
【自分用】chocolatey 一括インストールコマンド覚書【Windows用】

新しく環境をセットアップするときには、全体をコピペして使います。

```powershell
# 通信
cinst -y googlechrome brave discord ultravnc zoom advanced-ip-scanner microsoft-teams `
         wget bonjour 

# 開発
cinst -y git visualstudiocode composer dbeaver winmerge bzeditor winscp `
         virtualbox vagrant jre8 wsl2 microsoft-build-tools python python3 nodejs `
         mkcert openssl php 

# 画像・動画・音声
cinst -y camtasia Screenpresso vlc gimp InkScape eartrumpet ffmpeg obs 

# 資料作成
cinst -y libreoffice xmind pandoc

# ユーティリティ
cinst -y 7zip veracrypt win32diskimager scansnapmanager googlejapaneseinput cpu-z `
         crystaldiskmark  barrier
```

注記：`vagrant`は`virtualbox`のあとに来るようにしないと正しくインストールされない場合があります。

[【自分用】Homebrew 一括インストールコマンド覚書【Apple silicon macOS用】 - Qiita](https://qiita.com/hidao/items/3bf1a162a68b452d82f4)もあります。
アジャイルとスクラムの用語まとめ

アジャイルは開発方法の考え方で、
スクラムはアジャイル開発のプロセスにフォーカスを当てたフレームワークです。

アジャイルの説明で利用される用語も、
スクラムでは独自の用語で再定義されていたりします。
ややこしかったので、アジャイルのアレがスクラムのコレだ、を一覧化してみました。

:::note warn
書籍ベースで得た知識で、開発経験はないので、
少し間違っている解釈があるかもしれません。
:::
 ## 用語まとめ

該当する用語がないときは空欄としています。

| 従来の意味 | Agile | Scrum |備考
|:-:|:-:|:-:|:--|
|プロジェクトチーム|アジャイルチーム|スクラムチーム||
|顧客の代表|プロダクトオーナー|(同左)||
|開発する人たち|開発チーム|「開発者」の集合||
|支援型リーダー|チームリーダー|スクラムマスター||
||アジャイルコーチ|スクラムマスター||
|関係者|ステークホルダー|(同左)||
|開発範囲|スコープ|(同左)||
|要件|ストーリー|ユーザーストーリー||
|要件の相対的な大きさ|ストーリーポイント|||
|要件の優先順リスト|ストーリー一覧|プロダクトバックログ||
|要件を明確にする活動||プロダクトバックログリファインメント||
|具体的な作業|タスク|スプリントバックログ|ストーリ/プロダクトバックログを作業に砕いたもの|
|固定期間の考え方|タイムボックス|(同左)||
|1回の繰り返し期間|イテレーション|スプリント||
|1回の開発期間の開始時に行う会議|イテレーション計画会議(前半と後半)|スプリント計画、スプリントプランニング||
|1回の開発期間の最後に製品レビューする会議|イテレーションのレビュー会議|スプリントレビュー||
|1回の開発期間が終わってからやる振り返り|イテレーションの振り返り|スプリントレトロスペクティブ||
|1回の開発期間の生産性|ベロシティ|(同左)||
|1回目の開発の前の準備期間|イテレーション・ゼロ|スプリントゼロ||
|プロジェクト開始時に行う認識合わせ、キックオフ|インセプション|||
|朝ミ(日次ミーティング)|スタンドアップミーティング|デイリースクラム||
|反省会、振り返り会|レトロスペクティブ|(※1)|イテレーションに関係なく定期的に実施(毎週が推奨)|
|実行可能な成果物|インクリメント|||
|手法・習慣|プラクティス|(同左)||
|スクラムを定義したもの||スクラムガイド||
|自律した理想的なチーム|自己組織化したチーム|(同左)||

※1 アジャイル検定公式テキストを読んでややこしかったのは「振り返り」と「イテレーションの振り返り」が別だったことでした。イテレーション(スプリント)に関係なく定期的に行う振り返り、という考え方は、スクラムでの定義が分からなかったので空欄としています。
【Ruby】メソッドの後の感嘆符"!"について

メソッドの中には、破壊的にデータを変更してしまうものがあり、慣習として名前に"!"が付けられます。

例えば、以下のコードがあったとします。
```
self.email = self.email.downcase
```
参考：Railsチュートリアル 第4版 6章より
https://railstutorial.jp/chapters/modeling_users?version=5.0#sec-minimum_password_standards

上記だと右辺で"self.email"を全て小文字にしてから自身に代入することで更新していますが、
.downcase!メソッドを用いることで、直接"self.email"の値を変更することができ、より簡潔に書けます。

```
self.email.downcase!
```

破壊的なメソッドは便利そうですが、一方で元の値を強制的に上書きするので、使いどころには注意ですね。

【追記2022/08/26】
@nodai2h_ITC 様よりご指摘を頂きました。
以前、"!"をメソッドに付けると破壊的なメソッドになると勘違いしていました。
しかし実際には、"downcase"と"downcase!"のように、非破壊のメソッドと破壊のメソッドで対になっているものがいくつかあるだけとのことです。詳しくは元のコメントをご確認ください。
Ruby 2.7まで動いていたデフォルト値付きのブロックパラメータをRuby 3.0向けに書き替える

## はじめに：Ruby 2.7では動いていた奇妙なコード
とあるRailsプロジェクトをメンテしていたら、こんな奇妙なコードに遭遇しました。

```ruby 
def sample
  data = {
    a: nil,
    b: { x: 1, y: 2 },
    c: { x: 1 },
    d: { y: 2 },
  }
  data.map do |k, x: 0, y: 0|
    [k, x, y]
  end
end
```

Ruby 2.7でこの`sample`メソッドを実行すると以下のような結果が得られます。

```ruby 
# Ruby 2.7
sample
#=> [
#     [:a, 0, 0],
#     [:b, 1, 2],
#     [:c, 1, 0],
#     [:d, 0, 2],
#   ] 
```

## これはいったい何をやってるの？

このメソッドでは以下の行で`x`や`y`のデフォルト値を設定しています。

```ruby 
data.map do |k, x: 0, y: 0|
```

これにより、このメソッドは以下のような挙動を示します。

- `a: nil`であれば、`x`と`y`はどちらもデフォルト値の0になります。
- `b: { x: 1, y: 2 }`は`x`が1、`y`が2になります（デフォルト値は使われない）。
- `c: { x: 1 }`は`x`が1で、`y`がデフォルト値の0になります。
- `d: { y: 2 }`は`x`がデフォルト値の0で、`y`が2になります。

個人的には「こんな凝ったコード書くなよ〜」と思うのですが、Ruby 2.7まではちゃんと動いていたので、それまではこれで良かったのかもしれません。

## 発生した問題：このコードはRuby 3.0以降ではちゃんと動かない

ただし、Ruby 2.7で`-W:deprecated`オプションを付けて実行すると、以下のような警告メッセージが出ます。

```
warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
warning: The called method is defined here
```

そして、このコードをそのままRuby 3.0で動かすとRuby 2.7と異なり、`x`も`y`も全部0になります。

```ruby 
# Ruby 3.0だとxもyも全部0になる！
sample
#=> [
#     [:a, 0, 0],
#     [:b, 0, 0],
#     [:c, 0, 0],
#     [:d, 0, 0],
#   ] 
```

これはRuby 3.0で導入された「キーワード引数の分離」の影響です。

https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/

`k, x: 0, y: 0`のような記述がブロックパラメータではなく、メソッドの仮引数であれば以下のようにハッシュに`**`を付けることでこの問題を回避できます。

```ruby 
# 引用元 https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
def foo(k: 1)
  p k
end

h = { k: 42 }

# **を付けるとハッシュオブジェクトをキーワード引数に変換できる
foo(**h) #=> 42
```

ただし、今回はブロックパラメータなので、`**`を付ける作戦が使えません。

## 解決策：Ruby 3.0でも期待した結果が得られるようにコードを書き替える

そこで、やむを得ず今回は以下のようにコードを書き替えることにしました。

```diff_ruby 
 def sample
   data = {
     a: nil,
     b: { x: 1, y: 2 },
     c: { x: 1 },
     d: { y: 2 },
   }
-  data.map do |k, x: 0, y: 0|
+  data.map do |k, h|
+    x, y = { x: 0, y: 0 }.merge(h || {}).values_at(:x, :y)
     [k, x, y]
   end
 end
```

これでRuby 2.7と同じ結果を得ることができました。

```ruby 
# Ruby 3.0（修正後のコード）
sample
#=> [
#     [:a, 0, 0],
#     [:b, 1, 2],
#     [:c, 1, 0],
#     [:d, 0, 2],
#   ] 
```

`x, y = { x: 0, y: 0 }.merge ...` の部分は他にもいろんな書き方があると思いますが、「`**`を付けるだけでOK」みたいな、お手軽な解決方法はどうやらないみたいです。

## Special thanks
この件はruby-jpのSlackチャンネルでつよつよRubyプログラマのみなさんに解決策をいろいろと相談させてもらいました。
相談に乗ってくださったRubyプログラマのみなさん、どうもありがとうございました！

https://ruby-jp.github.io/

## おまけ

この記事を書くにあたって動作確認のために書いたテストコードです。
自分の手元で動かしてみたい場合にご利用ください。

```ruby 
require 'minitest/autorun'

class BlockParamsTest < Minitest::Test
  def sample
    data = {
      a: nil,
      b: { x: 1, y: 2 },
      c: { x: 1 },
      d: { y: 2 },
    }
    # Ruby 2.7
    data.map do |k, x: 0, y: 0|
      [k, x, y]
    end
    # Ruby 3.0
    # data.map do |k, h|
    #   x, y = { x: 0, y: 0 }.merge(h || {}).values_at(:x, :y)
    #   [k, x, y]
    # end
  end

  def test_sample
    expected = [
      [:a, 0, 0],
      [:b, 1, 2],
      [:c, 1, 0],
      [:d, 0, 2],
    ]
    assert_equal expected, sample
  end
end
```
【kintone x OCR】～OCR結果確認編～　kintoneのOCRプラグインを開発する⑦【GCP】

# 無償で試してみる
下記に「アカウント申請」という件名（本文なし）でメールを送付頂ければ、数分程度でアカウント情報を返信します。
ocr.lastonemile@gmail.com
* 利用規約に同意の上、ご利用ください。　https://tanoshimane.stores.jp/news/603313afc19c4527490eb72e
* kintoneというクラウドアプリ上に構築しており、そのゲストIDを発行します。
* 30日間又は100ページまで（kintoneの利用料含めて）無償で利用可能です。

詳細：https://qiita.com/Lastonemile/items/65b9102c868e09b3248e

# プラグインのダウンロード
kintone用OCRプラグイン及びテンプレートが、下記よりダウンロード（無償で購入）可能です。

利用（設定）方法

* **IEではご利用いただけません**（Chrome,edgeは動作確認済、その他ブラウザは未検証です）
* 初回利用時から1か月間無償でご利用いただけます。
* ご利用にあたり、ご利用者のドメイン情報を取得します（ドメイン毎に利用期間を管理しています）。
* 利用にあたり、別途Google Cloud Vision のAPIキーを取得頂く必要がございます。（取得代行も行っています）
Cloud Visionの詳細：https://cloud.google.com/vision/docs?hl=ja
APIキー取得方法：https://syncer.jp/cloud-vision-api
**APIキーの管理には十分ご注意ください**

# 最終目標
kintone上でこの↓画像（請求書）をOCR処理し、請求番号・支払期限・振込先・請求元・明細（品名・数量・・・のテーブル部分）の値を取得することを最終目標とします。
![請求書サンプル.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/13655cba-1ef7-40ba-748c-135bc5af3280.jpeg)


尚、説明は後回しで「まず試したい」という方は、[プラグイン（テンプレート）のダウンロード](#プラグインテンプレートのダウンロード)からkintone用のプラグインとテンプレートを試用（1か月間）頂けます。

### 今回（OCR結果確認編）の目標
前回（⑥）の通り、最終目標については、達成出来ました↓。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/7c5bcd75-9661-42ce-94ba-7cccc228b4d4.png)

ただし、現状ではOCR結果が正しいことを確認するためには、OCR結果毎に対象画像を表示させ、チェックしていく必要があり、あまり効率的とは言えません。そこで、OCR結果毎に対象画像が表示されるようにすることで、OCR結果と対象画像を並べてチェックできるようにしたいと思います。

### 具体的な方法
取得した値毎に座標(X,Y,W,H)を取得します。特にテーブルについては、行ごとの座標を取得します。
その上で、取得した座標に沿って、元画像を切り取り、その結果（切り取った画像）をアップロードしていきます。切り取りにはcanvasを利用します。

```
get_imagedata_croped = function(img, x, y, w, h) {
	const canvas  = document.createElement('canvas');
	canvas.width  = img.width;
	canvas.height = img.height;
	const ctx = canvas.getContext('2d');
	ctx.drawImage(img, 0, 0);
	return ctx.getImageData(x, y, w, h);
};
```
その結果、OCR結果と対象画像を並べて表示することが可能になりました。

### プラグイン（テンプレート）のダウンロード
ここまでの説明及び、以降の記事内容も網羅したkintone用OCRプラグイン及びテンプレートが、下記よりダウンロード（無償で購入）可能です。

利用（設定）方法

＊**IEではご利用いただけません**（Chrome,edgeは動作確認済、その他ブラウザは未検証です）
＊初回利用時から1か月間無償でご利用いただけます。
＊ご利用にあたり、ご利用者のドメイン情報を取得します（ドメイン毎に利用期間を管理しています）。
＊利用にあたり、別途Google Cloud Vision のAPIキーを取得頂く必要がございます。（取得代行も行っています）
Cloud Visionの詳細：https://cloud.google.com/vision/docs?hl=ja
APIキー取得方法：https://syncer.jp/cloud-vision-api
**APIキーの管理には十分ご注意ください**（自己責任でお願いします）

## ここまでで出来たこと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/3d9e69ea-a44b-ad68-967c-70a431d353cf.png)
以上で、長々と行ってきた「kintoneのOCRプラグインを開発」は完成にしたいと思います。
繰り返しになりますが、[プラグイン（テンプレート）のダウンロード](#プラグインテンプレートのダウンロード)からkintone用のプラグインとテンプレートを試用（1か月間）頂けますので、実際の動作やコード等を確認したいかたは、ご利用ください。

## 筆者の紹介
群馬県の渋川市・高崎市を中心に群馬県内でkintoneを利用したDX化支援を行っています。ご興味ある方はぜひご連絡ください。
https://ks-kiki.hp.peraichi.com/
【kintone x OCR】～文字列置換編～　kintoneのOCRプラグインを開発する⑤【GCP】

# 無償で試してみる
下記に「アカウント申請」という件名（本文なし）でメールを送付頂ければ、数分程度でアカウント情報を返信します。
ocr.lastonemile@gmail.com
* 利用規約に同意の上、ご利用ください。　https://tanoshimane.stores.jp/news/603313afc19c4527490eb72e
* kintoneというクラウドアプリ上に構築しており、そのゲストIDを発行します。
* 30日間又は100ページまで（kintoneの利用料含めて）無償で利用可能です。

詳細：https://qiita.com/Lastonemile/items/65b9102c868e09b3248e

# プラグインのダウンロード
kintone用OCRプラグイン及びテンプレートが、下記よりダウンロード（無償で購入）可能です。

利用（設定）方法

* **IEではご利用いただけません**（Chrome,edgeは動作確認済、その他ブラウザは未検証です）
* 初回利用時から1か月間無償でご利用いただけます。
* ご利用にあたり、ご利用者のドメイン情報を取得します（ドメイン毎に利用期間を管理しています）。
* 利用にあたり、別途Google Cloud Vision のAPIキーを取得頂く必要がございます。（取得代行も行っています）
Cloud Visionの詳細：https://cloud.google.com/vision/docs?hl=ja
APIキー取得方法：https://syncer.jp/cloud-vision-api
**APIキーの管理には十分ご注意ください**

# 最終目標
kintone上でこの↓画像（請求書）をOCR処理し、請求番号・支払期限・振込先・請求元・明細（品名・数量・・・のテーブル部分）の値を取得することを最終目標とします。
![請求書サンプル.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/13655cba-1ef7-40ba-748c-135bc5af3280.jpeg)


尚、説明は後回しで「まず試したい」という方は、[プラグイン（テンプレート）のダウンロード](#プラグインテンプレートのダウンロード)からkintone用のプラグインとテンプレートを試用（1か月間）頂けます。

### 今回（文字列置換編）の目標
前回（④）の最後で今後の課題とした、文字単位での認識違いの対策を説明したいと思います。対象となるのは↓の「単価」列の5行目で100を10Dと認識違いしていますので、100と取得できるようにしたいと思います。
![KEYWORZONE正規表現.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/cb4ca28e-7f59-deab-287b-7607cc05b263.png)

### 具体的な取得方法
今回の「単価」列には、数字しか記載されません。そのため、数字以外の文字で特に数字に間違い易い文字については、数字と間違って認識している可能性が高いと思われます。

そこで、取得した値の中に数字に間違い易い文字（下記参照）が含まれている場合は、間違い易い数字に変換することとします。
![アルファベット2数字.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/3f82a22a-ba8c-5d64-5d3e-8c4a61ffdd4e.png)
＊例えば、今回のようにDと認識した場合は0に変換します。

```
for (let i = 0; i < replacecsv.length; i++) {
   description = description.replace(replacecsv[i].Column1,replacecsv[i].Column2);
}
```
そうすることで、「単価」列が上手く取得出来ました。

### プラグイン（テンプレート）のダウンロード
ここまでの説明及び、以降の記事内容も網羅したkintone用OCRプラグイン及びテンプレートが、下記よりダウンロード（無償で購入）可能です。

利用（設定）方法

＊**IEではご利用いただけません**（Chrome,edgeは動作確認済、その他ブラウザは未検証です）
＊初回利用時から1か月間無償でご利用いただけます。
＊ご利用にあたり、ご利用者のドメイン情報を取得します（ドメイン毎に利用期間を管理しています）。
＊利用にあたり、別途Google Cloud Vision のAPIキーを取得頂く必要がございます。（取得代行も行っています）
Cloud Visionの詳細：https://cloud.google.com/vision/docs?hl=ja
APIキー取得方法：https://syncer.jp/cloud-vision-api
**APIキーの管理には十分ご注意ください**（自己責任でお願いします）


## 今後の課題
「品名」列の結果を見ると、その左側のseq番号を取得してしまっています。この場合、正規表現では上手くパターン化出来ないため、他の方法が必要です。

そのため、次回はこの品名列の値を取得することを目標とします。

## ここまでで出来たこと
![KEYWORZONE正規表現文字置換.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543387/5cfccd47-abb2-d7df-d10c-bee0ced86212.png)

＊KEYWORD検索（請求番号・支払期限・振込先）、ZONE検索（請求元）、正規表現検索（明細（数量・単位・金額））に加え、文字列置換で単価まで取得出来ました。

## 筆者の紹介
群馬県の渋川市・高崎市を中心に群馬県内でkintoneを利用したDX化支援を行っています。ご興味ある方はぜひご連絡ください。
https://ks-kiki.hp.peraichi.com/
【Xcode】【開発環境構築】エラー `xcrun: error: unable to find utility "xctest", not a developer tool or in PATH` への対応方法

# 事象

Xcodeでプロジェクトの開発環境構築のために、Terminal でスクリプトを実行した結果、以下のエラーが出力されました。

```
error: terminated(72): /usr/bin/xcrun --sdk macosx --find xctest output:
    xcrun: error: unable to find utility "xctest", not a developer tool or in PATH
```

xcrun は、開発者ツールを実行したり検索するコマンドです。

# 原因

Xcodeのコマンドラインツールに、別のバージョンを指定していたのが原因でした。
例えば、開発環境構築の時に使用したりする `xcodebuild` は、Xcode のコマンドラインツールのバージョンを参照するので、開発環境構築の時に起こりがちなエラーです。
業務で Xcode を利用するときは、案件ごとに使用する Xcode のバージョンが違うことがあるので、私はよくやっちゃいます :sweat_smile: 
ちなみに私は、Xcodeアプリの名前の末尾にバージョン番号を付して、目視ですぐにバージョンが区別でるようにしています。

__例__
- Xcode_13.3.1.app
- Xcode.app（最新）

# 対応方法

**Terminal での確認・変更方法**と、**Xcode の設定画面からの確認・変更方法**があります。
順番にやり方を書いていきます。

## Terminal での対応方法

### まずは、現在使用している Xcode のコマンドラインツールのバージョンを確認します

以下のコマンドを入力します。

```
xcode-select -p
```

または

```
xcode-select --print-path
```

__出力結果__
> /Applications/Xcode.app/Contents/Developer

どうやらエラー発生時には、Xcode.app という名前のアプリのコマンドラインツールを使っていたようです。

### 次に、使用したい Xcode のコマンドラインツールのバージョンを更新します

今回私の場合は、Xcode_13.3.1.app というアプリ名のコマンドラインツールを使いたいので、そのアプリ名を指定します。

```
sudo xcode-select -s /Applications/{使用したい Xcode のアプリ名.app}/Contents/Developer
```

例

```
sudo xcode-select -s /Applications/Xcode_13.3.1.app/Contents/Developer
```

## Xcode の設定画面での対応方法

### Xcode を開きます

![1_Launch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/705bc4de-8212-6ca3-5799-40b7f3f40964.png)

### Xcode のツールバーから [Preference]（環境設定）を開きます

![2_ToolBar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/2e3c7c08-b324-5dce-2016-d00b8c690326.png)

### [Locations] を選択します

下部に [Command Line Tools] という設定項目があります。
ここに表示されているバージョンが、現在設定されている、Xcode のコマンドラインツールのバージョンです。

![3_Preference_Location.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/daba8479-bd6c-5a78-ff6d-f0df543711c3.png)

### [Command Line Tools] のプルダウンボタンをクリックして、選択肢から、使用したい Xcode のコマンドラインツールのバージョンを選択します

![4_SetVersion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/abb89be7-370c-3e2d-20be-3c2e3da97266.png)

# まとめ

開発環境構築時にやりがちなエラーについて、対応方法を説明しました。
対応方法には、Terminal での確認・変更方法と、Xcode の設定画面からの確認・変更方法があり、好きな方で対応できることがわかりました。

# 参考

- [stackoverflow | What are the differences between xcodebuild, xcrun and swift command line tools?](https://stackoverflow.com/questions/69030618/what-are-the-differences-between-xcodebuild-xcrun-and-swift-command-line-tools)
- [xcrun マンページ](http://www.manpagez.com/man/1/xcrun/)
Rustでテキストの表記ゆれの直したい

# 目的
入力されたテキストを正規表現などでマッチさせたいときに、元々のテキストの表記ゆれを無くしてからチェックしたいです。

## Unicode正規化
特に表記ゆれの無くし方に指定が無い場合は[Unicodeの正規化](https://ja.wikipedia.org/wiki/Unicode%E6%AD%A3%E8%A6%8F%E5%8C%96)を使えばよいです。

```rust:Cargo.toml
[dependencies]
unicode-normalization = "0.1.20"
```

```rust:main.rs
use unicode_normalization::UnicodeNormalization;
fn main() {
    let src = "Ａ１＃＠（ｱｶﾞｰ";
    let c = src.nfkc().collect::<String>();
    println!("{}",src);
    println!("{}",c);
}
```

```text:結果
Ａ１＃＠（ｱｶﾞｰ
A1#@(アガー
```

## しかし細かい要件があった

今回は以下のような要件がありました。
 * 英数字 半角
 * 一部記号(#@) 半角
 * 半角カタカナ(括弧等の記号も含む) 全角

上記サンプルでは全角左括弧が半角になってしまって要件を満たさないです。

## 色々なcrateを調査
以下のcrateを試してみました。
* [unicode-jp](https://crates.io/crates/unicode-jp)
* [kanaria](https://crates.io/crates/kanaria)

半角カナだけ変換などの部分的なものはありましたが、記号を一部だけ変換する機能がなくてぴったりとは収まりませんでした。

## charに分解して変換
入力文字列をcharに分解して処理することを考えました。
```Rust:main.rs
use std::collections::HashMap;
fn main() {
    let mut map: HashMap<char, char> = HashMap::new();
    map.insert('Ａ', 'A');
    map.insert('１', '1');
    map.insert('＃', '#');
    map.insert('＠', '@');
    map.insert('ｱ',  'ア');
    map.insert('ｰ', 'ー');

    let src = "Ａ１＃＠（ｱｶﾞｰ";
    let dst = src.chars().map(|c| {
        //println!("{:?}", c);
        match map.get(&c) {
            Some(v) => *v,
            None => c
        }
    }).collect::<String>();
    println!("{}",src);
    println!("{}",dst);
}
```

```text:結果
Ａ１＃＠（ｱｶﾞｰ
A1#@（アｶﾞー
```

はい、要件を一つ満たしていないです。「ｶﾞ」が全角になっていません。
```rust
map.insert('ｶﾞ',  'ガ');
```
を入れればいいじゃないと思うじゃないですか。これコンパイルエラーになります。
```text
error: character literal may only contain one codepoint
```
一文字にみえるのですが、実は2文字で構成されています。
「'ｶ'」「'\u{ff9e}'」
です。
困りました。mapをcharからstrにするのは簡単ですがcharsをどうにかする必要があります。なんとか「ｶﾞ」を一文字として認識してほしいのです。

## unicode-segmentation
ありました。
[unicode-segmentation](https://crates.io/crates/unicode-segmentation)

# 完成したコード
```rust:Cargo.toml
[dependencies]
unicode-segmentation = "1.9.0"
```

```rust:main.rs
use std::collections::HashMap;
use unicode_segmentation::UnicodeSegmentation;
fn main() {
    let mut map: HashMap<&'static str, &'static str> = HashMap::new();
    map.insert("Ａ", "A");
    map.insert("１", "1");
    map.insert("＃", "#");
    map.insert("＠", "@");
    map.insert("ｱ",  "ア");
    map.insert("ｰ", "ー");
    map.insert("ｶﾞ", "ガ");

    let src = "Ａ１＃＠（ｱｶﾞｰ";
    let dst = src.graphemes(true).map(|c| {
        //println!("{:?}", c);
        match map.get(c) {
            Some(v) => *v,
            None => c,
        }
    }).collect::<String>();
    println!("{}",src);
    println!("{}",dst);
}
```

```text:結果
Ａ１＃＠（ｱｶﾞｰ
A1#@（アガー
```

# まとめ
細かい要件がある場合、必要な変換をHashMapに定義しておけば対応できるようになりました。
また複数の絵文字が合体したような絵文字も1文字として扱ってくれるので、絵文字をごにょごにょしたい時は便利そうです。
Lispとtcl/tkで三目並べ

# 覚えていますか？
1983年　「ウォーゲーム」という映画がありました。当時は米ソ冷戦、核戦争とコンピューターをテーマにした作品でした。最終場面で三目並べゲームが出てきます。どう頑張っても引き分けにしかならないのでした。あれから４０年くらい。まさか２１世紀においてこの映画にリアリティーが出てくるとは？！　

Easy-ISLispにTCLTKのライブラリを整備しましたので、テストがてら三目並べを書いてみました。


# イメージ
![Screenshot at 2022-08-25 07-33-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33927/51cfb70c-67cc-6378-b4cc-00a5f95cd733.png)


# 必ず引き分けになる
映画で人工知能のジョシュアは三目並べが必ず引き分けになることから、核戦争ゲームに勝者がいないことを学ぶのでした。ほんとに引き分けになるのかな？　GUIのテスト用なので思考ルーチは手抜きです。大丈夫？　大丈夫みたいです。

コンピューター側は後手の☓です。思考戦略は下記のとおりです。

初手　先手が真ん中に打ってきたら左上角に打ちます。先手が真ん中以外に打ってきたら真ん中に打ちます。

その後　
コンピューターがリーチなら勝ちを取ります。
人間がリーチなら妨害します。
両者ともにリーチでないなら空いている角をとります。
いずれでもない場合にはどこか空いているところをとります。


コードは下記のとおりです。

```lisp

;; first step
(defun computer1 (i j)
   (cond ((and (= i 1) (= j 1)) (setq init nil) (list 0 0))
         (t (setq init nil) (list 1 1))))

;; after first step
(defun computer2 ()
    (block after
      ;; if computer player one-more, get win
      (let ((res (one-more-p 2)))
        (if res (return-from after res)))
      ;; if human player one-more, disturb win
      (let ((res (one-more-p 1)))
        (if res (return-from after res)))
      ;; if not one-more, occupy corner
      (let ((res (computer-free-corner)))
        (if res (return-from after res)))
      ;; other case occupy free position
      (let ((res (computer-free)))
        (if res (return-from after res)))))
      

```

単純なゲームだと案外単純な思考ルーチンでもイケるもんですね。


# 与太話
さて、Easy-ISLispのTKはうまくいってるようです。調子にのって与太話

ロシアのプーチンさんが三目並べのことをしらないはずはありません。ゲームが単純化すれば最後まで手を読み切れます。もしもロシアが原子炉を攻撃する、あるいは局所戦術核兵器を使ったらNATO加盟国は核ミサイルを全弾ロシアに向けて発射すると宣言するとゲームは単純にならないものでしょうか？（あくまで妄想ですよ）　不毛で不幸な戦争が終わることを願っております。



      
https://github.com/sasagawa888/eisl
wsl2でStableDiffusionを動かすまでのメモ

## モチベ
ホストの環境汚したくないので仮想環境で

## 環境
OS: Windows 11 21H2
GPU: GeForce GTX 1080

## ホスト(Windows)でやること
### モデルデータへアクセスできるようにする
https://huggingface.co/CompVis/stable-diffusion-v-1-4-original

に登録して利用規約に同意して`Access repository`を押す。

### アクセストークンの発行
https://huggingface.co/settings/tokens
から発行しておく

### 最新のドライバのインストール

https://www.nvidia.com/download/index.aspx

### wsl2へのubuntuのインストール

```powershell
wsl --install -d ubuntu
wsl
```

### WSL2(Ubuntu)でやること
↓のスクリプトを実行
tokenはよしなにしてください

```sh
token=$(cat token)

# install git lfs to clone model data
sudo apt-get update
sudo apt-get upgrade -y git-lfs
git lfs install


# install cuda driver
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
rm cuda-wsl-ubuntu.pin
wget https://developer.download.nvidia.com/compute/cuda/11.7.1/local_installers/cuda-repo-wsl-ubuntu-11-7-local_11.7.1-1_amd64.deb
sudo dpkg -i cuda-repo-wsl-ubuntu-11-7-local_11.7.1-1_amd64.deb
rm cuda-repo-wsl-ubuntu-11-7-local_11.7.1-1_amd64.deb
sudo cp /var/cuda-repo-wsl-ubuntu-11-7-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda


# install miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
sudo sh Miniconda3-latest-Linux-x86_64.sh -b -p /opt/miniconda3
rm  Miniconda3-latest-Linux-x86_64.sh
/opt/miniconda3/bin/conda init bash


# clone stable-diffusion (fork)
git clone https://github.com/hlky/stable-diffusion.git


# setup model data
git clone https://:$token@huggingface.co/CompVis/stable-diffusion-v-1-4-original
mkdir -p stable-diffusion/models/ldm/stable-diffusion-v1
mv stable-diffusion-v-1-4-original/sd-v1-4.ckpt stable-diffusion/models/ldm/stable-diffusion-v1/model.ckpt
rm -rf stable-diffusion-v-1-4-original


# setup GFPGAN
wget -P stable-diffusion/src/gfpgan/experiments/pretrained_models \
  https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth

# setup RealESRGAN
wget -P stable-diffusion/src/realesrgan/experiments/pretrained_models \
  https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth \
  https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth


# setup stable-diffusion
cd stable-diffusion
conda env create -f environment.yaml
echo "conda activate ldm" >> ~/.bashrc
. ~/.bashrc

# python scripts/webui.py 
```

## ハマりポイント
- ホストに最新のドライバを入れましょう。Windows Updateで勝手に入るドライバだとNGです。
- [MSのドキュメント](https://docs.microsoft.com/ja-jp/windows/ai/directml/gpu-cuda-in-wsl) からリンクされてる[ドキュメント]( https://docs.nvidia.com/cuda/wsl-user-guide/index.html#getting-started-with-cuda-on-wsl) に書いてある方法だとgpgが無いって怒られます。
  - 参照すべきはこっち https://docs.microsoft.com/ja-jp/windows/ai/directml/gpu-cuda-in-wsl
- git lfsを入れましょう。モデルをcloneするときに失敗します。


## 参考にした記事
https://zenn.dev/choshicure/scraps/14bca2492bf49f

https://zenn.dev/ryoma310/articles/63bc3d20a8746c
文字列を別の文字列に置換する(SPSS Modeler データ加工逆引き2-10)

# 文字列を別の文字列に置換(名寄せ)

![スクリーンショット 2022-08-09 10.06.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/5ee6f1c9-bae0-0c0b-6753-2fc03cfa799d.png)

*（株）だけではない法人略称を同時に置き換える場合には以下の記事を参照ください。

https://qiita.com/416nishimaki/items/79092722425467ccf75c

## 1.想定される利用目的

・組織名や商品名の名寄せ
・コンタクトセンターログの分析用加工
・設備ログの分析用加工

## 2.サンプルストリームのダウンロード

https://github.com/yoichiro0903n/blue/blob/main/replace_another.str?raw=true

## 3.サンプルストリームの説明

![スクリーンショット 2022-08-09 10.07.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/dde22e8b-00d2-82ac-f2f1-c43c7e615da6.png)

a.入力するデータは以下の通りです。
![スクリーンショット 2022-08-09 10.08.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/b3a29405-c787-0858-95e1-1a990f4942b4.png)

b.[フィールド作成]ノードを編集します。replace("文字列1","文字列2",フィールド)でフィールド内に文字列1を文字列2に置換します。
![スクリーンショット 2022-08-09 10.08.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/8c3a7f5f-5397-1f15-05d3-6f028e7b3d22.png)

式ビルダーの文字列関数を利用すると便利です。
![スクリーンショット 2022-08-09 10.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/c506da13-64c7-8697-b81c-26b973dbd6a3.png)

[プレビュー]します。2レコード目は括弧が全角のため置き換わっていません。
![スクリーンショット 2022-08-09 10.21.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/c65edf90-6be5-f6fe-fc92-c1b00a9e1e2c.png)

c.[置換]ノードを編集します。同じ関数で全角括弧バージョンを作成します。
![スクリーンショット 2022-08-09 10.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/1ca04925-6fe1-2db7-0ed9-03c43287c1e1.png)

[プレビュー]します。
![スクリーンショット 2022-08-09 10.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286322/3ea74533-0111-6769-7997-6d530af15e5c.png)

#### 注意事項

法人等略語一覧表からレコード結合を利用して置換える方法も有効です。

## 4.参考情報

#### よく使う文字列関数

https://qiita.com/Makimaki2020/items/35ab02a7375325e678c1

#### Modelerと正規表現

https://qiita.com/kawada2017/items/025352797a87dd85fbea

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
STM32G031J6M6で4個のLEDでナイトライダー


x 超超重要 なぜか秋月STM32G031J6M6がうり切れていた。注意!!(2022/8/27現在)

x 過去ログを見よ!!

x PA0をGPIOがわかる人むけ


目的
GPIOのテスト


![o_con703.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/19157e3f-ef64-9c43-bb2d-bcc2bf102989.jpeg)


![o_con684.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/23fb9283-bef2-bef1-8fa8-f9d0e88e8b21.jpeg)



参考


https://os.mbed.com/users/okano/notebook/mbed_no_koneta/


```c++


//GPIO_4LED_Knight_Rider_031_1

#include "mbed.h"

//1 LED1 PB_7
//2 VDD
//3 GND
//4 LED2 PA_0
//
//5 SWD
//6 SWD
//7 LED3 PA_12
//8 LED4 PA_11

//GPIOの初期化
DigitalOut  leds[]  = {
    DigitalOut (PB_7),  //LED1
    DigitalOut (PA_0),  //LED2
    DigitalOut (PA_12), //LED3
    DigitalOut (PA_11)  //LED4
};

//メイン関数
int main()
{

    //not delete 3s wait
    wait_us(1000*1000);// 1秒待つ
    wait_us(1000*1000);// 1秒待つ
    wait_us(1000*1000);// 1秒待つ


    //無限ループ
    while(1) {

        for(int ii=0; ii<=4; ii++) {

            for(int jj=0; jj<=4; jj++) {

                //GPIOへビットを設定
                if(ii == jj) {
                    leds[ jj ] = 1;
                } else {
                    leds[ jj ] = 0;
                }

            }//for

            wait_us(1000*1000);// 1秒待つ

        }//for

    }//while

}//main




```
Zsh: no matches foundは(N)をつけると解消できる

Zshで、「`**/*.js`」のようなglobパターンを使ってスクリプトを書いたとき、パターンにマッチするファイルが見つからないと「no matches found」というエラーが起きます。

たとえば、次のコードのように、拡張子がjsのファイル名を出力するものがあったとします。

```zsh:main.zsh
echo **/*.js
```

これを実行したとき、jsファイルが1つ以上見つかれば、ファイル名が出力され正常終了します。

```text:正常終了
a/x.js y.js
```

一方で、jsファイルがひとつもないと、次のようなエラーが出ます。

```text:エラー終了
main.sh:1: no matches found: **/*.js
```

このエラーが発生すると、処理がそこで終了していまいます。

## `(N)`をつけるとエラーを抑制できる

このエラーを抑制するには、`(N)`をパターンの末尾に追加します。

```zsh:main.zsh
echo **/*.js(N)
```

これをつけて実行すると、マッチするファイルが見つからなくてもエラーになりません。

この`N`はnull globと呼ばれるものです。
npm コマンドのチートシート

#### npmのコマンドの覚書


##### package.jsonを対話方式で作成する
```
npm init
```

##### 作成したpackage.jsonのdependenciesおよびdevDependenciesからパッケージインストール

```
npm install
npm i
```

##### 個別パッケージをインストール、かつpackage.jsonのdependenciesに書き込み

```
npm install hogePackage --save
npm i hogePackage -S

rem バージョンを指定する場合はパッケージ名の後に@をつけその後ろにバージョン
npm install hogePackage@1.2.3
npm i hogePackage@1.2.3
```

##### 個別パッケージをインストール、かつpackage.jsonのdevDependenciesに書き込み

```
npm install hogePackage --save-dev
npm i hogePackage -D
```

##### パッケージのアンインストール

```
npm uninstall hogePackage
npm un hogePackage
```

##### 個別パッケージのバージョン確認　
```
rem ローカル確認
npm info hogePackage versions --local
rem グローバル確認
npm info hogePackage versions --global
rem 最新の確認
npm info hogePackage version
```

##### インストールしたパッケージの最新版出ているか確認
```
npm outdated
```

##### キャッシュクリア
```
npm cache clean --force
```
SNSやYoutubeの誘惑に勝つ技術

最近どうしても、Youtube、Twitter、Instagramの3大誘惑に負けて、在宅での研究活動のパフォーマンスが激落な状況です。
根性で解決するのは根性なしの僕には厳しいし、SWEなら仕組みで解決したいと思いました。

## 戦略

基本的にSNSやYoutubeをいじることを0にするとどこかでリバウンドが起きると思うので、適切なタイミングだけで見れる方法にしたいです。
そして、不適切な状況では基本どうやってもいじれないようにしたいです。僕の家では主にスマホとPC(Macbook)がその対象端末なので、それぞれで運用を考えていきます。

## PC

PCでは常にSNSにアクセス不可にして、スマホに娯楽は任せることにします。
解決方法としては対象のサイトのドメインごとブロックしてしまいます。
Macbookであれば、`/etc/hosts` ドメインとIPの対応を設定することができますが、SNSやYoutubeのドメイン(www.youtube.com など)をlocalhostに転送するように設定します。これでPC全体でアクセスできなくなります。


```:例
# Don't allow to access to SNS
127.0.0.1 twitter.com 
127.0.0.1 www.youtube.com
127.0.0.1 www.instagram.com
```

## スマホ

スマホでは適切なタイミング（夜の30分とか）では、いじれるようにしたいです。
解決方法は簡単で、スマホを物理的にいじれないようにするハードウェアを購入します。

こういった商品です。
https://www.amazon.co.jp/dp/B08HZ4LYHM
![スクリーンショット 2022-08-25 4.15.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263783/898adb3e-f7fc-5ab1-aab1-6990613f981a.png)

## まとめ
強制的に使わないようにするためには、アクセスできる端末(スマホ)を1つに絞って、その端末を物理的にロック。他の端末（PC）は、常にアクセスできないようにするって運用はすごく良さそう
Amazon CloudFrontなど

# Amazon CloudFrontとエッジサーバー
**Amazon CloudWatch**とは高速コンテンツ配信ネットワーク（コンテンツデリバリーネットワーク、略してCDN）サービス。**Webコンテンツの配信を高速化する**。S3のWebサイトホスティング機能を有効にして構成したWebサーバーと組み合わせてよく使う。
高速化は、Webサーバーの中身をキャッシュ（前もって用意）する**エッジサーバー**を利用して行う。通常はWebサイトの閲覧者はWebサーバーにアクセスしてページを取得するが、毎回Webサーバーが答えていれはWebサーバーに負担がかかるので、エッジサーバーにキャッシュした内容を返させる古音によって、オリジナルのWebサーバーの負担を低減させる。
エッジサーバーはネットワークの末端近くに置かれ、各リージョンに置かれる。クライアントからアクセスするネットワークの距離が近くなるので、レスポンス速度が早くなる。
# Amazon CloudFrontの料金体系
Amazon CloudFrontは基本的に**データ転送に対して料金がかかる**。
サイトの閲覧者からリクエストや、閲覧者へのページの転送、閲覧者からアップロードされたファイルの転送に課金される。
# Amazon CloudFrontの料金クラス
Amazon CloudFrontには料金クラスがあ利、クラスによって使用できるエッジサーバーが異なる。選択した料金クラスに含まれるロケーションのエッジサーバーからコンテンツが配信される。マラ、エッジサーバーごとに料金が異なるので、閲覧者数との兼ね合いになる。
**料金クラスごとに使用可能なエッジサーバー**
|料金クラス|料金クラスに含まれるロケーション|
|-|-|
|すべて|米国・カナダ、欧州、南アフリカ・中東、日本、オーストラリア、シンガポール・韓国・台湾・香港・フィリピン、インド、南米|
|200|米国・カナダ、欧州、南アフリカ・中東、日本、シンガポール・韓国・台湾・香港・フィリピン、インド|
|100|米国・カナダ、欧州|
# 余談
## 暗号化通信にも対応
CloudFrontは、TLS/SSLによる暗号化通信にも対応し、「https://」から始まるURLでアクセスしたときは通信が暗号化される。
通常、暗号化にはサーバー証明書が必要ですが、AWS Certificate Managerというサービスと使うと無料でサーバー証明書が作れる。
Dictionaryの紐解き方

Boto3 でのお話。
NatGateway を短時間に同じタグ名で立ち上げていて、前のものは削除しているのだが describe すると削除の状態で残ってしまっているので、タグでフィルターしても複数がひっかかってしまっている。
現在、available のものを選択して削除したい、ということで、次の関数に渡すために AllocationId が必要。
Dictionary を紐解くために、以下のコードとした。

```Python        
for i in range(10):
    nat_gateway_id=response1['NatGateways'][i]['NatGatewayId']
    public_ip=response1['NatGateways'][i]['NatGatewayAddresses'][0]['PublicIp']
    allocation_id=response1['NatGateways'][i]['NatGatewayAddresses'][0]['AllocationId']
    state=response1['NatGateways'][i]['State']
    print('allocation_id:' + allocation_id)
    print('state:' + state)
    if state == 'available':
        break
```
保存したデータの分析

# データ分析との連携
S3内のオブジェクトやオブジェクトの中身に対し、**データ分析**を行う機能がある。
**S3 Select**と**Amazon Athena**は、CSVやJSONのような構造化されたテキスト形式のデータに対して、SQLのSELECT文を実行する**クエリ機能**。
**Amazon Redshift Specutrum**も同じ機能だが、大量のデータを処理できる。
# データ分析サービス
Amazon S3には、ログやIoT機器から収集したデータなど、後に分析したいデータも含まれるので、データ分析サービスとの連携が用意されている。
S3 SelectとAmazon Athenaは、S3バケットに格納したデータに対して分析するサービス。一方で、Amazon Redshift Spectrumは、S3バケット以外に置いたデータも分析できる。
## S3 Select
S3 Selectは、S3の機能で保存されている１ファイルのデータに対して、SQLを使って、集計や検索ができる機能。
CSVファイルやJSONの他、ログに使われるApache Parquetフォーマットにも対応。
集計やマネジメントコンソールからSQLを入力することで、簡単に時効できる。
CLIやSDKにも対応していて、複雑な集計をするときはプログラムを実行できる。
## Amazon AtheneとAmazon Redshift Spectrum
AthenaとRedshift Spectrumはデータ分析のサービス。
これらのS3に格納されたデータをそのまま分析できる。
S3 Selectと違い、**何を対象にどのような検索をするのかを事前に構成する必要がある**。その反面、複数ファイルを対象にすることができる。
また、AthenaとRedshift Spectrumの大きな違いは、**分析のためのサーバーを作る必要があるかどうか**。
Athenaは都度、必要に応じて分析のサーバーが自動的に作られて実行されるので、実行したときだけ費用がかかる。
一方で、Redshift Spectrumは事前に分析用のサーバーを起動して、そのサーバーを起動しておき、そのサーバーを使って分析する。処理能力に応じて、コストの低いサーバから高いサーバーまで用意する。かつ分散処理でデータ分析ができる。
**大量の複雑なデータを高速に処理するときは**、Redshift Spectrumを使う。
## データ分析ツールの使い分け
**S3 Select**は最も手軽で、CSVファイルやJSONファイルなどの１ファイルを対象に集計検索ができる。これを使うと、時間帯ごとの売り上げや製品ごとの売り上げを計算できる。
**AthenaやRedshift Spectrum**を使うとS3に置かれた複数のファイルを処理できる。また集計や検索方法を保存できるので、**何度も繰り返し、集計・検索したいときはAthenaを使う**。**Redshift**は高度な分析機能を持つデータシェアハウス。**集計・検索だけでなく、予測を立てたりすることができる**。
# 余談
## AWS Lambdaとの連携
**このほかS3と連携できる機能として、AWS Lambdaが挙げられる**。
**Lambdaはイベントドリブン（イベントに応じて処理を実行する方式）でコードを実行できるサービス**。
**S3のバケットにオブジェクトがアップロードされたことをきっかけに、Lambdaの関数を呼び出すことができる**ので「特定のバケットに画像がアプロードされ、その画像のサムネイルを作成する」「ファイルがアップロードされたら通知する」などのシステムが簡単に作成できる。
Node.jsでUUIDを生成する（crypto.randomUUID）

# Node.js 14.17.0以降
サードパーティライブラリを使わずとも、標準のCryptoモジュールでUUID v4を生成できる。

```js
const crypto = require("crypto");
console.log(crypto.randomUUID());
// => 49affff9-0216-46ed-902c-b3324fd6d094
```

https://nodejs.org/docs/latest-v14.x/api/crypto.html#crypto_crypto_randomuuid_options

# Node.js 14.17.0以前
npmのuuidモジュールを使う。
https://www.npmjs.com/package/uuid

# ブラウザの場合
ブラウザでも `crypto.randomUUID()` が使える。


https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID

# 上記いずれも使えない場合

[こちら](https://www.30secondsofcode.org/js/s/uuid-generator-node)で下記コードが紹介されている。これが実用に耐えるものなのかは分からない。

```js
const crypto = require('crypto');

const UUIDGeneratorNode = () =>
  ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
    (c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
  );

console.log(UUIDGeneratorNode()); // => 0444ae6e-2226-4ca7-9b66-b8d60dce2333
```

ざっくり解析すると、
まず `[1e7] + -1e3 + -4e3 + -8e3 + -1e11` により`'10000000-1000-4000-8000-100000000000'`という文字列が生成される。
この文字列のうち、0, 1, 8の部分を1文字ずつランダムに置換する。
4を置換しないのは、この位置はUUIDのバージョンを表し、UUID v4では４で固定だから（[参考：wikipedia](https://ja.wikipedia.org/wiki/UUID#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B34)）。
同様に8の位置はバリアントを表し、`c=8`なら`c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))`は8, 9, a, bのいずれかになる。つまりバリアント1を意味する。
1と0の部分で置換結果に差異はないようだ。置換前文字列を `1e7` や `1e3` で生成しているから0と1が出てきているだけで、特に意味は無いと思われる。なので、関数の定義を
```js
const UUIDGeneratorNode2 = () =>
  '00000000-0000-4000-8000-000000000000'.replace(/[08]/g, c =>
    (c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
  );
```
と変えても結果は同じだと思われる。
docker-composeを使ってWordPress環境を構築する

# 構成について
- wordpressコンテナは、Node.jsを入れられるようにdockerfileからimageをインストールするようにした。
- DBの接続情報は、.envファイルに記述して外部ファイル化させた。
- プラグインとテーマファイルはホスト側からもいじれるように、wp-contentディレクトリをbindマウントさせた。
- DBをホスト側からいじりたい場面もないと思うのでvolumeマウントさせた。
- MySQLはバージョン5.7じゃないとうまく動かないらしいので、バージョン指定。
- その他のイメージファイルやNode.jsのバージョンも本当は固定した方がいいんでしょうけど、今回はしない。

以下の構成で組んだ。
```
myapp/
  ├ docker/
  | └ wordpress/
  |   └ dockerfile
  ├ wordpress/
  |  └ wp-content/    # 自動生成
  ├ .env
  └ docker-compose.yml
```

# 構成ファイルの中身
```docker-compose.yml
version: '3.8'

services:
  db:
    image: mysql:5.7
    container_name: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT}
      MYSQL_DATABASE: ${DB_NAME}
      MYSQL_USER: ${DB_USER}
      MYSQL_PASSWORD: ${DB_PASSWD}
    volumes:
      - type: volume
        source: mysql_vol
        target: /db:/var/lib/mysql
    networks:
      wp_network:
        ipv4_address: 172.20.0.2

  web:
    build: ./docker/wordpress
    container_name: wordpress
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWD}
      WORDPRESS_DB_NAME: ${DB_NAME}
    restart: always
    depends_on:
      - db
    ports:
      - "80:80"
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content/
    networks:
      wp_network:
        ipv4_address: 172.20.0.3
  
  phpmyadmin:
    image: phpmyadmin:latest
    container_name: phpmyadmin
    restart: always
    depends_on:
      - db
    ports:
      - 8080:80
    networks:
      wp_network:
        ipv4_address: 172.20.0.4

networks:
  default:
    name: bridge
  wp_network:
    name: wp_network
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/24

volumes:
  mysql_vol:
```

```.env
DB_NAME=wp_dbname
DB_USER=wp_user
DB_PASSWD=wp_passwd
DB_ROOT=wp_root
```

```./docker/wordpress/dockerfile
FROM wordpress:latest
RUN apt-get update -y && apt-get upgrade -y

WORKDIR /tmp
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt install -y nodejs
RUN npm install -g browser-sync

WORKDIR /var/www/html
```

# 起動
myappディレクトリで、`docker-compose up -d`で起動。
WordPressには、80番ポートで立ち上げているので、`http://{FQDN or IPアドレス}`で接続できるはず。
phpmyadminには、8080番ポートで立ち上げてるので、`http://{FQDN or IPアドレス}:8080`で接続できるはず。

# 終了
myappディレクトリで、`docker-compose down`で終了。
ホスト側にマウントさせた情報は残ります。
超ハイクオリティ顔復元GFPGANを超えるVQFR

# 機械学習で低解像度の顔を補完

たとえば、以下の写真で、緑の四角の二人の顔に注目してみます。
![pexels-icsa-1709003 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/bb957551-1d35-c010-5287-a6206a63727d.jpeg)

拡大すると、この二人の顔は不鮮明です。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/aaf82b2e-d7be-30f0-3c3a-39fe3e3fe04c.jpeg width=400> <img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/cbe717bd-8665-dd89-ecd0-255ba97a92cd.jpeg width=400>

これをVQFRで補完します。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/1c328770-47c4-e787-169c-d15473257e61.png width=400> <img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/87bc1909-04bf-74aa-97af-aede37f52b01.png width=400>

肌の質感など、細かいところまで補完されています。

https://github.com/TencentARC/VQFR

# 使い方

推論Colab

https://colab.research.google.com/drive/1Nd_PUrHaYmeEAOF5f_Zi0VuOxlJ62gLr?usp=sharing

セットアップ

```shell
git clone https://github.com/TencentARC/VQFR.git
cd VQFR

pip install -r requirements.txt
pip install basicsr
pip install facexlib
VQFR_EXT=True python setup.py develop
pip install realesrgan  # used for enhancing the background (non-face) regions
wget https://github.com/TencentARC/VQFR/releases/download/v1.0.0/VQFR_v1-33a1fac5.pth -P experiments/pretrained_models
```

実行

```shell
python demo.py -i inputs_dir_path -o results -v 1.0 -s 1 --aligned
```

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
【Flutter】デプロイゲートで配布するアプリのバージョンを上げる方法


ios側はXCodeからAndroidはFlutterのpubspec.yamlを変更すればOKです。

※ここではデプロイゲートでアプリを配布する方法は全て省いてます。ご了承ください。

## ios側

RunnerのTARGETSのGeneralの中にあるIdentityのVeisionを変更すればOKです。

![スクリーンショット 2022-08-25 1.09.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/3d75ce31-910d-62f3-b947-02a749207a4f.png)

## Android側

プロジェクト名/pubspeck.yamlの中で記載されているversionを変更すればOKです。

![スクリーンショット 2022-08-25 1.13.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/b039c590-5c1f-b8f8-af56-a33d3683f3fa.png)


アップするたびにデプロイゲートのバージョンを上げてくれっていうことを言われて、よくよく見てみたらバージョンが上がってないことに気づき調べたけど、なかったのでなんとなくで探したら見つけました。

多分今後も忘れるだろうなって思ったので、自身の忘備録も兼ねて共有です。

どなたかの参考になれば幸いです。
室内人数カウントシステムの開発

# はじめに
コロナ渦で室内の混雑状況を知りたい機会が増えたので，室内の人数を調査するシステムを作ってみようと思った。

# 概要
Yorov5とDeepsortを用いて，室内の人数をカウントするプログラムを作成した。また，室内の人数を取得，更新できるLINEボットを作成した。(おまけ)

# 手法
人数取得のおおまかな手法は以下の2つが考えられる
1. 店内上部から店内を撮影し，その画像から物体検出によって人数を推論する(**天井手法**)
1. 出入り口に設置したカメラの映像を用いて，トラッキングと物体検出によって，入店した人数と退店した人数から店内の人数を推論する(**出入り口手法**)

## 各手法のメリットとデメリット
### 天井手法
- 画像推論なので処理が軽い　→　マシンパワーがいらない
- 撮影時の画角内の人数が確実にわかる
- 複雑な構造な部屋だと，カメラが複数台必要になる

### 出入り口手法
- 出入り口の設置であるため部屋の構造に影響されない
- 推論人数がずれた場合の処理が必要
- 動画推論なので処理が重い　→　マシンパワーが必要


# 実装
今回はとりあえず出入り口手法を実装した。

## 技術スタック
- Heroku
- Flask(Python)
- LINE Messaging API
- SQLite
- Deepsort（出入り口手法）
- yorov5（出入り口手法)
- Amazon Rekognition（天井手法）

## 出入り口手法
アーキテクチャ図は以下のようになっている。画像にはJetson nanoと書いてあるが，開発段階では自前のPCで代用している。
![Untitled Diagram.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/03d7f4e9-4373-e260-a410-a1c87978225f.png)

ソースコードは，[Yolov5 + StrongSORT with OSNetのリポジトリ](https://github.com/mikel-brostrom/Yolov5_StrongSORT_OSNet)をクローンして利用する。このプログラムでは，人間の入室，退室判定ができないのでその部分を別途実装する。

### 入室，退室判定機能の実装
下の画像の様に動画内で境界線(部屋の出入口)を引く。物体検出によって得られたボックスの重心がフレームの前後で境界線をまたいだ場合その向きによって入店，退店を判定する。ここで，境界線と，フレーム前後のボックスの重心を結んだ線分が交差するとき，境界線をまたいだとみなす。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/26ce9a0c-4bc8-5da0-f547-81c24c584f9d.jpeg">

### 作成したプログラムの抜粋
```Python
# ２線分の交差判定
def crossing_detection(
    p1: Tuple[int, int], p2: Tuple[int, int], p3: Tuple[int, int], p4: Tuple[int, int]
) -> bool:
    tc1 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p3[0])
    tc2 = (p1[0] - p2[0]) * (p4[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p4[0])
    td1 = (p3[0] - p4[0]) * (p1[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p1[0])
    td2 = (p3[0] - p4[0]) * (p2[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p2[0])
    return tc1 * tc2 < 0 and td1 * td2 < 0
```
2線分が交差しているかどうかを判定する関数


```Python
# 入か出かの判定(入->True, 出->False)
def enter_exit_detection(
    border_point1: Tuple[int, int],
    border_point2: Tuple[int, int],
    point: Tuple[int, int],
) -> bool:
    a = np.asarray(border_point1)
    b = np.asarray(border_point2)
    p = np.asarray(point)

    ab = b - a
    ap = p - a
    cross_product = np.cross(ap, ab)
    return cross_product > 0
```
ある点が，境界線の線分に対して右にあるか左にあるかを判定する関数。カメラの位置によってどっちが部屋の外かは変わるので，調整する必要がありそう。

これらの関数を利用して，各フレームごとに入退室判定を行う。また，画面上にはカウンタや境界線の表示を行っている。作成したプログラムは[このリポジトリ](https://github.com/empelt/Yolov5_DeepSort_OSNet)のmytrack.pyにまとめている。

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/6806af38-6bba-285d-700e-edde352e002a.gif)

動画内の白い境界線をまたぐ方向によってカウンタが正しく動作していることがわかる。

# LINEボットの作成(おまけ)
室内の人数を取得，更新できるLINEボットを作成した。ソースコードは[こちら](https://github.com/empelt/proken)。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/0c9326bb-8e44-437c-edb4-dfb5316de8e5.png">

# 今後の展望
- 天井手法も実装したい(Amazon Recognitionを使えばすぐできそう)
- 今回実装した出入り口手法の推論をサーバー上で行う → ローカルのマシンコストや拡張性が高まりそう，AWSの料金はすごく高そう，，
- 出入口カメラを赤外線人感センサにすることで，プライバシー問題を解決したい(RNNで波形を学習することで入室か退室かの判定ができるかな？)

# 参考文献
https://qiita.com/zu_rin/items/e04fdec4e3dec6072104
Capybara内部のリトライ間隔をのばしてCPU節約

## 背景
Railsで作ったGUIのアプリをブラウザ自動化テストする際、CI環境のCPU使用率が高いことが気になっていました。複数のテストが並行した場合に、不安定になってどれか失敗してしまうということも起きました（※CPU使用率との因果関係は不明ですが）。

テストは RSpec + Capybara + Selenium + Headless Chrome で作ってあります。chromeの起動オプションでCPU使用率を節約できるものがないか調べたりしたのですが、効果のあるものは見つけられませんでした。

---

色々探していたら、CapybaraにもCPU使用率が上がってしまう要因があることを知りました。

https://zenn.dev/megeton/articles/f73dc1a0db69b7

> **待っているとPCのファンが唸りを上げてしまう原因と対策**
>
> 次のように書くと内部では 0.01 のウェイトが入っているため処理回数は1秒間で約100回、全体で約6000回になる
>
> ```ruby
> Capybara.has_selector?(..., wait: 60)
> ```

値 `0.01` はハードコードされていて外からは変更できません。上の記事には真っ当な対策が載っていますが、既に作り込んでいるテストコードをあちこち書き換えるのは大変です。そこで応急処置的に**インストールしたCapybaraのソースコードを書き換える**ことにしました。CI環境であれば基本的に毎回作り直すので、中身を壊してしまっても影響はまずありません。

---

【11/4追記】Capybaraの該当箇所を**設定可能**にするPullRequestを取り込んでもらえ、 3.38.0 でリリースされました。詳細については[記事末尾](#追記設定可能になりました)をご覧ください。

```ruby
Capybara.default_retry_interval = 0.25
```

## Capybaraの内容確認
javascriptを活用した動的なwebページだと、テスト時は**要素が現れる（or消える）まで待つ**といった対応がよく必要になります。Capybaraは指定条件が満たされないときに**自動的に指定時間リトライ**してくれるのですが、その頻度が多いようです。

---

Capybaraのメソッド `Capybara::Node::Base#synchronize` の中に、 `sleep(0.01)` という記述があります。これがリトライの間隔です。

https://github.com/teamcapybara/capybara/blob/3.35.3/lib/capybara/node/base.rb#L91

ここを例えば `sleep(0.25)` に変えれば、**チェック回数は 0.01/0.25 = 1/25 に激減します**。 0.25 でも1秒間に約4回チェックすることになるので、数秒間しか表示されない要素であっても見逃すことは無いと思います。

## 書き換え方法
CIで実行するために、シェルでsedコマンドを使ってソースコードを書き換えます。gemをbundlerで管理していれば、インストール先のディレクトリはコマンドで出力できます。

```bash
bundle install

# "sleep" を含む行にある "0.dddd" という形の数値を "0.25" に置き換える
sed -i.bk -e '/sleep/s/0\.[0-9]*/0.25/' $(bundle show capybara)/lib/capybara/node/base.rb

# "sleep" 周辺の行を表示する
grep -n -C3 sleep $(bundle show capybara)/lib/capybara/node/base.rb

# 差分を表示する（CIが失敗しないよう終了ステータスは無視）
diff -u $(bundle show capybara)/lib/capybara/node/base.rb{.bk,} || true
```

## 結果
今回実際に困っていたテストコードに適用したところ、CI環境のCPU使用率が元の **3/4** に減りました。目に見えるほど効果が出るとは思っていなかったため驚きました（待ちの多いテストの作りだったのかもしれません）。素直に考えると、これまでと同じCPU使用率で1.3倍並行してテストを実行できることになります。

---

手元のPC上で、もっと単純な*ただ待つだけ*のコードで実験すると、 ruby, chromedriver, chrome の各プロセスでCPU使用率が **1/10** 程度にまで減りました。

<details><summary>サンプルコード</summary><div>

Ruby: 3.1.2

```ruby:Gemfile
source 'https://rubygems.org'

gem 'capybara', '~> 3.35.0'
gem 'selenium-webdriver'
gem 'matrix'
```

```ruby:simple_test.rb
require 'capybara/dsl'
require 'selenium-webdriver'

#--- configure ---#
Capybara.register_driver :selenium do |app|
  options = Selenium::WebDriver::Chrome::Options.new
  options.add_argument('--headless')
  Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end
Capybara.default_driver = :selenium
Capybara.javascript_driver = :selenium

#--- main ---#
include Capybara::DSL

visit 'http://example.com/'
find('#dummy-id', wait: 60)
```

</div></details>

## 【追記】設定可能になりました。
[コメント](#comment-0fa46c969a2c93022cbd)に後押しいただき、このリトライ間隔を設定可能にするissue/PRをCapybaraのリポジトリに出したところ、無事に取り込んでもらえました。
[Make retry interval configurable #2577 - teamcapybara/capybara](https://github.com/teamcapybara/capybara/pull/2577)

バージョン 3.38.0 からは、sedやモンキーパッチなどで無茶をしなくてもテストコード側で以下のように設定できます。

```ruby
Capybara.default_retry_interval = 0.25

# または
Capybara.configure do |config|
  config.default_retry_interval = 0.25
end
```
material-uiのTextFieldをカスタマイズして行幅を広げる方法

はじめに
--
TextFieldを使って入力フォームを作る際に、自己紹介文の入力フォームのみ行幅を広げたいと考えました。
行幅を広げるために調べたことを備忘録として残そうと思います。


環境
--
react 18.0.0
material-ui 4.12.4

TextFieldのデフォルト幅
--

TextFieldを下記のように記述すると画像のようにフォームが作成されます。

~~~react
import React, { useContext } from "react"
import TextField from "@material-ui/core/TextField";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";

~~~省略~~~

  return (
    <form className={classes.root} noValidate autoComplete="off">
      <TextField
        required
        id="outlined-required"
        label="名前"
        variant="outlined"
      />
      <TextField
        required
        id="outlined-required"
        label="自己紹介文"
        variant="outlined"
      />
    </form>
  )
}
~~~

![スクリーンショット 2022-08-25 0.21.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641341/54bfd110-9358-9553-47c8-9e3da51123d7.png)

名前のフォームの幅はこれで問題ないのですが、自己紹介文はどう考えてもこの幅だと使いづらいはず。
どうやったら行幅を広げられるか調べました。

参考にしたのはmaterial-uiの公式ドキュメントです。
(5系のバージョンを使っている場合は、公式ドキュメントの左上からバージョンを変更する必要あり。)

https://v4.mui.com/api/text-field/

行幅を広げる方法
--

調べたら簡単でした。
行幅を変更したいフォームに下記のpropsを追加するだけです。

~~~react
  multiline //=>行幅を変更する記述を有効にするために必要
  minRows="行幅を数字で指定"//=>行幅の最小を指定できる。multilineの記述がないと反映されない
~~~

先ほどの記述で使用するとこのようになります。
今回は行幅の最小を10に指定しました。

~~~react
import React, { useContext } from "react"
import TextField from "@material-ui/core/TextField";
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";

~~~省略~~~

    return (
    <form className={classes.root} noValidate autoComplete="off">
      <TextField
        required
        id="outlined-required"
        label="名前"
        variant="outlined"
      />
      <TextField
        required
        multiline
        minRows="10"
        id="outlined-required"
        label="自己紹介文"
        variant="outlined"
      />
    </form>
  )
}
~~~

![スクリーンショット 2022-08-25 0.42.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641341/fbade922-bcf6-d43a-5ae5-6abdec048a5f.png)

いい感じに行幅を広げられました！
あとはフォームを横並びではなく縦で並ばせたいので後で調整します。
公式ドキュメントを読めば色々とカスタマイズできるので、ぜひ調べてみてください。
MacデフォルトのApple GitからHomebrewのGitに切り替える

## はじめに
MacにはApple GitというGitがデフォルトで入っていますが、
開発用のパッケージはHomebrewで管理することが多いと思うので、
Homebrewでの管理に切り替えます。

## 手順
### Gitのバージョン確認
ターミナルで以下のコマンドを打った時にバージョンの末尾に（Apple Git-xxx）とつくものが表示される場合は、MacデフォルトのGitが参照されてます。
```
git --version
```
### Homebrew経由でGitをインストール
ターミナルで以下のコマンドを実行します。
```
brew git install
```

### パスの変更
ターミナルで以下のコマンドを実行して、使用しているシェルを確認します。
```
echo $SHELL
```

#### /bin/zshの場合
.zshrcファイルを開く。
```
vi ~/.zshrc
```
ファイルに以下の記述を追記する。
```
export PATH=/usr/local/bin/git:$PATH
```
変更内容を反映する。
```
source ~/.zshrc
```
#### /bin/bashの場合
.bash_profileファイルを開く。
```
vi ~/.bash_profile
```
ファイルに以下の記述を追記する。
```
export PATH=/usr/local/bin/git:$PATH
```
変更内容を反映する。
```
source ~/.bash_profile
```
変更が反映されていることを確認する。
```
git --version
```
Appleの表記が消えていれば完了です。