OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonをはじめてみるメモ

必要に迫られて、数年ぶりのPythonにチャレンジ。
自分用のメモです。


# 環境構築
PythonじゃなくてAnacondaをインストールするんだった。
ここからダウンロード↓↓↓
https://www.anaconda.com/products/distribution

# 教科書
前に買ってたこれに沿ってはじめてみる。
https://www.shoeisha.co.jp/book/detail/9784798155067

# パッケージの読み込み

基本のパッケージ
```python
import numpy as np
import pandas as pd
```

# 使いそうなコマンドメモ
配列の作成は　`np.array` サイズを確認するときは　`配列名.shape`
```python
sample_array_2 = np.array(
    [[1,2,3,4,5],[6,7,8,9,10]])
sample_array_2.shape
```

データの読み込み　`pd.read_csv("ファイル名")`　`pd.read_clipboard()`
```python
file_data = pd.read_csv("data(0-49).csv")

file_data = pd.read_clipboard()
```

データフレームのサイズも　`.shape` で確認できる。
```python
file_data.shape
```

列名の取得　`.columns`
```python
columnname = file_data.columns
```

列名を確認して、4番から28番までのデータを別データフレームに入れる
※行番号、列番号は0からはじまる
```python
data = file_data.iloc[:,4:28]
```

全体に欠損値がひとつでも含まれているか確認
```python
print(data.isnull().values.sum() != 0)
```

行ごとに欠損値をひとつでも含むか判定
```python
print(data.isnull().any(axis=1))
```

printで配列を省略せずに表示する
```python
pd.set_option('display.max_rows', 最大表示列数)
pd.set_option('display.max_columns', 最大表示行数)
```

# クラスター分析（k-means）
```python
# ライブラリのインポート
from sklearn.cluster import KMeans

clu = KMeans(n_clusters=4) # クラスター数を指定

# dataにクラスタ分析をしてclass列に分類結果を格納
data["class"] = clu.fit_predict(data) 

# 各クラスタのサンプル数を確認
print(data["class"].value_counts())

# 各クラスタの平均点（クラスタ中心）を出力
print(data.groupby("class").mean()

# クラスタ中心の各項目の差を求める
clu_maxmin = clu_center.max(axis=0)-clu_center.min(axis=0)

# クラスタ中心と同じ配列に入れる
a = clu_center.T
a["maxmin"] = clu_maxmin  # colum名を"maxmin"として配列aに追加する

# maxmin の値が大きい順に並べ替える
a.sort_values("maxmin", ascending=False)

```

# グラフ化
```python
# グラフを描画するライブラリ
from matplotlib import pyplot as plt

# グラフをJupiter Notebookに表示させるための指定
%matplotlib inline

# 配列aのデータを、maxmin列の値の大きい順にプロットする
plt.plot(a.sort_values("maxmin", ascending=False))
```

# ランダムサンプリング
```sample()```でランダムに選んでくれる
```Python
# 抽出する行数を指定
data.sample(n=10)

# 割合を指定
data.sample(frac=0.8)
```

# 行ごとに中心化をする
それぞれの行のデータが平均値＝0になるように変換したい。
転置して列ごとに中心化し、転置して戻すのが一番早そう。
```python
data2 = data.T - data.T.mean()
data_centered = data2.T
```
【Git】git diffコマンドについて

## リモートとの差分

```
$ git diff HEAD..リモート名/ブランチ名
```
```
$ git diff リモート名/ブランチ名..HEAD
```

## 直近のコミットの差分

```bash
git diff HEAD^..HEAD
```

## ブランチ間の差分

```bash
git diff ブランチA..ブランチB
```

## コミット間の差分

```bash
git diff 変更前のSHA..変更後のSHA
```

## 特定のファイルの差分
```bash
git diff -- ファイルパス
```
```bash
git diff ブランチA..ブランチB -- 対象のファイルパス
```


## ファイル名のみ出力

```bash
git diff --name-only
```
今後やらかさないために失敗の経験から学ぶ記事まとめ（その後）

今後やらかさないために失敗の経験から学ぶ記事まとめ

https://qiita.com/shimajiri/items/0ad86ad0504ecbcc1156

を拝見した。　

本番環境でやらかしちゃった人 Advent Calendar 2019

https://qiita.com/advent-calendar/2019/yarakashi-production

の記事の紹介になっているらしい。　


本番環境でやらかしちゃった人 Advent Calendar 2020

https://qiita.com/advent-calendar/2020/yarakashi-production

については、　

2020年のうちに読んでおきたい2020年アドベントカレンダーをピックアップしますまいか

https://qiita.com/e99h2121/items/dfb5004f429e352567c4

で紹介があった。　


本番環境でやらかしちゃった人 Advent Calendar 2021

https://qiita.com/advent-calendar/2021/yarakashi-production

「配電盤の電源を切る」

https://qiita.com/kaizen_nagoya/items/5fee2f3a4fb3cede675c

を投稿させていtだきました。　

ありがおうございました。　


本番環境でやらかしちゃった人 Advent Calendar 2022

https://qiita.com/advent-calendar/2022/yarakashi-production

ごめんなさい。参加していません。　

ちょっと参加が少なくなって残念です。　

かけることとかけないことがあるんですもんね。
【Java基礎】if構文-4.複数の条件分岐

［問題］　　(参照：http://www.cc.kyoto-su.ac.jp/~mmina/bp1/hundredKnocksBasic.html)
整数値を入力させ、値が正であればpositive、負であればnegative、0であればzeroと表示するプログラムを作成しなさい。


# コード
```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        if(t > 0){
            System.out.println("positive");
        }else if(t < 0){
            System.out.println("negative");
        }else if(t == 0){
            System.out.println("zero");
        }
    }
}
```

↓「－8」と入力

# 結果
```
negative
```
Googleの代わりにOpenAIのGPT-3で質問に答えるようにした

# はじめに
今流行のOpenAIでGoogleの代わりに質問に答えるようにしました。
【変更】2023-2-18
speak.shは長文だとカットされるので、行単位に処理するようにしました。（。で改行）speak.shはgoogletts-cli.plを使用しています。
【変更】2023-3-3
chatGPTのAPIが公開されたので、それに変更しました。コストがGPT3の1/10だそうです。APIキーはGPT3のものと共通です。pipとopenaiのupgradeが必要な場合があります。
# 使用方法
■単独で使用する方法
python3 /home/xxxx/ai.py 電気料金の節約方法
■Googlehomeで質問し、回答を喋らす
[Google Assitant V2 対策（IFTTTの変数入力の実現）](https://qiita.com/kobbeko/items/4f05c3ff6c1a2454d374)
の記事でtask.jsを改造する。
下記の行を追加してください。
``` javascript
} else if(value1 === "AI") {
  command = "python3 /home/XXXXX/ai.py " + value2 + " >> /dev/null 2>&1 &";
  var execSync = require('child_process').exec;
  execSync(command) ;
``` 
自分：OK グーグル タスクリストに追加
自分：OK グーグル タスク　（ルーティンでタスク＝タスクリストに追加と定義した場合）
GoogleHome：追加するものを教えて下さい
自分：AI電気料金の節約方法

# GPT-3で質問に回答するプログラム(ai.py)

``` javascript

# -*- coding: utf-8 -*-
import requests
import openai
import argparse
import subprocess
import time

# 起動オプション取り出し
parser = argparse.ArgumentParser()
parser.add_argument("param")
args = parser.parse_args()
text = args.param
print(text)

# Set the API key
openai.api_key = "XXXXXXXXXXXXX"

def generate_answer(prompt):
    # OpenAI API request to generate answer
    response = openai.Completion.create(
    engine="text-davinci-003",
    prompt=prompt,
    max_tokens=1024,
    n=1,
    stop=None,
    temperature=0.5,
    )

    answer = response["choices"][0]["text"]
    return answer


answer=generate_answer(text)
say= answer
say = say.replace('\n','') #文字列の置換(改行を全角空白)
say = say.replace(' ','　')  #文字列の置換(半角空白を全角空白）
say = say.replace('。','。\n')  #文字列の置換(半角空白を全角空白）
f = open('myfile.txt', 'w')
f.write(say)
f.close()
print(say)
f = open('myfile.txt', 'r', encoding='UTF-8')
datalist=f.readlines()
for data in datalist:
   cmd = "/home/xxxxx/speak.sh" + ' ' + data;
   subprocess.run(cmd, shell=True)
f.close()
```
# chatGPTで質問に回答するプログラム(ai.py)

``` javascript

# -*- coding: utf-8 -*-
import requests
import openai
import argparse
import subprocess
import time

# 起動オプション取り出し
parser = argparse.ArgumentParser()
parser.add_argument("param")
args = parser.parse_args()
text = args.param
print(text)

# Set the API key
openai.api_key = "XXXXXXXXXXXXX"

res = openai.ChatCompletion.create(
   model="gpt-3.5-turbo",
     messages=[
         {
             "role": "system",
             "content": "日本語で返答してください。"
         },
         {
             "role": "user",
             "content": text
         },
     ],
)
answer = res["choices"][0]["message"]["content"]
print(answer)

say= answer
say = say.replace('\n','') #文字列の置換(改行を全角空白)
say = say.replace(' ','　')  #文字列の置換(半角空白を全角空白）
say = say.replace('。','。\n')  #文字列の置換(半角空白を全角空白）
f = open('myfile.txt', 'w')
f.write(say)
f.close()
print(say)
f = open('myfile.txt', 'r', encoding='UTF-8')
datalist=f.readlines()
for data in datalist:
   cmd = "/home/xxxxx/speak.sh" + ' ' + data;
   subprocess.run(cmd, shell=True)
f.close()
```
# 参考にした記事
[AIをフル活用してRaspberry Pi 4でGPT-3とかいうの動かしてみる話 前編](https://overwhelmingrowth.com/entry/2023/02/05/001057)
brew upgrade → brew doctorを実行後にWarningが発生

# 1.brew doctorを実行したら下記の警告文が出現した
先日homebrewを`brew upgrade`で更新しました。その後に、`brew doctor`でhomebrewに異常がないかを調べたところ、下記の警告文が出現しました。
````
~ $ brew doctor 
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: Some installed formulae are deprecated or disabled.
You should find replacements for the following formulae:
  ilmbase
````
**※↑はエラー文ではありません。「なんか注意しといてね〜」 みたいな警告文みたいです**

以前にもいたような現象が起きたことがあるので、今回は冷静に対応できました。
警告文を読み解くとなんか**ilmbase**とかいうやつが邪魔してるみたいなのでアンインストールしちゃいましょう！


# 2.ilmbaseのアンインストール

下記のコマンドを実行
````
~ $ brew uninstall ilmbase
Uninstalling /usr/local/Cellar/ilmbase/2.5.8... (87 files, 1.7MB)
````

うまくアンインストールできたようなので`brew doctor`を実行して確認
````
~ $ brew doctor
Your system is ready to brew.
````
はい！うまくいきました！

# 3.最後に
homebrewは日に日に更新されていくので、定期的に`brew upgrade`を実行して更新しましょう！
`brew update`で更新もできますが、クリーンアップも同時に行いたいので私は`brew upgrade`を使用しています！
更新が終わったら`brew doctor`を実行して異常がないか確認しましょう！異常があってもすぐに影響を及ぼさないので、長くほったらかしにしてしまいがちですが、後々作業が大変になるので異常を見つけたらすぐに処置を施すことをオススメします！私もpythonの環境構築の際にpyenvやらをインストールしたことで異常が出てもほったらかしにしてしまい後から（泣）になりましたｗ

# 4.参考にした記事
#### 1. **[brew doctorでWarningが発生した時の対処法](https://qiita.com/hirokun0204/items/56c4177e3e32ec808dc5)**
#### 2. **[Homebrewのエラー解消日記](https://qiita.com/sonio/items/9fa4b7aef1174e1bb6fb)**
#### 3. **[【Mac】brew doctorコマンドで「Warning: A newer Command Line Tools release is available」と表示されたときに確認すること](https://zenn.dev/ryuu/scraps/0491e831f729c0)**
Docker環境のPHPでBootstrapをインストールする手順

# Warpで直接コマンドでインストールする
Bootstrap本家サイトでインストールするコマンドをコピーしてDockerコードの後にコマンドを追加して実施する。

https://getbootstrap.jp/docs/5.0/getting-started/download/
※URLはサイトの構成見直しで変更される可能性がある。要は「ダウンロード」のリンク先。

色んな環境に合わせたインストール方法が紹介されている。

「Composer」の欄を見つける。
「Composer を使って Bootstrap の Sass と JavaScript をインストールできます。」とあり、コマンドが掲載されている。バージョンがアップデートされればバージョン名が変わっていく。
ちなみに今日は以下。
注意点！！：以下のコマンドをそのまま使ってはだめ。

```
composer require twbs/bootstrap:5.0.2
```

Dockerなので冒頭の記述を行った後で上記のコードを追記してコマンド実施する。
```
docker-compose exec app composer require twbs/bootstrap:5.0.2
```
InfluxDB に接続するエラー EOF を解決するにはどうすればよいですか?

Failed to connect to http://localhost:8086: Get http://localhost:8086/ping: EOF
Please check your connection settings and ensure 'influxd' is running.

上記のエラーが表示され、ファイルが破損している疑いがある場合は、次のツールを使用して TSM ファイルの整合性を確認できます。

influx_inspect verify -dir <storage_root>

詳細はこちらをご覧ください:
https://docs.influxdata.com/influxdb/v1.8/tools/influx_inspect/#verify
API 31までとAPI 32からは、onStartとonActivityResultの実行順序が逆になっている件

Android 12(API 31)までは、`onActivityResult` → `onStart` の順序でしたが
Android 12L(API 32)からは、`onStart` → `onActivityResult` の順序に変わっています

**※`ActivityResultContract`を使っていても影響を受けます。`ActivityResultContract`のコールバックは`ComponentActivity`の`onActivityResult`の中でコールされるためです。**

その順序が変わっても問題が起こるようなことはなかろうなどと思っていたら、問題にぶち当たりました（単に使い方が悪かっただけではありますが）

以下のように、`onActivityResult`（実際には`ActivityResultContract`のコールバック）で、LiveDataの値を2回更新するようなことをしていました。

```kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    viewModel.liveData.value = 1
    viewModel.liveData.value = 2
}
```

そして、このLiveDataをObserveしているとしましょう。

```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    viewModel.liveData.observe(this) {
       // hogehoge
    }
}
```

各ライフサイクルイベントなどにログを仕込んで実行してみます

Android 12(API 31)まで
```
onCreate
onStart
onResume
startActivityForResult
onPause
onStop
onActivityResult
onStart
liveData: 2
onResume
```

Android 12L(API 32)から
```
onCreate
onStart
onResume
startActivityForResult
onPause
onStop
onStart
onActivityResult
liveData: 1
liveData: 2
onResume
```

LiveDataのObserverがActiveになり、値を受け取るれるようになるのは`onStart`以降なのです。

Android 12L(API 32)以降の場合、`onStart` → `onActivityResult`なので、`onActivityResult`がコールされた時点で、ObserverがActiveになっているため、2回の更新どちらの値も受け取ることができます。

ところが、Android 12(API 31)までは、`onActivityResult` → `onStart`なので`onActivityResult`がコールされた時点で、ObserverがActiveになっていません。その後のonStartでActiveになります。そのため、最終的な値を1回のみ受け取るという違いが出てしまいます。

LiveDataをすべての値の更新を受け取れる前提で使うこと自体、良くない実装です。
ただ、このライフサイクルの違いは、開発に使用している端末が最新のOSだった場合、開発中には気づくことができず、下流工程で問題が見つかる。なんてことになったりするので注意しましょう。
go.mod、go.sumファイルは何なのか

# 概要

個人的にGolangを学習している中で`go.mod`ファイルと`go.sum`ファイルについて自分なりに調査をしてみたので備忘録として書き残します。

# 環境

今回はGoのバージョン`1.20`を想定してます。

# go.modとは

`go.mod`ファイルは使用されるモジュールの依存関係を管理するファイルです。

プロジェクトを新規で始める際に`go mod init <モジュールパス>`を実行すると作成されるファイルです

例えば、`go mod init sample/app` と入力すると下記のような`go.mod` ファイルが生成されます。

```go.mod
module sample/app

go 1.20
```

今後モジュールを`go mod tidy`などでインストールする場合はここに記載されていきます。

試しにGinをインストールしてみましょう。

```go.mod
module github.com/soicchi/chatapp_backend

go 1.20

require github.com/gin-gonic/gin v1.8.2

require (
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/go-playground/locales v0.14.0 // indirect
	github.com/go-playground/universal-translator v0.18.0 // indirect
	github.com/go-playground/validator/v10 v10.11.1 // indirect
	github.com/goccy/go-json v0.9.11 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/leodido/go-urn v1.2.1 // indirect
	github.com/mattn/go-isatty v0.0.16 // indirect
	github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/pelletier/go-toml/v2 v2.0.6 // indirect
	github.com/ugorji/go/codec v1.2.7 // indirect
	golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
	golang.org/x/net v0.4.0 // indirect
	golang.org/x/sys v0.3.0 // indirect
	golang.org/x/text v0.5.0 // indirect
	google.golang.org/protobuf v1.28.1 // indirect
	gopkg.in/yaml.v2 v2.4.0 // indirect
)
```

上記のようにインストールされるモジュールとそのバージョンを管理してくれます。

## go mod tidyとは（補足）

先ほど出てきたgo mod tidyコマンドは、ソースコードを参照して`go.mod`ファイルに記載されているモジュールとの整合性を見てくれるコマンドです。したがってソースコードでimportされているのにもかかわらず、インストールされてない場合、つまり`go.mod` に記載されていない場合に自動的に該当モジュールをインストールしてくれます。また、ソースコードで使用されていないモジュールが`go.mod`に記載されている場合、自動的に削除してくれます。そしてそれらの情報を`go.sum`に記載します。（`go.sum`ファイルの詳細については後述）

つまりまとめると下記のようになります。

- go.modファイルがソースコードと整合性あるかを確認する
- ビルドするために必要なモジュールを追加・削除する
- 上記の情報をgo.sumへ記載する

# go.sumとは

`go.sum`ファイルは先ほど説明した`go.mod`ファイル内のモジュールの依存関係をハッシュ化したものを保存するファイルです。このファイルはgo.modファイル同様にビルドする際に使用されます。なぜ、わざわざハッシュ化して保存するのでしょうか。確かに`go.sum`ファイルがなくてもビルドすることができます。それは`go.mod`との整合性を図り、一貫性と信頼性を担保するために必要なようです。

ではファイルの中身はどのようになっているのでしょうか。

先ほどginをインストールした際の`go.sum`ファイルです。

```go.sum
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
.......省略
```

# まとめ

今回はGoで開発する際の基礎的な部分のご説明でした。

普段インタプリタ言語しかやっていない私にとってこれからGoを学べることにワクワクしています。

これから日々の学びをアウトプットしていこうと思います！

最後まで読んでいただいてありがとうございました。
PyTorch 2.0 Nightly版でGPT日本語文章生成してみた

2023年3月上旬にPyTorch 2.0がリリースされる予定です。

https://pytorch.org/get-started/pytorch-2.0/

このPyTorch 2.0の目玉機能に`torch.compile()`というものがあります。これを使ってTransformersの日本語文章生成を試してみました。

## 環境
- Google Colaboratory
    - GPU有効（Nvidia Tesla T4）
- PyTorch 2.0.0.dev20230213+cu117

### 環境構築
[Google Colaboratory](https://colab.research.google.com/?hl=ja)を利用します。

2023年2月16日現在、PyTorch 2.0 Nightlyビルドは日々開発が行われているせいかインストールするたびに挙動が不安定になる事があります。なので、バージョンを指定してインストールします。

```
!pip install numpy --pre https://download.pytorch.org/whl/nightly/cu117/torch-2.0.0.dev20230212%2Bcu117-cp38-cp38-linux_x86_64.whl --force-reinstall
```

またTransformersもインストールしておきます

```
!pip install transformers sentencepiece
```

## 文章生成
[rinnaの公開しているGPTモデル](https://github.com/rinnakk/japanese-pretrained-models)を利用します。好みのモデル名を設定します。

```python
MODEL_NAME = 'rinna/japanese-gpt2-xsmall'
# 好みで選択
# MODEL_NAME = 'rinna/japanese-gpt2-medium'
# MODEL_NAME = 'rinna/japanese-gpt-1b'
```

指定したモデルを読み込みます。

```python
import torch
from transformers import T5Tokenizer, AutoModelForCausalLM

tokenizer = T5Tokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME)

if torch.cuda.is_available():
    model = model.to("cuda")
```

次がPyTorch 2.0で異なるところです。`torch.compile()`の1行を追加します。

```python
model_optimized = torch.compile(model)
```

文章を生成する実装をします。

```python
input_ids = tokenizer.encode(
    "昔々あるところに",
    add_special_tokens=False,
    return_tensors="pt"
)

def generate_by(model):
    return model.generate(
        input_ids.to(model.device),
        pad_token_id=tokenizer.pad_token_id,
        do_sample=True,
    )[0]

print(tokenizer.decode(generate_by(model_optimized)))
```


```:出力※毎回異なります。
昔々あるところに、お世継ぎを残すために産まれたばかりの王子様と魔女と4人の魔女がいました。
（以下略）
```

以上です。`torch.compile()`以外は今までと同じであり、この1行を通っていないモデルでも普通に動きます。PyTorch 2.0と1.x系は互換性が高いようです。

### PyTorch 2.0での変化
公式ブログによると、PyTorch 2.0で`torch.compile()`を噛ますことでTransformersの多くのモデルにおいて処理が高速化したようです。しかし今回利用したGPUとモデルでは、色々試してみたものの速度の変化が全く見られませんでした。

```python
# 生成速度は変わらず
generate_by(model)
generate_by(model_optimized)
```

`torch.compile()`では様々なモードを設定することができるようです。しかし、これらによる変化も今回のコードでは分かりませんでした。

```python
model_optimized = torch.compile(model)
# フレームワークのオーバーヘッドを減らすため最適化するが、メモリが多く消費される。小さなモデルで効果的
model_optimized = torch.compile(model, mode="reduce-overhead")
# 最速のモデルを生成するようになるが、コンパイルに時間がかかる
model_optimized = torch.compile(model, mode="max-autotune")
```

## 参考

- [PyTorch 2\.0 \| PyTorch](https://pytorch.org/get-started/pytorch-2.0/)
- [Accelerating Hugging Face and TIMM models with PyTorch 2\.0 \| PyTorch](https://pytorch.org/blog/Accelerating-Hugging-Face-and-TIMM-models/)
【JavaScript】ES2023で導入された非破壊的メソッド

# ES2023で導入された非破壊的メソッドを紹介します

* toReversedメソッド
* toSortedメソッド
* toSplicedメソッド
* withメソッド

# toReversedメソッド

* reverseメソッドは**破壊的**に配列の要素を逆順にする
* toReversedメソッドは**非破壊的**に配列の要素を逆順にする

```sample1.js
// reverse
const a = [1, 2, 3];
const b = a.reverse();

console.log(a); // [3, 2, 1]
console.log(b); // [3, 2, 1]

// toReversed 👍
const c = [1, 2, 3];
const d = c.toReversed();

console.log(c); // [1, 2, 3]
console.log(d); // [3, 2, 1]
```

# toSortedメソッド
* sortメソッドは**破壊的**に配列の要素をソートする。
* toSortedメソッドは**非破壊的**に配列の要素をソートする。

```sample2.js
// sort
const a = [3, 1, 2];
const b = a.sort();

console.log(a); // [1, 2, 3]
console.log(b); // [1, 2, 3]

// toSorted 👍
const c = [3, 1, 2];
const d = c.toSorted();

console.log(c); // [3, 1, 2]
console.log(d); // [1, 2, 3] 
```

# toSplicedメソッド
* spliceメソッドは**破壊的**に配列の要素を取り除いたり、置き換えたり、新しい要素を追加できる
* toSplicedメソッドは**非破壊的**に配列の要素を取り除いたり、置き換えたり、新しい要素を追加できる

:::note warn
ただspliceとtoSplicedの戻り値に下記違いがあるので、扱う際には注意が必要そうです。

* spliceの戻り値・・・削除された値が配列化されたもの
* toSplicedの戻り値・・・配列から要素を削除したコピーを返す
:::


```sample3.js
// splice
const a = [1, 2, 3, 4];
const b = a.splice(1,2);

console.log(a); // [1,4]
console.log(b); // [2,3]　戻り値は削除された値が配列化されたもの

// toSpliced 👍
const c = [1, 2, 3, 4];
const d = c.toSpliced(1,2);

console.log(c); // [1,2,3,4]
console.log(d); // [1,4]　配列から要素を削除したコピーを返す
```

# withメソッド
第一引数に配列のindex番号を指定して、その要素を第二引数の値で置換します。

既にJSでは、非推奨ですが別でwith文があるので、今回追加された配列操作のwithメソッドと命名が被ってるので、ややこしいですね。
[非推奨のwith文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/with)


```sample4.js
// with 👍
const c = [1, 2, 3, 4];
const d = c.with(1,'👍');

console.log(c); // [1, 2, 3, 4]
console.log(d); // [1, '👍', 3, 4]
```

# まとめ
いちいちシャローコピーしなくも良いので、コードがすっきりしそうですね。


# 参考にさせていただいた記事
https://github.com/tc39/proposal-change-array-by-copy
Ruby環境構築＆バージョン管理（Mac）

MacでのRuby環境構築についてまとめます。
また、開発を行う上で、複数のバージョンを管理したい時があると思うので、Rubyのバージョンを簡単に切り替えてくれるツールであるrbenvについても記載しています。
ちなみにMacでは元からRubyが入っています。

# Rubyインストール手順
- 1, Homebrewをインストールする
- 2, Homebrewを用いてrbenvをインストールする
- 3, rbenvを用いてRubyをインストールする

## 1,Homebrewをインストールする
下記コマンドをターミナルで実行
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```
インストールされているかの確認
```
brew -v
```
下記のように出ていれば問題ないです。バージョンの部分はインストールした際のバージョンで異なります
```
Homebrew 4.0.0
```

## 2, Homebrewを用いてrbenvをインストールする
下記コマンドをターミナルで実行
```
brew install rbenv ruby-build
```
インストールされているかの確認
```
rbenv -v
```
下記のように出ていれば問題ないです。バージョンの部分はインストールした際のバージョンで異なります
```
rbenv 1.2.0
```
#### rbenvの設定
```
echo 'eval "$(rbenv init -)"' >>  ~/.zshrc
source ~/.zshrc
```

## 3, rbenvを用いてRubyをインストールする
### インストール可能なRubyのバージョン一覧の表示
```
rbenv install -l
```
下記のようにインストール可能なバージョン一覧が表示されるかと思います。
```
2.7.7
3.0.5
3.1.3
3.2.1
jruby-9.4.1.0
mruby-3.1.0
picoruby-3.0.0
truffleruby-22.3.1
truffleruby+graalvm-22.3.1
```

### 指定したRubyのバージョンをインストール
```
rbenv install 3.2.0
```
全てのシェルでこのバージョンを使用するため、global設定を行います
```
rbenv global 3.2.0
```
インストールされているかの確認
```
ruby -v
```
下記のように出ていれば問題ないです。
```
ruby 3.2.0
```

### 【補足】下記のようなエラーが出た場合
```
warning: It seems your ruby installation is missing psych (for YAML output).
To eliminate this warning, please install libyaml and reinstall your ruby.
```
libyamlをインストールした後に、Ruby3.2.0をインストール
```
brew install libyaml
rbenv install 3.2.0
```

## 参考
[Ruby3.2.0をインストールするときは、libyamlも必要](https://zenn.dev/fuuukeee3/articles/22caeb537cf1a6)
deck.gl×React×TypeScript 環境構築

## はじめに
deck.gl をさくっと試してみたいと思います。
deck.glの環境構築はWeb記事が少なかったので記録してみました。

## deck.gl とは
>deck.glは、大規模なデータセットの高性能なWebGLベースの視覚化を簡素化するために設計されています。
ユーザーは、既存のレイヤーを合成することにより、最小限の労力で印象的な視覚的結果を素早く得ることができます。

引用：[Introduction](https://deck.gl/docs)


## 環境構築手順
### Reactプロジェクト作成
deck.glはReactとの親和性がよさそうなので、Reactを使います。

一から開発サーバの起動やらビルドやらの設定をするのは面倒なので、`create-react-app` を使います。
`sample` には適当なフォルダ名をいれてください。
`--template typescript` を指定することでcreate-react-appにTypeScriptを導入できます。

```powershell
npx create-react-app sample --template typescript
```

以下のコマンドを実行すると、開発サーバが起動します。
http://localhost:3000/ にアクセスすると、テンプレートのWebサイトが表示されます。
```powershell
npm start
```

### deck.glインストール
上で作成したプロジェクトにdeck.glをインストールします。

```powershell
cd sample
npm install deck.gl --save
```

### サンプルコード作成
[Using deck.gl with React](https://deck.gl/docs/get-started/using-with-react)と、[Using deck.gl with TypeScript](https://deck.gl/docs/get-started/using-with-typescript)を参考に、src/App.tsx を以下のように書き換えます。

```react
import React from 'react';
import DeckGL from '@deck.gl/react/typed';
import { LineLayer } from '@deck.gl/layers/typed';

// Viewport settings
const INITIAL_VIEW_STATE = {
    longitude: -122.41669,
    latitude: 37.7853,
    zoom: 13,
    pitch: 0,
    bearing: 0,
};

// Data to be used by the LineLayer
const data = [{ sourcePosition: [-122.41669, 37.7853], targetPosition: [-122.41669, 37.781] }];

function App() {
    const layers = [new LineLayer({ id: 'line-layer', data })];

    return (
        <div className="App">
            <DeckGL initialViewState={INITIAL_VIEW_STATE} controller={true} layers={layers} />
        </div>
    );
}

export default App;
```

~~達成感薄めですが~~ ラインを表示することができました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/2694ea1c-b5e2-28a1-f8a0-2aa7c9dca5ff.png)

## おわりに
deck.glで3D Tilesも読めるのはいいですよね。
deck.glを使ってGISデータをインパクトのある見た目にしてみたいです！

## 参考文献
https://deck.gl/

https://gunmagisgeek.com/slide/learn-deckgl/deck.gl/#/
tmux

・デタッチしたセッションの一覧を表示
tmux ls

・指定したセッションに再接続
tmux attach -t [番号]

・新しいセッションを作成
tmux new-session

・セッションの削除
tmux kill-session -t [番号]

・ウィンドウ切り替え
[ctrl + b] [ウィンドウ番号]

・カレントウィンドウの削除
[ctrl + b] [&]

・ウィンドウを上下に分割
[ctrl + b] ["]

・ウィンドウを左右に分割
[ctrl + b] [%]

・分割したウィンドウに移動する
[ctrl + b] [矢印キー]

・分割したウィンドウを閉じる
カーソルを移動して「exit」と入力する

・作業状態を保存して終了(デタッチ)
[ctrl + b] [d]
PHP：バリデーションエラー時にformで入力した値を消さないようにする

# input textなどの場合value値を使う

## テキスト入力欄などのvalue値は「初期入力値」を表す

例

```
<input type="text" id="title" name="title" value="<?php echo $album['title'] ?>">
```


# input radio（ラジオボタン）の場合は初期値はcheckedを使う

```
<input type="radio" name="card" id="spade" value="スペード" <?php echo ($player["spade"] === 'スペード') ? ' checked' : ''; ?>>
<label for="spade">スペード</label>
```
SwiftUIのAppStorage、UserDefaultsについて

# **1.UserDefaultsについて**

[Apple公式のUserDefaults](https://developer.apple.com/documentation/foundation/userdefaults)については、以下のように記載されています。
```
An interface to the user’s defaults database, where you store key-value pairs persistently across launches of your app.
```
つまり翻訳すると、UserDefaultsはキーと値のペアを永続的に保存することができるインターフェースなのですという意味になります。
UserDefaultsを利用することによって、簡単にデータを保存、参照したりできます。
永続的にデータを保存すると言っても、アプリを削除した場合データは削除されます。

# **2.データの保存方法について**
どんなオブジェクトでも保存可能です。

```swift
UserDefaults.standard.set(value: Any?, forKey: String)
```

使用したことはないですが、二次元配列も保存可能です。

```swift
let list: [[String]] = [["Microsoft","Windows","Hololens2","Unity"],["Apple","iOS","iPhoneXS","Swift"]]
UserDefaults.standard.set(list, forKey: "infoList")
```
こちらの記事を参考にしました
https://ios-docs.dev/userdefaults/

# **3.synchronize()は非推奨**
以前までは、永続的に保存するために、以下のコードが必要であった。

```swift
UserDefaults.standard.synchronize()
```
しかし、[Apple公式](https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize)によると非推奨であると以下のように明言されている。

```
Waits for any pending asynchronous updates to the defaults database and returns; this method is unnecessary and shouldn't be used.
```
# **4.データの参照方法について**

UserDefaults.standard　以降を型によって変えて取得する。
```swift
UserDefaults.standard.string(forKey: String)
UserDefaults.standard.bool(forKey: String)
UserDefaults.standard.integer(forKey: String)
```
guard letや if letを使い安全に取得すると良い。

以下の例は、保存方法で扱った二次元配列の続きです。
```swift
//if letの場合
if let infoList = UserDefaults.standard.array(forKey: "infoList") as! [String] {
    //何かしらの処理
}

//guard letの場合
guard let infoList = UserDefaults.standard.array(forKey: "infoList") as! [String] else { return }

```

# **本題 SwiftUIで[@AppStorage](https://developer.apple.com/documentation/swiftui/appstorage)を使う**
SwiftUIでは、[@AppStorage](https://developer.apple.com/documentation/swiftui/appstorage)の変数を定義することによって、UserDefaults.standardの構文を使わずにシンプルにデータを保存または参照することが可能になります。
以下のように実にシンプルであり、覚えていて損はないと思います。

```swift
@AppStorage("キー") var 変数名 = ""
```

以下は実装例です。
もしどこかの場面でcityの変数に対して、値を代入していれば、それが永続的に保存されていて、参照され、表示されます。
```swift
struct HomeView: View {
    @AppStorage("city") var city = ""
    
    var body: some View {
        VStack {
            Text(city)
        }
    }
}
```
UserDefaults.standardを全く使わないのか？と言われれば、UserDefaults.standardを使う場面もあると思います。
実際にはViewで表示する際に、保存されていない値を表示したり、保存している値を表示させたいケースもあるでしょう。
PHP：外部ファイルを読み込む方法が二種類（requireとinclude）あり、その違い

# 読み込みが失敗した時のその後の挙動に差があるだけ
処理を継続するか、終了するか、の違い。

# requireは処理を中断する

基本的に、関数などの重要な処理を読み込む時に使う。


# includeは処理を続ける

基本的にはHTMLやテキストの読み込みはinclude。
HTMLはシステム的な重症な弊害はないため。
疑問：ではHTMLもrequreでいいじゃないかと思うが、それも何か理由があるのだろう。

# ※ require_onceとinclude_once は言わずもがな。
一度しかファイルを読み込まない時に使う。


# 外部ファイルがなければ話にならない場合はrequire

例えば、外部ファイルがあるか無いかわからないけど、あれば読み込みたい場合などにはincludeを使います。

一方、その外部ファイルが無ければ話にならない場合などにrequireを使っておくと、万が一無かった場合に処理を終了させることができます。
UE4 マウスホイールでのアクションがカクカウでスムーズで無い事への対処法

環境等にもよると思うが、カメラのズームをするために[この](https://mozpaca.hatenablog.com/entry/20170605/1496672393)記事を元に作成した所。。スムーズに動かない・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912815/a9b7f802-c200-b850-feab-974f2d525e94.png)

入力を可視化してみたけど軸データで取ればスムーズに動いてる。
ほなこうじゃ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912815/18b49b48-532f-4399-890b-44ada42ac98c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912815/442adbc7-b262-a1d2-6356-b3aeda050ef7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912815/019c949e-75e1-73e8-f5da-d6c4ca64cdd5.png)

見下ろし型だからheightをいじってる。functionはheightの変数+-してるだけ。
ｽﾑｰｽﾞ!
ログ出力とログ監視についてまとめる

後輩よりログの出力と監視の正解がわからないという話を受けたので、私なりの考え方をまとめてみます。
ここは、個人、プロジェクトの趣向もあると思いますが、、、、経験上多かったもの、良かったパターンを記載してみることとします。

### ログ出力
パフォーマンスに影響する部分だと思っており、極力出力したくない。
下記の観点から、出力対象を限定する
　１．エラー発生時の原因調査ができること
　２．ユーザ問い合わせ時にトランザクションが追えること
　３．性能的問題が発生した場合原因調査できること

### １．エラー発生時の原因調査ができること
エラーと名のつくものすべて出します。（チェックエラー、業務エラー、検査例外、非検査例外）
Javaの話になりますが、例外に関しては基底クラスでcatchし、ログ出力の実装箇所を１つにまとめることが多いです。
もしくは、ErrorHandlerやAOPを実装し、例外発生を捉え一律規定のフォーマットでログ出力できるよう標準化を行えばよいかと思います。
チェックエラーや業務エラーはチェック処理自体が個別になりがちなので、基本個別出力にしています。

基底クラスで～～～のくだりはこんなイメージです。
ログ出力部分は基底クラスのみに実装し、各クラスは例外をthrowすればOKな作りとしてます。（適当なので文法ミスあればすみません、、、
```java

public class BaseService {
  abstract public void execute(); // 各クラスではBaseServiceを継承してexecuteを実装する

  public void main() {
    try {
        execute();
    } catch (Exception e) {
        // 基底クラスの中でexecuteが投げた例外をcatchしハンドリングする。各クラスはexecuteから例外をthrowするだけでよい
        logger.error(e);
    }
  }
}
```

### ２．ユーザ問い合わせ時にトランザクションが追えること
HTTPのInとOutを基本出すようにしています。
HTTPリクエストのクエリパラメータ、リクエストボディ、認証情報（例えばCookie）は出力することが多いです。
HTTPレスポンスはサイズが大きくなりがちなのであまり出力しません。HTTPステータスコードやレスポンスサイズ、レスポンスタイムはもちろん出します。
SQLのトレースログなども、あれば大助かりですが性能への影響が大きいので私はOFFします。

### 3. 性能的問題が発生した場合原因調査できること
上記のログが整っていれば十分かと思います。
レスポンスタイムから遅いものを特定 → クエリパラメータ、リクエストボディからリクエストの再現。と手順を踏めばローカルや開発環境で原因調査ができるかと思います。

### その他
アクセスログ系とエラーログ系で出力するファイルは別にしています。
また、ログレベルはもちろん出すのですが、それとは別にメッセージコードを採番することが多いです。
口述する監視に関わってきます（例えばFATALを一律エラーとして検知してしまうと運用が面倒になったり、、、）

最近だとSPAの構成も多いですが、Javascriptのエラー（ブラウザのconsole）はログ出力できないため、
ErrorHandlerを実装し、Javascriptで例外発生 → catch → ログ送信APIを呼んで例外内容を送り付ける → サーバサイドで受け取った内容をファイルに出力する。というやり方もやってます。

### ログ出力まとめ
基本、機能 × 非機能で問題が発生した際に原因調査できるよう情報を整理すればよいかと思います。
私は今まで上記の考え方で困ったことはないですが、サービスの特性によって必要な情報は変わってくると思います。
（例えばBtoCサービスならもう少しセキュリティ関連のログを出したほうが良い。とか）

### ログ監視
監視対象はエラーログ系のファイルのみです。
検知したい対象はユーザ業務が止まる可能性のあるエラーと、想定外のエラーとすることが多いです。
つまり、チェックエラーと業務エラー以外すべて。となります。
いろいろ考え方はあると思いますが監視定義はホワイトリスト方式が良いかと思います。
検知の除外対象としてチェックエラーと業務エラーをホワイトリストに追加し、それ以外の出力はすべて検知対象とみなします。
運用しているうちに、このエラーは検知しなくても問題ないな。とかそういった切り分けができてきます。
検知しなくて良いエラーはそのエラーメッセージコードをホワイトリストに追加し、エラーとして検知しないよう対応します。
なので、最初はエラーとして扱わなくて良いものもエラーとして検知してしまいますが、徐々に収束していくことになります。
私はFalsePositive的思考なので、エラーを誤検知して、結果問題なかったなら良いじゃん。って考えですね。
それよりもエラーの見逃しのほうが怖いので少し広めに検知しておきたい気持ちです。

まとめるとこんな感じです。

| ログファイル |    中文類   | 小分類          | 監視有無 | 検知有無 |
|:-----------|:------------|:----------------|:-------:|:--------:|
| アクセスログ |             |                 |   ×    |    ×   |
| エラーログ   |チェックエラー|                 |   〇   |    ×   |
|             | 業務エラー   |                 |   〇   |    ×   |
|             | 例外        | ホワイトリスト対象|   〇   |    ×   |
|             |             | その他           |  〇   |    〇   |



だいたい、こんな考えで普段運用設計を進めています。
違う考え方や、イマドキはこうだよ！というのがあればぜひ教えてください。
CodeBuild operational notification 対応

# 課題
AWS から CodeBuild operational notification が届きました。

> We are reaching out to you because you ran a build using the Ubuntu standard 4.0 [1] Docker Image, in the last 30 days.
Starting March 30, 2023, AWS CodeBuild will be moving these images to an unsupported status and they will not be cached on the build hosts anymore.
>
> You may continue using these images for your builds, but will notice an increase in provisioning latency after March 30, 2023.
These images will also not be getting any new updates. We recommend updating your Build Projects to use the latest build images in order to get the latest language runtimes and tools. For more information on how to do this you can follow 'Docker images provided by CodeBuild' [2].
>
> If you have any questions or concerns, please reach out to AWS Support [3].
> 
> [1] Platform: Ubuntu 18.04 - Image: aws/codebuild/standard:4.0 - Definition: ubuntu/standard/4.0
> [2] https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html
> [3] https://aws.amazon.com/support

「誰だ君は？」ということで日本語訳も載せておきます。

> 過去30日以内にUbuntu standard 4.0 [1] Docker Imageを使用してビルドを実行したため、ご連絡を差し上げました。
2023年3月30日から、AWS CodeBuildはこれらのイメージを非サポート状態に移行し、ビルドホスト上にキャッシュされなくなります。
> 
> これらのイメージをビルドに使用し続けることはできますが、2023年3月30日以降、プロビジョニングのレイテンシーが増加することに気がつくでしょう。
また、これらのイメージは新しいアップデートがされなくなります。最新の言語ランタイムとツールを利用するために、ビルドプロジェクトを更新して最新のビルドイメージを使用することをお勧めします。この方法の詳細については、「CodeBuildが提供するDockerイメージ」[2]を参照してください。
> 
> ご質問やご不明な点がございましたら、AWSサポートまでご連絡ください[3]。

書いてある通りですが、 Ubuntu18 のイメージはサポート切れだからもう使わないでね。
使っても良いけどずーっと遠くからイメージ取得するからデプロイ完了するまで時間が掛かるよ！
ということですね。

# 解決
[AWS Lambda における Python 3.6 のサポート終了](https://qiita.com/___nix___/items/218fdbe400cbb60829b0)
の時と同様にAWS環境内全てをサクッと精査したいですよね。

## コード

```shell
#!/bin/sh

_ACCOUNT_ID=************

for region in `aws ec2 describe-regions --region ap-northeast-1 --all-regions | jq -r .Regions[].RegionName`
do
  echo "# region: ${region}"
  for project in `aws codebuild list-projects --region ${region} --cli-read-timeout 5 --cli-connect-timeout 5 --query "projects[]" --output text`
  do
    image=$(aws codebuild batch-get-projects --region ${region} --cli-read-timeout 5 --cli-connect-timeout 5 --names "arn:aws:codebuild:${region}:${_ACCOUNT_ID}:project/${project}" --query "projects[].environment.image" --output text)
    if [[ "${image}" == "aws/codebuild/standard:4.0" ]]; then
      echo "${project}"
    fi
  done
done
```

# 結果

```
...
# region: ap-northeast-1
プロジェクト名
プロジェクト名
プロジェクト名
...
```

のような結果がリージョン毎に表示されますので、このプロジェクトのビルド環境を変更してあげてくださいね。

## 注意
```shell
An error occurred (UnrecognizedClientException) when calling the ListProjects operation: The security token included in the request is invalid.
```
のようなエラーがリージョンによっては表示されますが、そもそも EC2用 のリージョン一覧使っているので、`aws codebuild list-projects` が未対応のリージョンではこのようなエラーとなってしまいます。

# 一言
2023年2月16日現在、AWS公式のチェック用スクリプトは提供されていません。
今回はそれ程緊急性や重要性が高く無いということでしょうか。

だとしてもサポート切れについてはしっかりと対応しておきましょう。
Macbook キーボード重複入力のストレスを解消する

## 起きたこと
ある時から１回だけ押したはずなのに重複して入力されるキーが現れました。`b`と打ったはずなのに、`bb`となってしまうので、`macbook`が`macbbook`になってしまいます。どうやら、バタフライキーボードと呼ばれる薄いキーボードを搭載したMacbookではよく起きる現象だとか。

## 対策
「[Unshaky](https://unshaky.nestederror.com/)」を入れました。キータッチへの反応速度が速すぎる場合、制御してくれます。

https://unshaky.nestederror.com/

反応速度はキーごとに自由に変えられて、私はタイピング遅いので`50`設定で快適に使えています。

![スクリーンショット 2023-02-16 21.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/aef026ed-1a5f-789e-68bf-485d252a8e99.png)


🔽 制御してくれた数が見れます。

![スクリーンショット 2023-02-16 21.37.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293962/57d965bc-d133-70f7-2b8f-09f5b713ddb8.png)

## TIPS
購入して4年以内のバタフライキーボードを搭載したMacBook、MacBook Air、MacBook Proであれば、Appleが修理費用を負担してくれるそうです。

https://support.apple.com/ja-jp/keyboard-service-program-for-mac-notebooks
n度目の emacs font settings 2023

https://myrica.estable.jp/myricamhistry/ から font download

```elisp
(set-face-attribute 'default nil :family "MyricaM M" :height (* 18 10))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25422/bbf28419-8283-19cf-5df9-13aecfa0eb77.png)

とても簡単。
バーティカルバーが上下に分かれてるのが好きです。
Terraformのローカル変数(mapのlist)を使って複数のIAM設定を管理する

## 概要

TerraformでGoogle CloudのIAM設定をする際に、ロールとプリンシパルの組み合わせを変数で管理する方法について書きます。

TerraformでIAMの設定をする際には、`google_*_iam_member`や`google_*_iam_binding`といったリソースで定義します[^1]。
しかし、１ロールの設定毎に１リソースで定義すると、割り当てるロールやプリンシパルや種類が増える場合にリソース数が増え、命名が複雑化し、管理もしづらくなります。

そこで、IAMロールとプリンシパルの組み合わせをローカル変数(mapのlist)で定義し、IAM権限の設定を１リソースで定義します。
リソースは`google_*_iam_binding`を使ってますが、`google_*_iam_member`などでも同様に読み替え可能かと思います。ただし、併用はできないのでご注意ください。

[^1]: https://cloud.google.com/docs/terraform/best-practices-for-terraform?hl=ja#iam

## 前提

Providerは以下を想定します。
```
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "4.50.0"
    }
  }
}
```

以降の例では、以下の要件を満たすようなGCSバケットのIAM設定を想定します。
- メンテナー（Googleグループ）は、バケット設定を編集できるようにしたい
- アプリ（サービスアカウント）は、オブジェクトの更新をできるようにしたい
- 誰でもオブジェクトを閲覧できるよう公開したい

## ローカル変数の定義

ローカル変数を以下のように定義します。

```
# GCSにアクセスするプリンシパル
locals {
  maintainer_principal = "group:<Googleグループのメールアドレス>
  app_sa_principal = "serviceAccount:<サービスアカウントのメールアドレス>
}

locals {
  # ロールとプリンシパルの組み合わせで変数を定義
  storage_iam = [
    {
      # メンテナーの手動操作でバケットの設定変更を許可する
      role = "roles/storage.admin",
      members = [
        local.maintainer_principal,
      ]
    },
    {
      # アプリからの操作と、メンテナーによる手動操作でオブジェクトの更新を許可する
      role = "roles/storage.objectAdmin",
      members = [
        local.maintainer_principal,
        local.app_sa_principal,
      ]
    },
    {
      # GCSバケットはインターネットに公開する
      role = "roles/storage.objectViewer",
      members = [
        "allUsers",
      ]
    }
  ]
```

バケット内のオブジェクトをインターネットに公開する設定については公式ドキュメントを参照しました。

https://cloud.google.com/storage/docs/access-control/making-data-public?hl=ja#buckets

## GCSバケットの設定

バケットを定義し、先ほど定義したローカル変数を用いてIAM権限の設定をします。
for_eachのループによりそれぞれ設定されるので、個別にリソースを定義する必要がなくなります。

```
# バケットの定義は適当です。バケット名はグローバルで一意にする必要があります。
resource "google_storage_bucket" "hoge_fuga_storage" {
  name          = "hoge-fuga-storage"
  location      = "ASIA"
}

# ローカル変数を参照し、IAM権限を設定する。
resource "google_storage_bucket_iam_binding" "hoge_fuga_storage_iam_binding" {
  for_each = { for i in local.storage_iam : i.role => i }

  bucket  = google_storage_bucket.hoge_fuga_storage.name
  role    = each.value.role
  members = each.value.members
}
```

## まとめ

IAMロールとプリンシパルの設定をmapのlistとしてまとめることで、IAM設定をシンプルにする方法について書きました。
TerraformはIAM設定を１つのリソースとして定義するため、権限変更が重なった場合にリソース名の命名規則を一定に保つことは個人的に難しいと感じました。そのため、IAM設定に関してはあらかじめ変数化しておき、柔軟に変更できるようにしておくのが、個人的にはいいのではないかと考えています。
また、複数の権限修正であっても１箇所に変更が集中するため、レビュー時に差分を比較しやすいというメリットも挙げられると思います。
AACのネットラジオ

fmstream.orgを見ているとHLSではなく生のAACのストリームのステーションもあります。

http://fmstream.org/index.php?c=FT

これらはHLSの再生に使ったデコーダーで同じように再生できます。

```
# fetch -o /tmp/rajiru.aac  http://liveradio.swr.de/sw890cl/swr3/play.aac
```

fetchはFreeBSD標準のwgetやcurlのようなコマンドで、大きいので普通は入れてないんですが、こういう使い方もできます。

fetchはhttpsにも対応しています。証明書のエラーが出る場合は--no-verify-peerオプションがあります。

たいていの場合httpもあるケースが多いので、確認してみるのもよいです。

公共放送をhttpsで送るのはナンセンスです。

httpであればfetchコマンドではなくnc(netcat)コマンドでも頑張れば出来るかもしれませんが、リダイレクトとかのケースもあるので、ちょっと面倒です。

44100のストリームの場合は、playのオプションを合わせます。
【macOS】ターミナルが開かなくなった

# はじめに
突然、ターミナルが開かなくなりました。
アイコンを押してもウインドウが開く前にクラッシュしていて、クラッシュレポートが表示される状態です。
この問題は解決していませんが、代用案があったので記録しておきます。

# クラッシュレポート
![スクリーンショット 2023-02-16 21.05.26.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/bf165818-41ae-46b0-ed2e-3bb1c0243e2e.jpeg)

# 代用案
「iTerm」がいいらしいです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">iTermとかのサードパーティ製ターミナルは試されました？<br><br>同じく純正ターミナルが起動しない現象が起こってるんですけど、サードパーティ製は動いてますw</p>&mdash; Hikaru Kuroda (@ruu_meow) <a href="https://twitter.com/ruu_meow/status/1625481765942095872?ref_src=twsrc%5Etfw">February 14, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[こちら](https://iterm2.com/)のリンクを開いて「Download」を選択します
![スクリーンショット 2023-02-16 21.08.11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/9207f8c0-427f-7fcc-3622-d596e5d05e21.jpeg)

ダウンロードしたzipを解凍するとアプリケーションがはいっています
![スクリーンショット 2023-02-16 21.10.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/cbb2331a-280b-4e10-19c5-0e1c4cefd62b.jpeg)

# おわり
まじでどうにかして欲しいです
本当に突然なったのでおそらくバグ？かなと思います
ChatGPT先生、Pythonがなぜ流行らないのか教えてください

# 回答

実際には、Pythonは非常に人気のあるプログラミング言語の1つであり、多くのプログラマーや企業によって広く採用されています。以下に、Pythonがなぜ流行らないと考えられるかをいくつかの理由とともに説明します。

* パフォーマンスの問題：Pythonは、C++やJavaなどの他のプログラミング言語に比べて実行速度が遅いとされています。そのため、高速な処理が必要なアプリケーションや、大規模なデータ処理が必要な場合には、Pythonは適していない場合があります。

* ライブラリの制限：Pythonは非常に豊富なライブラリを持っていますが、それらのライブラリが必要な機能がない場合もあります。そのため、Pythonが適していないアプリケーションもあります。

* セキュリティの問題：Pythonは動的型付け言語であるため、コードのエラーを検出するのが難しい場合があります。また、Pythonのライブラリのいくつかには、セキュリティ上の脆弱性がある場合があります。

* 教育や研究分野での使用：Pythonは、教育や研究分野で広く使用されていますが、産業界での使用には、他のプログラミング言語よりも多くの時間がかかる場合があります。

* 実装上の問題：Pythonは、C++やJavaなどのプログラミング言語に比べて、実装が難しい場合があります。また、Pythonコードは、他のプログラミング言語のコードに比べて読みにくい場合があるため、チームでの開発には注意が必要です。

これらの理由は、Pythonが流行らないと考えられる要因のいくつかですが、Pythonが非常に人気のあるプログラミング言語であることに変わりはありません。Pythonは、Webアプリケーション、データ分析、機械学習、AIなどの領域で広く使用されており、今後もますます人気が高まることが予想されています。
ChatGPT先生、LISPがなぜ流行らないのか教えてください

# 回答

LISPは、プログラム言語の中でも非常にパワフルで柔軟性があり、高度なプログラミング機能を提供しています。しかし、以下のような理由から、LISPが一般的なプログラミング言語として広く普及していない可能性があります。

* 学習曲線が急であること：LISPは、他の一般的なプログラミング言語よりも学習曲線が急であることがよく指摘されています。LISPの関数、マクロ、リスト操作などの独自の構文や機能は、初心者にとっては難解に感じるかもしれません。

* 実装の違い：LISPは、Common Lisp、Scheme、Clojureなど、いくつかの派生言語があります。これらの言語は、構文や機能、ライブラリなどで異なることがあります。このため、LISPを学ぶ際には、どのバージョンや派生言語を選択するかが問題になることがあります。

* マーケティングの問題：LISPは、その柔軟性やパワーにもかかわらず、プログラミング言語としての知名度は比較的低く、広く普及していないため、マーケティング上の課題があるかもしれません。

* 開発コミュニティの規模：LISPの開発者コミュニティは、他の言語に比べて比較的小さいとされています。このため、LISPのライブラリやドキュメントの数が他の言語に比べて少ないことが問題になる場合があります。

以上の理由から、LISPは、高度なプログラミング機能を必要とする専門家や研究者など、一部の人々によって使用されていますが、一般的な開発者にとっては一般的な選択肢ではありません。
ChatGPT先生、Emacsがなぜ流行らないのか教えてください

# 回答
Emacsは、非常に柔軟でカスタマイズ性が高く、プログラマーやテキストエディタのパワーユーザーにとっては非常に魅力的なエディターです。しかし、一般のコンピューターユーザーにとっては、学習コストが高く、覚えるために時間がかかるため、人気が出にくい傾向があります。以下にEmacsが一般的に普及しない理由をいくつか挙げてみます。

* 学習コストが高い：Emacsは非常に柔軟であり、多くの機能を持っています。しかし、その分、学習コストが高く、初めて使う人にとっては使い方を覚えるのに時間がかかります。

* キーバインディングが複雑：Emacsのキーバインディングは非常に複雑で、初めて使う人にとっては覚えるのが難しい場合があります。

* ユーザーインターフェイスが古い：Emacsのユーザーインターフェイスは、他のエディターに比べて古い印象を与えることがあります。これは、新しいユーザーにとっては魅力的ではないかもしれません。

* 競合するエディターが多数存在する：Emacsには、多くの競合するエディターが存在します。これには、Vim、Sublime Text、Atom、Visual Studio Codeなどが含まれます。これらのエディターも非常に人気があり、Emacsにとっての競争相手になっています。

* マルチプラットフォームに対応していない：Emacsは、Windows、Mac、Linuxなど、さまざまなプラットフォームで動作します。しかし、そのインストールや設定はやや複雑で、初心者には敷居が高い場合があります。

以上が、Emacsが一般的に普及しない理由のいくつかです。ただし、Emacsは依然として非常にパワフルで、カスタマイズ性が高いエディターであることに変わりはありません。プログラマーやエンジニア、ライターなど、パワーユーザーには非常に人気があります。
GIGAスクール端末だけでもブログは運営できる！

※あまりにも量が少ないので、しばらく運営してみての感想を追加で書きます。
2023-2-17 スマホだとレイアウトが崩れます。PCから閲覧してください。

## はじめに
GIGAスクール端末でどこまで遊べるか、日々楽しんでいる筆者ですが、今回GIGAスクール端末だけでブログを作れたので、備忘録として残しておこうと思います。

作ったブログ

https://moyashi-blog.vercel.app/

しばらくちゃんと記事を投稿しようと思うので、SNSなどで広めてもらえると嬉しいです。

## 開発環境
### 概要
Next.js+tailwindCSSで作りました。作成期間はだいたい2日です。
デプロイはNext.jsなのでvercelを使ってます。

### 使ったツールなど
・GithubCodespace　　chromeosで開発するならこれがないと無理です。
・dillinger　　　　　　 ブラウザで動くMarkdownエディタです。
・vercel　　　　　　　 Githubからデプロイができるので便利です。

## 作ってみた感想
コード自体はそんなに難しくなかったのと、調べまくってコピペしたところも多くあるので、難易度としては低いかなと思います（Linuxが使える前提）。

Next.js自体初めてでしたが、情報が結構出ていたのと、reactの改良版ということで使いやすかったです。tailwindCSSは少ないコードでサイトがきれいになるのでいいですね。
Markdownで記事を作っていますが、ファイルと画像をいちいちgithubにアップロードをしなければいけないのが難点ですね。それも自分でエディタを作ってみようと思います。

運営できる！と書きましたが、まだ一つしか記事を投稿していないので微妙なところですが、少なくともブログとしては機能するでしょう。
GIGAスクール端末だけでもブログを作れるのは魅力的ですね。
サイトがブロックされていなければ、やってみてはどうでしょうか？

※アナリティクスや広告系は殆どの場合（僕の環境でも）使えないので、収益化などは無理だと思います（GIGA端末だけでは）。

## 参考記事
https://reffect.co.jp/react/nextjs-markdown-blog#i-3
【Laravel】ExampleComponentが表示されない

Laravelにてデフォルトで用意されているvueのコンポーネント「ExampleComponent」を利用しようとしているのに表示されない。

という問題が発生して、それを解決したので、備忘録がてら。



【開発環境】

Laravel:5.8
node(nodebrew):10.16.3


【起こっていたこと】

npm run dev
をターミナルに入力しても、下記のようなエラーが発生してコンパイルが完了しない
　

Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
    at Object.createHash (node:crypto:133:10)
    at module.exports〜


そのため当然ながら「ExampleComponent」の内容が表示されない。
　



【原因と解決策】

私の場合、このエラーは以下の手順で解決しました。
　

① nodebrew　のバージョンを下げる（エラー時：v18.13.0　→　v10.16.3へ）
② ターミナルで　「npm run dev」を実行
③ ExampleComponentを使いたいファイルにscriptタグを入れる

　
　



Laravelのバージョンに合わないnodeを使っていた（？）ことでコンパイルがそもそも行われていませんでした。

なので①②のようにまずはバージョンを合わせてコンパイルしてもらう。

　

それでもExampleComponentの内容が表示されずにしばらく悩んでいましたが、ただのイージーミスで

　
③scriptタグを書いてない。ってだけでした( ´Д`)


なのでapp.blade.phpの head部分に書いてあるscriptタグをコピペっ。ってしたら解決。

　
　



初心者なので色々間違っているかもですが、誰かの参考になれば幸いです〜。
Lambdaの定期実行をEventBridgeのルールからスケジューラへ

# Lambda関数のスケジュール実行

Lambda関数を定期的に実行したい場合、今までは **EventBridge ルール** の cron式を使ってスケジュールをセットすることが多かったと思います。

その後、**EventBridge スケジューラ** が登場しました。

AWSとしては、スケジュールは EventBridge スケジューラ を推奨しているようです。

# Lambda関数のエイリアスやバージョンの実行は？

## 今まで（移行時に課題あり）

じゃあ **EventBridge スケジューラ** に移行してみよう、と進めていたところで、困りました。

Lambda関数のバージョンやエイリアスを普段よく使っているのですが、バージョンやエイリアスの選択が画面上にありませんでした。
で、仕方なく EventBridge スケジューラ には移行できないなあ、とあきらめていました。

以下リンクの記事で見ると、添付の画像ではLambda関数のバージョンやエイリアスは選べそうにないですよね。

https://dev.classmethod.jp/articles/amazon-eventbridge-scheduler-new-way-to-launch-tasks/

## これから（課題解消！）

**だったんですが、**

たまたまマネージメントコンソールを見てみたら **エイリアスとバージョンが選べるようになっていました！バンザイ！🙌**

![eventbridge_scheduler_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204490/f56eeb1e-e87d-b381-1334-4796a9605017.png)


# スケジューラーに移行するといいこと

上記リンク先の記事からの抜粋させてもらって申し訳ないのですが、**300ルールの制限が無い**　ことと、**タイムゾーンの指定が出来る** ことが挙げられています。

個人的には、タイムゾーンを ```Asia/Tokyo``` を選択すると、**9時間の引き算をしなくてよくなったのが楽** ですね。
楽ってだけじゃなく、日本時間の 0:00～8:59 のスケジュールの場合に、曜日を変え忘れて1日ずれるというやりがちの事故も防げます。

また、```日付``` に ```*``` を入れると自動的に ```曜日``` に ```?```　が入ってくれます。これも **「cronのハテナの記法ってどうだったかな・・・」と迷わなくて楽** ですね。

![eventbridge_scheduler_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204490/37d154ba-51af-c4c6-dda5-c68a9a5b7ba7.png)

逆に、EventBridgeルールから移行する際は、数字をコピペしないように注意が必要です。

ぜひ、EventBridge スケジューラを使っていきましょう。
Tang-Nano-9Kで動くＮＥＳのCHR.ROMのDRAM化し、大容量カートリッジが動くようにする

# 目的
　fpganesのPRG.ROMをDRAM化する事により、Tang-Nano-9Kの  内蔵RAM容量以上のカートリッジを動作させることは成功した。
　しかし、CHR.RAMは内蔵RAMでの動作であり、RAMとして使える32KB以下でないと動作しないと言う問題が有った。
　手持ちのカートリッジで動作するのは極わずか。之では寂しいな。
　◆◆◆　そうだ、PPUもDRAM化しよう　◆◆◆
　手持ちでは最大容量の、星のカービィを動作させたいな。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/e84e22b1-719e-bc55-9429-5e3244760a5f.jpeg" width="400">

# 実施内容
　Tang-Nano-9Kの内蔵DRAM容量は8MB、之を2分割して使用出来る事は判って居た。
　今までは面倒なので、単一で使用していたが。
　今回はこれを2分割する、ライブラリを交換するだけなのでこれは簡単。
　次に、現行のPRG.ROMを、片方の4MBの部分で動作させる。
　次に、残った4MBの部分で、CHR.ROMを動かせば完成となる。

　と、書けば簡単だが問題点が有る。
　　※だから、手を付けなかったのだが。
　DRAMのアクセス速度が足りない。
　データをキャッシュする等を試みたが上手く行かない、全て徒労に終わった。
　そこでDRAMのスビートアップを検討。今はPLLの都合で128MHzで動作させている。
　DRAMのアクセスを166MHzに上げれば間に合うのだが、そのクロックが供給できない。
　そこで、NESメインクロック21.6MHzの8倍の、172.8MHzで動作させることにした。
　オーバースペックだが104%であり、問題無いだろう。
　　※仕様外の動作であり、動かない個体がある場合はご容赦の程。
　波形で確認したが、リード完了直前にDRAMからのデータが到着している。

　これで出来上がりと思ったら、CHR.ROMが書き換わるという問題点を発見。
　之は何のことは無い、CHR.ROMと同じ番地(8000-FFFF)のレジスタアクセスで、書き換わっていたと言うお粗末の一席。
　該当エリアを書き込み禁止にしたら、大部分のカートリッジが動作するようになった。
　　※そんな所にレジスタが有るなんて、思わなかったよ。

# 参照資料
　※格納位置は前回と同じ。
　※通信速度を従来の4倍に上げたので、ロードが失敗する場合は速度を下げてください。
　「[fpganes Tang-Nano-9K バージョン](https://github.com/hi631/tang-nano-9K/tree/master/NES/fpganes)」
　「[fpganes Tang-Nano-9K ローダー](https://github.com/hi631/tang-nano-9K/tree/master/NES/loader)」
　「[fpganes Tang-Nano-9K モニター](https://github.com/hi631/tang-nano-9K/tree/master/NES/mon)」


# 機能概説
　元々のfpganesはRAMリソースとして、基板PARAMに集約してアクセスしていた。
　之を　PRG.ROM　PRG.RAM　CHR.ROM　CHR.RAM　に再び分離。
　PRG.RAM　CHR.RAM　は各2KBなので内蔵RAMを割り当て。
　PRG.ROM　CHR.ROM　はDRAMを割り当てたので、4MB使えるようになる。
　メモリ信号は合成される前のものを取り出し、DRAMに与えている(つもり)。
　　※途中から信号を取り出したものだからぐちゃぐちゃ、要らない信号の整理が必要だが。
　カートリッジによっては追加のRAM(6000-7FFF)が必要なものが有るが、CPU側のDRAMを割り当てた。
　　※RAMの交換が出来ないので、連続して遊ぶと可笑しくなるかも。
　　　RAMのSAVE,CLEAR,LOAD機能が必要なのだろう。
　マッパーなどの一部は「[NESTang](https://github.com/nand2mario/nestang)」から頂いた。
　元のプログラムからなにかしら良くなったのだろうが、改善点の確認はして居ない。
　　※良くなって居る筈という、希望的観測です。

PRG.ROMリードタイミング(psr_mt00で動作開始、ps_mdo0で読出し完了)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/b738e9ac-08bb-9056-345b-5bfc12cf1b34.png)
CHR.ROMリードタイミング(psram1_csで動作開始、ps_mdo1で読出し完了)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/aba39ca3-64ae-db8d-1556-7390e83b6aa7.png)


# 動作検証
　手持ちのカートリッジは、全て起動とキー操作可能な事は確認した。
　星のカービー(PRG:512KB,CHR:256KB)も元気に飛び回っている。
　　※最後まで行きつける保証は無いよ。
　だからと言って、全てが動くと思わない様に。
　カートリッジにはメモリ拡張の為に、マッパーと呼ばれる回路を搭載している。
　fpganesが理解出来るマッパーは限られており、登録されていないマッパーでは動作しない。
　　※マッパー云々の前に、NES-TN9の動作タイミングを疑うべきかな。
　　※比較的新しめの数字の大きいマッパーは、まず動かないだろう。
　NES-TN9は少々無理なタイミングで動作させている、動かないと言って文句言わないでね。

![50.fc_cart.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/f5e713f0-0bfa-4a31-e9d9-cd4d182a9fa7.jpeg)

# 感想
　Tang-Nano-9Kでも出来るものだ、出来る子なんだなと一寸感心。
　でも、内蔵DRAMにダイレクトアクセスが出来たらもっと良かったのだけど。
　なお、上記記載内容は全て無保証であり、各自の責任においてご利用願います。
【Rails】Railsの環境構築でエラーが出てインストールできない時の対処法

## はじめに
M1 MacでRailsの環境構築をした時にエラーが出てうまくいかなかったので、
出たエラーと解決方法についてまとめました。

## 経緯
gemでrailsをインストール

**gemとは**
　①RubyGemsが公開しているRubyのパッケージ
　②パッケージ管理システム　
　　→最近はbundlerというパッケージ管理ツールを使うことが多い
```
$ gem install rails
```

## エラー内容
```
error: while executing gem ... (gem::filepermissionerror) you don't have write permissions for the /library/ruby/gems/2.6.0 directory.
2\. 
```

## 解決方法
gemがどこにあるか？
```
$ which gem

/usr/bin/gem
```

rubyがどこにあるか？
```
$ which ruby

/usr/bin/ruby
```

rubyはrbenvで管理しないといけないらしいが、現状は`/usr/bin`で管理されているよう。

では`/.rbenv`の直下で管理するように以下を試した。

brewでrbenvをインストールする
```
$ brew update

$ brew install rbenv ruby-build
```

Rubyをインストールする
```
$ rbenv install 2.7.7
```

するとエラー発生。

参考記事１のケースを参考に、下記のコマンドを叩く。
```
$ RUBY_CFLAGS="-w" rbenv install 2.7.7
```
が先ほどと同じエラーが...。
```
error: while executing gem ... (gem::filepermissionerror) you don't have write permissions for the /library/ruby/gems/2.6.0 directory.
2\. 
```

参考記事２を参考に、`sudo`を付けて実行したところ、
```
$ sudo rbenv install 2.7.7
```

ちなみに`sudo`とは、管理者権限が必要な作業を実行するコマンドです。（参考記事４から）

3分ぐらい時間がかかったが、ついにRubyのインストールに成功！
きちんとインストールできているか下記コマンドで確認。

```
$ rbenv versions

* system
  2.7.7   ←ちゃんとできてる〜！
```

この状態だと、systemの方が利用されているので、インストールした2.7.7を利用するように下記コマンドで設定する。
```
$ rbenv global 2.7.7
```

2.7.7を利用に設定できているか確認。
```
$ rbenv versions

  system
* 2.7.7   ←OK！
```

次にrbenvにパスを通す必要があるため、シェルの設定ファイルを編集する段階に。
自分のPCのデフォルトシェルを確認するには、下記のコマンド。
```
$ echo $SHELL

/bin/zsh
```  
| デフォルトシェル | 設定ファイル |
|:-:|:-:|
|/bash   | .bash_profile  |
|/zsh   | .zshrc  |

設定ファイルがない場合は、参考記事３を見て、設定ファイルを作成する。


パスを追加するため、設定ファイルを開く。
```
$ open ~/.zshrc  
```

開いたファイルに下記を追加し、保存する。
```
[[ -d ~/.rbenv  ]] && \
  export PATH=${HOME}/.rbenv/bin:${PATH} && \
  eval "$(rbenv init -)"
```

そして、追記した内容を反映させるため、下記のコマンドを。
```
$ source ~/.zshrc 
```

そしてそして、ターミナルを再起動。

rubyとgemがrbenvの管理下に置かれているか、下記コマンドで確認。
```
$ which ruby

/Users/(名前)/.rbenv/shims/ruby
```

```
$ which gem

/Users/(名前)/.rbenv/shims/gem
```

おお、できてる！


ここで、`sudo`を付けてRailsのインストールコマンドを叩く。
```
$ sudo gem install rails
```
成功したっぽい。

もう一度、ターミナルを再起動。

ちゃんとRailsがインストールされたか下記コマンドで確認。
```
rails -v

Rails 7.0.4.2
```

できてる〜！

## まとめ
rubyはrbenvで管理しないといけないが、`/usr/bin`下で管理されていたため、Railsのインストールがうまくいっていなかったようです。

また`sudo`を付けて管理者権限でコマンドを実行するとうまくいきました。

## 参考記事
１

https://kenzoblog.vercel.app/posts/m1-chip

２

https://www.yururiwork.net/archives/1563

３

https://qiita.com/k3ntar0/items/eb8cdbd8eba9da388def

４

https://gihyo.jp/admin/serial/01/ubuntu-recipe/0410