OmniAICreator/Qiita-1.07M huggingface dataset:
summernote使ってみたッ

業務でsummernoteを触ったので備忘録としてsummernoteについて書きます。

# summernoteとは

リッチエディタ
WYSIWYGエディタ（ウィジウィグエディタ）

> WYSIWYG（アクロニム: ウィジウィグ）とは、コンピュータのユーザインタフェースに関する用語で、ディスプレイに現れるものと処理内容（特に印刷結果）が一致するように表現する技術。What You See Is What You Get（見たままが得られる）の頭文字をとったものであり、「is」を外したWYSWYG（ウィズウィグ）と呼ばれることもある。

（[wikipedia](https://ja.wikipedia.org/wiki/WYSIWYG)から引用）

と呼ばれるもので、HTMLで書いたテキストがそのままHTMLが描画された見た目で編集できるものです。
例えば、WordPressの記事作成ページのようなものですね。（WordPressはさらにリッチですが）

### Features

- ブートストラップ 3.xx ～ 5.xx をサポート
- 軽量 (js+css: 100Kb)
- スマートなユーザーインタラクション
- すべての主要なブラウザで動作します:
Safari、Chrome、Firefox、Opera、Edge、Internet Explorer 9 以降
- すべての主要なオペレーティング システムで動作します。
Windows、MacOS、Linux

公式ドキュメントにあったものの引用です。
公式ドキュメント：[https://summernote.org/](https://summernote.org/)

内部的にはjQueryで動いており、Bootstlap3~5系に対応しているので既存のサービス（特にレガシーシステム）に導入しやすいと思います。

# インストール・始め方

https://summernote.org/getting-started/
公式サイトのインストールガイドをなぞり、ブラウザでsummernoteを動かすところまでやってみました。

できるようにしたこと
- フォームでsummernoteを使えるようにした
- 高さを調整した
- ページ読み込み後フォーカスが当たるようにした
- 日本語化した

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>

    <!-- include libraries(jQuery, bootstrap) -->
    <link
      href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
      rel="stylesheet"
    />
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>

    <!-- include summernote css/js -->
    <link
      href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css"
      rel="stylesheet"
    />
    <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
    <!-- 日本語対応するため読み込む -->
    <script src="lang/summernote-ja-JP.js"></script>
  </head>
  <body>
    <form method="post">
      <!-- idを指定する -->
      <textarea id="summernote" name="editordata"></textarea>
      <input type="submit" value="送信" />
    </form>

    <script>
      $(document).ready(function () {
        $("#summernote").summernote({
          height: 300, // エディタの高さ
          minHeight: null, // エディタの最小高さ
          maxHeight: null, // エディタの最大高さ
          focus: true, // ページ読み込み後最初にフォーカスするか
          lang: "ja-JP", // 言語 default: 'en-US'
        });
      });
    </script>
  </body>
</html>
```

HTMLファイルを作成してコピペすれば動くと思います。
ページによりますが個人的にフォーカスを当てるのはfalseで良い気もしました。

- 必要なライブラリを読み込む
- HTMLで`<textarea id="summernote"></textarea>`を記述
- JSで`$("#summernote").summernote()`を記述

最低限必要なのはこれだけです。
簡単にリッチエディタを用意できるので良いですね。

あとはサービスによって、動画は使わせたくないとか、使えるフォントを増やしたいとか、UIを変えたいなどなど要望があるかと思うので、そういったカスタマイズについては後追いで更新していければと思います。
エレキ素人が何か考える（その23）：今さらながらコンデンサ

# コンデンサの動作確認
またしても初心者レベルのはなし。コンデンサの放電を確認する。

## 回路
コンデンサの放電状況をマイコン（Arduino互換機）からつくるため、トライステートバッファを用いることとした。トライステートバッファについては、「[エレキ素人が何か考える（その13）：トライステートバッファ](https://qiita.com/infinite1oop/items/b783f0b943097594a1e7)」を参照されたい。後述する検証と同一ではないが、回路的には下記のようなものである。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/83a6cda6-e48a-f38d-f985-891060b7c87d.gif", width=70%>
左にあるものがトライステートバッファであり、ここでは矩形波により、５V供給またはハイインピーダンス（配線なし）状態を作り出している。ハイインピーダンスになると、コンデンサが放電を始め、LEDが<b>徐々</b>に消える。

## ソースコード
トライステートバッファを制御（On/Off）するコードである。

```c++
#define PIN 5

uint32_t val = 500; // ms

void setup() {
  Serial.begin(9600);
  pinMode(PIN, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    String data = Serial.readStringUntil('\n');
    val = data.toInt();
    Serial.println(val);
  }
  digitalWrite(PIN, LOW); // Active LOW for tristate buffer
  delay(val);
  digitalWrite(PIN, HIGH);
  delay(2000);
}
```
LOW時に５Vが供給され、HIGH時にハイインピーダンスとなる。なお、シリアル（PC）からの入力値により、On（Low）の時間を変化させている（あまり意味はなかったかも）。

## 検証
### 様子
![Capacitorあり.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/12d4b672-484c-9389-3226-2290e1592efb.gif)
LEDの上にあるものがコンデンサ、左のものがトライステートバッファである。少々わかりにくいかもしれないが、LEDが徐々に暗くなっている。

### オシロスコープの波形
オレンジがコンデンサとLEDとの間の波形、青がトライステートバッファ直後の波形である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/19c5ed4f-2e05-92d4-2f60-447055fc4195.png)
コンデンサの放電が観測されている。まずは、こんなところか。

EOF
C#のMSTestでFine Code Coverageでカバレッジを計測する

# 1. はじめに
* Visual Studio 2022 CommunityでMSTestのカバレッジを計測したい
* GUI上でソースコード内のカバレッジ状況を確認したい

# 2. 開発環境
* C#
* MSTest
* Visual Studio 2022 Community
* Windows 11

# 3. Fine Code Coverageのインストール
* 下記サイトからDownloadボタンをクリックする

https://marketplace.visualstudio.com/items?itemName=FortuneNgwenya.FineCodeCoverage2022

* ダウロードした```FineCodeCoverage2022.vsix```をダブルクリックする
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/19ddbb57-d3f7-379f-854a-69ce04226a05.png)

* ```Install```ボタンをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/d501858b-f59e-81cf-6aad-b4c89d5c334a.png)

* Fine Code Coverageのインストールが完了する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/0e4813de-b670-1e5c-4b55-95d8708414af.png)

# 4. カバレッジの取得
## 4.1. テスト対象メソッド
```Csharp:Calc.cs
public int add(int x, int y)
{
    if(x ==0 && y ==0) return 0;

    return x + y;
}
```

## 4.2. テストクラス
```Csharp:CalcTests.cs
[TestClass()]
public class CalcTests
{
    [TestMethod()]
    public void addTest()
    {
        var obj = new Calc();

        int actual = obj.add(1, 2);

        int exp = 3;

        Assert.AreEqual(exp,actual);
    }
}
```

## 4.3. カバレッジ計測結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/3d71374d-8c19-e285-c265-e24cfc1d7bdc.png)

## 4.4. ソースコードカバレッジ結果
* 画面の左右に色で表示される
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/f79d54db-34f9-309b-2402-9276dd93853c.png)

# 5. 参考文献

https://github.com/FortuneN/FineCodeCoverage
iRemocon Wi-Fi (IRM-03WLA)

# センサから温度など読み込むスクリプト作成
iRemocon Wi-Fi (IRM-03WLA) を使った。理由は手元にあったから。
コマンド仕様書が公開されており、スマホアプリだけでなく自作システムからも制御可能。
[IRM-03WLAコマンド仕様書](http://i-remocon.com/hp/documents/IRM03WLA_command_ref_v1.pdf)

## TCP/IPでiRecomon Wi-Fiから温湿度を取得する
コマンド仕様書には51013のポートにTCP/IP接続してコマンドを送ると結果が返ってくると書いてある。
ということでtelnetとexpectで取得するようにした。

### telnet, expectのインストール

~~~
$ sudo apt-get install telnet expect
~~~

次にtelnetでiRecomonのIP addressとportを指定して接続、コマンド *au\r\n を打って、OKが返ってくることを確認する。

~~~
$ telnet $IREMOCON_HOST $IREMOCON_PORT
> *au\r\n
ok 
~~~

あとはこんな感じでtenletとexpectを使って値を取得し、表示する。

```sensors_iremocon.sh
#!/bin/sh

IREMOCON_HOST=192.168.0.10
IREMOCON_PORT=51013
expect -c "
set timeout 20
spawn telnet $IREMOCON_HOST $IREMOCON_PORT
expect \"Escape character is\";send \"*au\r\n\"
expect \"ok\";send \"*se\r\n\"
expect \"se;ok\";send \"^]\"
" | grep -e "^se;ok;" | cut -d ';' -f3,4,5
```
盗撮は無くならないですね

カメラって、どこまで巧妙になるんでしょう。
プライバシーが重視されてますが、意味ないですよね。

https://amzn.to/3XhFtcB

https://youtu.be/gNQLiNrrXD8

https://niteruero.com/%e7%9b%97%e6%92%ae-%e8%a6%8b%e3%81%a4%e3%81%8b%e3%82%89%e3%81%aa%e3%81%84%e6%96%b9%e6%b3%95%ef%bc%9f/
AIによるreadme.md開発という提案 (個人開発の始めに)

# 要約
重要な情報はread.meに書いておきませんか？という提案です。
なぜなら、AIはアルゴリズムの優先順位的に、真っ先に開いているファイルの情報を読んでくれるからです。

AIに質問をする時はread.meファイルと設計やコードに関連するファイルを開いて質問を繰り返していくというスタイルです。


# 個人開発の始まり
タイトルのとおり、個人開発を始める時は、ある程度何かを作りたいか考えAIに開発手順をまとめてもらいます。

## 例 AIに質問

＊＊＊＊＊アプリを作りたいので手伝ってもらえますか？
>はい、お手伝いできます。どのような＊＊＊＊＊アプリを作りたいのか、どのような機能が必要なのか、詳細を教えていただけますか？それによって、どのような技術やアプローチが最適かを考えることができます。

とAIは返答してくれます、この後どんどん質問していくのですが、会話ログには残っているはずなのに、システム的に一定の文章量を超えるとAI忘れてしまいます。
なのでまとめた情報をread.meにまとめて置いておくという手法を取りたいと思います。

そもそもNext.jsでアプリ開発を始めると(Next.jsに限らず)read.meには起動方法とかインストール、ドキュメントなどの情報が載っているだけで開発に必要ありません。

なのでread.meを対AI用の情報を載せてAIの提案の精度を上げようという提案です。

# さらに開発を進めていくと
開発を進めていくとテーブル設計、データの型ファイルなど出来上がっていきます。
重要なファイルはVSCodeのピン止め機能（タブ上のファイル名で右クリック）を使ってタブに固定しておきます。

そして必要な時にファイルを開いておきます。
AIに質問する時は、不要なファイルは閉じておきます。

これでAIの提案の精度が上がっていくはずです。



# 参考

【GPT】結論ファーストはAIにも大事だった - Qiita

https://qiita.com/largetownsky/items/3c74c79e4dc93369b810

GitHub Copilot導入後、初めて使う時。(豊富な使用例付き) - Qiita

https://qiita.com/masakinihirota/items/0e58a6b921e4420a2882#%E8%87%AA%E5%88%86%E3%81%AE%E6%83%B3%E5%83%8F%E4%BD%93%E9%A8%93%E3%81%8B%E3%82%89%E5%87%BA%E3%81%97%E3%81%9F%E7%AD%94%E3%81%88

>自分の想像、体験から出した答え
優先順位は
>ファイルで範囲選択をしている箇所
ファイルでカーソルが置いてあった場所から上下数行分のコード、コメント部分
開いているファイル全体 (ファイルを開いているが、範囲選択はしていない 例:ターミナル上にカーソルがあった)
VSCode画面には表示されていないファイルだが、タブで開いてある複数のファイル
コミットログを見ている、直近のコミットを見ている。
質問 (ファイルを開いているが、範囲選択はしていない)
質問 (ファイルやタブを閉じている。)
GitHub Copilot chatとの会話ログ (ファイルやタブすべてを閉じている)
みたいな感じだと思います。
※「もっと詳しく教えてください」等と 主語を抜かして質問をすると 優先順位に従って質問が返ってきます。(※重要)
※普通に質問したい場合は、すべてのファイルを閉じておいた方が良いです。(※重要)
※GitHub Copilotは賢く、開いているファイルと関係のない質問にも答えることができます。つまり、質問自体が開いているファイルとの関連性が低いと判断されると、優先順位が低くなると思われます。
※会話ログに関しては、過去の会話ログを参考にしているかどうかは不明です。参考にしていたとしても、優先順位はかなり低いと思われます。
M1 MacでDockerはダメゼッタイ?

# Overview
- M1　macにDockerを入れるとマシンが耐えられない。。。
- マシンのスペックによるけどね。
    - ちなみに僕のスペックはこんな感じです。
        - Apple M1
        - メモリ8GB
        - OS: Ventra13.2.1
        - SSH 256GB
- 「なんか最近重と感じる + Dockerが入ってる」っていう人向け。


# Get Started!
## 結論
- M1でSSD256GBの人限定で、Dockerは入れない方が良い！
- なぜなら・・・Dockerのせいで貴重な256GBのSSHのうち100GBくらいが持っていかれるから。。。
- Docker入れて動かした瞬間に100GBくらい持っていかれました。

## 現象
- ここ数日マシンの調子がおかしい・・・
    - Vscodeがよく落ちる
    - notionがよく落ちる
    - その他アプリもよく落ちる

## 問題点
- Dockerによるストレージの圧迫
    - 最初はDockerを使うことでカーネルとかそこら辺がバックグラウンドで動いて悪さしてるな？と思ってました。
    - そこで再起動やらなんやらしたけど改善せず。
    - まさかとは思いストレージを確認すると220/256くらい使っていて残り30GBくらいしかない・・・。
    - この前まで100GB以上空きがあったのに？！と思ってシステムファイルを調べてみました。
    - すると、ユーザーディレクトリ配下にあるDocker関連のファイルだけで100GB以上・・・。

## 解決策
- Dockerごとアンインストールしてやりましたよ。（ついでにAdobe関連も）

## 解決策による新たな問題
- 想像の通り、Dockerがローカルで使えなくなりましたね。
- でも大丈夫。
- 最近VPSを契約してそこでDocker環境を作ったんです。
- だからLocalではDockerが不要になりました！
- 貧相なSSDで頑張ってるあなたも、VPSを使って快適なエンジニアリライフをどうぞ！
「隣の芝は青く見える」PHPerが浮気してGoの並行処理について頑張って考えてみた

普段仕事ではPHPを使って開発しているのですが、興味本位でGoを触り始めました。
はい、完全な趣味です。
「仕事しろ！」って怒られそうです。
そんな中、PHPではあまり聞かない「並行処理」について

**「これ便利やな〜」**

と感じたため、メモ書きしておきます。


## 並行処理とは
プログラムは、コンピュータに対して「何かをする」指示を与えるものです。
通常、プログラムは順番に命令を実行していきます。
しかし並行処理では、複数の命令を同時に実行することができます。

Goでは、このような並行処理を簡単に行うことができる仕組みが提供されています。
**ゴールーチン（Goroutine）** と呼ばれる軽量なスレッドを使用することができるのです。

## ゴールーチンとチャネル
ゴールーチンは、一つのプログラム内で複数作成することができます。
それぞれのゴールーチンは、異なる処理を同時に実行することができます。
ゴールーチン同士は、情報をやり取りするために **チャネル（Channel）** という仕組みを使います。
チャネルは、ゴールーチン間でデータを送受信するためのパイプのようなものです。

例えば、友達が机で勉強しているゴールーチンと、あなたが宿題をしているゴールーチンがあるとします。
チャネルとは、友達とあなたがメモを渡し合ってコミュニケーションを取るイメージです。

ゴールーチンとチャネルを使うことで、プログラム内で複数のタスクを同時に処理することができます。
友達が勉強している間に、あなたは別の作業を並行して行うことができるわけです。

## Goは並行処理がお得意
Goの並行処理は、前述したゴールーチンとチャネルによってプログラムをより効率的に実行されます。
複数のタスクを同時に処理することで、プログラムの実行時間を短縮したり、処理能力を最大限に活用したりすることが期待できます。
こちらの記事で処理速度についてわかりやすく説明してくださっています。

https://zenn.dev/farstep/articles/f712e05bd6ff9d

## 実装例の紹介
```golang
package main

import (
	"fmt"
	"time"
)

func goroutineA() {
	for i := 1; i <= 5; i++ {
		fmt.Println("ゴールーチンA:", i)
		time.Sleep(1 * time.Second)
	}
}

func goroutineB() {
	for i := 1; i <= 5; i++ {
		fmt.Println("ゴールーチンB:", i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	go goroutineA()
	go goroutineB()

	time.Sleep(6 * time.Second)
	fmt.Println("メイン関数終了")
}
```
このコードでは、goroutineA()とgoroutineB()という2つのゴールーチンを定義しています。
goキーワードを使用して、それぞれの関数をゴールーチンとして実行します。
両方のゴルーチンは同時に実行され、メイン関数はゴルーチンの終了を待つために一定時間待機します。
この実装例から感じられるメリットとして

- **並行処理がシンプル**
- **ゴールーチンは非常に軽量であり、数千ものゴールーチンを同時に実行することができちゃう**
- **ゴールーチン間でのデータの同期や通信は、チャネルを使って簡単に実現できちゃう**

などが読み取れます。

## 並行処理の注意点
並行処理は正しく扱わないと予期せぬ結果や問題が生じる可能性があります。
例えば、複数のゴールーチンが同じ変数に同時にアクセスすると、競合状態（競合条件）が発生し、プログラムの実行結果がおかしくなることがあります。
複数のゴールーチンが同じ変数に同時にアクセスすると、競合状態（競合条件）が発生し、プログラムの実行結果がおかしくなることがあります。
競合状態を避けるために、適切な同期機構を使ってゴールーチンの実行順序やデータの整合性を保つ必要があります。

その対策としてGoでは、**ミューテックス（Mutex）** や **セマフォ（Semaphore）** などの同期機構を提供しています。これらを使うことで、ゴールーチンの実行を制御し、競合状態を回避することができます。

https://qiita.com/TsuyoshiUshio@github/items/c3234f3705949d8cf413

https://zenn.dev/mitsugu/articles/56a0d8ad36d992



## 今後のGoに注目
PHPより案件数が少ないGoですが、優れた面があることがわかったと思います。
Gohpher人口の増加も夢ではない？！

ちなみにですが、PHPでも並行処理に似たようなことができるようです。
それはまたの機会に・・・。
magic_testでシステムテストを楽に書こう

こんにちは、[Bullet Train](https://bullettrain.co/)コアチームメンバーのガブリエルです。
最近は[magic_test](https://github.com/bullet-train-co/magic_test)を触っていて、結構面白いと思ったので紹介したいと思います。

# magic_testとは
Railsのシステムテストで使える[Capybara](https://github.com/teamcapybara/capybara)のメソッドを直感的に、ブラウザーを介してクリックなどしながらテストを実装していくgemです。

例えば、レコードの作成をテストしたい時は、Capybaraでこんな感じになります。

```ruby
click_on 'New foo'
fill_in 'Title', with: 'Test Foo'
click_on 'Create Foo'
assert page.has_content? 'Foo was successfully created.'
```

magic_testでは、これを全部手動で書く代わりに、ブラウザーでクリックしたりして変更をターミナルで確認すると、このコードは全部自動的に自分のファイルに追加されます。

作成者の[アンドリュー・カルバー氏](https://twitter.com/andrewculver)の[紹介動画](https://twitter.com/andrewculver/status/1366066621480067084?s=20)を見ていただくと分かると思いますが、瞬時的に何行ものコードを楽に実装できます。

# 使い方

gemのインストール
```ruby
# 今現在、最新版はGitHubからダウンロードする必要があります。
group :test do
  gem "magic_test", git: "git@github.com:bullet-train-co/magic_test.git"
end
```

```
> rails g magic_test:install
> bundle binstubs magic_test
```

これで`test/system/basics_test.rb`というファイルが作成されますが、そこの`magic_test`メソッドでブラウザーが起動され、テストに書きたい動作をブラウザーで行う、という流れになります。

※ 完全に新しいRailsアプリで動作確認したい方はまずrootを`config/routes.rb`で設定してください。今回の説明のため`rails g scaffold Foo title:string`でモデルを作ってからルーティングを`root "foos#index"`にしました。

準備が整ったら、新しく作られたテストはこの通りになります。
```ruby:test/system/basics_test.rb
require "application_system_test_case"

class BasicsTest < ApplicationSystemTestCase
  test "getting started" do
    visit root_url
  
    magic_test
  end
end
```

`bin/magic test test/system/basics_test.rb`を実行し、`magic_test`メソッドで新しいブラウザーを起動しましょう。

![magic_test 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74313/667b8cb7-d496-348a-df55-2344984f0239.png)

テストコード、デバッガー、そしてブラウザーが表示されるはずです。

まず`New foo`をクリックし、タイトルを"Test Foo"にしてから`Create foo`をクリックします。

新規Fooレコードが上手く作られたメッセージが表示されることもテストしましょう。「Foo was successfully created」を確認するのに、その文字列をハイライトして、Ctrl+Shift+Aを入力します。そして、このメッセージが表示されます。

![magic_test 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74313/6fddcfb2-cc20-8915-4df0-b605c5f84767.png)

**これで終わり！**
次はターミナルで`flush`を打ったら、ブラウザーで行った動作は全部自動的に記録されます。

![magic_test 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74313/9953c1d0-8d4d-8d88-bf40-3e0ad8058fbe.png)

これで`exit`を打ってデバッガーから出て、`magic_test`メソッドを削除したらそのままテストをコミットできます。

楽でしょう？

# まとめ

ということで、直感的にブラウザーを使いながらCapybaraのテストを実装したい人はぜひ使ってみてください。Bullet Trainの[Discord](https://discord.gg/bullettrain)もあるので、質問のある方は気軽に入って話しましょう！
Amazon Linux 2023でs3fsを使いたい

# はじめに

Amazon Linux 2023 の EC2 インスタンスに S3 のバケットをマウントしたい。

選択肢としては goofys や s3fs 、最近出てきたAWS謹製の Mountpoint for Amazon S3 の3つが思い浮かぶ。


https://github.com/kahing/goofys

https://github.com/s3fs-fuse/s3fs-fuse

https://github.com/awslabs/mountpoint-s3

Mountpoint for Amazon S3 はまだ read only な使い方しかできないみたいなので、今回は更新が活発な s3fs の方を使ってみたいと考えた。


# リポジトリどこ？

s3fs 関連の記事を探していると Amazon Linux 2 向けの記事が多く見受けられる。

参考にしたいところだけど、Amazon Linux 2 は RHEL/CentOSベースだったので EPEL リポジトリが使用できたが、Amazon Linux 2023 は Fedora 34〜36 がベースなので使えない...

https://docs.aws.amazon.com/linux/al2023/ug/relationship-to-fedora.html

そこで別ルートを探すと、Fedoraのリポジトリが使えるような記事を見つけた。

https://w.atwiki.jp/sanosoft/pages/218.html

https://www.gclue.jp/2022/06/amazon-linux-2022-epel-fedora.html


# インストール

記事通り、リポジトリの登録をしてみる。

```
# vi /etc/yum.repos.d/fedora.repo
```

```
[fedora]
name=Fedora 36 - $basearch
#baseurl=http://download.example/pub/fedora/linux/releases/36/Everything/$basearch/os/
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-36&arch=$basearch
enabled=0
countme=1
metadata_expire=7d
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=https://getfedora.org/static/fedora.gpg
skip_if_unavailable=False
```

そしてリポジトリを指定してインストールを実行したら、無事に成功した。

```
# dnf --enablerepo=fedora install s3fs-fuse
```

# マウントしてみる

S3のバケットを作成し、EC2のインスタンスを立てて、以下のポリシーを持つIAMロールをアタッチする。（権限はもう少し絞りたいけど、必要なものが分かったら随時変更したい）

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<<YOUR_BUCKET_NAME>>",
                "arn:aws:s3:::<<YOUR_BUCKET_NAME>>/*"
            ]
        }
    ]
}
```

EC2のインスタンス内にSSH接続し、マウント設定をする。
```
# mkdir /mnt/s3bucket

# echo "<<YOUR_BUCKET_NAME>> /mnt/s3bucket fuse.s3fs _netdev,uid=1000,gid=1000,nonempty,allow_other,endpoint=ap-northeast-1,iam_role=auto 0 0" | tee -a /etc/fstab

# mount -a
```

無事マウント完了
```
# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           951M     0  951M   0% /dev/shm
tmpfs           381M  5.2M  376M   2% /run
/dev/nvme0n1p1  8.0G  5.9G  2.2G  74% /
tmpfs           951M     0  951M   0% /tmp
s3fs             16E     0   16E   0% /mnt/s3bucket
tmpfs           191M     0  191M   0% /run/user/1000
```

( ﾟωﾟ )o0O(サイズの単位に「E」って出てるけど、エクサ（10の18乗）のこと？？？）

マネコンからファイルをアップロードしてインスタンス内から参照したり、インスタンス内からファイルを保存してS3に反映されることを確認できた。
StatelessWidgetとStatefulWidgetの違い

flutterを学び始めたので、学んだことをメモしていきます。
### StatelessWidget
```dart
class MyHomePage extends StatelessWidget {

  @override
  widget build(BuildContext content) {
    return MaterialApp(...);
  }
}
```
StatelessWidgetクラスは、ステート（状態を表す値）を持たないウィジェットのベースとなるクラスです。ウィジェットのクラスは、StatelessWidgetと、ステートを持つStatefulWidgetのいずれかを継承して作成します。
StatelessWidgetクラスは、ステートのないウィジェットというだけで、表示されるデザインなどは特に扱っていません。これをreturnすることで、マテリアルデザインによるアプリが表示されます。

### StatefulWidget
StatefulWidgetクラスの基本形
```dart
class MyHomePage extends StatefulWidget {

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
```
Stateクラスの基本形
```dart
class _MyHomePage extends State<MyHomePage> {

  @override
  widget build(BuildContext content) {

    }
}
```
StatefulWidgetは、ウィジェット部分とステート部分の2つで構成されてます。ウィジェットクラスは、StatefulWidgetクラスを継承して定義します。このクラスには、`createState`というメソッドを実装する必要があります。これはステートを作成するためのもので、ステートクラスのインスタンスを作成し、返すだけのシンプルな処理を用意します。
ステートクラスは、Stateクラスを継承して作成します。このとき、ウィジェットクラスを<>で指定しておきます。指定したウィジェットクラスで使われるステートクラスが定義できます。
`build`というメソッドが用意されていて、ステートを生成する際に呼び出されるもので、ここでステートとして表示するウィジェットを生成し返します。

#### 勉強した本
https://www.amazon.co.jp/%E3%83%9E%E3%83%AB%E3%83%81%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E5%AF%BE%E5%BF%9C-%E6%9C%80%E6%96%B0%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF-Flutter-3%E5%85%A5%E9%96%80-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798068527
cscの作法 その380

# 概要
cscの作法、調べてみた。
wpfやってみた。
コントロール、並べてみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/83cc86f7-9c7a-7258-e7be-383fc3c2a3dd.png)


# サンプルコード

```
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Hello, WPF!">
	<StackPanel>
		<TreeView Margin="10">
			<TreeViewItem Header="フォルダ1">
				<TreeViewItem Header="ファイルa" />
				<TreeViewItem Header="ファイルb" />
			</TreeViewItem>
			<TreeViewItem Header="フォルダ2">
				<TreeViewItem Header="ファイルc" />
			</TreeViewItem>
			<TreeViewItem Header="フォルダ3" />
		</TreeView>
		<Grid>
			<ListView Name="lvwSample" Margin="10">
				<ListView.View>
					<GridView>
						<GridViewColumn DisplayMemberBinding="{Binding [0]}" Header="列A" />
						<GridViewColumn DisplayMemberBinding="{Binding [1]}" Header="列B" />
					</GridView>
				</ListView.View>
				<ListViewItem Content="0,Apple" />
				<ListViewItem Content="1,Banana" />
				<ListViewItem Content="2,Cherry" />
				<ListViewItem Content="3,Kiwi" />
				<ListViewItem Content="4,Orange" />
			</ListView>
		</Grid>
	</StackPanel>
</Window>




```

以上。
cscの作法 その379

# 概要
cscの作法、調べてみた。
wpfやってみた。
コントロール、並べてみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/292ef95b-c04f-2fcb-bf1d-15396afac080.png)


# サンプルコード

```
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Hello, WPF!">
	<StackPanel>
		<Slider Margin="10" Maximum="50" Minimum="0" TickPlacement="TopLeft" Value="20" />
		<Slider Height="50" Margin="10" Maximum="10" Minimum="0" Orientation="Vertical" TickPlacement="Both" Value="7" />
		<ProgressBar Height="6" Margin="10" Maximum="100" Minimum="0" Value="33" />
		<ProgressBar Width="6" Height="60" Margin="10" Orientation="Vertical" Value="77" />
		<Grid>
			<Menu>
				<MenuItem Header="ファイル(_F)">
					<MenuItem Header="開く(_O)" />
					<MenuItem Header="上書き保存(_S)" />
					<Separator />
					<MenuItem Header="終了(_X)" />
				</MenuItem>
				<MenuItem Header="編集(_E)" />
				<MenuItem Header="表示(_V)" />
				<MenuItem Header="ヘルプ(_H)" />
			</Menu>
		</Grid>
		<Expander Margin="10" Background="SpringGreen" IsExpanded="True">
			<StackPanel>
				<Button Margin="10" Content="ボタン1" />
				<Button Margin="10" Content="ボタン2" />
				<Button Margin="10" Content="ボタン3" />
			</StackPanel>
		</Expander>
		<WrapPanel>
			<Button Width="50" Margin="5" Content="ボタン1" />
			<Button Width="80" Margin="5" Content="ボタン2" />
			<Button Width="100" Margin="5" Content="ボタン3" />
			<Button Width="50" Margin="5" Content="ボタン4" />
			<Button Width="80" Margin="5" Content="ボタン5" />
			<Button Width="100" Margin="5" Content="ボタン6" />
			<Button Width="50" Margin="5" Content="ボタン7" />
			<Button Width="80" Margin="5" Content="ボタン8" />
			<Button Width="100" Margin="5" Content="ボタン9" />
		</WrapPanel>
		<Viewbox Height="10">
			<TextBlock Text="こんにちは" />
		</Viewbox>
		<Viewbox Height="30">
			<TextBlock Text="こんにちは" />
		</Viewbox>
		<Viewbox Height="50">
			<TextBlock Text="こんにちは" />
		</Viewbox>
	</StackPanel>
</Window>




```

以上。
cscの作法 その378

# 概要
cscの作法、調べてみた。
wpfやってみた。
コントロール、並べてみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c5798681-35c5-881d-04bc-540dad8da242.png)

# サンプルコード

```
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Hello, WPF!">
	<StackPanel>
		<TabControl Height="150" Margin="5" SelectedIndex="0">
			<TabItem Header="タブ1">
				<StackPanel>
					<Button Margin="10,5" Content="ボタン1" />
					<Button Margin="10,5" Content="ボタン2" />
					<Button Margin="10,5" Content="ボタン3" />
				</StackPanel>
			</TabItem>
			<TabItem Header="タブ2">
				<StackPanel>
					<Button Margin="10,5" Content="ボタン4" />
				</StackPanel>
			</TabItem>
		</TabControl>
		<Border Width="300" Height="15" Margin="10" BorderBrush="Blue" BorderThickness="1" />
		<GroupBox Width="300" Margin="10" Header="グループ">
			<StackPanel Orientation="Horizontal">
				<Button Margin="10" Content="aaa" />
				<Button Margin="10" Content="bbb" />
				<Button Margin="10" Content="ccc" />
			</StackPanel>
		</GroupBox>
		<Rectangle Width="150" Height="10" Margin="10" Fill="Magenta" />
		<Ellipse Width="80" Height="30" Margin="10" Fill="MediumAquamarine" />
		<DatePicker Width="150" Margin="10" />
		<Calendar Margin="10" />
	</StackPanel>
</Window>




```

以上。
cscの作法 その377

# 概要
cscの作法、調べてみた。
wpfやってみた。
コントロール、並べてみた。

# 写真


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/8589c899-2d75-f3e2-c42c-ffe30ace3025.png)

# サンプルコード

```
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Hello, WPF!">
	<StackPanel>
		<Label Margin="10" Padding="0" Content="ラベル" />
		<TextBlock Margin="10" Text="テキスト" />
		<TextBlock Margin="10" Text="長いテキスト。長いテキスト。長いテキスト。長いテキスト。長いテキスト。長いテキスト。長いテキスト。長いテキスト。" 
			TextWrapping="Wrap" />
		<TextBox Margin="10" Text="テキストボックス" />
		<TextBox Width="400" Height="100" Margin="10" Text="テキストボックス。テキストボックス。テキストボックス。テキストボックス。"
			TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" />
		<RichTextBox Margin="10">
			<FlowDocument>
				<Paragraph>
					こんにちは、<Bold>世界</Bold>
				</Paragraph>
				<Paragraph>
					<Run Foreground="Red">あいうえお</Run>
					<Run Foreground="Blue">かきくけこ</Run>
				</Paragraph>
			</FlowDocument>
		</RichTextBox>
		<Button Width="100" Margin="10" Content="ボタン" />
		<ToggleButton Width="75" Margin="10,10,10,1" Content="トグルボタン1" IsChecked="True" />
		<ToggleButton Width="75" Margin="10,1,10,10" Content="トグルボタン2" />
		<CheckBox Margin="10" Content="チェックボックス" IsChecked="True" />
		<StackPanel Orientation="Horizontal">
			<RadioButton Margin="10" Content="ラジオボタン1" GroupName="Grp1" IsChecked="True" />
			<RadioButton Margin="10" Content="ラジオボタン2" GroupName="Grp1" />
			<RadioButton Margin="10" Content="ラジオボタンA" GroupName="Grp2" />
			<RadioButton Margin="10" Content="ラジオボタンB" GroupName="Grp2" IsChecked="True" />
		</StackPanel>
		<ComboBox Margin="10" SelectedIndex="0">
			<ComboBoxItem Content="選択肢1" />
			<ComboBoxItem Content="選択肢2" />
		</ComboBox>
		<ListBox Height="80" Margin="10" ScrollViewer.VerticalScrollBarVisibility="Visible" SelectedIndex="0">
			<ListBoxItem Content="選択肢1" />
			<ListBoxItem Content="選択肢2" />
		</ListBox>
	</StackPanel>
</Window>




```

以上。
バ美肉の限界とフォルマント解析の闇

久しぶりにQiitaに記事を書きます。最近はライトノベルを書いていました。直近では、エロ同人音声をテーマにしたミステリ小説を書き企画賞に応募していたのですが、作中にフォルマント解析のプログラムを登場させたので、リアリティを出すために実際にコーディングしてみます。あ、作品はこちらです。

https://novelup.plus/story/552949343

## Pythonコード

さて、まずは<b>「先輩、やめてください」という音声ファイルを用意します</b>。で、parselmouthというライブラリを使い、そのフォルマントを解析してmatplotlibで図示してみます。

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

sound = parselmouth.Sound("SenpaiNoPlease.wav")  

formant = sound.to_formant_burg()

plt.figure()
plt.plot(formant.xs(), [formant.get_value_at_time(1, t) for t in formant.xs()], 'r')  # F1
plt.plot(formant.xs(), [formant.get_value_at_time(2, t) for t in formant.xs()], 'g')  # F2
plt.plot(formant.xs(), [formant.get_value_at_time(3, t) for t in formant.xs()], 'b')  # F3
plt.plot(formant.xs(), [formant.get_value_at_time(4, t) for t in formant.xs()], 'y')  # F4
plt.plot(formant.xs(), [formant.get_value_at_time(5, t) for t in formant.xs()], 'm')  # F5
plt.title("Formants over time")
plt.xlabel("Time [s]")
plt.ylabel("Frequency [Hz]")
plt.show()
```

実行結果はこちら。
![stretch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2866483/81d8b4e6-3ca0-fa39-133f-555b18300b30.png)

## 説明

to_formant_burg()は音声信号から共振周波数を抽出するための関数です。線形予測分析（LPC）の一種、バーグ法と呼ばれるアルゴリズムを用いており、John Burgによって1960年代に確立された手法だそうです。上記のソースで示されている通り、parselmouthでは、F1からF5までのフォルマントの検出が可能になっています。

DTMソフト等を使っていると、フォルマントというものは、ピッチやベロシティと同じ1つのパラメータなのだと思ってしまいがちです。しかし実際には周波数帯域によってF1, F2, F3と別れており、それぞれが口の開き方や舌の位置によって規定される母音の音色に対応しています。

いや、例えば、ボイスチェンジャーでピッチとフォルマントを上げる操作を行い、男声を女声に変えたりすることがありますよね。でも、一般的なボイスチェンジャーでは上記の全帯域を一括で操作しているため、根本的な声質は変わりません。近い口の構造を持った人の声になるだけで、誰か他の人になることはできないのです。

つまり、<b>俺がボイスチェンジャーを使っても美少女になれないのは、パラメータが足りないから</b>です。フォルマントだけでもF1, F2, F3などを個別に調整する必要があるはずですし、それ以外にも、アクセントや発話スタイルなどの様々な声質の要素があり、計算操作で人の声を変えることは極めて難しい。そのため最近では、機械学習を用いて声質を変換する手法が主流になっているようです。

とにかく、声というものは闇が深い。冒頭のラノベでもその辺りの限界を前提にして物語を作っています。もしその筋の専門家の方が見ていたら、アクセスして間違いを指摘していただけますと幸甚です。

## おまけ

実音声を聞きたいという酔狂な方はこちらからぞうぞ。QiitaでAudioタグ使えないみたいなのでYouTubeでUnlisted公開してリンクしました。元音声と、Rubber Band( https://breakfastquay.com/rubberband/ )のwindowsコマンドツールでピッチシフトしたバージョンの2つで試しています。

https://youtu.be/epGvvuQ4HII

参考：
https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E4%BA%88%E6%B8%AC%E7%AC%A6%E5%8F%B7
【GPT】結論ファースト以外もAIに分からせたい

# 概要

* 独自文書質疑でよく使われる、OpenAI Embedding(Ada v2)ベクトル変換の特徴を見た
* 文章の先頭ほど重視される事が分かった
* :new: HTMLのタグである程度制御できることが分かった

:::note info
ポイント
HTMLファイルの前処理で、タグはある程度残すのも選択肢
HTML以外でも、重要箇所のマーカーとしてembeddingの際に付けるのもアリかもしれない
:::


# 背景

前回の記事で、OpenAI Embedding(Ada v2)には、文書の先頭ほど重視される癖があることが分かった。

https://qiita.com/largetownsky/items/3c74c79e4dc93369b810

だがしかし、先頭以外に重要箇所がある場合もあるはず。それをAIに分からせる方法はないのか？という事で追加で調べてみた。検証環境などは前回参照。


# 結果

:::note warn
クエリ文
今日、私は田中とカラオケで遊んだ。
:::

:::note info
検索対象１（１行目がクエリ文）
**今日、私は田中とカラオケで遊んだ。**
昨日、兄は鈴木とドライブに行った。
明日、妹は両親と遊園地で楽しむ。
:::

:::note info
検索対象２（２行目がクエリ文）
昨日、兄は鈴木とドライブに行った。
**今日、私は田中とカラオケで遊んだ。**
明日、妹は両親と遊園地で楽しむ。
:::

:::note info
検索対象３（３行目がクエリ文）
昨日、兄は鈴木とドライブに行った。
明日、妹は両親と遊園地で楽しむ。
**今日、私は田中とカラオケで遊んだ。**
:::

:::note info
検索対象３の修飾例
昨日、兄は鈴木とドライブに行った。
明日、妹は両親と遊園地で楽しむ。
&lt;title&gt; **今日、私は田中とカラオケで遊んだ。** &lt;/title&gt;
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1747214/32a9a6c1-e28d-8389-4e90-a712504fadaf.png)

文章末に検索クエリがあるため、近い距離でHitしない検索対象３を、検索クエリに近くできるほど、その修飾はOpenAI Embedding的に強調効果があったことになる。

:::note info
ポイント
* **HTMLのstrongタグが最強。** 文頭クエリ文の検索対象１までの距離を半分詰めている
* HTMLのtitle/h1なども効いているが、効果が弱くなるのと、本来の意味は強調ではないので、副作用が無いか気になるところ
* Markdownの強調表現は、効かない
* テキストで「重要」とか書いても、ベクトル強調の意味では効かない
:::
GuardDutyを重要度でフィルターして通知（CDK）

# 概要
AWS Lambdaを使用せずにEventBridge + SNSでGuardDuty脅威検知のメール通知を行うCDKサンプルコード（TypeScript）を紹介します。

# フィルター範囲
severityはGuardDutyで定義されている重要度レベルを示しており、数値と重要度は以下の通りです。
* 高： 7.0〜8.9 の範囲 
* 中： 4.0〜6.9 の範囲
* 低： 0.1〜3.9 の範囲

本記事の例では重要度中以上を通知対象としています。

# ファイル構成
ファイル構成は以下です。
* bin/
    * main.ts
* lib/
    * GuardDuty/
        * GuardDutyStack.ts

# サンプルコード

## bin/main.ts

```typescript:bin/main.ts
#!/usr/bin/env node

import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Environment } from 'aws-cdk-lib';
import { GuardDutyStack } from '../lib/GuardDuty/GuardDutyStack';

if (process.env['NODE_ENV'] == null || process.env['NODE_ENV'] === '') {
    throw new Error('NODE_ENV is not set');
}
if (process.env['AWS_PROFILE'] == null || process.env['AWS_PROFILE'] === '') {
    throw new Error('AWS_PROFILE is not set');
}

const app = new cdk.App();

const env: Environment = {
    account: '<AWSアカウント番号>',
    region: '<AWSリージョン>',
};

new GuardDutyStack(app, {
    env: env,
});
```

## lib/GuardDuty/GuardDutyStack.ts

```typescript:lib/GuardDuty/GuardDutyStack.ts
import * as cdk from 'aws-cdk-lib';
import { Rule } from 'aws-cdk-lib/aws-events';
import { Topic } from 'aws-cdk-lib/aws-sns';
import { EmailSubscription } from 'aws-cdk-lib/aws-sns-subscriptions';
import { SnsTopic } from 'aws-cdk-lib/aws-events-targets';
import { Construct } from 'constructs';

/**
 * 構築プロパティ
 */
export interface GuardDutyProps extends cdk.StackProps {}

export class GuardDutyStack extends cdk.Stack {
    private readonly _props: GuardDutyProps;

    constructor(scope: Construct, props: GuardDutyProps) {
        super(scope);

        // アラートトピック作成
        const snsTopic = new Topic(this, 'SNSTopic', {
            displayName: 'GuardDutyFindingAlert',
            topicName: 'GuardDutyFindingTopic',
        });
        snsTopic.addSubscription(new EmailSubscription('user@example.com'));

        // GuardDuty通知イベント作成
        const guardDutyEvent = new Rule(this, 'GuardDutyEvent', {
            ruleName: 'GuardDutyFindingEvent',
            description: 'GuardDuty Finding Alert',
            eventPattern: {
                source: ['aws.guardduty'],
                detailType: ['GuardDuty Finding'],
                detail: {
                    severity: [
                        { numeric: ['>=', 4] }, // 重要度中以上のみ通知するようにフィルタリング
                    ],
                },
            },
        });

        // ターゲット追加
        guardDutyEvent.addTarget(new SnsTopic(snsTopic));
    }
}
```

# メール通知の発砲
重要度中以上の脅威が検知された際に以下のような内容のメール通知が発砲されます。
```json
{"title":"EC2 instance i-99999999 is behaving in a manner that may indicate it is being used to perform a Denial of Service (DoS) attack using an unusual protocol.","description":"EC2 instance i-99999999 is behaving in a manner that may indicate it is being used to perform a Denial of Service (DoS) attack using an unusual protocol.","type":"Backdoor:EC2/DenialOfService.UnusualProtocol","severity":8}
```

:::note warn
メールの本文は改行されていないJSONがそのまま出力されるため、必要に応じてEventBridgeの入力トランスフォーマー等で整形して下さい。
:::
WSLでROS(Noetic)を使う

# 概要
WSL2(Windows Subsystem for Linux)を用いてROSを動かしました。
基本は以下の記事を参考にしてやりました。一部そのままではできなかった部分があったので、そこについて記します。

https://qiita.com/rnkj/items/ad5cd67aadb957dfc10f

* 環境
    * Windows11
    * WSL2
    * Ubuntu 20.04.6 LTS
    * ROS(Noetic)

* 全体の流れ
    * WSLの導入
        * 本体の導入
        * GUIを使えるようにする
    * ROSの導入
    * ROSの実行(確認)

## WSLの導入
参考記事では、MobaXtermを利用してGUIアプリを使えるようにしていたが、WSL2ではWSLgが使えるようになったので別途Xserver機能を用意する必要がなくなったらしい。
他の記事を参考にしつつ、GUIアプリを使えるようにする。

1. コマンドプロンプトを管理者として開く
2. WSLとLinuxディストリビューションをインストール
    ~~~ 
    wsl --install -d Ubuntu-20.04 
    ~~~
3. UserNameとPasswordを聞かれるので、設定したいUsernameとpasswordを入力
4. ディストリビューション内のパッケージを更新
    ~~~
    sudo apt-get update
    sudo apt-get upgrade
    ~~~
5. GUIアプリを利用できるようにする。調べた感じでは、特に何も入れなくてもWSLgを使えるような雰囲気だったが、以下のMicrosoftのWSLチュートリアルの通りに、以下のツール群をインストールしないと何故かGUIの画面表示ができなかった。そのため、対症療法的に以下の諸々をインストールした。

    ~~~
    sudo apt install gimp -y
    sudo apt install vlc -y
    sudo apt install x11-apps -y
    ~~~


    Microsoftのチュートリアル記事：https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/gui-apps


6. 動作確認。目玉のGUIが表示されれば成功。
    ~~~
    xeyes
    ~~~

## ROSの導入

1. Windowsのターミナルを開き、WSLでubuntuを開く。ターミナルであれば上部の下矢印マークからUbuntuのターミナルを開くこともできる。
    ~~~
    ubuntu2004
    ~~~
2. ROSをインストール。ここは普通のUbuntuにROSをインストールする手順と同じなので割愛。以下を参考にした。

https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e

http://wiki.ros.org/ROS/Installation


## 動作確認
1. Ubuntuが動作しているターミナル画面でroscoreを起動する。
    ~~~
    roscore
    ~~~
2. Ubuntuが動作する別のターミナル画面を用意し、turtlesimのノードを起動する。亀のGUIが表示されたらOK。
    ~~~
    rosrun turtlesim turtlesim_node
    ~~~

## 参考記事
大元の参考記事「Windows WSL2にROSをインストールする」：https://qiita.com/rnkj/items/ad5cd67aadb957dfc10f
MicrosoftのWSLチュートリアル：https://learn.microsoft.com/ja-jp/windows/wsl/tutorials/gui-apps
ROS講座02　インストールhttps://qiita.com/srs/items/e0e0a9dc3f94c2d3348e
ROSwiki：http://wiki.ros.org/ROS/Installation
Windows 10でLinuxを使う(WSL2)：https://qiita.com/whim0321/items/ed76b490daaec152dc69
Pythonでインターフェイス的なものを使いたい

## はじめに
キャンプ場の予約状況を確認する簡単なアプリを作ろうとしていて、インターフェイスで予約可能かをboolで返すメソッドの実装を強制したかった。Python初学者なのでPythonにインターフェイスがないことを知ってえっ？　となったが、近いことのできる仕組みにProtocolなる仕組みがあることを知ったのでまとめておく

```python
from typing import Protocol

class SiteAvailability(Protocol):
    def check(self) -> bool:
        ...

class Site1:
    def check(self) -> bool:
        return True
    
class Site2:
    def check(self) -> bool:
        return False

def check_availability(site_available: SiteAvailability) -> bool:
    return site_available.check()

print(check_availability(Site1()))
print(check_availability(Site2()))
```
こう書くと、check()メソッドが実装されているならそれぞれで実装したcheckが呼ばれる。クラスが別であっても同じ名前のメソッドを使用することができ、異なるオブジェクトで同じ操作を切り替えて使うことができる。これをダックタイピング（duck typing）と呼ぶ

## おわりに
ダックタイピング初体験でこれはすごいと思う一方、メソッド名が被ったりしないか心配になってくる。自分だけならギリ良さそうだが、外部のライブラリなど入れたり自分の知らないどこかで同じ名前がある場合などがありそう。
そう思いつつ、ダックタイピングは見るからに強力な表現力なのでもっと知りたいと思った
Imposterを３６０°回転させてみる

とりあえず
HoudiniでDebug!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540879/974159c4-8fc6-5f46-8b2d-870af412542b.png)


```diff_c_make:"VEX"
//Pos
v@UEPos = set(@P.x,@P.z,@P.y);

//U
@Arctangent = atan(@UEPos.x,@UEPos.y)/($PI*2)*-1+0.25;
//V
@Dot = (dot(set(0,0,1),@UEPos)+1)*0.5;

//UVRot
v@UECamUP = normalize(point(1,"P",1));
@UECamUP = set(@UECamUP.x,@UECamUP.z,@UECamUP.y);
v@UECamSide = normalize(point(2,"P",0));
@UECamSide = set(@UECamSide.x,@UECamSide.z,@UECamSide.y);

v@UEZPos.y = dot(v@UECamUP,set(0,0,1));
@UEZPos.z = dot(v@UECamSide,set(0,0,1));
@UVRot = atan(@UEZPos.z,@UEZPos.y)/($PI*2);
```
```diff_c_make:"VEX"
v@UEPos=point(0,"UEPos",0);
@Dot=point(0,"Dot",0);
@ArcTangent=point(0,"Arctangent",0);

v@UECamUP=point(0,"UECamUP",0);
v@UECamSide=point(0,"UECamSide",0);

@UVRot=point(0,"UVRot",0);
```

で、Unrealで構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540879/f3179fcd-454a-0d41-7462-f3b4db18ff51.png)

Sprite のフリップ以外ではうまくいってるように見えるが、回転させると、うまくいかないところがある。

RotateAboutAxisがうまくいってないのかもしれない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540879/ae350f8d-e50c-0a1a-bfee-f90e3e7853aa.png)

もう少し考えることが必要
複製登録

Detailを少しだけ変更して、新しいデータとして登録したい時があると思います。

例えば、このような登録があったとして、11 Pro MaxのMaxだけを消して、11 Proとして登録したい時です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/eed5af56-5214-874c-5187-e903a8b42772.png)
scaffoldで作成されたSaveボタンを少し変更して実装出来たので紹介したいと思います。

まずSaveボタンの隣にボタンを配置し、名前をAddに変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/add09d32-e81a-bfec-822d-3b7b3d9c81c2.png)
次にSaveDetailというClient Actionをコピーして名前をAddDetailにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/b639673a-9834-7448-0c8f-bb0f57a8539a.png)

AddボタンのOn ClickをAddDetailにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/1ced6df1-f667-9190-99a2-a4804842e2b2.png)

AddDetailを開き、Startの下にAssignを配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/ded66bb1-d5c5-6f2b-5800-2d37d1d4770a.png)
CreateOrUpdateで使用しているSourceを確認します。（コピーしておくと良いでしょう。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/f56fe8d9-2563-347f-a7ed-982817f325e7.png)
配置したAssignのAssignmentsでそのEntity(?)のIdをNullIdentifier()にしてしまいます。
最近OutSystemsを始めたばかりで用語の使い方が怪しいので(?)が付いてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254659/d5be58ba-1fa4-296d-d2dd-0d70cdb097f3.png)
するとCreateOrUpdateが新規と認識し、データを新規で登録してくれます。
サーバーレスNoSQLデータベースのFirestoreを型安全に扱うことのできるオープンソースライブラリをリリースしました

![SkeetTypeSafeFirestore2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/36c63398-2563-364a-3945-56095d1fb4a6.png)



こんにちは！kishi.solです。普段はオープンソースを応援するEpics DAOやELSOUL LABOというソフトウェア研究所をやっていたりします。

この度は、Google Cloud の サーバーレス NoSQL データベース である Firestore を型安全に扱うことのできるオープンソースライブラリ「Skeet Firestore」をリリースしました。

Skeet Firestore: https://github.com/elsoul/skeet-firestore


## サーバーレス NoSQL データベース "Firestore"

Google Cloud の サーバーレス NoSQL データベースサービス "Firestore" はモバイルアプリケーションのバックエンドとして利用され、リアルタイムクエリー機能を備えています。その主な特徴として以下の 4 点が挙げられます。

- 容易な利用方法(Ease of Use): 事前のデータベース設計に時間をかけずにアプリケーションんを開発をスタートできます。また、一般的な NoSQL データベースと異なり強い整合性を持った ACID トランザクションをサポートしています。
- サーバーレス環境と高速なスケーリング(Fully Severless Operation and Rapid Scaling): 完全サーバーレスサービスで、Google のデータセンター内で稼働する分散データベース Spanner にデータが保存され、高速なオートスケーリングが可能です。
- 柔軟で効率的なリアルタイムクエリー(Flexible, Efficient Real-time Queries): データベース上でのデータ変更をリアルタイムにクライアントに通知・反映することが可能で、この機能によりクライアントのリアルタイム UI 更新が容易になります。
- オフライン操作(Disconnected Operation): モバイルデバイスがオフラインの場合でも、ローカルキャッシュによりデータの参照や書き込みが可能で、デバイスがオンラインになったタイミングでデータベースに反映されます。

参考 - "Firestore: The NoSQL Serverless Database for the Application Developer (2023)": https://research.google/pubs/pub52292/


Skeet Firestore は、さらに TypeScript を使ってこの Firestore を型安全に利用することで、変更に強いソフトウェア開発を可能にします。

詳しくは 下記 Skeet 公式ドキュメントを御覧ください。

Skeet 公式ドキュメント (Skeet Firestore): https://skeet.dev/ja/doc/plugins/skeet-firestore/

## どんなアプリがつくれるの？デモ AI チャットアプリを使って想像してみましょう
![SkeeterAppSample16-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/cf81b85f-16ce-c7ac-0dd1-cae02c05dd3a.png)


Skeet は Firebase 上に自動スケールするアプリを構築できるフルスタックサーバーレスフレームワークです。

今までアプリのリリースやサービス公開には、アプリケーションコードとサーバーの用意が必要で、特にサーバーの構築・管理には大きなコストがかかっていました。

Google Cloud、Firebase の提供するサーバーレス環境はこのサーバー構築・管理を不要にします。すべてのサーバーインフラはユーザーの使用に合わせて自動でスケーリングするため、詳細なアクセス予想や負荷対策のリソース管理はもう必要ありません。

Skeet は iOS・Android・Web アプリの開発のために、これらのサーバーレス製品をワンコマンドで構築・管理できます。そのため、Skeet 開発者はすぐにアプリケーションのロジックに取り掛かることが可能です。そして、書いたアプリのデプロイは保証されています。

Skeet を使えば、OpenAI の ChatGPT API を活用したアプリケーションもすぐに構築しリリースすることが可能です。

Skeet チュートリアルを完了させた状態のアプリをデモとして公開しています。

Skeet デモ AI チャットアプリ: https://skeeter.app/

このデモの様に、一般的にアプリケーションが行う認証やデータベースの利用等、アプリの開発及び公開に必要なものはすべて揃っています。

バックエンド、フロントエンド共に TypeScript を利用していますが、必要に応じて Python 等もバックエンドとして関数毎に利用できるため、機械学習が必要になった場合にも対応できます。

Skeet を活用してたくさんの役に立つアプリが生まれることを信じて、これからも開発・改善を続けてまいります。

## 新しいアプリ開発を体感してください
![EffortlessServerlessSkeet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/25d9290a-8fdb-f1de-e52c-73c8a99fdb8a.png)


新しいアプリ開発を体感してください。

すぐに iOS・Android・Web アプリを開発し公開できます。

Skeet チュートリアルでは、実際にこのデモのような AI チャットアプリを構築し、すぐにリリースすることができます。

ぜひお試しいただけますと幸いです。

Skeet チュートリアル: https://skeet.dev/ja/doc/backend/quickstart/
【VSCode】画面配色の設定項目一覧


## 画面配色の設定項目
```json-doc:setting.json
{
  "workbench.colorCustomizations": {
    "editor.background": "",  // エディタの背景色
    "editor.foreground": "",  // エディタの前景色
    "editorGroup.border": "", // 複数のエディタを横に並べた時の境界線の色
    "editorLineNumber.foreground": "", // エディタの行番号の色
    "editor.selectionBackground": "",  // エディタカーソルの背景色
    "errorForeground": "",  // エラーメッセージの全体的な前景色

    "button.background": "",  // ボタンの背景色
    "badge.background": "", // バッジの背景色

    "input.background": "",  // 入力ボックスの背景
    "input.border": "",  // 入力ボックスの枠線
    "input.placeholderForeground": "",  // プレースホルダ

    "scrollbarSlider.background": "",  // スクロールバー背景色
    "scrollbarSlider.hoverBackground": "",  // ホバー時のスクロールバー背景色

    "statusBar.background": "", // ワークスペースを開いていない状態のステータスバー背景色
    "statusBar.foreground": "", // ワークスペースを開いていない状態のステータスバー前景色
    "statusBar.noFolderBackground": "",  // フォルダーを開いていない状態のステータスバー背景色
    "statusBar.debuggingBackground": "",  // プログラムをデバッグしている時の背景色
    "statusBar.border": "",  // ステータスバーの枠線
    "statusBarItem.prominentBackground": "",  // ステータスバー内で強調する項目の背景色

    "list.activeSelectionBackground": "",  // 選択された項目のリスト/ツリー背景色
    "list.hoverBackground": "",  // ホバー時のリスト/ツリーの背景
    "list.invalidItemForeground": "",  // 無効な項目のリスト/ツリーの文字色

    "activityBar.background": "",  // アクティビティバーの背景色
    "activityBar.foreground": "",  // アイコン
    "activityBar.border": "",  // アクティビティバーとサイドバーの境界線
    "activityBarBadge.background": "",  // 通知バッジの背景色
    "activityBarBadge.foreground": "",  // 通知バッジの文字色

    "titleBar.activeBackground": "", // タイトルバーの背景色
    "titleBar.activeForeground": "", // タイトルバーの文字色

    "sideBar.background": "",  // サイドバーの背景色
    "sideBar.foreground": "",  // サイドバーの文字色
    "sideBar.border": "",  // サイドバーとエディターの境界線の色
    "sideBarTitle.foreground": "",  // サイドバータイトルの前景色

    "editorGroupHeader.tabsBackground": "",  // タブの背景色
    "tab.activeBackground": "",  // アクティブなタブの背景色
    "tab.activeForeground": "",  // アクティブなタブの文字色
    "tab.border": "",   // タブを区切るための境界線
    "tab.activeBorder": "",  // アクティブなタブの下の線
    "tab.inactiveBackground": "",  // 非アクティブな色の背景色
    "tab.inactiveForeground": "",  // 非アクティブなタブの文字色
  }, 

```
Active Record マイグレーションについて

## 概要
Active Record マイグレーションは、Railsでデータベースのスキーマ変更をRubyのDSLを使って管理するための機能です。これにより、データベース設計の変更がRubyのコードで表現され、バージョン管理の対象となります。

## マイグレーションの作成

新たなテーブルを作成するためのマイグレーションは、以下のコマンドで作成します。

```bash
rails generate migration CreateProducts name:string description:text
```

このコマンドは`CreateProducts`という名前のマイグレーションを作成し、`name`と`description`というカラムを`products`テーブルに追加します。

## マイグレーションの実行

マイグレーションを実行するには、以下のコマンドを使います。

```bash
rails db:migrate
```

このコマンドは未実行のマイグレーションすべてを実行し、データベースのスキーマを更新します。

## マイグレーションのロールバック

間違ったマイグレーションを実行した場合や、マイグレーションの結果を元に戻す必要がある場合は、以下のコマンドでロールバックできます。

```bash
rails db:rollback
```

このコマンドは最後に実行されたマイグレーションを元に戻します。

Active Record マイグレーションは、データベースのスキーマ管理を容易にし、チーム開発やデプロイメントのプロセスをスムーズにします。

## 参考
- [Active Record マイグレーション - Railsガイド](https://railsguides.jp/active_record_migrations.html)
- [ディープロ DPro / エンジニアのプロのスタートラインに立つならディープロ | マイグレーションとは？](https://diveintocode.jp/blogs/Technology/RailsMigration1)
vagrant box add でVagrant failed to initialize at a very early stage:が出た

# 事象
下記サイトを参考にさせていただき、vagrantでCentOS7のboxをaddしようとしたらエラーが出た。

https://qiita.com/kanazwk/items/6d0c62480580a570cbb5

[app.vagrantup.com](https://app.vagrantup.com/bento/boxes/centos-7.7)からダウンロードしたboxを格納したフォルダでコマンドプロンプトを開き、
```ruby:コマンドプロンプトにて
> vagrant box add centos7 b91ca53e-fe9d-4b8f-bbe1-28f9206011c8
                    ↑                  ↑
           追加するboxの名前    app.vagrantup.comからダウンロードしたbox
```
を実行
![2023-06-23_19h16_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/5691a2d3-a80c-0622-457f-23cb2fc82b81.png)
↑エラーが発生

# 環境
Windows10
Vagrant 2.3.7
VirtualBox 7.0.8 r156879 (Qt5.15.2)
Vagrant box(Vagrant box)　v202005.12.0

# エラー内容

```ruby:コマンドプロンプトに出たエラー
Vagrant failed to initialize at a very early stage:

The version of powershell currently installed on this host is less than
the required minimum version. Please upgrade the installed version of
powershell to the minimum required version and run the command again.

  Installed version: N/A
  Minimum required version: 3
```

訳）
vagrantが早い段階で初期化に失敗
このホストに現在インストールされているpowershellのバージョンは最低限必要なバーン以下です。
powershellのインストールされているバージョンを必要最低限のバージョンにアップグレードして、コマンドをもう一度実行してください。

インストールされているバージョン：不明
最低限必要なバージョン：3


(日本語訳間違えていたら申し訳ありません。。。)

**powershellのバージョンが低いから、最低限3以上に上げろとのこと。**

# powershellのバージョンを確認
$PSVersionTable
変数でpowershellのバージョンを取得。

https://cheshire-wara.com/powershell/ps-cmdlets/system-service/how-to-check-psversion/#PSversionTable%E3%81%A7%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E5%8F%96%E5%BE%97

```ruby:powershellで実行
> $PSVersionTable
```
実行結果
![2023-06-23_22h54_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/b4dc6c50-2510-62ca-ff4c-0ce14e7a5755.png)

powershellのバージョンは「5.1.19041.3031」と、エラーに出ていた3以上というのはクリアしていそう。。。

※コマンドプロンプトでは、
```ruby:コマンドプロンプトで実行
> powershell $PSVersionTable
```
を打つ

http://piyopiyocs.blog115.fc2.com/blog-entry-857.html


![2023-06-25_16h36_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/b4349218-bd1e-9b4b-d2f5-74fd221b61d5.png)


因みに、コマンドプロンプトで同コマンドを打つとコマンドが無いと怒られる。
![2023-06-23_23h17_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/8923acb5-ff34-1ca3-b50b-a3db42dfcc57.png)

# 原因

どうやら、powershellのバグのようです。

> So it seems it's powershell 's bug.

https://github.com/hashicorp/vagrant/issues/12355
 
# 対応(？)

下記サイトにあった
> 根本的な原因・解決法がわかっていないがエラーメッセージからすると「powershellが見つからない」か「powershellからの応答がない」のが原因と思われる。

より、コマンドプロンプトではなく **powershellでもう一度コマンドを実行** してみた。

```ruby:powershellにて
> vagrant box add centos7 b91ca53e-fe9d-4b8f-bbe1-28f9206011c8
```

https://teratail.com/questions/343287



実行結果
![2023-06-23_23h32_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/be545402-f352-1f90-df7c-25462f2576e3.png)

できた！！

念のため、boxが追加されたかを確認。


```ruby:コマンドプロンプトにて
> vagrant box list
```
![2023-06-23_23h34_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2330584/6122f8ce-dc95-d510-faea-d30998613b4f.png)

追加されている！！

以上、同じような事象が起きた際の参考にしていただければと思います。
【AWS】【GCP】GCEにSSM Agentをインストールし、AWS Systems Managerからログインしてみました

# 前書
AWSのSystems Managerのセッションマネージャー機能はあまりにも便利すぎで、個人的にはそのサービスが大好きです！！

SSM Agentさえサーバー内にインストールしておけば、アウトバウンド通信がAWS側のSystems Managerとの疎通がさえできていれば、Systems Manager機能がフル活用することができます。

なので、GCP側のGCEにSSM Agentをインストールし、AWSのSystems Managerのセッションマネージャー機能から利用してみました！

# １．AWS側でアクティベーション作成
まず、Systems Mangaer側に`Systems Manager` -> `ハイブリッドアクティベーション` -> `アクティベーションの作成`を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/5e28b65e-1a62-8a55-6f7d-49ec71999f91.png)

生成された`Activation Code`と`Activation ID`はメモっておいてください
![截屏2023-06-23 23.34.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/bb133d83-823c-2f12-585e-5fb1e32a8eb9.png)

# ２．GCE側で実装
まずGCEを作成します。今回私はUbuntuのGCEを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/a0daaeec-177d-8480-bcf1-359b7daaacae.png)

UbuntuインスタンスにSSHでログインして、以下のコマンドを実行します。
なお、下記コード中の`activation-code`、`activation-id`はそれぞれ上記メモって置いた情報を置換してください。`region`にはAWSのSystems Managerが利用しているリージョンを記入してください。
```
mkdir /tmp/ssm
curl https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/debian_amd64/amazon-ssm-agent.deb -o /tmp/ssm/amazon-ssm-agent.deb
sudo dpkg -i /tmp/ssm/amazon-ssm-agent.deb
sudo service amazon-ssm-agent stop
sudo -E amazon-ssm-agent -register -code "activation-code" -id "activation-id" -region "region" 
sudo service amazon-ssm-agent start
```

参考URL：

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-install-managed-linux.html

# ３．AWS側でセッションマネージャーでログイン
上記のコマンド実行完了後に、アクティベーションの`登録済みインスタンス`が`1`に変更したことを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/60702e87-1127-8a00-bb6c-dde5c17e009b.png)

セッションマネージャー側で、GCP側のインスタンスを選択の上、セッションを開始します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/4cb6c4b3-d2fb-e963-3009-1dbd7bdadf9e.png)

無事にログインできることを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/7423b92f-a57b-b456-c615-8ce0f03481dc.png)

# その他
プライベートキーのローテーションもサポートされているので、下記の手順を参考の上設定していただけます。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-install-managed-linux.html#ssm-agent-hybrid-private-key-rotation-linux