OmniAICreator/Qiita-1.07M huggingface dataset:
Railsでの状態保持と永続的セッションの実現方法

### はじめに
今回はRailsチュートリアルの9章が難しかったので自分なりにまとめてみました。
状態を保持することは、ウェブアプリケーションで非常に重要です。状態とは、ログイン状態やカートに入れた商品など、ユーザーの行動に応じて変わるデータのことです。Railsではこの状態を保持するために`session`や`cookies`といった仕組みがあります。

---

### 1. なぜ状態保持が必要なのか？

#### なぜ必要か？
ウェブは「ステートレス（状態を持たない）」と言われています。具体的には、一度ページを閉じたらその前の情報（ログインしていた、カートに何を入れていた等）が全部失われてしまいます。これでは、ユーザーが毎回ログインし直したり、カートに商品を再度追加する手間が発生してしまいます。そこで、これらの情報を一時的にでも保存しておく必要があります。

---

### 2. `session`で短期間の状態をどう管理するか

#### なぜ必要か？
ユーザーがウェブサイトを閲覧している途中で、ログイン状態やフォームの入力状態などを保持しておくことで、ユーザーはよりスムーズに操作できます。

#### コード例
```ruby
# ユーザーIDをsessionに保存
session[:user_id] = @user.id
```

#### 使い方
1. ユーザーがログインすると、そのユーザーのIDが`session[:user_id]`として保存されます。
2. ユーザーがサイト内で移動しても、このIDを使って「この人はログインしているんだな」とサーバーが認識できます。
3. ユーザーがブラウザを閉じると、この`session`情報は消えます。つまり、セキュリティの観点からも比較的安全です。

### 3. `cookies`で長期間の状態をどう管理するか

#### なぜ必要か？
`session`と違い、`cookies`はブラウザを閉じた後も情報が残ります。例えば、「次回から自動でログインする」ような機能を作る際には、`cookies`が必要です。

#### コード例
```ruby
# ユーザーIDを暗号化してcookiesに保存
cookies.signed[:user_id] = @user.id
```

#### 使い方
1. ユーザーが「ログインしたままにする」にチェックを入れてログインすると、その情報が`cookies`に保存されます。
2. ユーザーが再度ウェブサイトを訪れると、`cookies`に保存された情報を参照して自動的にログイン状態になります。

#### 注意点
- `cookies`はブラウザに長期間保存されるため、セキュリティの観点から重要な情報は暗号化するなどの対策が必要です。

### 4. 永続的セッションの実現方法

#### なぜ必要か？
永続的セッションはユーザーがブラウザを閉じた後も、そのログイン状態を保持する機能です。これによりユーザーが毎回ログインしなくてもよくなり、使い勝手が大幅に向上します。

#### コード例
```ruby
# 記憶トークンと記憶ダイジェストの作成
remember_token = SecureRandom.urlsafe_base64
remember_digest = Digest::SHA1.hexdigest(remember_token)

# cookiesとデータベースに保存
cookies.permanent.signed[:remember_token] = remember_token
@user.update_attribute(:remember_digest, remember_digest)
```

#### 使い方
1. まず、`SecureRandom.urlsafe_base64`を使ってランダムな文字列（記憶トークン）を生成します。
2. このトークンをSHA1でハッシュ化し、それを`remember_digest`として保存します。この値はデータベースにも保存します。
3. 次に、`cookies.permanent.signed[:remember_token] = remember_token`とすることで、このトークンを暗号化して永続的な`cookie`として保存します。
4. ユーザーがサイトに再訪した際には、この`cookie`に保存されたトークンとデータベースの`remember_digest`を照合します。一致すれば、ユーザーはログイン状態と認識されます。

#### 注意点
- セキュリティが非常に重要なので、トークンは必ず暗号化して保存してください。
- 永続的セッションは便利ですが、セキュリティリスクもあるため、例えば公共のコンピュータでは使わないように注意が必要です。

### 5. ログアウトの実装

#### なぜ必要か？
セキュリティとプライバシーを保つためには、ログアウト機能が不可欠です。ログアウトすることで、保存された`session`や`cookies`の情報を削除します。

#### コード例
```ruby
# sessionとcookiesを削除
session.delete(:user_id)
cookies.delete(:remember_token)
```

#### 使い方
1. ユーザーがログアウトボタンをクリックすると、上記のコードが実行されます。
2. `session`と`cookies`に保存されたユーザー情報が削除され、ログアウトが完了します。

---

### まとめ
この記事では、状態を保持する理由とその具体的な手法について、`session`と`cookies`を例に解説しました。これらは、ユーザーが快適にサービスを利用するためには欠かせない機能です。

---

### おわりに
ウェブアプリケーション開発での「状態管理」は初めての方には少し難しく感じるかもしれませんが、何事も慣れな気がします。頑張って開発していきましょう！
ゼロから始めるGolang①

# はじめに
**本記事について**
初めまして！Golangを学び始めましたので，備忘録＆みなさまの導入の助けになればと思い記事にします．＃Qiita初投稿なので，お手柔らかに
1. （本記事）開発環境の設定
2. （予定）基本的な知識
3. （予定）簡単なWeb開発
  
の順で書いていくつもりです．
## Golangとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3305858/b0eb2765-231c-59cb-7294-005323527d5a.png)
可愛いマスコットキャラGopherくんで有名ですね．
特徴はこの絵にもあるとおり，
- シンプルで親しみやすい
- 処理速度が速い
- 効率的にメモリの管理ができる
- 並列処理が可能

などなど，大規模な開発であったり，チーム開発に向いた特徴を持っています．

# Goの開発環境を作る
この記事ではGo言語が実行できる環境を整え，`"Hello World!"`が出力できるところまで進めていきます．

**開発環境**
- Mac OS 13.2.1
- VSCode 1.81.1
- Homebrew 4.1.6

Homebrewのインストールは[こちら](https://brew.sh/index_ja)
VSCodeのインストールは[こちら](https://code.visualstudio.com/)

## Goのインストール
まずはGoのインストールとその確認をしましょう．
ターミナルから
```bash
$ brew install go
$ go version
go version go1.21.0 darwin/arm64
```
のように出力されればOK．

## Goの拡張機能をインストール
次にVSCodeでGoの拡張機能をインストールします．
VSCodeの拡張機能のページから`go`と検索します．
![スクリーンショット 2023-09-06 12.57.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3305858/9a6aec25-3ecc-567b-5cbb-d6ea8555d945.png)

- Go（優秀なサポート）
- Go Nightly
- Go Test Explorer（テスト機能の強化）
- Go Outliner（アウトラインの強化）

あたりをインストールしておくと良いです．他にもおすすめが紹介されているので[拡張機能10選](https://yurupro.cloud/2531/)を参照ください．
### 依存パッケージをインストール
拡張機能が依存するパッケージもインストールしましょう．
VSCodeのコマンドパレット(`Command + Shift + P`)から`GO: Install/Update tools`と検索します．
選択すると，
![スクリーンショット 2023-09-06 13.05.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3305858/6bd517a4-5c71-7dc7-9b61-a7a261cd2b98.png)
のようにたくさん出るので全選択してインストールします．![スクリーンショット 2023-09-06 13.07.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3305858/43795824-cbf8-a089-fa8a-65965dbe964b.png)
と出れば完了です．

## プロジェクトを作成
では`"Hello World!"`を出力するためのプロジェクトを作りましょう．GO1.16以降Go-Moduleモードがデフォルトで追加されるようになり，GOPATH配下に/src/...とプロジェクトを作るという制約はなくなったそうです．詳細は[こちら](https://zenn.dev/nobonobo/articles/4fb018a24f9ee9)

ですので，好きな場所で
```bash
$ mkdir go-learning
$ cd go-learning
```
としてフォルダを作成しましょう．
この`go-learning`をモジュールにするためにある宣言をします．
```bash
$ go mod init <モジュール名>
```
<モジュール名>はgithubに公開する際は`github.com/githubのユーザ名/モジュール名`とし，公開しない場合は`好きなモジュール名`をつけます．基本はフォルダと同じ名前にしておくのが良さそうです．

次に実行ファイルを作成します．作成したフォルダ内に`main.go`ファイルを作成します．ファイルの中身は，
```go:main.go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World!")
}
```
`fmt`は標準パッケージで，入出力の処理などが行えます．
では実行しましょう．
ターミナルから，
```bash
$ go run main.go
Hello World!
```
出来ましたか？
目標の通り，`"Hello World!"`の出力まで行えたので本記事はここまでとします．

# 最後に
今日はGoの実行環境を作成しました．package?import?mod?などわからないことが出たままではあるので，次回はその辺りも調べてまとめようと思います．ありがとうございました．

**参考記事**
[Goのプロジェクトの基本](https://zenn.dev/nobonobo/articles/4fb018a24f9ee9)
[VSCodeでGo言語の開発環境を構築する](https://qiita.com/melty_go/items/c977ba594efcffc8b567)
[少しずつ育てるGo言語のプロジェクト構成](https://zenn.dev/foxtail88/articles/824c5e8e0c6d82)
スッキリわかるJava入門 第３版を読んでみて- part17 -例外[後編]

# はじめに
こんにちは　◤●ㅅ●◥ﾉ
前回に続いて例外について学びました！

## 第１７章　例外[後編]

### 5.さまざまなcatch構文
:pencil2: try-catchの基本構文
```
try{
 本来の処理
}catch(例外クラス 変数名){
 例外が発生した場合の処理
}
```
#### 2種類以上の例外をキャッチする
基本構文でキャッチできる例外は１つのみ
ただcatchブロックを複数記述することができる

```
try{
 FileWriter fw = new FileWriter("data.txt");
 fw.write("hello!");
 fw.close();
}catch(IOException e){
 System.out.println("書き込みが失敗したよ");
//ファイルへの書き込みが失敗した時の例外処理
}catch(NullPointerException e){
 System.out.println("nullだよ");
//nullだった時の例外処理
}
```

##### ザックリと例外をキャッチする方法
catchブロックに指定する例外クラスは多態性のザックリ捉えた型を使用することができる
IOException,NullPointerExceptionもザックリ捉えるとException
どちらの例外が発生しても１つのcatchでキャッチできる

##### 後片付け処理への対応
後片付け処理は「例外が発生しても、またはしなくても、たとえ強制になる時でも必ず実行しなければいけない処理」
→finallyブロックを使い実行する
##### :pencil2: 例外発生の如何を問わず必ず処理を実行する
```
try{
 本来の処理
}catch (例外クラス 変数名){
 例外が発生した場合の処理
}finally {
 例外があってもなくても必ず実行する処理
}
```
tryブロックを開始したら、必ず最後にfinallyブロックの内容も実行されることが保証されている

:star: 必ずfinallyを使うべき状況
後片付け処理は、必ずfinallyブロックに記述する
（ファイル・データベース接続・ネットワーク接続など）

##### 自動的にclose()が呼ばれるtry-catch文
tryの直後に丸カッコで囲まれた複数の文を記述する

##### :pencil2: try-with-resources文
```
try(closeによる後片付けが必要な変数の宣言){
 本来の処理
}catch(例外クラス　変数名) {
 例外が発生した場合の処理
}
```

### 6.例外の伝播
mainメソッドで例外をキャッチしなかったら...
例外をキャッチしないと実行時エラーとなり強制終了してしまう。
mainメソッドではなく呼び出した先のメソッドで例外が発生したらどうなるのか？

<前提>
・mainメソッドでsubメソッドを呼んでいる
・subメソッドの中でsubsubメソッドを呼んでいる
・subsubメソッドでは処理中に何らかの例外が発生することがある
<subsubメソッド実行時に例外が発生した時>
1.subsubメソッドで例外をキャッチしてなければ、「subsubはこの例外的状況にお手上げ」
　となり、呼び出し元のsubメソッドへ対応が委ねられる
2.subメソッドでもキャッチしないと、その対応はmainメソッドに委ねられる
3.mainメソッドでも例外をキャッチしなければ強制終了される

上記のような感じで例外はキャッチされないとメソッドの呼び出し元までたらい回しにされる
→このような現象を __例外の伝播__ という

基本的には例外の伝播は発生することはないが __スロー宣言__ を行うことで
発生するチェック例外をキャッチせずに呼び出し元へと伝播させることができる
:pencil2: スロー宣言による例外伝播の許可
```
アクセス修飾　戻り値　メソッド名（引き数リスト）
 throws 例外クラス１、例外クラス２...{
 メソッドの処理内容
}
```
スロー宣言を行うことでtry-catch文がなくてもコンパイルエラーにならない

##### :star: スロー宣言によるチェック例外の伝播
メソッドを定義するとき、チェック例外をキャッチしないことをthrowsで宣言できる
この時メソッド内でtry-catch文によるキャッチをしなくてもエラーにならない

:thinking:なぜコンパイルエラーにならないのか
:grinning:スロー宣言は、そのメソッドが自分の呼び出し元が処理すると表明する宣言だから

##### :star:<font color="#ff4d4d">スロー宣言が及ぼす影響</font>
1.呼び出される側のメソッドは、メソッド内部での例外のキャッチが義務ではなくなる
2.呼び出す側のメソッドは、例外を伝播してくる可能性があるメソッド呼び出しをtry-catch文で囲む義務が生まれる

チェック例外に対する処理方法について２つの指針のどちらかを選び義務を果たす必要がある

方針１.チェック例外を自分で処理
【意味】
　自分で例外的状況を解決し、例外が発生してもお手上げせず、呼び出し元には伝播させない
【義務】
　発生する可能性がある、すべてのチェック例外をtry-catch文で処理する

方針２.チェック例外を処理せず、呼び出し元に委ねる
【意味】
　自分で例外的状況を解決できない、例外が発生したら呼び出し元に処理を任せる
【義務】
　メソッド定義にスロー宣言を加え、委ねる例外の種類を表明する

### 7.例外を発生させる
:pencil2: 例外的状況の報告(例外を投げる)
`throw 例外インスタンス;`

※スロー宣言で使うthrowsと例外的状況の報告に使うthrowはまったく違うもの

## まとめ
後片付け処理は状況にかかわらず必ず実行するfinallyブロックに記述される
呼び出し先で例外をキャッチされなかった場合呼びだし元へと例外が伝播する
スロー宣言を行うことで例外の処理を呼び出し元に委ねることができる
throw文を使うことで、開発者自ら例外を発生することができる

前編に比べて後編は例外処理について少し難しく感じた
後片付け処理の部分がいまいち理解し切れていないかなと感じたので、そこを復習していければと思います

今回もありがとうございました！
ではまた〜　◤●ㅅ●◥ﾉ"
Reactでdialog試してみた。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/dialog

作ったサンプル

```tsx:dialog.tsx
import { useRef } from "react";

export function Dialog() {
  const dialogRef = useRef<HTMLDialogElement>(null);

  const handleShowDialogEvent = () => {
    if (dialogRef.current) {
      dialogRef.current.showModal();
    }
  }

  const handleCloseDialogEvent = () => {
    if (dialogRef.current) {
      dialogRef.current.close();
    }
  }

  return (
    <>
      <button onClick={handleShowDialogEvent}>ダイアログ表示</button>

      <dialog ref={dialogRef}>
        <h1>サンプル</h1>
        <div>ダイアログが表示される。</div>
        <button onClick={handleCloseDialogEvent}>閉じる</button>
      </dialog>
    </>
  )
}
```
AWS ECS Fargateを使用してMattermostを構築してみた

# なぜMattermostを構築したのか？
エグゼクション社内では、メインで使用しているチャットツールの他に、メインが障害等で使えなくなったときに使用するサブツール（グループウェアのメッセージ機能）が用意されていました。
が、そのサブツールが使いづらい・・・という意見が多く出たため、”この際、社内のエンジニアの手でAWS上にMattermostを構築してみようか！”ということで、この社内プロジェクトが走り始めました。

初めてのコンテナ技術だったので、紆余曲折しましたが、なんとか動作したので、そのノウハウ共有にこの記事を書きました。

一からの構築方法というよりポイントとなる点を書いていきます。
間違っている！なんだそれ！など、ツッコミどころもあるかと思いますが、大目に見ていただけると嬉しいです。

# システム構成
こんな感じの構成で構築しました。ところどころ端折ってます。![1690682687236-dZqY91XEYu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552913/7a31867f-fc96-7010-93d0-3c0d0fd692d7.png)

画像やテキストファイルなどの保存場所としてEFSを使用し、その他データはAuroraを使用しています。　
Secrets Managerで管理用のEC2に接続し、そこからECS Execでコンテナ内部に入ったり、5432ポートでDBを触りに行ったりします。（ECS ExecはMattermostのチーム削除など、システムコンソールからではできない操作に使用します。）
ECRにMattermostのイメージを置いて、そこからECSを起動しています。（MattermostのイメージはDockerhubから）

# 構築全体の流れ
S3（.envファイル置き場）→EFS→ECR（リポジトリ作成、イメージのプッシュなど）→RDS（Aurora）→ECS→ALB→EC2（管理用）

今回は、存在するだけでお金のかかるサービスを後回しにして作成しているので、違和感があるかもしれません。
なお、IAMやVPCなどNW周り、CloudWatchやログなどの運用管理サービスは省略します。

# 構築のポイント
##### ・Mattermostの設定値を変更する
Mattermostのシステムコンソールの[環境]タブの設定値については、GUI上から設定を変更しても、コンテナ再起動時に設定内容が反映されず消えてしまいます。
そのため、変更したい設定はタスク定義にECSの環境変数に設定するか、envファイルとして引き渡す必要があります。
設定値に対してどの変数を設定する必要があるのかは以下のドキュメントを参照してください。

https://docs.mattermost.com/configure/environment-configuration-settings.html

![1690682788359-gfaushzAyb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552913/e6aa0720-7ba2-ada4-4ea6-4febe7775415.png)

##### ・参照先DBをAuroraに向かせる
参照先のDBは環境変数で設定します。
コンテナに環境変数を設定するには、タスク定義から環境変数を設定するか、S3に.envファイルを配置し、タスク定義作成時に「ファイルから追加」でS3の.envファイルのパスを指定し、環境変数を設定するかの2つ手段があります。
今回は、タスク定義から直接環境変数を設定しました。

<設定した環境変数>
キー：MM_SQLSETTINGS_DATASOURCE
値：postgres://{DBユーザ名}:{DBパスワード}@{エンドポイント}/{DB名}

なお、実際にこの方法で構築する場合は、この変数にはDBの認証情報が含まれているため、Secrets Managerを使用することを推奨します。
Secrets Managerを使用する方法は以下を参照してください。

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/secrets-envvar-secrets-manager.html


##### ・EFSに画像やテキストファイルを保存する
MattermostにアップロードされたファイルはEFSなどのコンテナ外のストレージに保存しないと、再起動時に消えてしまうので、EFSにファイルを保存するように設定します。
これをしないとテキストや画像ファイルの共有やアイコンの画像設定ができません。
Mattermostのデフォルトは、mattermost/data/配下にファイルが保存されます。
なので、コンテナマウントポイントのソースボリュームにEFSを指定し、コンテナパスにmattermost/data/を指定することで、EFSにファイルが保存されるようにします。

##### ・ECSサービスのコンピューティングオプション
「キャパシティプロバイダー戦略」を選択すると、ECS Execを行うことができないため、ECS Execを行いたい場合には、「起動タイプ」を選択する必要があります。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/ecs-exec.html#ecs-exec-considerations

※ECS Execは現在(2023年9月6日)、Auto Scaling グループのキャパシティープロバイダーを使用して起動されたタスクに対応していません。

![1690682825259-rbizxMsFZP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552913/de3301b5-70e8-7de6-6312-453272ea7c91.png)

# まとめ
今回は社内サブチャットツールということで、あまり使用しない見込みだったため、Fargateを採用しました。
中に入っていじれるから、とりあえずはEC2か～と思われるかもしれませんが、AWS FargateでもECS Execで中に入れますし、余計なコストや管理面での手間がかかりません。落ちたら自動で上がってくる設定も簡単です。
Mattermostも無料で使用可能で、使ってみるとSlackみたいで使いやすく、モバイルアプリでも使用できるので、今回の構成はサブシステムにはもってこいだと感じました。
ただ、FreeプランのMattermostだと、AD認証ができません。サーバーに招待するにはリンクを共有するか、メールを送る必要があります。
特定の人に限定したアクセスにするためにはAWSかMattermostの設定に工夫が必要かもしれません。

AWSとコンテナの知識が多少あればすぐに構築できると思うので、勉強ついでにやってみてはいかがでしょうか。
VanJS x Parcelで環境構築する方法

以前VanJS x Vite x TypeScirptで環境構築する方法の記事を投稿しました。

https://qiita.com/mori_goq/items/90bf167aa9b4649e1597

VanJSの公式に、「ViteやParcelなどのツールを使用してWebアプリケーションを簡単に構築できます。」と書いてあるので、今回はParcelでVanJSが使えるように環境構築する方法をご紹介します。

> making it handy to build web applications with tools like Vite or Parcel.

https://vanjs.org/start

## 環境構築

### 実行環境

Node.jsが推奨のバージョンであれば問題ないと思います。

```shell
$ node -v
v18.17.1
```

### Parcelの環境構築

まずはParcelの環境構築から始めます。プロジェクトのディレクトリを作成してプロジェクトに移動します。

```shell
$ mkdir vanjs-parcel
$ cd vanjs-parcel
```

Parcelをインストールします。

```shell
$ npm install -D parcel
```

`src/index.html`ファイルを作成します。

```shell
$ mkdir src
$ touch src/index.html
```

`src/index.html`に以下を記述します。

```html:src/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <title>My First Parcel App</title>
  </head>
  <body>
    <h1>Hello, World!</h1>
  </body>
</html>
```

`package.json`に以下を記述します。parcelのバージョンは変更する必要ありません。

```json:package.json
{
  "name": "my-project",
  "source": "src/index.html",
  "scripts": {
    "start": "parcel",
    "build": "parcel build"
  },
  "devDependencies": {
    "parcel": "^2.9.3"
  }
}
```

以下コマンドでParcelが起動します。

```shell
$ npm run start

> start
> parcel

Server running at http://localhost:1234
✨ Built in 194ms
```

ブラウザで http://localhost:1234 にアクセスして以下が表示されれば、Parcelの環境構築が完成です。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1125523/0fc38c31-dee9-83a7-d953-ac3c15acbfaa.png)



### VanJSを使えるように環境構築

VanJSをインストールします。

```shell
$ npm install vanjs-core
```

`src/index.html`を以下のように書き換えます。

```html:src/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <title>My First Parcel App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="main.js"></script>
  </body>
</html>
```

`src/main.js`ファイルを作成します。

```shell
$ touch src/main.js
```

`src/main.js`に以下を記述します。

```javascript:src/main.js
import van from 'vanjs-core'

const App = () => {
  const { div } = van.tags

  return div('こんにちは')
}

van.add(document.getElementById('app'), App())
```

ブラウザで http://localhost:1234 にアクセスして以下が表示されれば、VanJS x Parcelの環境構築の完成です🎉

![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1125523/baf8d523-153e-5980-10bf-127b2ff99a2c.png)


## まとめ

今回はVanJS x Parcelで環境構築する方法をご紹介しました。個人的にはViteで環境構築する方が多いですが、Parcelは依存関係が少なくシンプルなセットアップなため、細かな設定をする必要が無い場合はParcelでも良いかもしれません。

## 最後に

### GoQSystemでは一緒に働いてくれる仲間を募集中です！

ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=8fac01f520b6d24b7097
OpsRamp ワークフローのScript Taskについて

本記事では、OpsRamp ワークフローのScript Taskについて説明します。
![scripttask1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/f0431f08-4a45-78c7-e91b-730f16bbce1c.png)

# 概要
OpsRampのワークフローには、管理デバイスに対してスクリプトを実行できるScript Taskがあります。Script Taskは、OpsRamp Agentから実行するスクリプトを実行するAgent型とOpsRamp AgentをインストールしたAnsibleホストから実行するAgentless型の2種類あります。
また、Signal Start Eventと組み合わせることにより特定のアラート発生時にスクリプト実行することやTimer Start Eventと組み合わせることにより定期的なスクリプト実行することが可能です。

# 設定の説明
プロパティには、以下のような意味があります。

- Agent
Select Category: 予め設定したスクリプトのカテゴリを選択
Script Name: 予め設定したスクリプトを選択
Resource Id: 対象のリソースIDを指定
Run As: Default user または Other user を選択、Default userはAgentが実行されているユーザ、Other userは設定したcredentialのユーザ
![scripttask_properties_agent.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/16b7f4e9-e5f2-281a-fe4f-1ad1dbf7e026.png)

- Agentless
Integration: 予め設定したAnsibleインテグレーションを選択
Playbook: 予めAnsibleインテグレーションで設定したPlaybookを選択
Inputs: Playbookに渡す引数を指定
![scripttask_properties_agentless.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/d1a7e3ba-67e0-2a63-99bf-4704218dd8d4.png)

# 設定例
下記では、アラートが上がったリソース上でAgent型のスクリプトを実行する際の設定例を示します。
Resource Id に \$\<start_event_id\>.alert.resource.uuidを入力することにより、アラート情報のリソースIDを指定することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/301a1dba-8e39-abd0-af89-066f75fff767.png)

# Appnedix
- Agent型のスクリプト設定方法
Automation \> Scriptsから設定することができます。

- Agentless型のスクリプト設定方法
Ansibleホストに対し、OpsRamp Agentをインストールする必要があります。
Setup \> Integrations and AppsからAnsibleインテグレーションをインストールし、Ansibleホストを選択します。
Ansible Playbookを登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/9003a0d0-e996-4837-4c46-ec51ed6b2203.png)


---------------------------------------
[<img width = 250 height = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344939/111de30a-4d33-aa33-5c7d-83d9015093e6.png">](https://www.vistanet.jp/knowledge-base/)
coeiroinkのengineとeditorを別のマシン上で動かす

### やりたいこと

・engineはGPU、またはハイエンドCPUを搭載したマシン上で動かしたい。
・しかしeditorはノートPCやタブレット上で動かしたい。
・この要件のためにRDP等、画面転送するような仕組みは使いたくない。(遅延も気になるし帯域も無駄)


### 問題となる仕様

問題になる仕様は2点です。
・engineは、127.0.0.0.1:50032でlistenする。そのためlocalhost以外からのアクセスを受け付けない。
・editorは127.0.0.1:50033に接続しようとする。そのためlocalhost以外に接続できない。

### 手法

オプションや設定ファイルの変更で、Listen設定、接続先を変更できないか調べてみましたが、情報が見つかりませんでした。

そこで、portproxyを使って転送します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421201/4809c873-901e-2357-85c1-75105b427527.png)

PC1側で実行
```
netsh interface portproxy add v4tov4 listenport=50032 listenaddr=0.0.0.0 connectport=50033 connectaddress=[PC2のIP]
```
PC2側で実行
```
netsh interface portproxy add v4tov4 listenport=50033 listenaddr=0.0.0.0 connectport=50032 connectaddress=127.0.0.1
```

先にPC#2側でengine.exeを実行しておきま、次にPC#1側でCOEIROINKv2.exeを実行します。
これで、軽いノートPC側ではeditorのみを起動し、実際の音声合成処理はリモートで処理することができました。

### 問題点１
ネットワークが不調だとPC#2側への接続に失敗し、ローカルで「engine.exe」を起動しようとしてしまいます。
PC#1側は「COEIROINKv2.exe」ファイル単体で動きますので、engine/speaker_infoディレクトリは削除しておきます。

### 問題点２
PC#1とPC#2のいずれでeditorを起動しても、一方で単語辞書に登録した内容は、他方の単語辞書画面には反映されません。engineとeditorの両方を再起動しても、各端末で登録した内容のみが表示されます。
どうやら辞書データは、editorを起動した端末のAppData\Roaming\coeiroink-v2\dictionaryStore.jsonで管理されているようです。
そしてeditorで「辞書登録」画面を開くと、editor側の辞書データ（dictionaryStore.json）でengine側の辞書データ（user.csv・user.dic）を上書きする仕組みのようです。
そのため、複数の端末で辞書を登録する場合は両端末のdictionaryStore.jsonをマージしないと、最後に「辞書登録」を開いたeditor側で登録した辞書のみが有効になってしまいます。
puppeteer  (node.js) のスクリプト例 – BASIC認証 + テキスト入力 + ボタンクリック + スクリーンショット撮影

```js
// package.json
//
// {
//   "dependencies": {
//     "puppeteer": "^21.1.1"
//   },
//   "type": "module"
// }

// $ node example.js

import puppeteer from 'puppeteer'

async function sleep(delay) {
  return new Promise((resolve) => setTimeout(resolve, delay))
}

(async () => {
  const browser = await puppeteer.launch({headless: false})
  const page = await browser.newPage()

  const url = 'https://example.com'

  //Basic認証のAuthorizationヘッダーを設定
  const BASIC_AUTH_USERNAME = 'username'
  const BASIC_AUTH_PASSWORD = 'password'
  await page.setExtraHTTPHeaders({
    Authorization: `Basic ${new Buffer(`${BASIC_AUTH_USERNAME}:${BASIC_AUTH_PASSWORD}`).toString('base64')}`,
  })

  const response = await page.goto(url, { waitUntil: ['domcontentloaded'], timeout: 60000 })

  if (response) {
    const status = response.status()
    const statusText = response.statusText()

    console.log(status)
    console.log(statusText)

    await sleep(1000)

    await page.type("[id='email']", 'example@example.com')
    await page.type("[id='password']", '************')

    await sleep(1000)

    await page.screenshot({path: './step1.png'})

    await page.click("[id='submit']")

    await sleep(1000)

    await page.screenshot({path: './step2.png'})

  }

  await browser.close()
})()
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
[Flutter] インスタグラムのプロフィール画像の表示の実装をしてみた

![スクリーンショット 2023-09-06 15.58.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/22eee3c4-ad47-f012-5005-3cc52375e822.png)



こんにちわ。いせりゅーです。
開発している中で、インスタグラムのプロフィール画像の表示がいいなと思い、Flutterで実装できないかなと思ったりしました。色々調べたり、してみたところ、実装ができましたので共有させていただきます。

# 実装したいやつ

こちらです。(例を推しにしてしまいました🙇)


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/9af407b4-2253-a82f-00f0-e03bf0639430.gif" width="50%">


# 実装していく

```dart
  showDialog<void>(
      context: context,
      builder: (_) {
        return BackdropFilter(
          filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20),
          child: AlertDialog(
            elevation: 0,
            backgroundColor: Colors.transparent,
            content: CircleAvatar(
              radius: MediaQuery.sizeOf(context).size / 1.8,
              foregroundImage: CachedNetworkImageProvider(image),
            ),
          ),
        );
      },
    );
```


Flutterで実装してみた感じはこちらです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/e99198cf-515a-900d-3485-4ed8bf76b329.gif" width="50%">




# 最後に

どうでしょうか？少し違うものの似ている実装ができましたね。少しでも参考になれば嬉しいです😁

個人開発で作成しているアプリがリリース直前になって、権利関係でリリースができない状態になっています。泣きたい。でも、頑張ります👍
施策を考える時は、まずは良い問いを作るところから始めよう

## この記事は何
僕は普段プロダクトマネージャーとして施策を考えることが多いです。
この記事では、僕が施策を考えるときに特に意識している「良い問いを作る」という話を紹介したいと思います。

## 問いとは
「良い問い」とざっくり書きましたが、そもそも「問い」とは何でしょうか？
問いとは、思考を始める上での出発地点です。
問いが変われば考え方やアプローチも変わってきます。
つまり、良い問いを作ることができないと、どれだけ考えるのが得意でも結論にたどり着くことは難しいでしょう。

## 問いの良し悪しとは
前項で「問い」についての説明をしましたが、問いの良し悪しはどうやって判断すればよいでしょうか？

まず、良い問いとは具体的な目標に向けてどれだけクリアになっているかどうかです。
いわゆる「解像度」が高い問いであるとも言えます。

ここで僕がよくメンバーに話している例を記載します。

よく皆さんお腹が空いた時は「何か食べよう」と思うと思います。そして最終的には何かしらの選択をして食事をとるでしょう。
しかし、本当に「何か食べよう」と思って「何か」を文字通り食べている人は少ないと思います。
実際は例えば以下のようなステップで具体的に食べるものを決めているはずです。

- 何か食べたいな
- 今日の昼は中華だったから中華以外がいいな
- 明日は休みだしお酒とか飲んでも良いな
- 今日は給料日だからせっかくだし贅沢したい
- 今まで行ったことない新しいお店を開拓しようかな
- ...


このような思考を整理すると、結局この人は「何か」を探しているのではなく「中華以外の」「アルコールが飲める」「少し高めな」「新しいお店」を探しているのだとわかります。
つまりこの人は「中華以外のアルコールが飲める少し高めな新しいお店はどこか？/何か?」という問いを立てて何を食べるか考えているということになります。

このような具体的でクリアな問いを言語化することができている状態が「良い問い」だと考えています。

## 良い問いを立てるために意識していること

僕は良い問いを立てるために「立てた問いに対して『なぜ？』を投げかける」ことを常に意識しています。
基本的に曖昧な問いは「具体的には？」や「なぜ？」という問いを繰り返すと「例えば」や「なぜなら」という流れで具体的な要素や理由を挙げることができます。そしてそれらの内容を踏まえて問いを言い換えたり、内容を加えたりを繰り返していくことで曖昧さは減っていき、クリアな問いへと進化していきます。

物事を考える上でこのプロセスを意識的に踏めるか踏めないかで思考の質が大きく変わってきます。

例えば「何か食べたい」という問いをクリアにしていくとすると以下のような感じでしょうか。

- 例えば何が食べたい？
    - 特になし
- 逆に食べたくないなと思ったものは？
    - 中華
- なぜ？
    - お昼も食べたから
- 考えている候補の共通点はある？
    - お酒と一緒に食べると美味しそうなもの
- お酒が飲みたいのか？
    - 飲みたい
- いつも飲みたいと思っている？
    - そうでもない
- なぜ今日は飲んでもいいと思った？
    - 明日が休日だから
- 休日前ならいつでもお酒を飲みたいと思ってる？
    - そうでもない
- なぜ今日はOKなのか
    - 給料日でもあるので、お金にも余裕がある
- ...

## 最後に
今回は施策を考える上での「良い問いを作る」という重要性について紹介しました。

具体的な問いの立て方や、施策の考え方については多くの本で紹介されています。
僕が読んだ本の中でおすすめを最後に紹介します。

- [イシューからはじめよ――知的生産の「シンプルな本質」](https://amzn.asia/d/8wGAuOn)
- [DMM.comを支えるデータ駆動戦略](https://amzn.asia/d/huICEQd)
- [ジョブ理論 イノベーションを予測可能にする消費のメカニズム](https://amzn.asia/d/13c4LUb)
- [プロダクトマネジメント ―ビルドトラップを避け顧客に価値を届ける ](https://amzn.asia/d/fvO3UXM)
- [この1冊ですべてわかる 新版 コーチングの基本](https://amzn.asia/d/6kQxTTW)
ラズパイでpywebviewをインストールする方法

ラズパイでpywebviewを使いたいと思い、インストールしたのですがうまく動かず苦労したので備忘録として投稿します。

# 動作環境
RaspberryPi4 
Description:	Raspbian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

Python 3.9.2

# インストール方法

```
#まずはアップデートから
sudo apt update
sudo apt upgrade

#pywebviewのインストール
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-webkit2-4.0
pip3 install pywebview

```
# 経緯

多くのサイトには、
```
pip3 install pywebview
```
でインストールができると書いてあったので最初はpipでインストールしました。
しかし、いざ動かしてみるとこのようなエラーが……

```
ImportError: cannot import name 'Unpack' from 'typing_extensions' (/usr/lib/python3/dist-packages/typing_extensions.py)
```



こちらのエラーは

```
pip3 install typing_extensions --upgrade
```
で解決することができましたが、次はこのようなエラーが……
```
logger.warning('qtwebkit does not support _settings['private_mode']=False')
                                                         ^
SyntaxError: invalid syntax
```

ここから先が行き詰ってしまい、いろいろと調べたのですが原因がわからず……
とりあえずインストールをやり直してみようと思い、pywebview公式ページを調べたところ
aptによるインストール方法が書いてあったので試してみました。
その結果、エラーを出すことなく動いてくれました。
この方法でインストールするという情報がなかなか見つからなかったので記事にしました。

公式ページを確認することって大事なんだなと痛感いたしました……。


# 参考サイト
pywebview公式ページ

https://pywebview.flowrl.com/
XrayGPT: Chest Radiographs Summarization using Large Medical Vision-Language Models

:::note info
インフォメーション
母語が日本語じゃないので、変な日本語で論文をまとめようと思います。
どうぞよろしくお願いいたします。
:::
# モチベーション
1.大規模モデルをそのまま医療分野に使えない。
  近年Large-scale Vision-Language modelsの研究が盛んでいる。Vision-text pre-trainingを用いて、ゼロショットにしても高い性能が発揮できる。当然、医療にも使いたいですが、二つの問題点がある。一つ目が医療データ量が少ない、二つ目が医療分野の特殊性である。（「車や犬など」と「がんや炎症細胞など」の区別が全然違う）

2.医療AIの研究が主にテキスト分析のみ

→そのため、この論文が自由形式の質問（open-ended questions）に対応可能な新型対話式医療Vision-language model[XrayGPT]を提案した。
# 関連研究
1.Medical Chatbot
Chatdoctor (Li et al., 2023) [LLaMA model]
MedAlpaca (Han et al., 2023)[Based on LLM’s and finetuned on specific medical instructions]
PMC-LLaMA (Wu et al.,2023)[Based on LLM’s and finetuned on specific medical instructions]
DoctorGLM (Xiong et al., 2023)[Based on LLM’s and finetuned on specific medical instructions]

2.Large Language Vision Models(LLVM)
Image captioning
Visual question answering (Bazi et al., 2023; Liu et al.,2023; Muhammad Maaz and Khan, 2023)
Image generation (Zhang and Agrawala, 2023).
# Method
![スクリーンショット 2023-09-06 11.40.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1277696/fd129e1f-55db-8814-eb2b-e3ed197c5a9d.png)

事前準備：
・A pre-trained medical vision encoder (VLM) 
　　MedClip (Wang et al., 2022) 
・A medical large language model (LLM)
　　 Vicuna (Chiang et al., 2023).

繋がり：
①画像をVLMでencodeし、その後512次元にマッピングする（線形射影）
②A trainable linear transformation layerdで①の結果をlanguage embedding tokensに変換
③ ```###Doctor: XRXQ ###Assistant: XS```をLLMに入れておく。（XRが②の結果、XQが簡単な質問、XS：関連summary）

データセット：
・ MIMIC-CXR (Johnsonet al., 2019) reports：
　　　　377,110 images　and 227,827 associated reports
・ OpenI (Demner-Fushman et al., 2015) reports：
　　　　6,459 images and 3,955 reports.
・　Data cleaning
　　 gpt-3.5-turbo　modelの活用

学習：
MIMIC-CXRでtrain->OpenIでtrain
以下のフォマットでLLMに入れる。　
```###Doctor: <Img><ImageFeature></Img> <Instruction> ###Assistant:```
# 実験結果：
Rogue Score
GPT-based evaluation(perplexity,BLEU score,Self-BLEU score)
![スクリーンショット 2023-09-06 15.48.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1277696/7f7da43a-1cc8-3d34-4b33-c8444a4d62ba.png)
Javaで「引数があるコンストラクタ」の動作を確認してみた

# 概要
Javaで「引数があるコンストラクタ」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/constructor/index2.html

# 実装
以下のファイルを作成しました。
```CTest9.java
class CTest9{
  public static void main(String args[]){
    Television tv1 = new Television("居間");
    tv1.dispChannel();

    Television tv2 = new Television("台所");
    tv2.dispChannel();
  }
}

class Television{
  private int channelNo;
  private String place;

  Television(String newPlace){
    channelNo = 1;
    place = newPlace;
  }

  public void setChannel(int newChannelNo){
    channelNo = newChannelNo;
  }

  public void dispChannel(){
    System.out.println("現在のチャンネルは" + channelNo+ "です");
    System.out.println("設置してある場所は" + place + "です");
  }
}
```
以下のコマンドを実行しました。
```
$ javac CTest9.java 
$ java CTest9 
現在のチャンネルは1です
設置してある場所は居間です
現在のチャンネルは1です
設置してある場所は台所です
```

# まとめ
何かの役に立てばと。
Power Platformを知っていますか？#1

# はじめに
Power Platformというサービスを知っていますか？
私が携わっているプロジェクトで導入されているPower Platformについて、何回かに分けて紹介していきたいと思います。

人手不足が深刻なこのご時世ですが、世の中のIT化はどんどん進んでいます。
ただでさえ人手不足なのに、エンジニアも足りていないというダブルパンチな状況。
その影響もあり、非IT系社員にもITの知識が求められる時代に入ってきました。

エンジニア職でない人がいきなりアプリを作ったりするのはハードルが高くて無理！と思うかもしれませんが、そんな中、注目を集めているのがローコード(Low-Code)やノーコード(No-Code)のツールです。

### ローコード
必要最低限のソースコードを記述しながらアプリなどを開発できるツールやサービス。

### ノーコード
ソースコードの記述が不要で、GUIなどでアプリなどを開発できるツールやサービス。

# ローコード、ノーコードツールの紹介
実は既に世の中には非常に多くのローコード、ノーコードのツールが存在します。
一般社団法人NoCoders Japan協会（ノーコーダーズ・ジャパン協会）が公開しています「ノーコード・カオスマップ」(2022年8月版）を紹介します。

https://no-coders-japan.org/nocode-chaosmap-2

それぞれ、各業務に特化してはいるものの2022年8月時点でこれだけの数が存在します。
そんな山ほどあるサービスの中で、私が携わっているプロジェクトで導入されている**Power Platform**を紹介します！
KintoneやServiceNowなどCMで広告しているツールもありますが、Power Platformが広告をされているのは見たことがありません。
そのため、知名度としてはまだまだこれからかもしれません。

# Power Platformについて
Power PlatformはMicrosoft社が提供するサービスで、以下の4つのサービスを総称した名称です。
- Power Apps
- Power Automate
- Power BI
- Power Virtual Agents

それぞれは後ほど説明します。

Power Platformの一番の推しどころはやはり、Microsoft社製品との親和性の高さです。

社会人であればMicrosoft社のExcel、Teams、Sharepointなどに触れる機会は多いはず。Power Platformはこれらに対し自動で操作してくれるような機能が豊富に用意されています。

もちろん、Microsoft社製品以外にも多くのサービスとも接続が可能です。なんと、接続できるサービスの数は300をこえるとか。すごい数ですね！！

それでは、Power Platformの各サービスについて、簡単に説明していきます。

### Power Apps
GUI(Graphical User Interface)を使い、簡単なWebアプリを作ることができるサービスです。
私の感覚としてはPower Pointで資料を作成するような感覚で、図形を配置したりテキストボックスを配置したりすることで簡単にアプリを作成することができます。
また、データベースを基に自動でアプリを作成してくれる機能もあります。

### Power Automate
フロー図を書くような感覚で自動化処理を作ることができるサービスです。いわゆるRPAツールです。
Power Automateで作成したフローを　Power Appsから呼び出したり、スケジュールで自動実行ということも可能です。

### Power BI
いわゆるBIツールで、用意したデータを基に多角的な分析を可能とするデータの視覚化サービスです。
個人的な見解で言えばExcelのピボットテーブルの上位種のような印象です。　こちらも、Power AppsやPower Automateとも連携が可能です。

### Power Virtual Agents
チャットボットを作成するサービスでユースケース毎に独自のチャットボットを作成することが可能となります。

![ms-power-platform.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552913/e12e9d47-ac62-8f80-66fe-9b61e9e59c39.png)

# さいごに
今回はPower Platform全般についての紹介となりました。
次回以降は、よく使われているPower AppsやPower Automateを実際に使ってアプリを作成していきたいと思います。お楽しみに～。
ubuntu 22.04にnvidia-driver-535入れるためのメモ書き

# 経緯
自宅サーバ用（AI）に以下スペックのPCにubuntuを入れて、
グラボドライバーをインストールしようとしたらハマったので解決策を書いときます。
マザボ	PRO Z790-S WIFI
CPU	Core i5 13400 BOX
メモリ	D5D4800-16G2A
電源	1000w
グラボ	RTX3090
SSD	M.2 2280 1TB
ケース	PABYS PB30 ECB-PB30-WW-ARGB
cpuクーラー	AK400 R-AK400-BKNNMN-G-1
（え、マザボとグラボだけで十分だって？自作したレシピ公開したいだけですはい）

# ハマったところ
```
sudo apt update
sudo apt upgrade
sudo apt-get --purge remove nvidia-*
sudo apt-get --purge remove cuda-*
ubuntu-drivers devices
sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt update
sudo apt install nvidia-driver-535
reboot
nvidia-smi
```
ここで
```
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
```
これが出る。だる。

# 解決策
どうやらセキュアブートを解除しないといけないみたい。
rebootコマンドをした後に、UEFI起動で
４つの選択肢が出るが
２つ目の「enroll MOK」を選ばないといけないみたい。
参考サイトは「Change Secure Boot state」というメニューだったから、これが表示する人はこれっぽい。
ドライバインストール後の1回目のrebootしかUEFI起動しないから、再度する人はdriver削除からやったほうがいい。

https://nisshingeppo.com/ai/install-nvidia-driver/
STM32 LL UARTがOREで氏ぬ時の対処

こんにちは。STM32でLL使ってUARTで基板間通信させようとした時にOREで詰んでたのでその時の対処法をば。
## 結論
**割り込みを一旦止めてから**UARTを初期化する事で解決。
例(USART2、割り込み処理)：
```c++
// stm32〜_it.c

// 〜略〜

void USART2_IRQHandler() {
    /* USER CODE BEGIN USART2_IRQn 0 */

    // 〜略〜

    if(LL_USART_IsActiveFlag_ORE(USART2)) {
        LL_USART_ReceiveData8(USART2);
        LL_USART_DisableIT_RXNE(USART2);
        MX_USART2_UART_Init();
        LL_USART_EnableIT_RXNE(USART2);
    }

    // 〜略〜
}
```
## 考察というか憶測
OREのフラグ単体を折ったりしても解決しなかったし、何より参考記事だとHALで色んなフラグを折ったりしてるので受信完了あたりのフラグが悪さしてる、と思われる多分。
## 参考記事
https://qiita.com/Masacccch/items/77ce05ef1f657b99cab3

http://meerstern.seesaa.net/article/476512935.html
## 後記
ただでさえSTM32関連記事って少ない印象なのにほとんどが古いかHALでLLのだと全然転がってないのがツラい。
リファレンスとヘッダファイルだけが友達さ...とか言ってみたいなぁ
あと記事名に「氏ぬ」って入れるのどうなの
prettier×VSCode 保存時に自動で整形してもらう方法

# pretteier
pretteirとは、ソースコードの整形ツールのことで、コードのフォーマットを開発者間で統一することが可能である。
私自身、githubにpushするときに、毎回prettierをターミナルから実行していたが、毎回毎回これだと時間と手間がかかる上に、github actionsでテストが落ちたりするのも面倒である。そこで今回は、VSCode上でファイル保存時に勝手にprettierを実行してもらう方法を紹介する。

### prettierを使用することによるメリット
* 開発者間で同じ整形ルールで開発を行うことができる
* コードの品質を保つことができる

### 今回やっていくこと
VSCode上でprettierの拡張機能をインストールし、コードの保存時に自動でフォーマットを整形してもらえるようにしていく。そのため、今回はprettierの自動実行プラグイン導入の手順を追っていこうと思う。

### 導入方法
導入方法は簡単で、以下1~4の手順に沿って導入を行なっていく。
1. VSCodeで拡張機能「Prettier-Code formatter」をインストールする。
  拡張機能からPrettierと検索し、「Prettier-Code formatter」をインストールします。
![スクリーンショット 2023-09-05 13.19.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/66c42ba4-d106-af92-c6e6-7c22af29ea3d.png)

2. 設定から、保存時の設定を行う。
* 歯車マーク>設定を開く
 歯車のマークから、設定をクリックし、設定画面を開く。
![スクリーンショット 2023-09-05 20.45.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/fa12808c-e066-acfe-18de-a17728dc0d35.png)

* 検索窓で「save」と検索し、「Editor: Format On Save」にチェックを入れる
![スクリーンショット 2023-09-05 21.13.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/8a361ac4-6971-6607-8a71-8709b112ccff.png)


3.　defaultFormatterの設定をする。
* 設定画面の検索窓で 「defaultformatter」と検索
![スクリーンショット 2023-09-05 21.14.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/44529427-a5dd-60a7-8cfa-d1c4a4019735.png)

* 「Prettier Code formatter esbenp.prettier-vscode」にチェックを入れる。
![スクリーンショット 2023-09-05 21.15.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/d1dd7acc-0f23-f2b0-766f-3782c0c9fc93.png)

4.　設定の反映を行うために画面のリロードを行う。
これまでにやった設定を反映させるために画面をリロードします。
``` command + shift + P```でコマンドのパレットを展開し、「開発者：　ウィンドウの再読み込み」をクリックすることでVSCodeのリロードを行います。
![スクリーンショット 2023-09-06 15.25.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3552209/5a9f9b3b-60fb-74c5-5ff8-5f99c3ce5f2b.png)

### まとめ
この設定が完了すれば、ファイル保存時(```command + S```)に自動でprettierが実行されるはずである。効率的な開発を行うためにも是非導入を！

### 参考文献
* [VSCodeでファイル保存時にPrettierを走らせる方法](https://zenn.dev/k_kazukiiiiii/articles/670ebae0005872)
* [【VSCode】Prettirの使い方&おすすめ設定を紹介](https://ma-vericks.com/blog/vscode-prettier/)
【小ネタ】Reactのmaterial-tableで特定の行のみを編集可能とする

material-tableを使って特定の行のみを編集可能としたくて試していたがある罠にはまって中々できなかった。
同じような罠にはまる人がいるか分からないが一応記録として残しておきます。

## material-tableとは
Reactで使えるMaterial-UIをベースとしたデータテーブルコンポーネントとしてmaterial-tableというOSSがあります。 material-tableを使うことにより、Reactの標準のデータテーブルコンポーネントよりもフィルター、検索、ソートなどのテーブル機能を拡張することができます。

## 特定の行のみを編集可能とする
参考にした記事が特定の列を編集可能にする記事だったので、
私は特定の行を編集可能とする方法を調べていました。

https://qiita.com/orangeroad0922/items/36d27df9a5989e0d7ac9

特定の行を編集可能とするには、以下から``isEditable``を使えばいいんだなと分かり早速試してみました。
https://material-table.com/#/docs/features/editable

## isEditableを試してみる
上のページのExamplesからすぐ試せるので試してみてください。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480832/4d21b00f-cf9a-cf79-06cb-0867ee92e6f1.jpeg)

以下の追加箇所の行を追加してみます。

```jsx
// 省略
    <MaterialTable
      title="Editable Preview"
      columns={columns}
      data={data}
      editable={{
        isEditable: rowData => rowData.birthYear === 2017, // 追加箇所
        onRowAdd: newData =>
          new Promise((resolve, reject) => {
            setTimeout(() => {
              setData([...data, newData]);
              
              resolve();
            }, 1000)
          }),
// 省略
```

1行目はペンマークから編集できなくなり、
2行目はペンマークから編集できるままとなりました。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480832/0c0995e5-8f44-05a4-25ca-dd1f79dfa021.jpeg)

## 実際に実装してみるとうまくいかなかった
例でもうまく動いたし意気揚々と実際に実装してみたところ、全行編集可能なままでうまくいきませんでした。
これは結論から言うと自分が使っているパッケージのバージョンだと``isEditable``が使えないバージョンだったようです。
![003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2480832/52276c8e-6666-4198-a9fa-886df3b16f77.jpeg)
パッケージのバージョンを上げたらちゃんと特定の行のみを編集可能とするようにできました。

## まとめ
結局パッケージのバージョンが足りないということに中々気づくことができなかったが、うまくいかないときの原因の1つとしてバージョンで直った機能を確認するという教訓を得ました。
Leetcode 509. Fibonacci Number

# Problem
Fibonacci数列を求める問題です。

```
F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), for n > 1.
```

InputとOutputの例は次になります。
```
Input: n = 3
Output: 2
Explanation: F(3) = F(2) + F(1) = 1 + 1 = 2.
````

https://leetcode.com/problems/fibonacci-number/description/

## Key Idea
大きく分けて、f(n) → f(n-1) → f(n-2) ... と考えていくTop-downの方法と、f(1) → f(2) → f(3) ...と考えていくBottom-upの方法があります。

## Approach 1 : Top-down Approach (Recursion)
このアプローチでは、問題（n番目のフィボナッチ数を求めること）を部分問題（n-1番目とn-2番目のフィボナッチ数を求めること）に分解します。n番目から考え始めるのでTop-downアプローチと呼ばれます。再帰を使用してこれを実現します。

```python
class Solution:
    def fib(self, n: int) -> int:
        if n <= 1:
            return n
        else:
            return self.fib(n-1) + self.fib(n-2)
```


## Approach 2: Top-Down Approach using Memoization

このアプローチでは、再帰を使用してフィボナッチ数を求めますが、計算を高速化するために「メモ化」も使用します。メモ化とは、以前計算した結果を保存して再利用することで、同じ計算を繰り返さないようにする方法です。
![IMG_9614.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99549/39b40a3c-c9d6-ce26-b2d1-d18a061e62ad.jpeg)

```python
class Solution:
    memo = {0:0, 1:1}

    def fib(self, n: int) -> int:
        if n in self.memo:
            return self.memo[n]
        else:
            self.memo[n] = self.memo[n-1] + self.memo[n-2]
            return self.memo[n]
```


## Approach #3  Bottom-Up Approach using Tabulation
このアプローチでは、0からnまでのフィボナッチ数を順番に計算します。途中の結果を配列に保存し、新しいフィボナッチ数を計算する際に以前の結果を再利用します。




![IMG_9616.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99549/45508971-77ac-4e7a-dfbb-7b04a20a649f.jpeg)

```python
class Solution:
    def fib(self, n: int) -> int:

        memo = []
        memo.append(0)

        if n >= 1:
            memo.append(1)

        for i in range(2,n+1):
            memo.append(memo[i-1] + memo[i-2])

        return memo[n]
```

## Approach #4  Iterative Bottom-Up Approach
この解き方は、Approach 3と同じくBottom-upの方法です。ただし、テーブル全体をメモリに保持することなく、必要な直前の2つのフィボナッチ数だけを保持する方法を採用しています。そのため、メモリの節約が期待できます。

```python
class Solution:
    def fib(self, n: int) -> int:

        if n == 0:
            return 0
        elif n == 1:
            return 1
 
        prev_1 = 1
        prev_2 = 0

        for i in range(2,n+1):
            current = prev_1 + prev_2

            prev_2 = prev_1
            prev_1 = current

        return current
```


## Complexity Analysis
計算量は下記の様になります。

| Approach  |Time complexity  | Space complexity |
|:---:|:---:|:---:|
|1. Top-down Approach (Recursion)   | O(2^n) | O(n) |
|2. Top-Down Approach using Memoization   | O(n)  | O(n)  | 
|3. Bottom-Up Approach using Tabulation   |  O(n) | O(n)  |
|4. Iterative Bottom-Up Approach   |  O(n) | O(1)  |


## Reference
https://www.youtube.com/watch?v=dDokMfPpfu4
AWS CDK(Typescript) で LambdaEdge を使う

# 想定

1. クロスリージョンスタック(複数リージョンのスタックを連携)
2. [NodejsFunction](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html)を使っている（ts で書いたハンドラーをそのままデプロイできる construct）

# 結論

```cdk.ts
#!/usr/bin/env node
import * as cdk from "aws-cdk-lib";
import "source-map-support/register";
import { LambdaEdgeStack } from "../lib/lambda-edge-stack";
import { SampleStack } from "../lib/sample-stack";

const app = new cdk.App();

const account = process.env.CDK_DEFAULT_ACCOUNT;

export const REGION = {
  VIRGINIA: "us-east-1",
  TOKYO: "ap-northeast-1",
};

const lambdaEdgeStack = new LambdaEdgeStack(app, LambdaEdgeStack.name, {
  env: { account, region: REGION.VIRGINIA },
  crossRegionReferences: true,
});

const sampleStack = new SampleStack(app, SampleStack.name, {
  env: { account, region: REGION.TOKYO },
  lambdaEdgeFunction: lambdaEdgeStack.function,
  crossRegionReferences: true,
});

sampleStack.addDependency(lambdaEdgeStack);
```

```lambda-edge-stack.ts
import { Stack, StackProps } from "aws-cdk-lib";
import { CompositePrincipal, ManagedPolicy, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Construct } from "constructs";
import { join } from "path";

export class LambdaEdgeStack extends Stack {
  function: NodejsFunction;

  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const role = new Role(this, "LambdaEdgeExecutionRole", {
      assumedBy: new CompositePrincipal(
        new ServicePrincipal("lambda.amazonaws.com"),
        new ServicePrincipal("edgelambda.amazonaws.com") // デフォルトで生成されるロールはこれがないので追加
      ),
      managedPolicies: [ManagedPolicy.fromAwsManagedPolicyName("service-role/AWSLambdaBasicExecutionRole")],
    });

    this.function = new NodejsFunction(this, NodejsFunction.name, {
      entry: join(__dirname, "./handler.ts"),
      handler: "handler",
      runtime: Runtime.NODEJS_18_X,
      awsSdkConnectionReuse: false, // このプロパティを`false`にしないと、`LambdaEdge`は環境変数は使えないよエラーを出す
      role,
    });
  }
}
```

```handler.ts
import { Callback, CloudFrontRequestEvent, Context } from "aws-lambda";

export const handler = async (event: CloudFrontRequestEvent, context: Context, callback: Callback) => {
  console.log("hi mom")
};
```

# ポイント

1. `lambda-edge-stack.ts` で `awsSdkConnectionReuse: false`
2. cloudfront でのログ出力のため`lambda-edge-stack.ts` で ロールに`edgelambda.amazonaws.com`を付与必須

1 を `true` にすると `lambdaEdge` では環境変数は使えないエラーが出ます。
2 はデフォルトのロールも生成されるのですが、それだと ServicePrincipal に`lambda.amazonaws.com`しかないので、`edgelambda.amazonaws.com`を追加しないと

cdk デプロイ時に

```
Resource handler returned message: "Invalid request provided: AWS::CloudFront::Distribution: The function execution role must be assumable with edgelambda.amazonaws.com as well as lambda.amazonaws.com principals. Update the IAM role and try again.
```

というエラーが出るのでそのため新しくロールを作成しています。

# 参考

- https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-permissions.html#lambda-edge-permissions-function-execution
jetpack compose navigationを使ってnullableの値付き遷移を実装する方法

# はじめに
今回は、jetpack compose navigationを使ってnullableの値付き遷移を実装する方法を紹介していきます
### 本文
通常の画面遷移では下記のようにすれば`userId`に対してデータが格納されて遷移先で`userId`から取得することができます
```kotlin
val profileRoute = "profile/{userId}"

navController.navigate("profile/user1234")
composable(
        "profile/{userId}",
        arguments = listOf(navArgument("userId") { type = NavType.StringType })
    ) {
        Profile(navController, backStackEntry.arguments?.getString("userId"))
    }
```
では、遷移時に値が必ず渡されるわけではない場合はどのようにすればいいのでしょうか。
実装は下記の通りになります。
```kotlin
val profileRoute = "profile/?userId={userId}"

navController.navigate("profile/?userId=user1234")
composable(
        "profile/{userId}",
        arguments = listOf(
            navArgument("userId") {
                type = NavType.StringType
                nullable = true
            }
        )
    ) {
        Profile(navController, backStackEntry.arguments?.getString("userId"))
    }
```
ここで注意が必要なのは引数が複数ある場合です。
下記のようにすることで複数個かつ混合でも遷移することができます
```kotlin
// NonNullとNullable
val profileRoute = "profile/{userId}?userName={userName}"
// NullableとNullable
val profileRoute = "profile/?userId={userId}&userName={userName}"
```
### 最後に
今回は備忘録としての役目が強いですが、どなたかのお役に立てれば幸いです
XpathでIDを指定する – id("foo") 

# 方法

以下のいずれかで指定できるようだ


```
id("foo")
```

```
//*[@id="foo"]
```

# Playgroundで確認

![image](https://github.com/YumaInaura/YumaInaura/assets/13635059/f08358c8-71d9-401e-9c93-ee589424fd36)

https://scrapinghub.github.io/xpath-playground/



# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
Oracle File System (OFS)構築について

## はじめに
Oracle Database には 表領域を利用してファイルシステムを構成し、OS上にマウントして使用する Oracle File System (OFS)があります。Database をファイル・ストアとして使用するケースとして代表的なものがDBFSですが、Oracle Clientがインストールされていないノードからアクセスする必要がある場合、OFSを使用してファイル・システムをNFSマウントする事が可能です。
<https://docs.oracle.com/cd/F39414_01/adlob/dbfs_access_using_ofs.html#GUID-034FC394-AE15-4D16-8AA0-45CC0A70CACC>

## DBMS_FSパッケージの概要
DBMS_FS パッケージは Database File System (DBFS)を利用したファイルシステムの作成・マウント・アンマウントや破棄など基本的な操作を行う事ができるプロシージャで構成されています。19c以降では、PDBでも利用可能でPDBごとに最大5までのファイルシステムがサポートされます。
![ofs_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470713/bdba5d6e-fdcd-a459-b93f-a6c3c795dc4b.png)
参考にしたサイトURL
<https://docs.oracle.com/cd/F19136_01/arpls/DBMS_FS.html#GUID-F42D42FE-B1B6-4A5F-8DC3-BBDA98CC09F9>

## OFS 環境構築手順
### 1)	FUSEのインストール
```
[root@ofstest05 ~]# yum install fuse
```
OSの再起動

### 2)	表領域の作成
```
CREATE TABLESPACE "OFS" DATAFILE　SIZE 209715200
LOGGING ONLINE PERMANENT BLOCKSIZE 8192
EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULT
NOCOMPRESS  SEGMENT SPACE MANAGEMENT AUTO;
```
![ofs_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3470713/1ee2672f-9d43-5e2b-4a81-e53f55b82ed6.png)

### 3)	DBMS_FS によるファイルシステム作成とマウント
```
SQL> exec dbms_fs.make_oracle_fs(fstype=>'ofs',fsname=>'ofs_fs',fsoptions=>'TABLESPACE=OFS')
PL/SQLプロシージャが正常に完了しました。
SQL> exec dbms_fs.mount_oracle_fs(fstype=>'ofs',fsname=>'ofs_fs',mount_point=>'/ofs/data',mount_options=>'default_permissions, allow_other, persist');
PL/SQLプロシージャが正常に完了しました。
```
dfによる確認で、<font color="Red">/ofs/data</font> がOS上のマウント位置で確認できる
```
[root@ofstest05 ~]# df -hT
ファイルシス                 タイプ   サイズ  使用  残り 使用% マウント位置
devtmpfs                     devtmpfs    32G     0   32G    0% /dev
tmpfs                        tmpfs       32G     0   32G    0% /dev/shm
tmpfs                        tmpfs       32G   11M   32G    1% /run
tmpfs                        tmpfs       32G     0   32G    0% /sys/fs/cgroup
/dev/mapper/ol_ofstest05-root xfs       1000G   72G  929G    8% /
/dev/sda1                    xfs       1014M  228M  787M   23% /boot
/dev/mapper/ol_ofstest05-home xfs         84G  8.2G   76G   10% /home
tmpfs                        tmpfs      6.3G     0  6.3G    0% /run/user/54321
tmpfs                        tmpfs      6.3G   12K  6.3G    1% /run/user/42
/dev/fuse                    fuse        32G     0   32G    0% /ofs/data
tmpfs                        tmpfs      6.3G     0  6.3G    0% /run/user/0
```

[参考] OFSについての情報の収集は以下で可能
select * from v$ofs_stats;
select * from V$OFSMOUNT;

## 最後に
現状のOracle Database は Multitenant Architectureを全面に出し、Converge Database として様々なデータタイプ、ワークロードを一元管理する方向での実装も進めています。コンテンツとトランザクション、あるいは他のサービスとの連携において一貫性を保持したい場合はDBFSの方が良いのかも知れませんが、OFSは手順も簡素でリレーショナルのデータとファイルシステム上のコンテンツが緩い一貫性のもとで保ちやすいものであると言えると思います。
PowershellからOfficeの印刷ページ設定操作

ネット上にあまり情報が無かった（特にマージン設定とか）ので検索にかかる様残して置きます。
PowershellからOfficeで印刷をする際のページ設定について。
ここではExcelを例にしています。

```Powershell:Powershell
# Excelオブジェクトの作成
$excel = New-Object -ComObject Excel.Application

# 可視設定（Powershellからは$True/$False）で指定
$excel.Visible = $True

# 読み込みファイルパス取得、この例では同DIRのoutput.csvを指定
$excelFile = (Get-ChildItem "output.csv").FullName

# Excelを開く
$book = $excel.Workbooks.Open($excelFile)

# 1シート目を取得（インデックスは1から始まる）
$sheet = $book.Sheets(1)


# ここから印刷設定（PowershellでWithは使えない）

# ズーム設定。明示的にFalseにしないと印刷範囲が正しくならない事がある
$sheet.PageSetup.Zoom = $False

# 最上行を固定して印刷時に常時表示させる
$sheet.PageSetup.PrintTitleRows = "1:1"

# 幅に収まる様に自動でスケーリングする
$sheet.PageSetup.FitToPagesWide = 1

# 縦幅自動スケーリングを明示的に無効にする（0代入ではダメ）
$sheet.PageSetup.FitToPagesTall = $False

# 印刷向きを横に指定
$sheet.PageSetup.Orientation = 2

# 各種マージン指定。数値直で代入はエラーにならず反映もされない
$sheet.PageSetup.TopMargin = $excel.CentimetersToPoints(1)
$sheet.PageSetup.BottomMargin = $excel.CentimetersToPoints(0)
$sheet.PageSetup.LeftMargin = $excel.CentimetersToPoints(0)
$sheet.PageSetup.RightMargin = $excel.CentimetersToPoints(0)
$sheet.PageSetup.HeaderMargin = $excel.CentimetersToPoints(0)
$sheet.PageSetup.FooterMargin = $excel.CentimetersToPoints(0)

# ヘッダー＆フッター追加
$sheet.PageSetup.LeftHeader = ""
$sheet.PageSetup.CenterHeader = ""
$sheet.PageSetup.RightHeader = "&P of &N"
$sheet.PageSetup.LeftFooter = ""
$sheet.PageSetup.CenterFooter = ""
$sheet.PageSetup.RightFooter = ""

# 印刷（Powershell上で括弧を省略するとエラーとなるケースが多いので注意）
$sheet.PrintOut()

```

使えるVBAコードはここ参考
https://learn.microsoft.com/ja-jp/office/vba/excel/concepts/workbooks-and-worksheets/formatting-and-vba-codes-for-headers-and-footers