OmniAICreator/Qiita-1.07M huggingface dataset:
selectSlice returned undefined for an uninjected slice reducer のエラーに対応したメモ

## 概要
sliceのselectorsで定義したselectorを使用したら表題のエラーが出てしまった。
結論から言うと、reducerの名前の指定がsliceの`name`とズレていたために発生したものであった。

## 環境
- `reduxjs/toolkit": "^2.2.3"`
## エラーが発生する原因となったソース

```ts:messageSlice.ts
import { createSlice } from '@reduxjs/toolkit';
export const messageSlice = createSlice({
  name: 'massage',
  initialState: { text: 'hello' },
  reducers: {
    setText: (state, action: PayloadAction<string>)=>{ state.text = action.payload; },
  },
  selectors: {
    messageSelector: (state) => state.text,
  },
});
export const { messageSelector } = messageSlice.selectors;
```

```ts:store.ts
import { configureStore } from '@reduxjs/toolkit';
import { messageSlice  } from './messageSlice';

export const store = configureStore({
  reducer: {
    // ここで messageではなくmassageとタイポしている
    massage: messageSlice.reducer
  },
});
```

```tsx:App.tsx
import { useSelector } from 'react-redux';
import { messageSelector } from ' messageSlice';

function App() {
  const message = useSelector(messageSelector);
  return (<div>{message}</div>);
}
```

## 修正

タイポを直したらエラーはおさまった。

```diff:store.ts
import { configureStore } from '@reduxjs/toolkit';
import { messageSlice  } from './messageSlice';

export const store = configureStore({
  reducer: {
-    massage: messageSlice.reducer
+    message: messageSlice.reducer

  },
});
```

## 対策
タイポを減らすために、パラメータを使って指定したほうが事故は減るかもしれない。

```diff:store.ts
import { configureStore } from '@reduxjs/toolkit';
import { messageSlice  } from './messageSlice';

export const store = configureStore({
  reducer: {
-    massage: messageSlice.reducer
+    [messageSlice.reducerPath]: messageSlice.reducer

  },
});
```

## 参考
[Redux-toolkit createSelector](https://redux-toolkit.js.org/api/createSlice#parameters)


## (おまけ）エラー本文

```
selectSlice returned undefined for an uninjected slice reducer

Error: selectSlice returned undefined for an uninjected slice reducer
    at selectSlice (http://localhost:5173/app/node_modules/.vite/deps/chunk-O4UCS54J.js?v=f7eed15d:2810:19)
    at wrapper (http://localhost:5173/app/node_modules/.vite/deps/chunk-O4UCS54J.js?v=f7eed15d:2865:22)
    at wrapper (http://localhost:5173/app/node_modules/.vite/deps/chunk-L4XXUM6S.js?v=f7eed15d:189:28)
    at memoizedSelector (http://localhost:5173/app/node_modules/.vite/deps/chunk-L4XXUM6S.js?v=f7eed15d:46:38)
    at getSnapshotWithSelector (http://localhost:5173/app/node_modules/.vite/deps/chunk-L4XXUM6S.js?v=f7eed15d:74:22)
    at mountSyncExternalStore (http://localhost:5173/app/node_modules/.vite/deps/chunk-NT24UTPT.js?v=f7eed15d:12509:28)
    at Object.useSyncExternalStore (http://localhost:5173/app/node_modules/.vite/deps/chunk-NT24UTPT.js?v=f7eed15d:13196:22)
    at useSyncExternalStore (http://localhost:5173/app/node_modules/.vite/deps/chunk-7ABS7DTB.js?v=f7eed15d:1120:29)
    at useSyncExternalStoreWithSelector3 (http://localhost:5173/app/node_modules/.vite/deps/chunk-L4XXUM6S.js?v=f7eed15d:81:23)
    at useSelector2 (http://localhost:5173/app/node_modules/.vite/deps/chunk-L4XXUM6S.js?v=f7eed15d:243:27)
```
【備忘録】phpmyadminでエラー発生　-作業目安5分-

# 背景
[こちら](https://qiita.com/watermelon_saisai/items/3f7d635073d650d2e8d1 "【備忘録】ラスパイ上にSQLサーバーを立てて別PCからアクセスできるようにする　-作業目安20分-")にてラズパイ上にSQLサーバー環境のセットアップをした後、
phpmyadminでテーブル作成しましたが、早速トラブル発生。。
備忘録として対処方法を記述しておきたいと思います。


# 事象
新規テーブルを作成して表示タブで開こうとすると、下記のような赤い画面でエラー表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3745465/9fb4d820-ab61-ac86-3d1c-313eb101211a.png)

./libraries/sql.lib.phpの613行目で警告が発生しているようです。

```Warning in ./libraries/sql.lib.php#613
count(): Parameter must be an array or an object that implements Countable
```
# 対象方法
 @nanbuwks様の記事を参考にして『sql.lib.php』の613行目を修正することでエラー解消することができました！！
 count 関数のところ()の括りが不足しているようです。

↓参考にさせていただいた記事
 
 https://qiita.com/nanbuwks/items/2277dd308ddd0f1ee4dc

記事ではvimコマンドを使っていましたが、私は使い慣れているnanoコマンドで編集しました。
``` 
$sudo nano /usr/share/phpmyadmin/libraries/sql.lib.php
``` 

Ctrl+wボタンで検索モードになるので該当のコードを検索すれば探す手間を省くことができます。

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3745465/8882badf-9d92-5b51-8368-271bef42f12d.png)

# 解決
下記の通りエラー解消していることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3745465/bb596fa6-3d13-55a6-c516-284c443a4bb3.png)
【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.2【動画 2分02秒】【YouTubeチャンネルからの転記です】

この記事は、わたしの[YouTubeチャンネル](https://bit.ly/Yamanaka-YouTube "Living without things. 持たない生き方 手放す生き方")にある公開動画を転記しております。
( どこかのタイミングで、プログラミング-Google Apps Script or iPaaS-Zapier をつかって自動転記させる予定です )

転記のための時間コストを少なくしたいので、文字装飾( Markdown記法 )を極力つかわずに書いております。

こちらが動画内容です👇

***

![99 サムネイル 【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.1【動画 2分02秒】.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386308/ea47ec43-e1e7-618c-fd79-b2b1a1321297.png)



* # 動画URL
    * https://youtu.be/oThPBtqS2_0

<br>

* # 動画タイトル
    * 【Suno AIでつくった楽曲】ピアノ曲( ショパンのオマージュ ) ver.2【動画 2分02秒】

<br>

* # 動画の説明欄(一部を抜粋)

📅撮影日 = 2024-04-09(火)

Suno AIでつくった曲をMP3で出力してから、動画編集いたしました。
Suno AIとは、文章から音楽を生成することができるAI( Text-to-Music-AI )です。
ぜひ聴いてみてください。

楽曲の正式名称:
Moonlight Sonata ver.2

Suno AI Library URL:
https://bit.ly/suno-Moonlight-Sonata-ver-2

Instrumental:

作曲日:
2024-04-02(火)

契約の種類:
Pro Plan


---


Suno AIへの指示文章( プロンプト ):


🇬🇧English

A gentle piano piece that soothes the mind and induces sleep for my sweet lover, in homage to Chopin.


🇯🇵日本語訳

わたしの伴侶のための、穏やかで心が休まりながら睡眠を誘うピアノ曲、ショパンのオマージュ


---


Suno AI 公式URL
https://accounts.suno.ai


---


✓ 🎥この動画と関連が強いわたしの動画 ↙
　・“Suno AIでつくった楽曲”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghMLdiSVqwvSs_Z5y0H4VGOe


　・“効果的にSuno AIを活用するヒント”シリーズ
　https://www.youtube.com/playlist?list=PLpQhBHT4oghPuaNOVZn-N53wVvsBkeHdI


　・【Suno AI】文章から音楽を生成するAI( Text-to-Music-AI )で、3分間で2曲、6分間で4曲作りました【試聴可能】1)伴侶の曲 2)税理士の曲【動画 16分11秒】
　https://youtu.be/QKfhk4HgQ_g


✓ 🎥Shortened URL for this video | この動画の短縮URL ↙
　https://bit.ly/3vKbxwl
MVAは定着するか？

# 時代はMVCからMVAへ
Microsoft AI Day - Osakaを見に行きました。
とっても気になったので、スカイツリーの足元から大阪まで行ってきましたよ。
800名ほどの参加者で大阪と冠しているカンファレンスとしては大成功ですよね。

## そもそもMVCっなんだ？
C#やっている人なら、mvc.netのプロジェクトで作るやつねとなるところでしょうが
あれも、画面単位での分岐後だけを見ればいいつくりなので、

mはmodelまあざっくりデーターとか出力結果とかのレイヤーです
vはviewまあざっくりユーザーインタフェース
cはcontrollerでソフトウェア全体の制御
という、もはや古典的なレイヤーアーキテクチャ。

## じゃMVAは？
controllerをAIでよしなにしてもらおうというw

現実問題それはないので。 <-キッパリいいきったねw
じゃあなに、というわけで、

ズバリ、Function callingでの処理分岐なんですね。
ちょっとすっ飛ばしたかな

従来のcontrollerをなくすのではなく。
UIからの自然言語の指示をもとに、Function callingの機能も使って、処理(model)を呼び分けよう。
というわけです。

で、PythonはいいよねLangchainあるから…
そうだったんですが。
microsoft頑張ったね。
Semantic Kernel に Function callingが追加されたってよ！
詳しくはこちらを
https://zenn.dev/microsoft/articles/semantic-kernel-18
じゃ何がうれしいかって？
新してモデルを追加したら、Function callingとして、追加したら、良しなに判断して必要に応じて使ってくれる…

microsoftはこれをもって、MVAとするらしい。

100%個人の妄言なので、違っていたら御免なさいとしか言えないっす。
t-SNEを使用した画像データの次元削減: 実用例としてのガイド

## 概要
この記事では、高次元データセットの可視化に広く使用される機械学習のテクニックであるt-SNE(T-distributed Stochastic Neighbor Embedding)について解説します。特に、画像データの次元を削減し、どのようにして2次元プロットで視覚的に表現するかに焦点を当てています。

## 1. t-SNEとは
t-SNEは、高次元データを低次元（通常は2次元または3次元）の空間にマッピングする非線形次元削減技術です。この手法は特に、個々のデータポイント間の類似性を保持しつつ、データのクラスタリングを視覚的に表現するのに適しています。

## 2. Pythonによるt-SNEの実装
以下のステップに従って、Pythonを使用して画像データにt-SNEを適用する方法を説明します。

パラメータの設定

```python
n_img = 100       # 画像の数
n_height = 16     # 画像の高さ（および幅）
n_channel = 10    # チャンネル数
```
ここでのパラメータは、画像の数、画像の次元、チャンネル数を定義しています。

データの生成と前処理

```python
import numpy as np
data = np.random.normal(loc=0, scale=1, size=(n_img, n_height, n_height, n_channel))
flattened_data = data.reshape(n_img, -1)

```
データは正規分布から生成され、それぞれの画像データを1次元配列に平坦化します。

t-SNEの適用と結果の解析

```python
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
tsne = TSNE(n_components=2, random_state=42)
tsne_results = tsne.fit_transform(flattened_data)

plt.figure(figsize=(10, 6))
plt.scatter(tsne_results[:, 0], tsne_results[:, 1], alpha=0.6, edgecolors='w', linewidths=0.5)
plt.title('2D t-SNE of Images')
plt.xlabel('t-SNE Component 1')
plt.ylabel('t-SNE Component 2')
plt.grid(True)
plt.show()
```

![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208980/5709da35-d459-3af3-cc6f-6814d170b375.png)

このセクションでは、平坦化されたデータにt-SNEを適用し、その結果を2次元プロットで表示します。

## 3. コード解説
### パラメータ設定の重要性
t-SNEの結果は初期パラメータに敏感です。例えば、random_stateを設定することで結果の再現性を保証できます。

### 正規分布データの生成
実際のデータセットを模倣するために、正規分布からランダムデータを生成しています。

### データの平坦化
多次元のデータをt-SNEに適用する前に、1次元に変換する必要があります。

### t-SNEの実行とプロット
t-SNEオブジェクトを作成し、fit_transformメソッドを呼び出してデータを変換後、matplotlibを使用して結果をプロットします。

## 4. t-SNEの利点と限界
t-SNEは非常に強力な可視化ツールですが、計算コストが高く、大規模データセットには適用が難しい場合があります。また、パラメータの選択が結果に大きく影響します。

## 5. まとめ
この記事では、t-SNEを使用して画像データを次元削減し、2次元空間で視覚化する方法を紹介しました。t-SNEはデータの構造を理解するのに非常に有効なツールであり、多くの機械学習
ST7735(SPI)でテキストの表示(128x160)(StampS3)

参考

↓クリック↓

https://tamanegi.digick.jp/computer-embedded/mcuboa/m5stamps3/

目的
液晶のテスト



![o_coq041.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a9275457-ad31-0a4e-5d96-0c30f0812846.jpeg)


https://www.aitendo.com/product/3858

![o_coq042.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e0fecc0a-a388-5a4b-bd1f-84096a8a4c7b.jpeg)

![o_coq037.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bd68ddd9-fb90-8203-b9d5-97ec87b674fa.jpeg)



```c++



//spi_st7735_M5S3_1


//ヘッダーファイル
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>


//定義
#define TFT_CS    1
#define TFT_RST   3
#define TFT_DC    5
#define TFT_MOSI  7
#define TFT_SCLK  9

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);


//初期化
void setup() {

  //液晶を初期化する。
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  tft.fillScreen(ST77XX_BLACK);

  // テキストサイズを設定
  tft.setTextSize(3);
  // テキスト色を設定
  tft.setTextColor(ST77XX_WHITE);
  // テキストの開始位置を設定
  tft.setCursor(0, 10);


  // 1行目に46を表示
  tft.println("StampS3");


  delay(1000); //1秒待つ

}//loop



```
CIF, POSCAR, structure, atomsのファイル変換まとめ

第一原理計算などを行う際にpythonを使って結晶構造ファイルの処理をする必要があるのだが、結晶構造のファイル形式には以下の4種類がある。
- CIF：Crystallographic Information File。ICSDなどでもこの形式
- POSCAR：VASPに入力する際のファイル形式(.vasp)
- structure：pythonライブラリであるpymatgenの形式
- atoms：pythonライブラリであるASEの形式

計算したい内容などによってpymatgenやASEを使い分けたり、場合によっては両方使ったりする。その度にいちいち変換の仕方を調べているのでまとめる。

# 1. atomsとPOSCARの変換
### atoms ⇒ POSCAR
ase.io.writeを使う。
```python
from ase.io import write
write('POSCAR.vasp', images=atoms, format='vasp', direct=True, vasp5=True, sort=False)
```
### POSCAR ⇒ atoms
```python
from ase.io import read
atoms = read('POSCAR.vasp', format="vasp")
```
詳しくはこちらを参照。
https://wiki.fysik.dtu.dk/ase/ase/io/formatoptions.html#vasp

# 2. atomsとstructureの変換
どちらの変換もpymatgen.io.ase.AseAtomsAdaptorを使う。
https://pymatgen.org/pymatgen.io.ase.html
### atoms ⇒ structure
```python
from pymatgen.io.ase import AseAtomsAdaptor
structure = AseAtomsAdaptor.get_structure(atoms)
```

### structure ⇒ atoms
```python
from pymatgen.io.ase import AseAtomsAdaptor
atoms = AseAtomsAdaptor.get_atoms(structure)
```

# 3. CIFとstructureの変換
pymatgenのStructureを使う。すごい簡単。
### CIF ⇒ strucutre
```python
from pymatgen.core.structure import Structure
structure = Structure.from_file("./xxx.cif")
```

### strucutre ⇒ CIF
```python
structure.to(filename="xxx.cif")
```

# 4. POSCARとstructureの変換
pymatgenのPoscarを使う。
### POSCAR ⇒ strucutre
```python
from pymatgen.io.vasp import Poscar
poscar = Poscar.from_file('POSCAR.vasp')
structure = poscar.structure
```

### strucutre ⇒ POSCAR
```python
from pymatgen.io.vasp import Poscar
poscar = Poscar(structure)
poscar.write_file(filename="POSCAR.vasp",significant_figures=16)
```

# 5. CIFとPOSCARの変換
VESTAを使ってもよいが、python上で変換する場合は以下の通り。
他にも良い方法がありそう・・・。
### POSCAR ⇒ CIF
```python
from pymatgen.io.vasp import Poscar
from pymatgen.io.cif import CifWriter
p = Poscar.from_file('POSCAR')
w = CifWriter(p.structure)
w.write_file('xxx.cif')
```

### CIF ⇒ POSCAR
```python
parser = CifParser('xxx.cif')
struct = parser.get_structures(primitive=primitive)[0]
poscar = Poscar(structure)
poscar.write_file(filename="POSCAR.vasp",significant_figures=16)
```

# 6. CIFとatomsの変換
atomsとPOSCARの変換の時と同じくASEのreadとwriteを使う。
### CIF ⇒ atoms
```python
from ase.io import read
atoms = read('xxx.cif', format="cif")
```

### atoms ⇒ CIF
```python
from ase.io import write
write('xxx.cif', images=atoms, format='cif')
```


変換方法は上記に示したもの以外もあるのでよりおすすめの方法があれば教えてください。
Pythonで「ファイルやディレクトリの存在を確認する(pathlibモジュール)」の動作を確認してみた

# 概要

Pythonで「ファイルやディレクトリの存在を確認する(pathlibモジュール)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/file/index13.html

# 実装

以下のファイルを作成しました。
```sample.py
import pathlib

path1 = './test/address.txt'
p1 = pathlib.Path(path1)
if p1.exists() :
  print(path1 + 'は存在します')
else :
  print(path1 + 'は存在しません')

path2 = './test/user.txt'
p2 = pathlib.Path(path2)
if p2.exists() :
  print(path2 + 'は存在します')
else :
  print(path2 + 'は存在しません')

path3 = './test/img'
p3 = pathlib.Path(path3)
if p3.exists() :
  print(path3 + 'は存在します')
else :
  print(path3 + 'は存在しません')
```

以下のコマンドを実行しました。
```
$ mkdir test
$ mkdir test/doc
$ mkdir test/img
$ touch test/address.txt
$ touch test/name.txt
$ python3 sample.py 
./test/address.txtは存在します
./test/user.txtは存在しません
./test/imgは存在します
```

# まとめ

何かの役に立てばと。
String.formatでjson文字列作成

```java
public class Main {
    public static void main(String[] args) throws Exception {
        // Sample data
        String name = "John";
        int age = 30;
        String city = "New York";

        // Format JSON string using String.format
        String jsonString = String.format("{\"name\":\"%s\", \"age\":%d, \"city\":\"%s\"}", name, age, city);

        // Print formatted JSON string
        System.out.println(jsonString);
    }
}
```
指定されたURLパターン の正規表現

```java
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String urlString = "/api/v1/2022.2/xxx";
        
        // 正規表現パターン
        String regexPattern = "^/api/v1/\\d{4}\\.\\d{1}/\\w+$";
        
        Pattern pattern = Pattern.compile(regexPattern);
        Matcher matcher = pattern.matcher(urlString);
        
        if (matcher.matches()) {
            System.out.println("URLパターンが一致しました。");
        } else {
            System.out.println("URLパターンが一致しませんでした。");
        }
    }
}


```

```
URLパターンが一致しました。
```

この正規表現パターン /api/v1/\d{4}\.\d{1}/\w+ は、以下のような条件を満たす文字列に一致します：

/api/v1/ から始まる
\d{4} で4桁の数字が続く
\. で小数点が続く
\d{1} で1桁の数字が続く
/ が続く
\w+ で1文字以上の単語文字列が続く
このパターンは、指定されたURLパターンにマッチするかどうかを検証します。
java。urlからドメインとドメイン以降の別に取り出す

```java
import java.net.MalformedURLException;
import java.net.URL;

public class Main {
    public static void main(String[] args) {
        String urlString = "https://www.example.com/path/to/resource";
        
        try {
            URL url = new URL(urlString);
            
            // ドメインを取得する
            String domain = url.getHost();
            System.out.println("ドメイン: " + domain);
            
            // ドメイン以降の部分を取得する
            String path = url.getPath();
            System.out.println("ドメイン以降の部分: " + path);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
}

```

```sh
ドメイン: www.example.com
ドメイン以降の部分: /path/to/resource
```
学習日記#3: 決定木モデルで予測〜KaggleでSubmit

## ゴール
予測結果をKaggleで提出する


## やったこと
- 加工済みデータをテストデータと学習データに分割
    - Survivedが空値 = テストデータの条件で分割
    - テストデータと学習データをそれぞれ新しい変数に格納
- 学習データを特徴量と回答に分割
    - X_train, y_trainの変数にそれぞれ格納
        - ```y_train = train.Survived```
        - ```X_train = train.drop(columns = ['Survived'])```
        - 配列を表すときは大文字なのでXは大文字にするのが通例らしい
- 機械学習モデルを扱うためのライブラリインポート
    - ライブラリScikit-Learnを使う
    - 今回は決定木モデルのみなので```from sklearn import tree```
- 使用するモデルの宣言
    - ```model = tree.DecisionTreeClassifier()```
    - ```()```にはオプションの引数をセットできるが今回は無し
- 決定木モデルの作成
    - model.fitメソッドで学習データを引数として渡す
        - ```model.fit(X_train, y_train)```
- テストデータを渡して予測結果を得る
    - ```y_pred = model.predict(test)```
- テストデータと予測結果の大きさをチェック
    - lenを使う　```len(test), len(y_pred)```
- 予測結果をテストデータに反映する
    - ```test['Survived'] = y_pred```
- Kaggle提出用のデータを作成する
    - Kaggleで提出フォーマットを確認する
    - フォーマットに合わせてindexを指定したテーブルを作成する
        - ```pred_df = test[['PassengerId','Survived']].set_index('PassengerId')```
        - 提出フォーマットとデータ型が違う場合はastypeメソッドで変換する
            - ```pred_df.Survived = pred_df.Survived.astype(int)```
- 提出用CSVファイルの作成
    - to_csvメソッドを使ってCSVファイルを作成
    - 　```pred_df.to_csv('submission_v1.csv', index_label=['PassengerId'])```
    - 　ダウンロードしてKaggleのSumit Predictionから提出

---

一旦データ加工〜予測結果提出までできたんだが後はひたすら課題にトライしてみるかなぁ
KaggleのDiscussions覗いてみるのもいいらしい
[Unity]classes.jarの格納場所

意外と忘れるので自分用に残しておきます。
（unityバージョンによってディレクトリが異なる可能性があるので注意）

* * *
確認環境：unity 2023.3.10.f1

unityがインストールされている場所に格納されています。
`Unity\Hub\Editor\2022.3.10f1\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar`

Hubの「エクスプローラーで表示」からなら`\Editor`から開くので探しやすい。
![unityhub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552480/6a0550e0-fa4f-e6b6-2e66-e9a7b39d14c4.png)
cronって何？～実務半年エンジニアの備忘録～

# はじめに:beginner:
こんにちは、実務経験半年のエンジニアのTunです。
今回は、初案件で学んだことの備忘録になっています。
　案件に入るや否や、未経験で四苦八苦しながら詳細設計を作成し、プログラム製造、単体試験、総合試験を経て、無事、リリースすることができました。

 今回の初案件で、多くのことを学びましたので、`cron`についてですが、今後はいろいろなことを書いていきたいと思います。

 ## cronとは何ぞや？
 > **cron**とは、ジョブを自動実行するためのデーモンプロセスです。
 Linuxシステムの管理を行う場合、ログローテやバックアップなど、定期的に自動実行したいジョブが数多くあり、その中でもバックアップ等の処理は、システムへの負荷が大きいため、ユーザのアクセスの少ない、深夜や早朝に行われるのが一般的です。

 :::note info
 cronは**crond**というデーモンによって管理することができます。

 cronの設定等は*crontab*コマンドを使用しますが、詳細はデーモンなども含めて後程記述したいと思います。
:::

**．．．cron？ジョブを自動実行？何ぞや？**　と思ったそこのあなた

　私自身も、書籍やUdemy等で学習していた時期は、cronは言葉でしか理解していませんでいたし、コマンドに至っても叩いたことはあるけど、使い方丸暗記、オプションの意味も丸暗記で、全く使い物になりませんでした。


 　では、例題で考えてみましょう。

  
  Aさんは会社で上司から、

```
毎月1日にQiita部署の全員分のフォルダを、社員名でQiitaフォルダ配下に作成してくれ、頼んだよ
```
と言われたとします。(~~正直こんなことは自分でやれと思いますが、、、~~）





　この部署が2,3人だったら「新規作成で名前を設定する」で全然問題ないと思いますが、規模が大きくなっていき100人、200人となると骨が折れます。

 　そこでAさんは、このタスクのために**cron君**を契約社員として採用しました！！
 このcron君は、根っからの真面目で、言われたことはいつ何時でもその仕事を遂行します。

 　毎月1日になると、莫大なフォルダを作り上げるのです！！
 しかし、手作業で行うとなると、ミスも出てきますし、その日が出勤ではない場合、その仕事は行われないことになります。


 どんなに優秀な人材でも**ヒューマンエラー**は起きないとは限りません！
### そんな時は定時処理はLinuxのcronに任せよう！！

　ここで登場するのが、`cron`です。`cron`に登録しておけば、人件費もかからず、かつ**正確に超高速にタスクをこなしてくれます。**


 ### 今回上司に言われた仕事は以下の通りです
 + 毎月1日にフォルダを作成
 + フォルダ名は社員名で作成
 + 作成するフォルダは、Qiitaフォルダの配下に

 上記のタスクを**cron**と**シェル**に処理を分担します。
 
 ::: note warn
**注意:warning:**
**cron**は定時処理はできますが、複雑な処理を記述するのには適していません。
シェルなどに複雑な処理を記述し、そのシェルをcronで呼び出して定時処理を実現します。
:::

:::note alert
**システム構築の注意点**:no_entry_sign:
システムによっては、常駐プログラムが多く存在してしまうケースがありますが、負担が大きくなり、パフォーマンスが低下したり、常駐プログラムが急停止して多大な経済的損失が発生したりすることがあります。
常駐プログラムをなるべく少なくし、サーバの負担を軽減して、定時処理に代用できるのであれば、cronに任せたほうが良きかなと思います。
:::

　「毎月1日に...」は`cron`に、「フォルダ作成...」は**シェル**に任せます。
 以下は例になるので、細かい処理や説明は省きます。
 ```:定時処理_cron
0 0 1 * * /qiita/make_dir.sh
 ```

 ```:make_dir.sh
 #!/bin/bash
 for name in 社員名リスト
 do
   mkdir -p /qiita/$name
done
```

+ `cron`は、**毎月1日の0:00**にフォルダ作成のシェルを実行
+ **シェル**は、**qiitaフォルダ配下に社員名のフォルダ**を人数分作成

    これで、crondデーモンが起動しておけば、今後は**誰も何もせずとも自動的に**作成されます！！


## cronとは

ここまで読んでいただければ、ある程度cronで何がしたいか、cronはなにをしているのかがぼんやり理解できたと思います。
> **cron**とは、ある決まった時間に、決まった処理を行いたいときに使用する。

　この程度の理解で、最初は問題ないかと．．．

もっと詳しく言うと、cronは各ユーザ1ファイル持っており、cronの実体は`/var/spool/cron`配下にあり、cronを編集するときは `crontab -e`コマンドを使ったり、`anacron`も名前は似ているけどちょっと違う動きをしたり、、、

詳しいことは次回以降まとめていきま～す:wave:
UmbrelのRPC接続の備忘録

# 趣旨
BitcoinのNodeを自分で建てているとInscriptionサイトがアクセス過剰でダウンしていても自分のNodeを経由してInscribeできるみたいなので、Runeが実装される前ですし、面白そうだし、Umbrelをもっと使いこなしてみたいのでぜひやり方を把握しておこうと思い、リサーチし実践した結果を備忘録として残します。

https://x.com/daniel_tanaka_/status/1780154259176120429


# 使用したもの
- Mac
- Umbrel

# RPC接続の手順

## Macでの作業
まずはMacでHomebrewでordをインストールします。
```bash
brew install ord
```

あとで使うのでMacのローカルIPを取得します。
```bash
ipconfig getifaddr en0
```

こちらもあとで使うのでUmbrelのローカルIPを取得しておきます。
```bash
ping umbrel.local
```

## Umbrelでの作業
UmbrelでRPC関連情報を取得します。
```bash
umbrel@umbrel:~/umbrel/app-data/bitcoin/data/bitcoin$ sudo docker inspect -f '{{ .Config.Env }}' bitcoin_server_1
```

以下の項目を探します。
BITCOIN_RPC_PASSWORD
BITCOIN_RPC_USER
BITCOIN_RPC_PORT

:::note info
http://umbrel.local:2100/上でGUI確認もできます。
:::

以下のようにbitcoin.confにrpcallowipを書き込みます。
```bash
umbrel@umbrel:~/umbrel/app-data/bitcoin/data/bitcoin$ cat bitcoin.conf 
# Load additional configuration file, relative to the data directory.
includeconf=umbrel-bitcoin.conf
rpcallowip=MACLOCALIP/24
```
:::note info
configurationの弄り方のリサーチにかなり時間がかかりました。以下のXに載せておいたコミュニティページ以外に解決策を提示しているWebサイトはみつけられませんでした。GPT先生に聞いてもDockerの大元のconfiguration弄りに行く複雑な方法ばかり提示されていたので、このコミュニティページは本当に助かりました。
:::

https://x.com/daniel_tanaka_/status/1780262703824617964



再起動して変更を反映させます。
```bash
sudo docker stop bitcoin_server_1
sudo docker start bitcoin_server_1
```

## Macでの作業
再びMacに戻り、Macで以下のコマンドをうちます。
```bash
ord --bitcoin-rpc-username RPCUsername --bitcoin-rpc-password RPCPassword --bitcoin-rpc-url http://<UMBRELLOCALIP>:<BITCOIN_RPC_PORT> server
```

[indexing blocks] ███████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 47727/839500


indexing blocksのあとにordコマンドを打つと、毎回以下のエラーが出てきたので加えてリサーチしました。

```bash
error: cookie file `/Users/daniel/Library/Application Support/Bitcoin/.cookie` does not exist
```

以下のように毎回UsernameとPasswordとURLを添えてコマンドを書けばとりあえず動きます。
```bash
ord --bitcoin-rpc-username RPCUsername --bitcoin-rpc-password RPCPassword --bitcoin-rpc-url http://<UMBRELLOCALIP>:<BITCOIN_RPC_PORT> COMMAND
```
環境変数にセットしてもダメだったので、とりあえず僕は添字をあてがってコマンド打っていきます。

もしMacにBitcoin Core入れてもいいんだったら、多分そっちの方がはるかに簡単です。以下のポストのURLからどうぞ。

https://x.com/daniel_tanaka_/status/1780305218904678826
Cohere Command R+ 4bit modelをローカル環境で動作させてみた

https://github.com/hisashi-ito/command-r-plus
* ソースはこちらのgithubで公開しています
### はじめに
Cohere Command R+ をlcoal (非MLX環境)　環境で動かすための手順と資材などを保存します。

### 動作環境
* コンテナランタイム: docker
* GPU: A100 80 GB x 1 
  * 104B 4bit 動作させるにはGPUメモリが64GB以上必要。
* ディスクの空き容量
  * models--CohereForAI--c4ai-command-r-plus-4bit が59GBあるので空き容量に注意。

### 利用モデル
[CohereForAI/c4ai-command-r-plus-4bit](https://huggingface.co/CohereForAI/c4ai-command-r-plus-4bit)  
4bitモデルでないと本環境ではGPUメモリが足りなくて動作しない。

### 環境構築方法
```bash
$ git clone https://github.com/hisashi-ito/command-r-plus.git
$ cd command-r-plus/docker
$ ./build.sh
$ ./launch.sh
```
上記のコマンドで、`commande-r-plus` コンテナができるので、当該コンテナ内で作業。

### 実行方法
```bash
$ sudo docker exec -it commande-r-plus bash
# time python3 ./generate.py
<BOS_TOKEN>

京都アニメーションの映画でお勧めを３つ教えてください


京都アニメーション（京アニ）は、日本のアニメ業界において高品質な作品で知られており、その中には劇場版アニメも数多くあります。お勧めの京都アニメーションの映画を３つ紹介します。

1. 『涼宮ハルヒの消失』（2010年）：『涼宮ハルヒ』ιθシリーズを締めくくる劇場版アニメです。主人公であるキョンが、涼宮ハルヒや他の仲間たちが存在する以前の、平凡な日常の世界へと迷い込んでしまったところから物語が始まりendas ます。キョンは元の現実世界に戻ろうと試みる中で、複雑な時間旅行と平行現実の謎に直面します。本作は、タイムトラベル、SF、超自然現象など、様々なジャンルの要素を巧みに織り交ぜた作品です。

2. 『映画 けいおん！』（2011年）：同じく人気の高いアニメシリーズである『けいおんDetail!』の劇場版アニメです。『けいおん！』シリーズは、桜が丘高校軽音部の日常や友情を描いた作品で、劇場版では、桜高軽音部の部員 prestazioni が卒業を控える高校3年生の時期を描いています。彼女たちは卒業旅行としてロンドンに行くことを決め、そこで様々な冒険や音楽体験をします。この映画は、シリーズの可愛らしくて心温まる雰囲気を維持しながら、キャラクターたちの成長と友情の強さを強調しています。

3. 『劇場版يرانが鳴く日は』（2018年）：京都アニメーションのオリジナル作品で、高校の合唱部を舞台としています。映画は、幼い頃に母親を亡くし、歌うことをやめていた主人公のタクトが、音楽を通じて転校生の転入生、ナギと運命的な出会いを果たすところから始まります。ナギはタクトに合唱部の部長就任を持ちかけ、タクトはその依頼を受け入れ、仲間たちと共に全国大会への出場を目指します。この映画は、美しい音楽と感動的な物語で高く評価されています。

以上、京都アニメーションの３つのお勧め映画を紹介しました。これらの作品は、美しいアニメーション、魅力的なキャラクター、心を打つストーリーで知られており、京都アニメーションの代表作として挙げられます。


real	1m25.337s
user	5m29.840s
sys	0m11.552s
```
### 推論コード
```python
from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = "CohereForAI/c4ai-command-r-plus-4bit"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)

# Format message with the command-r-plus chat template
messages = [{"role": "user", "content": "京都アニメーションの映画でお勧めを３つ教えてください"}] 
input_ids = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt")
## <BOS_TOKEN>

京都アニメーションの映画でお勧めを３つ教えてください




gen_tokens = model.generate(
    input_ids, 
    max_new_tokens=1024, 
    do_sample=True, 
    temperature=0.7,
)

gen_text = tokenizer.decode(gen_tokens[0])
print(gen_text)
```
TypeScriptのコードが変更されたら自動で再実行させる

皆さんはTypeScriptの学習であったり、すぐにコードの挙動を確認したい時はどうしてますか？公式のプレイグラウンドを使う方が多いのでしょうか。今回は普段使っているエディターでそれに似た環境を作ってみたのでご紹介します。コードに変更があったら自動で再実行させるため、`nodemon`と`ts-node`を使いました。

**nodemon**
ファイル変更を検知してアプリケーションを再起動するツール

**ts-node**
REPLも備えた、TypeScript実行ツール

https://www.npmjs.com/package/nodemon

https://www.npmjs.com/package/ts-node

<br>

### 動作環境
- macOS Sonoma
- Node.js 20.10.0
- TypeScript 5.4.5
- nodemon 3.1.0
- ts-node 10.9.2

### ディレクトリ構成
```
myApp/
├── src/
│   └── index.ts
├── package-lock.json
└── package.json
```
`※一部省略`

<br>

必要なパッケージをインストールします。
```
npm i -D typescript nodemon ts-node
```

<br>

`package.json`を変更します。
```diff json:package.json
{
  // 一部省略
- "main": "index.js",
+ "main": "src/index.ts",
  "scripts": {
+   "start": "nodemon -w src -e ts"
  },
}
```
**`nodemon -w src -e ts`**
`src`ディレクトリ以下の`ts`ファイルに限定して監視する設定です。デフォルトではアプリケーション全体の`ts` `json`ファイルの監視になります。

<br>

では実行してみましょう。
```
npm start
```

ターミナルにこのように表示されれば成功です。🎉
```
> test_tsnode_nodemon@1.0.0 start
> nodemon -w src -e ts

[nodemon] 3.1.0
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): src/**/*
[nodemon] watching extensions: ts
[nodemon] starting `nodemon -w src -e ts`
```

これで`src`ディレクトリ内の`ts`ファイルを変更したら再実行されるようになりました。
処理としては、ファイル変更を検知した`nodemon`が`ts-node`を起動、`ts-node`がTypeScriptを実行する、といった流れです。もちろん`index.ts`以外に他のディレクトリやファイルを追加してもしっかり動作します。

ちなみに`nodemon`は`ts-node`が存在した場合はデフォルトでそれを起動するため、特に設定は必要なく今回のような動作をさせることが出来ています。

<br>

最後まで読んでいただき、ありがとうございました！
[備忘録]gpg failed to sign the data他の対策

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [実現したかったこと](#実現したかったこと)
1. [最初に行ったこと](#最初に行ったこと)
1. [起こった問題](#起こった問題)
1. [原因と思われるもの](#原因と思われるもの)
1. [最終的に実施した手順](#最終的に実施した手順)
1. [かなり参考になった記事](#かなり参考になった記事)


# 実現したかったこと
- 各コミットにGPGキーを使った(検証済みの)署名を付けたかった
- 理想は`git commit -S -m "commit message"`で、"Verified"がつくコミットを作成できる状態

# 最初に行ったこと
- Githubドキュメント [GitHub アカウントに GPG キーを追加する](https://docs.github.com/ja/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account) の手順に沿ってGPGキーを新しく作成、Github設定ページに登録した
- .gitconfigにも`user.signingkey=[KeyID]`、`commit.gpgsign=true` を設定した

# 起こった問題
- Github設定ページで公開鍵登録時、検証されていない旨のエラーによりサブキーが登録できない
- メインキーを使って署名付きコミットを実行しようとすると、  
  `error: gpg failed to sign the data`が発生してコミットできない

# 原因と思われるもの
- Github設定ページで公開鍵登録時、検証されていない旨のエラーによりサブキーが登録できない
  →**クロス認証が必要**
- メインキーを使って署名付きコミットを実行しようとすると、  
  `error: gpg failed to sign the data`が発生してコミットできない
  →**鍵検証に加えて鍵のUsage設定が一部不足？**

# 最終的に実施した手順
  1. 既存のGPG鍵有無を確認する
      ```shell:
      gpg --list-secret-keys --keyid-format=long
      ```
  1. (GPG鍵を生成していなかったとして)新しくGPG鍵作成
      ```shell:
      gpg --full-generate-key
      # Use default in any question, and use new passphrase
      ```
      - ここで各選択肢をデフォルトのまま進めていくと設定不足で以下問題が発生する
          - 問題①：デフォルトのままだとサブキーの属性に"S"が付与されない
          - 問題②：作成した状態のままだとサブキーが検証されてない？
  1. GPG鍵を再確認
      ```shell:
      gpg --list-secret-keys --keyid-format=long
      ```
  1. 鍵の用途を修正
      - ここでサブキーの属性に"S"を付与し、問題の原因①が解決
      ```shell:
      gpg --edit-key [Github user name]
      ※gpg> key 1
      ※gpg> change-usage
      ※Your selection? s
      ※Your selection? q
      ※gpg> save
      ```
  1. GPG鍵にCross-Cretificationを設定する
      - たぶん前ステップと一緒にできる
      - ここでサブキーの検証が行われ、問題の原因②が解決
      ```shell:
      gpg --edit-key [Github user name]
      ※gpg> key 1
      ※gpg> cross-certify
      ※gpg> save
      ```
  1. メイン側のキーIDをコピー
      ```shell:
      $ gpg --list-secret-keys --keyid-format=long
      ...
      ------------------------------------
      sec   XXXXX/[Main key ID (ここをコピー)] [Created date] [expires: YYYY-MM-DD]
      uid                          [Github user name] <email address>
      ssb   XXXXX/[Sub key ID(Do not need to copy)] [Created date]
      ```
  1. コミットのたびに-Sオプション付けるのは面倒なので、.gitconfigに署名設定追加
      ```shell:
      git config --global user.signingkey [前ステップでコピーしたキーID]
      git config --global commit.gpgsign true
      ```
  1. 公開鍵を出力してコピー
      ```shell:
      gpg --armor --export [前々ステップでコピーしたキーID]
      Prints the GPG key ID, in ASCII armor format
      # 公開鍵が出てくるので、コピー
      ```
  1. Githubのユーザ設定ページに入って、GPG鍵を登録
  1. 自環境の場合、`~/.bashrc`の最後に以下追記が必要だった
      ```shell:
      export GPG_TTY=$(tty)
      ```
  1. `~/.bashrc`をリロード
      ```shell:
      source ~/.bashrc
      ```

# かなり参考になった記事
- [GitHub アカウントに GPG キーを追加する](https://docs.github.com/ja/authentication/managing-commit-signature-verification/adding-a-gpg-key-to-your-github-account)
- [Gitでerror: gpg failed to sign the dataと出てコミットできないときの対処法](https://qiita.com/goahi/items/493ff01b8fc86539f885)
- [Signing Subkey Cross-Certification](https://gnupg.org/faq/subkey-cross-certify.html)
【Rails　備忘録】　画像設定ボタンを画像に置き換える方法

画像設定ボタンが無骨だったので、画像に置き換える方法を調べたので共有します。

## 方法
jsファイルで画像のIDを読み取り、クリックされると画像設定ボタンがクリックされたことにします。

## jsファイル
``` Javascript
function imageclick(){
  // 画像のid取得
  const setImage = document.getElementById('imagePreview')
  // 画像にクリックイベントをつける
  setImage.addEventListener('click', function() {
    // 画像がクリックされたらボタンのidを取得　クリックイベントを発火させる
    document.getElementById('fileInput').click();
  })
}
// Event lisnersに登録
document.addEventListener("turbo:load", imageclick);
```

## HTMLファイル

``` HTML
= form_with model: @recipe, local: true do |f|
 /#カメラの画像
 = image_tag 'camera.jpg', id: 'imagePreview'
 /# 画像設定ボタン
 = f.file_field :thumbnail, id: 'fileInput', style: 'display: none;'
```

## 結果

[![Image from Gyazo](https://i.gyazo.com/9cb155390e8a5a51ec9a4b5598cd9ffb.gif)](https://gyazo.com/9cb155390e8a5a51ec9a4b5598cd9ffb)

カメラの画像をクリックしたら画像選択メニューが表示されるようになりました。
prisma-dbml-generatorで複数行のNoteが正しく生成されない

# prisma-dbml-generator　について

prisma.schemaファイルからdbmlファイルを生成することができます。
また、生成したファイルをdbdocsというサービスで共有する事ができます

https://github.com/notiz-dev/prisma-dbml-generator

# 問題

下記のように、複数行に渡るコメントは正しく変換されない問題がありました。

変換前

```:prisma.schema
/// User comment line1
/// User comment line2
model User {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
```

変換後

```schema.dbml
Table User {
  id Int [pk, increment]
  createdAt DateTime [default: `now()`, not null]
  updatedAt DateTime [not null]

  Note: 'User comment line1
User comment line2'
}
```

# 解決方法

本当はリポジトリに修正PRを作成するのがいいですが、急ぎだったためpythonスクリプトで置換する方針で対応しました

```python:convert_multiline_note.py
import re


input_file_path = 'prisma/dbml/schema.dbml'
output_file_path = 'prisma/dbml/new_schema.dbml'
match_pattern = r"Note:\s*'([^']+)'"
replace_pattern = r"Note: '''\n\1\n'''"

def main(input_file, output_file):
    with open(input_file, 'r', encoding='utf-8') as f:
        input_text = f.read()

    output_text = re.sub(match_pattern, replace_pattern, input_text, flags=re.MULTILINE)

    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(output_text)

main(input_file_path, output_file_path)
```

下記実行するとoutput_file_pathに置換後のデータが保存されます

```shell
$ python3 convert_multiline_note.py
```

下記の様に変換されます

```new_schema.dbml
Table User {
  id Int [pk, increment]
  createdAt DateTime [default: `now()`, not null]
  updatedAt DateTime [not null]

  Note: '''
User comment line1
User comment line2
'''
}
```
【備忘録】jQueryでアコーディオンメニュー

## はじめに

- jQueryを使ったUIパーツの練習アコーディオンメニュー編です。
- [【jQuery】アコーディオンメニューの作り方解説（複数パターン紹介） - PENGIN BLOG](https://pengi-n.co.jp/blog/accordion/)を参考に、[アコーディオンメニューの基本構成](https://pengi-n.co.jp/blog/accordion/#%E3%82%A2%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%82%AA%E3%83%B3%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%A7%8B%E6%88%90)部分を取り組みました。
- 後々、追記するかもです。

## 実装

### 1. とりあえずHTML/CSSで見た目を作る

- この段階で`.accordion__content`には`display: none;`を適応
    - 本家サイトでは後述のjQueryパートでjQuery側で操作していたが、ブラウザを再読み込みした際に一瞬コンテンツ部分が表示されるのが気になったので変更した。

```html
<dl class="accordion">
  <dt class="accordion__title">メニュー1</dt>
  <dd class="accordion__content">
    メニュー1のコンテンツ内容
  </dd>

  <dt class="accordion__title">メニュー2</dt>
  <dd class="accordion__content">
    メニュー2のコンテンツ内容
  </dd>

  <dt class="accordion__title">メニュー3</dt>
  <dd class="accordion__content">
    メニュー3のコンテンツ内容
  </dd>

  <dt class="accordion__title">メニュー4</dt>
  <dd class="accordion__content">
    メニュー4のコンテンツ内容
  </dd>
</dl>
```

```css
.accordion__title {
    text-align: center;
    padding: .5em;
    background-color: #6b90ff;
    border-bottom: 1px solid #fff;
    cursor: pointer;
    transition: all .3s;
}

.accordion__content {
    padding: 2em 1em;
    background-color: #d3deff;
    display: none;
}
```

### 2.  jQueryで動きをつける

- `slideToggle`メソッドを使って、コンテンツ部分の表示/非表示を切り替える。

```jsx
$(function () {
  // CSS側で設定したので削除
  // $('.accordion__content').css("display", "none");
  $('.accordion__title').on('click', function() {
    $(this).next().slideToggle();
  });
});

```

## 実装後の疑問と調査

- `display: none/block;`の切り替えにはtransitionが効かないはずでは？
    - 参考 : [CSS display:noneでアニメーションする方法](https://csshtml.work/displaynone-anime/#i-2)
        - ここでは`SlideToggle`メソッドによって、該当の動作が実現できると解説されている。
            - 「簡単に実装できるありがたい機能」として完結してよいのだろうか…?
- そもそも`slideToggle`メソッドって？
    - 参考 : [jQueryのtoggleを活用したいろいろなUIパターンの実装方法 - PENGIN BLOG](https://pengi-n.co.jp/blog/jquery-toggle/)
        - toggle系メソッドを使うと下記のことができると解説されている。
            - `display: none/block;`の切り替え
            - クラスの付け外し

## 参考サイト

- [【jQuery】アコーディオンメニューの作り方解説（複数パターン紹介） - PENGIN BLOG](https://pengi-n.co.jp/blog/accordion/)

- [jQueryのtoggleを活用したいろいろなUIパターンの実装方法 - PENGIN BLOG](https://pengi-n.co.jp/blog/jquery-toggle/)

- [CSS display:noneでアニメーションする方法](https://csshtml.work/displaynone-anime/)
makeをタスクランナーとして使う！

# Makefileを作る

## 自動でコードをきれいに整理したい
今回はblack, ruff, mdformatを使用します

👇Makefileの中身
```
.PHONY: black
black:
	poetry run black .
 
.PHONY: ruff
ruff:
	poetry run ruff check . --fix
 
.PHONY: mdformat
mdformat:
	poetry run mdformat *.md
 
.PHONY: cake
cake:
	$(MAKE) black
	$(MAKE) ruff
	$(MAKE) mdformat
 
```
`make cake`を実行すると、3つがまとめて実行されます:cake:
※cakeは好きな文字に変更してください

# 依存関係をインストール

必要なものを入れましょう！

※今回はPoetryを使用しています

Poetryは依存関係をグループ別に整理する方法があるよ
(テストやドキュメントの構築だけに必要な依存関係をグループで整理しとくと便利)

```
$ poetry add <足したいもの> --group <グループの名前>
```

👇実行結果　(blackの例)
```
$ poetry add black --group dev
Using version ^24.4.0 for black

Updating dependencies
Resolving dependencies... (4.0s)

Package operations: 7 installs, 0 updates, 0 removals

  - Installing click (8.1.7)
  - Installing mypy-extensions (1.0.0)
  - Installing packaging (24.0)
  - Installing pathspec (0.12.1)
  - Installing platformdirs (4.2.0)
  - Installing tomli (2.0.1)
  - Installing black (24.4.0)

Writing lock file
```

書くとgroup名のdevに依存関係が追加される

👇pyproject.tomlの中
```
[tool.poetry.group.dev.dependencies]
black = "^24.4.0"
```
グループdevの依存関係を表しているよ

# 実行
必要なものが入れ終わったら
```
$ make cake
```
を実行してお掃除します :cake: 

# 参考文献(公式)

https://python-poetry.org/docs/cli/#options-4

https://python-poetry.org/docs/managing-dependencies/#dependency-groups
MacでCronが動かない（dockerコマンド）

# はじめに
<!-- 発端や概要を記載 -->
ちょっとした環境をローカルで作った際に、
MacでCronを動かそうとしてつまづいたので、
解消までに試したことを忘備録。

# 目次
<!-- タイトルとアンカー名を編集 -->
- [簡単なコマンドで動作確認](#Try1)
- [ログとして吐き出してみる](#Try2)
- [「bash: docker: command not found」の対応](#Try3)
- [まとめ](#Conclusion)

<!-- 各チャプター -->
<a id="#Try1"></a>
# 簡単なコマンドで動作確認

以下のようなcronを仕込んでみる。

```
*/2 * * * * echo "hello world" >> ~/Desktop/hello.txt
```

2分おきにデスクトップのhello.txtに「hello world」が書き込まれていれば、
cronは正常に動作していることが確認できる。

<a id="#Try2"></a>
# ログとして吐き出してみる

標準出力ごとログファイルに吐き出してみる。（`2>&1`の部分）

```
*/2 * * * * [docker 実行したいコマンド] >> ~/Desktop/cron.log 2>&1
```

実行時のログが何かしら出力されるはず。
自分の場合、`bash: docker: command not found`のエラーが出ていた。

<a id="#Try3"></a>
# 「bash: docker: command not found」の対応

ローカルで以下を叩いてみる。

```
whereis docker
```

すると`docker: /usr/local/bin/docker`と出力されたため、
cronのdockerコマンドを明示的に指定する。

```
*/2 * * * * [/usr/local/bin/docker 実行したいコマンド] >> ~/Desktop/cron.log 2>&1
```

すると正常に動いた。

cronだと一部の環境変数が設定されず、
いつも通りに叩くだけだと使えないコマンドが出てくるみたい。
今回みたいにフルパス指定してあげると動かせる。

<a id="#Conclusion"></a>
# まとめ

以上、忘備録でした。
他にも、-itオプションがついたままだとエラーが出るなどもあるみたい。

https://zenn.dev/tatto/articles/f1009bf153d4b0#docker%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B

色々、知らない仕様があるなあ。
【React】lazyで名前付きエクスポートのコンポーネントを動的インポートする方法

Reactの [lazy](https://ja.react.dev/reference/react/lazy) で名前付きエクスポートのコンポーネントを使用したい場には以下のように記述します。

```jsx
import { lazy } from 'react'

const Modal = lazy(() =>
  import('.components/modal').then((mod) => ({
    default: mod.Modal,
  }))
)

```
AWS Certified Cloud Practitioner(CLF-02)取得までの道のり

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3687568/17a98fe4-1136-33fb-a59f-a333520e3cba.png)

2024/4/13 AWS Certified Cloud Practitioner(CLF-02)に合格しました。
備忘録も兼ねて、AWS初心者の私が歩んだCLF取得までの軌跡を記載している記事となります。

## 0.お詫び
最初にお詫びとしてお伝えしておきます。
今から本気でCLFの合格を目指して勉強方法を探している方には参考にならない内容です。
どう参考にならないのかは最後まで読んでいただければわかると思います。笑

## 1.自己紹介
30中盤のAWS初心者です。とある製造業の情報システム部2年目です。
それまではSIerで主に業務系Webアプリの開発を8年ほど行っていました。

こちらの記事に私がどんな人間かは記載されています。

https://qiita.com/umataro/items/6cb57a900bea60aefa54

## 2.きっかけ
CLFを取得しようとおもったきっかけは、<font color="red">**AWS Summit Tokyo 2024で認定者ラウンジに入ってみたい**</font>から。はい、ただそれだけです。
取得したことを業務に生かそうとかは全く考えていませんし、会社に報告予定もありません。

## 3.AWS Summit Japanとは
2024年6月20,21日に幕張メッセでAWS Summit Japanというイベントが開催され、参戦する予定です。
去年の開催日はまだAWSを触れたことも見たこともなかったタイミングです。
そのため、今年が初参戦ですが去年のレポートを見るとどうやら認定者ラウンジというものがあり、認定資格を持っているとシールをもらえたり、専用ラウンジに入れたりした模様。

せっかく行くのであれば、ラウンジにもはいれるようにしておきたい！という、本当にただただそれだけの思いで資格取得を目指しました。

**AWS Summit Japan 2024**
(記事作成時点ではまた参加登録は始まっていません)

https://aws.amazon.com/jp/summits/japan-teaser/

**AWS Summit Tokyo 2023**
2023年の認定者ラウンジについてはこちらのページの最下部の方を参照してください

https://aws.amazon.com/jp/summits/tokyo-2023/expo/

## 4.申し込み
1月にAWSのユーザー会JAWS-UGの初心者支部に参加した際、今なら再受験無料キャンペーンをやっているという話を聞いて、4月から受験料が値上げされるということでしたので、キャンペーン期間内でできるだけ後ろの方にとりあえず申し込んでしまおう。とうことで、3月上旬に2024/4/13の受験申し込みをしました。
この日は問題の雰囲気をつかむだけで合格する気は全くなく、再受験時の合格を目指していました。

**JAWS-UG初心者支部**

https://jawsug-bgnr.connpass.com/

**再受験無料キャンペーン**

https://www.pearsonvue.co.jp/aws/freeretake

## 5.学習方法
申し込んでからは、とりあえず本を読もうということでネットでいろいろ探して、評判の高そうなこちらの本を買うことに決めました。
<a href="https://books.rakuten.co.jp/rb/17770412/?s-id=ph_pc_itemname">AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー　改訂第3版</a>

買おうとしてよく見ると約2週間後に第3版が出るみたいだったので、そちらを予約して3月下旬に届きました。

## 6.学習時間
最初に申し込んだ日に合格する気はなかったので、気分の乗ったときに少しずつ本を読み進めました。
本の内容自体はわかりやすく読みやすかったです。結局、受験日までに163Pまで読んでいました。
AWSアカウントは作ってありますが、受験勉強ために特に触ったりはしていません。
受験勉強としては本当にこの本を読んだだけです。

## 7.受験当日
受験はテストセンターで受けました。
当日は写真撮影とかもあるようでしたので、早めに行こうと思い40分前くらいに到着しましたが、一瞬で受付を終えたため、30分以上待合室で待機していました。
※初めて受験する人は、当日に身分証が2点必要なためお気をつけて！
　私は免許証 + マイナンバーカードを持っていきました。

時間になり席へ案内してもらい試験開始です。
ぽちぽち問題を解いていきましたが、意外にわかるなーと思いながら最後まで解き終わって、終わった人から退出できるはずなのにまだ誰も退出しておらず、コミュ障には一番に出る勇気はなかったので、丸々もう一周見直し兼ねて解きなおしました。
その間に一人退出したので、私も試験完了したところ、画面に表示された文字は...

<font color="red">**合格**</font>

信じられずびっくりしすぎて、実感ないままちょっときょどりながら退出しました。
翌日に無事にメールでも合格の案内が届きました。

## 8.まとめ
というわけで、ろくに知識もないのに資格だけ持っているという状況になってしまいました。
これで無事にラウンジに入れるため、嬉しいのですが少し複雑な気持ちもあります。
とりあえず買った本は最後まで読みます。他のCLF合格者に失礼の無いように最低限の知識はつけておきます...

こんな感じで、私はろくに勉強もせずCLFに合格していまったというお話でした。
vueJSのemit

子コンポーネント
```vue.js:child.vue
<template>
  <button @click="CCCevent">ボタン</button>
  //①このボタンクリックしたら、同コンポーネントのCCCevent起動
</template>

<script setup>
const xxx = defineEmits();
//②親に打ち上げるための事前準備。defineEmitsをどこでもつかえるようにしておく。

const CCCevent = () => {
    xxx("xxxevent");
};
//③defineEmitsすることで親のxxxeventが発火
//親コンポーネントのタグに＠xxxeventがいる。
</script>

```

親コンポーネント
```vue.js:parent.vue
<template>
  <div>
    <Child @xxxevent="YYYevent" />
    //③子でxxxevent発火したら　右辺の名前のメソッドが実行される。
  </div>
</template>

<script setup>
import Child from "./Child.vue";

const YYYevent = () => {
 console.log('発火したよ')
};
//最後にこのメソッドが実行される。
</script>

```


<Child @xxx="YYYevent" />
コンポーネントタグの＠はv-on
＠xxxだったら、そのコンポーネントの中でxxxという合図があったときに、ついでにやってくれるアクションを追加できる。

defineEmitsのimport必要ない


emitについて調べていて、変数名や関数名が似たり寄ったりで目が泳いだので、記号的な書き方にしてみました。


emitと一緒にデータを渡す方法

子コンポーネント
```vue.js:child.vue
<template>
  <button @click="CCCevent">ボタン</button>
  //①このボタンクリックしたら、同コンポーネントのCCCevent起動
</template>

<script setup>
//なにかしらのデータ　追記
const hogeOgject = {
  hogehoge //中略
};

const xxx = defineEmits();

const CCCevent = () => {
    xxx("xxxevent",hogeOgject);//hogeOgject追記
};
</script>

```

親コンポーネント
```vue.js:parent.vue
<template>
  <div>
    <Child @xxxevent="YYYevent" />
    //③子でxxxevent発火したら　右辺の名前のメソッドが実行される。
  </div>
</template>

<script setup>
import Child from "./Child.vue";

//引数に入れるだけで受け取り完了
const YYYevent = (data) => {
 console.log('dataもらったよ')
};
</script>

```

第二引数に入れてあげてあげれば
xxx("xxxevent",hogeOgject);//hogeOgject追記
親のメソッドの引数に勝手に入る
Mind8の中間コードディスパッチャ（の一部）をCからC#に書き換えてみたい（キックオフ）

# はじめに
[こちらの記事](https://qiita.com/mylifewithviolin/items/2804356ae2f39b055b8c)でVSCodeでMind 8 for Windowsのkernelをデバッグ実行できる環境をつくり、[前回記事](https://qiita.com/mylifewithviolin/items/923875a640768e3e993f)まで主に64bit整数変数の処理単語の習作をMind開発者の@killyさんのご支援をいただきつつ行って参りました。

今回はその処理単語追加の習作へと進行する分岐点となったMind8のkernelをデバッグ実行できる環境の記事に立ち戻り、その後の習作で学習した知見もまじえつつ、Mind8の中間コードディスパッチャ（の一部）をCからC#に書き換えてみるという野望に進行してみようと思います。今回はそのキックオフ的な記事で、当時の振り返りとこれまでのまとめです。

# 前提条件
Windows11 Pro 22H2
VSCode(Visual Studo Code)　1.86.1
Microsoft Visual C++ 2008 Express Edition
Mind Version 8.0.08 for Windows

このテーマでは処理単語の追加はなく、既存単語のMCode（の一部）を解釈実行する部分をCからC#に書き換えるというお題のため、辞書再構築ツールは使用しないので、Mind7ライセンスは不要です。

C# 10 
dotnet-sdk-6.0.419-win-x64
dotnet-sdk-6.0.419-win-x86
Mind Version 7.5 for Windows

## VSCodeの拡張機能
C/C++ for Visual Studio Code 1.18.5 Microsoft 
C/C++ Extension Pack 1.3.0 Microsoft 
.NET Install Tool 2.0.2 Microsoft
Base language support for C# 2.18.16 Microsoft

C/C++のデバッガはMind8のCカーネルアプリケーションをデバッグ実行するために使用しています。実装には使いませんが動作を確認するのに引き続き使用します。
.NETCoreバージョンは少し低めなので、どこかのタイミングで引き上げる見込みです。x86かx64か微妙ですが、いまのところx64で実装してなにか問題があればx86に切り替えるというスタンスで行きます。

# これまでのまとめ
・kernel.cがkerbody.cをインクルードしてkerbody.cがkermain.cをインクルードする入れ子構造となっていて、kermain.cのexecute_main_wordという関数内で、同じくkermain.cのsetupForDispatchという関数でMCodeファイルが読み込まれ、同じくexecute_main_word関数内からdispatch.c内のdispatcher()という関数が実行されます。

・dispatcher()の中身はざっくり書くと下記のような感じになっているようです。
細かい話ははしょってます。以下は疑似言語Re:Mindによる表記です。

```
〇ループする

　□mcode = フェッチする
 ◇mcodeと0x8000のビット論理積が偽の場合
   //C関数
   □C_Words_Addr[mcode]()
 ◇真の場合
   //Mind単語
   □PUSH_R( McodePointer.l )
   □SET_MCODE_POINTER_BY_WORDNO( mcode & 0x7fff )
 ◇ここまで

〇ここまで
```
当面の課題は上記のC関数の方に分岐した場合の
```
C_Words_Addr[mcode]();
```
をC#に書き換えることをめざします。

このあたりの実行イメージは、64bit整数変数の処理単語の追加習作の過程でだいぶつかんでいるとはいえ、MindのCランタイムが用意しているアプリケーションスタックやそのポインタの動きはまだ細かくは認識していません。いろいろな試行錯誤が想定されます。

このループが回ってmcodeにいろいろな値が入ってくるとビット論理積がC関数側に成立して、C_Words_Addr関数配列が実行されると、mcodeがインデックスになって、テーブルを参照して所定の対応関数を呼び出していく処理のあたりです。

これはものすごく画期的な処理構造と認識しました。mcodeは相当ランタイムフリーな実装と思われます。これによりほとんどの範囲の特定の実装言語で実装された処理を直接ファンクションコールすることを回避していることになります。ただし、ディスパッチャ自体はその実装言語で実装される必要はあり、ここが本記事のテーマです。


# なにがうれしいかのまとめ
本記事はキックオフということであまり中身がありませんが、最後にMind8の中間コードディスパッチャ（の一部）をCからC#に書き換えれると、なにがうれしいのかまとめてみます。

Mind自体がmcodeというCPU実装やOSから切り離された環境で走行していますが、ランタイムがCで書かれているため、他の言語実装の機能を利用するためにはC言語のDLLにする必要があったり、Cで処理単語を追加する必要があります。

Mind8の中間コードディスパッチャがC#で書かれた処理単語を呼び出せるようになると.NETCoreや.NETFrameworkの資産をMind側のソースコードから簡単に呼び出せるようになる気がします。mcode上のデータフォーマットはC言語互換っぽいので、マネージドランタイム型へのマーシャリングとか問題になるかと思われますが、MindのDLLをC#から呼び出す際にちらっとやっているので、そのあたりがとっかかりにはなる想定です。

またC#のランタイムの.NETCoreは今日的にはいろいろなプラットフォームで動くのでそれらの環境でMindが走行できるようになるのも楽しいかもしれません。

# おわりに
しかし、実際の課題は山積で思うように進まないことも想定されますので、いろいろなテーマと並行してのんびりやっていこうかと考えております。Cで書かれているすべての処理単語を対応させるのは気の遠くなる作業なので、あくまで一部単語を動かして悦んでみたいという興味本位のテーマです。

# 追記
* その後の展開情報

https://qiita.com/mylifewithviolin/items/818de8aca51f6750da6c

https://qiita.com/mylifewithviolin/items/151517f7a57b5b8b97f5
【シリーズすごいぞiQ-F】ラベルが意味するものの派閥について

## この記事の対象
+ 暇な方
+ マニュアルを読んでいて、場所によってラベルと書いてあったり変数と書いてあったりするのが気になる方

## はじめに
一般的には「変数」と呼ばれているものを三菱電機は「ラベル」と言っているという認識だったのですが、マニュアルのあちらこちらに「変数」という言葉も記載されているのでいったいどういう用語の扱いなのか調べてみました。

## 派閥1　ラベルは変数派
+ iQ-RもiQ-Fもカタログには「変数」という用語は一言も出てこない
    + 変数プログラミング＝ラベルプログラミング　という扱い    
+ 【ラベルとは，入出力データや内部処理に任意の文字列を指定した変数】
    + MELSEC iQ-F FX5プログラミングマニュアル(プログラム設計編)
    + MELSEC iQ-R CPUユニット　ユーザーズマニュアル(応用編)
    などでの記載    
+ 【一般的なプログラミングの変数にあたるラベル】
    + 技報　「GX Works3 におけるiQ-F シリーズシーケンサのパラメータ省力設定に向けた開発」
    での記載

プログラムの中で配置して使用するものは「ラベル」、一般的な意味合いで説明するときは「変数」を使用しているように見えるのですが、統一はされていないように見受けられました。

「内部処理に任意の文字列を指定した変数」というのは変数に関数を代入するという概念が導入されていれば意味が通じるのですが、そこまでの概念は導入されていないので初見では混乱しました。

## 派閥2　ラベルは名前（識別子）派
+ 【ラベルとは，入出力データや内部処理に任意の文字列を指定した識別子(文字列)】
    + 「MELSEC iQ-F FX5ユーザーズマニュアル(応用編)」
    での記載

派閥としては小さい派になりますがファンクションブロックを扱うようになるとこちらの方が理解し易い表現でした

## 派閥3　ラベルはプログラムのジャンプ先派
+ 「ラベル」という用語はIEC61131-3ではプログラムのジャンプ先を表す
    + 三菱電機では「ポインタ」という用語を使用

## おわりに
三菱電機は独自の用語を使いたがる傾向があると私は感じています。

最近まで変数をラベルと言い換えているという認識だったのですが、変数という言葉もマニュアルで沢山使っていることに少し驚きました。

マニュアル中に変数部品（ラベルとデバイス）という記述があるので、
+ 組込変数＝デバイス
+ ユーザー定義（宣言）変数＝ラベル

という解釈でデバイスプログラムとの差別化を図る為に「ラベル」という用語を導入したのでしょうか。
せめてIECで使われている用語とは異なるものを導入してもらいたかったです。

細かいくせにいい加減なまとめとも思ったのですが、ラベルというのが変数を指すのか、インスタンス等の名前を指すのか、文脈に合わせて理解する助けになることもあれば幸いです。

## 過去記事一覧
+ [過去記事一覧](https://qiita.com/fujiteruo/items/af2459d320e8109963db)
GASで、セルのコピペを禁止したい

スプレッドシートでいろいろと条件書式をつけたのですが、
コピペをするとそれも一緒に引き連れてしまうので、
社内で共有するには、コピペを禁止にしたいのですが
ＧＡＳで可能でしょうか？？

どなたかコードを教えてください。
Laravel Auditingのログがクエリビルダのイベントでは記録されない

# 概要
業務でLaravel Auditingを使用しており、監視対象のカラムが変更された際にレコードがInsertされない事象に対応したときの備忘録です。
間違いがあればご指摘をいただけると嬉しいです！

# Laravel Auditingとは
Laravel Auditingとは、DBにおいてレコードに変更が行われた際、自動でログを記録してくれるパッケージのこと。
どのカラムが誰によってどんな風に変更されたか監視することができます。
（問い合わせサポート業務とかであると助かるかも…）

# クエリビルダを使用した場合はテーブルにレコードが入らない
以下のドキュメントにもあるようにクエリビルダによるDBの更新は記録されません。
EloquentでModelを使って変更してあげる必要があります。
https://laravel-auditing.com/guide/community/troubleshooting.html
https://laravel-auditing.com/guide/community/why-laravel-auditing.html

# Eloquentを使用しよう
Auditingで記録したいならEloquentを使用しましょう！
## サンプル
### Modelクラス
```PHP
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class AuditTarget extend Model implements Auditable
{
    use \OwenIt\Auditing\Auditable;

    private $table = 'audit_target';

    /**
     * Attributes to include in the Audit.
     * ここでは監視対象を指定します
     * デフォルトは全カラムが対象
     * @var array
     */
    protected $auditInclude = [
        'audit_target',
    ];

    /**
     * Attributes to exclude from the Audit.
     * ここでは監視から除外するカラムを指定できます
     * デフォルトは除外カラムの指定はありません
     * @var array
     */
    protected $auditExclude = [
        'excludion_target',
    ];
}
```

### 変更処理(create・delete・update・save)
これでOK
```PHP

namespace App\Service;

use App\Models\AuditTarget;

class Service
{
    public function update()
    {
        $changeTarget = AuditTarget::first();
        $changeTarget->update([
            'column' => 'hoge',
        ]);
    }
}
```

# 最後に

そもそもイントロダクションに書いてありました…
（公式ドキュメントはちゃんと読もう！）

>This powerful tool offers detailed auditing capabilities for Eloquent models, allowing you to keep track of changes made to records, as well as any changes to their attributes.

https://laravel-auditing.com/guide/introduction.html
コメント自動でつけれる機能

「Mintlify」という拡張機能が、読み込ませたコードの内容を要約し、コメントを書いてくれる。

VSCodeの拡張機能を入れて、欲しいコードを選択すると、それなりに長いコードでも即コメントを入れてくれる。
誤ってself-hosted-runnerをforce removeしてしまい、tokenを再作成したい

削除しようとしてたrunnerじゃないやつを間違えて消してしまった・・・
となって困っていたのですが、どうにか解決できました。

以下を実行すれば大丈夫です。

```sh
sudo ./svc.sh uninstall
rm .runner
./config.sh remove
```

肝は`.runner`のファイルを消すことで、問題なくconfigのremoveができるようになること。
強制削除してしまっているのでtokenが分からず、正常に`./config.sh remove`に実行できずに困っていましたが、これで解決しました。

この後、再度登録処理を実行すればOKです
Error: Malformed PostCSS Configuration

tailwind cssが効かなく，解決までに時間がかかったので共有します．

## エラー
```
./src/app/globals.css.webpack[javascript/auto]...
Error: Malformed PostCSS Configuration
    at Array.forEach (<anonymous>)
```

## 結論
```postcss.config.js
module.exports = { 
  plugins: [
    'tailwindcss',
    'autoprefixer',
    'postcss-import',
    'postcss-flexbugs-fixes',
  ]
}
```

pluginsの指定方法が間違っていて(バージョンで異なる？)エラーになっていました．


```postcss.config.js
// 失敗例
module.exports = { 
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
    require('postcss-import'),
    require('postcss-flexbugs-fixes'),
  ]
}
```


## 参考
https://github.com/nrwl/nx/issues/8884#issuecomment-1046897099

https://nextjs.org/docs/pages/building-your-application/styling/tailwind-css