OmniAICreator/Qiita-1.07M huggingface dataset:
Hashicorp Boundaryのリソースについて

こちらの記事の続きです。
https://qiita.com/came_ske/items/7a8f9670d967a1d85980

参考文献はこちら
https://developer.hashicorp.com/boundary/tutorials/oss-getting-started/oss-getting-started-console

# Boundaryのリソース関係
上記の記事でhttp://127.0.0.1:9200 へログインできました。
こちらでリソースを簡単に管理できます。

リソースについてはざっくり書くとこの通りです。
Global（1つ）を頂点に階層構造となっています。
```
例）XProojectではAWSとAzure両方を使っていて、それぞれのクラウドにAPPサーバのHA、DBサーバのHAがあるとします。

Global
    |- Org
        |- Project（XProoject）
            |- Target (APPサーバ群、DBサーバ群とか)
                （|- Host Set（DBサーバHost Set1））
                    |- Host（APPサーバ#1、APPサーバ#2、DBサーバ#2とか）
```

```
|- Host Catalog（AWSCatalog、AzureCatalog）
        （|- Host Set（APPサーバHost Set1、BシステムDBサーバ））
                |- Host（AシステムAPPサーバ#1、AシステムAPPサーバ#2）

```

詳細はこちらリソースの関係図
https://content.hashicorp.com/api/assets?product=tutorials&version=main&asset=public%2Fimg%2Fboundary%2Fboundary-resources.png
3/28 Linux コマンド操作part4

# 個人的リマインド用
パーミッション

## ファイルのオーナーとグループ
ファイルには全てオーナーとグループが設定されていて、権限管理されている

・前提：Linuxではユーザーごとにアカウントを発行する
・オーナー：ファイルの所有者
・グループ：ファイルの所有グループ。ユーザーをグループに所属させ、グループに権限を与えることで、複数ユーザーの権限を一括で管理できるようにする

確認方法 ls -lコマンドでファイルのオーナーとグループが確認できる
```
ls -l /etc/less
-rwxr-xr-x. 1 root(オーナー) root(グループ) 158240 7月 31 2015 /bin/less
```
## パーミッション
ファイルやディレクトリを「誰がどのように操作できるか」を定めたのがパーミッション
```
-rwxr-xr-x. 1 root root
-r(ファイルタイプ)wxr(オーナーのパーミッション)r-x(グループのパーミッション)r-x(その他のユーザーのパーミッション)
```
**パーミッションの記号**
r read(読み取り)
w write(書き込み)
x execute(実行)

**rwxr-xr-xの場合**
対象　読み取り　書き込み　実行
オーナー　○ ○ ○
グループに属するユーザー　○ × ○　
その他のユーザー　○ × ○

## chmodコマンド
ファイルやディレクトリのパーミッションを設定する
```
chmod [ugoa] [+-=] [rwx] <ファイル名>
```
記号　内容　記号　内藤
u 所有者の権限 + 権限を追加
g グループの権限 - 権限を削除
o その他のユーザーの権限 = 記述した権限にする
a 全ユーザーの権限 
```
chmod u+r file
```
**数値で指定**
```
chmod <8進数の数値> <ファイル名>
```
r(読み取り) 4
w(書き込み) 2
x(実行) 1
rwx = 7, r-x = 5, -wx = 3
```
chmod 755 file
```
## スーパーユーザー
管理者権限をもつ特別なユーザーがスーパーユーザー
・システムの根幹に関わる作業が誰にでもできると危険
・そのため、システムの根幹に関わる作業はスーパーユーザーとしてコマンドを実行
```
sudo <コマンド>
switch user and do

具体例
sudo mkdir /storage
```
アンチパターン　メンタルヘルス

:::note alert
警告
もしいずれかのアンチパターンをしている場合は早急に中止し、メンタルクリニックや精神科の受診を検討してください。
:::
# はじめに
この記事はメンタルを病んだシステムエンジニアのあくまで個人的なアンチパターン集です。
少しでも皆様の心に響けば幸いです。そして決して真似しないように。

# アンチパターン1 「残業」
残業は本来許されざるものです。しかし残業代が稼げるので最初のうちは楽しくなります。
この結果、体力はもちろんのこと、免疫力も低下します。

# アンチパターン2 「休日出勤」
休日出勤手当、いいですよね。静かなオフィス（もしくは誰もログインしていないslack)に唯一人ログインするのもまた趣がありますよね。
でも、よく考えてください。本来、その日は休日なのです。休むべき日なのです。
この結果、体力はもちろんのこと、免疫力も低下のみならず、ワークライフバランスも崩れます。

# アンチパターン3「連勤」
これは「アンチパターン1」と「アンチパターン2」の合せ技で錬金術と化します。
やったね！おちんぎんがふえるよ！！！！
なお。この後体調を崩しそのお賃金は消えてしまうのはお約束・・・

# アンチパターン4「根拠のない工数見積・KKD法に基づく工数見積」
アンチパターン3までやらかすと、今までの工数見積が全く当てにならなくなります。
すでに自分の体はランナーズハイ状態です。そのため「勘」「経験」「度胸」に基づく工数見積なんてもっての外です。

# アンチパターン5「周りの気遣いを無視する」
流石に連日連夜残業や休日出勤をしていると社内の人から　**「本当に大丈夫なのか」** と確認が入ります。
それに対して  **「あー大丈夫っすよーなんとかなりますー」** と答えてはいけません。
あなたの体はもうボロボロです。

# アンチパターン6「酒に溺れる」
もうここまでくると論外ですね。残業からの一杯、美味しいですね。しかし体には良くないです。

# アンチパターン7「どか食い気絶部」
過食はドーパミンを発生させるので気持ちいいです。まして **どか食い気絶部** となると血糖スパイクで気持ちいいです。
しかし、これはかなり体に良くないです。

# アンチパターン8「仕事以外は死んだように寝る（気絶する）」
残業終わり、暴飲暴食をして死んだように寝るのはいよいよ末期です。「休みの日は寝て過ごした」ともなればなおさらです。早急に精神科に行ってください。

# アンチパターン9「趣味に興味を示さなくなる」
完全にうつ状態です。

# アンチパターン10「頭痛などを市販薬で誤魔化す」
体の悲鳴をロキソニンやアスピリンでごまかさないでください。用量以上に服用する行為（いわゆるオーバードーズ）は論外です。病院に行ってください。

# 終わりに
私はこのアンチパターンを半年ほどすべて行った結果、気がつけば精神病棟でした。
うつ病と診断され、即休職の診断書でした。
今はなんとか回復し、2023年4月より復職します。

# 仕事が辛いあなたへ
厚生労働省ー相談先一覧

https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/hukushi_kaigo/seikatsuhogo/jisatsu/soudan_info.html
オブジェクト指向プログラミング『OOB』

# オブジェクト指向とは
- プログラミングを記述する上での概念
    - オブジェクト指向 = Object-Oriented（オブジェクトへ向けられた）
        - 現実世界を正しく捉えてコードを記載すること（プログラミング記法）
    - OOP（Object-Oriented Programing）= オブジェクト中心のプログラム
        - 処理や機能をまとめておき、使いたい時に呼び出す。
    - 手書き型プログラミング記法
        - コードが長くなる
        - メンテしづらい、変数を探すのが大変
    - オブジェクト指向記法
        - 頻繁に使用されるコードをまとめて記述する。
        - 問題の切り分けがしやすい、コードの使い回しができる

# オブジェクト指向の書き方
- クラス 機能をまとめた設計書
    - プロパティ（名詞）
        - 特徴・要目
    - メソッド（動詞）
    - 技・関数
- インスタンス
    - 設計書をもとに作られた実体
### 例：人間Aさんが料理をする をオブジェクト指向で表現する
- クラス 人間
    - プロパティ
        - 名前
        - 性別
        - 体重
    - メソッド
        - 料理をする
- インスタンス
    - 上記のクラス、プロパティ、メソッドをもとにつくられた人間を生み出す（＝　人間クラスをインスタンス化）
![スクリーンショット 2023-03-28 22.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/c09a91fa-9d42-1466-7632-638d44cb1025.png)
### 例：車の車種と走行距離
![スクリーンショット 2023-03-28 22.33.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/b7dcf180-45fa-9d94-acc7-ce8ccab62282.png)


### その他
- アクセス修飾子（private,public,protected）
    - public クラスの内外からアクセスできる
    - private クラスの中からのみアクセスできる
- ゲッター、セッター
    - セットで使う
- カプセル化
    - プロパティをprivateでアクセス制限し、セッターメソッドとゲッターメソッドを使ってプロパティへアクセスする構造
- コンストラクタ
    - インスタンスが作られたと同時に起動するメソッド
![スクリーンショット 2023-03-28 22.35.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/21490a04-c3cb-1113-2768-f1d20c1b286d.png)
- 継承
![スクリーンショット 2023-03-28 22.37.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/41175418-a497-f56c-8ccc-266fedd1b813.png)
メディアクエリの指定で比較演算子（width >= ***px）が使える！

## はじめに
CSSでレスポンシブデザインを実装する際にメディアクエリを使用することが一般的ですが、範囲指定で比較演算子が使えるようになり直感的でわかりやすくなりました。
今まではメディアクエリで比較演算子（>=, <=）を使用することはできませんでしたが、対応ブラウザが増えたことにより実用的になりましたので紹介します。

### 今までの記法
「デバイスの幅が375px以上600px以下の場合にだけ適用するスタイル」を定義するには、複数のメディアクエリを使用する必要がありました。
```css
@media (min-width: 375px) and (max-width: 600px) {...}
```

### 比較演算子を使った記法
Media Queries Level 4 で"range"型を持つ特性を使って以下のようにメディアクエリーを記述することができます。
```css
@media (375px <= width <= 600px )  {...}
```
## おまけ
###  論理代数（and, not, or）を使ったメディアクエリーも使える
**not による特性の否定**
not() を使用してメディア指定を囲むとその指定を否定します。
例えば、 not(hover) は端末でホバーができない場合に一致します。
```css
@media (not(hover)) { ... }
```
GitHub上で作成したリポジトリをCloud9にcloneし、PRを作成するまでの流れ


## Cloud9へのcloneまで

①GitHubにログインして、新しいリポジトリを作成します。リポジトリ名は任意のものを設定し、Public（公開設定）にします。  


②Cloud9の開発環境に移動し、ターミナルを開き、  

```
$ cd ~/environment
```
を実行して、カレントディレクトリを開発環境のルートディレクトリに変更します。  

③git clone <GitHubのリポジトリのURL> を実行して、GitHub上のリポジトリをCloud9にクローンします。 
### Cloud9ならSSHのurl
 
```
$ git clone <リモートリポジトリのURL>
```  

④以下のコマンドでクローンしたリポジトリのディレクトリに移動します。  
```
$ cd <リポジトリ名>
```   
⑤リモートリポジトリにまだブランチがない場合、  
```
$ git push -u origin main
```  
を実行して、"main"という名前の新しいブランチを作成します。  
⑥続いて  
```  
$ cd git checkout -b <新規ブランチ>
``` 
を実行し新規ブランチに切り替えます。 
⑦続いて 
```  
$ touch <新規ファイル>.md
``` 
を実行して、"新規ファイル"というファイルを作成します。  
  
## PRまでの流れ  
①ローカルの編集中のブランチに移動する。  
```  
$ git checkout <編集中のブランチ名>
``` 
②ファイルをGitのステージング領域に追加するために

```  
$ git Add <編集中のファイル>
``` 
③コミットメッセージを記述してコミットします。  
```
git commit -m "変更内容のメッセージ"
```  
④pushします。  
```
git push origin <編集中のブランチ名>
```
  
以上でcloneしたリポジトリの編集、PRの作成まで行えると思います。
拙い記述でしたがもし間違いなどあればご指摘いただけますと幸いです。
SQLを簡単に試す方法について

# はじめに
SQLを学習、もしくは実務で使っていて、自身の作成したクエリが想定通り動くかどうかを
テストデータを使って検証したいと思ったことはないでしょうか。

私は何度もそのような場面に出会したのですが
その際、環境を構築してテストデータをSQLに読み込んで、、、や
pythonでsqliteを使って、、、、といった方法を試しました。
しかし、どれも手間がかかってしまい他の方法を調べていたところ
SQL fiddleというものを見つけ、試したところ便利だったので紹介します。

# SQL fiddleとは
http://sqlfiddle.com/
をクリックするだけで環境を構築することなく
WEB上でログインなど不要でSQLを試すことができます。
また、以下のように色々な種類のRDBに対応しております。(2023年3月28日時点)
![x1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522066/e5add713-ec7e-ca29-a76b-fb7c253982c9.png)

# SQL fiddleの使い方
①出力したいテーブルの情報とデータを記載
②Build_Schemaをクリック
③出力したいデータのクエリを記載
④Run SQLをクリック
⑤出力結果がアウトプットされます。
![x４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1522066/78d6f492-5502-d885-e0ac-56577c5fee97.png)

# 終わりに
このようにSQL fiddleを使うことで簡単にSQLを試すことができます。

本記事が皆さんのSQL利用の参考になれば幸いです。

また、こっちの方が便利だ〜などの情報も教えていただけるとありがたいです。
データの変更が何度あったか集計する


データ算出をするときにある数値が何回変更があったかを確認する機会があったので記事に保存します。




| datetime       |       userid |    変更がある数値    |
|:-----------------|------------------:|:------------------:|
| 10:00             |             123 |        a        |
| 10:01           |            123 |            a |
| 10:04            |              123 |        a        |
| 10:08            |                123 |         b         |
| 11:17             |             123 |       b       |
| 11:19          |           123 |        a     |
| 13:08            |                123 |         b         |
| 13:10             |             123 |       c       |
| 13:59          |           123 |      c       |




このようなログがあったときに、123というユーザーの「変更がある数値」に何回変更があったかを集計します。


上記の例でいうと、aaa→bb→a→b→ccと数値が変わっていくので
変更数は5回となります。


### やりたいこと

上記のログに3つのデータを追加します。

①ユーザーIDごとのカウント
→ウィンドウ関数を利用
ROW_NUMBER()OVER(PARTITION BY userid ORDER BY datetime) 


②変更がある数値ごとのカウント
→ウィンドウ関数を利用
ROW_NUMBER()OVER(PARTITION BY userid, 変更がある数値 ORDER BY datetime) 


③①と②の差分


3つのデータを追加したテーブルが下記になります。




| datetime| userid |A 変更がある数値|B ユーザーIDごとのカウント |C 変更がある数値ごとのカウント|差分|
|:-----------------|------------------:|:------------------:|:------------------:|:------------------:|:------------------:|
| 10:00  |     123 |        a        | 1 |1 |0|
| 10:01  |     123 |            a |        2     |2 |0|
| 10:04  |      123 |        a        |        3        |3|0|
| 10:08  |      123 |         b         |        4        |1|3|
| 11:17  |      123 |       b       |        5        |2|3|
| 11:19  |      123 |        a     |        6        |1|5|
| 13:08  |        123 |   b|  7|1|    6|    
|13:10 |        123 |       c       |        8  |1|7|
| 13:59    |      123 |      c       |        9 |1|8|





すると上記のようなテーブルになるため、差分として出てきた数字のユニーク数が「数値に変更があった数」になるため、
ユーザーごとにカウントします。
ヘッダーファイル参照ツリー


下記手順でプロジェクトのプロパティの中から、ヘッダーファイルのツリーを作成することを設定できます。
Project Settings -> Configuration Properties -> C/C++ -> Advanced -> Show Includes

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188794/5c5a6d1d-cb0d-95b2-2436-dec91b186934.png)

これは、コマンドラインの「/showIncludes」は同様な効果があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188794/37afe575-14fa-7ea3-10ad-ddcb3d278788.png)

設定に変更したら、再度ビルトすると「出力」ウィンドウにヘッダーファイルのツリーが表示されます。
ネストされたヘッダーファイルのは、図のように、ネストのレベルごとに1つのスペースのインデントで示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188794/36bd1d76-413e-270d-a503-4f775665cb13.png)

複雑なヘッダーファイルの参照を確認する時に有効でしょう。
QUERY関数についての覚書

QUERY関数は、Googleスプレッドシート上でデータの検索、フィルタリング、集計を行うための関数です。SQLのように、クエリを書くことで複数の条件を指定してデータを取得できます。

## 基本的な構文

```spreadsheet
=QUERY(data, query, [headers])
```
- data：検索するデータがある範囲を指定します。例えば、シート名を含む範囲、A1から始まる範囲などです。

- query：検索条件を記述します。SQLに似た記述方法で、SELECT、WHERE、GROUP BY、ORDER BYなどのキーワードを使用してデータをフィルタリング、並べ替え、集計することができます。

- headers：省略可能なパラメータで、データのヘッダーを表示するかどうかを指定します。


## データの例

|名前|年齢|都道府県| 
|---|---|---|
|田中|20|東京都| 
|山田| 25|大阪府| 
|鈴木| 30|東京都| 
|佐藤| 35|北海道| 

このデータから、年齢が30歳以上で、都道府県が東京都の人の名前と年齢を取得するには、以下のようなQUERY関数を使用します。

```spreadsheet
=QUERY(A1:C5, "SELECT A, B WHERE B >= 30 AND C = '東京都'")
```
この場合、A1からC5の範囲を検索し、年齢が30以上かつ都道府県が東京都の人の名前と年齢を取得します。結果は以下のようになります。

|名前|年齢|
|---|---|
|鈴木| 30| 

このように、QUERY関数を使うことで、スプレッドシート上で高度なデータ分析を行うことができます。


## QUERY関数のキーワードについて

- SELECT
SELECTキーワードは、取得する列を指定するために使用します。以下のように、列名や範囲を指定することができます。

```spreadsheet
SELECT A
SELECT A, B
SELECT A:C
```

- WHERE
WHEREキーワードは、検索条件を指定するために使用します。以下のように、条件式を記述することができます。

```spreadsheet
WHERE A > 10
WHERE A = 'abc'
WHERE A LIKE '%def%'
```
- ORDER BY
ORDER BYキーワードは、取得したデータの並べ替えを指定するために使用します。以下のように、並べ替えの基準と方向を指定することができます。

```
ORDER BY A ASC
ORDER BY B DESC
ORDER BY A, B DESC
```
- GROUP BY
GROUP BYキーワードは、取得したデータをグループ化するために使用します。以下のように、グループ化する列を指定することができます。

```
GROUP BY A
GROUP BY A, B
```

- LIMIT
LIMITキーワードは、取得するデータの件数を制限するために使用します。以下のように、取得する行数を指定することができます。

```
LIMIT 10
LIMIT 10 OFFSET 20
```
- OFFSET
OFFSETキーワードは、取得するデータの先頭行を指定するために使用します。LIMITキーワードと一緒に使用することが多いです。以下のように、取得する行数と先頭行の位置を指定することができます。

```
OFFSET 10
LIMIT 10 OFFSET 20
```
これらのキーワードを組み合わせることで、複雑なデータ分析が可能になります。以下に例を示します。

## 各キーワードの使用例

```
=QUERY(A1:C5, "SELECT A, AVG(B) WHERE C = '東京都' GROUP BY A ORDER BY AVG(B) DESC LIMIT 3")
```

この場合、A1からC5の範囲を検索し、都道府県が東京都の人の名前と年齢の平均値を求め、名前でグループ化して平均値の降順で並べ替えます。そして、平均値の上位3件を取得します。


QUERY関数では、日付を条件に入れることができます。以下に、日付を条件に入れた場合の例を示します。

```
=QUERY(A1:C5, "SELECT A, B WHERE C > date '2022-01-01'")
```
この場合、A1からC5の範囲を検索し、日付が2022年1月1日よりも後のデータを取得します。日付は、date '年-月-日'の形式で指定することができます。

また、以下のように、日付を範囲指定することもできます。

```
=QUERY(A1:C5, "SELECT A, B WHERE C >= date '2022-01-01' AND C <= date '2022-03-31'")
```

この場合、A1からC5の範囲を検索し、日付が2022年1月1日から3月31日までのデータを取得します。>=と<=を使って、範囲を指定することができます。

なお、日付には時刻情報も含めることができます。以下のように、日時を条件に指定することもできます。

```
=QUERY(A1:D5, "SELECT A, B WHERE C >= timestamp '2022-01-01 00:00:00' AND C <= timestamp '2022-01-01 23:59:59'")
```
この場合、A1からD5の範囲を検索し、日時が2022年1月1日のデータを取得します。timestamp '年-月-日 時:分:秒'の形式で指定することができます。

## 特定条件下で、特定列のみ抽出する例

例：2023年05月01日以降に生まれたユーザーだけを抽出し、nameだけを出力させる場合

```
=QUERY(A1:C, "SELECT B WHERE A > date '2023-05-01'")
```
この場合、A列には生年月日が入っており、B列にはユーザー名が入っていると仮定しています。
A1からCの範囲を検索し、A列が2023年05月01日以降のユーザーの名前をB列から取得します。SELECT句には、nameを指定するためにB列を指定しています。また、条件にはWHERE句を使用し、A列が指定した日付よりも後のデータのみを取得します。

なお、もしA列に生年月日だけでなく生年月日と時刻が入っている場合は、dateの代わりにdatetimeを使用して以下のように書き換える必要があります。

```
=QUERY(A1:C, "SELECT B WHERE A > datetime '2023-05-01 00:00:00'")
```
このように、条件を変更することで、特定の列のみを抽出することができます。
tensorflow-addonsのSpectralNormalizationでTypeError

# エラー全文はこんな感じ
```
TypeError: isinstance() arg 2 must be a type or tuple of types
```
私はSpectralNormalizationでのみ確認したが、どうやらWeightNormalizationなどの他の複数の関数でも発生する模様。
# 原因
tensorflow-addonsの依存ライブラリの1つに「typeguard」というものが存在する。もしもtypeguardがインストールされていない状態でtensorflow-addonsのインストールを行った場合は、pipが最新のtypeguardを同時にインストールしてくれる。
しかし、最近リリースされた「typeguard 3.0」系列はtensorflow-addonsと互換性がないので、pipがこれを取ってくるとエラーとなってしまう。
# 対処法
なので対処法は簡単で、typeguard2系列（たとえば2.13）をインストールする
より具体的には、`pip install typeguard==2.13`すればOK
ちなみに、2023年3月28日現在では、最新のtensorflow-addonsである0.19.0でも対策はされていない。よって現状ではtensorflow-addonsのバージョンを変更しても無意味（確認済み）
# 参考
https://github.com/tensorflow/addons/issues/2819
Android Studio でエラーが発生している部分に赤い波線が表示されなくなった場合の対処法

## 発生した事象
Android Studio でFlutter を書いていたが、ある時からエラー発生箇所のコードに赤い波線が出力されなくなった。

## 対処法
下記記事を参考にした
https://issuetracker.google.com/issues/244376727?pli=1

下記手順を実施してインデックスを再スキャンをし再構築する
File > Repair IDE > Rescan Project Indexes

これで事象が解消した
Simulinkモデルの複雑度を管理してメンテ性アップ

Simulinkでモデルの複雑度を計測することができることをご存じでしょうか。

# 複雑度とは
複雑度とは 名前の通り、対象のモデルがどのくらい複雑なのかを数字で表します。Simulinkでは循環的複雑度という指標が用いられます。イメージとしては処理の分岐数≒複雑度。複雑なモデルほど可読性が低く、モデルを修正する際にバグが混入しやすくなってしまいます。

　下図はMathWorks社が提唱している複雑度とバグ混入率の関係表です。
複雑度が75以上の場合、何か変更を加えるとほぼ確実にバグが入ってしまうことになります。バグの混入を防ぐために、複雑度30未満を意識してモデルを作成しましょう。

![image-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/8192dace-4667-0143-7d2f-f63deb8726a0.png)
(https://jp.mathworks.com/discovery/cyclomatic-complexity.html)

例として下図のようなSwitchブロックが2つの単純なモデルの複雑度は2になります。
![image-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/8ece4d73-f36f-088a-828f-7ef7ee7b3854.png)
下図のような3通りの出力パターンがあるMultiportSwitchの場合の複雑度は3になります。
![image-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/7f4d1c75-8c43-5602-9049-81434ef042b7.png)

# 複雑度の計測方法

R2019bの場合
複雑度を計測したい階層で右クリック→メトリクスダッシュボードをクリック
![image-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/8d78aca0-1cc5-ca60-a5a5-1dee5f95aaa7.png)


メトリクスダッシュボードウィンドウが開くので、すべてのメトリクスボタンをクリック。クリックすると解析が始まります。![image-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/46728147-e576-1064-d0ad-1a8ee903b3c0.png)


解析が完了するとモデルの複雑度解析結果が更新されます。![image-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/e5bded65-2c0f-766b-bfd3-6b84f4a58187.png)

解析が完了するとモデルの複雑度解析結果が更新されます。
![image-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2643741/068b05ce-873c-f8e8-e69c-568a7e34895e.png)

# 複雑度の低減方法
モデルの複雑を低減するには、適切な粒度でモデルをサブシステム化することが有効です。(1つのサブシステムに処理を書き込みすぎない)

# まとめ
このページでは複雑度の概要と計測方法、そして複雑度の低減方法を紹介しました。複雑なモデルはメンテナンス性が低くなってしまいます。メンテナンスしやすい(=ほかの人も見やすい)モデルを作るために意識的に複雑度の低いモデルを作成しましょう。
Google Identity Service のワンタッププロンプトによるアカウント認証

# Google Identity Service で(自動)サインインし、プロフィール情報を取得する

- ワンタッププロンプトを表示し、以前サインインしたアカウントがあれば自動的にそのアカウントでサインインする
- プロンプトが何らかの理由で閉じられた場合に手動でサインインできるよう、サインインボタンをレンダリングする
- プロフィール情報のデコードに jwdDecode モジュールを使用

## 実装(擬似コード)

```html
<html>
  <body>
    <div id="sign-in-button-container"></div>
  </body>
</html>
```

```js
import jwtDecode from 'jwt-decode';

// Google Identity Service のインターフェイスを取得する
let google = await new Promise(resolve => {
  let scriptElement = document.createElement('script');
  scriptElement.src = 'https://accounts.google.com/gsi/client';
  scriptElement.type = 'text/javascript';
  scriptElement.onload = () => { resolve(window.google) };
  document.head.appendChild(scriptElement);
});

// プロンプトが消えた際に表示するサインインボタンをレンダリングする
const renderSignInButton = () => {
  google.accounts.id.renderButton(
    document.getElementById('sign-in-button-container'),
    {
      theme: 'outline',
      size: 'large',
    },
  );
};

// 資格情報
let credentialResponse = await new Promise((resolve, reject) => {
  // 初期化
  google.accounts.id.initialize({
    client_id: 'YOUR_GOOGLE_CLIENT_ID', // XXX.apps.googleusercontent.com
    callback: resolve, // 初期化が完了したら呼ばれる
    auto_select: true, // 最後にサインインしたアカウントを自動選択
  });

  // cf. 自動選択を無効化する
  // google.accounts.id.disableAutoSelect();

  // サインイン用のワンタッププロンプトを表示する
  google.accounts.id.prompt(notification => {
    // 予期せぬ理由でサインイン処理が行われなかった場合の処理
    if (notification.isNotDisplayed()) {
      let notDisplayedReason = notification.getNotDisplayedReason();
      switch (notDisplayedReason) {
        case 'browser_not_supported':
        case 'opt_out_or_no_session':
        case 'suppressed_by_user':
          renderSignInButton();
          break;
        default:
          reject(new Error(notDisplayedReason));
          return;
      }
    } else if (notification.isSkippedMoment()) {
      let skippedReason = notification.getSkippedReason();
      switch (skippedReason) {
        default:
          renderSignInButton();
          break;
        case 'issuing_failed':
          reject(new Error(skippedReason));
          return;
      }
    }
  });
});

// jwtDecode モジュールで資格情報をデコード
let decodedCredential = jwtDecode(credentialResponse.credential);
// decodedCredential['sub']: ID
// decodedCredential['name']: フルネーム
// decodedCredential['picture']: プロフィール画像
```

### 参考
https://developers.google.com/identity/gsi/web/reference/js-reference?hl=ja
Scalaのcirceで出てくる Maximal number of successive inlines (32) exceeded というコンパイルエラー

コンパイル時に以下のようなエラーが出た。

```plain
Maximal number of successive inlines (32) exceeded,
Maybe this is caused by a recursive inline method?
You can use -Xmax-inlines to change the limit.
```

コンパイラオプションの `max-inlines` という値がデフォルトで32であり、これを超えてしまうということらしい。
コンパイル時に `-Xmax-inlines 64` のような大きい数字を指定すれば解決する。 `build.sbt` には以下のように書く。

```plain
scalacOptions ++= Seq("-Xmax-inlines", "64")
```
React onChangeイベント

# 成果物
https://codesandbox.io/embed/ming-qian-arenzi-x4954y?fontsize=14&hidenavigation=1&theme=dark

# プログラム概要
- [ ] App.js:メインの処理を記述するプログラム
- [ ] index.js:AppコンポーネントをDOMに変換し、HTMLにレンダリングする
- [ ] Styles.css:デザイン

# onChange
`onChange`イベントは、フォーム内のエレメント（要素）である、`input`、`select`、`textarea`の値がユーザーの操作によって変更された際に発生するイベントです。

# コード
## index.js
```javascript
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
```

## App.js
```javascript
// useStateをApp.jsで利用できるようインポートする
import React, { useState } from "react";
import "./styles.css";

// 他のファイルでも使用できるようAppコンポーネントをエクスポートする
export default function App() {

  // inputから入力された値（姓）の状態を管理する
  const [firstName, setFirstName] = useState("");

  // inputから入力された値（名）の状態を管理する
  const [lastName, setLastName] = useState("");

  // inputタグで入力された姓の値(value)を受け取り、setFirstName関数にセットする
  // 引数eに受け渡される値を確認するために　※1　を確認
  const firstNameChange = (e) => setFirstName(e.target.value);
  const lastNameChange = (e) => setLastName(e.target.value);

  // リセットボタンが押された場合、姓名に入力された内容をクリアする
  const resetName = () => {
    setFirstName("");
    setLastName("");
  };

  return (
    <>
      // 値が入力されるとfirstNameChange関数が実行される
      <input
        type="text"
        value={firstName}
        onChange={firstNameChange}
        placeholder="姓"
      />

      // 値が入力されるとlastNameChange関数が実行される
      <input
        type="text"
        value={lastName}
        onChange={lastNameChange}
        placeholder="名"
      />

      // useStateに保持されているfirstName, lastNameの値を表示する
      <p>
        私の名前は{firstName} {lastName} です
      </p>

      // ボタンが押されるとresetName関数が実行される
      <button onClick={resetName}>リセット</button>
    </>
  );
}
```
<br>

※1
```javascript
  // 省略
  const lastNameChange = (e) => setLastName(e.target.value);
  // 省略
  <input
      type="text"
      value={lastName}
      onChange={lastNameChange}
      placeholder="名"
  />
```

上記のinputからlastNameChange関数に渡された引数eの中身を確認すると以下のようになっている。
ここで、setLastNameには`e.target.value`が渡されているが、下記を確認すると`e.target.value`には`太郎`が渡されていることがわかる。
つまり`e.target.value`には`input`に入力された値(`value`)が入っていることが分かる
```console
SyntheticBaseEvent {_reactName: "onChange", _targetInst: null, type
: "change", nativeEvent: InputEvent, target: HTMLInputElement…}
_reactName: "onChange"
_targetInst: null
type: "change"
nativeEvent: InputEvent
target: 
<input type="text" placeholder="名" value="太郎"></input>
currentTarget: null
eventPhase: 3
bubbles: true
cancelable: false
timeStamp: 151516.59999999963
defaultPrevented: false
isTrusted: true
isDefaultPrevented: ƒ functionThatReturnsFalse() {}
isPropagationStopped: ƒ functionThatReturnsFalse() {}
preventDefault: ƒ preventDefault() {}
stopPropagation: ƒ stopPropagation() {}
persist: ƒ persist() {}
isPersistent: ƒ functionThatReturnsTrue() {}
<constructor>: "SyntheticBaseEvent"
```

## styles.css
```javascript
input {
  display: block;
}
```
memosをwindowsで再起動するとデータが全部消える問題

## 問題点
GitHubにある起動コマンドでは何故かWindowsドライブのマウントが上手くいってなかった。
(そのためPCを再起動するたびにメモのデータが全部消えていた)
```
docker docker run -d --name memos -p 5230:5230 -v ~/.memos/:/var/opt/memos neosmemo/memos:latest
```

## 解決
```docker
docker run -d --name memos -p 5230:5230 -v C:/Users/USER_NAME/.memos/:/var/opt/memos neosmemo/memos:latest
```
ホームディレクトリをチルダではなく絶対パスで指定すると上手くいった。

## 参考

https://github.com/usememos/memos?source=noted.lol
もっとワイの間違いを教えてくれ (Ruby3.2のerror_highlightを試す)

# はじめ

> ErrorHighlight
TypeErrorとArgumentErrorの引数を下線表示するようになりました

引用: https://www.ruby-lang.org/ja/news/2022/12/25/ruby-3-2-0-released/

Ruby 3.1から導入された errror_hightligt はエラー箇所を下線部で教えてくれるというものです。
そちらの紹介については以下で紹介しています

https://qiita.com/Satoooon/items/2412e9ba6de1f3afefb1


今回はそれがRuby 3.2でどう変わったか実際に動かしながら見ていこうと思います

「ワイの間違いをもっと教えてもらわないとな　（〇-〇ヽ）クイッ」 ← ハナから間違いしようとすな！

# 動かしてみる

今回から下線部表示で該当のエラーを表示してくれるようになったエラーは以下の２種類のようです
- TypeError
- ArgumentError

今回動作確認するRubyのバージョンは3.2.1です

## TypeError

```sample_2.rb
1 + '2'
```

型の違うそれぞれの値を加算した場合のエラーが以下の通りになりました

### 従来(Ruby3.1) のとき

```
$ ruby sample_2.rb 
sample_2.rb:1:in `+': String can't be coerced into Integer (TypeError)
        from sample_2.rb:1:in `<main>'
```

### Ruby3.2 のとき

```
$ ruby sample_2.rb
sample_2.rb:1:in `+': String can't be coerced into Integer (TypeError)

1 + '2'
    ^^^
        from sample_2.rb:1:in `<main>'
```

## ArgumentError

```sample_3.rb
10.to_s(2,2)
```

`to_s(args)` によって引数の進数に変換しつつstring型に変換するメソッドですが、引数を上記の通り過剰に入れて見た場合のエラー内容が以下の通りになりました

### 従来(Ruby3.1) のとき

```
$ ruby sample_3.rb
sample_3.rb:1:in `to_s': wrong number of arguments (given 2, expected 0..1) (ArgumentError)
        from sample_3.rb:1:in `<main>'
```

### Ruby3.2 のとき

```
$ ruby sample_3.rb
ruby sample_3.rb 
sample_3.rb:1:in `to_s': wrong number of arguments (given 2, expected 0..1) (ArgumentError)

10.to_s(2,2)
        ^^^
        from sample_3.rb:1:in `<main>'
```

# その他

ArgumentError もハイライト表示できるようになりましたが、全てが網羅できているようではなさそうでした。定義したメソッドなどに対してのArgumentErrorなどは既存のものと変わらない表示でした

```sample_4.rb
def hoge(n)
  puts n
end

hoge(5,2)
```

### 従来(Ruby3.1) のとき

```
$ ruby sample_4.rb
sample_4.rb:1:in `hoge': wrong number of arguments (given 2, expected 1) (ArgumentError)
        from sample_4.rb:5:in `<main>'
```

### Ruby3.2 のとき


```
$ ruby sample_4.rb
sample_4.rb:1:in `hoge': wrong number of arguments (given 2, expected 1) (ArgumentError)
        from sample_4.rb:5:in `<main>'
```

# 最後に

今回はRuby3.2によって新しく追加されたエラーのハイライト表示について紹介しました
今回の動作確認する上で使用したコードは以下で公開しておきます！

[1_error_highlight](https://github.com/saku888/ruby_3_2_sandbox/tree/main/1_error_highlight)
GitHub CopilotをAndroidStudioに導入してみた（感想）

GitHub CopilotをAndroidStudioに導入してみたのでメモ。

## 手順
AndroidStudioのプラグインからGitHub Copilotをインストール
IDEを再起動
GitHubアカウントが連携されてない場合、ダイアログが出るのでそこからログイン
デバイスを登録

## 使い方
コメントを書く
エンターキー押す
コードがサジェストされるのでOKならタブを押す

## 注意点
あまり良くない書き方になってる時がある
既に非推奨クラスを使っている時とかね

## 良い点
既にあるプロパティの内容も見て良い感じに使ってくれる
特にViewModelはプロパティを適切にセットすれば思った通りのコードをそこそこの精度で書いてくれるぽい

## 参考
https://tech.yappli.io/entry/make-apps-with-ai
「SnowProCore認定資格」 取得に向けた学習まとめ

# はじめに
先日、Snowflakeの認定資格である、SnowProCore認定資格の試験を受験し、無事合格しました。自分が利用した学習コンテンツとその概要について、記載をしています。

# 受験目的
Snowflakeを用いた分析基盤構築案件に携わることになり、Snowflakeの基本について、業務上でのキャッチアップと並行して、体系的な知識の習得を行いたいと思い、受験することに決めました。

# 前提
- データ関連サービスの業務経験としては、BigQueryを中心とした分析基盤の構築PJにて、1年半程度の開発リード業務経験あり。
- 体系的な学習という面では、「AWS 認定データアナリティクス 専門知識」や「GCP Professional Data Engineer」を取得。加えて関連書籍も数冊読んでおり、一般的な知識は習得済。

# 利用した学習コンテンツ
- Quick Start(公式講座)の受講
    - PJの関係で幸いなことに公式の講座を受講する機会をいただけました。
    - Snowflakeを構成する各オブジェクトについての概要からベストプラクティスまでカバーされており、加えて実際にハンズオン形式で操作するパートもあり、非常に勉強になりました。
- 公式ドキュメントの精読
    - 試験問題において、公式ドキュメントの細かい部分が取り上げられることが多いと聞いていたので、かなり読み込みました。そのうえで重要と思われる部分は別途メモに書き出して、頭に叩き込みました。
- 実操作
    - 無料枠を利用して、実際に操作もしてみました。実際に手を動かすことで、講座やドキュメントで得た知識を解像度高く理解したり、定着させたりできたと感じています。
    
# 受験を終えての感想
今回は最初に公式講座を受講できたので、大枠を事前につかんだうえで学習に取り組めて、比較的早く吸収できたかなと思います。公式ドキュメントをかなり読み込む必要がある試験だったので、ドキュメントのどこにどういった内容が書いているのかのインデックスが頭の中に作れた気がします。PJに直結する知識も多く得られたので、さっそく今後の設計・開発に活かしていきたいと思います。
eTaxのXMLをテキストエディタとブラウザのみでPDFに変換する方法 (Mac)

インボイス事業者の適格請求書発行事業者登録通知書でダウンロードされるxml。
このXMLをPDFに変換しようとしたのですが、そのままだと開けなかったり文字化けしたりとそれなりに手間だったので手順をメモします。

## 準備するもの
- 適格請求書発行事業者登録通知書のxmlファイル

## 使うツール
- テキストエディタ（メモ帳でも可）
- ブラウザ（ここではChrome）

# 手順の流れ
1. XMLファイルを複製してテキストエディタで開く
1. xml-stylesheet をブラウザで開いて保存
1. xml-stylesheet のパスを変更
1. XMLファイルをブラウザで開く
1. 印刷でPDFで保存

## XMLファイルを複製してテキストエディタで開く
念の為XMLを複製してからテキストエディタで開きます
（バックアップは必ず取っておくこと）

## xml-stylesheet をブラウザで開いて保存
開いたXML

```
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="https://uketsuke.e-tax.nta.go.jp/xsl/NSH1000-220.xsl"?>…
```
xml-stylesheet（XMLのレイアウトCSS）の参照先URLをブラウザで開く
難しい人は下記リンクからでもOK
https://uketsuke.e-tax.nta.go.jp/xsl/NSH1000-220.xsl

![Screen Shot 2023-03-28 at 6.16.25 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5923/9f5be356-9bcd-abfe-8bdd-5809c61b5a33.png)

ブラウザで保存(Cmd+S）で、XMLと同じフォルダに保存
何も指定しなければファイル名は `NSH1000-220.xsl` になるはず

## xml-stylesheet のパスを変更
xml-stylesheetのパスを、同じフォルダのファイルに `NSH1000-220.xsl` 書き換える

修正前
```
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="https://uketsuke.e-tax.nta.go.jp/xsl/NSH1000-220.xsl"?>…
```
↓
修正後
```
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="NSH1000-220.xsl"?>…
```

![Screen_Shot_2023-03-28_at_6_14_44_PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5923/d7114b55-ef19-844e-475b-7c1993c0a3b0.png)

この時点のファイル構成）
- 適格請求書発行事業者登録通知書.xml
- 適格請求書発行事業者登録通知書_copy.xml ←パス修正したファイル
- NSH1000-220.xsl


## XMLファイルをブラウザで開く
パスを変更して保存したXMLをブラウザで開く
うまく行けばレイアウトが反映された登録通知書が表示

![Screen_Shot_2023-03-28_at_8_58_03_PM-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5923/2ade088b-ab06-68c8-4f0d-41e367270528.png)
## 印刷でPDFで保存
あとは印刷を実行して、印刷画面からPDF保存を選択すればOK
（ヘッダー、フッターの情報は出力しないこと）

![Screen_Shot_2023-03-28_at_8_58_18_PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5923/51c3aa04-df2f-ec12-8d73-9d718f8c0fb8.png)

# さいごに
ブラウザでローカルファイルを読み込めないセキュリティポリシーが原因と思われる
ChatGPT×MarkMap: 簡単マインドマップ生成

# 概要

マインドマップはトニー・ブザンという人が提唱した、「頭の中を書き出す」ことに優れた図の書き方です。

中央にテーマを書き、枝分かれする形でサブテーマ、サブテーマのサブテーマを書いていきます。

![mindmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/5fef3889-2a3e-8c3c-106b-3dc19ed3f9f6.png)

そして[MarkMap](https://github.com/markmap/markmap)はマインドマップをマークダウン記法から生成してくれるライブラリです。

今回はその[VSCode拡張機能](https://marketplace.visualstudio.com/items?itemName=gera2ld.markmap-vscode)を使いました。

最後に[ChatGPT](https://chat.openai.com/chat)は皆さんご存知のAIとチャットできるWebサービスです。

今回はこれらを組み合わせて、いろんな物事のあらましを素早く掴める状態にしたいと思います。

# 必要なプロンプト

驚いたのですが、ChatGPTはすでにMarkMapの特徴を知っています。

```
はい、markmapというライブラリを知っています。markmapは、マークダウン形式のテキストをマインドマップに変換するJavaScriptライブラリです。このライブラリを使うと、マークダウンの見出しやリストを視覚的に表現でき、情報の構造化や整理が容易になります。

markmapは、主に以下の特徴があります：

マークダウン形式のテキストをマインドマップに変換
見出しタグ（例：#、##）による階層構造の生成
リスト（箇条書き）のサポート
一部のマークダウン記法（リンク、太字、斜体など）のサポート
インタラクティブな操作（ズームイン・アウト、ノードの折りたたみ・展開など）
SVG形式での出力が可能
このライブラリは、情報を整理したり、アイデアを視覚的に表現する際に非常に便利です。しかし、マークダウンの全ての記法をサポートしているわけではないため、利用時にはその点に注意が必要です。
```

なのでプロンプトは、`MarkMapに対応したマークダウン記法を使って、{IDEA}の情報を出力してみてください`といったものになります。

ChatGPT３.５と4で微妙に結果が異なりましたが、どちらにしても

![スクリーンショット 2023-03-28 20.34.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/39203a0e-de74-4087-9a97-dcd30384c364.png)

上記のようにコピーできる形で出してくれるはずです。

出してくれない場合は例を示してみましょう。

あるいは、`その情報をコピーして使いたいので、 ```markdown と ``` でくくってみてください`というプロンプトも効果的でした。

# VSCodeで確認

コピーできる形で出してくれたら、VSCodeで`.md`ファイルを作って確認してみます。

拡張機能が入っていたら、画面上部のメニューにプレビューボタンができているはずなので、それをクリックします。

![スクリーンショット 2023-03-28 20.44.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/e5ad850f-6586-715c-09e5-c21a75e497d6.png)

こんな感じで綺麗に出力されます(ところどころ文字が切れているのは日本語対応のせい？)。

# 応用可能性

## 知らない業界・分野の概要をつまみ食いしたいとき

使えますが、嘘が混じる可能性は捨てきれません。

例えば自分の場合、先ほどの「フロントエンドのスキルマップ」マインドマップはわりと良さそうと判断できましたが、

![スクリーンショット 2023-03-28 20.49.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/a46e7ba3-fbb1-a1b8-94f9-c67e499e2ff0.png)

DDD（ドメイン駆動設計）の場合、どの程度参考にして良いのか判断できませんでした。

## 知っている情報をまとめてほしいとき

![スクリーンショット 2023-03-28 20.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/1c20336d-829a-2399-7681-38562a23ac32.png)

これはビートルズの情報を出してもらったものです。

自分はある程度ビートルズを知っているので、このマップの正しさを判断できます。

それでいて「まとめろ」と言われたら大変だったと思うので、ChatGPTの便利さをある程度実感できます。


## 常識のリストがほしいとき

これがおすすめの使い方です。

常識のリストとは、言われてみると納得できるけれど常識的すぎて逆に例を挙げにくいリストです（自分の造語です）。

例えば、以下は髪型のリストです。

![スクリーンショット 2023-03-28 20.57.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92027/e6cddfe0-dfc0-c5ac-7e0c-5d0ea89fa251.png)

言われてみると髪型はこのように分かれると思います(ちょっと女性の髪型に寄り過ぎな気もしますが)。

このように、常識的な情報もあえてリストにしてみることで参考になったりします。

# まとめ

マインドマップは一見して構造が分かる優れた描画方法です。

ChatGPTとMarkMapを利用することで、これを手軽に作ることができます。
リーダブルコードの感想などまとめ

![picture_large978-4-87311-565-8.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238817/2dff293c-c5f3-fe90-2703-9cd4b838bd8f.jpeg)

## リーダブルコード とは？

リーダブルコードは、**Dustin Boswell、Trevor Foucher　著、角 征典　訳** の書籍です。

https://www.oreilly.co.jp/books/9784873115658/

エンジニアであれば、間違いなく読むべき書籍であるといえるでしょう。

今回は、そんなリーダブルコード（以下本書）を読み直しましたので、内容をまとめつつ感想をお伝えしたいと思います。

## 要点まとめ

- コードは理解しやすくなければならない
- コードは**他の人が最短時間で理解できるように**書かないといけない
- 変数名、関数名に意味を込める
  - 具体的かつ伝わりやすくする
- インデントを適切に配置する
- 最善の名前とは、**誤解されない**名前である
  - 意図が正しく伝わるようにする
- **プログラミングとは、ほとんどがコードを読む時間**である
- いいコメントよりも、いいメソッド名を目指す
- 「自分の考え」をコメントする
  - なぜこうしたのか、TODOなど
- 要約するコメントも良い
- 実例を示すコメントも良い
- for文などの制御フローは要注意
  - 自然な並びを心がける
  - `if (10 < length)` よりも、
  - `if (length > 10)` の方が読みやすい
- 行数を短くするよりも、**他の人が理解するのにかかる時間を短く**する
- 早期リターンでネストを浅く保つ
- 計算が長くなる場合は、途中結果を変数として保持すること
  - （ただし、通常は中間結果を保持するための変数は不要）
- 変数のスコープは小さくする
  - グローバル変数はNG
  - クラス変数も歓迎されない
- **変数は更新しない**こと
  - イミュータブルにする
- 処理は**積極的にメソッドに切り出す**こと
- **ひとつのコードはひとつの処理**のみ行うこと
- 複数のタスクを行っている場合は、**分割**すること
- **実装したい処理を、言葉にしてみる**こと
  - 言葉にすることで、理解しやすいコードになる
- **できるだけ短いコードにする**こと
  - 最も読みやすいコードは、何も書かれていないコードだ
- コードは小さく保つこと
  - 小さいコードは変更しやすい
- 未使用のコードを見つけたら削除すること
- **ライブラリに詳しくなる**こと
  - 既存ライブラリで解決できないか調べること
- 安心してテストを追加・変更できるよう、テストコードも読みやすくすること
- テストも小さい方がよい
  - 小さなテストを複数パターン作る
- 入力値は、最も単純な組み合わせをテストする
  - マイナスの値が欲しければ、「`-1`」を使う
  - `-99998.7`などという値は使わないこと
- テストを容易にするため、下記のような実装は避けること
  - グローバル変数を使っている
  - 外部コンポーネントに依存している
  - コードが非決定的な動きをする
- テストが容易なのは、以下のようなコードである
  - クラスが小さい
  - 内部状態を持たない
  - クラスや関数が1つのことをしている
  - 他のクラスに依存していない
  - インターフェースが明確である
- 下記書籍を読もう！
  - 『Code Complete』
  - 『リファクタリング』
  - 『プログラミング作法』
  - 『達人プログラマー』
  - 『Clean Code』
  - 『JavaScript: The Good Parts』
  - 『Effective Java』
  - 『オブジェクト指向における再利用のためのデザインパターン』
  - 『珠玉のプログラミング』
  - 『ハイパフォーマンスWebサイト』

## 感想

普段の開発にすぐさま活かせるノウハウが詰まっており、大変勉強になる書籍だと思いました！

読みやすいコードを書く大切さと、どうやって読みやすく書くかが学べました。

自分自身の書いたコードでも、数ヶ月後見直して愕然とすることってありますよね。

「この人、何を考えてこんな複雑な実装をしたんだ？」みたいな。

命名については、ChatGPTなどAIの得意分野だと思うので、どんどん活用していきたいです。

実装したい処理を言葉にしてみる、というのは去年実際に試してみて、「わかりやすい！」との評価をいただくことができました:pray:

勧められている書籍はまだ読んでいないものもあるので、今年中に読みたいと思います。

コードは書くよりも読む時間のほうが長い、という言葉にはいつもハッとさせられます。

（ドキュメントについても同様かもしれませんね）

これからも、本書の内容を踏まえて開発を行っていきます！

最後まで見ていただきありがとうございました。
Oracle Linuxで日本語入力を追加(GUI)

# 環境
* Oracle Linux Server 9.1

# 方法
設定 > keyboard > 入力ソース から "+"を押して「日本語」を選択する．

日本語の入力方法がいくつか表示されるので，「日本語(Anthy)」を選択する．

Windowsキー + Space で日本語入力ができるようになる．
React useStateを利用したいいねボタン

# 成果物

丸いアイコンをクリックすることで、アイコンの色とそれに対応した文字が出力されます

https://codesandbox.io/embed/iinebotan-arenzi-84k9lt?fontsize=14&hidenavigation=1&theme=dark

# プログラム概要
- [ ] App.js:メインの処理を記述するプログラム
- [ ] index.js:AppコンポーネントをDOMに変換し、HTMLにレンダリングする
- [ ] Styles.css:デザイン

# useState
`state`はコンポーネントが内部で保持する状態のことで、画面上に表示されるデータなどのアプリケーションが保持している値を指します。`state`が更新されると、`state`を管理するコンポーネントが再描画されることにより画面上のUIや挙動が変更する。

今回の場合、`state`の値が変化すると`state`を管理しているAppコンポーネントが再描画される

関数コンポーネントでは`state`の管理をフックである`useState()`を利用している

# レンダリング
Reactにおける`レンダリング`とは、現在の`props`と`state`をもとにコンポーネントがどのように画面上に表示されるか、変更前と変更後の仮想DOMを構築して変更差分を検出することで、実際にDOMに変更を加える必要があるかどうかを知るためのプロセス。
レンダリングは以下のタイミングで実行されます
- [ ] コンポーネントの初回レンダリング時
- [ ] コンポーネント内の状態（`state`）が変化したとき
- [ ] 親コンポーネントがレンダリングされたとき
- [ ] カスタムフックからコンポーネントが受け取っている変数が変化したとき

# コード解説

## index.js
```javascript
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

```

## App.js
```javascript
// useStateをApp.js内で使用できるようにする
import React, { useState } from "react";

// styles.cssを適用する
import "./styles.css";

// 「export default function App(){}」で他のファイルでApp.jsを使用できるようにする
export default function App() {

  // 関数コンポーネントの一番上で宣言する
  // likedは現在の「いいね」の状態、setLikedはlikedの状態を更新するための関数
  // 初期値は「false」
  const [liked, setLiked] = useState(false);

  // ボタンが押された際に実行する
  // likedの値がtrueの場合、falseに変更する
  // likedの値がfalseの場合、trueに変更する
  const toggleLiked = () => setLiked(!liked);

  return (
    // Reactは最上位の階層に複数の要素を記述することができないため、<></>で囲む
    <>
      // HTML内にJavaScriptのコードを埋め込むためには{}で囲む
      <button
        // likedがtrueの場合、ボタンを赤色にする
        // likedがfalseの場合、ボタンを青色にする
        className={liked ? "btn red" : "btn blue"}

        // ボタンが押された場合、toggleLiked関数を実行する
        onClick={toggleLiked}
      ></button>

        // likedがtrueの場合、「いいね済み」を表示する
        // likedがfalseの場合、「いいね前」を表示する
      　<p>{liked ? "いいね済み" : "いいね前"}</p>
    </>
  );
}
```

## styles.css
```css
.btn {
  padding: 10px;
  border-radius: 50%;
  border: none;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
```
TeraTermで背景色を接続先ごとに設定

TeraTerm配布サイトにアクセスして、zipファイル（teraterm-4.106.zipなど）をダウンロードする。

ダウンロードしたzipを解凍すると、中に TTXCommandLineOpt.dll があるのでこのファイルをTeraTermのインストール先にコピペする。

/BG=R,G,B で背景色を指定できる。
/RG=R,G,B で文字色を指定できる。
/SIZE=XxY or /SIZE=X,Y でウィンドウサイズを指定できる。

https://iww.hateblo.jp/entry/20201022/TTXCommandLineOpt

さらに、それを便利につかえるようにしたものに `TTXCommandLineOptKai` がある。
オリジナルは文字色背景が変わらないが、こちらにも対応したものである。

また、/BR=R のようにプリセットされた色を設定することも可能な模様。
[R]ed, [G]reen, [B]lue, [C]yan, [M]agenta, [Y]ellow, [B]lacK, [S]ilver

詳細は作者サイトを確認する。

https://github.com/hsur/TTXCommandLineOptKai
【脱JavaScript】Laravelだけで非同期通信してみた

# はじめに
Laravelのみで完結してるアプリってどうやってフロントとの非同期通信してるの・・・？
という疑問を抱いた私は、ググってみたり、ChatGPTに聞いてみたりしてLaravel単体で非同期通信を行う方法について調べました。

調べた結果いくつかの方法が見つかりましたが、最近触ったLivewireという機能についてご紹介したいと思います。

# Livewireとは何者？
Livewireとは、`PHPフレームワークであるLaravelに統合された、フルスタックフレームワーク`です。
簡単に説明すると、JavaScriptを実装せずに動的なコンポーネントを作成できるライブラリです。
Blade構文で使用できるため、Laravelと相性が良いです。

# 導入手順
### ①composerでインストール後、artisanコマンドを使用して必要なファイルを生成していきます。
```terminal:terminal
composer require livewire/livewire
```
### ②Livewireを使用する画面に、livewireのディレクティブを記載する。

```php:layout.blade.php
...
    @livewireStyles
</head>
<body>
    ...
 
    @livewireScripts
</body>
</html>
```
直感的に理解できそうですが、`@livewireStyles`はLivewireのスタイルが、`@livewireScripts`はLivewireのスクリプト処理が適応されるようになります。
### ③コンポーネントの作成
```terminal:terminal
php artisan make:livewire random
```
このコマンドの実行により、以下の２ファイルが生成されます。
**・app/Http/Livewire/Random.php**
**・resources/views/livewire/random.blade.php**

以上です！
実際にLivewireを使用して、非同期通信を行っていきます。
# ボタンを押すとランダムに数字が表示される機能を実装してみる
### 機能を実装する
ランダムに整数を生成する処理を実装します。
実装するファイルは、導入時に生成した**app/Http/Livewire/Random.php**です。
```php:Random.php
class Random extends Component
{
    public $randomNumber = 0;

    public function createRandomNumber()
    {
        $this->randomNumber = rand(0, 10);
    }

    public function render()
    {
        return view('livewire.random');
    }
}
```
### bladeに動的に変化するコンポーネントを実装する
```php:random.blade.php
<div style="text-align: center">
    <button wire:click="createRandomNumber">create</button>
    <h1>{{ $randomNumber }}</h1>
</div>
```
### 生成したLivewireコンポーネントを読み込む
```php:layout.blade.php
<head>
    ...
    @livewireStyles
</head>
<body>
    <livewire:random />

    ...

    @livewireScripts
</body>
</html>
```

これで完成です！
たったこれだけの処理を記載するだけで、非同期通信を行うことができます。

ロジック的には、裏側でAjaxが走っているみたいです。
通信速度の心配をしていましたが、意外と速度の変化は見られませんでした（Livewireの方が約40~60ms遅い）。
ただ、多少Livewireの方が遅い＋様々な設定等も難ありそうなので、大量のデータを扱う処理や複雑な処理が必要な場合は不適かと思います。
![スクリーンショット 2023-03-11 23.27.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693783/c0e9baa4-5c42-ace6-37f2-1e1992c5b683.png)
![スクリーンショット 2023-03-11 23.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693783/c03667a1-2c46-635d-1413-9e415108d920.png)

その他にも保守性やアーキテクチャ的側面から考えると、色々な問題は出てくると思いますが、1度触ってみるのはアリかと思います！
（脱してないけど）脱JavaScriptで非同期通信を行ってみたでした。

【公式サイト】
https://laravel-livewire.com/
DockerとかのUnix socketに一般ユーザがアクセスできない場合の恒久対策

# はじめに
例えばDockerなどのUNIX socketを利用するサービスで、Socketにroot以外の一般ユーザからアクセスしたい場合がある。
サービス起動後に手動で`chmod`したり、何らかのScriptなどを用いて権限変更を行ってもよいが、Ad-hocな方法な上、少々面倒くさい。
# 対応方法
最近のLinuxには、`tmpfiles.d`という機構が備わっており、システム起動時にファイルやディレクトリの作成や権限変更を行ってくれたり、定期的に対象ディレクトリ内のファイルをファイルを削除してくれたりする。これを用いて、UNIX Socketファイルの権限付与を管理すると良い。
## UNIX Socketの権限変更の設定例
以下に、例としてDockerのSocketファイルをtmpfiles.dで管理する例を示す。
```/etc/tmpfiles.d/socket.conf
f	/var/run/docker.sock	0766	-	-	-	-
```
まず、最初の`f`フラグがファイルの作成を示す。なお、フラグを大文字の`F`に指定すると、該当ファイルの内容をクリアし、空ファイルを該当PATHに配置する。
2カラム目に記載されたファイルが存在しなければ空ファイルを作成し、3カラム目の権限を付与する。
3カラム目で、該当PATHの権限を指定する。
4カラム目はUID(ユーザ名), 5カラム目はGID(グループ名), 6カラム目は寿命(Age), 7カラム目にはArgumentが入る。

`tmpfils.d`の詳細な使用方法については以下が詳しい。

https://www.unix.com/man-page/centos/5/tmpfiles.d/

UNIX Socketファイルは、通常はサービス起動時のみ作成され、サービスを停止すると削除されてしまう。
なので、今回は`tmpfils.d`によってシステム起動時に予めUNIX SocketのPathに必要な権限を付与した空ファイルを作成しておき、該当サービス起動時にその空ファイルにOverrideする(つまり権限を引き継ぐ)形でSocketが作成されるようにした。なお、該当サービス終了時にはUNIX Socketの機能は失われ、ただの空ファイルに戻る。
# おわりに
UNIX Socketの権限周りは、該当サービスの設定ファイル内で設定できるものも多いが、そうではない場合に再起動時に権限が失われるなどでハマることも多い。
誰かのお役に立てれば幸いです。

参考:
https://www.mk-mode.com/blog/2015/12/08/linux-dir-file-automatic-creation-on-boot/
Reactで、stateを更新したのに再レンダリングされないとき

## 以下のことを言いたいわけではない。

- useStateの更新関数を実行した直後に、stateの値が更新されてない
    - 更新されるのはコンポーネントが再レンダリングされた後なのは知っている
    - 問題にしたいのは、DOMに反映されない（=再レンダリングされない）こと
- 更新関数に渡したオブジェクトがstateと同じため、stateの更新を検知でない
    - 今回発生したのは、文字列型や数値型のstateを更新した時

## どうのようなコードで発生したか

以下のコードは、ボタンを押すと、stateが更新され、それをDOM上に反映するコンポーネントだ。
実際には、もっと複雑なコードであるのだが、ともかく文字列や数値のstateを更新しているのに、
再レンダリングが行われない、すなわち`Count: {count}`が更新されない、という現象に遭遇した。


```jsx
import { useState } from 'react';

const Counter = () => {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
    // ここでcountの値が更新されないのは当然
    console.log(count);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
};

export default Counter;
```

ボタンをクリックしても表示がかわらず、何秒待っても反映されないのだが、
おかしなことに、マウスを動かしてボタンからフォーカスを外すとコンポーネントが再レンダリングされた。
何を言っているのかわからねえと思うが、俺も（ry

## 解消方法
**タブを閉じて新しいタブで開き直す。**

Chromeで閲覧して発生していた現象だったのだが、Firefoxで確認したところ問題なく動く（ボタンクリック後に即時に再レンダリングされる）ことに気づき、
Chromeのタブを閉じて新しいタブで当該ページを開き直したところ解消した。

雑な解釈だが、タブを開きすぎていたりしたせいで、ブラウザの挙動が重くなっていたということなのだろう。
Reactの再レンダリングは非同期である。普通はstate更新すると即座（に思えるくらいには速く）再レンダリングが実行される。
だが、ブラウザの状況が劣悪だと、stateが更新された後もずっと再レンダリングを実行しないということがありうるようだ。
（そしてボタンのフォーカスをはずすとか、ひょんな拍子で再レンダリングしたりする）

このような現象は検索しても全然出てこない。
もしかしたら、同じ問題に躓くひともいるだろうと思い、ここに書き残しておく。
PostgreSQLでNaNを扱う

# PostgreSQLでNaNを扱う
## 定数値としてのNaN
'NaN'::NUMERICという値が使えます。

```
postgres=# select 'NaN'::NUMERIC;
 numeric
---------
     NaN
(1 row)

postgres=#
```

## NaNを判定する
'NaN'::NUMERICと比較すればよいですね。

```
postgres=# create table hoge (num1 numeric);
CREATE TABLE
postgres=# insert into hoge values('NaN'::NUMERIC);
INSERT 0 1
postgres=# select * from hoge;
 num1
------
  NaN
(1 row)

postgres=# select * from hoge where num1 = 'NaN'::NUMERIC;
 num1
------
  NaN
(1 row)

postgres=#
```

## ::NUMERICなくても
いけますね

```
postgres=# insert into hoge values('NaN');
INSERT 0 1
postgres=# select * from hoge;
 num1
------
  NaN
  NaN
(2 rows)

postgres=# select * from hoge where num1 = 'NaN';
 num1
------
  NaN
  NaN
(2 rows)

postgres=#
```

# 参考
https://stackoverflow.com/questions/25858859/how-to-check-if-number-is-nan

https://www.postgresql.jp/document/9.2/html/datatype-numeric.html

マニュアルにも記載があった。
'Infinity'とか、'-Intinity'も使えますね。
初心者がruby silverの勉強初期に知っておくと暗記が楽になる内容と、受験体験記

無事ruby silverに合格したので、体験記などをまとめます。
ruby silverの合格体験記は他にも数多くの記事があるので、
ここでは、
①勉強の初期に気づけたら暗記が楽だったな。という内容と、
②受ける上での自分なりの戦略や、途中のモチベーションの変化などについて書いていきたいと思います。

テストの点数は８４点でした。
# 自己紹介など
自己紹介などです。
* 2023年2月から未経験からIT企業に転職しました。
* 年齢は33歳です。
* 前職では建築関係の仕事をしていました。
# 勉強の初期に気づけたら暗記が楽だったな。という内容。
初学者だからこそ、メソッドの読み方がわからず、暗記がしにくい内容がありました。
少し恥ずかしいですが、勘違いなどをしていたものを羅列します。
## File.chmod
ファイルチョモッドではありません。
チェンジモードです。
チェンジモードと読めれば、ファイルのモードをチェンジするんだなと、意味を暗記しやすいです。
また、一つ気づければ同じような考えで、下記に示すような他のメソッドの読み方を理解できる気がします。
## Dir．pwd
ピーダブリューディーと読んではいけません。
プリントワーキングディレクトリ、若しくは、プレゼントワーキングディレクトリです。
## Dir.rmdir
ルムディアーではありません。
リムーブディレクトリです。
## File.chown
チョウンじゃありません。
~~チェンジオウンです。~~
チェンジオーナーです。
## 0d, 0x, 0o, 0b
10進数:Decimal, 16進数:Hexadecimal, 8進数:Octal, 2進数:Binary
それぞれの英語読みの頭文字をつけています。
## Hash({})
ハッシュを作るときは、{}で作ることができますね。
それをただ()で囲っているだけです。
## 未だによくわからないもの。
解決しました!
grep
https://ja.wikipedia.org/wiki/Grep
> grep の名の由来は、ラインエディタedのコマンド g/re/p である。その意味するところは「global regular expression print(ファイル全体から/正規表現に一致する行を/表示する)」で略号になっている。

sub→substitute
gsub→global substitute
※subとgsubは引用元がないため、予想です。
## その他余談
NGはNo Goodの略みたいです。
OKは諸説あるみたいです。ググると出てきます。
# 勉強時間
2月の半ばから勉強を開始したので、一月半ぐらいの勉強期間でした。
勉強時間としては、50時間ぐらいだと思います。
結構時間がかかりました。
# 戦略
最初にざっくりと戦略を立てました。
* 勉強期間は1ヶ月程度としたい。
* 過去問はRex,Ruby教本,githubの問題があるので、Rexで安定的に合格点が取れるようになってから、Ruby教本,githubの問題を解く方針とする。
* 一度問題を解くと、なんとなく問題を覚えてしまって、テスト前に実力を図るための問題がなくなってしまうかなと思い、この方針としました。
# 点数の推移とモチベーションの変化など
## Rex一周目(1日~4日)
全然わからないので、問題を解くのにも、回答を確認するのにも時間がかかる。
4日程度かけて、Rex一周目が終了。
点数は50点。
## Rex2~6周目(5日~14日)
点数の推移は58点、66点、78点、82点、86点
2周目以降は1周に掛かる時間がだんだんと早くなり、6周目ぐらいには、1日に1周(1時間)ぐらいできるようになりました。
## Ruby教本1回目(15日~20日)
もうそろそろ受かるかなと思い、Ruby教本の模擬試験に挑戦しました。
結果は55点。
模擬試験の内容はRexの問題でみたことがないものが多く、点数がガクッと下がりました。
もうそろそろ受かるかもと思っていたので、かなり落ち込みやる気が低下しました。
## github　Ruby2．1の模擬試験1回目(21日~25日)
こちらも、点数は60点ぐらい。
見たことがない問題が出ると、点数が落ちることがわかりました。
## 再度Rexを実施(26日~35日)
教本等の問題も理解できたので、再度Rexに取り組みました。
点数は74点、80点、92点、90点。
## github　Ruby3.1の模擬試験1回目と最後の仕上げ(36日~42日)
70点。
また点数が下がって、がっくり。
このころ会社の先輩と雑談をしていて、「教本やgithubの問題は、他の模擬試験とかぶらない問題が多いのでは」というような会話をして、
「実際のテストでは、300問とか固定の問題から、ランダムに問題を出すはずだろうから、そこまで見たことのない問題が出る確率も高くなく、もうそろそろ合格できるのでは?」
みたいな会話をしたので、とりあえず勇気をだして1週間後のテストを予約しました。
# 実際のテスト
実際のテストでは、50門中、37問が100%正解と確信して回答。
13問が50%程度正解だろうというような感じでした。
13問のうち、1問でも正解できれば合格できるだろうと考えて、試験を終了したところ、84点で合格でした。
ClosedXML-セルの値を読み込む バージョン 0.95

ClosedXMLでのExcelファイル内のセルの値を読み込む方法について、
実施した内容を記載したいと思います。

・環境
ClosedXML :バージョン 0.95

# 目次
　[文字列読み込み](#文字列読み込み)
　[int型読み込み](#int型読み込み)
　[まとめ](#まとめ)


#### 文字列読み込み
string型に関しては、IXLCellクラスの中にstring型で読み取るメソッドがあるため、
読み取りたいセルを選択してそのままメソッドを実行しました。
```cs:C#
//シートの選択　今回はシート名"Sheet1"で検索
IXLWorksheet workSheet = workbook.Worksheets.Where(x => x.Name.Contains("Sheet1")).FirstOrDefault();
//セルの選択 今回は[A1]のセルを選択
IXLCell cell = workSheet.Cell(1, 1);
//セルの値を文字列で読み込む
string readString = cell.GetString();
```

#### int型読み込み
バージョン 0.95.0のClosedXMLではセルの値を読み込むメソッドに
int型専用のものがなかったためdouble型を読み込むメソッドからint型にキャスト
をすることで値を読み取りました。

```cs:C#
//セルの値を文字列で読み込む
int readInt = (int)cell.GetDouble();
```

#### 番外
バージョン0.100以後ではクラスIXLCellにあるプロパティValueから
とれる値の型がObject型でなく、XLCellValue型で厳格に型指定されているみたいです。
今後バージョンアップとなる場合は、新しいメソッドを使う必要があることに注意しておきたいと思います。

https://closedxml.readthedocs.io/en/latest/migrations/migrate-to-0.100.html
【GitHub Actions】ログ内容をAnnotationsに表示する

# はじめに
GitHub Actionsで実行したチェック(自動テスト・静的解析ツール等)が失敗した時、
Jobの実行ログを確認するのは地味に手間がかかります。
このときActionsのSummaryにあるAnnotationsに、
「Jobが失敗した」という通知に加えてエラー内容も表示されていると、
なぜ失敗したかをより簡単に把握できるようになります。
この記事ではProblem Matchersを使ってエラー内容を確認しやすくする方法についてまとめました。
![スクリーンショット 2023-03-28 14.45.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/ec1247f2-34fa-ecbb-1cbb-55302cc9d755.png)

# Problem Matchersとは
Problem MatchersはGitHub Actionsに備わったツールの1つです。
指定した正規表現をもとにJobのログ出力をスキャンし、
マッチした部分をAnnotationsに表示してくれます。

# Problem Matchersの使い方
ここでは例として以下のように出力されたログをAnnotationsに表示していきます。

```text
Failure:
BooksControllerTest#test_AAAの場合_XXXになる [/home/runner/work/sample-app/sample-app/test/controllers/books_controller_test.rb:7]:
Expected false to be truthy.
```

## Matcherの作成
`.github`ディレクトリにjsonファイルを作成してMatcherを定義します。
```json:problem-matcher.json
{
  "problemMatcher": [
    {
      "owner": "test-failure",
      "pattern": [
        {
          "regexp": "^Failure:$"
        },
        {
          "regexp": "^.*?#test_.*?\\s\\[/home/runner/work/sample-app/sample-app/(.*?\\.rb):(\\d+)\\]:$",
          "file": 1,
          "line": 2
        },
        {
          "regexp": "^(.*)$",
          "message": 1
        }
      ]
    }
  ]
}
```

マッチさせたいログについて、行ごとに正規表現パターンを指定します。
`file` `line` `message`といったプロパティでは、
正規表現中で`()`で括った部分のうち
何番目がファイル名・行番号・メッセージにあたるのかを指定しています。
同様に設定できるプロパティは他にも`code`(エラーコード)等いくつか存在します([参考](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md))。

## Matcherの有効化
jsonで定義したMatcherを、対象のチェックを実行する前の段階で有効化しておきます。
```yaml
- name: Enable Problem Matcher
  run: |
    echo "::add-matcher::.github/problem-matcher.json"
```
これにより直後に実行されるチェックのログ出力のうち、
マッチした部分がAnnotationsに表示されるようになります。
![スクリーンショット 2023-03-28 14.44.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/5bd489be-72d9-3ff7-e78d-0f38cb34c44d.png)
また、生成されたAnnotationはプルリクエストのファイル差分にも表示されます。
![スクリーンショット 2023-03-28 14.42.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777885/9a9627be-ffd3-4727-f6f1-a1053fb3024b.png)

# 参考
[toolkit/problem-matchers.md at main · actions/toolkit](https://github.com/actions/toolkit/blob/main/docs/problem-matchers.md)
[toolkit/commands.md at main · actions/toolkit](https://github.com/actions/toolkit/blob/main/docs/commands.md#problem-matchers)