OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Organizationsでメンバーアカウントのルートメールアドレスを変更できるようなりました

## 概要
AWS Organizationsで、配下のメンバーアカウントのルートメールアドレスを一元管理できるようになった旨のリリースがありました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/06/manage-member-account-root-email-addresses-aws-organization/

▼寝起きにこのリリースを読んだときの私の反応

https://x.com/hedgehog051/status/1799224884750581971

Organizationsの管理アカウント側で勝手にメンバーアカウントのルートメールアドレス変えられちゃっていいのか？本当にできちゃうのか気になって、2度寝出来なくなったので試してみてブログ書いてます。
Bedrockネタじゃなくてすまんの

## 前提条件
- 管理アカウント側で、信頼できるサービスアクセス「AWS Account Management」有効にする

## 注意点
- 管理アカウント側でルートメールアドレスを変更しても、パスワードやMFA構成は以前のまま
    - 新メールアドレスでログインを施行して「パスワードのリセット」でパスワードは変更可能

## やってみた
一般のご家庭なら大抵ある個人アカウントOrganizationsで試してみました。

### メンバーアカウントを用意
メールアドレス: `xxxxxxx+v2@gmail.com`を設定したメンバーアカウントを用意しました。

※この段階(信頼できるサービスアクセス「AWS Account Management」が無効)では、メンバーアカウント詳細画面を開いてもメールアドレスの変更はできません。

![スクリーンショット_2024-06-08_9_50_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/1ce4c48e-796d-a20c-beb7-fcae23a94f44.png)

### 信頼できるサービスアクセス「AWS Account Management」有効化
AWS Organizationsコンソールから「サービス」画面を開いて「AWS Account Management」をクリックします。

![スクリーンショット 2024-06-08 9.55.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/2ea9b4d4-6bda-6920-d208-c01cfb822c57.png)

「AWS Account Management」画面に移動するので「信頼されたアクセスを有効にする」ボタンをクリックします。
![スクリーンショット 2024-06-08 9.56.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/57d00b59-7ada-9106-31a5-c33c36ddaed7.png)

確認ウィザードが表示されるので「有効化」と入力して「信頼されたアクセスを有効にする」ボタンをクリックします。
![スクリーンショット 2024-06-08 9.57.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/cf71cabf-840d-3d06-5ac1-4a788dd6af67.png)

「AWS Account Management に対する信頼されたアクセスを正常に有効にしました。」と表示されたら有効化完了です。
![スクリーンショット 2024-06-08 9.58.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/92769c7f-7fc9-ab3e-1671-30f6e7102afe.png)

### メンバーアカウントのルートメールアドレスを変更
メンバーアカウントの詳細画面に移動すると、先程はなかった「アクション」が表示されていることが確認できます。

「アクション」から「Eメールアドレスを更新」をクリックします。
![スクリーンショット_2024-06-08_9_18_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/a8fc20d9-0b41-2710-9340-9f1c3ffbfd09.png)

「Eメール」セクションでメールアドレスを入力して「保存」をクリックします。
今回はエイリアスを`v2`から`v3`に変更してみました。

![スクリーンショット_2024-06-08_9_20_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/530c9f5f-2bbd-7f97-2ef4-1b93e59186f9.png)

### 検証メール受信
変更した新メールアドレス宛てに検証メールが届くので認証コードをコピーする。
※認証コードは24時間で切れます。

![スクリーンショット_2024-06-08_9_20_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/d1213e4e-a613-9641-cc85-ffdceed3f51b.png)

### 認証コード入力
認証コードを入力して「確認」ボタンをクリックします。

![スクリーンショット_2024-06-08_9_26_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/7266292c-3575-3e83-9f46-c1600e603660.png)

### 変更確認
画面に「ルートユーザーのEメールアドレスが正常に更新されました」と表示されれば、完了です。

![スクリーンショット_2024-06-08_9_29_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/2031d5f0-1a4b-74ce-61cd-4e612bc6fc28.png)

簡単にできちゃったなあ。。

つまり、今回の機能追加によって**管理アカウント側でメンバーアカウントのメールアドレスと、パスワードのリセットによるパスワード変更まで可能**となったということになりますね。

## 結論
MFA、兎に角MFAを設定しましょう。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_mfa.html
コードリーディングの負担を軽くする方法

## やること

- 読んだ箇所に目印をつけます

## 準備

- 以下をインストールします
    - [Visual Studio Code](https://azure.microsoft.com/ja-jp/products/visual-studio-code)
    - [Visual Studio Codeの拡張機能「Bookmarks」](https://marketplace.visualstudio.com/items?itemName=alefragnani.Bookmarks)

## プログラムの例
- 以下を例にします

![スクリーンショット 2024-06-08 9.48.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/93434bd1-d665-ba85-bba6-278a5d75335d.png)

![スクリーンショット 2024-06-08 9.49.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/978967a8-e526-3506-27ef-9ac56788b029.png)

![スクリーンショット 2024-06-08 9.49.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/c1574136-1515-c00f-6d5e-155e49647412.png)

## やり方
- ここから先は読むのが大変そうだなと思ったら、数字をコメントします
![スクリーンショット 2024-06-08 10.00.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/6a221c16-50c5-981f-e310-35b0536375b6.png)

- 数字を付けたら、ブックマークも付けます
![スクリーンショット 2024-06-08 10.01.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/d58e3685-8cee-6d3f-2d1b-e5dbb1896e8b.png)

- 常に最大の番号より先の箇所を読みます
![スクリーンショット 2024-06-08 10.03.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/75460fef-dfee-178d-f48e-21b749c82580.png)

- 最大の番号より先を読み終えたら、最大の番号を消します
![スクリーンショット 2024-06-08 10.05.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/ced7f2f1-2dd3-5cb4-fcc1-6b2aebbe13b0.png)

- 1つ前の番号に戻ります
![スクリーンショット 2024-06-08 10.07.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/e26036eb-6562-e169-b2e4-ea951ccaac2d.png)

- もう`func3();`は読み終えたので、番号1も消します
![スクリーンショット 2024-06-08 10.10.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690075/7c3ef2e6-3b74-4d12-fe6d-d63ec9ce4133.png)

- これをすべてのコードを探索しきるまで続けます
- 今回は簡単かつ浅いコードを例にしました
    - しかし、これが複雑かつ深いコードになると、目印が役に立ちます

## メリット
- 気軽にサイドバーで番号を見れるので、コードのマップができます
	- マップができると、現在地を楽に意識できるので、頭の負担が減ります
	- マップができると、いつでも辿ってきた**順に**道を戻れます
		- **順に**が大事だと思います
		- 普通にコードを読んでも、最初の位置には戻れます
			- しかし「どうやってこの場所までたどり着いたんだっけ？」がわからなくなります
- 常に「最大番号より先（目印が無くても覚えられる範囲）」しかコードを読まないので、頭の負担が減ります

## デメリット
- 慣れるまで、少し時間がかかります
- マウスを使うと、サイドバーやブックマーク操作がめんどくさいです
	- 以下をおすすめします
		- サイドバークリック : [Homerow](https://www.homerow.app/)を使う
		- ブックマーク操作 : Bookmarksのショートカットキーを使う
- 数字をコメントした後、ブックマーク設置を忘れることがあります

## その他
- 番号設置のタイミングが**定性的**なのがミソだと思っています
	- その人の覚えられる（＝覚えやすい）範囲で区切り地点ができるからです
	- つまり、その人に最適な記憶ポイントが設置できます

## まとめ
- ルールは以下だけです
	- ここから先は読むのが大変そうだなと思ったら、数字とブックマークを残す
	- 常に最大番号より先だけを読む
Javaで「continue文の使い方」の動作を確認してみた

# 概要

Javaで「continue文の使い方」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/start/for/index10.html

# 実装

以下のファイルを作成しました。
```JSample10_1.java
class JSample10_1{
  public static void main(String[] args){
    for (int i = 1; i < 10; i++){
      if (i % 3 == 0){
        continue;
      }

      System.out.println("i = " + i);
    }

    System.out.println("End");
  }
}
```

```JSample10_2.java
class JSample10_2{
  public static void main(String[] args){

    Outer:
    for (int i = 1; i < 6; i++){

      Inner:
      for (int j = 1; j < 6; j++){
        if (i * j % 4 == 0){
          continue Outer;
        }

        System.out.println(i + " * " + j + " = " + i * j);
      }

      System.out.println("Next");
    }

    System.out.println("End");
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample10_1.java 
$ java JSample10_1 
i = 1
i = 2
i = 4
i = 5
i = 7
i = 8
End
```

```
$ javac JSample10_2.java 
$ java JSample10_2 
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
End
```

# まとめ

何かの役に立てばと。
Tidyverseのgt packageで特定文字列に色をつける。

## 目的

Tidyverseのgt packageで下記のように各列の特定文字列に色をつけること。
左の表を右の表にように変更する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285482/4296a8da-728e-e24e-91ce-2b6b89df3b3a.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285482/49d20ccf-b047-ad27-470a-b9d548176eba.png)

## 左の表の作成方法

```r

library(tidyverse)
library(gt)

AA <- c("aaa","ab","ac")
BB <- c("ba","bbb","bc")
CC <- c("ca","cb","ccc")

data <- tibble(AA,BB,CC)

data |> gt() 

```

## 右の表の作成方法

%in%を使用しても、カラムがたくさんあるとほぼ同じ内容を繰り返す必要があるので、もっと簡単にしたい。

```r

marks <- c("aaa","bbb","ccc")

data |>
  gt() |> 
  gt::tab_style(style = cell_text(color = "red", weight = "bold"),
                locations = list(
                  gt::cells_body(columns = AA,
                                 rows = AA %in% marks ),
                  gt::cells_body(columns = BB,
                                 rows = BB %in% marks ),
                  gt::cells_body(columns = CC,
                                 rows = CC %in% marks )
                  )
  )

```


## 自作関数を使った右の表の作成方法

自作関数を使わないで行う方法が見つけられなかったので、自作関数を使用したが、tidyevalの解決に時間がかかった。!!symを勉強しました。

```r

list_of_location <- function(columns, marks){
 
  location = list()
  
  for (i in 1:length(columns)) {
        location[[i]] <- gt::cells_body(columns = !!rlang::sym(columns[i]),
                                        rows = !!rlang::sym(columns[i]) %in% !!marks)
  }
  
  return(location)
}

columns_labels <- c("AA","BB","CC")
marks <- c("aaa","bbb","ccc")

data |> gt() |> 
  gt::tab_style(style = cell_text(color = "red", weight = "bold"),
                locations = list_of_location(columns_labels, marks))

```

## 参考
https://excel2rlang.com/rlang-tidyeval-abstract/
https://excel2rlang.com/rlang-tidyeval-usecases/

## sessionInfo()

```r
R version 4.4.0 (2024-04-24 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22000)

Matrix products: default


locale:
[1] LC_COLLATE=Japanese_Japan.utf8  LC_CTYPE=Japanese_Japan.utf8    LC_MONETARY=Japanese_Japan.utf8 LC_NUMERIC=C                    LC_TIME=Japanese_Japan.utf8    

time zone: Asia/Tokyo
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] rlang_1.1.4     gt_0.10.1       lubridate_1.9.3 forcats_1.0.0   stringr_1.5.1   dplyr_1.1.4     purrr_1.0.2     readr_2.1.5     tidyr_1.3.1     tibble_3.2.1    ggplot2_3.5.1  
[12] tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] gtable_0.3.5      compiler_4.4.0    tidyselect_1.2.1  xml2_1.3.6        scales_1.3.0      fastmap_1.2.0     R6_2.5.1          generics_0.1.3    munsell_0.5.1    
[10] pillar_1.9.0      tzdb_0.4.0        utf8_1.2.4        stringi_1.8.4     sass_0.4.9        timechange_0.3.0  cli_3.6.2         withr_3.0.0       magrittr_2.0.3   
[19] digest_0.6.35     grid_4.4.0        rstudioapi_0.16.0 hms_1.1.3         lifecycle_1.0.4   vctrs_0.6.5       glue_1.7.0        fansi_1.0.6       colorspace_2.1-0 
[28] tools_4.4.0       pkgconfig_2.0.3   htmltools_0.5.8.1

```

以上
八百屋システムを考える（DX内製化の手順３）

# VBAで実装するための仕組み
VBAを使ってDXを内製化する場合、必要になってくる機能として
１．データベースを読み書きする機能
２．表にデータを転記する機能
３．データを編集する機能

これだけの機能を再利用可能な形でフレームワーク化すると、数点の注意点を覚えるだけで誰でもプログラムが作れるようになります。

# 1.データベースを読み書きする機能
データベースを読み書きする機能は、ExcelシートにSQLと呼ばれるデータ操作命令を使って読み込みだけを行います。

書き込みは３のデータ編集機能を呼び出した後、変更のあったもののみを書き込みますが書き込みに関しては難しい面があるのでフレームワーク内で処理する事で、内製化が簡単に行えます。

読み出すSQLは
select よみ出すデータ要素の羅列 from 読み出すデータの塊
という形になるようにまとめておけば内製化時、楽にデータが扱えるようになります。

# 2.表にデータを転記する機能
Excelの特徴は、表に計算式を入れることで様々な帳票を楽に作れる点にあります。
なので１の機能で読み出したデータを表に転記する機能があると手間なく帳票を作ることができます。

ここで転記機能を実現するためには帳票に表示するデータの件数によりページングが必要になります。
この制御もかなり複雑な処理になるため、フレームワーク内で処理する事で内製化が簡単に行えるようになります。

# 3.データ編集機能
データ編集機能では、Excelのユーザーフォームという機能を使うことでダイアログを使ったデータ編集が可能になります。

データ編集を行う場合、編集する項目が多いとダイアログにその詳細をまとめて現在編集しているデータが全体の何処にあるかを示す簡単な表と連動することでデータ編集の全体像を掴むことができます。

ユーザーフォームも一から作り上げると結構大変なのですがここもフレームワーク化することで簡単に内製化が可能です。

# フレームワークの実装版
以下のリンクからフレームワークを公開いたします。

　　　　　[フレームワークのダウンロードはこちら](https://embed-ai.com/kawa/progs/ExcelBase2021.zip)

フレームワークの使い方はYoutubeの再生リストにある動画をご覧ください。
https://www.youtube.com/playlist?list=PL5FKFa9bpZNH-_1G4s5p0BZaZuAQT6hqN

このフレームワークに関するお問い合わせは、m_kawase@embed-ai.comまでお願いいたします。
自己評価を他人に委ねないようにすること

## はじめに
最近、気負ってしまい、物事を進めることを考え過ぎて、周りがついてくることを疎かにしてしまい、失敗した事があったので、「周囲の期待に応えようと無理をしてしまう時に考えて欲しいこと」を整理しました。まずは、自己評価を他人に委ねないためのチェックリストに該当する項目がないか、確認してみて下さい。__該当するものがいくつかあるならば、気負ってしまい、承認欲求の呪縛に囚われているかも知れません。__

## 自己評価を他人に委ねないためのチェックリスト

- [ ] 仲間にも厳しくしがちである __(それは、あなたが認められたいだけでは？)__ 
- [ ]  周囲との経験値にギャップがあり、自分の価値を認められず、他人からの評価が気になる
- [ ] 前提知識がないため、他人に頼りがちで、一人で考える事が出来ないと思い込んでいる
- [ ]  部外者扱いを受け、孤独を感じることを恐れている
- [ ] 後がないと思い込んでしまい、自分を追い込んでしまっている
- [ ] 誰にでも好かれようと、顔を使い分けたい
- [ ] 自分の思い通りにゴリ押ししたい
- [ ] 他人と自分を比べてしまう
- [ ] 褒められないと不安になる
- [ ] 些細なことでもすぐにSNSで発信したくなる
- [ ] いいねやコメントの数ばかり気にしてしまう
- [ ] 目立ちたい
- [ ] 自慢話をしたい
- [ ] 被害者意識をアピールし、周囲の同情を引きたい
- [ ] 凄く良い意見なのに、周囲の反応が気になって、自分の意見を言いづらい
- [ ] 周囲の注目を集めたい


## 承認欲求の呪縛から逃れる方法

* **自分の価値観を明確にする** 自分が何を大切にしているのか、何をしたいのかを明確にする。
* **他人と比較しない** 他人と自分を比較しても意味がないことを理解する。
* **ありのままの自分を受け入れる** 完璧を求めず、自分の欠点も含めてありのままの自分を受け入れる。
* **小さな成功体験を積み重ねる** 自分でできることから始めて、小さな成功体験を積み重ねることで、自信をつける。
* **自分自身を大切にする** 自分の心と体を大切にし、リフレッシュできる時間を設ける。


  **自分の価値観を明確にする**

  自分にとって何が大切なのか、どのような人生を送りたいのかを明確にすることが重要です。自分の価値観を軸に行動することで、他人からの評価に左右されにくくなります。

  **自分自身を大切にする**

  他人からの承認を得ようとするのではなく、ありのままの自分自身を大切にすることが重要です。自分の良いところも悪いところも受け入れ、自分を好きになることで、自信がつき、他人からの評価に左右されにくくなります。

  **完璧主義を捨てる**

  誰もが完璧ではありません。完璧主義を捨てて、ありのままの自分を受け入れることが重要です。失敗を恐れずにチャレンジすることで、成長することができます。

  **周りと比べるのをやめる**

  人と自分を比べることは、不幸の始まりです。自分自身の成長に集中することで、他人からの評価を気にする必要がなくなります。

  **感謝の気持ちを忘れない**

  自分自身が持っているものに感謝することで、幸せを感じられるようになります。感謝の気持ちを持つことで、承認欲求から解放されやすくなります。


:::note info
- **自己受容** 自分をありのままに受け入れることが重要です。完璧を求めるのではなく、自分の弱点や失敗も含めて受け入れることで、自己肯定感を高めることができます。
- **内的な価値観の確立** 他人の評価に依存せず、自分の価値観や目標に基づいて行動することが大切です。自分が何を大切にしているのかを明確にし、それに従って生きることが推奨されます。
- **課題の分離** アドラー心理学の「課題の分離」の考え方を取り入れることが有効です。他人の課題と自分の課題を分け、他人の評価は他人の課題であると認識することで、自己評価を他人に委ねないようにします。
- **他者貢献** 他人に対して貢献することが、自分の存在意義を感じるための方法とされています。他者に対して親切にすることで、自分も幸福を感じることができます。
- **マインドフルネス** 現在の瞬間に集中し、過去や未来の評価にとらわれないようにすることが役立ちます。マインドフルネスの実践は、ストレスや不安を軽減し、自己受容を促進します。

- **日記をつける** 自分の感情や考えを日記に書くことで、自己理解を深めることができます。他人の評価に対する自分の反応を客観的に見ることができます。
- **フィードバックの受け入れ** 他人からのフィードバックを建設的に受け入れることが大切です。ただし、それを自己評価の全てとしないように注意します。
- **小さな成功体験を積む** 自分の目標に向かって小さな成功体験を積むことで、自己肯定感を高めることができます。
:::

承認欲求の呪縛から解放されるためには、自己理解と自己受容が鍵となります。他人の評価に依存せず、自分の価値観に基づいて生きることで、より充実した人生を送ることができるでしょう。

今の自分を素直に受け入れる事で、無駄な力が取れて、仲間に頼るべき事を頼る事が出来て、本来の自分の力を発揮出来ると思います！


#### 読んで頂きまして、ありがとうございました。
ArduinoをVSCodeで使う

## はじめに

本記事ではVSCodeでArduino開発を行うための手順を大雑把に解説しています。

これまでArduinoIDEを使用していました。特に不満はないのですが、VSCodeの方が使い慣れていて、Github Copilotの恩恵を受けたいと思い移行することにしました。

筆者はmacで利用しましたが、windowsでも動作するはずです。

## 目次
[はじめに](#はじめに)
[目次](#目次)
[前提](#前提)
[手順](#手順)
[おわりに](#おわりに)

## 前提

- VSCodeインストール済み

## 手順

VSCodeの拡張機能タブで「PlatformIO」と検索し、[PlatformIO IDE](https://platformio.org/platformio-ide)をインストールします。

![install-platformIO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/59e1d5b2-f7c6-74ac-6ac9-f1d8f9f213b2.png)

PlatformIOをインストールすると新しくPlatformIOタブが生成されるので、そこをクリックします(PlatformIOのインストール後、VSCodeをReStartすると表示されるようです)。

![here-platformIO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/da45b93a-524c-6f7d-16cc-3cac55649071.png)

PlatformIOタブをクリックし、左下のQUICK ACCESSからOpenをクリックするとPlatformIOのホーム画面に遷移します。

ここではプロジェクトを新規作成します。

![platformIO-home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/d879aa7a-cf6c-eb60-d2fb-0370af394e67.png)

作成するプロジェクトの名前、使用するボード(筆者はArduino Uno)を選択し、プロジェクトを作成します。

初めてプロジェクトを作成すると諸々のダウンロードがあり時間がかかりますが、2回目以降はすぐに作成されます。

:::note warn
Locationにチェックをつけるとデフォルトのディレクトリにプロジェクトが作成されます。
筆者のmac環境では、/Users/name/Documents/PlatformIO/Projects/ に作成されました。
:::

![create-project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/b6b32d95-682f-a818-7cad-f981df3aa8a5.png)

作成されたプロジェクトを開くと以下のようなディレクトリ構成が成されています。

Arduinoのコードの編集はsrcディレクトリ内のmain.cppを編集します。

![default-file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/483ffcad-0e7f-8517-5451-713ea7b7c3b3.png)

main.cppのコードを編集し、LEDが点滅するようにします。

<details><summary>ここで利用したソースコード</summary>

```cpp
#include <Arduino.h>

int led = 9;

void setup() {
  pinMode(led, OUTPUT);
}

void loop() {
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}
```
</details>

コード編集後、画面下部の「✔」をクリックするとビルドされ、「→」をクリックするとArduinoへ書き込みされます。問題なく動作することを確認しました。

コンセント🔌みたいなところをクリックするとシリアルモニタを開くことができます。

![test-program.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3712663/c5f06f41-7cf4-4cd1-3457-eb948ea5878e.png)

## おわりに
本記事ではArduinoをVSCodeで利用するための手順を記しました。これでGithub Copilotを利用でき、効率的に開発が行えるようになりました。
COBOLのプリプロセッサ

C言語のプリプロセッサは、例えばこんな感じ。
```
#define DLEVEL  3
#if DLEVEL > 2
    display( debugptr );
#else
    #define STACK 200
#endif
```

同じ事をCOBOL言語で書いてみるとこう。
```
001000 >>DEFINE  DLEVEL AS 3
001010
001020 >>IF DLEVEL > 2
001030     display debugptr .
001040 >>ELSE
001050     >>DEFINE STACK AS 200
001060 >>END-IF
```
とてもよく似ています。

この書き方はCOBOLの国際規格で追加された正式な仕様ですが、
実際に使われているのをあまり見たことがありません（苦笑）。
COBOLの少しおもしろい言語仕様

# はじめに
銀行障害でちょっとだけCOBOLが注目されました。
他のプログラム言語に比べて、COBOL言語がちょっと変わっているな、と思う部分を紹介します。
これは全くの個人的趣味なので、他の人には全くささらないかもしれません。

#  マイナスがデータ名に使える
```cobol
009500 WORKING-STORAGE SECTION.
009600   01 A PIC 9(5) VALUE 4.
009700   01 B PIC 9(5) VALUE 1.
009800   01 C PIC 9(5) .
009900   01 A-B PIC 9(5) VALUE 2.
010000 PROCEDURE DIVISION.
010100     COMPUTE C=A-B         *> これは「A-B」というデータ名
010200     DISPLAY 'C=' C .
010300     COMPUTE C = A - B .   *> こちらは減算
010400     DISPLAY 'C=' C .
```
実行結果
```
C=00002
C=00003
```

# ピリオドが後ろの文字で意味が変わる
```
009600 REPLACE ==999.== BY ==ZZZ.==.
009610   01 AAA PIC 999.     *> PICTURE文字列999と終止符の.   置換される
009620   01 BBB PIC 999..    *> PICTURE文字列999.と終止符の.  置換される
009630   01 CCC PIC 999.999. *> PICTURE文字列999.999と終止符の. 置換されない
010000 PROCEDURE DIVISION.
010200     MOVE 3.4 TO AAA BBB.
010300     DISPLAY AAA.
010300     DISPLAY BBB.
```
実行結果
```
  3
  3.
```


※実行は「Windows版 MicroFocus COBOL V9.0（Personal Edition）」を使っています。

#  似たようなUSAGE（データの型）が多い
```
USAGE COMP
USAGE COMP-1
USAGE COMP-2
USAGE COMP-3
```
というのがあって、その違いを覚えるのに最初苦労します。
そのうち各ベンダーが拡張機能をつくり
```
USAGE COMP-4
USAGE COMP-5
```
などというものがあったり、さらにはラスボス感のある名前
```
USAGE COMP-X
```
が出てきたりと大変です。
最後の方のはC言語連携などで使う２進系の型なのですが、COBOLの国際規格でBINARY-SHORT、BINARY-LONGなども出てきてこれまた大変です。
USAGEの何と何が同じ意味になるのか、マニア向けのクイズになりそうです。

参考）
https://www.microfocus.co.jp/manuals/VC90/VS2022/HRLHLHPDF40Q.html


※私はMicroFocus社の人間ではありません。単なる一(いち)プログラマーです。
70歳の挑戦... オマケの「STM32F103 Blue Pill」をPCがやっと認識してくれた（解決した）ので使ってみた

![ST-LINK.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3189926/3864bdaa-0403-fefe-2506-ee9b535aef03.jpeg)

　USBシリアル変換モジュールと ST-Link V2（Mini）が欲しくて、このセット商品を購入しました。

|ST-Link V2|STM32F103C8T6|FT232RL FTDIモジュール|
|--------------|----------|------|
|プログラムダウンローダ|BluePill|USBシリアル通信|
|デュポンケーブル付き|ピンヘッダー2列、マイクロUSBケーブル付き|ミニUSBケーブル付き|

https://www.amazon.co.jp/Youmile-V2%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%BF%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%A6%E3%83%8B%E3%83%83%E3%83%88%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%80-40%E3%83%94%E3%83%B3STM32F103C8T6-%E3%83%9E%E3%82%A4%E3%82%AF%E3%83%ADUSB%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB-%E3%83%9F%E3%83%8BUSB%E3%82%B1%E3%83%BC%E3%83%96%E3%83%AB%E4%BB%98%E3%81%8D/dp/B09KP9BF9Q/ref=sr_1_24?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=22TBFT9WGCU6W&dib=eyJ2IjoiMSJ9.EkyHm55jZPZMIDJBMGFQxPEaeQWVtbakN90stit4td1YmIDZpRnMgegOPYvP7uSXb8ZXSt3y7eAv8g32x43gRBC59nzF7lDVSG12bHAkdSm8W9UYZrP40vxYZF7KK419FxFNAqnO5ROgB6yylqgbZjutcVkJS2imoDO4a7Jx_K0w9OcvGvOyyb4m03nfb7e2q39Hj1fH1dSiB9QTeFFNj9s44KOCl14z3KbmZC_y7eEgT-ogc-OtForPCMC0IqVhNVOgh4jl2RR2E3M-7mGn3ML8se5PSGKkJuN7kJSJYrU.IRW5NZBztO1iVe1cSOuHamoM321pQW_-43GIwhW5dx8&dib_tag=se&keywords=usb%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E5%A4%89%E6%8F%9B%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB+ST-LINK&qid=1717755816&sprefix=usb%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E5%A4%89%E6%8F%9B%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB+st-link%2Caps%2C352&sr=8-24

　いくつかの点で困りました（やっちまったかと思いました）。

:::note alert
ST-LINK本体・・・PCは認識する
付属デュポンケーブル・・・端子の接続不良（一方はスカスカで、他方は挿入出来ない）
BluePill本体・・・PCが認識しない。
:::

　その後、ST-LINK本体は既にあるSTM32マイコンの書込みでも使えると判明。
　デュポンケーブルの接続不具合は、はんだ付けで対処しました。
　次は「BluePill」をPCが認識しない問題。なので当然「STM32CubeProgrammer」や「ArduinoIDE」からの書込みもできない。同趣旨の商品はネット上にあふれており、中にはフェイクの烙印が押されている例もあるよう。私にとってはオマケだったので、まあいいかと思うものの何とかしたくなる。
　色々試してみて、私の環境と購入物では一応、解決しました。それはST-LINKにボードを繋ぎ「STM32CubeProgrammer」で「Connect」するとき、もし失敗するようなら
 
 :::note
 あらかじめボードの「RESET」ボタンを2，3秒押し続けておき、「Connect」ボタンを押してから「RESET」ボタンを離すと接続できる
:::
ことを発見。それで「STM32CubeProgrammer」での書込みはできます。
　また、接続できたところで

:::note
書込まれているプログラムをイレイス（消）しておく
:::
そうしておけば、ArduinoIDEでの書込みも出来るようになりました。
　これでやっと初歩的なLチカ（Blink。内蔵LEDはPC13に接続されてます）もできるように。なお、FT232RL FTDIモジュールは「ArduinoIDEのExample->MultiSerial」で無事使えることを確認。良かった良かった。その後、CDC(generic 'Serial' Supersede U(S)ART)や8ビットパラレル接続のTFT-LCDモジュールも使えました。その話はまた後日に。ご来店有難うございました。
LINEスタンプ出しました

https://sites.google.com/view/extension-of-rakugaki/home

LINEスタンプ出しました!
その時に使った、OPPOスマホ標準の写真アプリが優秀すぎました...
文字以外すべて写真アプリで書いてます!

こんな感じ
![Screenshot_2024-06-08-07-55-59-00_99c04817c0de5652397fc8b56c3b3817.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726617/b64407d5-356c-3c53-b24c-773c0a9f9239.jpeg)
![Screenshot_2024-06-08-07-56-08-54_99c04817c0de5652397fc8b56c3b3817.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726617/3f85e2d5-0d63-61f5-2d7a-3972b9e73722.jpeg)

あと、書いたものを選択して動かせる機能が地味に便利だった!
![Screenshot_2024-06-08-07-56-22-13_99c04817c0de5652397fc8b56c3b3817.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726617/5a5b3bbd-b73e-7643-6495-31926e75b6ae.jpeg)
![Screenshot_2024-06-08-07-56-35-04_99c04817c0de5652397fc8b56c3b3817.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726617/c194dc03-3749-1697-1fcb-a2363e8b229a.jpeg)

文字はCanvaのスマホ版か、LINEスタンプメーカーで入れてます!

https://sites.google.com/view/extension-of-rakugaki/home
お金稼ぎしてるわけじゃないけどダウンロードよろしくお願いします!
HybridCache混合缓存


asp.net core 9中、HyBridCacheが導入されました。これは本質的に全く新しい種類のキャッシュではなく、従来のキャッシュと組み合わせて使用されます。

```xml
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.0-preview.4.24267.6" />
  </ItemGroup>
</Project>
```

以下の例では、time0はメモリキャッシュ、time1はRedisに基づく分散キャッシュ、time3はハイブリッドキャッシュです。

もしtime0、time1がそれぞれ独立しているなら、time2はMemoryまたはDistributedキャッシュに基づいています。デフォルトでは、builder.Services.AddHybridCacheはメモリキャッシュに基づいていますが、他の分散キャッシュを基にしたい場合は、対応するServiceを追加するだけです。

```cs
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Hybrid;
using Microsoft.Extensions.Caching.Memory;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddMemoryCache();

builder.Services.AddStackExchangeRedisCache(opt =>
{
    opt.ConfigurationOptions = new StackExchange.Redis.ConfigurationOptions
    {
        EndPoints = { "localhost:6379" },
        AbortOnConnectFail = false
    };
});

builder.Services.AddHybridCache();

var app = builder.Build();

app.MapGet("/time0", async (IMemoryCache cache) =>
{
    return await cache.GetOrCreateAsync("time0", async _ => await Task.FromResult(DateTime.Now));
});

app.MapGet("/time1", async (IDistributedCache cache) =>
{
    var time = await cache.GetStringAsync("time1");
    if (string.IsNullOrWhiteSpace(time))
    {
        time = DateTime.Now.ToString();
        await cache.SetStringAsync("time1", time);
    }
    return time;
});

app.MapGet("/time2", async (HybridCache cache) =>
{
    return await cache.GetOrCreateAsync("time2", async _ => await Task.FromResult(DateTime.Now));
});

app.Run();
```

上記のコードによると、メモリーと一つの分散キャッシュが追加された場合、ハイブリッドキャッシュはどちらを使用するのか？実験してみて、結果をこの記事のコメントに同期してください。：）

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247488177&idx=1&sn=cfd5676278779249afb56dba720c3352&chksm=9f004d9ba877c48d74f41af484b3dcb0f7a52c8f299f401dd12c4ac1d68421fc23a26f1c6520&token=1053798272&lang=zh_CN#rd&wt.mc_id=MVP_325642
Semantic Kernel概览


随着Semantic Kernel（以下简称SK）功能的使用和版本功能的稳定，是时候梳理一下SK的功能了。本系列文章会以C#作为主要的案例分享语言，尽量做到“概念解释简明易懂，示例代码清晰简洁”。

为了简单说明，之后Semantic Kernel都简写为SK。

![图片](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRC2ibcBlMngs6ByoblZZA1KmOdfAo2kw5hZ81Q8mjBNw3StuWfrzeeSggAs9cEffXxBv9cWd8ljhibw/640?wx_fmt=png&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)

SK是一个软件开发工具包（SDK），它将大型语言模型（LLMs）如OpenAI、Azure OpenAI和Hugging Face与传统编程语言如C#、Python和Java集成在一起。SK通过允许你定义插件，并可以用几行代码将这些插件串联起来，从而实现这种集成。

然而，使SK独特的是它能够自动用人工智能（AI）来协调这些插件。使用SK的计划器（planners），你可以请求一个大型语言模型生成一个实现用户独特目标的计划。然后，Semantic Kernel会为用户执行这个计划。

说一下我对SK的感受：首先是SK同时支持Python，C#，Java三种语言，虽然每种语言的SDK发版时间有时间差，但功能基本上都是能对齐的，为相同解决方案下的不同项目提供了一致的API。另一个好处是可以共用一些基础设施或平台，比如日志收集，监控指标等。

再有就是SK与是LLM无关的，目前SK支持了主流的LLM，有的还在支持和完善的路上，相信随着LLM和SK的稳定和成熟，SK能很好地拟合LLM之间的使用差异，从而提升开发效率和提升LLM切换的灵活性，为LLM聚合网关提供了先天条件。

【SmartFill】是本人开发的一款Chrome插件式智能输入小工具，欢迎试用：https://tinyurl.com/222ajrfd

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247488174&idx=1&sn=c436e3461f43ae44d53fcfa629cde9d0&chksm=9f004d84a877c4920a04a1508c1ba2d459ef6b2d8eb112c448a18ecf6e8b212add143cdc8e27&token=1053798272&lang=zh_CN#rd&wt.mc_id=MVP_325642
別紙による書き初め

エンジニアの皆さんが使っているQiitaというサービスを、私もやってみようと思う。


## 自己紹介
#### よく使われていると思うOS
・debian等のUnixやUbuntuではないOS
#### 好きなコマンド
<blockquote>$ ls -lart | grep .CSV</blockquote>
<blockquote>$ jhead -purejpg ./a.jpg</blockquote>
<blockquote>$ exit</blockquote>


## 感想
MarkdownよりはHTMLやLibreOffice Writerのほうが慣れていることに気付いてしまった。

よくないですけど、慣れますので、よしなに。
让传统应用开发融合AI能力


![图片](https://mmbiz.qpic.cn/sz_mmbiz_jpg/4CAA63nvHRCAiaibLxY8kYuUY74icCMS4nUqjV5NgY0L030MwoicZiaN4uXHum1Vl1QMK4XXBeA3kTngDXQpUeDhUrg/640?wx_fmt=other&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1)

首先说一下我的观察和体会啊，这只是我个人的观察：生成式AI不再像之前那样粗暴地火爆，而是变得更加细化，推陈出新或者是进行版本迭代？与此同时，在许多常用的工具中，可以看到更多AI的踪迹。的确，AI的加入并非一种排山倒海的方式，而是以一种润物无声的形式融入我们的应用或工作之中。

其实新旧技术的更迭从来不是简单的切换，就像以往面向桌面的编程技术，在遭遇互联网的冲击时，也受到了质疑。但最终，旧有技术和新兴技术并存，不是相互替换，而是共同让IT开发的蛋糕更加丰富，从而推动社会信息化和科技化的进步。

因此，从最近开发AI应用的体验来看，AI与传统应用的关系也是如此，它们是相互依存，相互支持的。两者结合可以使信息化、移动化的优势进一步扩大。

生成式AI擅长内容生成、分类、转换、总结、翻译、分析、推理等方面，这些能力所产生的结果本质上并不是确定性的，而是语义上相似的。与此同时，传统应用处理的数据是具体且确定性的。如果将它们比作函数，那么即便AI在相同的输入下，其输出只能保证大体相似或语义相近，但传统开发的结果应当是幂等性的。两者的结合，正是强强联合。

另外，在我开发[SmartFill](http://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247488116&idx=1&sn=58248196ef7999fe5236253ff060f22f&chksm=9f004d5ea877c448f88504fb99b9bbf70aa0520d68429fed3186c0a437b6c141515e4dd446f6&scene=21#wechat_redirect)时，对两种开发范式有了些许感悟，应让AI担任更有创意的任务，然后通过传统编程方法来规范化结果。如果需要得到确定的结果，就不应该让不确定性产生更多不确定性，中间必须进行修正和判断。再者，不应该把所有鸡蛋放在一个篮子里，除了GPT之外，还有很多优秀的选择，每个领域都有更优的选择。

(Translated by GPT)

元のリンク：https://mp.weixin.qq.com/s?__biz=MzA3NDM1MzIyMQ==&mid=2247488140&idx=1&sn=1f46249001eeba2efa3d6f83b1fa0943&chksm=9f004da6a877c4b0e0b9d1a5af41070d732a144e68c2151139ae6ff94b01cd63a41c9a95c1b1&token=1053798272&lang=zh_CN#rd&wt.mc_id=MVP_325642
Web push 通知？サイトに実装？…うぇ～い（汗

# § 初めに
この記事は、以下の内容でお話が進む（かも）というようになっています：

- Web push 通知？なにそれ美味しいの？
- Push.js？なにそれ美味しいの？
- HTTP？HTTPS？なにそれ美味しいの？

※すみません。昨日のお昼から食べてないので...

# § Main.article
この記事では、web サイトに通知機能はどのようにして実装できるのか、そして、実装する際の注意点などについて、記載させていただきます。

少しでもなにかしらの参考になりましたら幸いです
（※幸いすぎです。えへ）

## Web push 通知？なにそれ美味しいの？
Web push 通知とは何か！
ざっくり解説するに、**通知を許可したユーザーにWEBブラウザ経由でプッシュ通知をする**ことです。

ブラウザ経由で行われるため、ユーザーは特定のアプリをインストールする必要がなく、サイトを訪れた際にポップアップされるメニューなどで通知を許可するだけで受信できるようになります。

WEBプッシュ通知は任意のタイミングで行えます。
サイトに訪れてから一定期間経過後に通知する、定期的配信するなどの配信予約も可能です。

さらに詳しく知りたい方は、以下のサイトを参考にしてみてください：
https://materialdigital.jp/media/web-push-notification/

## Push.js？なにそれ美味しいの？
では、さっさと Web push 通知を実装しましょう！
というお話なのですが、そこで今回必要（走れメロスのメロスなみに重要）になるものが、**Push.js**　たる **フレームワーク** です。

以下が公式サイトになります：

:::note alert
以下のURLは、原因不明の不具合を起こしています。
詐欺サイト（マイクロソフトを語ったウイルス警告など）に連れていかれることもありますので、絶対にクリックしないでください。
:::

https://pushjs.org/

:::note alert
上のURLは、原因不明の不具合を起こしています。
詐欺サイト（マイクロソフトを語ったウイルス警告など）に連れていかれることもありますので、絶対にクリックしないでください。

※私が確認した三つのサイトでは、危険を感じなかったので、whois の使い方を知っていたり、危ない勉強がしたい人は自己責任で使用してください。
※こういったものを記事として残すべきではないと考える方は、お手数ですが編集リクエストをお願いいたします。即採用させていただきます。
:::


（まぁ読まなくとも…ハハハ…（汗）

ということで、実際に実装していく際には、いろいろ方法がありますが、一番手軽なのは（私個人の意見です）HTML に入れちゃうことです。

具体的な実装に関しては、下記サイトを参考にしてみるとよいかもしれません：
https://tune-up.co.jp/archives/5947

## HTTP？HTTPS？なにそれ美味しいの？
ここからが、私が今回この記事を書こうと思ったきっかけであり、そして最も重要なお話です。

ここまでだらだらと書かれた文字列を読んでくださった方、本当にありがとうございます！

そして、もう一度ですが、ここからがこの記事の核（酢酸ダーリア溶液で染まることはありません）です！
ぜひ最後まで読んでください（くださると嬉しいです。えへ）

以下に、私の身に何が起こったのか、順を追って記載します

1. Web push 通知を実装する
1. 動いてる（うぇ～い）
1. 機能をリリース
1. ・・・動いてなくない？

ご理解いただけましたでしょうか？

それでは原因について記載してまいります。

原因は、**HTTP のサイト** です。
こいつが **悪の根源** です。

そもそも、HTTP のサイトと HTTPS のサイト、違いが…うん、有名なお話ですしいいですね

下記サイトにおいて、まじわかりやすく解説が記述されています。好きです：
https://www.cloudflare.com/ja-jp/learning/ssl/why-is-http-not-secure/

つまり、実装した Web push 通知が動かなかったのは、**セキュリティ上の問題** のためです。

Push通知はセキュリティ上、HTTPSが有効になっているWebサイトでしか動作しません。

また、**ローカル環境で動作させている場合、localhostであれば例外としてHTTPでも動作します** が、**これ以外の場合はHTTPSが必須** です。

ご理解いただけただろうか？
（※言ってみたかっただけです～ごめんちゃい）

つまりです！
Cursor で LiveServer で動いてうぇ～い♪してる場合ではないのです！

私がこの記事で一番書き留めたいこと、伝えたいことは

**本番環境でテストしてからリリースしやがれ！！**

ということです。

「ちゃんと情報収集する」ということも必要なのでしょうが…はははははっ

# §最後に
いきなり最後になっちゃいましたねww

今回は、Web push 通知の実装から、機能を実装するなどの際には、「しっかりと本番環境でテストして」リリースしろよ

というお話でした。

私自身はマジなよわ弱炎ジニアです。

今回の記事が少しでも、なんでも、ちょっとでも、どなたかの何かしらのことに参考になれば、

**それ以上に嬉しいことはありません！！**


最後まで読んでくれてありがとう！

…おなかすいたねん
ライブラリver1.0.0にpublicな関数を追加したらver1.0.1か？ver1.1.0か？


## 前書き（予防線）

知識がある人にとっては常識すぎる話です。
自分は数秒悩みました。

## 結論

ver1.1.0にする。

## 理由

>バージョンナンバーは、メジャー.マイナー.パッチ とし、バージョンを上げるには、
>
>1. APIの変更に互換性のない場合はメジャーバージョンを、
>1. 後方互換性があり機能性を追加した場合はマイナーバージョンを、
>1. 後方互換性を伴うバグ修正をした場合はパッチバージョンを上げます。
>
>プレリリースやビルドナンバーなどのラベルに関しては、メジャー.マイナー.パッチ の形式を拡張する形で利用することができます。

引用元：[セマンティック バージョニング 2.0.0](https://semver.org/lang/ja/)

ライブラリにpublicな関数で新たな機能を提供することは
「2. 後方互換性があり機能性を追加した場合はマイナーバージョンを～」
に該当するから。

マニュアルを校正したり、インタフェースを変えない範囲でバグを直した場合はパッチバージョンを上げるものと思われます。
to_iを用いたnil回避術

## integer型の結果を表示する際の例
```rb
# 外部APIから取得したデータをシミュレートする
api_response = {
  user_id: 123,
  usage_count: nil  # APIレスポンスにusage_countが含まれていない場合
}

# usage_countを整数に変換する。
usage_count = api_response[:usage_count]

puts "ユーザーID: #{api_response[:user_id]}"
puts "使用回数: #{usage_count} 回"
```
例えば、外部APIから取得したレスポンスにuser_idとusage_countが含まれているとします。
ただ、usage_conutがレスポンスに含まれていない場合usage_countはnilとなります。
この際に、usage_countをnilという表示するのは避けたいです。

そんなときに、to_iが力を発揮します。

## to_iとは
to_iメソッドはRuby標準ライブラリです。
to_iは文字列の数値をinteger(整数)に変換してくれます。
to_iの挙動は以下のようになります。

### 文字列からinteger(整数)に変換
数値が文字列に含まれていれば返します。文字列ならば0を返します。
そして、数値＋数値以外の文字列の場合は数値のみ返します。
```rb
"123".to_i   #=> 123
"abc".to_i   #=> 0
"12abc".to_i #=> 12
```

### 浮動小数点からinteger(整数)に変換
浮動小数点の場合は小数点以下は切り捨てられます。
```rb
12.34.to_i   #=> 12
```

### その他の場合
nilの場合は0を返し、trueの場合は1、falseの場合は0を返します。
```rb
nil.to_i     #=> 0
true.to_i    #=> 1
false.to_i   #=> 0
```

### 基数変換
また()の中に進数を指定することで基数に基づいてinteger(整数)に変換されます。
```rb
"ff".to_i(16)  #=> 255
"1010".to_i(2) #=> 10
```

## まとめ
冒頭で述べたものでは
```rb
# 外部APIから取得したデータをシミュレートする
api_response = {
  user_id: 123,
  usage_count: nil  # APIレスポンスにusage_countが含まれていない場合
}

# usage_countを整数に変換する。nilの場合は0として扱う
usage_count = api_response[:usage_count].to_i

puts "ユーザーID: #{api_response[:user_id]}"
puts "使用回数: #{usage_count} 回"
```
`api_response[:usage_count].to_i`とto_iをつけることでnilを0に変換でき、表示結果をnilの場合は0とすることができます。

to_iにはこのような使い方もあるので、ご参考にしてください。
【Node.js】ts-nodeの実行で躓いた話

社内でNode.jsを使用した以下の勉強課題をいただきました。
+ [Nodeビギナーズブック](https://www.nodebeginner.org/index-jp.html)

この記事はJavaScriptで記載されていますが、TypeScriptに直して実行することが今回の課題です。

実行の条件として以下をもらいました。
+ TypeScriptで記載すること
+ 「require」ではなく、「import」を用いること
+ TypeScriptでは「node」コマンドは動かないので、「ts-node」で実行すること

上記条件にて、順にコードを記載していったところ、今回タイトルとして記載している「ts-node」の実行という、だいぶ初歩的なところで躓いたので備忘として整理しておきます。

環境はMac端末にて以下で実行しています。（多分現時点で最新の状態のハズ、、、）
```
% nodebrew -v
nodebrew 1.2.0

% node -v
v20.5.0

npm -v
9.8.0
```

## 概要
コードを記載し、下記コマンドにて「ts-node」を実行。
```
% ts-node [実行ファイル]
```
実行結果として以下がエラーとして出力されました。。

### エラー内容
```
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /実行リポジトリ/index.ts
    at new NodeError (node:internal/errors:399:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:79:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:121:38)
    at defaultLoad (node:internal/modules/esm/load:81:20)
    at nextLoad (node:internal/modules/esm/loader:163:28)
    at ESMLoader.load (node:internal/modules/esm/loader:605:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:457:22)
    at new ModuleJob (node:internal/modules/esm/module_job:64:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:480:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:434:34) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}
```

## 解決方法
エラー内容を調べると下記記事を見つけました。

https://zenn.dev/galapagos/articles/thank-you-tsx

こちらを参考に以下コマンドで実行。

```
npx tsx [実行ファイル]
```

結果としては無事にNode環境を立ち上げることができました。


## 原因調査
エラーになった原因を少し調査してみたところ、下記記事を見つけました。

https://qiita.com/suin/items/35537440bfe0adf27c6b

ts-nodeはESMのTypeScriptでは動作しないことが今回のエラーの原因のようです。

## 終わりに
今回は「import」を用いることが条件として１つありました。
「ts-node」で実行することも条件としてありましたが、実行で時間を取られるのも癪ですし、動かなければ意味がないので、「ts-node」は諦め、「npx tsx」での実行となりました。

ただ、ほかにも調べてみると「ts-node」 かつ ES Modulesで実行できている参考サイトも多々見受けられたので、別の方法があるのかもしれません。
交差検証のモデル保存と精度一覧を出す関数を作った

交差検証はScikit-Learnだと「sklearn.metrics.cross_val_score」にあります。
しかしそこでできるのは精度の計測で、一番良かった時のモデルが保存されているわけではありません(もしかしたら自分が知らないだけかも)。
そこで今回は交差検証をしてなおかつ詳細な精度の分かる関数を作ってみました。
# 関数
```Python3
import pandas as pd
from sklearn.metrics import classification_report
def closs_val_model_accuracy(model, x, y, cv=50):
    ylist = list(set(y.values.astype("str")))
    models = []
    acc = []
    for i in range(cv):
        x_test = x.loc[int(i*len(x)/cv):int((i+1)*len(x)/cv)]
        y_test = y.loc[int(i*len(x)/cv):int((i+1)*len(x)/cv)]
        x_train = pd.concat([x.loc[0:int((i)*len(x)/cv)], x.loc[int((i+2)*len(x)/cv):]])
        y_train = pd.concat([y.loc[0:int((i)*len(x)/cv)], y.loc[int((i+2)*len(x)/cv):]])
        model = model
        model.fit(x_train, y_train)
        y_pred = model.predict(x_test)
        rep = classification_report(y_test, y_pred, output_dict=True)
        tmp = []
        for i in range(len(ylist)):
            try:
                tmp.append(rep[str(ylist[i])]["precision"])
                tmp.append(rep[str(ylist[i])]["recall"])
                tmp.append(rep[str(ylist[i])]["f1-score"])
                tmp.append(rep[str(ylist[i])]["support"])
            except:
                tmp.append(None)
                tmp.append(None)
                tmp.append(None)
                tmp.append(None)
                print(rep)
        tmp.append(rep["accuracy"])
        acc.append(tmp)
        models.append([model, rep["accuracy"]])
    columns = []
    for i in range(len(ylist)):
        for col in ["precision", "recall", "f1-score", "support"]:
            columns.append(ylist[i]+"_"+col)
    columns.append("accuracy")
    df_acc = pd.DataFrame(acc)
    df_acc.columns = columns
    return df_acc.describe(), models, df_acc
```
## 使用例
ここではScikit-Learnにある乳がんデータを使用します。
```Python3
from lightgbm import LGBMClassifier
import numpy as np
import pandas as pd

df = pd.read_csv("breast_cancer.csv")

y = df["y"]
x = df.drop("y", axis=1)

model = LGBMClassifier()
df_dcb, models, df_acc = closs_val_model_accuracy(model, x, y, cv=50)
```
```
{'0.0': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 13}, 'accuracy': 1.0, 'macro avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 13}, 'weighted avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 13}}
{'1.0': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}, 'accuracy': 1.0, 'macro avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}, 'weighted avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}}
{'1.0': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}, 'accuracy': 1.0, 'macro avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}, 'weighted avg': {'precision': 1.0, 'recall': 1.0, 'f1-score': 1.0, 'support': 12}}
```
この出力は片方のラベルしかテストデータに無かった時の物です。
```Python3
df_dcb
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2782889/ee4e75d8-0fe4-577e-c9a6-ff713c8232b7.png)



このように詳細な精度の分布が分かります。
count(サンプル数)が異なるのは先ほどの片方しかラベルが無い場合です。

これで最適なモデルはsorted関数を使って一番スコアの高かったモデルを使えば最適なモデルになります。
Vimで複数行一括に挿入する方法

# 基本的なvim操作
|       |       |
| :---: | :---: |
|  esc  |  ノーマルモード  |
|  i    | 挿入モード |
|  v    |  ヴィジュアルモード  |
|  :wq  |  保存して終了  |
|  :q!  |  保存しないで終了  |
|  yy   |   コピー  |
|  p    |  ペースト  |
|  dd   |   一行削除  |
|  x    |  一文字削除  |
|       |       |

# 複数行一括に挿入する方法
#### 矩形選択（ブロックモード）
| Ctrl + v |
| :----: |

ノーマルモード`esc`で`Ctrl + v`をするとブロックモードとなり、矩形選択ができます。
複数行一括で同じ操作をしたいときに役立ちます。

## 行頭に挿入
ブロックモード`Ctrl + v`で挿入したい行数を選択する。
一番下まで選択したい場合は`Shift + G`
| Shift + I |
| :----: |

これでブロックモードから挿入モードになり、入力できる。※`i`ではないので注意
`esc`で抜ければOK。

#### `Shift + I`をおした後、*矢印キー*で挿入する位置を変更できる。
※`h` `j` `k` `l` では移動できない

## 行末に挿入
行末に挿入するには、上記と同様、ブロックモード`Ctrl + v`で短形選択し、
`＄`で行末に移動できる。

| Shift + A |
| :----: |

これでブロックモードから挿入モードになり、入力できる。
※`I`ではないので注意。`I`を押すと、行頭が選択される。
`esc`で抜ければOK。
Pathの拡張子をチェックしたい

Pathの拡張子をチェックしたい場合、PathMatcherクラスのmatchesメソッドを利用します。

例) Pathの拡張子がcsvかどうかをチェックする

```java
Path path = Path.of("Path/To/Target.csv");
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**.csv");
if (matcher.matches(path)) {
	System.out.println("This file is csv.");
} else {
	System.out.println("This file is not csv.");
}
```

**環境情報**

```
C:\>javac -version
javac 21-beta

C:\>java -version
openjdk version "21-beta" 2023-09-19
OpenJDK Runtime Environment Temurin-21+35-202309042131 (build 21-beta+35-ea)
OpenJDK 64-Bit Server VM Temurin-21+35-202309042131 (build 21-beta+35-ea, mixed mode, sharing)
```
【GCP】PDFファイルをOCR処理し、内容を構造化してCSVファイルを作成するツールを作ってみた（その２）

## １．おおまかな要件
①　ローカルのPDFファイルをGoogle Cloud Storageに連携
②　連携したPDFファイルをGCP VisionAIでOCR処理し、JSONファイルに出力
##### ↑ここまでが（その１）の範囲
③　②で作成したJSONファイルをGCP-4のAPIを使用し、予め用意した構造化モデル（大げさ）設定ファイルを基に解析
④　③で解析した結果をCSVファイルで出力
##### ↑ここまでが（その２）の範囲
## ２．ツールのイメージ図（再掲）
![ocr_csv_create構成イメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2472326/cbca01ed-576a-f111-dbcb-dab942a9feea.jpeg)
## ３．事前準備
・OpenAIアカウントの作成
　[参考URL：OpenAIのアカウント作成方法を画像付きでわかりやすく解説！](https://www.goatman.co.jp/media/chatgpt/howto-create-account/)

・GPT Keyの発行
　[参考URL：GPT-4o対応【24年5月最新】API Key 発行手順と課金方法](https://qiita.com/okinakamasayoshi/items/0643199d3407d301373a)

## ４．プログラム
[GitHub:OpenAI-JSON-Anarysis.py](https://github.com/k-tsuru/tool/blob/main/ocr_csv_create_tool/OpenAI-JSON-Anarysis.py)
[GitHub:json_config](ocr_csv_create_tool/json_config)
### （１）OpenAI Keyの実装
OpenAIアカウントで発行したキーの格納場所（環境変数）を設定し、GPT-APIを使用できるようにする。
```python:OpenAI-JSON-Anarysis.py
import os
from openai import OpenAI
import json
import base64

#端末に格納したAPI Keyの環境変数を設定
OpenAI.api_key = os.environ['OPENAI_API_KEY']

client = OpenAI()
```
### （２）構造化モデルの設定

今回のツールでは読み取ったPDFが試算表であることを想定して構造化モデルをJSONで作成。
```JSON:balancesheet_config.json
{
"現金（貸方残高）": "number | null",
"現金（貸方合計）": "number | null",
"現金（借方残高）": "number | null",
"現金（借方合計）": "number | null",
"普通預金（貸方残高）": "number | null",
"普通預金（貸方合計）": "number | null",
"普通預金（借方残高）": "number | null",
"普通預金（借方合計）": "number | null",
・・・
}
```

（その１）でOCR処理した内容を記載したテキストファイルを準備する。
また、上段で用意した構造化モデル（試算表）のJSONファイルを準備する。
```python:OpenAI-JSON-Anarysis.py
# 一時的な読込措置（その１でOCR処理結果を格納したファイル）
path = 'D:\\work\\tool\\ocr_csv_create_tool\\text\\test_w.txt'

with open(path) as f:
    string = f.read()

# JSONファイル（試算表のスキーマ）を読み込む
path_json = 'D:\\work\\tool\\ocr_csv_create_tool\\json_config\\balancesheet_config.json'
with open(path_json, 'r', encoding='utf-8') as f:
    schema = json.load(f) 

```
### （３）JSON形式での出力
上段で準備したテキストファイル（OCR結果）とJSONファイル（構造化モデル）を基にGPT-APIを使って解析依頼を行う。
行った結果についてはJSONオブジェクトとして出力する。

```python:OpenAI-JSON-Anarysis.py
# OCR処理したテキストファイルを指定したスキーマの形式にGPTで整理
response = client.chat.completions.create(
    model="gpt-4-turbo-preview",
    response_format={ "type": "json_object" },
    messages=[
      {"role": "system", "content": f"次の文字列から試算表の勘定科目毎の貸方残高・貸方合計・借方残高・借方合計を抜き出して、JSON形式で出力してください。JSONのスキーマは次の通りです：{schema}"},
      {"role": "user", "content": string}
    ]
  )

# GPTで整理した結果をJSONオブジェクトに変換
response_json = json.loads(response.choices[0].message.content)

# JSONオブジェクトを文字列に変換
json_str = json.dumps(response_json)
```
## ５．今後の課題
ここで作成したものはあくまでベースとして、PDFをOCR処理してJSONオブジェクト化するところのコアの部分になる為、これを誰でも使えるインターフェースや、今回準備した試算表以外にもJSONファイルを用意し、多種多様なPDFを手軽にCSV化できるようアプリケーション構築を進めていきたい。
Open WebUI (Formerly Ollama WebUI) がすごい

Open WebUIを使ってみました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/7a4b2a44-3db1-dede-d889-791f59ced002.png)
[https://openwebui.com/](https://openwebui.com/)

当初は「Ollama WebUI」という名前だったようですが、今はOpen WebUIという名前に変わっています。Ollama専用じゃなくなったということでしょう。OpenAIに対応済みです。

早速使ってみました。もちろんBedrockで。

---
6/11 続編を書きました。

https://qiita.com/moritalous/items/9677ec160da90092b51d

---

## 環境構築

Dockerですんなり構築です。Bedrockに対応はしてないので、「LiteLLM」を使って対応させます。

環境変数でこのあたりを指定
* Ollamaを無効化
* LiteLLMのエンドポイントをOpenAIのエンドポイントとして登録
* APIキーを登録（LiteLLMとの通信には不要ですが、未指定だとOpen WebUIが正しく動作しませんでした）

```yaml:docker-compose.yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui
    container_name: open-webui
    volumes:
      - open-webui:/app/backend/data
    ports:
      - 8080:8080
    environment:
      - 'WEBUI_SECRET_KEY='
      - 'ENABLE_OLLAMA_API=false'
      - 'OPENAI_API_BASE_URL=http://litellm:4000'
      - 'OPENAI_API_KEY=sk-12345'

  litellm:
    image: ghcr.io/berriai/litellm:main-stable
    volumes:
      - ~/.aws:/root/.aws
      - ./litellm/config.yaml:/config.yaml
    command: [ "--config", "/config.yaml" ]

volumes:
  open-webui: {}
```

LiteLLMの設定ファイルを作成します。

```yaml:litellm/config.yaml
model_list:
  - model_name: claude-3-sonnet
    litellm_params:
      model: bedrock/anthropic.claude-3-sonnet-20240229-v1:0
      aws_region_name: us-east-1
  - model_name: claude-3-haiku
    litellm_params:
      model: bedrock/anthropic.claude-3-haiku-20240307-v1:0
  - model_name: command-r-v1:0
    litellm_params:
      model: bedrock/cohere.command-r-v1:0
  - model_name: command-r-plus-v1:0
    litellm_params:
      model: bedrock/cohere.command-r-plus-v1:0
```

:::note
LiteLLMで対応しているモデルはこちら。Bedrock以外も設定ファイルを用意するだけです。

https://docs.litellm.ai/docs/providers
:::

## 起動

```shell
docker compose up
```

ブラウザで`http://localhost:8080`にアクセスします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/c97c4071-a3ab-365c-9c33-2d58d757bbb3.png)

セルフサインアップが可能です。サインアップ後の画面はこちらです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/3c4e6ca4-9a3b-4e37-224a-19d9a1cc1a0e.png)

LiteLLMに登録したモデルが選択できます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/7960c22d-a5ad-c7d6-a16a-608811c33752.png)

当たり前ですがチャットができます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/db9e7cce-1778-1ca5-c855-3087acd31e30.png)

ドキュメントを添付してチャットができます。
（Claude 3で対応している画像添付はうまくいきませんでした）

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/cf3bb94b-1c30-a11d-a59d-72c474ff298c.png)

目玉機能です。

複数のモデルに対して、同時にチャットができます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/32a20add-8907-47df-4136-07e0979ad41d.gif)

まあ素敵

:::note
とりあえずチャットがほしいときはこれでいいですね
:::

---
6/11 続編を書きました。

https://qiita.com/moritalous/items/9677ec160da90092b51d

---
How to install the TensorRT on ComfyUI

先日、Syable Diffusion ComfyUIの作者comfyanonymous氏が、ComfyUI用のTensorRT拡張機能を発表しました。
https://github.com/comfyanonymous/ComfyUI_TensorRT

TensorRT高速化技術は、既にA1111が先行して拡張機能を実装していましたが、これでComyUIにおいてもTensorRT技術を使用できる環境が整ったことになります。

今回は、そのインストール方法について解説したいと思います。

尚、ComfyUIのインストール環境は、一般的なportable形式で使用している前提で以下、解説していきます。

まず下図のように、拡張機能のインストール先であるcustom_nodesフォルダにパスを通した形でpowershellを起動します。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/3f40ae54-da5d-c59a-be45-7afb9d69c563.png)

次に下図のように、
git clone https://github.com/comfyanonymous/ComfyUI_TensorRT
と入力して実行します。これによって拡張機能ファイルがダウンロードされます。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/7813a940-0700-4b39-3ec4-8c1ad73ccaa6.png)

次に下図のように、ComfyUI_windows_portableフォルダにパスを移動させます。ここから、TensorRTを動作させる為に必要なPythonライブラリーをインストールしていきます。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/91351b24-ef53-47a0-7fa0-456439cb7745.png)

次に下図のように、python_embeded\python.exe -m pip install nvidia-cudnn-cu12==9.1.1.17 --no-cache-dirと入力して実行してください。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/3fff53ca-0047-5999-0c52-329bbdc42673.png)

この手順は公式の解説では不要の様ですが、A1111に対してTensorRTをインストールする際には必要な手順なので、念のために実行しておきます。
(この手順を省略しても動作する可能性はありますが)


次に下図のように、python_embeded\python.exe -m pip install --extra-index-url https://pypi.nvidia.com/ tensorrt tensorrt-bindings tensorrt-libs --no-cache-dirと入力して実行してください。これが、TensorRT本体のライブラリーになります。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/fd3429de-33b6-8196-4e28-1c768beacce4.png)

次に、onnxruntime関係のライブラリーをインストールしていきます。

公式の解説では、ComfyUIの場合はonnxだけインストールすれば良いようなのですが、ここでも念の為にA1111と同じライブラリーをインストールしていきます。

まず、下図のように「python_embeded\python.exe -m pip install install importlib_metadata onnx polygraphy」と入力して実行してください。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/69d75dc4-e71c-12d5-f67f-d591b82e81b3.png)

次に、これもA1111と同様に念の為、onnxruntime-gpuライブラリーをインストールしておきます。

また、これもA1111で発生した障害ですが、最新バージョンをインストールするとip-adapterに支障をきたす可能性がある為、1.17.1を指定してインストールします。

下図のように、python_embeded\python.exe -m pip install onnxruntime-gpu==1.17.1 --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/
と入力して実行してください。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/af4c1456-f689-3155-bc9b-8672ca8419ef.png)

以上で、ComfyUIの為のTensorRTのインストールは完了です。powershellを閉じて、ComfyUIを起動してください。

モデルの作成方法と、TensorRTの適用方法に関しては公式の解説をご覧ください。
(後日、追記するかもしれませんが)

尚、下図のように\ComfyUI_windows_portable\ComfyUI\custom_nodes\ComfyUI_TensorRT\workflowsフォルダには、モデル作成及びTensorRTを適用する為の基本的なノードが用意されています。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/6dc91f69-1135-a657-5a65-17ee50d66c1a.png)

下図は、あらかじめ用意されているSD1.5用の基本的なワークフローの図です。
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661150/4c63ecb0-7a58-d4a3-6694-23269a60d09a.png)

公式の解説を読みつつ、これらのノードを読み込めば、モデル作成も適用も問題なく実行できると思います。
限界三流エンジニアが見てきた、一流エンジニアの特徴

こんばんは。
私は三流エンジニアとして毎日ギリギリで仕事している感じなのですが、そんな日々の中でも、たまに「こ、この方は一流だ…！」と感じる凄腕エンジニアとお仕事させていただくことがあります。
今回は、そういった方に共通する特徴をシェアしていきたいと思います。

# 1. プログラムに触れている時間が長い 

身も蓋もないですが、皆さん異常に長く働きます。
本人的には、働いてるのか遊んでいるのか区別ついてないように見えます。
毎日23時くらいまで残っててすごい働くなと思っていたら、定時後は自分のためのライブラリ作っていたりします。
土曜も9時くらいからコードを書き始めて、断続的に夜中まで何かPR書いたりブログで検証記事を書いたりしている方が多いように思います。とにかく楽しそうにやっています。

1万時間の法則等でいわれるように、質の前にまずは量なんだなーと感じます。
また、仕事を仕事と思わず楽しんでやってる人が伸びるのは言うまでもないんですよね…

# 2. 違和感をスルーしない（手間暇を惜しまない）

大体、優秀な方は仕様やコードに違和感を感じたら、納得いくまで調べたり確認しています。
その結果、重大な不具合に気づいたり、言語やフレームワークに対する知見を深めているように思います。
三流限界エンジニアは、今はとにかく進捗を伸ばさないといけないので動けばヨシ！としてしまいがちですが、その結果テスト工程で地獄を見ることになります。

# 3. 新しい技術が大好き

一流の方は、流行るかどうかわからない、GitHubのスターが1000くらいだけど尖ってて面白そうなライブラリが一部で話題になると、すぐに手元で動かしています。
その後、良さそうであれば動向をキャッチアップし続けて、タイミングを見てスッと出してきます。
そもそも仕事で役立つかはあまり考えずにやっているのかもしれない…

三流限界エンジニアは、流行っている技術でないとネットに知見が転がってないから駄目！と言い、自分が習得済みの技術に固執します。また、仕事に直結しない技術の習得は避ける傾向が見られます。自分で書いていて悲しくなるほどダサいですね。

# 4. 仕事道具にこだわり、投資を惜しまない

これは人によりけりかもしれませんが、私がこれまでお仕事させていただいた一流の方は、キーボードやエディタにこだわりのある方が多いように思います。
逆に、弘法筆を選ばずで、どんな環境でもハイパフォーマンスなのがカッコいいんだと言っている人もいましたので、全員がそうというわけでもなさそうです。
（道具を選ばない、という逆向きの拘りともいえる）

ただ、皆さん例外なく技術書や自己啓発本は気軽に購入しているようです。会社で買ってもらうのを待つとか、ネットの無料記事で何とかしようとはせず、きちんと身銭を切ってますね。

# 5. 頑張れば何とかなると思っている（自己肯定感が強い）

これは条件というよりは、前述の取り組みを続けた結果そうなっている気もしますが、皆さん自己肯定感が強く、何でも頑張ればできらあ精神を感じます。

![ダウンロード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3810012/6c664b7d-5e3d-6826-6d48-f7dba77047d5.jpeg)

日本語の情報が全くと言っていいほどないライブラリでも、英語で調べればできらあ！とか。
そもそも学歴が高く受験戦争に打ち勝ってきた等の過去の成功体験がしっかり行動原理にセットされていて、困難に際しての自分のポテンシャルを疑っていないような気もします。
三流は途中で諦めちゃうんですよね…

# 6. 説明できないものは作らない

一流の方は「なんとなく」や「動くからヨシ」でモノを作ることはしていないように思います。
自分で書いたコードは全部明確に説明できますし、どっちでもよさそうなこと（ファンクションかアロー関数か、みたいな）でも、その人なりの理由やこだわりを持って取り組んでいます。

# 7. 原典や、一番いいものから学ぶ（でも疑ってかかる）

技術を勉強する際に、まずは公式ドキュメントやissueを熟読し、それを鵜吞みにせず実際に動かして検証しています。
結局それが一番近道なんですよね…
三流だと、とりあえずサンプルコードだけ読んでから書き始めてしまったり、雑な翻訳記事を根拠に作業を進めてしまったりします。

# 8. 調べたことや成果を形にして残す

一流の方は成果を残る形にしておき、次のプロジェクトでもそれを使って成果をあげています。
具体的には、技術情報をブログに残す、自分用のライブラリやスニペットを作るといったことです。

三流だと、とりあえず目の前の課題がクリアできたからOKとしてしまい、せっかく調べたことや頑張って書いた面倒なソースを自分のために残しません。
その結果、新しい仕事のたびに苦労する羽目になります。

# 最後に

私の狭い観測範囲の話ですので異論はあると思いますが、以上になります。

今回書くために思い出した方々は、社内やプロジェクトで引っ張りだこで仕事が途切れることがない、素晴らしいエンジニアだったなと思います。
私も少しでも近づけるように頑張っていきたいと思います。
現場からは以上です。
iOSでもバックグラウンドでWeb Audio APIの音が鳴るようにする

## 問題提起
iPhone、iPadなどに搭載されているmobile safariの仕様により、WebAudioAPI経由で出した音はホーム画面に戻った際に中断されます。
もう一度safariを開いた際に音は中断したところから再開されますが、以下のコードを記述すればバックグラウンドでも音が再生され続けます。

## 解決策
```javascript:解決策.js
/* let audioContext; */

window.addEventListener("visibilitychange", () => {
    if (document.visibilityState !== "hidden") {
        return;
    }
    audioContext.resume();
});
```
もっといい方法があれば教えてください🙇‍♂️

### 参考文献
https://developer.mozilla.org/ja/docs/Web/API/Document/visibilitychange_event

https://kimizuka.hatenablog.com/entry/2015/07/16/194116#google_vignette

https://bugs.webkit.org/show_bug.cgi?id=231105

(最終閲覧日はいずれも2024/06/08)