OmniAICreator/Qiita-1.07M huggingface dataset:
Service Cloud 学習メモ　ハンズオン②

# セルフサービス強化

## 公開サイト＆公開ナレッジ

### 「サービスの設定」を利⽤した公開サイトの作成

「サービスの設定」を開く。
「推奨設定」の「すべて表⽰」をクリック。
「Lightning コミュニティの設定」をクリック。
次へ　＞　ドメイン名：「serviceclouddemo1」　次へ　＞　
　　コミュニティ名：「funny」
　　コミュニティ URL：serviceclouddemo1.force.com/funny
　　✅このコミュニティを公開する
次へ　＞　コミュニティの詳細およびブランド設定　何もせず
次へ　＞　コンテンツを強調　「Service Cloud」、「Sales Cloud」を選択
次へ　＞　顧客からの問い合わせを受け付ける
　　ゲストユーザータブで「項目の追加」
　　「Web⽒名」を選択し、「項⽬の追加」
　　⽮印で任意の順番に並び替え、
次へ　＞　完了

### 作成されたサイトのカスタマイズ
設定　＞　すべてのサイト　＞　該当サイトの「ビルダー」

Home　＞　コンテンツの管理　＞　トピック　＞　ナビゲーショントピック
トピックに既存ナレッジを紐づけ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/2f60456f-6aa3-48fc-b568-815193a1407c.png)

新規作成されるナレッジにカテゴリに応じたトピックを⾃動的に付与す
るルールを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/3040b172-b17d-357a-aea0-310226f186ac.png)

コミュニティホームに表⽰する主要トピックの設定
必要なトピックを追加

### 外部ユーザのアクセス設定
ビルダー　＞　全般設定タブ　＞　外部ユーザプロファイルの変更
指定されたプロファイルにナレッジオブジェクトへの参照権限追加
カテゴリの参照権限追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/da5e10c7-279d-283a-3b26-98ee9fb72c25.png)

### API権限追加
Home　＞　管理　＞　詳細
✅公開 Chatter API 要求へのアクセス権をゲストユーザに付与



# Einstein ボット

## サービスの設定より、推奨設定の「すべて表⽰」をクリック
「顧客とのチャット」をクリックします

### チャットキューを作成
キュー名：Chat / グループ名：Chat Team
ユーザーを選択

次へ

作業負荷の調整はデフォルトのまま

次へ

Web サイト URL：現在のサイトURL

次へ

種別：サービス（ケースと取引先責任者）

次へ　＞　完了

## サイトでのチャットの許可

設定から「チャットの設定」を開き、「チャットAPIエンドポイント」のURLをコピーします。

「すべてのサイト」から、「ビルダー」をクリックします。

「設定」（左側の⻭⾞マーク）＞「セキュリティとプライバシー」にアクセス。

「セキュリティレベル」を[緩和されたCSP: インラインスクリプトと許可されたホストへのアクセスを許可]に設定
「＋信頼済みサイトを追加」をクリック。
サイト名：Chat
サイトURL：「チャットAPIエンドポイント」のURL

## サイトへの組み込みサービスチャットの追加

「コンポーネント」（左側の雷マークのボタン）から、[組み込みサービスチャット]を「テンプレートのフッター」にドラッグ＆ドロップします。

サービスの設定からクイック検索で[Einstein ボット]を選択し、設定をオンにする（右上）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/9b7a55a7-df35-f8ca-746e-67de15552f94.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/0c43c787-6401-0214-4e09-e8d0c4d8c9c4.png)

### 「新規ボットを作成」をクリック

「標準ボット」を選択し、「次へ」 →「最初から開始」を選択し、「次へ」
ボットの名前を⼊⼒、⾔語は[⽇本語]を選択し、「次へ」
「メニュー項⽬１」に[よくあるご質問の検索]、「メニュー項⽬２」に[トラブルシューティング]と⼊⼒し、「次へ」。
「組み込みサービスリリース」に[Chat Team]を選択し、「次へ」
そのまま「続⾏」をクリックし、ボットを作成。


## メインメニューへの事前作成済みダイアログの追加

Einsteinボットビルダー：

「メインメニュー」を選択。
「メニュー項⽬」を選択から、[エージェントに転送]および[チャットを終了する]を追加。
「よくあるご質問の検索」ダイアログを選択し、「次のステップ」で[別のダイアログを開始]＞[困惑]を設定。
「保存」

ドロップダウンメニューから「概要」をクリック。
「会話を記録」の「編集」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/6e37242a-cb96-49d9-ac72-feca7e906a07.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159211/ade0247b-1e4a-c959-0ff0-038b929a509a.png)

「有効化」
【Salesforce】数式で文字列結合（文字列連結）のやり方

数式は数式項目、入力規則、承認プロセス、フローなどで使用できます。

数式で文字列結合（文字列連結）する方法を紹介します。

演算子「&」を使う
演算子「+」を使う

使用例や詳細は以下から
https://hishikiryu.com/salesforce-formula-concat-text/
Oracle Cloud Infrastructure 認定試験について（前提）

# 資格名称と試験番号について
資格の正式名称、試験番号、難易度について記載する。
- Foundationsは公式動画を一通り見れば問題なく取得可能と思われるので、業務でOCIに触れる方はとりあえず取得しておいてよいと思われる。
- Architectはある程度の実務経験があれば取得可能と思われる。
- Architect Professionalは5年以上の実務経験と業界への関心が無いと厳しいと思われる。
    - いわゆる業務知識もある程度必要になる印象

## 2022年版
| 項番 | 資格名称  | 試験番号 |試験時間 | 出題数 | 合格ライン | 難易度 |
|:-:|:----------------------------------------------------|:----|:----|:----|:----|:-----:|
|1|Oracle Cloud Infrastructure 2022 Foundations Associate |1Z0-1085-22-JPN|90分|55問|65%|簡単|
|2|Oracle Cloud Infrastructure 2022 Architect Associate   |1Z0-1072-22-JPN|90分|55問|65%|普通|
|3|Oracle Cloud Infrastructure 2022 Architect Professional|1Z0-997-22-JPN|120分|50問|65%|難しい|

## 2023年版
| 項番 | 資格名称 | 試験番号 |試験時間 | 出題数 | 合格ライン | 難易度 |
|:-:|:----------------------------------------------------|:----|:----|:----|:----|:-----:|
|1|Oracle Cloud Infrastructure 2023 Foundations Associate |1Z0-1085-23-JPN|90分|55問|65%|簡単|
|2|Oracle Cloud Infrastructure 2023 Architect Associate   |1Z0-1072-23-JPN|90分|55問|65%|普通|
|3|Oracle Cloud Infrastructure 2023 Architect Professional|1Z0-997-23-JPN|120分|50問|65%|難しい|

:::note warn
- 試験番号で検索すると怪しげな問題集販売サイトが上位にヒットするので誤クリックに注意
:::
:::note info
- 2022年版の試験は2023/10/31に提供終了となり、2023年版の試験が9月以降に提供される予定
- 資格名称、試験番号ともに22→23への変更のみ
:::

# 取得に向けた準備
1. Oracle Universityが使用できるように手続きを取る
1. Learning PathよりJapanese:Become _資格名称_:_YYYY_ 日本語を受講する
    - 「Japanese: Become OCI Architect (Associate): 2022 日本語」等々
        - 日本語以外の言語の講座を誤って受講しないように注意する（1敗）
1. 練習問題を解く
1. 試験の申し込みをする
1. 受験用端末の準備を実施する
    - 会場へのチェックインに必要となるため、カメラが必須
    - LockDown Browserのインストールが必要
1. 受験する
    - 30分前から試験会場（Web)にチェックイン可能
    - この際、政府発行の顔写真付き身分証明書が必要（eKYC用、身分証と顔をカメラに写す）
        - マイナンバーカード、免許証、パスポート等々

<!-- 公式の更新があったら追記 -->

# Oracle Universityからの検索方法
下記リンク経由で適宜検索する。英語版のLearning Pathが検索で多数引っかかってくるので、
検索語句に「日本語」を含めることを推奨する。

https://mylearn.oracle.com/ou/search/Oracle%20Cloud%20Infrastructure%20%E6%97%A5%E6%9C%AC%E8%AA%9E

:::note info
- 2023/07/30時点では2023年版のLearningパス「Become A OCI...」の日本語版は公開されていない
:::

# 参考サイト、記事
先人の皆様に感謝

- Qiita内

https://qiita.com/liu-wei/items/f5cda0a0ff8b09c6bb35

https://qiita.com/liu-wei/items/9f8afc74f1061d8d86f7

- 公式

https://www.oracle.com/jp/education/news-172121-ja.html#20230605

https://www.oracle.com/jp/education/certification/examlist-172597-ja.html#5

https://education.oracle.com/oracle-exam-prep#testingSpace
【Ansible備忘録番外編】Ansibleのイベントに参加してみた。～現場を支えるPlaybook編

# 参加イベント
https://ansible-users.connpass.com/event/287975/

# はじめに
「Ansible備忘録」の番外編として、**Ansibleユーザー会**主催のオンラインイベントに参加してきました。
コード等の詳細は書けませんが、Ansibleや自動化に対する考え方について新たに知ることが出来たので、簡単にまとめつつ、感想を書き記したいと思います。

## ☆Ansible備忘録バックナンバー
https://qiita.com/pon1202/items/1b9eef884f6a07e1fc67

https://qiita.com/pon1202/items/ae41d0e8ddbb72745539

# まとめ
#### 簡単な実装例

今回のイベントで紹介されたansible実装事例の中で私が最も驚いたのは、
「**ネットワークOSが異なる場合でも、Playbookで自動識別し、OSを意識せずに設定可能にする**」
という実装方法でした。

<br>
<br>

ネットワークOSにはいくつか種類があります。
有名なものだと「IOS」や「JUNOS」が挙げられます。

種類が多い分には「へーそうなんだ」くらいで何とも思いませんが、コンピュータのWindowsOSとMacOSの違いで少し混乱するように、ネットワークOSもそれぞれの違いによって面倒な思いを味わうことになります。

今回挙げられた例では、
「IOSとJUNOS間でサブインターフェースの設定コマンドが違うこと」
が挙げられていました。

紹介された方の現場では、ネットワークOSがIOSとJUNOSの2つが混在しており、ネットワークOSごとに手順書や設定ファイルを作成する必要があった為、求められるスキルが非常に高かったと言います。
また、商用環境ともなると作業台数も多い上、サブインターフェースの設定数は相当数になる為、自動化が必要だったとのことでした。

実装内容としては、Playbook内でネットワークOSを自動識別できるタスクを導入し、その結果を基に各ネットワークOSごとの設定ファイルを作成（更新）するという内容でした。
これにより、作業者がネットワークOSごとのコマンドの違いを意識せずに作業できるようになったと言います。

<br>

#### Ansible実装によるメリット
>**①作業品質の向上**

⇒コマンド作成や設定変更が自動で実行される為、人的ミスが減少。作業時間の個人差が減り、作業時間の見積もりがしやすくなった。

<br>

>**②未経験者でも作業のハードルが比較的容易になった**

⇒ネットワークOSを意識することなく作業可能になったことや、作業ファイルがYAML形式の為、作業者の学習コストが低くなった。

<br>

#### Ansible導入後の課題
>①Ansibleによって自動化された作業の内容がイメージしづらくなった

⇒今回で言えば、「サブインターフェースの設定」という作業だが、この作業を**手動**で実施したことがない人からしたら、「今、自分はどんな作業をしているんだろう？」という状態になってしまう。


# 所感
上述した「Ansible実装によるメリット」は、日常的に業務でAnsibleを触るようになったからこそ頷けるのかなと思いました。

Ansibleの使い方や構造をある程度理解できれば、圧倒的にミスは減りますし、一つひとつの作業に対するハードルは低くなると思います。
しかし、Ansibleに**慣れるまで**の間は、「Ansible導入後の課題」で述べた観点には細心の注意を払う必要があると考えます。

私もAnsibleを業務で触るようになった当初は、「今、何がどう動いているのか」をしっかりと把握できていない状態のまま作業をしていました。
把握しようとplaybookの記載内容を確認してもよく分からず。。
調べてもよく分からず。。
このような漠然とした不安を抱えた状態で仕事をしていた時は非常にストレスを感じていました。

徐々に慣れていき、
「あ、この作業は○○コマンドと同様のことをしているのか！」
と気づいた時にようやく**Ansibleの素晴らしさ**に気が付けたと思います。

例えるなら、
「**マニュアル車の運転方法を知っているから、オートマ車のありがたさや楽さに気が付ける**」
みたいなもんでしょうか？:red_car:

Ansibleを実装することで得られるメリットは大きいと思いますが、インフラエンジニアとして最低限必要な知識や技術を身に付ける為には、「**手動**」での作業を経験することも大事なのかもしれません。
[laravel-admin]$formで条件付きのバリデーションを実装(Rule::when)

# laravel-adminとは
Laravelの管理画面作成用ライブラリ
https://www.laravel-admin.org/docs/en


# やりたいこと
`$form->rules()`にLaravelのバリデーションルールを記載するが、入力値によってバリデーションの内容を変更できるようにしたい

[※$form->rules()](https://www.laravel-admin.org/docs/en/model-form-validation)には書いてなさそう。
  

# どうやったか？→Rule::when()を使って実装した
Laravelのバリデーションルールで、`sometimes`のような条件付きでバリデーションを実行してくれるメソッド`Rule::when()`があるようなので、それを使って実装した。

https://www.magutti.com/blog/laravel-conditional-validation-using-rule-when-method


```php:実装サンプル
$form->currency('price_min', '価格（最小）')
    ->symbol('￥')->digits(0)->default(0)
    ->rules('required|integer|between:0,99999');

$form->currency('price_max', '価格(最大)')
    ->symbol('￥')->digits(0)->default(0)
    ->rules([
        'required', 'integer', 'between:0,10000',
        Rule::when(static fn($request) => $request->price_max > 0, ['gt:price_min']) ,
    ]);

```
→ 「価格(最大)」を設定する（１円以上）時だけ、「価格(最大) > 価格（最小）」のチェックをする


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/3a48abf7-b56d-ffd0-148c-e5661598e7fd.png)


# 終わりに
`Rule::when()`はLaravelのバリデーションページに書いてなかった・・
laravel-adminを使わないときでもwhenメソッドは便利そう

https://readouble.com/laravel/9.x/ja/validation.html#rule-date
Go言語プログラムの資料を自動生成する

※こちらは，会社の技術ブログとのクロスポスト記事です．元の記事は[こちら](https://www.timedia.co.jp/tech/20230606-tech)

業務でプログラムのドキュメント資料が必要になることがあります．
面倒な資料作成は，なるべく効率的に終わらわせたいですよね．
この記事では，Go言語プログラムの資料を自動生成する方法を紹介します．

# 前提
今回は例として，[Gin](https://github.com/golang-standards/project-layout)というウェブフレームワークの資料を自動生成したいと思います．
目標は，`docs`ディレクトリに資料を用意することです．最初に環境を用意します．

```bash:Bash
$ git clone https://github.com/gin-gonic/gin.git
$ go install github.com/gin-gonic/gin@latest
$ cd gin/
$ echo */ # ディレクトリ確認
binding/ docs/ examples/ ginS/ internal/ render/ testdata/
```
資料の生成に[godoc](https://pkg.go.dev/golang.org/x/tools/cmd/godoc)，資料の保存に[wget](https://www.gnu.org/software/wget/)を使います．
コマンドが通っていることを確認してください．

# 準備と実行
まず，スクリプトファイル`doc_generator.sh`を作成します．
```bash:doc_generator.sh
#!/bin/bash

godoc -http=:6060 & # バックグラウンド実行
RUNNING_PID=$!      # godocのPIDを取得
sleep 1             # godocの実行を1秒待機
wget -np -k -p -q -r -E http://localhost:6060/pkg/github.com/gin-gonic/gin/?m=all
kill ${RUNNING_PID} # godocの実行を終了

find localhost+6060 -name "index.html" -delete
mv -f localhost+6060 docs/localhost+6060
```
次に，資料へ遷移するhtmlファイル`docs/document.html`を作成します．
```html:docs/document.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0;
URL=localhost+6060/pkg/github.com/gin-gonic/gin/index.html@m=all.html">
</head>
</html>
```
以上で準備は完了です．プログラムを実行して資料を確認しましょう．
```bash:Bash
$ ./doc_generator.sh       # シェルスクリプト実行
$ start docs/document.html # ウェブブラウザで閲覧
```
![godoc1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308259/120b8d3e-1a77-9a0e-14d5-d85a5a9be40b.png)
ウェブブラウザで上の画面が表示されたら，資料の自動生成は成功です．

# 解説
`godoc`は，Go言語プログラムの資料を自動生成する便利ツールです．
実行すると`localhost:6060`が起動します．
（`http`の指定がない場合も`localhost:6060`が起動します）
作業のゴールは，`localhost:6060`起動中のみ閲覧できる資料を手元に保存することです．

通常`godoc`では，先頭が小文字のprivate関数と`internal`ディレクトリ配下のプログラムが見れません．
URLの末尾に`?m=all`と記述し，queryを追加するとプログラムが表示されるようになります．
![godoc2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308259/425e100c-2d15-26da-bcca-c07db5c9e583.png)
![godoc3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308259/1fdeabd4-f1c3-05fa-2219-6d1139f831a3.png)
左側はqueryなし，右側は`?m=all`queryありの資料です．
上は表示関数を比較した図，下は表示ディレクトリを比較した図です．

`doc_generator.sh`では，最初に`godoc`をバックグラウンドで実行し，`wget`で資料をファイルとして手元に保存します．
そして，バックグラウンドで実行している`godoc`を終了します．
次に，今回はquery`?m=all`を指定した資料が欲しいので，queryがない資料を削除します．
最後に，保存した資料を`docs`ディレクトリ配下に移動します．

`wget`のオプションの意味は，以下の通りです．
* np, no-parent: 親ディレクトリを無視する．情報を取得しない．
* k, convert-links: ローカルでの参照を有効にする．リンクを書き換える．
* p, page-requisites: HTML表示に必要な画像，CSS，JavaScript等も取得する．
* q, quiet: 途中経過等を何も出力しない.
* r, recursive: 再帰的にダウンロードする．
* E, html-extension: HTML形式のファイル末尾に.htmlを追加する．

# 終わりに
Go言語プログラムの資料を自動生成する方法を紹介しました．
便利な`godoc`を積極的に活用していきましょう．
これだけは知っておきたいDNSについて

# はじめに

DNSについて、最低限知っておきたいポイントを整理しました。誰かのお役に立てれば幸いです。

## 登場人物

## DNSを動かすために必要なこと

- 自分のドメイン名をインターネットでつけるようにする
    - 権威サーバーを動かすことで自分のドメイン名をインターネットで使えるようにする
- インターネットで使われているドメイン名を自分が使えるようにする
    - フルリゾルバー、スタブリゾルバー、特にフルリゾルバーを動かすことでインターネットで使われているドメインを自分で使えるようにする
- DNSを動かし続け、可用性を高める
    - 問題なく動作していることを確認すること、外部攻撃に備え動かし続ける必要がある

## DNS設計
### ユースケース

- 運用しているサービスやサーバーが少ない場合
サブドメインを作成せず、階層構造を持たないフラットな管理をする。

- 部門別のシステムをサブドメインを作成し、システム部門が全体の管理する場合
1つのゾーンで運用する

- 他部門が独自サブドメインを使ってサービスサイトを運用し、そのサブドメインもその部門が管理する場合
サブドメインを作成し、ゾーンの管理をその部門委任する

## 権威サーバーの可用性
### プライマリサーバーとセカンダリサーバーの設置

**役割**
プライマリサーバーがセカンダリサーバーからのゾーン転送の要求を受け、要求されたゾーンデータを送る

**考慮すること**

プライマリサーバーをセカンダリサーバーへのゾーン転送のコピー元としてだけ使う。
- 利用者からの問い合わせは受け付けないように構成する
プライマリサーバーのIPアドレスをプライベートにすることで、サイバー攻撃のリスクを減らすことができる

### ゾーン転送の仕組み
- AXFR
全てのゾーン情報を転送する
- IXFR
前回のゾーン転送情報をジャーナルファイルに記録しておき、ゾーン転送時にはジャーナルファイルを参照して差分情報のみを転送する

## 権威サーバーが応答する情報

- リソースレコードの表記フォーマット
    - TTLとクラスは省略できる
    - 同じドメイン名に複数のリソースレコードを設定する場合、二行目以降はドメイン名を省略できる

```jsx
<name> <TTL> <class> <type> <data>
```

## フルリゾルバー

**役割**

利用者の機器で動作するスタブリゾルバーから名前解決要求を受け付け、名前解決を行い結果を返す

**考慮すること**
- ネット上に設置された権威サーバー群に問い合わせを送るため、一般的にグローバルIPを割り当てる
- 利用者のネットワークからアクセスしやすい場所に設置することが望ましい

## 代表的に攻撃手法
### DNSリフレクター攻撃
DNSを利用したDoS攻撃の一つ

送信元IPアドレスを偽った問い合わせをフルリゾルバーや権威サーバーに送ることでそれらのサーバーが応答を攻撃対象に送りサービス不能の状態に陥らせる

**対策**

RRL(Response Rate Limiting)の導入
- ある宛先に対する同じ内容の応答が所定の頻度を超えた場合に、応答を送らない用にするなどの制限を発動させる
### ランダムサブドメイン攻撃

権威サーバーやフルリゾルバーに対するDDoS攻撃手法の一つ

問い合わせのドメイン名にランダムなサブドメインを付加することでフルリゾルバーのキャッシュ機能を無効化し、攻撃対象となる権威サーバーに問い合わせを集中させることにより、権威サーバーやフルリゾルバーをサービス不能の状態に陥らせる

**対策**
- 必要なアクセス制限がされておらず、外部から不正使用可能な状態になっているオープンリゾルバーをなくす
- 顧客側に設置された欠陥をもつホームルーターなどの機器を悪用されないようにするためにISP側でIP53Bを実施する
- フルリゾルバーにおいて、フィルタリングや問い合わせレートによる制限
- 監視の強化と攻撃検知する仕組みを導入

## 参考
[DNSがよくわかる教科書](https://amzn.to/3rQsYck)
【Unity】WebGLでGoogle Analytics(GA4)へカスタムイベントを送信する

# はじめに
WebGL以外のプラットフォームであれば[FirebaseUnitySDK](https://firebase.google.com/docs/unity/setup?hl=ja)を使うことができるので、[公式ドキュメント](https://firebase.google.com/docs/analytics/unity/start?hl=ja)に従うことでGoogle Analyticsを利用することができるのですが、WebGLプラットフォームには非対応のため、Jslib側からイベントを発行する必要があります。

# 実装方法

先ずは、以下スクリプトを適当なゲームオブジェクトをアタッチし、InspectorでGoogleAnalyticsの計測IDを入力しておきます。

```cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.UI;

public class GA4Manager : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void InitializeGoogleAnalytics(string measurementId);

    [DllImport("__Internal")]
    private static extern void LogGA4Event(string eventName, string eventParams);

    [SerializeField] private Button[] _eventButtons;
    [SerializeField] private string _measurementId;
    private void Start()
    {
        // GoogleAnalyticsイベント送信準備
        InitializeGoogleAnalytics(_measurementId);

        // ボタン押下でLogEvent(ボタン番号)が実行されるようにイベント登録
        _eventButtons.ToList()
            .ForEach(button => button.onClick.AddListener(
                () => LogEvent(Array.IndexOf(_eventButtons, button)
                )));
    }


    private void LogEvent(int buttonNo)
    {
        Dictionary<string, string> eventParams = new()
        {
            { "button_no", buttonNo.ToString() },
            { "send_to", _measurementId }
        };
        string jsonString = JsonConvert.SerializeObject(eventParams);

#if UNITY_WEBGL && !UNITY_EDITOR
        LogGA4Event("EventButtonClick", jsonString);
#endif
    }
}
```

`{ "button_no", buttonNo.ToString() },`の様に{パラメータ名,パラメータ値}を設定することができます。

次にPluginsフォルダに以下のjslibファイルを格納します。

```javascript
var GoogleAnalytics = {
    // Google Analyticsを初期化する
    InitializeGoogleAnalytics: function(measureIdPtr) {
        // 渡されたポインターから文字列に変換
        var measureId = UTF8ToString(measureIdPtr);
        var scriptTag = document.createElement('script');
        scriptTag.async = true;
        // Google Analyticsのスクリプトを読み込むURLを設定
        scriptTag.src = 'https://www.googletagmanager.com/gtag/js?id=' + measureId;

        // Google Analyticsスクリプトがロードされたときに実行される関数
        scriptTag.onload = function () {
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', measureId);
        };
        document.head.appendChild(scriptTag);
    },

    // イベントの送信
    LogGA4Event: function(eventNamePtr, eventParamsPtr) {
        var eventName = UTF8ToString(eventNamePtr);
        var eventParams = UTF8ToString(eventParamsPtr);
        var eventParamsObj = eventParams ? JSON.parse(eventParams) : {};
        gtag('event', eventName, eventParamsObj);
    }
};

// GoogleAnalyticsオブジェクトをLibraryManagerのライブラリに追加します
mergeInto(LibraryManager.library, GoogleAnalytics);


```

これでC#スクリプトにアタッチしたボタンに応じて、パラメータ名"button_no"がボタン番号として設定されたEventButtonClickイベントが発行されます。

以上
デジタル署名できるPowerShellコマンドを用意した

# TL; DR

下記のような使い方で、 `my-command.ps1` コマンドがPowerShell内で実行できるようになります。

```powershell:実行例
authenticate-to-script.ps1 'PowerShell Script for my-command.ps1' .\my-command.ps1
```


# はじめに

PowerShellスクリプトを用意するためには、デジタル署名が必要です。

https://kondeneenen.com/powershell_digitalsignature/

スクリプトを用意するだけで、毎回上記手順が必要になると大変です。
そこで、デジタル署名用のスクリプトを用意して、スクリプト作成を簡単にしたいです。


# デジタル署名用スクリプトの用意

以下手順にて、デジタル署名用スクリプトを用意します。


## スクリプトファイルの用意

以下コマンドを保存したPowerShellファイルを、パスの通ったディレクトリに配置してください。

```powershell:authenticate-to-script.ps1
Param(
  [parameter(mandatory=$true)][String]$Description,
  [parameter(mandatory=$true)][String]$ScriptFile
)

$ScriptFilePath = Convert-Path $ScriptFile

if ( $ScriptFilePath -ne $null )
{
  $ScriptFileFullPath = Get-Command $ScriptFilePath | select $_.FullName
  $Cert = New-SelfSignedCertificate `
    -Subject "CN=$Description, OU=Self-signed RootCA" `
    -KeyAlgorithm RSA `
    -KeyLength 4096 `
    -Type CodeSigningCert `
    -CertStoreLocation Cert:\CurrentUser\My\ `
    -NotAfter ([datetime]"2099/01/01")
  Move-Item "Cert:\CurrentUser\My\$($Cert.Thumbprint)" Cert:\CurrentUser\Root
  $RootCert = @(Get-ChildItem cert:\CurrentUser\Root -CodeSigningCert)[0]
  Set-AuthenticodeSignature $ScriptFileFullPath.Source $RootCert
}
```

https://stackoverflow.com/questions/13126175/get-full-path-of-the-files-in-powershell


## 用意したスクリプトファイルのデジタル署名

次のコマンドでデジタル署名をしてください（まだ上記スクリプトは利用できません）。

```powershell:デジタル署名のコマンド
# ファイルのフルパスを取得する
$ScriptFileFullPath = Get-Command authenticate-to-script.ps1 | select $_.FullName

# 証明書を用意する
$Cert = New-SelfSignedCertificate `
  -Subject "CN=PowerShell Script for authenticate-to-script.ps1, OU=Self-signed RootCA" `
  -KeyAlgorithm RSA `
  -KeyLength 4096 `
  -Type CodeSigningCert `
  -CertStoreLocation Cert:\CurrentUser\My\ `
  -NotAfter ([datetime]"2099/01/01")

# 証明書をルートに移動する
Move-Item "Cert:\CurrentUser\My\$($Cert.Thumbprint)" Cert:\CurrentUser\Root

# ルート証明書として自己証明する
$RootCert = @(Get-ChildItem cert:\CurrentUser\Root -CodeSigningCert)[0]
Set-AuthenticodeSignature $ScriptFileFullPath.Source $RootCert
```

上記までで、 `authenticate-to-script.ps1` が使えるようになりました。
実際に動作を確認してみてください。


## もし自己証明書を消したくなったら

以下を参考にしてください。

https://learn.microsoft.com/en-us/answers/questions/360772/powershell-commands-to-delete-personal-certificate


# おわりに

このコマンドを使って用意した最初のコマンドはdiff.ps1です。

https://qiita.com/Morichan/items/63a3b6905a1006d92ca2
Vue.jsで、リスト表示順の入れ替え処理を実装

# 結論
コンポーネントに表示させる項目を格納した配列を用意しておきます。入れ替えは用意しておいた配列の要素同士を入れ替える関数を作成すればOKです。その関数を実行すると、要素入れ替えのあと再レンダリングがかかり、リストの表示順が入れ替わったように見えます。

# 前提
- この記事ではCDN の Vue を使用しています。
- vue@3.3.4を使用しています

# サンプルコード
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="bGQQOae" data-user="kabuto64425" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kabuto64425/pen/bGQQOae">
  Untitled</a> by kabuto64425 (<a href="https://codepen.io/kabuto64425">@kabuto64425</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

以上です。
EC2 Instance Connectエンドポイント経由でWindows ServerにRDP接続してみた

## EC2 Instance Connectの概要

- 略称はEIC。2023年6月のアップデートでエンドポイント機能が登場。
- エンドポイント機能を使うとプライベートサブネットにあるEC2インスタンスにssh/rdpで接続できる
- session managerと異なりssm agentのインストールとEC2インスタンス側のSSMへのアクセス権付与&ルーティング設定が不要で管理が楽

## 参考ドキュメントとイメージ図
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect-Endpoint.html

![](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/images/ec2-instance-connect-endpoint.svg)


## RDPの場合の設定手順

### インスタンス起動
- VPCとsubnetはすでにあるものとする。また、Microsoft Remote Desktopもインストール済みとする。
- aws cliも設定済みとする（IAMユーザーアクセスキーはなるべく払い出したくないのでIAM Identity Centerを設定してaws configure ssoで利用するのがおすすめです）
- EC2インスタンスを起動。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/407dc1d0-3a90-bd27-7a23-31e8d518f454.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/8b02f834-f1ef-3dc8-43f3-7dfcd8c34aca.png)

    - 後続のMicrosoft Remote Desktopの設定でパスワードの指定が必要となるが、そのパスワードの取得のためキーペアの指定が必要。
    - セキュリティグループはdefaultを選択（defaultでなくても良いがEICエンドポイントから到達できるよう設定する必要あり）

### EICエンドポイントの作成
- EICエンドポイント作成
    - VPCコンソールのエンドポイントを開き、エンドポイントを作成をクリック
    - サービスカテゴリでEC2 Instance Connect Endpointを指定
    - VPCはEC2インスタンスと同じものを指定。
    - サブネットはプライベートを指定。
    - セキュリティグループはdefaultを指定（2023年7月30日現在は後からEICエンドポイントのセキュリティグループを編集できないので注意）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/487fda9d-7c13-7ed1-f5d1-1df82245e813.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/81bef414-1ee5-a16a-91ab-9a20b9d66e15.png)

- エンドポイントが作成されるまで3-4分待つ。

### RDP接続
- EC2のインスタンスIDをコピー。
- ローカルから以下のコマンドでトンネルを開通
    
    ```bash
    aws ec2-instance-connect open-tunnel --instance-id {instance_id} --remote-port 3389 --local-port 13389
    ```    
    - local-portは任意のポート番号で良い（ここでは13389を指定）
    - 正常に開通すると`Listening for connections on port 13389.`と表示されるのでターミナルはそのまま放置してマネコンに戻る
    
- EC2コンソールで対象のインスタンスを選択し、接続をクリック
    - ~~RDPクライアントタブのリモートデスクトップファイルのダウンロードをクリック~~
    - ~~ダウンロードしたファイルをローカルのMicrosoft Remote Desktopで開く~~ ⇒ このパターンでは動かなかった
    - パスワードを取得をクリックし、インスタンス起動時に指定したキーペアをアップロード or 内容をcatコマンド等で表示してコピーしパスワードを表示。
    - パスワードをコピー。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/cf1a02ae-af53-fa2e-65d3-8ccbeee4480e.png)


- ローカルのMicrosoft Remote Desktopを開き、Add PCをクリック
- PC Nameにlocalhost:13389を指定。
- User Account > Add User AccountからUsernameをAdministator、パスワードを先程コピーしたパスワードにしてAdd
- 作成したPCをダブルクリックすると接続が開始する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77606/088db7fc-64f7-6f9b-4195-353ebd73dfe2.png)
JavaScriptデザインパターン入門【ファクトリパターン】

こんにちは！今日はTypeScriptを使用してGoF（Gang of Four）のファクトリパターンを解説します。この記事では、基本的なファクトリパターンから抽象ファクトリパターンまで、具体的なコードサンプルを交えて説明します。デザインパターン初心者の方でも理解しやすいように詳しく解説しますので、ぜひ最後までお読みください。

## 目次
1. [ファクトリパターンとは](#what-is-factory-pattern)
2. [基本的なファクトリパターン](#basic-factory-pattern)
3. [抽象ファクトリパターン](#abstract-factory-pattern)
4. [まとめ](#summary)

<a id="what-is-factory-pattern"></a>
## ファクトリパターンとは
ファクトリパターンは、クラスのインスタンス生成を専門の「ファクトリ」クラスに委ねることで、オブジェクトの作成とその使用を分離するデザインパターンです。

<a id="basic-factory-pattern"></a>
## 基本的なファクトリパターン
まずは基本的なファクトリパターンから見ていきましょう。以下の例は、`Toy`と`Book`という異なる2つのタイプの製品を生成するシンプルな`ProductFactory`です。

```typescript
interface Product {
    description: string;
}

class Toy implements Product {
    description = 'A toy';
}

class Book implements Product {
    description = 'A book';
}

class ProductFactory {
    createProduct(type: string): Product {
        if (type === 'toy') {
            return new Toy();
        }
        if (type === 'book') {
            return new Book();
        }
        throw new Error('Invalid product type');
    }
}
```

<a id="abstract-factory-pattern"></a>
## 抽象ファクトリパターン
次に、より進んだファクトリパターン、具体的には「抽象ファクトリパターン」を見てみましょう。以下の例では、異なるAPIエンドポイントにリクエストを行うためのクライアントを生成するファクトリを作成します。

```typescript
interface ApiClient {
    get: (path: string) => Promise<any>;
}

class UserApiClient implements ApiClient {
    get = async (path: string) => {
        // User APIに関するリクエスト処理
        console.log(`User API request to ${path}`);
    };
}

class ProductApiClient implements ApiClient {
    get = async (path: string) => {
        // Product APIに関するリクエスト処理
        console.log(`Product API request to ${path}`);
    };
}

interface ApiClientFactory {
    createApiClient(): ApiClient;
}

class UserApiClientFactory implements ApiClientFactory {
    createApiClient(): ApiClient {
        return new UserApiClient();
    }
}

class ProductApiClientFactory implements ApiClientFactory {
    createApiClient(): ApiClient {
        return new ProductApiClient();
    }
}

// 使用例
let factory: ApiClientFactory = new UserApiClientFactory();
let apiClient = factory.createApiClient();
apiClient.get('/users');

factory = new ProductApiClientFactory();
apiClient = factory.createApiClient();
apiClient.get('/products');
```

<a id="summary"></a>
## まとめ
以上が、TypeScriptでのGoFのファクトリパターンの解説でした。このパターンは、オブジェクトの作成をカプセル化することで、システムのフレキシビリティと再利用性を高める役割を果たします。具体的なクラスのインスタンスを作成する責任をファクトリクラスが担うことで、コードの依存性が減少し、メンテナンスが容易になります。

初心者から上級者まで、これからTypeScriptでファクトリパターンを使ってみようと考えている方々が何か参考になれば幸いです。お読みいただきありがとうございました！

以上です！いいねとコメントは励みになりますので、よろしければお願いします。また質問やコメントもお気軽にどうぞ！
【Python】正規表現パターンに生文字列と通常の文字列を使う...機能に違いはあるのか？

# 概要
与えられた値が半角英数字のみか、また、空文字か`None`ではないか、を判定する関数を実装しました。その過程で、正規表現パターンに生文字列`raw string`と通常の文字列を使うと機能（pythonの解釈）に違いがあるのか、についても検証してみました。

# サンプルコード

```py
import re

# 半角英数字のみかの判定
def _is_alphanum(value: any) -> bool:
    if _is_none_or_empty(value):
        return False
    return bool(re.fullmatch('^[a-zA-Z0-9]+$', str(value)))
    # return True if re.fullmatch('^[a-zA-Z0-9]+$', str(value)) else False

# Noneまたは空文字かの判定
def _is_none_or_empty(value: any) -> bool:
    return value is None or value == ''

value01 = 'Sample'
value02 = 1234
value03 = '(^_^)/=半角英数字以外'
value04 = {'key': 'value'}
value05 = None

result01 = _is_alphanum(value01)
result02 = _is_alphanum(value02)
result03 = _is_alphanum(value03)
result04 = _is_alphanum(value04)
result05 = _is_alphanum(value05)

print(result01)  # True
print(result02)  # True
print(result03)  # False
print(result04)  # False
print(result05)  # False
```

### 補足1:関数について
- `_is_alphanum`関数: 与えられた値が半角英数字のみから構成されているかどうかを判定
- `_is_none_or_empty`関数: 与えられた値が`None`または空文字列であるかを判定

### 補足2:型ヒント
- `(value: any) -> bool`としていますが、これは、Pythonの関数定義において型ヒント（Type Hint）を示します。Python 3.5以降で導入された機能らしい。関数が受け取る引数や返り値のデータ型を明示的に指定するために使われるものであって、あってもなくても実行に影響は与えません（Pythonは動的型付けの言語のため）。
- `bool`は真偽値（`True`または`False`）のデータ型を表し、関数が常に真偽値を返すことが期待されていることがわかります。
- `any`は、「この引数にはどんな型の値でも渡せるよ〜」ということを意味しています。

### 補足3:`bool()`関数

```py
return bool(re.fullmatch('^[a-zA-Z0-9]+$', str(value)))
```

上記について。
`bool()`関数を使って、`re.fullmatch()`関数の返り値を直接ブール値に変換しています。
以下とやっていることは同じです。


```py
return True if re.fullmatch('^[a-zA-Z0-9]+$', str(value)) else False
```

この場合は、三項演算子を使って`re.fullmatch()`関数がマッチした場合は`True`を、マッチしない場合は`False`を返すというコードです。
サンプルコードで書いた（=直接ブール値に変換する）方法の方が、コードを簡潔に保てて読みやすいですね。

### 補足4:正規表現パターンの生文字列と通常の文字列(本題)

ということで本題です。
以下の二つの違いはなんでしょうか？

```py
# raw string（生文字列）
r'^[a-zA-Z0-9]+$'
```

```py
# 通常の文字列
'^[a-zA-Z0-9]+$'
```

`"\n"`を`r"\n"`と書くとバックスラッシュをエスケープ文字として解釈させないようにできます。ということは、上記の`raw string`の方の書き方をすれば、`re.fullmatch()`関数のときにバックスラッシュを機能させないようにできるのか？と思いつつ、そうではなかったです。

Pythonでは`raw string（r"..."）`を使っても通常の文字列`（"...")`を使っても、正規表現パターンは同じように機能します。これはPythonが正規表現パターンの文字列内でバックスラッシュをエスケープシーケンスとして解釈しないため。そのため、`r'^[a-zA-Z0-9]+$'`と`'^[a-zA-Z0-9]+$'`は同じ意味として扱われます。
Markdown備忘録

Markdownの記述方法をまとめる。

# 一覧
- [見出し](#見出し)
- [リンク](#リンク)
- [太字_訂正](#太字_訂正)
- [インライン](#インライン)
- [コード](#コード)
- [箇条書](#箇条書)
- [章_節](#章_節)
- [水平線](#水平線)
- [引用](#引用)
- [チェックボックス](#チェックボックス)
- [表](#表)
- [折り畳み](#折り畳み)
- [他の記事の目次へのリンク](#他の記事の目次へのリンク)


## 見出し
```
# 見出し1
## 見出し2
### 見出し3
```
[一覧へ戻る](#一覧)


## リンク
```
#URLリンク
[Qiita](https://qiita.com/)

#ファイル内参照(#の数は見出し階層にかかわらず1回でOK。)
[ファイル内参照](#一覧)
```
:::note warn
注：ファイル内参照の際、ハマりどころ。
+ 大文字の英字を含む場合、小文字にする。
+ 半角の空白がある場合は```-```にする。
+ 全角で★・→などの記号文字は省略する。

```# リンク★Link りんく``` は```(#リンクlink-りんく)``` 
:::

ハマりどころがまとめられていたサイト。

https://qiita.com/hennin/items/7ee58dd7d7c013a23be7

[一覧へ戻る](#一覧)


## 太字_訂正
**太字**　~~訂正~~
```
**太字**
~~訂正~~
```
[一覧へ戻る](#一覧)


## インライン
```
```インライン```
```
```インライン```
[一覧へ戻る](#一覧)


## コード
[```]で囲む。シンタックスハイライトの場合、言語名を記載する。

[```C:hello.c]
```C:hello.c
#include <stdio.h>
void main(void){
    printf("hello");
}
```
[```Python:hello.py]
```Python:hello.py
print('Hello, world!')
```
[```PowerShell:hello.ps1]
```PowerShell:hello.ps1
echo "Hello World!!"
```
[一覧へ戻る](#一覧)



## 箇条書
```
- aaa
- bbb
- ccc
```
- aaa
- bbb
- ccc

[一覧へ戻る](#一覧)


## 章_節
```
#自動で連番される
1. aaa
1. bbb
1. ccc
```
1. aaa
1. bbb
1. ccc

[一覧へ戻る](#一覧)


## 水平線
```
***
---
___
```
***
---
___
[一覧へ戻る](#一覧)


## 引用
```
> 引用
>> 引用2
```
> 引用
>> 引用2

[一覧へ戻る](#一覧)


## チェックボックス
```
- [x] OK
- [ ] NG
```
- [x] OK
- [ ] NG
[一覧へ戻る](#一覧)

## 表
```
|名前|概要|
|---|---|
|1|AAA|
|2|BBB|
```
|名前|概要|
|---|---|
|1|AAA|
|2|BBB|

[一覧へ戻る](#一覧)


## 折り畳み
```<details>```で囲む。題名は```<summary>```。内容は```<div>```。
```html
<details><summary>折り畳み</summary><div>
#divの中に折り畳む内容を記載。
</div></details>
```

<details><summary>折り畳み</summary><div>

あいうえお
aiueo
```C
#include <stdio.h>
void main(void){
    printf("hello");
}
```
</div></details>


[一覧へ戻る](#一覧)


# 他の記事の目次へのリンク
他の記事へのリンク
+ [ファインナンスのリンク](https://qiita.com/tapitapi/items/2f71e89dcfd0a8f6bf41#ファイナンス)
```
記事：https://qiita.com/tapitapi/items/2f71e89dcfd0a8f6bf41
目次：#ファイナンス

だった場合は下記のように記事のURLの後に、目次を続ける。
[ファイナンスのリンク](https://qiita.com/tapitapi/items/2f71e89dcfd0a8f6bf41#ファイナンス)
```

[一覧へ戻る](#一覧)
Googleアナリティクスで自分のアクセスをIPアドレスで除外するには

## はじめに
Googleアナリティクスで自分のアクセスを**IPアドレスで**除外するための方法を探していると、
2023/07/30現在、Google検索でヒットする情報が軒並み古く、大変困っていました。

どうやらGoogleアナリティクスの管理画面が変わったようです。


## やり方
https://support.google.com/analytics/answer/10104470?hl=ja

を参照してください。

動画もあり大変分かりやすいです。

困ったときは、公式を見るに限ります。

https://www.cman.jp/network/support/go_access.cgi

にアクセスすれば、自分のIPアドレスがすぐに分かって便利です。


## 自分のスマホからのアクセスをIPアドレスで除外したい

スマホの場合、携帯回線に接続していると、IPアドレスが変わることがあり、IPアドレスでアクセスの除外ができません。

しかし、使用プロバイダにもよりますが、スマホをWi-fiに接続しているとIPアドレスは固定になり、IPアドレスによるアクセスの除外が可能となります。


https://keitai-tiebukuro.com/2017/10/16/ip-address-changes/


スマホからIPアドレスを確認すると分かりますが、スマホもPCもWi-fiに接続していると、すべて同じIPアドレス（グローバルIPアドレス）になります。

Wi-fiでスマホやPCからアクセスする場合は、
1つのIPアドレスを除外するだけで、設定完了です。

## 終わりに
困っていた自分のような誰かに役に立てれば幸いです。

間違いがあれば指摘していていただけると大変うれしく思います。（すぐに修正します）
ラズパイ起動時にpythonファイルを実行（デバッグ方法つき）

# モチベ
- Raspberry Pi起動時にPythonを実行したい
- rc.localみたいな深いところは触りたくない

# 方法
- 移動
    - `cd /etc/systemd/system`
- serviceファイルを作る
    - `sudo nano やりたいこと.service`
    - 以下の通り書く
        ```
        [Unit]
        Description=実行する内容をメモ
    
        [Service]
        ExecStart=/user/bin/python3 /home/ユーザ名/Desktop/実行したいもの.py
        
        [Install]
        WantedBy=multi-user.target
        ```
- 登録&試しに今実行させてみる
    - `sudo systemctl daemon-reload`
    - `sudo systemctl start やりたいこと.service`
- ちゃんと実行できているか確認する
    - `sudo systemctl status やりたいこと.service`

# 所感
- `sudo systemctl start`だけではエラーで途中停止していたとしても気付かない．`status`でエラーメッセージを閲覧可能なので，ここを確認すること．
セミナーやもくもく会などイベントに参加するメリット

リモートワークが一般的になりましたが、「家だと集中できない」は多くの人が抱えている問題だと思います。
仕事の時は、コワーキングスペースやレンタルオフィスなど借りるのも効果的だと思います。

今回は自宅での学習についてです。
独学でプログラミングを勉強する時は、どうしても集中力や継続、分からない問題の解決策など色々と止まるタイミングがあります。

そういう時はセミナーやもくもく会のようなイベントに参加するのもありです。
（かくいう、私もプログラミングを勉強し始めた時は、セミナーやイベントに参加して学んでいました）

セミナーやもくもく会などのイベントに参加するメリットについて書いていきます。
ちなみに、イベントを探す時は、「TECH PLAY」や「connpass」、「Doorkeeper」などがオススメです。

## イベントに参加するメリット
### モチベーションの向上
他の参加者の意欲や話を聞くことで、自分のモチベもアップします。
学校生活と同じです。
テスト試験の前に誰かが勉強していると、自分も勉強してしまうもの。

### フィードバックや相談ができる
自分よりも技術力のあるプログラマーと直接会話できるので、自分が詰まっている箇所や問題が相談できます。
一歩前に進んでいるプログラマーからの的確なアドバイスが聞けるのはいいですね。

### 集中できる
誘惑がない環境は集中できます。
プラス、私の経験上、集中している時のほうが、スキルは身に付きますね。

まずコード書く。
とにかくコード書く。
そしてコードを書く。

### コミュニティへの参加
プログラマーが集まるコミュニティの場でもあります。
同じ興味を持つ人々と交流することで、新しいつながりが生まれる可能性もあります。
そこでできた繋がりから、独自のアプリ開発やサービス化が生まれることも。
PyCharmにもAIサポート機能がやってきた

## イントロダクション

AIによる開発サポート機能が流行しています。
vscodeやPyCharmに「ChatGPTプラグイン」を入れてみたりしていた方も多そうですが、ついにPyCharmの開発元JetBrains社からも「AI Assistant」という機能がリリースされました。

https://blog.jetbrains.com/idea/2023/06/ai-assistant-in-jetbrains-ides/

:::note warn
**制限**
他のサービスと同じく申請が多いと順番待ちが発生する可能性があります。
~~また、Pro以上に含まれる有償機能のため無料のCommunity版では利用できないようです。~~

Early Access Programの間だけProで無償のようです。
:::

## インストール

https://pleiades.io/help/pycharm/ai-assistant.html

まずはPyCharm本体のバージョンを最新の2023.2にアップデートします。
あとはプラグインをインストールしたら画面に従ってアカウントと紐づけします。メールが届けば利用可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/2d57b477-e218-6032-119a-5c2b69c1b05c.png)


## 使い方

### チャットでの問い合わせ

ツールウィンドウに「AI Assistant」が隠れているので表示したら使えます。
日本語で問いかければ日本語で返してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/f90842e9-94ba-3224-2730-a2cc0ad2f098.png)

### コンテキストメニュー（右クリック）からの利用


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/8cd6eb84-ac61-aa0f-6c1a-e5fb3129847e.png)

※Japanese化プラグイン入れてます

#### New chat using selection

新しいチャットタブを開いて現在選択中の内容を送信できる状態にします。

#### ドキュメントの追加

docstringを追加してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/474fde47-ad4e-9d0d-031c-ad2a20ddaa0c.png)

#### Explain ～

選択箇所のコードの読んで説明してくれます。
初見のコードを読み解く際に役立ちそうです。
英語で返ってきますが、日本語でとお願いすれば日本語にしてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/b925de9e-60f9-7553-ddcb-35418a9e9ed9.png)


#### Suggest refactoring

リファクタリングをお願いできます。
with文無し、close無しの関数を投げると以下の通りになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/4cac582a-9006-97fc-65e5-d3732f6ee116.png)


#### Find potential problems

問題点の調査をお願いできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/f63f1285-14af-9c9d-ae8c-e2c02b562c58.png)

### エラーの説明

エラーした際に「Explain with AI」という表示が出ますのでクリックすると原因について解説してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/16605646-5f55-11f7-7020-7219240805cc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/e5707cbd-d1b2-3b0a-435e-95d8dae00a31.png)


### コミットメッセージの作成

コミットする際のメッセージを生成してくれます。英語で出てくるので手動で翻訳する必要がありそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330873/67ef8744-4031-36fa-38ad-41b9410789aa.png)




## その他


### サービス プロバイダーは？

OpenAIらしいです。

https://www.jetbrains.com/legal/docs/terms/jetbrains-ai/service-providers/

### やってはいけないことは？

- JetBrains AIのリバースエンジニアリング、不正アクセス
- 第三者にJetBrains AIを利用させること

https://www.jetbrains.com/legal/docs/terms/jetbrains-ai/

### 送信される情報は？

>"Input" means any instruction, source code snippet, text, or other information sent by You or Your Users through JetBrains AI to an AI Service.

「入力」とは、お客様またはお客様のユーザーが JetBrains AI を通じて AI サービスに送信する指示、ソース コード スニペット、テキスト、またはその他の情報を意味します。
とのことで開いているプロジェクト内のデータは送られる可能性があります。

https://www.jetbrains.com/legal/docs/terms/jetbrains-ai/
【UE5】選択中のオブジェクトの取得系ノード

自分へのメモも兼ねて投稿します。
便利なんだけど、『あれどうやるんだっけ？』っといつもド忘れして調べて直していたノードについて、改めて調査し直しました。



# 検証環境

UnrealEngine 5.2.1

# GetSelectSet

![GetSectionSet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/35d6f18a-aa88-78f0-c20b-0d26695829e2.png)


GetSelectionSetは、アウトライナーの選択中のActorを取得する事が出来ます。
結果は、Actor型の配列です。


# GetSectionBound

![GetSectionBound.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/d145e8ba-e2ed-c0d4-272d-84be4c510721.png)

GetSectionBoundは、アウトライナーの選択中のActorのBoundScaleを取得する事が出来ます。
Actorを複数選択して実行した場合は、そのインスタンスを含むBoundScaleの情報を返すようです。


# GetSelectedAssets

![GetSectedAssets.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/01fb28a3-1b92-c6ad-7770-0b3d1f85f882.png)

GetSelectedAssetsは、コンテンツブラウザの選択中のアセットを取得する事ができます。
結果は、オブジェクト型の配列です。


# GetSelectedAssetsOfClass

![GetSectedAssetOfClass.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/22813205-296d-b673-0629-1141769f089a.png)

GetSelectedAssetsOfClassは、コンテンツブラウザの選択中のアセットから、クラス名でフィルタして取得する事ができます。
結果は、オブジェクト型の配列です。


# GetSelectedAssetData

![GetSectedAssetData.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/cb88dd9e-eb05-8c62-6858-09a81754ec78.png)

GetSelectedAssetDataは、コンテンツブラウザの選択中のアセットのAssetDataを取得する事ができます。
結果は、

また、AssetDataについては、UE5.0～5.2で構造体の定義が変わっていますので注意してください。
[**こちら**](https://posita.blog/article/study/2023/05/reassetdata_51_to_52/)の方が対応方法も含め詳しく紹介されています。


# GetSelectedBlueprintClasses

![GetSelectedBlueprintClasses.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/80d78128-e8c4-8776-91cf-746c46fa15c7.png)

GetSelectedBlueprintClassesは、コンテンツブラウザの選択中のアセットのクラスを取得する事が出来ます。
結果は、オブジェクト型のクラス参照の配列です。


# まとめ

GetSelectSetしか使った事が無かったのですが、選択中のオブジェクトを取得するノードが複数実装されていることが分かり、今後活用していきたいと思います。
Startメソッドの優先順位を変える方法（Unity）

# 初めに
Unityで次のような経験はないでしょうか

* AのスクリプトのStartメソッドを先に実行しないといけないのにBのスクリプトStartメソッドを先に実行してしまう
* 無理やり遅らせてAのスクリプトを後に実行させようとする

これを解決する方法が存在するので紹介します

# 方法
* Unityの画面から【Edit -> Project Settings】をクリック
* Project Settingsより【Script Execution Order】をクリック
* +ボタンから順番を変えたいスクリプトを選択
* 値が少ないほど先に実行されるようになる

写真の例だと、CharacterStatsスクリプトのStartメソッドが先に呼ばれて、HealthBarUIスクリプトのStartメソッドが後に呼ばれるようになります

 ![スクリーンショット 2023-07-30 164426.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471631/ea76c6da-4eac-4a74-a86b-3d3135114378.png)
＜設計＞posts（投稿）テーブルのマイグレーションとシーダー作成

概要
-
【PHP/Laravel】プログラミング初学者によるアプリケーション開発
https://qiita.com/AlpacaFace/items/b8e05a3da599815d8e31

上記トークアプリ開発の設計を説明します。

対象機能
-
- posts（投稿）テーブルのマイグレーションとシーダー作成



基本設計
-
- Adminerに作成するDBテーブルのうち、posts（投稿）テーブルについて、
マイグレーション実行とシーダー作成を行う。

- マイグレーションファイルを新規作成する。

- Postモデルを作成する。

- postsテーブルにはユーザの投稿内容を格納する。

- 投稿内容は文字列で140文字とする。バリデーションチェックのため、テスト用の投稿内容を160文字とする。

- 投稿内容の文字数制限はバリデーションファイルに記載する。

- postsテーブルのテスト用投稿数は、テスト用ユーザ10人が1人1投稿行うものとし、１０通りの投稿内容を用意する。





詳細設計
-
- マイグレーション実行
1. postsマイグレーションファイルの新規作成
    $ docker exec -it laravel_app bash
    #ls
    #cd laravelapp ; pwd 
    #php artisan make:migration create_posts_table --create=posts
    #exit

2. ファイル編集
    ・database/migrations/xxx_create_posts_table.php

        （中略）
 		    public function up()
 		    {
 		        Schema::create(‘posts', function (Blueprint $table) {
 		            $table->bigIncrements('id');
 		            $table->bigInteger('user_id')->unsigned()->index();
 		            $table->text(‘content’);
 		            $table->timestamps(); 		            
 		        });
 		    }

        （中略）
            public function down()
            {
                Schema::dropIfExists(‘posts');
            }

3. マイグレーション実行
    $ php artisan migrate

***
- Postモデル作成

1. Postモデル作成
    $ php artisan make:model Post

2. ファイル編集
    ・　app/Post.php

        （中略）
         		class Post extends Model
         		{
         		    use SoftDeletes;
         		    public function user()
         		    {
         		        return $this->belongsTo(User::class);
         		    }
         		}

***
- シーダー作成
1. シーダーファイル作成
    $ php artisan make:seeder PostsTableSeeder

2. ファイル編集
    ・　database/seeds/PostsTableSeeder.php

        （中略）
        public function run()
            {
                for ($i = 1; $i <= 10; $i++) {
                    DB::table('posts')->insert([
                        'user_id' => $i,
                        'content' => 'テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。テスト投稿です。',
                        'created_at' => now(),
                        'updated_at' => now()
                    ]);
                } 
            }

3. posts（投稿）をDBへ登録するシーダーコマンドを実行
    $ php artisan db:seed --class=PostsTableSeeder
【Rails】TablePlusを使ってローカルDBと接続する方法

プログラミング初学者がローカル環境のDBをTablePlus を使って視覚化出来るようにした方法をメモした記事です。
## 開発環境
Rails 7.0.4.2
Ruby 3.1.2
sqlite3

## 前提
今回はインストールをした状態からの手順となります。
インストールは[こちら](https://tableplus.com/)から出来ます。

## 手順
![スクリーンショット 2023-07-30 16.16.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1374322/bbea180f-f5e8-2ea8-6463-e44a68988468.png)
検索ボタンの左隣にある + を押します。


![スクリーンショット 2023-07-30 16.20.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1374322/33c972e8-2940-b095-d4ec-c0a704ae4f26.png)
SQLite をクリックします。


![スクリーンショット 2023-07-30 16.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1374322/5e44d367-1268-4d27-383f-c6974712482b.png)
**Name**
任意の名前を入力

**Database path**
「Select file」をクリックしてデータベースを選択。
私の場合はこんな感じです。
projectsは自分で作成したディレクトリなので、無視して頂いて大丈夫です。
```
/Users/ユーザー名/projects/アプリ名/db/development.sqlite3
```
DBの場所はdatabase.yml で確認しました。
```
development:
  <<: *default
  database: db/development.sqlite3
```

最後にConnect を押すとDBに接続が出来ます！

記事は以上になります。
読んで頂きありがとうございました！
【SpringBoot】LocalDate型のthymeleafでフォーマットして表示する

# はじめに
SpringBootでThymeleafを使用した日付の表示について、
フォーマット方法がいまいち理解できず行き詰まったのですがなんとか解決できましたので、その証跡を残します。


## 参考資料

https://www.tuyano.com/index3?id=7496003&page=4

https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#temporals-java.time


### 実際のコード

HTMLファイル（日付入力用）
```html
<p>日付を指定してください。</p>
<form th:action="@{/day}" method="get">
    <input type="date" name="date">
    <input type="submit" value="進む">
</form>
```


Controllerクラスの処理
```java
    @GetMapping("/day")
    public String day(@RequestParam("date") LocalDate date, Model model) {
        this.date = date;
        model.addAttribute("date", date);
        return "date";
    }
```


HTMLファイル（日付表示用）
```html
<h1 th:text="${#temporals.format(date, 'yyyy年MM月dd日')}"></h1>
```

ControllerクラスなどでフォーマットしなくてもHTMLファイルでフォーマットできることがわかりました。
とても便利なので多様していきたいと思います。
Next.jsでページ遷移時にスクロール位置がリセットされないバグ

## 問題
Next.jsで`<Link>`タグを使用してページ遷移する時に、スクロール位置が 0, 0 にリセットされない。
または、以下のようにスクロール位置が指定できない。
```javascript
window.scroll({
  top: 0,
});
```

## 解決した方法
CSS内に記述していた `overflow-x: hidden;` を消すことで動作した。
原因は不明だが、調べても出てこなかったのでメモ。
```css
html,
body {
    overflow-x: hidden;
}
```
Javaの正規表現について学習してみた

# 概要
Javaの正規表現について学習してみました。以下のページを参考にしました。

Java正規表現の使い方

https://www.javadrive.jp/start/regex/

パターンとマッチする

Javaでの正規表現の利用方法

https://www.javadrive.jp/start/regex/index1.html

正規表現パターンにおけるエスケープ処理

https://www.javadrive.jp/start/regex/index6.html

PatternオブジェクトとMatcherオブジェクトを作成する

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

文字列の全体がパターンとマッチするか調べる(Matcher.matches)

https://www.javadrive.jp/start/regex/index3.html

文字列の先頭からパターンとマッチするか調べる(Matcher.lookingAt)

https://www.javadrive.jp/start/regex/index7.html

文字列の中でパターンとマッチする部分があるか検索する(Matcher.find)

https://www.javadrive.jp/start/regex/index4.html

パターンとマッチした部分文字列の情報を取得する(Matcher.start,Matcher.end,Matcher.group)

https://www.javadrive.jp/start/regex/index5.html

リージョン(対象文字列の中のパターンと比較する範囲)を設定する

https://www.javadrive.jp/start/regex/index26.html

Matcherオブジェクトをリセットして位置情報をゼロへ戻す(Matcher.reset)

https://www.javadrive.jp/start/regex/index29.html

# まとめ
何かの役に立てばと。
＜エラー解決＞cv2.imshow() is disabled in Colabを解消する

# エラー内容
Google colablatoryで画面上部にpurpleと表示される紫色の画像を表示させようとしたところ、
cv2.imshow()のところでエラーが出てしまったので、解決方法を備忘録として記します。

```python
import numpy as np
import cv2

img_size = (100, 100)

img = np.array([[[150, 30, 100] for _ in range(img_size[1])] for _ in range(img_size[0])], dtype = "uint8")

cv2.imshow('purple', img)
```
最初に上のコードを実行してみました。
すると、

```
DisabledFunctionError                     Traceback (most recent call last)
<ipython-input-14-dcc119b73c38> in <cell line: 8>()
      6 img = np.array([[[150, 30, 100] for _ in range(img_size[1])] for _ in range(img_size[0])], dtype = "uint8")
      7 
----> 8 cv2.imshow('purple', img)

/usr/local/lib/python3.10/dist-packages/google/colab/_import_hooks/_cv2.py in wrapped(*args, **kwargs)
     46   def wrapped(*args, **kwargs):
     47     if not os.environ.get(env_var, False):
---> 48       raise DisabledFunctionError(message, name or func.__name__)
     49     return func(*args, **kwargs)
     50 

DisabledFunctionError: cv2.imshow() is disabled in Colab, because it causes Jupyter sessions
to crash; see https://github.com/jupyter/notebook/issues/3935.
As a substitution, consider using
  from google.colab.patches import cv2_imshow
```
**DisabledFunctionError: 
cv2.imshow() is disabled in Colab, because it causes Jupyter sessions to crash** 
というエラーが出てしまいました。
cv2.imshow()はJupyter sessionsをクラッシュさせてしまうため、Colabでは無効になっているということみたいです。

As a substitution, consider using from google.colab.patches import cv2_imshow
とあるように、
**from google.colab.patches import cv2_imshow**をインポートし、
cv2.imshow()関数の代わりにcv2_imshow()を使って再度実行してみます。

```python
import numpy as np
from google.colab.patches import cv2_imshow

img_size = (100, 100)

img = np.array([[[150, 30, 100] for _ in range(img_size[1])] for _ in range(img_size[0])], dtype = "uint8")

cv2_imshow('purple', img)
```
またエラーが出てしまいました。

```
TypeError                                 Traceback (most recent call last)
<ipython-input-15-eb51fa524664> in <cell line: 9>()
      7 img = np.array([[[150, 30, 100] for _ in range(img_size[1])] for _ in range(img_size[0])], dtype = "uint8")
      8 
----> 9 cv2_imshow('purple', img)

TypeError: cv2_imshow() takes 1 positional argument but 2 were given
```
**TypeError: cv2_imshow() takes 1 positional argument but 2 were given**
cv2_imshow()は位置引数を1つ取るが、引数が2つ与えられているというエラーですね。
imgだけをcv2_imshow()の引数として入れてみます。

```python
import numpy as np
from google.colab.patches import cv2_imshow

img_size = (100, 100)

img = np.array([[[150, 30, 100] for _ in range(img_size[1])] for _ in range(img_size[0])], dtype = "uint8")

cv2_imshow(img)
```
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517930/a47e86b4-2367-9ca1-319a-6c1e64417ec9.png)

無事に表示されました！

# まとめ
Google colablatoryで画像を表示させたいときは、
cv2.imshow()は使えないので、
代わりにcv2_imshow()を使って表示させる。
"学生エンジニアのC言語理解日記：#include <stdio.h>とは何か？"

# はじめに
最近宇宙開発系の企業に興味を持っていて、その会社に行くためにはC言語の理解が必要不可欠なのではないかと感じたので、ここ最近C言語を触っています。

`JavaScript`や`Ruby`で標準出力をする時下記のように書くことできますよね。
```hoge.js
console.log("hello world");
```
超絶簡単に出力することができます。しかしながら、C言語では以下のように書かなければなりません。
```hoge.c
#include <stdio.h>

int main() {
    printf("hello world\n");
    return 0;
}
```
なんとまぁ長いなとおもいました。その中で`#include <stdio.h>`はなんだ、という疑問が湧いたので今回はそれを調べてアウトプットしようと思います。

# 対象者
読んでいただきたい対象者は以下の方になるかと思います。
- `include <stdio.h>`がおまじないだと思っている方
- 自分と同じくC言語初心者の方
- 強強エンジニアの方（間違えていたらご指摘お願いします）

# `#include　<stdio.h>`はなんだ？
[IBMのドキュメント](https://www.ibm.com/docs/ja/zos/2.2.0?topic=hf-stdioh)をみたところ、
>stdio.hというヘッダー・ファイルは、標準入出力を処理する関数を宣言します。

と書いてあります。ここでさらに疑問が出てくるのが「ヘッダーファイルって何？」っていうことですね。ヘッダーファイルを調べていきます。

## ヘッダーファイルとは？
[GNUのドキュメント](https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html)によると、以下のように記述されています。
>ヘッダーファイルは、C宣言とマクロ定義（マクロを参照）を含むファイル

と書かれています。つまり、マクロ定義や特定の変数、関数、型を含んでいるファイルのことをヘッダーファイルというんですね。


# `#include　<stdio.h>`
さきほど記述した通り、ヘッダー・ファイルは、`マクロ定義や特定の変数、関数、型を含んでいるファイルのこと`と述べました。つまり、`#include　<stdio.h>`とは**標準入出力を処理するマクロ定義や特定の変数、関数、型を含んでいるファイルのこと**なんですね。
実際に、`stdio.h`のなかに`printf`関数のソースコードを見てみます。
```stdio.h
int _EXFUN(printf, (const char *, ...));
```
このファイルをincludeすることでこの関数を使うことができるんですね。

# まとめ
これまで`#include <stdio.h>`はおまじないだと思っていましたが、実際は、`stdio.h`を読み込んで、その中にある`printf`関数を使用していたんですね。
そして、`stdio.h`などのヘッダーファイルはマクロ定義や特定の変数、関数、型を含んでいるファイルのことを指すんですね。

# おまけ
ここまでの記事を書いている中で、includeせずにprintf関数を使ってみると、奇妙な現象に陥りました。
```hoge.c
int main() {
    printf("hello world\n");
    return 0;
}
```
上記のコードを実行すると、
```
hoge.c:2:5: error: call to undeclared library function 'printf' with type 'int (const char *, ...)'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    printf("hello world\n");
    ^
hoge.c:2:5: note: include the header <stdio.h> or explicitly provide a declaration for 'printf'
1 error generated.
hello world
```
という警告が発生するのですが、`hello world`は出力されるんですね。ヘッダーファイルをincludeしていないのになぜ出力されたのか謎です。有識者の方がいたら教えてください！