OmniAICreator/Qiita-1.07M huggingface dataset:
Firebase App HostingでNextJSのホスティングができるようになったけど、ハマった

Firebase で NextJSのホスティングができる機能となる [App Hosting](https://firebase.google.com/products/app-hosting?hl=ja) が使えるようになっていたので、触ってみた。

いくつか詰まった箇所があったので記事に残しておく

# 1. NextJSのバージョン
App HostingではNextJSのバージョンは13.0.0以上である必要があった。
公式ドキュメントでは見つけられなかったが、ビルドを実行したところ、以下のエラーが発生していた。

```
WARNING: Unsupported version of next: 12.2.5
WARNING: Update the next dependencies to >=13.0.0
```
いじっていたNextJSが古すぎたので、最新のNextJSに更新することでビルドできるようになった。

# 2. 環境変数の定義（Cloud Buildが実行されるサービスアカウントの問題）
App Hostingではビルドは、GCPのCloud Build機能を使ってビルドされる。
そのため環境変数は apphosting.yaml を使う必要がある。
ここまではApp Hostingのページにも記載があり[ドキュメントも存在](https://firebase.google.com/docs/app-hosting/configure?hl=ja&authuser=0)していた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69167/6eec60ae-69d5-b236-d632-d0b2c6b7d71a.png)

ドキュメントに沿い、環境変数の定義を行い、GCPのシークレットマネージャーに環境変数と紐づける情報を設定し、ビルドを実行したところ、ビルドに失敗するようになった。

## 設定していた環境変数
```# apphosting.yaml
# Environment variables and secrets
env:
  - variable: FIREBASE_PROJECT_ID
    secret: APP_FIREBASE_PROJECT_ID
    availability:
      - BUILD
      - RUNTIME

  - variable: FIREBASE_PRIVATE_KEY
    secret: APP_FIREBASE_PRIVATE_KEY
    availability:
      - BUILD
      - RUNTIME

  - variable: FIREBASE_CLIENT_EMAIL
    secret: APP_FIREBASE_CLIENT_EMAIL
    availability:
      - BUILD
      - RUNTIME
```

## エラーの内容
```
Step #1: 2024/07/17 23:46:36 pinning secrets in apphosting.yaml: 
calling GetSecretVersion with name=projects/~~~~/secrets/APP_FIREBASE_PROJECT_ID/versions/latest: 
getting secret version: rpc error: code = PermissionDenied desc = Permission 'secretmanager.versions.get' denied for resource
'projects/~~~~/secrets/APP_FIREBASE_PROJECT_ID/versions/latest' (or it may not exist).
```
ざっくり纏めるとSecretManagerに定義した値へアクセス権がないというものであった。

Cloud Buildで実行されているため、Cloud BuildのサービスアカウントをCloud Buildの設定画面で確認し、IAM機能で、対象のサービスアカウントへ「Secret Managerのシークレットアクセサー権限」を設定しビルドするが同じエラーとなってしまった。
![スクリーンショット 2024-07-18 14.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69167/226c4a25-c441-94a0-b85f-f44029b81cf1.png)

## 結論
* サービスアカウントへ設定する権限は、 `secretmanager.versions.get` を使う場合は、Secret Manager Viewerの[ロール](https://cloud.google.com/secret-manager/docs/access-control?hl=ja)が必要であった
* App Hostingでビルドする場合は、Cloud Buildのサービスアカウントではなく、 `firebase-app-hosting-compute` のサービスアカウント使用されていた

とくに2番目のCloud Buildのサービスアカウントではないという箇所にハマった。

どのサービスアカウントでCloud Buildが実行されているかは、ビルドの詳細画面へアクセスし、
ビルドの概要→実行の詳細にて確認することができる

ここに行き着くまでにかなりの時間を要したので、誰かの参考になると幸いだ。
![スクリーンショット 2024-07-18 14.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69167/472e5673-9781-6184-ecbe-cbe3604188a6.png)

# 所管
us-centralのリージョンしかまだないが、これは正式リリースされればリージョンは増えるだろう。
最初のシークレットマーネージャーの部分には詰まったが、一度やってしまえば慣れてしまえばリリースは簡単。
SSRやSSGは試さなかったが、APIの機能はきちんと動いていることも確認できた。

vercelと比較して機能は少ないが、複数人で開発してサーバーレスでNextJSをホスティングしたいがコストは抑えたいというケースや、すでにFirebaseを使っているユーザーにとっては良い選択肢となりそうである。
【SwiftUI】@AppStorageでUserDefaultsをかんたんに

## はじめに
`@AppStorage`は、SwiftUIでUserDefaultsに簡単にアクセスするためのプロパティラッパーです。ローカルにデータを保持できるコードをより簡潔に書くことができます。iOS14から使用できます。

https://developer.apple.com/documentation/swiftui/appstorage

## `@AppStorage`のメリット
- 初期値設定、アクセス、変更、取得がかんたん
- 値が変更されたときにViewが自動的に更新される

コードを見るとメリットがより理解できると思います。

## 使い方
`@AppStorage("Key")`をプロパティに定義するだけです。変数が変更される度に自動的に保存され、通常の変数と同様に使用できます。


```swift
import SwiftUI

struct ContentView: View {

    // @AppStorageを使用してUserDefaultsのキーを入力
    @AppStorage("name") private var name: String = "Sauna1137"
    
    var body: some View {
        VStack {
            Text("Hi, \(name)!")
            
            TextField("名前を入力してね", text: $name)
        }
    }
}
```

上記コードではTextFieldに入力されたテキストは リアルタイムで"name"というキーでUserDefaults に保存され、View(Text)も更新されます。保存、取得など既存のUserDefaultsでは記述量が多く、明示的に保存する必要がありましたが`@AppStorage`を使用すれば不要なのがかなり便利ですね！

## まとめ
既存のUserDefaultsを知っていると`@AppStorage`はかなり使いやすくなっている印象です。
まだ知らないプロパティラッパーがあるので調べてみたいと思います。

## 最後に
私の働いている会社で経験の有無を問わず採用を行っています。
興味のある方は是非カジュアル面談から応募してみてください！

https://jambo-support.com/recruit_engineer/
[linux備忘]chatGPTにmanコマンドカテゴリを語呂合わせで考えてもらう

## chatGPTにmanコマンドカテゴリを語呂合わせで考えてもらう

前提
LINUCを受験予定の初心者
学習中の不明点をChatGPTに質問した結果を備忘・記録として書きます。
コードの整合性は確認しておりません

| カテゴリ | 説明 | 語呂合わせ | コマンド例 |
|----------|------|------------|------------|
| 1 | だれもが実行できるユーザコマンド | **「1番は だれでもいい(1) コマンドだ」** | `ls`, `cp`, `mv` |
| 2 | システムコール、つまり、カーネルが提供する関数 | **「2番は 2(9)屋のシステムカーネルサンダースが考案」** | `open`, `read`, `write` |
| 3 | サブルーチン、つまり、ライブラリ関数 | **「3(サン)の サブルーチン サンサン(3)日光輝くライブラリ」** | `printf`, `scanf`, `strcpy` |
| 4 | デバイス、つまり、/dev ディレクトリのスペシャルファイル | **「4番 デバイス ディレクターはヨン(4)様」** | `/dev/sda1`, `/dev/null`, `/dev/tty` |
| 5 | ファイルフォーマットの説明、例 /etc/passwd | **「5(ファイブ)は ファイルの フォーマット」** | `/etc/passwd`, `/etc/fstab`, `/etc/hosts` |
| 6 | ゲーム | **「6番は 昔のゲームは16bit」** | `nethack`, `fortune`, `tetris` |
| 7 | その他 例：マクロパッケージや取り決め的な文書 | **「7番 なんて(7)いいマグロのパック」** | `man`, `info`, `groff` |
| 8 | システム管理者だけが実行できるシステム管理用のツール | **「8番 蜂(8)と戦うのは管理人のさだ(sudo)め」** | `sudo`, `iptables`, `useradd` |
| 9 | Linux 独自のカーネルルーチン用のドキュメンテーション | **「9番 九州(9)のケンタの独自カーネルだ」** | `spin_lock`, `schedule`, `copy_to_user` |
| n | 新しいドキュメンテーション：よりふさわしい場所に移動されるだろう | **「nは 新しい ドキュメント」** | なし（ドキュメントの移動中） |
| o | 古いドキュメンテーション 猶予期間として保存されているもの | **「oは 古い ドキュメント」** | `ed`, `xedit`, `telnet` |
| l | 独自のシステムについてのローカルなドキュメンテーション | **「lは ローカル システム」** | `/usr/local/share/doc`, `/usr/local/bin` |
Azurite https SSL 証明書の検証エラー

# Azurite https SSL 証明書の検証エラー
ローカルとAzure上で、Azure Storageに接続する際、同じコードにしたいので
DefaultAzureCredentialでAzuriteに接続したいと思った

```test.py
config = os.environ

credential = DefaultAzureCredential()

storage_account_url = config["STORAGE_ACCOUNT_URL"]

blob_service = BlobServiceClient(storage_account_url, credential)

containers = blob_service.list_containers(include_metadata=True)
for container in containers:
    logging.info(f"{container['name']} {container['metadata']}")
```

```
STORAGE_ACCOUNT_URL=https://127.0.0.1:10000/devstoreaccount1
```


## Azuriteをhttpsで起動する
READMEにある様に、mkcertを使って、証明書の発行に必要なルート証明書を作成し、Azurite に使用できる派生証明書を作成して、それらを使ってAzuriteをhttpsで起動した
https://github.com/Azure/Azurite?tab=readme-ov-file#pem

```
brew install mkcert
mkcert -install
mkcert 127.0.0.1
Created a new certificate valid for the following names 📜
 - "127.0.0.1"

The certificate is at "./127.0.0.1.pem" and the key at "./127.0.0.1-key.pem" ✅

It will expire on 18 October 2026 🗓
```

![スクリーンショット 2024-07-18 14.45.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44351/1a9a5a08-73b8-d1df-77cc-16cd70eac737.png)

```
azurite --location .azurite --debug azurite.log --cert ./127.0.0.1.pem --key ./127.0.0.1-key.pem --oauth basic
```




test.pyを実行すると、HTTPS リクエストの SSL 証明書の検証エラーが発生した

```error.txt
Exception: ServiceRequestError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)
```

## どうやらpyenvだと、mkcert -installでインストールしたルート証明を見てくれてない・・・

```
% python
Python 3.10.13 (main, Oct 23 2023, 13:08:08) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import certifi
>>> certifi.where()
'/Users/********/.anyenv/envs/pyenv/versions/3.10.13/lib/python3.10/site-packages/certifi/cacert.pem'
```

```
% mkcert -CAROOT
/Users/********/Library/Application Support/mkcert
% cd "/Users/********/Library/Application Support/mkcert"
% ls
rootCA-key.pem	rootCA.pem
```

# 環境変数にセットして、再度実行したら解決した

```.zshrc
REQUESTS_CA_BUNDLE="/Users/********/Library/Application Support/mkcert/rootCA.pem"
```
asciidocで番号付きリストで番号が巻き戻る対策

asciidocでドキュメントを書くときに番号付きリストを使うのですが、表やコードを入れると番号が巻き戻ってしまうのでその対策を残しておきます。

### 番号付きリストを書いてみる
- 普通に番号付きリストを書く
```
. 番号付きリスト1
. 番号付きリスト2
. 番号付きリスト3
```

出力すると`1. 2. 3.`の様に自動採番されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/d967500d-169f-ed1e-2403-251f2887d736.png)

- 表を間に入れてみる
しかし、表を入れてみると・・・
```
. 番号付きリスト1
|===
| name | age | 説明 
| 田中 | 28 | 東京都出身です。
| 佐藤 | 21 | 神奈川県出身です。
|===
. 番号付きリスト2
. 番号付きリスト3
```
出力すると`1. 1. 2.`の様に自動採番されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/410b169d-8ca7-a46f-de8e-00e386bb9dd2.png)


### 対策する
https://www.woodscom.co.jp/asciidoc/asciidoc-%E7%AE%87%E6%9D%A1%E6%9B%B8%E3%81%8Dlist%E3%81%A7%E5%85%88%E9%A0%AD%E3%81%AE%E7%95%AA%E5%8F%B7%E3%81%8C1%E3%81%AB%E6%88%BB%E3%82%8B%E6%99%82.html#gsc.tab=0

こちらを参考にすると、`+`を入れると採番がもとに戻らないらしく、実際にやってみました。

```
. 番号付きリスト1
+
|===
| name | age | 説明 
| 田中 | 28 | 東京都出身です。
| 佐藤 | 21 | 神奈川県出身です。
|===
+
. 番号付きリスト2
. 番号付きリスト3
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/89e52330-123d-951c-f835-90f36a95b2f7.png)

うまく自動採番されました。

### 表にちょっとした説明を入れたいとき
表の上にちょっとした説明を入れると表の下部分の自動採番が崩れてしまいます。

```
. 番号付きリスト1
+
これは名前と年齢と出身地の表です。
|===
| name | age | 説明 
| 田中 | 28 | 東京都出身です。
| 佐藤 | 21 | 神奈川県出身です。
|===
+
. 番号付きリスト2
. 番号付きリスト3
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/e5d313ca-2b04-8013-4865-2693e367cc38.png)

これを直すにはその説明文も`+`で囲むと表の下も自動採番が継続してくれます。
```
. 番号付きリスト1
+
これは名前と年齢と出身地の表です。
+
|===
| name | age | 説明 
| 田中 | 28 | 東京都出身です。
| 佐藤 | 21 | 神奈川県出身です。
|===
+
. 番号付きリスト2
. 番号付きリスト3
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884542/2e4c6728-36df-f14c-0d47-a6c526090d91.png)
外部からデータベースを読み込むときのunique制約

## 概要

### 困っていたこと
Flutterで単語帳アプリを作っています。
データベースは、Driftというパッケージを使用していました。
（https://pub.dev/packages/drift）
あるカラムをユニークキーにしたくて、あとで追加で設定を加えたのですが、反映されませんでした。
データベースは、assetsフォルダにデータベースを入れて、それを読み込ませる方式をとっていました。

### 結論
CSVからDB  Browser for SQLiteでデータベースにする際にも、unique設定をしないといけませんでした。
Qiitaで質問させていただいて、解決できました。

## 詳細
### dartファイル
```dart
TextColumn get name => text().unique()();
```
カラムの定義に`unique()()`を付けます。

```terminal
flutter pub run build_runner build --delete-conflicting-outputs
```
上記をターミナルで実行して、自動生成ファイルを更新します。

### データベースファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663353/be2fa184-dcd8-ce70-86e9-2c98669cc93c.png)
DB Browser for SQLiteで該当のデータベースファイルを開いて、テーブルの名前の上で右クリック→「テーブルを変更」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3663353/3e3bf99d-6f22-9aa5-c034-cc55dcc1a4c4.png)

該当カラム（ここでは「name」）の「U」にチェックを入れます。
（スクショではPK（プライマリーキー）にもチェックが入っています。）

これで解決しました！！

## あとがき
私は初心者すぎて、こんなふうにしないといけないとは、思いつきませんでした…
教えていただいて、ありがとうございました！！
deleteメソッドの戻り値は、最後に削除した要素の値である

Action Mailerを使って、アプリに登録されている全ユーザにメールを送信するという実装をしたのですが、メールが飛ばないというような事がありました。
実際のコードがこちらです！
```ruby
@posts = Post.yesterday_liked_ranking_top_ten
mail(to: User.pluck(:email).delete(''), subject: default_i18n_subject)
# emailを登録していないユーザもいるので、空であれば削除する
```
emailを登録していないユーザもいるので、pluckして取得した値のうち、空文字は削除するといった実装です。
この時点で既にお気づきの方もいらっしゃると思いますが、この記述だとmailのto引数には空を渡してしまうのです。

実際にコンソールで挙動を確認してみましょう！
```ruby
>> emails = User.pluck(:email)
  User Pluck (1.0ms)  SELECT "users"."email" FROM "users"
=> ["", "", "hattsuan@example.com"]

>> emails.delete('') # deleteメソッドの戻り値は空
=> ""

>> emails # 配列からはちゃんと空文字は削除されている
=> ["hattsuan@example.com"]
```
deleteのリファレンスです。
https://docs.ruby-lang.org/ja/latest/method/Array/i/delete.html

コンソールでdeleteメソッドを実際に使って問題なかったので、メールが飛ばない原因に気付くまでかなり時間を要しました。
今回の反省点は2つあり、1つ目は、メール作成後のテストをプレビュー使って問題ないことを確認しただけだったことで、送信できるかどうかのテストが出来ていなかったことです。mailのspecを書くことも習慣化したいと思います。
2つ目は、コンソールで試した内容と、実際プロジェクトのコードに記述した内容がイコールになっていなかったことです。
学びがあって良かったと思います！

ちなみにですが、pluckとwhereを組み合わせられるみたいなので、pluckする前にwhereすると、Active Recordのメソッドだけで完結できるので、より読みやすいと思います。
```ruby
>> User.where.not(email: '').pluck(:email)
  User Pluck (0.3ms)  SELECT "users"."email" FROM "users" WHERE "users"."email" != $1  [["email", ""]]
=> ["hattsuan@example.com"]
```
コードの行数も減り、こっちの方が良いですね。
以上です。読んでいただきありがとうございました。

-追記-
delete_ifだと、戻り値は削除した後の配列の値でした。
https://docs.ruby-lang.org/ja/latest/method/Array/i/delete.html
```ruby
>> emails.delete_if{|email| email==''}
=> ["hattsuan@example.com"]
```
右クリックの「送る」メニューに「FFmpegで結合」を追加

## 概要
FFmpegとPythonがインストールされていれば、`SendTo`ディレクトリにスクリプトファイルを1つ配置するだけで、エクスプローラーの「送る」に「FFmpegで結合」メニューを作れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/f2a3efca-f241-ce90-c6b3-ed1c355634c2.png)

**万一プログラムの不具合で大事なファイルを失ってしまっても責任はおえません。すいません。**


## 実行環境

今回稼働確認を取った環境です。厳密にこのバージョンでなくてもある程度動くと思います。メモ程度に。

* Windows 11 Home
* Python 3.10.1
* FFmpeg 4.4.1

## 前提条件

* Pythonがインストールされていること
    * コマンドプロンプトで`python`と打つとPythonが起動すること
* FFmpegがインストールされていること
    * コマンドプロンプトで`ffmpeg`と打つとFFmpegが起動すること

## 導入手順

以下のファイルを配置してください。

* ファイル
    * `FFmpegで結合.bat`
     https://gist.github.com/tatesuke/246f6039b149ca5d7cc91544813502eb
* 配置先
    * `%AppData%\Microsoft\Windows\SendTo`
     ※↑の文字列をそのままエクスプローラーのアドレスバーにコピペでディレクトリに飛べます

以上。

## 使い方

動画ファイルを複数個選択してください
![ファイル選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/ccd785f6-1a32-c2cc-2645-400372fc6a31.png)

右クリックしてください。「送る」の中に「FFmpegで結合」メニューが表示されます。
![コンテキストメニュー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/1e1d6ccc-0104-0d11-b2f0-04cd8412009b.png)

「FFmpegで結合」をクリックすると、連結順、出力ファイル名を確認されます。
![cmd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/21381fd4-ef70-25cf-c454-071f56ed3a1d.png)

`yes`または`y`と入力してエンターキーを押すと選択したファイルがFFmpegで結合されます。
![cmd2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/98b9d875-fa7a-d815-43af-4847e0b75ba6.png)

![file2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29682/4dae9662-f2cf-c7d4-b23c-577cbc4350ce.png)

事故防止のため、`_`から始まるディレクトリに元の動画ファイルを退避させています。

## 注意
* 連結はファイルの名前順に行います
    * ただし「neko.mp4」「neko (2).mp4」のように末尾が「半角スペース(数字).拡張子」となっているファイルについては、数字なしのファイルを0として扱います。
        * 単純に名前順にすると「neko(2).mp4」→「neko.mp4」の順でになってしまいますが、このパターンだけは特別に「neko.mp4」→「neko (2).mp4」の順で連結します。

* 連結後のファイルは連結の最初のファイルの名前になります
* 同じカメラ、同じ設定で撮影した時に出力される動画を連結する意図で作っています
    * →縦横サイズとかフレームレートが異なるファイルに使った時何が起きるかは試していません
    * もちろん動画ファイル以外の組み合わせも試してません
* 字幕ファイルとかも試してません
* 改めてですが、万一大事なファイルを失ってしまっても責任はおえません

## 補足

プログラミング的な補足をしておきます。

### `.bat`ファイルにPythonスクリプトを書く
`FFmpegで結合.bat`はコマンドプロンプトのバッチファイルですが、1行目にこうかかれています。

```
@python -x "%~f0" %* & exit /b %errorlevel%
```

これはちょっとしたテクニックで、1行目を読み飛ばすようにPythonのインタープリタに指示することで、バッチファイルなのにPythonスクリプトがかけるようになります。

【参考】
Windowsでshebangもどき、またはバッチにスクリプトを埋め込む方法
https://qiita.com/snipsnipsnip/items/50e4ca88e3ce3f8cffda


### 「送る」メニューに表示される「SnedTo」ディレクトリ
Windows11では`%AppData%\Microsoft\Windows\SendTo`にスクリプトファイルや実行ファイル（またはそのショートカット）を配置すると、「送る」メニューに表示されます。

スクリプトでは選択されたファイルのパスを実行時引数として受け取ることができます。

```python
input_path_list = sys.argv[1:]  # 2番目以降の引数にファイルパスが渡る
```

### プログラムの内容
これといって特筆することはないです。
FFmpegに渡すリストファイルを作って、ファイル退避して、FFmpegを実行しているだけです。
日付や時間をうす〜く扱う~JavaScript編

# この記事のを書くきっかけ
「日付や時間の取り扱いについてうす〜く調べてみた〜その１」の続きです。
あれ、タイトル変わっちゃった。
計画立ててやらないといかんすね。汗

https://qiita.com/ikedachin/items/8d23fca666f3137fcfb1

そう、時間を扱うことがあって、少し苦労したので最小限必要なことを抜き取ってみました。

# なぜ薄く・・・なのか
これ、前回、書き忘れました。
理由は簡単。「**忘れるもん**」
細かく書いても読まないし、細かく理解しても忘れる。
繰り返せば覚えるんだけど、いや、日付や時間だけをずっと扱うことも少ない。
なので、「ああ、そんな感じだよね〜」っと理解できる程度にうす〜く扱っていきたいと思います。

# 公式というか、MDN
これは抑えておかねばならん。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date

# 復習
MDNを読むとわかりますが、1970年1月1日の0時0分0秒を基準にしてm秒単位でカウントアップしたものがシリアル値になります。
<br>
<br>

# 今の日付時刻を取得するもっともん簡単な方法
```JavaScript
let now = Date();
console.log('今の時間',now)
```
出力
```
今の時間 – "Thu May 09 2024 12:40:41 GMT+0900 (日本標準時)"
```
実はこれって結構落とし穴になりました。
とにかく、今の時間を出したい時はいいと思うけど、これでなくてもいい。
<br>
<br>

```JavaScript
let now = new Date();
console.log('今の時間2', now)
```

これは新しくコンストラクタを立ち上げる方法。`new`があるかどうかだけが違い。

出力は同じ
```
今の時間2 – "Thu May 09 2024 12:40:41 GMT+0900 (日本標準時)"
```
<br>
<br>


# 特定の日時を指定したい
ISO8601の拡張形式で指定しましょう。
`new Date`の引数に入れて表示します。

```JavaScript
date_str1 = '2024-02-01T08:21:15Z'
let date1 = new Date(date_str1)
console.log('date1',date1)
```

日本時間で表示されました。あれ？＋9時間。そうそう、指定した文字列の最後に`Z`を入れるとUTCになります。でも僕のパソコン（mac）は日本にあるので+9時間です。
```
date1 - Thu Feb 01 2024 17:21:15 GMT+0900
```

時間を省いて引数に入れます。
```JavaScript
date_str2 = '2024-03-01'
let date2 = new Date(date_str2)
console.log('date2',date2)
```
そうすると、UTCで0時0分0秒の日時を表示します。
またまた日本なので朝の9時になっています。グリニッジは0時0分。

```
date２ - Thu Feb 01 2024 09:00:00 GMT+0900
```

<br>
<br>


# 取得している日時を変更したい
一度取得した日時を変更します。

<br>
<br>

まずは今の時刻の再取得から
```JavaScript
let now = new Date();
console.log('now', now);
```
now – Thu May 09 2024 12:52:34 GMT+0900 (日本標準時)
<br>
<br>

シリアル値の表示
```JavaScript
console.log(now.getTime())
console.log('now', now)
```
1715226754009

<br>
<br>

2024年を1970年に変更
```JavaScript
now.setUTCFullYear(1970)
console.log('set1970', now)
```

set1970 – Sat May 09 1970 12:52:34 GMT+0900 (日本標準時)
<br>
<br>

時間をUTC0時に。
```JavaScript
now.setUTCHours(0)
console.log('set0h', now)
```

set0h – Sat May 09 1970 09:52:34 GMT+0900 (日本標準時)
<br>
<br>

月を１月に（０始まり）
```JavaScript
now.setUTCMonth(0)
console.log('set0month', now)
```

set0month – Fri Jan 09 1970 09:52:34 GMT+0900 (日本標準時)
<br>
<br>

日付を１日に
```JavaScript
now.setUTCDate(1)
console.log('set1date', now)
```
set1date – Thu Jan 01 1970 09:52:34 GMT+0900 (日本標準時)
<br>
<br>


時間差を計るときは、シリアル値で計算して表示するなど工夫すればなんとかなりそ。

```JavaScript
let start = new Date("2024-05-09T08:21:15");
console.log('start', start)

let goal = new Date();
console.log('goal', goal)

let diff = goal.getTime() - start.getTime()
console.log('different millisec', diff)

let diffTime = new Date(diff);
console.log('different', diffTime.toString())
console.log('different ISO', diffTime.toISOString())
```

start – Thu May 09 2024 08:21:15 GMT+0900 (日本標準時)
goal – Thu May 09 2024 18:27:21 GMT+0900 (日本標準時)
different millisec – 36366575
different – "Thu Jan 01 1970 19:06:06 GMT+0900
different ISO – "1970-01-01T10:06:06.575Z"

<br>
タイム計測した結果をテキストに変換する時なんかはISOで文字型に変換して抜き取った方が良さそうですね。
<br>
<br>



# ということで・・・

今僕ができる時間計算はこんな感じで行っています。
もっと良い方法を探してググってみよう。
関数、使ってますか？

## 今日はなんの話？
- プログラミングにおける「関数」のお話です

----
## 関数とは何か
- プログラミングにおいては**入力が同じなら常に同じ出力となる**性質のこと（不完全な定義）


----
## 関数の例
- 足し算

```js
function add(rh, lh) {
    return rh + lh;
}
```

入力が同じなら常に同じ結果となるので、**関数である**

----
## 非関数の例
- 1～100までの整数をランダムで返す
```js
function random() {
    return Math.floor(Math.random() * 100);
}
```
呼び出す度に結果が変わるので、**関数ではない**

----
## これは関数？
- DB更新
```js
function update(records) {
    const updateCount = db.updateRecords(records);
    return updateCount
}
```

----
## 関数の性質
- **入力が同じなら常に同じ出力**
- **副作用（関数の外に影響を及ぼさない）がない**


----
## 関数の性質と定数
- 引数のない関数は、つまり定数である
  引数がない＝状態は１つしかない＝定数

----
## 関数の何が嬉しいのか（今日はこれが最重要）
- 安全です！
  何が嬉しいって「副作用がない」＝「関数の中だけを見ればよい」
- ただし安全度は言語による

----
## 関数型プログラミング言語について
- 関数の利点を最大限発揮するように設計されたPG言語のこと
  Haskell/Elmが該当する
  変数なし／ループなし／メソッドなし／関数しかない、狭量かつ堅牢な言語
- 関数型PG言語でなくても、**関数を多く用いた実装は良い実装**

ちょっと目先は変わるが、定数を参照する箇所も少ない方が良い実装になります。

----
## 最後に（今日もっとも伝えたかったこと）
- 関数型PG言語でなくても、**関数を多く用いた実装は良い実装**（２回目）
- 経験上、変数がないとどうしても実装できない、というケースはほぼないです
- だまされたと思って、地道に関数を作ってください
エイリアシング

```
import numpy as np
import matplotlib.pyplot as plt

# サンプリング周波数と信号周波数を設定
fs = 1000  # サンプリング周波数 (Hz)
f_signal = 50  # 信号周波数 (Hz)

# サンプル数
N = 1000
t = np.arange(N) / fs

# 正弦波信号を生成
signal = np.sin(2 * np.pi * f_signal * t)

# エイリアシングを起こすためのサンプリング周波数
fs_alias = 2 * f_signal

# エイリアシングの影響を再現するために高周波成分を含む信号を生成
signal_aliasing = np.sin(2 * np.pi * f_signal * t) + 0.5 * np.sin(2 * np.pi * 1.5 * f_signal * t)

# FFTを計算
fft_signal = np.fft.fft(signal)
fft_freq = np.fft.fftfreq(N, 1/fs)

fft_signal_aliasing = np.fft.fft(signal_aliasing)
fft_freq_aliasing = np.fft.fftfreq(N, 1/fs)

# プロット
plt.figure(figsize=(14, 10))

plt.subplot(2, 2, 1)
plt.plot(t, signal, label='Original Signal')
plt.title('Original Signal')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)
plt.legend()

plt.subplot(2, 2, 2)
plt.plot(t, signal_aliasing, label='Aliased Signal (Sampling at {:.1f} Hz)'.format(fs_alias))
plt.title('Aliased Signal')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)
plt.legend()

plt.subplot(2, 2, 3)
plt.plot(fft_freq, np.abs(fft_signal), label='Original Signal FFT')
plt.title('Original Signal FFT')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.grid(True)
plt.xlim(0, 100)
plt.legend()

plt.subplot(2, 2, 4)
plt.plot(fft_freq_aliasing, np.abs(fft_signal_aliasing), label='Aliased Signal FFT (Sampling at {:.1f} Hz)'.format(fs_alias))
plt.title('Aliased Signal FFT')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.grid(True)
plt.xlim(0, 100)
plt.legend()

plt.tight_layout()
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759109/0643d76d-720b-7319-61ac-7597a1b697dc.png)
RSpecでRailsのテストを書いてみる

# はじめに
Railsの自動テストを学ぶにあたって、RSpecでの実装方法を勉強したので書き残していく。
Ruby:3.2.1
Rails:7.1.2
# RSpec のセットアップ
gemの追加。`rspec-rails`をGemfileに追加する。
```ruby:Gemfile
group :development, :test do
    gem 'rspec-rails'
end
```
テスト用のデータベースを設計。今回はSQLiteを採用。
```ruby:config/database.yml
test:
    <<: *default
    database: db/test.sqlite3
```
RSpecの基本的な設ファイルの追加。
```shell-session
$ rails generate rspec:install
```
## テストの作成
モデル/ビュー/コントローラーでそれぞれテストを作成していく。
RSpecの基本的な書き方は以下。
```ruby
RSpec.describe User, type: :mode do
    it "is valid with a name" do
        user = User.new(
        name: "test01")
        expect(user).to be_valid
    end
end
```
`RSpec.describe User, type: :mode`の部分は、Userモデルをテストしますよというようなニュアンス。
`it "is valid with a name"`の部分はexampleというもので、テストの内容を記載する。
今回だと、Userに対してnameのバリデーションがあるかを確認する。
実際のテストはexampleをネストさせて、その中に記載する。
`expect(user).to be_valid`の部分がテストの実処理で、`expect`に渡したオブジェクトを検証して`to be_valid`ではバリデーションが有効かどうかを確認している。
マッチャーの種類については[公式リポジトリ](https://github.com/rspec/rspec-expectations#built-in-matchers)を参照。
exampleには見出しを担う`describe`や条件分岐の`context`や事前処理の`before`などがある。

### モデルスペックの作成
以下コマンドで対象のモデルのSpeファイルが作成される。
```shell-session
$ rails g rspec:model モデル名
```
### コントローラスペックの作成
以下コマンドで対象のコントローラのSpeファイルが作成される。
```shell-session
$ rails g rspec:controller コントローラ名 --controller-specs --no-request-specs
```
AGVへの道は遠からじ ① 目標は低く、志は高く

　AGVなるものを作ろうと思う。完成しないかもしれない。私の後を勝手についてくる搬送車を想定している。試作機なので、重いものは乗せられない。
 
### ハードウェア
- Raspberry Pi 5 8GB
- 2組のモータ BLMR5100K-A-B+BLVD-KRD
- XBOXコントローラ


### ソフトウェア
　ROS2は初めて触るので、別途勉強中。
　CANopenの最新のまとめ記事；[ラズパイ5 ＋Python＋CANopenでモータを回す](https://www.denshi.club/parts/2024/04/razupai5.html)
- ROS2
- CANopen

### 環境
- Raspberry Pi 5 8GB
- 追加ボード；NVMe Base for Raspberry Pi 5 (NVMe Base by Pimoroni)
- Crucial クルーシャル P2シリーズ 500GB 3D NAND NVMe PCIe M.2 SSD CT500P2SSD8
- OS ubuntu24.04にROS2 Jazzy

### フレームから用意する
　アマゾンで、30mm角のアルミ部材を購入しました。フレームを組み立てた上には、アルミ板を張ります。
 - M6 ボルト （https://www.amazon.co.jp/gp/product/B086JKNKNP/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1）
 - SF2-30・30 SF9-322 400mm 8本
 - SF2-30・30 SF9-322 300mm 8本
 - SF2-30・30イエロー SFF-324Y 200mm 4本
 - 3030シリーズ アルミプロファイルコネクターセット 20個
 - 六角ドライバ 対辺5.0mm B-5400BP
 - 六角ドライバ 4mm BS4MM No.10660

![IMGP2150.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/1d0e4d98-6d29-004f-00f0-d06e32c2a4fe.png)

### モータは100W

　利用するモータです。オリエンタルモーター製で、用途は搬送車向けのように感じます。100Wモデルですが、400Wまで各種そろっています。

- BLMR5100K-A-B（BLDCモータ 100W　シャフト径12φ）
- BLVD-KRD（コントローラ modbusとCANopen対応）
- SOL5M8F（モータ・マウント）

 ![IMGP2157.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/54d2ef2f-617f-3831-6c00-a6379b5ed77f.png)

### どうも、車輪はカスタムで用意するらしいが市販品を探し出した
　車（タイヤ）です。 ロボショップ楽天市場店で購入しましたが、納期は長いです。
- 12mmシャフト用 ユニバーサル アルミニウム マウンティング ハブ
- 8 inch SmoothGripホイール 50A 

![IMGP2161.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/85b5892c-dd8e-b7b3-535f-6ed63489f242.png)
　車体の先頭には、自在タイプの車輪を一つ付ける予定です。

### そのほか
　アマゾンで購入したバッテリです。
- 5V出力；エレコム モバイルバッテリー 大容量 10000mAh USB PD対応 20W Type-C×1 USB-A×2
- 12VTAIWAN YUASA [ 台湾ユアサ ] シールド型 バイク用バッテリー [YT4L-BS高性能版] YTX4L-BS ブラック

　エレコムのモバイル・バッテリは、ラズパイ5につないで放置しておくと、約6時間うごいていました。モータとコントローラは別々の24Vで動かすべきですが、12V+12Vの1セットです。モータの動作可能電圧はDC15～55V、コントローラの定格電圧はDC24～48Vです。


　非常停止スイッチや、電源スイッチを用意しました。

*****
 
https://qiita.com/jamjam/items/9ad621bda6ab2e1d325b
【Unity】Editorでシーン上のオブジェクトを一括で置き換え方法

```c#:ReplaceMono.cs
using UnityEngine;
using UnityEditor;

public class ReplaceMono : MonoBehaviour
{
    public Transform LookRoot;
    public GameObject NewObj;
    public string matchName;
}

#if UNITY_EDITOR
[CustomEditor(typeof(ReplaceMono))]
// 継承クラスは Editor を設定する
public class ReplaceObjectEditor : Editor
{
    // parent直下の子オブジェクトをforループで取得する
    private static Transform[] GetChildren(Transform parent)
    {
        var ctransforms = parent.GetComponentsInChildren<Transform>();
        return ctransforms;
    }

    // GUIの表示関数をオーバーライドする
    public override void OnInspectorGUI()
    {
        // 元のインスペクター部分を表示
        base.OnInspectorGUI();

        // targetを変換して対象スクリプトの参照を取得する
        ReplaceMono tg = target as ReplaceMono;

        // public関数を実行するボタンの作成
        if (GUILayout.Button("Replace Object"))
        {
            Transform rootGOs = tg.LookRoot;
            var rootG = GetChildren(rootGOs);
            foreach (var n in rootG)
            {
                if (n.name.IndexOf(tg.matchName) != -1)
                {
                    var parent = n.parent;
                    var pos = n.position;
                    var name = n.name;

                    var newObj = UnityEditor.PrefabUtility.InstantiatePrefab(tg.NewObj, parent) as GameObject;
                    newObj.transform.position = pos;
                    newObj.name = name;

                    GameObject.DestroyImmediate(n.gameObject);
                }
            }
        }
    }
}
#endif
```

使用方法：
１.「ReplaceMono.cs」を適当にどこかのゲームオブジェクトにアタッチします。
２.インスペクタでチェックしたいゲームジェクトを設置し、「Replace Object」ボタンを押下します。
３.下記の画像は参考になります。（シーン内のCubeを別のスクリプトアタッチしたCubeで置き換えます）

元シーン、普通のCubeを三つで置く：
![スクリーンショット 2024-07-18 12.50.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757569/e6dc6409-c39e-4864-7000-be08422f2b3d.png)
置き換えしたいCubeのプレハブ作成：
![スクリーンショット 2024-07-18 12.49.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757569/11437933-b7a2-28b1-0baf-a77e00e9b9a4.png)
結果：
![スクリーンショット 2024-07-18 12.50.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3757569/2b089bfa-3551-df2f-2936-d0595136ebcb.png)
VBAのデバッグモードとボタンからの実行で処理速度が１０倍以上変わる？？？

結論だけ知りたい方は[こちら](#結論)

地味に沼にはまったので似たような方がいたときのためにナレッジを残しておきます


# ある日のこと
私は社内の業務を効率化することが趣味である。
今回は上司の依頼により貸出物の管理をカレンダーとして可視化するマクロの作成を行っていた。
ボタン一つ押すだけで貸出対象が何日から何日まで貸し出されるかを読み取りその期間に色をつけたカレンダーを作成するというシンプルなものだ。

## コード抜粋
```vb
Sub OptimizedMode(ByVal enable As Boolean)
    With Application
        .EnableEvents = Not enable
        .Calculation = IIf(enable, xlCalculationManual, xlCalculationAutomatic)
        .ScreenUpdating = Not enable
        .EnableAnimations = Not enable
        .DisplayStatusBar = Not enable
        .PrintCommunication = Not enable
    End With
End Sub

Sub カレンダー反映main()
    ' 最適化モードを有効にする
    OptimizedMode True
    ' カレンダーの色をリセット
    Call ResetCalendarColors
    
    Dim mainWs As Worksheet
    Set mainWs = ThisWorkbook.Worksheets("台帳")

    Dim reqNum As String
    Dim startDay As String
    Dim endDay As String

    Dim targetList() As Variant
    Dim oneDimTargetList() As String

    Dim i As Long
    Dim j As Long

    Dim lastRow As Long
    lastRow = mainWs.Cells(mainWs.Rows.Count, "A").End(xlUp).Row
    For i = 8 To lastRow
    '''
    'ここで配列に貸出物の情報をもろもろ配列に入れ込む
    '''
        Call ColoringDateRange(startDay, endDay, reqNum, filterdList)
        'ここは色塗り用の別関数
    Next i

    ' 最適化モードを無効にする
    OptimizedMode False
End Sub
''''
'色塗り処理の一部抜粋
    With targetSheet
        For Each strTarget In targetList
            pcRow = GetRowNum(targetSheet, strTarget)
            .Cells(pcRow, dayColumn).Interior.ColorIndex = colorNum
        Next
    End With

''''
```

# 問題発生
さて、完成しVBE上で実行して正常に動くことを確認できたマクロをボタンに登録し、改めて実行してみた。
なんと**遅い！！遅すぎる！！** のだ。
VBE上で実行していた時は体感で押したら１秒もせずに終わっていたのに、ボタンを押してからの実行だと８倍くらいかかっている気がしたのだ。

**は？？？** と思ったが何度試しても結果は変わらず。
検索に強いと話題の`perplexity.ai`を使用してかなりネットの大海を泳ぎまくっても似たような事象を見つけることが出来ない。
`OptimizedMode`はその試行錯誤の中で生まれた関数である。

`VBEからの実行:0.56s`
`ボタンからの実行:7.52s`

# 検証開始
さてこうなると原因が気になってくるのがエンジニアという生き物ではないだろうか。（少なくとも私は気になってしょうがなかった）

まず私は途中にブレイクポイントを設定し、一度改めてそこで配列の内容などを確認してから続きを実行した。
すると**早くなった**のである。なぜだ…。私は途方に暮れた。

ここで諦める私ではない。一度デバッグモードに入ってからだと早いし、VBE上でそのまま実行しても早い。ということは何かあるはずだとひたすらに実行を繰り返していた。

# 原因発見
試行錯誤を繰り返す中でふと気になる事象をまた発見した。
**ボタンを押した後マウスを動かさなければ**VBE上で実行したときと同じくらいの速度で完了するのである。
はて？これはこれでおかしいぞと思ったわけである。
ではボタンの上にカーソルがあるときとボタン上にカーソルが無いときでよく見比べたところ、**ボタンの上にカーソルがないときはやたらカーソルがチカチカしている**ことに気づいた。
ここまで読まれた方はなんとなくもう原因に気づいているだろう。

# 結論
```vb
Application.Cursor = xlWait
```
これを入れるだけで解決した。
どうやらボタンを押した後にマウスをセルの上に移動させていると、色塗り等の処理が発生するたびにマウスカーソルの変化が発生し、それにより処理が大幅に遅延していたというオチであった。
VBE上で実行するとアクティブウインドウがVBEなのでカーソルの変化はさほど発生せず通常通りのスピードで完了していたようだ。

最終的には
```diff
Sub OptimizedMode(ByVal enable As Boolean)
    With Application
        .EnableEvents = Not enable
        .Calculation = IIf(enable, xlCalculationManual, xlCalculationAutomatic)
        .ScreenUpdating = Not enable
        .EnableAnimations = Not enable
        .DisplayStatusBar = Not enable
        .PrintCommunication = Not enable
+        .Cursor = IIf(enable, xlWait, xlDefault)
    End With
End Sub
```
この一文を付け足すことで事象解決となった。


# まとめ
これまで遭遇したことのない事象だったため苦戦したがこれからはこういうこともあると頭において自動化を進めていきたい。
[Ruby] メール配信設定の処理における「大きな泥団子」を責務分離した上で、キャッシュ化した話

## 問題点
メール配信設定に関する機能についてです。

SendGrid では、メール配信を行うために （CNAME・ないし MX/TXT 形式の）DNS 登録・及び認証が必須となっており、その認証状態を確認するための [Domain Validation API](https://www.twilio.com/docs/sendgrid/api-reference/domain-authentication/validate-a-domain-authentication) が提供されています。

その DNS 認証を行うための処理をクラス化していたのですが、無関係の様々な処理（例えば「メール配信結果にまつわる情報取得など」）も役割を持たせられており、責務が肥大化し、いわゆる「大きな泥団子」と化していました。

その状態で過剰にリクエストされた結果、ある時 SendGrid API から Rate Limit 超過エラーを受け取るケースが発生しました。

## 分析
まず掲題の外部 API が許容している Rate Limit の詳細を確認しました。

公式ドキュメントを見ても詳細は書いていなかったため、実際に呼び出している箇所にログを仕込み、「何分・何秒間に何回までリクエストが許容されるか」を確認しました。

そして、それに耐え得る構成とするため、以下の方針を取りました。

## 解決方針1：責務分離
まず責務を分離するところから始めました。

「DNS 認証」を行う処理にそれ以上の責務を持たせるべきではないと考えました。
特に自社ではなく、外部連携先の API を呼び出している箇所なので慎重にならないといけません。

結果として、認証処理をクラス化し、利用が必須な箇所のみで呼び出すように API を新たに用意しました。

下記のようなイメージです。
```
class VerifyEmail
    def perform(email)
        res = SendgridClient.new.domains.validate(email)
        return true if res&.dig(:valid)
        return false
    end
end
```

## 解決方針2：キャッシュ化対応
REDIS を用いて認証情報のキャッシュ化を行いました。
いくら責務を分離したとて、過剰にリクエストされると同じ問題が起きてしまうからです。

なおキャッシュが有効化されている内は情報が更新されないので、その旨ユーザーへの注意喚起も忘れてはなりません。

REDIS にそれ用のキャッシュデータを持たせるため、DB ナンバーを指定した上で追加・取得・削除などの処理を適宜行わせるように修正しました。

下記のようなイメージです。
```
REDIS_CACHED_VERIFICATION_EMAIL_STATUSES = Redis.new(
   host: 127.0.0.1
   port: 6379
   db: 1
)
redis = REDIS_CACHED_VERIFICATION_EMAIL_STATUSES

# キャッシュの追加
redis.set(email, { status: is_verified }.to_json )

# 有効期限の設定（単位：秒）
redis.expire(email, 60)

# キャッシュの取得
res = redis.get(email)

# キャッシュの削除
redis.del(email)
```

## まとめ
今回の件で、改めて外部 API にリクエストしている箇所は注意が必要だと認識しました。
自社の持ち物ではないため、先方に迷惑をかけないような配慮が必要とされます。

また責務がごちゃ混ぜになった「大きな泥団子」は作業効率を優先して実装が行われると作られがちなので、注意していきたいところですね（自戒の意味も込めて）。
One-liner to Find the Longest Filename in the Current Directory

カレントディレクトリのファイルとディレクトリのうち、名前が最長のものを得るワンライナー

```shell
command ls | awk '{print length, $0}' | sort -rn | head -1 | cut -d' ' -f2-
```

AIに毎回作成させるのも面倒くさくなって……:sweat_smile:
【ChatGPT＋Code Interpreter】透過画像を作成して、ほかの画像に重ねます。


　どうも、カーブミラーです。

　今回は、透過画像を作成して、通常画像に重ねてみます。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。あしからず。
:::

　ニュースはないので、
　　本題に入ります。

　昨日（2024/07/17）は、
　　Code Interpreterで
　　　シンプルな図形を描きました。
[【ChatGPT＋Code Interpreter】でシンプルな図形を描く。](https://qiita.com/kabumira/items/f00737e26ad471ecae0c)

　今回は、
　　同じ図形を
　　　透過画像として
　　　　作成します。

　透過画像とは
　　なんでしょうか？

　ChatGPTさんに
　　尋ねてみました。
***
***user***
透過画像とはなんですか？

***ChatGPT***
透過画像とは、背景が透明な画像ファイルのことを指します。透明な背景を持つことで、画像を他のデザインや背景に重ねた際に違和感なく表示されます。一般的に、透過画像の形式としてはPNG（Portable Network Graphics）やGIF（Graphics Interchange Format）がよく使用されます。

透過画像を作成するには、画像編集ソフト（例えば、Adobe PhotoshopやGIMP）を使って、画像の背景部分を透明に設定します。透過画像は、ウェブデザインやグラフィックデザインなどで頻繁に使用されます。
***

　ChatGPTでふつうに
　　“背景を透過にしてください”と
　　　指示して、DALL-E3で描画させると
　　　　斜め格子の背景になります。

　実は、これは透過になっていません。

　DALL-E3に
　　透過画像を
　　　生成できる機能は
　　　　ないのです。

　ではどうしたら？

　専用ツールを
　　使うしかありません。

　もちろん、
　　Code Interpreterには
　　　透過処理できる機能はあります。

　しかし、
　　複雑な画像を
　　　透過するのは難しいのです。

　そこで
　　Code Interpreterに
　　　最初から透過画像を
　　　　描かせればいいわけです。

　もちろん、
　　複雑な画像は
　　　作成できません。

　今回は
　　この“Code Interpreterに描かせる”を
　　　テーマにしています。
***
　さて、
　　本題の本題です😅

　では、
　　透過画像を作成する手順です。

　❶GPT-4oであることを確認
　❷Prompt入力
```Text:
CodeInterpreterを使って、透過画像を作成してください。ただし、下記の要素も含みます。

作成する画像は、以下のとおり。
・白い横棒
・白い丸
・白い横長の楕円

なお、画像は別々に作成してください。
```
　❹送信
　❺ダウンロードリンクが表示
***
　次に、
　　透過画像を
　　　ふつうの画像に
　　　　重ねる手順です。

　念のために、
　　新たなセッションを
　　　開きます。

　❶GPT-4oであることを確認
　❷透過画像と通常画像をアップロード
　❸Prompt入力
```Text:
CodeInterpreterで、最初の透過画像をサイズをそのままに、次の画像に重ねてください。
コードは必要ありません。
```
　❹送信
　❺ダウンロードリンクが表示
***
　上記の手順のサンプルとしての
　　アップロード画像が
　　　こちらになります。
![white_ellipse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/e3c86390-0f7c-2f67-6e65-3c8e38eb588d.png)
![flipped_image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/3fc379ae-2b24-5973-cf7d-e90d8f45d2ea.png)

　重ねた画像が
　　こちらになります。
![combined_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/887992d7-805c-2246-1554-0ee4005d984a.png)

　注意して欲しいのは
　　両方の元画像が
　　　サイズが違う、ということです。

　透過画像は、154×154
　通常画像は、1024×1024　です。

　指定しないと
　　ChatGPTさんが
　　　通常画像にサイズを合わせて、
　　　　透過画像を大きくします。

　また、ファイルフォーマットも
　　透過画像はPNG（またはGIF）
　　通常画像はWebP（またはJPEG）
　　合成画像はPNGになります。

　もちろん、
　　サイズやフォーマットは
　　　指定可能です。

　こういうのがあったな、と
　　知っておけば、あとで困ったときに
　　　“あー、あったな”とわかり、
　　　　調べられるかと思います。

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。
グループ宛てに結果メールを送信するようにする【PowerAutomate】

## 1.グループ宛てに結果メールを送信する

![図面 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/e318f0a4-e2a4-aadc-fc75-6f02468c5da1.png)

※RPAのフロー送信完了後は上記画像のようにフロー終了後に成功Or失敗メール送信するのが一般的だと思いますので上記画像を載せておきます。

UipathやAutomationAnywhereから
Office365のPowerAutomateで自動化を行うようになって
最高に便利でやないの…！と感じたのは
グループ宛てにメール送信ができることです。

:::note warn
フロー管理側でフローの送信先を変更したくない人は参考にしてみてください
:::

## 2.メールの送信先として使えるグループ

メールの送信先として、なんと下記を利用できます。

:::note info
1.SharePointのサイトメンバー
2.Teamsのグループ
3.Outlookのグループ
:::

上記はユーザーのほうで変更してもらえますよね！

:::note warn

ただし上記はメール送信先が999人以下の時のみです。
※大体、メールの送信先はそんなにたくさんいらっしゃいませんよね。
:::


## 3.実際にフローを作成してみる
今回は既存のグループを利用したいと思いますので、
Teamsのグループをフローで利用します。
ではPower Automateのアクションを追加していきましょう。

使用するのは
グループをOutlookのメール送信先とするには
Office365グループのアクションと、データ操作のアクションが必要となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/90ebc7af-5405-1661-07ea-5fa47367184b.png)


【グループメンバーの一覧表示】のアクションを追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/46d69af3-04c7-b864-1fe1-6c1dd23a4627.png)
グループIDの所にメールの送信したいグループを選択する
全ての表示をクリックして上に999と入力(取得できるのは999人まで)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/046a8005-94c3-9bcb-09d9-ced8c6804fb4.png)
同アクション＞設定＞改ページ＞しきい値を999と入力

【選択】のアクションを追加

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/b6bacfbf-f91a-90ab-344f-a09af65225c1.png)
Fromにvalueを追加
赤枠のテキストモードに切り替えをクリックして切り替え、
Mapにメールの項目を追加

【結合】のアクションを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/4b6b5acc-9cc9-171b-c2a6-366f0ffa1e82.png)

メール送信先となるようにすべてのメールアドレスを;でつないでいきます。
Fromに選択アクションの結果(Output)を追加
Join Withに;(セミコロン)を追加

結合のアクションについてもっと知りたい場合は下記内容を参照されるとよろしいかと思います。

https://learn.microsoft.com/ja-jp/power-automate/data-operations#use-the-join-action

これでメール送信先一覧として、すべてのメールアドレスを；で結合できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/4183f080-7fb8-e268-1fe5-509788cbe738.png)
あとはメールの宛先に結合の結果(output)を追加すれば、常に最新のメンバーグループにメール送信が可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111714/d8487a5e-6782-a9a6-8815-03727dc5987d.png)


## 最後に

フロー作成にあたり、業務を全てユーザーから吸い上げる形になりがちですが
今回説明したメール送信先など恒常的に管理が必要な部分はこちらで全て引き受けるのではなく
相手におまかせしたほうが押しつけがましくなくお互いにとって良い結果をもたらすことも多いと感じています。

Office 365だとExcelやOutlookとの連携が最初からできているので、そのあたりが組み立てやすく
使いやすいなと思っています。
Buffaloの Tagged,Untaggedがわからないので調べてみた。

# 調べた内容

* アクセスポートにはタグがつかない
* トランクポートにはタグが付く、ただしnativにはつかない

|トランク内でタグ付けなし(いろいろな呼び方)|
|---|
|native vlan|
|default vlan|
|PVID|

## 対応表
|access,trunk|tagged,untagged|
|--|--|
|access vlan 10|untagged 10|
|trunk vlan 10,20|tagged 10,20|
|trunk vlan 10-30 native vlan 10|untagged 10 tagged 20,30|



## 
|各ポートで|
|---|
|tagは０個以上|
|untagは０~１個|


## 勉強になったこと
* Native VLAN の不一致は、特に PVSTP ではループの検知が出来なくなる可能性があるため、エラーにも出力されます


## 追記
### HybridとMultipleについて
* chatgptさんへ質問してみた

1. Hybrid（ハイブリッド）
「Hybrid」は、TaggedとUntaggedのトラフィックを同時に処理できるポート設定です。
Hybridポートは、指定されたVLANのトラフィックをタグ付きとして処理し、一部のVLANのトラフィックをタグなしとして処理することができます。これにより、トランクポートとアクセスポートの両方の役割を担うことができます。
用途: 同一ポートに対して、複数のVLANのトラフィックを処理しつつ、一部のデバイス（VLANタグを扱えないもの）に対してタグなしのトラフィックを送信する場合。
例: 特定のVLANタグを理解できるサーバやスイッチと、タグなしトラフィックを使用するPCが混在する場合に使われます。

1. Multiple（複数）
「Multiple」は、複数のVLANに対してUntaggdとして接続する設定です。
通常、1つのポートは1つのVLANに対してUntaggedとして扱いますが、Multiple設定では、同じポートで複数のVLANに対してUntaggedとして接続できるようにする設定です。
用途: 例えば、複数の異なるVLANに同時に接続する必要がある場合、特定のポートでそれぞれのVLANのUntaggedトラフィックを処理します。
### VLAN設定のイメージ
* Tagged: 複数のVLANのトラフィックがタグ付きで1本のケーブルを通る
* Untagged: 特定のVLANのトラフィックだけがタグなしで通る
* Hybrid: TaggedトラフィックとUntaggedトラフィックが同時に扱われる
* Multiple: 複数のVLANにUntaggedで参加するポート設定
### まとめ
* Tagged: 複数のVLANトラフィックをタグ付きで運ぶ（主にトランクポート）
* Untagged: 特定のVLANトラフィックをタグなしで運ぶ（主にアクセスポート）
* Hybrid: TaggedとUntaggedを同時に処理可能
* Multiple: 複数のVLANにUntaggedで参加

## 参考
* [結構このページが噛み砕かれていてわかりやすかった。](https://milestone-of-se.nesuke.com/nw-basic/ethernet/tag-native-vlan/)
`pandas.json_normalize([{"a":{}}])`で生成したDataFrameには`a`列は存在しない

# 環境
* Python 3.12.4
* pandas 2.2.2

# はじめに
ネストされているdictのlistをpandas.DataFrameで扱うため、[pandas.json_normalize](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.json_normalize.html)を使ってpandas.DataFrameを生成しています。


```
In [104]: data=[{"a":{"x":1,"y":2}, "b":"alice"}, {"a":{"x":4}, "b":"bob"}]

In [108]: df = pandas.json_normalize(data)

In [109]: df
Out[109]:
       b  a.x  a.y
0  alice    1  2.0
1    bob    4  NaN

```

# ハマったこと

変数`data2`のキー`a`の値は空のdictです。`pandas.json_normalize`で生成した場合、`a`列に`None`が格納されることを期待したのですが、実際には`a`列は存在しませんでした。


```
In [111]: data2 = [{"a":{}, "b":"alice"}]

In [115]: df2 = pandas.json_normalize(data2)

In [116]: df2
Out[116]:
       b
0  alice

```

ネストされたdictでも同様でした。

```
In [117]: data3 = [{"a":{"x":{}}, "b":"alice"}]

In [118]: df3 = pandas.json_normalize(data3)

In [119]: df3
Out[119]:
       b
0  alice
```

変数`data4`のキー`c`の値は`None`です。この場合は、DataFrameに`c`列は存在しました。

```
In [120]: data4 = [{ "b":"alice", "c":None}]

In [121]: df4 = pandas.json_normalize(data4)

In [122]: df4
Out[122]:
       b     c
0  alice  None
```
雑念を捨て、集中して学習するための10の方法


どうも、みなさん！今日は勉強に集中するための10のコツをお届けします。ええ、僕も昔はスマホをいじったり、ぼーっとしたりで集中力ゼロだったんです。でも、いくつかの方法を試してみたら、びっくりするほど効果があったんですよ。それでは、さっそくいってみましょう！

### 1. **デジタルデトックス**
スマホやパソコンの通知は誘惑の塊。勉強する時間は、スマホをサイレントモードにして、できれば別の部屋に置いちゃいましょう。最初は辛いけど、慣れればスッキリ！

### 2. **タイマーを使う**
ポモドーロテクニック、聞いたことありますか？25分集中して5分休憩する方法です。タイマーをセットして、25分間だけ全集中！思ったよりも捗りますよ。

### 3. **リラックスできる音楽を**
カフェの雑音や自然の音がおすすめ。歌詞がない音楽もいい感じです。SpotifyやYouTubeで「集中できる音楽」を探してみてください。

### 4. **目標を明確にする**
「今日はここまでやる！」って具体的な目標を立てると、達成感がアップします。大きな目標を小分けにして、1つずつクリアしていきましょう。

### 5. **ご褒美を用意する**
頑張った後には自分へのご褒美を！チョコレートや好きな飲み物、一話だけドラマを見るとか。モチベーションがぐんと上がりますよ。

### 6. **運動する**
軽いストレッチや散歩でリフレッシュ。血行が良くなって頭もスッキリします。5分間の運動でも効果は絶大です。

### 7. **環境を整える**
勉強スペースをきれいにしましょう。必要なものだけを机に置いて、不要なものは片付ける。視界がクリアになると、頭の中もクリアになります。

### 8. **休憩を忘れずに**
人間はそんなに長時間集中できない生き物です。1時間に1回は短い休憩をとりましょう。お茶を飲んだり、軽くストレッチしたりしてリフレッシュ。

### 9. **姿勢を正す**
背筋を伸ばして、座り心地の良い椅子に座る。猫背だと集中力も落ちちゃいます。姿勢が良いと、自然とやる気もアップ！

### 10. **ポジティブに考える**
「できない」と思うと本当にできなくなります。「できる、やれる、自分はすごい！」とポジティブに自己暗示をかけてみましょう。自己肯定感が上がると、意外と何でも乗り越えられます。

---

以上、雑念を捨てて集中するための10の方法でした。どれも簡単に始められるものばかりなので、ぜひ試してみてくださいね！みなさんの勉強が少しでも捗るように、心から応援しています。
なーんて、おそらく僕は今日も集中できずyoutubeで猫の動画を見てますけどね！アデュー！
【メモ】Session ManagerでEC2に繋がらないとき確認すること【二度と忘れない】

## 事の始まり
プライベートサブネットにインスタンス立てたけどセッションマネージャーで繋がらない！
どうすればいいかわからん！誰か助けて！

## 確認すること
### SSM Agentはインストールされているか？
そのAMI、デフォルトでSSM Agentはインストールされていますか？
インストールされていない場合は、ユーザーデータ等で手動インストールしましょう。


【参考】Amazon EC2 Linux インスタンスの起動時に SSM Agent をインストールする方法を教えてください。
https://repost.aws/ja/knowledge-center/install-ssm-agent-ec2-linux


### IAMロールは適切ですか？
EC2インスタンスにアタッチしているIAMロールに**AmazonSSMManagedInstanceCore**はアタッチされていますか？


### VPCエンドポイントありますか？
Session Managerで接続する場合、3つのVPCエンドポイントが必要です。

- **ec2messages.region.amazonaws.com**
- **ssm.region.amazonaws.com**
- **ssmmessages.region.amazonaws.com**

→インターフェース型エンドポイントのセキュリティグループは、EC2インスタンスからの443ポートの通信を許可します。


### セキュリティグループは正しく設定されているか？
アウトバウンド通信で443ポートが、パブリックエンドポイントであるSSM エンドポイントへ通信可能な状態ですか？


### NATゲートウェイを配置する場所間違ってませんか？
パブリックサブネット側にNATゲートウェイが配置されていて、VPCにインターネットゲートウェイがアタッチされていますか？

## 終わり

いかかでしたか？参考になりましたか？
Redmine からのメールのタイトルに優先度と担当者を追加する

Redmineからのメール通知を見落とさないようにしたいという要望があったので対応したときのメモ。

メールタイトルに [優先度][担当者名] が含まれるので仕分けが容易になります。

ソースを書き換える必要があります。

編集するファイル
\Bitnami\redmine-4.2.3-1\apps\redmine\htdocs\app\models\mailer.rb

2箇所修正します。

## チケット本文

「subject =」 を探して下記を追加します。

優先度："[#{issue.priority.name}]"
担当者："[#{issue.assigned_to.name}]" if issue.assigned_to

:::note warn
if 以下がないと担当者の指定がない場合、ウォッチャーにメールが送信されません。
:::

```mailer.rb
 subject = "[#{issue.priority.name}]" 
 subject += "[#{issue.assigned_to.name}]" if issue.assigned_to
 subject += "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]" 
 subject += " (#{issue.status.name})" if Setting.show_status_changes_in_mail_subject?
 subject += " #{issue.subject}" 
```

## チケットの返信

 「s =」 を探してください。
 subject = と同様に修正します。

```mailer.rb
 s = "[#{issue.priority.name}]" 
 s += "[#{issue.assigned_to.name}]" if issue.assigned_to
 s += "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] " 
 s += "(#{issue.status.name}) " if journal.new_value_for('status_id') && Setting.show_status_changes_in_mail_subject?
 s += issue.subject
```
今日実施する家事をランダムで通知してくれる家事おみくじ

# 家事をおみくじ形式で通知できるアプリを作りたい。
みなさんこんな声を聞いたことはありませんか？

:::note
・家庭内での家事の分担が偏っているので、相手にも協力してほしい。
:::

我が家も家事の分担が偏っているので、家庭内での不満を解消するべく、家事をおみくじ形式で通知してくれるような（重い腰を上げる手助けになるような）アプリを作りたい。

\
＜アプリイメージ＞
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/ffa3ee11-39b2-7eac-1306-89bb940d05d1.gif)



# 使用環境
・Make
・Google スプレッドシート
・Google Apps Script



# アイデア
①．通知したい家事を一覧にしておき、そこからランダムに一つを選択する。
②．選択した家事をラインに通知する。
③．お楽しみ要素としておみくじ機能も搭載する。


# 実装①：家事を一覧の作成
Google スプレッドシートに通知したい家事と運勢の一覧を作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3775986/a653da23-3815-3bb7-c40e-a74955345509.png)


# 実装②：家事一覧からランダムに一つを選択する。
実装①で作成した一覧からランダムに１行分運勢と家事の情報を取得させる。
スプレッドシート状の行番号を配列（seq）として定義して、random関数でランダムに番号を取得する。

```js
  //家事番号
  const seq = [2,3,4,5,6];

  //送信する家事をランダムにピックアップ
  const randomnum = seq[Math.floor(Math.random()*seq.length)];
  
  unsei = sheet.getRange(randomnum,2).getValue()
  housework = sheet.getRange(randomnum,3).getValue()

```
</details>


# 実装③：LINEにメッセージを通知する。
Google Apps ScriptでGoogle スプレッドシートからメッセージを取得し、Makeを経由してLINEに向けて発信する。

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

```js
function housework() {
  //■テーマ■
  //家事をおみくじみたいにランダムにラインで送信

  //makeのwebhookのURL設定
  const url = "webhookURL";

  //アクティブなシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();

  //家事番号
  const seq = [2,3,4,5,6];

  //送信する家事をランダムにピックアップ
  const randomnum = seq[Math.floor(Math.random()*seq.length)];
  
  unsei = sheet.getRange(randomnum,2).getValue()
  housework = sheet.getRange(randomnum,3).getValue()

  console.log(unsei);

  if (unsei == "大吉"){
  Sendmessage = "おめでとう！今日の運勢は" + unsei + "だ！\n"
              + housework + "をして最高の一日にしよう！"
  } else if(unsei == "凶"){
  Sendmessage = "残念！今日の運勢は" + unsei + "だ！\n"
              + housework + "をして運気を上げよう！"
  } else {
  Sendmessage = "今日の運勢は" + unsei + "だ！\n"
              + housework + "をしてさらに運気を上げよう！"
  }

    console.log(Sendmessage);

  //makeを使ってLINEにメッセージを通知
  UrlFetchApp.fetch(url + encodeURIComponent(Sendmessage));

}

```
</details>


# 改良点
:::note warn
・通知をLINE等、スマホから直接出せるようにしたい。
・完了したら完了通知を返送できるようにしたい。
:::
PSPPを使おうとしたけどすぐにあきらめた件

## PSPPとは
PSPPは統計解析のためのフリーソフトウェアである。GUIとコマンドライン操作の両方で利用することができる。C言語で書かれており、内部では数値計算にGNU Scientific Libraryを、プロットの描画にGNU plotutilsを使っている。PSPP は、商用の統計解析ソフトウェアのSPSSと同等の機能を実装することを目的として開発が進められている。 

PSPPの開発プロジェクト（かつては "Fiasco" と呼ばれていた）は、SPSSのフリーなオープンソースの互換ソフトウェアを作り上げることを目的としている。SPSSのソースは公開されておらず、利用条件には厳しい制限とDRMが課せられているため、ライセンスを更新しなければ限られた期間だけしか使うことができない。それはおかしい、納得できない、とPSPPの開発者は考え、ライセンスの期限切れ以外はSPSSと同じ機能を持つソフトウェアを開発し、万人が共有、改良できるものにしたいと考えた。 

https://ja.wikipedia.org/wiki/PSPP より

## PSPPを利用しようとしたきっかけ
SPSS は高価である。　学生版のライセンスでさえ、Amos とセットだと3万円以上する。
大学まで行けば使えるものの、片道90分ほどかかるので、できれば自宅で作業したい。
そこで以前に名前を聞いたことのある 無料で利用できる PSPP を評価してみることにした。
今回は「研究事例で学ぶ SPSSとAmosによる信じ・調査データ解析」の、データを使ってできることの確認と答え合わせしてみようと思う。

## インストールしてみた
本家サイト https://caeis.etech.fh-augsburg.de/downloads/windows/latest-release/ 
からインストーラーをダウンロード、実行するだけ。
主な表示は特に日本語化することなく、最初から日本語であった。

起動すると、SPSSでおなじみの「データビュー」「変数ビュー」の画面が出てくる。
![PSPP初期画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1252322/a97cde6a-b11a-69c1-a0ad-121accae3c4b.png)

## 変数とデータを入力してみた
早速、Excel からデータをインポートしようとしたけどできない。
SPSS だと、直接 Excel形式のバイナリ(.xlsx) からインポートできるが対応していない。

手入力で試してみる。
### データビュー
・Excel からのコピペで無事完了。
### 変数ビュー
・Excel からも、メモ帳のプレーンテキストからもコピペさせてもらえない。
やむなく手動で30個ほどやってみた。

### CSVからのインポート
ここでようやく、インポート機能があることに気が付き、使ってみる。
Excel のデータを CSV に変換して、インポートしてみるとエラーに、プログラムが怪しい💦
念のためファイル名を日本語から英語に変更してみたら読み込めた。
変数ビューは問題なかったが、データビューの1行目に、なぜかゴミが入る。

## 基本統計量を出してみる
フロア効果、天井効果を確認するために、まず基本統計量を出してみる。　メニュー構成は似ていて迷わない。
なぜか空白のままだが、メニューから書き出しを選んだ瞬間に結果が表示される、プログラムが怪しい💦
![基本統計量.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1252322/ba4d7324-b802-2596-2169-fc652643843b.png)
ここから、平均±標準偏差を計算するために、SPSS だったら、
ダブルクリックして編集画面 →  Excel にコピペ → 数式入力、条件付きセルで色分け
の流れになるが、PSPPでは
CSVファイルに書き出し → メモ帳で開いて「BOM付きUTF8」で保存 → Excel で読み込んで作業
に、なる。　 
「BOM付きUTF8」でないと読めないのは Excel が悪いけれども、面倒くさい💦

## スクリープロットを出してみる
「分析」メニューに因子分析は無いが、「Factor Analysys」があるので選択して、オプションを開くとスクリープロットにチェックできるので出力してみる。
ここもなぜか空白のままだが、メニューから書き出しを選んだ瞬間に結果が表示される、プログラムが怪しい💦
![スクリープロット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1252322/2a846208-99dc-71c4-1308-bd077f84b15c.png)

## 因子分析をしてみる
スクリープロットを見て、3因子でやってみたい。　そして何はともあれプロマックス回転したい。

が、
![ない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1252322/c0c1ad17-f600-0533-24bf-127b4d38f4c4.png)

どこにもそれらしき設定がなく、検証終了💦

## SPSS の結果表示
PSPP での、因子分析はあきらめて、SPSSで計算した結果の表示を試してみる。
因子分析した後に *t* 検定した結果を SPSSの表示形式(.spv)にしてあったが、読み込めなくて、、
こちらもファイル名を英数字のみに直したところ読み込めた、プログラムが怪しい💦

![因子分析の後にt検定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1252322/e1cca63e-80b2-73ac-d40d-07739c24551d.png)

これは便利！と一瞬思ったものの、ここから編集できるわけでもないので、SPSS で PDFにしておけば良いのではないかということで、特に使い道はなかった。

## 結論
R と HAD で頑張ります！
Python を使って MySQL に接続しようとしたところ、いくつかエラーがでたので解決策をメモ

## はじめに
pythonをつかってmysqlに接続しようとしたところ、少しつまずいたので、メモがてら記事を書いています。

### 今回解決できたエラー

- *mysql.connector.errors.DatabaseError: 2005 (HY000): Unknown MySQL server host*
- *mysql.connector.errors.ProgrammingError: 1045 (28000): Access denied for user*

### 今回の環境
- ラズパイで dokcer のコンテナ使用(mysql server 側)
- 同じネットワーク内のメインPCから接続する(Python側)

<br?>

## 本文

### python側の修正
port番号の指定をhostと分けて指定する必要があった。

- 誤り
  ```python
  import mysql.connector

  def conn_db():
     conn = mysql.connector.connect(
        host = "192.168.0.***:3306",
        user = "root",
        password = "password",
        database="test"
    )
    return conn
  ```
<br>

- 正しい
  ```python
  import mysql.connector

  def conn_db():
     conn = mysql.connector.connect(
        host = "192.168.0.***",
        port = "3306"
        user = "root",
        password = "password",
        database="test"
    )
    return conn
  ```

### リモート接続の権限付与
localhostではないため、接続の権限を付与しなければならなかった。

:::note warn
localのrootでmysqlに入り、以下のコマンドを実行します
:::
<br>


- リモート接続用のユーザーの作成
  ~~~
  CREATE USER 'root'@'192.168.0.***';
  ~~~
<br>

- 作成したユーザーのパスワードを割り当て
  ~~~
    ALTER USER 'root'@'192.168.0.***' IDENTIFIED BY 'password';
  ~~~
  <br>

- 作成したユーザーに権限付与
  ~~~
  GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.0.****' WITH GRANT OPTION;
  ~~~
  <br>

- 権限の変更を有効化
  ~~~
  FLUSH PRIVILEGES;
  ~~~

## 参照
https://dev.mysql.com/doc/refman/8.0/ja/create-user.html

https://dev.mysql.com/doc/refman/8.0/ja/assigning-passwords.html

https://dev.mysql.com/doc/refman/8.0/ja/privilege-changes.html
VS Codeで既存のGitHubリポジトリを別のリポジトリに変更する方法


# VS Codeで既存のGitHubリポジトリを別のリポジトリに変更する方法

VS CodeでPlatformIOなどで新規プロジェクトを作成した場合になぜか前のリポジトリと紐図いたままになっていることがよくあるのでリポジトリの変更方法をメモします。

## 1. コマンドラインを使ってリモートリポジトリのURLを変更

1. **VS Code**のターミナルを開きます（`Ctrl + ` または `Cmd + `）。
2. 以下のコマンドを実行して現在のリモートリポジトリを確認します。

   ```sh
   git remote -v
   ```


3. リポジトリが異なる場合リポジトリを初期化します。

    ```sh
   git init
   ```
3. リモートリポジトリのURLを変更します。

   ```sh
   git remote add origin 新しいリポジトリのURL
   ```

4. 変更が適用されたか確認します。

   ```sh
   git remote -v
   ```

## 2. 変更をプッシュ

1. コードをコミットしていない場合、変更をコミットします。

   ```sh
   git add .
   git commit -m "コミットメッセージ"
   ```

2. 新しいリモートリポジトリにプッシュします。

   ```sh
   git push -u origin main
   ```


これで、VS CodeでのリポジトリのURL変更が完了です。新しいリポジトリへの変更内容がプッシュされます。