OmniAICreator/Qiita-1.07M huggingface dataset:
UnityでUPMを使いライブラリ公開する際のTips & 注意点

自分はUnityライブラリを公開する際に，Keijiroさんのリポジトリを参考にして作っていいます．パッケージを作ってGitHub Actionを作ってReleaseするだけなのですが，結構注意しないと毎回つまづくのでメモします．

https://github.com/keijiro/KinoAqua/blob/main/.github/workflows/main.yml

## 手順1: main.ymlをコピーする

ライブラリ化するリポジトリに，以下のmain.ymlをコピーして，`.github/workflows/main.yml`として保存する．ファイルの中のパッケージ名やそのパスには注意する．

https://github.com/supertask/ShaderLibCore/blob/v1.0.3/.github/workflows/main.yml

## 手順2: GitHubでNPMトークンを登録

[NPMへアクセス](https://www.npmjs.com/settings)し，トークンをコピーします．

![スクリーンショット 2022-12-18 183600.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/fc30ad57-a4d5-0750-f49a-5896e9e026c7.png)

`NPM_TOKEN`というKeyで値は上記のNPMのサイトで取得したNPMトークンとして保存します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/3634d74b-2fdd-6a2d-fb70-34db86e6983b.png)


## 手順3: タグ付け & Packages/<パッケージ名>/package.jsonを更新

https://github.com/supertask/ShaderLibCore/blob/v1.0.3/Packages/jp.supertask.shaderlibcore/package.json

のようなPackage.jsonがあったら，以下の箇所のバージョンを更新します．番号は適当で良いです．

```
"version": "1.0.3"
```

その後，そのバージョンと同じ番号をGitでタグづけします．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/11604412-dcd1-2200-9f07-af80c432fb5b.png)

こんな感じです．最後にpushします．

## 手順4: GitHubでリリースする

その後, GitHubで作成したタグ番号を指定してリリースをすると，
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/6b03b0c0-dc87-6f08-626f-2584a2fc8978.png)
GitHub Actionsで以下のようにデプロイがされるはずです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/51f4890c-f1ef-5e96-1428-f7f97f203b81.png)
ここでエラーが良く起こるのでエラー内容をよく見るようにしてください．

## 手順5: ライブラリを読み込む

このデプロイにより，パッケージマネージャに自分のNPMを指定したときに問題なく，ライブラリが読み込まれるはずです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/5cc5122e-fcfe-6b74-35f4-82528a9ccd89.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/415636fd-06c5-9549-a02c-a8b4577ab8c3.png)

もしライブラリが読み込まれない場合は，手動でPackages/manifest.jsonを操作してください．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1771055/ddc64367-6e7c-a4a4-08de-0da2c4b0e266.png)


以上！！！
(補足) LINE ボットを無償で試したい: Gitpod 以外で無償実行する方法


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/2a032a02-75d1-c44e-2587-4c67938c66a6.png)

タイトルだけ見ると、「おや？」という感じだと思います。
この記事は、Qiita Advent Calendar 2022 に投稿している [New Watson Assistant と LINE をつなぐ Part 2](https://qiita.com/yanagih/items/804bb3d26cc7146ce7a7)の補足記事になります。

(詳細な手順は省略させていただきます。ご了承ください)

# Gitpod が直ぐにサスペンドしてしまう

Gitpod を有償で使用することで回避できそうですが、有償なら IBM Cloud で Node-RED を常時起動できますし、他にも選択肢がありますね。
やはりここは無償にこだわってみます。

# ひと手間かかりますが、無償で試す方法があります

無償というのは何かと手間がかかるのかもしれません。
でも方法があるならそれを知りたいというのが人情です。

それは、『パソコン上で Node-RED を立ち上げ、ngrok 経由で LINE Platform からの Webhook リクエスト受け付ける』 という方法です。

(自宅パソコンで Node-RED 起動)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/5c1ded61-dce5-3e6d-88c7-47a8e9e2f7f6.png)

LINE Developers で Webhook 先を ```https://*****.ngrok.io/line_webhook```のように変更します。

(ngrok を使って、LINE プラットフォームからの webhook リクエストを受信します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/b66e66b6-e6aa-1e86-ce0e-32a3fe1a112a.png)

### テストしてみます

使用するアクションは、[この記事](https://qiita.com/yanagih/items/f98cff2b5b9ce3208fc4)で作成しました。

(LINE アプリの画面)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/19bbe2d8-d8f1-aeb9-ab42-f27e2df19420.png)


(自宅パソコンで動かしている Node-RED)

LINE メッセージをしっかり処理しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/a89a622c-eaf6-c69e-1d5b-6e082504e039.png)

# 参考情報

https://ngrok.com/

https://qiita.com/mininobu/items/b45dbc70faedf30f484e
AWSであれこれ試す

# AWSであれこれ試すための参考にしたこと

## URLからメモリに読み込む

https://qiita.com/Kanahiro/items/dd585599f36a77540439

https://atmarkit.itmedia.co.jp/ait/articles/1910/15/news018.html

## URLからメモリに読み込みS3に直接書き込む

いろいろ参考にした。CLI環境でリソースを読み込んで実施。
```python
    url_path = r'https://www.data.jma.go.jp/obd/stats/data/mdrr/snc_rct/alltable/snc00_rct.csv'
    response = urllib.request.urlopen(url_path)
    data = response.read()

    s3 = boto3.resource('s3')
    bucket_name = 'test-bucket'
    object_key = 'putdir/put.csv'

    s3.Bucket(bucket_name).put_object(Key=object_key, Body=data)
```

## Lambda から S3へファイルを置くのに苦労

https://repost.aws/ja/knowledge-center/access-denied-lambda-s3-bucket

https://repost.aws/ja/knowledge-center/lambda-execution-role-s3-bucket

https://zenn.dev/mn87/articles/1ae8fb56cffd50

https://dev.classmethod.jp/articles/s3-bucket-policy-multi-condition/

https://lets-hack.tech/programming/aws%E3%81%AElambda%E3%81%A8s3%E9%80%A3%E6%90%BA%E3%81%A7%E3%83%8F%E3%83%9E%E3%82%8B%E6%89%80/


### BOM追加
```
@echo off

call :GET_FILENAME %1

GOTO :END

:GET_FILENAME

echo     %~1
echo     %~p1
echo     %~n1

echo %~d1%~p1%~n1-BOM%~x1

copy /b .\utf8bom.bin+%1 %~d1%~p1%~n1-BOM%~x1

```

## GridJsでリスト表示
まずはテストから。

index.html
```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <link href="https://unpkg.com/gridjs/dist/theme/mermaid.min.css" rel="stylesheet"/>
    <script src="https://unpkg.com/gridjs/dist/gridjs.umd.js"></script>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script src="index.js"></script>
  </head>
  <body>
    <div id="wrapper"></div>
  </body>

<script>
  abc()
</script>
</html>
```

```js
function abc(){
  new gridjs.Grid({
    columns: ["Name", "Email", "Phone Number"],
    data: [
      ["John", "john@example.com", "(353) 01 222 3333"],
      ["Mark", "mark@gmail.com", "(01) 22 888 4444"],
    ]
  }).render(document.getElementById("wrapper"));
}

```
エンジニア初心者が輪読会を経験したお話

# はじめに
元々本を読むことが苦手だった私がメンバーから薦められて輪読会に参加した所感を簡単にまとめてみます

# 輪読会で使用した本

https://www.amazon.co.jp/s?k=%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%2F%E6%82%AA%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%E3%81%A7%E5%AD%A6%E3%81%B6%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80+%E4%BF%9D%E5%AE%88%E3%81%97%E3%82%84%E3%81%99%E3%81%84+%E6%88%90%E9%95%B7%E3%81%97%E7%B6%9A%E3%81%91%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9&crid=3EJMF4K4Y1UGY&sprefix=%E8%89%AF%E3%81%84%E3%82%B3%E3%83%BC%E3%83%89%2Caps%2C193&ref=nb_sb_ss_ts-doa-p_6_5

https://oukayuka.booth.pm/items/2368045

https://oukayuka.booth.pm/items/2368019

https://oukayuka.booth.pm/items/2367992

https://booth.pm/ja/items/4086937


# 輪読会概要
- 1日5分~1時間程度の時間で毎朝実施
- チームメンバー全員で一斉に読む(一人ずつ段落毎に読むパターンもあり)
- 疑問点はその場で質問、相談してOK

# 良かった点
- その場で質問してOKな場だったので気楽に取り組みことができた
- 新しいことをメンバー全員で学ぶ雰囲気が楽しかった

# 気をつけたい点
- 輪読会で学んだことをすぐ生かせるわけでもないので、備忘録としてアウトプットしておくようにする
- 余裕があれば事前に読み進めて輪読会で理解を深められるようにする

# おわりに
本を読むことは苦手でしたが、短く読み進めることで長く続けることができました。
また、質問をすぐにできる環境だったことは輪読会のメリットだと思います。
チームとして何か新しいことを学ぶ必要がある状況やメンバーの教育をしたいときには輪読会をするのも良さそうです。
CDK でプライベートサブネットの ECS on EC2 を書くときに困ったこと

# 前提
* CDK を使い始めて一ヶ月
* TypeScript で CDK を書く
* ECS を触るの初めて

# やりたいこと
* 他の人が書いた CDK のコードに ECS on EC2 のコードを追加する
* ECS on Fargate のコードは既にある

# 詰まった箇所
* サービスを作成しようとすると「[サービス名] was unable to place a task because no container instance met all of its requirements. Reason: No Container Instances were found in your cluster.」のエラーが出る
* クラスタ用に作成した EC2 インスタンスがクラスタに認識されていない…？

# 原因
EC2 インスタンスから ECS へ通信するには以下の三つの ECS 用のエンドポイントが必要だった
* com.amazonaws.region.ecs-agent
* com.amazonaws.region.ecs-telemetry
* com.amazonaws.region.ecs

# 困ったこと
* ググって出てくるコードはほぼパブリックサブネットに作られていてエンドポイントが必要なことにすぐに辿り着けなかった
* ECS on Fargate では上記の三つのエンドポイントは不要であることに気づけなかった
Security Assurance Specificationについて

This article is about the OpenChain Security Assurance Specification 1.1.

# はじめに
OpenChain Japan WGの浅羽 鉄平です。Japan WGでは初期から活動していますが、Advent Calendarの参加は初めてだったりします。さらに最近はアクティブな活動ができていなかったので、今回の記事をきっかけに何か貢献できればと思っています。

# OpenChain Security Assurance Specificationとは
OpenChainプロジェクトは、OSSのライセンス コンプライスの国際標準であるOpenChain ISO/IEC 5230:2020をメンテナンスしています。
これは、OSSのライセンス コンプライアンスを遵守する上で必要なプロセスを規定したもので2020年12月15日にリリースされました。
この延長でOSSのセキュリティのアシュアランスのプロセスを規定したOpenChain Security Assurance Specification 1.1が2022年12月14日にリリースされました。
OSSのセキュリティ向上に取り組むプロジェクトとしては、OpenChainと同じLinux Foundation傘下のOpenSSFもありますが、OpenSSFはOSSそのもののセキュリティ向上を目的にセキュリティの専門家をOSSコミュニティへ派遣したり、ツールをOSSコミュニティに提供するなど仕組み作りに取り組むプロジェクト、OpenChain Security Assurance SpecificationはOSSを利用する上で意識すべきポイントを体系化したものというのが私の理解です。

# OpenChain Security Assurance Specificationの概要
OpenChain Security Assurance Specificationは、GitHubで公開されています。

https://github.com/OpenChain-Project/Security-Assurance-Specification/blob/main/Security-Assurance-Specification/1.1/en/openchain-security-specification-1.1.md

OpenChain Security Assurance Specification (以下、本仕様)は、3章から構成されています。
1章は、Scope、本仕様の範囲について
2章は、Terms, Definitions and Examples、本仕様の用語の定義について
3章は、Requirements、本仕様の本体で、要件が項目毎に記されていて、ここだけ節・項と細分化されています。
3章の節・項をそれぞれざっくり読んでいきましょう。

## 3.1 - Program Foundation
3.1節には下記の項目があります。
- Policy
- Competence
- Awareness
- Program Scope
- Standard Practice Implementation

OpenChain ISO/IEC 5230:2020を理解されている人ならお馴染みの「プログラムの基盤」について、OSSのセキュリティ保証のポリシーや組織内での役割・責任、メンバーが理解しているかの確認などの文書化する内容について規定しています。

## 3.2 - Relevant Tasks Defined And Supported
3.2節には下記の項目があります。
- Access
- Effectively Resourced

ここもOpenChain ISO/IEC 5230:2020と同様に「関連業務の定義と支援」について、外部からの問い合わせ窓口が定義されているか、十分なリソースが割り当てられているかなどの内容について規定されています。

## 3.3 - Open Source Software Content Review And Approval
3.3節には下記の項目があります。
- Software Bill of Materials (SBOM)
- Security Assurance

この節では、「OSSコンテンツのレビューと承認」について規定され、注目のSBOMがここで登場します。
SBOMの作成と継続的なメンテナンスを行うためのプロセスについて、脆弱性の検出から影響の特定、影響に応じたアクションなどの内容について規定されています。

## 3.4 - Adherence To The Guideline Requirements
3.4節には下記の項目があります。
- Completeness
- Duration

ここもOpenChain ISO/IEC 5230:2020と同様に「仕様要件への遵守」について、要件を満たしていることを確認する文書や規定期間毎に確認できているかを規定しています。
規定されている期間は、OpenChain ISO/IEC 5230:2020とは異なり、2回目の確認は18ヶ月、3回目は2回目から24か月、その後は36ヶ月毎です。

# OpenChain Security Assurance Specificationのチェックリスト
OpenChain Security Assurance Specificationの自己認証のチェックリストも併せてリリースされています。

https://github.com/OpenChain-Project/Reference-Material/blob/master/Self-Certification/Checklist/Security-Assurance-1.1/en/Security-Assurance-1-1-Checklist-Version-2.md

これは、本仕様の3章の項の下3.x.y.**z**の**z**に記載されたVerification Material(s)、要はエビデンスをリスト化したもので、仕様の概要をざっくり把握するには、このチェックリストを眺めた方が早いかもしれません。

# さいごに
OpenChain Security Assurance Specificationのリリースは下記です。

https://www.openchainproject.org/news/2022/12/14/security-assurance-global-support

クォートしているのは、中国、台湾、ドイツ、英国と米国のパートナーです。
また、2022年12月14日時点でリリースされているのは、英語版、ドイツ語版と中国語 (簡体)版です。

日本のサプライチェーンに浸透させるには日本語版も欲しいですね。
OpenChain, SPDX, OpenSSFやOSPOがスパイラルに絡み、やりたいことがたくさんあり過ぎる昨今ですが、私の貢献ネタが見つかった気がするので、本記事はこれで締めたいと思います。

Merry Christmas and Happy New Year!
Alibaba Cloud Event Bridgeを使ってイベントドリブンアーキテクトを構成しよう

# Event Bridgeとは
他のAlibaba Cloudのサービスやカスタムアプリケーション、SaaSからアクセスできるサーバーレスな**イベントバス**サービスです。
[Alibaba Cloud Event Bridge](https://www.alibabacloud.com/help/en/eventbridge)

# CloudEvents1.0
CloudEventsはCNCF(Clpud Native Computing Foundation)がイベントデータ(通知)の記述仕様を共通化させたものです。
Alibaba Cloud Event BridgeはCloudEvent1.0の仕様に基づいて、アプリケーション間のイベントをルーティングしています。
CloudEventsの詳細については、[公式サイト](https://cloudevents.io/)や[GitHub](https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md)を参照してください。

# Event SourceとEvent Target
Event BridgeにはEvent SourceとEvent Targetからアクセスできます。
また、Event Bridgeはスキーマグループによってイベントのスケジュールと処理ができます。

## Event Source
Event Sourceはイベントを生成するもので、Event Bridgeでは下記のEvent Sourceがサポートされています。
サポート対称のカテゴリとして、大きく2つあります。
Alibaba Cloudサービスのイベントソースとカスタムイベントソースです。

**Alibaba Cloudサービスのイベントソース**
下記のAlibaba Cloudサービスは、イベントソースとしてEvent Bridgeに接続できます。
* Elastic Computing
* Storage
* Database
* Container
* ミドルウェアサービス

**カスタムイベントソース**
以下の方法によりカスタムイベントソースとしてEvent Bridgeに接続することができます。
* SDKを利用したカスタムアプリケーション
* イベントプロバイダーを指定したメッセージデータ

## Event Target
イベントターゲットは、イベントの処理および消費を行います。
Event BridgeでサポートされているEvent Targetは下記のものです。
* Function Compute
* Message Queue for Apache RocketMQ
* Message Queue for RabbitMQ
* Message Service(MNS)
* HTTP gateway
* HTTPS gateway
* Short Message Service(SMS)
* Direct Mail
* ApsaraDB RDS for MySQL
* Self-managed MySQL database
* EventBridge
* Log Service

## リソース管理
Event Bridgeを使用する際のリソースの管理方法は3つあります。
* カスタムイベントソースの管理
* カスタムイベントバスの管理
* イベントルールの管理

## イベント処理
Event Bridgeを使用した、イベント処理を行います。
* イベント配信
* イベントフィルター
* ルートイベント
* イベントの再試行
* イベントの公開
* クエリイベント

# スケーリング
Event Bridgeには、イベント送信容量の自動スケーリング機能がサポートされています。

# セキュリティ
Event Bridgeを利用することで、アクセス許可やリクエスト送信を制限できます。
* Alibaba Cloudアカウントを使用して、RAMユーザーにアクセス許可を付与
    * 異なるRAMユーザーに異なるアクセス許可を付与することも可能
* Alibaba Cloudアカウント全体にアクセス許可の付与
* HTTPまたはHTTPS経由でリクエスト送信

# 可用性
Event Bridgeにはサービスの可用性が考慮された仕組みがあります。
* 高スループットでのイベント発行
* 自動スケーリングをサポートしてバーストトラフィックを処理
* ステートレスインスタンスのサポート
* ネットワーク待機時間短縮のための複数リージョンへのデプロイ
* 同一リージョン内の2つのデータセンターへのデプロイ

# 料金
パブリックプレビュー期間中は無料です。

# SDK
SDKはAliyun SDKとCloud Events SDKが用意されています。
[Cloud Events SDK](https://www.alibabacloud.com/help/en/eventbridge/latest/cloudevents-sdk-reference)はJavaのみの対応となっています。

## Aliyun SDK
Event Bridge用のSDKは7言語に対応しています。
* Java
    * JDK 1.7以降が必要
* Go
    * バージョン1.12以降が必要
* Python
    * バージョン3.4以降が必要
* PHP
    * 未記載(おそらく5.5以上)
* C#
    * .NET Standard 2.0/.NET Framewor 4.5
* TypeScript
    * 未記載
* C++
    * 未記載

# API
SDKだけでなくAPIも用意されています。
イベントリソースやイベントバスの管理など必要な機能に対応したAPIがあります。
[API機能一覧](https://www.alibabacloud.com/help/en/eventbridge/latest/list-of-operations-by-function)

# Event Bridgeの利用手順
事前準備は別として、どのパターンの利用シーンでも大体下記の様な流れになります。
1. カスタムイベントバスの作成
2. カスタムイベントソースの作成
3. イベントルールの作成
4. イベントの公開(Publish)
利用シーンによっては、RAMロールの作成やポリシーの変更などが手順として含まれます。
チュートリアルとして、7パターン手順がドキュメントとして用意されているのでやりたい事と似ているパターンを探して試してみてください。
[チュートリアル](https://www.alibabacloud.com/help/en/eventbridge/latest/tutorial)

# まとめ
上記の内容ですと、イメージが掴みにくいかもしれません。
その場合は利用イメージを作るために、こちらの[ベストプラクティス](https://www.alibabacloud.com/help/en/eventbridge/latest/best-practices)をまずは参考にしてみてください。
また、CloudEventsに基づいているのでマルチクラウド構成の対応なども今後利用シーンとして増えてくるかと思います。
FlutterでKeychain Sharingを実現する方法

# Keychain Sharingとは

- [公式ドキュメント](https://developer.apple.com/documentation/security/keychain_services/keychain_items/sharing_access_to_keychain_items_among_a_collection_of_apps)

Keychain Sharingを使用することで、異なるアプリ間で情報を共有することができます。
例えばですが、異なるアプリ間で共通のユーザー名やパスワードを使用したい場合において、アプリAでログインする際にユーザー名やパスワードをKeychainの共有領域に保存させ、アプリBにログインする際にはKeychainに保存されている情報を使用して、ユーザー名やパスワードの入力なしにログインさせる
といったことができるようになります。

注意事項として、チームIDが同じプロビジョニングプロファイルでビルドされたアプリでしか上記は実現できません。
当たり前と言えば当たり前ですが、、、

チームIDはプロビジョニングプロファイルから確認できます。
大体は以下の赤い箇所に記載されていると思います。
![スクリーンショット 2022-12-18 17.53.05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454780/571491e4-2313-e6d4-a4f7-8fd67592415b.jpeg)






# FlutterでKeychain Sharingを実現するには
今回はKeychainに認証情報を保存するために、[flutter_secure_storage](https://github.com/mogol/flutter_secure_storage/tree/develop/flutter_secure_storage)を使用しました。

具体的なソースコードは以下になります。

```dart
  FlutterSecureStorage secureStorage = const FlutterSecureStorage(
    iOptions: IOSOptions(
      groupId: "TeamID.jp.co.hoge.group",
      accountName: "jp.co.hoge.service",
    ),
  );
```

- ```TeamID```にはプロビジョニングプロファイルに記載された、チームIDを記載してください。
- ```jp.co.hoge.group```というのは、xcode上で設定したKeychain Groupsです。
![スクリーンショット 2022-12-18 18.34.57.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454780/7f4fd0b1-cf4b-cd4b-5d76-0cf9bf47b6a6.jpeg)

    - 異なるアプリ間でKeyChain Groupsに同じ値を設定することで、以下のようにKeychain上に共有領域を確保することができます。
![スクリーンショット 2022-12-18 18.26.11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454780/58c08370-5ad6-7c0e-123e-e7e932c3d064.jpeg)

- accountName（iOSで言うところのService Name）が必要な場合は設定してください。アプリ間でaccountNameに異なる値を設定している場合、KeyChainの共有領域から値を読み出すことができません。

あとは、お好きなように```secureStorage.write(key: key, value: value);```なり、```secureStorage.read(key: key);```すれば、KeyChainの共有領域に対して読み書きができるようになります。
Windows + PostgreSQL構成のプリザンターのバックアップ取得

## はじめに
以前、プリザンター(Windows + PostgreSQL構成)のDBのバックアップを取得する簡易的なプログラムを作成したので、備忘録として残しておきたいと思います。

## Pythonダウンロード・インストール
### ダウンロード
下記ページよりダウンロードします。

https://www.python.org/downloads/windows/
### インストール
ダウンロードしたインストーラを起動し、Pythonをインストールします。
参考：https://www.javadrive.jp/python/install/index1.html#section2

## PostgreSQLダウンロード・インストール
### ダウンロード
下記ページよりダウンロードします。

https://www.enterprisedb.com/downloads/postgres-postgresql-downloads
### インストール
ダウンロードしたインストーラを起動し、PostgreSQLをインストールします。
参考：https://www.javadrive.jp/postgresql/install/index1.html#section2

### パス追加
環境変数「Path」に「C:\Program Files\PostgreSQL\14\bin」を追加します。
参考：https://www.javadrive.jp/postgresql/install/index3.html#section1

### パスワード省略設定
システム環境変数に変数「PGPASSWORD」を追加します。値はインストール時に設定したpostgresのパスワード。

## Pleasanterダウンロード・インストール
### ダウンロード
下記ページよりダウンロードします。

https://pleasanter.org/dlcenter

### インストール
[ユーザマニュアル](https://pleasanter.org/manual?category=0090_0105)を参考にインストールします。

## プログラム
下記プログラムをタスクスケジューラに登録して定期実行する。
参考：https://laboratory.kazuuu.net/using-task-scheduler-to-automate-python-scripts-windows-10/

```python
from datetime import datetime
import subprocess

#Variables
user = "postgres"
database = "Implem.Pleasanter"
dest_dir = "C:\\backup\\"
dump_file = f"{dest_dir}{database}_{datetime.now().strftime('%Y%m%d%H%M%S')}.dump"
command = f"pg_dump -U {user} -Fc -f {dump_file} {database}"

#Take a backup of the database (Implem.Pleasanter)
try:
    subprocess.check_call(command)
except:
    print("Error.")
```

## さいごに
普段はPythonを使用する機会がないので、いい経験になりました！また、プライベートで色々試してみようかなと思います！
ホスト系からのリスキリング

# はじめに
私は金融業界のSIerで、過去約10年間COBOL言語（汎用COBOL、オープンCOBOL（UNIX）を各約5年間）を用いたプロジェクトに参画、オープン系システム主流の言語を用いたプロジェクトに参画し始めたのは2020年4月からだった。
現在はOpenShift、Angular、SpringやCICD等を利用しているプロジェクトに参画している。


この記事は今と違うことをしたいけど、なかなか一歩を踏み出せない人に読んでほしい。

# 外部環境の変化
VUCAの時代と呼ばれ、先行きが不透明で、将来の予測が困難な時代になってきた昨今、金融業界もついにアジャイルや先端技術を採用した開発が増えてきた。

# リスキリングについて
SIerに限った話かもしれないが、複数の技術を完璧に習得する必要はないと思っている。
個人差はあるものの、ある程度システム開発した経験があれば、他の技術は「つまみ食い」をして、あまり時間をかけず特徴やメリットデメリットを押さえる程度学習しておくだけでも顧客と話ができるし、プロジェクト参画後にスムーズに立ち上って、他者をリードできる。
「つまみ食い」は言語であれば、Git公開されてるサンプルアプリを自分の環境に持ってきて動かしてみたり、Udemy等の教材の初級編を学習するだけでもいい。

そんなんじゃ身につかない！現場では通用しない！と思う人もいるかもしれないが、ホスト系からリスキリングする人や技術が得意じゃない人はまず一歩を踏み出すために、「つまみ食い」してみるかーくらいの感覚で始めるのがいいと思う。
一歩踏み出せずに何もしないよりもずっといいし、「つまみ食い」してるうちに理解が早くなって自信も着くかもしれない。
経験上では、細かいところはプロジェクト参画後に都度調べながらやれば大体なんとかなった。

# OODAループについて
何事もはじめは計画通りには通りにはいかない事が多い。
そんな時は、変化に対応するための考え方OODAループ（ウーダループ）も併せて意識するといいと思う。
OODAループとは下記の頭文字をとったものだ。このループを素早く回し改善していく。

- Observe：観察
- Orient：状況把握
- Decide：意思決定
- Action：行動

# さいごに
金融業界でアジャイルや先端技術を採用した開発はまだ結構難しいと思っている。顧客含め未経験のことが多いからだ。そんな時こそ、リスキリングのマインドで必要な能力をその都度身に付け、課題を解決することを当たり前にしていきたい。私はオープン系プロジェクト経験はまだ少ないが、現在のプロジェクトでは活躍できていて結構自信がついた。
同じように一歩を踏み出す人が増えますように、、！

# 参考
https://www.keyence.co.jp/ss/general/manufacture-tips/ooda-loop.jsp
【Rspec】レシーバーの「FactoryBot」の記述を省略する設定

## FactoryBotの記述を省略し、よりコードをすっきりさせる
インスタンスを作成する記述のたびにFactoryBotを書く手間を減らし、よりコードをすっきりさせていきます。
```ruby
user = FactoryBot.build(:user, fullname: "")
```
# spec/rails_helper.rbに省略する記述を追加
```ruby:spec/rails_helper.rb
RSpec.configure do |config|
:
  #下記の記述を追加
  config.include FactoryBot::Syntax::Methods
:
end
```

# 設定後
書く手間が減り、よりコードをすっきりさせることができました。
```ruby
user = FactoryBot.build(:user, fullname: "")
↓
user = build(:user, fullname: "")
```
Windowsの画面ロックをC#で検知する

C#で画面ロックと画面ロック解除を検知します。

## 手法

以下の選択肢があるようです。

- WTSRegisterSessionNotification
- SystemEvents.SessionSwitch

### WTSRegisterSessionNotification

`WtsApi32.dll`とやらが必要とのこと。見慣れない子ですね…………。
こちらの記事で解説されています。

https://qiita.com/Yusuke_Pipipi/items/5c561b81e861e286e0c5

[MSの公式ドキュメント](https://learn.microsoft.com/ja-jp/windows/win32/api/wtsapi32/nf-wtsapi32-wtsregistersessionnotification "WTSRegisterSessionNotification 関数 (wtsapi32.h)")には

>セッション変更通知を受信するように指定された**ウィンドウを登録**します。

とあるので、WinFormsなりWPFなり何かしらのウィンドウが必須っぽいですね。
しっかりと調べてはいませんが、本当にウィンドウ必須なら**画面が要らないケースでも画面の実装を強制されてしまう**ということになります。個人的には、出来れば選択肢から除外したいです。
また、ググって出て来るサンプルがWinFormsばかりなあたりもなんだか古そうで忌避感が加速します。


### SystemEvents.SessionSwitch

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.win32.systemevents.sessionswitch?view=dotnet-plat-ext-7.0

こちらは画面不要です。Microsoft.Win32名前空間にいるイベントを使います。
下記コードで検証し、いい感じに動いてくれました。

```C#:Program.cs
using Microsoft.Win32;
using System;

namespace ScreenLockObserver {
    internal class Program {
        static void Main(string[] args) {

            SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;

            for (; ; );
        }

        private static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {

            switch (e.Reason) {
                case SessionSwitchReason.SessionLock:
                    Console.WriteLine(DateTime.Now + "：画面ロック");
                    break;

                case SessionSwitchReason.SessionUnlock:
                    Console.WriteLine(DateTime.Now + "：画面ロック解除");
                    break;
            }
        }
    }
}


```

Windows 11、.NET Framework 4.7.2での実行結果です。

![2022-12-18_17h06_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164419/045ea30f-fbda-5ba1-095f-0fb6e99b5040.png)

先日リリースされたばかりの.NET 7でも同様に動きます。
```C#:Program.cs (.NET 7.0)
using Microsoft.Win32;

SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
for (; ; );

static void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {

    switch (e.Reason) {
        case SessionSwitchReason.SessionLock:
            Console.WriteLine(DateTime.Now + "：画面ロック");
            break;

        case SessionSwitchReason.SessionUnlock:
            Console.WriteLine(DateTime.Now + "：画面ロック解除");
            break;
    }
}

```

(最近のC#はMain関数を省略できるのでプロジェクトテンプレートが勝手にMain()を省略しやがるんですが、なかなか慣れないですね……)

## おわり
何かしら事情があったり既にWinFormsの画面があったりする場合を除き、`SystemEvents.SessionSwitch`がいいかな～と思います。
余談になりますが、`SystemEvents.SessionSwitch`は画面ロックだけでなくログオンやログオフ、リモート接続なんかもキャッチできるみたいです。

https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.win32.sessionswitchreason?view=dotnet-plat-ext-7.0
【Playdate】9スライスウィンドウを表示する

前回のプロジェクトを更に改造します。
入力したテキストの背景に9スライスに対応したウィンドウを表示してみます。

```main.lua
import "CoreLibs/object"
import "CoreLibs/graphics"
import "CoreLibs/sprites"
import "CoreLibs/timer"

import "CoreLibs/keyboard"
import "CoreLibs/qrcode"
import "CoreLibs/nineslice"

local gfx <const> = playdate.graphics

local inputText = "Edit PressA"
local qrImage = nil
local qrSprite = nil
local window = nil

function QRDone(image, errorMessage)
	qrImage = image
end

function myGameSetUp()
	playdate.keyboard.textChangedCallback = function()
		inputText = playdate.keyboard.text
		gfx.sprite.redrawBackground()
	end
	
	playdate.keyboard.keyboardDidHideCallback = function()
		print(playdate.keyboard.text)
		gfx.generateQRCode(inputText, nil, QRDone)
	end
	
	qrSprite = gfx.sprite.new( qrImage )
	qrSprite:moveTo( 70, 120 )
	qrSprite:add()
	
	-- 9slice
	window = gfx.nineSlice.new("Images/window_9slice", 8, 8, 48, 48)
	
	gfx.sprite.setBackgroundDrawingCallback(
		function( x, y, width, height )
			gfx.drawText('_'..inputText..'_', 20, 20)
			local width, height = gfx.getTextSize('_'..inputText..'_')
			window:drawInRect(20 - 8, 20 - 8, width + 16, height + 16)
		end
	)
end

myGameSetUp()

function playdate.update()
	
	if playdate.buttonIsPressed(playdate.kButtonA) then
		playdate.keyboard.show(inputText)
	end
	
	qrSprite:setImage(qrImage)
	gfx.sprite.update()
	playdate.timer.updateTimers()
end
```

9スライスの表示には`import "CoreLibs/nineslice"`でAPIを読み込む必要があります。
更に今回`window_9slice`という9スライス用のウィンドウ画像を制作しました。

![window_9slice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/c038b0bf-5d66-8f9b-bf9f-8fbc851122d7.png)
`window_9slice.png`
それぞれ四隅のサイズは8x8の領域となります。

これを`window`というnineSliceオブジェクトとして以下のように新規作成します。
`window = gfx.nineSlice.new("Images/window_9slice", 8, 8, 48, 48)`

テキストの描画サイズは`gfx.getTextSize(str)`で取得するしています。widthとheightをそれぞれ返します。
最後にウィンドウの描画です。
`window:drawInRect(20 - 8, 20 - 8, width + 16, height + 16)`とウィンドウの四隅のサイズを考慮して記述しています。

これで編集して以下のような形で動的にウィンドウのサイズが変わっても四隅のグラフィックが崩れることなく可変できるようになりました。

**変更前**
<img width="408" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/6f098355-ada4-4fc8-f3d7-8e8bf70a21ee.png">

**変更後** テキストに応じてウィンドウも可変している
<img width="409" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100912/6e488d88-b6a2-e6e3-66d1-f6df5ed0d973.png">
AWSで独自ドメインメールを送受信

## はじめに
- 独自ドメインのメールアドレスが欲しかった。
- 独自ドメインはRoute 53で取得済みです。
- メーラー（Outlook）で送信、即時受信がゴールです。

## ホストゾーンを作成する
- WorkMailの設定に使用するホストゾーンを作成します。
- すでに作成済の方は飛ばしてOKかと思います。
- 僕の場合ドメインとホストゾーンに割り当てられたネームサーバが違ったのでご注意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/cbab5da8-7305-2107-fc0d-a69170491edd.png)
```
ドメイン名：example.com など
タイプ：パブリックホストゾーンを選択
```

## WorkMailの設定
- Amazon WorkMailの組織を作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/aa414a0a-6b8d-a8b9-b2fd-fb2d40f62ec4.png)
```
Email domain：Existing Route 53 domainを選択（既存のRoute53のドメイン）
Route 53 hosted zone：先ほど作成したホストゾーンを選択
Alias：任意の名前を入力
```

ホストゾーンの設定はほぼ自動でやってくれるみたいです。
僕の場合「Improved security（セキュリティの向上）」のTXTレコードが「Missing」になっていたので手動で設定しました。
「Improved email delivery（メール配信の改善）」は必須ではなく推奨みたいなのでそのままにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/9dec4a83-d8c9-593b-d9b3-cf7691499b43.png)

## ユーザー作成
- WorkMailのユーザーを作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/848b308a-dc8f-a83c-e009-1c01602c61a2.png)
```
User name：ユーザー名
Display name：表示名
Email address：メールアドレス
Password：パスワード
```

## 送受信の確認
- WorkMailのWebアプリから送受信ができる事を確認します
- https://(Alias).awsapps.com/mail

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/b48e0434-0ef7-e590-9b41-4a8c790454fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/96bfd25b-68e7-69e6-62ac-c78f5856f1cc.png)
```
ユーザー名：ユーザー名（@～以降は不要）
パスワード：パスワード
```

## メーラーの設定
- WorlMailのWebアプリでは使い勝手が悪いのでメーラーを設定します。（今回はOutlookモバイル）
- IMAPで設定するとどうやら即時受信ができない？ようなのでExchangeで設定する必要があります。
- その他の設定は[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/workmail/latest/userguide/clients.html "Amazon の E メールクライアントの設定 WorkMail")をご確認いただくのが良いかなと思います。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/582665/dccc4fb3-1680-f4f3-bca8-27fe503b8a5c.png">

```
メールアドレス：メールアドレス
パスワード：WorkMailのパスワード
サーバー：下記のいずれか
	米国西部 (オレゴン)：mobile.mail.us-west-2.awsapps.com
	米国東部 (バージニア北部)：mobile.mail.us-east-1.awsapps.com
	欧州 (アイルランド)：mobile.mail.eu-west-1.awsapps.com
ドメイン：空
ユーザー名：WorkMailのアカウント
```

## おわり
何のトラブルも無く設定できた方はいいねをいただけると励みになります。
[Unity]Visual Effect Graphをとりあえず触ってみたい人用の記事

# 概要
Visual Effect Graphってどんな感じに作るのか体感したい人用の記事です
# 本文
まず、URPテンプレートで新規プロジェクトを作ります。そのままではVisualEffectGraphは使えませんのでPackageManagerからインポートします
![スクリーンショット 2022-12-18 17.57.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/da0e0d9f-394a-7d4a-fa07-47facaefa001.png)

ProjectからCreate > Visual Effects > Visual Effect Graphを選びます。
![スクリーンショット 2022-12-18 18.04.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/ba583653-df47-8fb0-490d-bff57e0957b1.png)
作成されたVFXファイルはHierarchy上にドラッグ&ドロップで設置しておきます
![スクリーンショット 2022-12-18 18.06.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/5e0d3954-6d59-6002-b263-8f6a643de764.png)
VFXファイルをダブルクリックすると編集画面が開きます。Output Particle QuadのMain Textureに画像を設定すると
![スクリーンショット 2022-12-18 18.08.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/a8aea270-67b7-5fe5-d501-59ccba1dff37.png)
画像が湧き上がるエフェクトが出来上がりました。
![スクリーンショット 2022-12-18 18.08.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/585c9b3a-136a-6c5f-0b60-83642ad93e94.png)
Googleで効率よく検索するためのテクニック

# はじめに
「ググる力」（情報収集能力）はエンジニアにとっては必須な能力と言っても過言ではないでしょう。ということで今回はGoogleで効率よく検索するためのテクニックを紹介していこうと思います。
関連記事はネット上にすでに多く存在していますので、今回は私が普段よく使う検索テクニックを中心にまとめてみました。
また、エンジニアに限らず色んな方の役に立てると思いますので、ぜひ参考にしていただければと思います。

# 完全一致
キーワードを「""」（ダブルクォーテーション）で囲みます。

```
"キーワード"
```
例えば、下記のように、Linuxコマンドのあるオプションを検索したい場合は、コマンドとオプションで検索しても、コマンド全体の解説が上位検索結果に表示される場合が多いと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/ebafc1fd-3e4b-535a-ff3c-7c5219ba60a2.png)

こういう時は完全一致で検索した方がいいのではないかと思います。
例：ダブルクォーテーションで囲んで完全一致で検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/7ba83588-cc2a-d912-bcec-359986181521.png)



# キーワードの除外
「-」で除外したいキーワードを指定します。

```
検索キーワード -除外キーワード
```
例：「python for文」で検索した結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/0a50ac68-759d-599f-2e6f-c21e0af2f674.png)
例：udemy関連の記事を除外した検索結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/37861b2e-d650-c97b-eaa7-ab60e6e1e2ea.png)

# AND検索とOR検索
全てのキーワードを含む検索結果を表示したい場合（AND検索）は、キーワードの間にスペースを入れます。普段よく使う検索方法の１つだと思います。
```
キーワード1 キーワード2 
```

合わせてOR検索も覚えておいた方がいいでしょう。いずれかのキーワードを含む検索結果を表示すしたい場合は「OR」を使います。
```
キーワード1 OR キーワード2 
```



# サイトの指定
特定のサイト内で検索したい場合は「site:」を使います。

```
site:サイト キーワード
```

例：Qiitaに投稿されたpython関連の記事を検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/0c6ec652-1349-6abd-1ce7-c553f524c91d.png)



# Webページのタイトルの指定
「intitle:」（部分一致）と「allintitle:」（完全一致）を使います。

```
intitle:キーワード
allintitle:キーワード
```

例：「python入門」と「初心者」のいずれかのキーワードを含む検索結果を表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/09f51ee7-9999-6a4a-a985-771f67d8f1cb.png)

例：「python入門」と「初心者」のすべてのキーワードを含む検索結果を表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/f26ba102-359e-9246-a10c-f5dc5c3c8a2f.png)

他にも本文に含まれるキーワードを指定する「intext:」などがありますので、合わせて覚えておくといいでしょう。

# 日付の指定
「before:」（指定した日付より前の検索結果）と「after:」（指定した日付以降の検索結果）を使います。年月日の区切りは「-」でも「/」でもどちらも使えます。

```
before:yyyy-mm-dd
after:yyyy/mm/dd
```

例：2022/12/01以降投稿されたpythonの記事をqiita内で検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/04bd991e-f368-a851-6b2b-c1895a010f82.png)

特に技術記事は情報の鮮度も重要なので、検索時に日付指定を活用するといいでしょう。

# ファイル形式の指定
「filetype:」を使います。

```
filetype:ファイル形式 キーワード
```

例：aws関連のpdfファイルを検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2954734/717dd956-193e-a304-901f-fddf467a8da5.png)

# その他の検索方法
類似性の高いWebサイトを検索する「related:」、リンクされているページを検索する「link:」、SNS内で検索する「@」など、他にも検索方法がたくさんあると思いますので、気になりましたら、ググってみてください！
RSpecでtravel_toを使ってみた

## はじめに
ポートフォリオの作成で初めてtravel_toを使ったので記事にしました。

## タイムゾーンを変更する
時間の変化を分かりやすくするため、タイムゾーンを日本に設定します。
```ruby: config/application.rb
class Application < Rails::Application
  config.time_zone = 'Tokyo'
end
```

## travel_to
putsで時間を表示させると、タイムスタンプが変わっていることが分かります。

```ruby: spec/system/posts_spec.rb
  describe 'travel_toを使ってみた' do
    it '24時間前、現在、24時間後' do
      travel_to Time.zone.now.yesterday do
        puts Time.zone.now
      end
      puts Time.zone.now
      travel_to Time.zone.now.tomorrow do
        puts Time.zone.now
      end
    end
  end
```

```bash: 結果
Posts
  travel_toを使ってみた
2022-12-17 18:02:46 +0900
2022-12-18 18:02:46 +0900
2022-12-19 18:02:46 +0900
    24時間前、現在、24時間後

Finished in 0.04604 seconds (files took 3.92 seconds to load)
1 example, 0 failures
```
<br>

参考
https://qiita.com/mightysosuke/items/72f764fc237422b423b0
【C#】delegate、非同期処理を完全に理解する【メモ書き】

# delegateとは
関数の呼び出し先を格納する変数。
他クラスから他クラスにメソッドを渡すことができる。
delegateは主にC#の非同期処理やコールバックとして使われる。

# なぜdelegateを使うのか
クラス同士のやり取りは通常一方方向。
例えばメインクラスでサブクラスのインスタンスを生成し、メインクラスでサブクラスのインスタンスを使うことができる。
しかしサブクラスでメインクラスのメソッドを使おうとしても、サブクラスはメインクラスの存在を知らないため使えない。
そこでサブクラスでメインクラスのメソッドを使うときにdelegateを使う。

# 基本的な使い方
基本的には以下の手順で実装可能。
①サブクラスでdelegate定義、delegate変数を定義
②メインクラスでサブクラスのインスタンスをnewする
③delegate変数にメインクラスのメソッドを代入
④サブクラスでdelegate変数を実行

## インスタンス化が難しいとき
メインクラスでサブクラスのインスタンスを生成するときに、引数の問題でインスタンスが生成できない時がある。
その時の解決方法として以下がある。
・引数を新たに作成する
・サブクラスのコンストラクタの引数に新たにdelegate型の引数を追加

引数を新たに作成する方法は、その引数の役割を考えて作成しなければいけないため注意が必要。

delegate型の引数を追加するということは、呼び元（メインクラス）のメソッドを引数で持っていき、コンストラクタ内でdelegate変数にメソッドを代入する方法。
この方法は他でインスタンスを生成している場合は注意が必要。

# UIスレッドに処理を投げる
テキストボックスやラベルなどのコントロールは、UIスレッドでしか操作することができない。
別スレッドでコントロールを操作したいときは、その処理だけUIスレッドに投げることで操作が可能。
それぞれのアプリケーションでUIスレッドへ処理を渡す仕組みは異なるため、使用するクラスは異なる。
WindowsフォームアプリではSystem.Windows.Forms.ControlのInvoke()、WPFではSystem.Windows.Threading.Dispatcher、UWPではWindows.UI.Core.CoreDispatcherを使用する。

[基礎学習 × .NET Framework の非同期処理を見直してみた × その４](https://www.kinakomotitti.net/entry/2018/06/13/213614#WPF%E3%81%AE%E5%A0%B4%E5%90%88)


[非同期処理とディスパッチャー](https://ufcpp.wordpress.com/2012/04/26/%E9%9D%9E%E5%90%8C%E6%9C%9F%E5%87%A6%E7%90%86%E3%81%A8%E3%83%87%E3%82%A3%E3%82%B9%E3%83%91%E3%83%83%E3%83%81%E3%83%A3%E3%83%BC/)

[スレッド モデル](https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/advanced/threading-model?view=netframeworkdesktop-4.8)

## Invoke
Invokeはスレッドを新しく生成し、そのスレッド内でコントロールなどのオブジェクトを操作する際に呼ぶ。
Invoke()は主にWindowsフォームで使われる。（WPFでも使える）
**サブスレッドでInvokeを実行すると、Invoke内の処理はメインスレッド内で実行される。**
以下のサイトがわかりやすかった。
[【C#】UIスレッド以外からUIのコントロールを操作する](https://hikotech.net/post-388/)

またInvokeは**コントロールのオブジェクトが存在するクラスでしか呼び出すことができない。**
**delegate変数に入れたメソッド内でコントロールの操作がしたい場合、そのメソッド内でInvokeRequiredをすることで実装できる。**
InvokeRequiredはそのスレッドがサブスレッドの場合はtrue、メインスレッドの場合はfalseになる。
つまりInvokeの実行が必要かどうかを返す。
InvokeRequiredがtrue（サブスレッド）の場合は、Invokeの実行が必要なためInvokeを実行するように書いてあげる。
[[C#]Invokeの引数の使い方とは？InvokeRequiredプロパティ](https://www.fenet.jp/dotnet/column/language/9704/)


# Action,Func
delegateの宣言、インスタンス化、メソッド代入を省略した構文のこと。
- Action→戻り値なしのもののみ
- Func→戻り値あり
参考サイト：[【C#】delegate, Action, Funcについて 多分一番易しい解説](https://hikotech.net/post-449/)

# ラムダ式
一回の実行であるならば定義は必要がないもの。
参考サイト：[【C#】delegate, Action, Funcについて 多分一番易しい解説](https://hikotech.net/post-449/)


# Task,async/await
Task=非同期　ではない。
Taskは処理としてとらえるとわかりやすい。
awaitは、タスクの処理の完了を待つ。同期処理のような感じになる。
[Taskを極めろ！async/await完全攻略](https://qiita.com/acple@github/items/8f63aacb13de9954c5da)

[C#による音声の同期・非同期再生](https://qiita.com/Shi05yu/items/9c2f984f71806bcafa5c)

[[雑記] スレッド プールとタスク](https://ufcpp.net/study/csharp/misc_task.html)

[【C#】taskの使い方を基礎から使い方までわかりやすく解説してみる](https://hikotech.net/post-477/)
Nuxt3安定版でのバージョンアップで詰まったこと

Nuxt3.0.0-rc.12を使用していたため、この度バージョンアップをしました。

それほど、変わったことはしていませんが、備忘録というか、どなたかの助けになれば。

## 行ったこと
①Nuxt3をインストール
②headの記載をnuxt.config.tsから、app.vueに移動。
③nuxt.config.tsの「buildModules」を「modules」に変更。
④piniaの再インストール
⑤型定義の修正（nullやundefinedが未定義だったため。）


## 詳細（必要そうなところのみ。）

### ①Nuxt3をインストール
```
yarn add nuxt -d
```
または、npmの方は、
```
npm install -d nuxt
```

### ②headの記載をnuxt.config.tsから、app.vueに移動。
特になし。

### ③nuxt.config.tsの「buildModules」を「modules」に変更。
特になし。

### ④piniaの再インストール
```
Cannot read properties of undefined (reading 'nuxt')
```
上記のエラーが出たため、対処。
結論としては、piniaを一度消して、再度インストールすれば、OK。

うちの開発では、以下を使っていたため、二つとも消して、もう一度入れました。
```
 "pinia": "^2.0.13",
 "@pinia/nuxt": "^0.1.8",
```
 基本は、"@pinia/nuxt": "^0.1.8"のみでいいです。
うちでは、開発が進み、両方使っているため、削除するとエラーが出てしまうため、一旦、両方入れておくことに。（これは後日対処します。）

### ⑤型定義の修正（nullやundefinedが未定義だったため。）
これに関しては、エラーが出るので、気付けます。
undefinedの可能性があるデータに関しては、if分岐を使って回避することも必要です。
厳格な型定義ができるようになりました。
【Snowflake】実行計画・実行統計の確認（EXPLAIN 入門編）

# はじめに
Snowflakeに限らずですが、データべースはSQLを実行する前にオプティマイザが実行計画を作成してからSQLを実行します。
SQLが帰ってこないとき、SQLが処理しているかどこではまっているのか実行計画・実行統計を見て確認をします。

# 実行計画・実行統計の見方（実行中・実行後のSQLの場合）
実行中、実行後のSQLはSnowsightからアクティビティ⇒クエリ履歴⇒SQLを選択⇒「クエリプロファイル」タブで参照することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964512/10e550ce-d7e1-ad74-1465-034cbfb085c3.png)

このSQLでは右下の「統計」を見ると「リモートストレージにスピル」という項目が表示されていることがわかります。
Snowflakeでは内部メモリ内で処理できない場合、一時領域としてローカルストレージを使用し、それでも不足する場合はリモートストレージ（AWSであればS3）に処理を逃がします。
リモートストレージにスピルするような処理は特に時間がかかり、コストがかかる上に帰ってこないSQLになっていると思いますのでSQLを見直さないといけません。

SQLで負荷の高い処理は画面右上の「最も負荷の高い深いノード」に表示され、以下のようにノードを選択すると具体的にSQLのどの句を処理しているのか、を見てSQL修正の参考にすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964512/8c8888e2-83f2-33b7-f739-b2adf941676f.png)

# SQL実行前にどのような実行計画になるか確認する
SQLを実際に実行する前に実行計画を確認することができます。
または多くのテーブルをjoinして実行計画が複雑でグラフィカルな表示では見ずらい場合にEXPLAIN文を実行して確認します。

+ テーブル形式で参照する場合
こちらは実行順序は直感的にはわかりずらいのですがどこがネックになりやすそうか、は一番見やすいかもしれません。
```sql
EXPLAIN USING TABULAR
SELECT XX FROM XX .. （←実行計画を見たいSQL文） 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964512/98886421-a795-d674-24bc-6f16a0718ea6.png)

+ TEXT形式で参照する場合（個人的にはこちらのほうが見やすい）
```sql
EXPLAIN USING TEXT
SELECT XX FROM XX .. （←実行計画を見たいSQL文） 
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2964512/679b6844-02e0-ec33-735d-da2607bf6bc6.png)

実行計画の出力項目の意味は以下を参照ください。
参考URL:
https://docs.snowflake.com/ja/sql-reference/sql/explain.html#output

query_idがわかる場合は以下で取得することもできます。
```sql
SELECT SYSTEM$EXPLAIN_JSON_TO_TEXT(SYSTEM$EXPLAIN_PLAN_JSON('<query-id>'));
```

# おわりに
今回は初級編ということで、基本的な操作や高負荷SQLで表示される項目を紹介しました。
私自身より深い知識を得たらまた中級編以降を書こうと思います。

参考URL:
https://docs.snowflake.com/ja/sql-reference/sql/explain.html
【Python】CustomTkinter でコンボボックスの選択肢を動的に変化させる

# やりたいこと

[CustomTkinter](https://github.com/TomSchimansky/CustomTkinter) でコンボボックスを２つ作成し、コンボボックス１の選択に連動して、コンボボックス２の値が変化するようにしたかった。

例えば、Combobox_1 に西暦・和暦（令和）、Combobox_2 に年を選択するとき、西暦が選択された場合は年の選択肢が「2019年」「2020年」「2021年」「2022年」となるようにし、和暦が選択された場合は年の選択肢が「元年」「2年」「3年」「4年」となるようにしたかった。

# 実装

```python
import customtkinter as ctk

dict = {'西暦': ['2019年', '2020年', '2021年', '2022年'], 
        '令和': ['元年', '2年', '3年', '4年']}

ctk.set_appearance_mode("system")
ctk.set_default_color_theme("blue")

app = ctk.CTk()
app.geometry("290x110")
app.title("テストプログラム")
app.resizable(False, False)

def cb1_selected(event):
    combobox_2.configure(values=dict[combobox_1.get()])
    combobox_2.set(dict[combobox_1.get()][0])

combobox_1 = ctk.CTkComboBox(app, values=list(dict.keys()), command=cb1_selected, width=100)
combobox_1.pack(pady=10, padx=10)
combobox_1.set("西暦")
combobox_1.place(x=35, y=35)

combobox_2 = ctk.CTkComboBox(app, values=dict[combobox_1.get()], width=100)
combobox_2.pack(pady=10, padx=10)
combobox_2.place(x=155, y=35)

app.mainloop()
```

# 実行結界

下記のとおり、コンボボックス１（西暦・和暦）の選択に連動して、コンボボックス２（年）の値が変化するようになっています。

![Screenshot 2022-12-18 17.54.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667942/ff635988-cf3e-52a6-847f-f545bae63d1b.png)
![Screenshot 2022-12-18 17.54.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667942/f9230350-18de-081d-d672-2a71a6c6273c.png)

# 解説

コンボボックス１（combobox_1）で選択できる値（values）には、辞書のキーを設定します。
また、コンボボックス１のコールバック関数として cb1_selected 関数を指定します。

```python
dict = {'西暦': ['2019年', '2020年', '2021年', '2022年'], 
        '令和': ['元年', '2年', '3年', '4年']}
...
combobox_1 = ctk.CTkComboBox(app, values=list(dict.keys()), command=cb1_selected, width=100)
```

コンボボックス１が選択されたら cb1_selected 関数がコールされ、下記のコードが実行されます。ここでは ```combobox_1.get()``` の値に基づいて、コンボボックス２の値を辞書で指定します。

```python
def cb1_selected(event):
    combobox_2.configure(values=dict[combobox_1.get()])
    combobox_2.set(dict[combobox_1.get()][0])
```
【Rspec】FactoryBotとは

# FacroryBotとは
Rspecでテストを行う際にテストデータの作成をサポートするGemです。
Gemfileで`group :test do ~ end`の箇所に`gem "factory_bot_rails"`記述し使用します。
FacroryBotを使用するには`spec/factories/モデル名.rb`といった形でファイルを作成します。

# 例
今回は仮にUserモデルを例にして作成します。
```
% rails g factory_bot:model user(モデル名)
```
gemのインストールができたら上記のコマンド入力することで`spec/factories/users.rb`が作成され以下の雛形が出来上がっています。
```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do

  end
end
```
今回は名前とメールアドレスのダミーデータを作成する例として、テストコードを一つずつ見ていきましょう。
```ruby:spec/factories/users.rb
FactoryBot.define do
 factory :user do
  full_name  { Faker::Name.name } #名前のようなダミーデータの生成
  email      { Faker::Internet.email } # メールアドレスのようなダミーデータの生成
 end
end
```

### FactoryBot.define do ~ end
- 宣言文であり、データの定義を行う際に記述します。

### factory :user do ~ end
- どのモデルに対してデータ定義を行うのかを記します。
ex) factory :モデル名 do ~ end

### full_name  { Faker::Name.name }
- 名前のようなダミーデータの生成をしています
- カラム名 {値}の形になっています。
- Faker::はFaker(gem)を使用する時の宣言
- Nameの部分はどのダミーテキストタイプを使用するかを指定
- nameの部分で文字列を作成します

### email      { Faker::Internet.email }
- メールアドレスのようなダミーデータの生成をしています
- カラム名 {値}の形になっています。
- Faker::はFaker(gem)を使用する時の宣言
- Internetの部分はどのダミーテキストタイプを使用するかを指定
- emailの部分で文字列を作成します

# 定義したデータをどのように使用するのか
```ruby:models/user_spec.rb
RSpec.describe 'Userモデルのテスト', type: :model do
 describe `保存確認` do
  it "有効な会員情報の場合は保存されるか" do
    expect(FactoruBot.build(:user)).to be_vaild
 end
end
   
```
expectの期待値でFactoruBot.build(:user)として使用されています。
FactoryBot.build(:モデル名)で対象モデルのインスタンスを作成します。
FactoryBotを使用すれば、インスタンスをnewして値を代入する手間が省かれ、簡潔に記述することが可能になります。
メタバース空間で「におわせ写真は撮れるのか」を検証しました

こちらはクラスター Advent Calendar 2022（1ページ目）の18日目の記事です。
昨日は @swanman さんの「Switchであそぼう」でした。
Switch×VRでためになる記事でしたね。さすがスワンさんです。

<p><strong>はじめに</strong></p>
こんにちは、はじめまして。クラスタ―株式会社で広報をしているMIRINです。
わたしはエンジニアではないので、実のある話ができないかもしれませんが、どうぞお付き合いください。

突然ですが、今世間はクリスマス一色。
そうです。「匂わせ写真」がSNSをにぎわすビッグseasonが到来したのです。
何かを「匂わせる」写真。
そこで、ふと疑問に思いました。
メタバースSNSプラットフォームでも「匂わせ写真」、は撮影できるのか、と。

クラスター社員のりりィとmonaCを呼び出し、言いました。
「私、匂わせ写真撮影してみたい」
すぐに承諾を得ることが出来、我々３人は秘境へ――、ではなく、clusterへログインしました。

<p><strong>バーチャル「匂わせ写真」撮影してみた</strong></p>

以下は、「」のタイトルを添えて誰かがTwitterやInstagramで投稿していることを想像しながらお読みください。世界観がより一層伝わるかと思います。

エントリーNO1「ケーキおいしかった♡」
![eeebd89f-082a-4ca7-a110-608bcb65b220.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/42c2fd5f-59ca-4f10-a12b-efd63a10bf4b.png)

ご覧ください。
一人で行ったカフェの報告投稿かと思いそうですが、うっすら誰かが映っています。
新実装された「フォーカス機能」を存分に活かして、絶妙に「誰かの存在を感じさせる」ことに成功しました。

エントリーNO2「今日は誕生日！」

![14e26e0e-156f-416e-8965-fedddd0fc923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/e9e6ec4e-4679-79d7-cd71-0550252f52b8.png)

![6c9cf95a-73dc-4cfa-b35b-22f5dab36467 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/aac9c3f7-2810-0273-03fe-54bd0056c630.png)


この美しいホテルエリアはどこだ！？と思わず前のめりになってしまうこと間違いなし、美しいスポットが「少しだけ」映っています。（誕生日にぴったりの高千穂マサキさん作のワールドPiscina di lussoで撮影）記念日に誰もが憧れるホテルプールにいることを匂わせています。
これを見たフレンドも気になってJOINしたくなるかな？

エントリーNO3「無題」

![0d08fb99-0bb7-4c11-8645-8312461b3cc6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/0b9e0cae-47c0-79a2-d6b4-2c296e78e2b0.png)

続いて、高度な匂わせになります。
「誰か」を想起させるデザインの「何か」を映した画像です。
自分の部屋のインテリアに組み込んだり、NOタイトルでTwitterに投稿したりすると、「ハイコンテクスト！」と叫びたくなるかもしれません。

同じように以下の画像も高度に何かを匂わせています。

![afee922d-3426-4fd2-9bab-5933b95b8d3f (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/6b37c6d9-5c4d-8c8c-2a11-482d4fab9e53.png)

この角度の何を撮ろうとしたのか？と相手に思わせる構図。
人物は二人いますが、撮影者は誰だったのか？誰が、何のために？
考察がはかどってしまいます。
撮ってみて思ったのですが、これに関しては「様々な解釈」が出来ますので、もしよろしければストーリーを想像していただければと思います。

エントリーNO4「友達の家に来た！」

![20221216160415031 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/6deea124-8f3d-f03f-a8cd-a3c1f355b28d.png)

ごく普通のみんなでワイワイ画像に見えます。とみね氏の家（ワールド）に集まる４人組。楽しそうに思い出写真を撮っています。

だけど、よーく見てください。
おわかりいただけただろうか‥‥？

二人だけ、マフラーアイテムをおそろいカラーにして、他の二人のやや後ろに立っています。そして、「ハイチーズ」の写真を撮影した瞬間に、たまたま同じモーションをする。
これは何かが生まれた気配を感じます。
友情なのか、愛情なのかはわかりませんが、二人の心がつながりつつある証拠が撮れてしまった瞬間です。

エントリーNO5「今から仕事で検証～！」

次は、今回の素材を撮影中の現実の様子ですが、これもある意味「誰かが他にいる」ことをなんとなく映りこませています。

![IMG_9264.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/dd8e0bf2-325c-2036-7aeb-3e41cd8f62ed.jpeg)

こちらも「自撮りモードじゃない撮影」をすることで、「誰かが近くにいる」をうかがわせることができました↓
![d3b8f409-6881-4b20-8d03-6ffec4060c76.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953570/53cd955c-2afe-448d-bfe1-b2753043a0e4.png)


ここまで読んでいただきありがとうございます。
どうです？「で、どうしたんだ」と思われた方もいるでしょう。
誠に申し訳ございません。
女社員３人で仕事を忘れてclusterを楽しんだ瞬間でした。
「写真も遊びになる」を体験することができ、
そしてメタバースでも何かを「匂わせる」写真を撮影することが可能だと感じました。
ぜひ、みなさんも「何かを匂わせる写真」にチャレンジしてみていただけたら幸いです。

クリスマスシーズンということで、毎日皆様にハッピーを届けれられるようなアドベントカレンダーになれたらと思っています。
少し早いですが、メリークリスマス＆ハッピーニューイヤー！

明日はクラスター@Sixeightさんの「入社エントリー」です！何が書かれるかご期待ください！！
ログ出力(slf4j)の単体テスト

## はじめに
slf４jを使用したログ出力メソッドを実装した際に単体テストを書く必要があり、少し詰まったのでまとめておきます
Spring Boot + junit5 + mockito

## 概要
* テスト対象クラスのサンプルコード
* テストメソッドのサンプルコード
* テストメソッドの補足

### テスト対象クラス
INFOログを出力するような簡単なサンプル

```java
public class LogService{
  public void output() {
    Logger logger = LoggerFactory.getLogger(getClass());
    logger.info("hoge");
  }
}
```

### テストクラス

```java
  // 引数検証の為のArgumentCaptor、LoggingEventを検証する
  @Captor
  private ArgumentCaptor<LoggingEvent> captorLoggingEvent;

  // モック化されたAppender
  @Mock
  private Appender<ILoggingEvent> mockAppender;

  @Test
  void test() {
    // テスト対象のクラス名を設定
    Logger logger = (Logger) LoggerFactory.getLogger(LogService.class);
    // loggerのログ出力先をモック化する
    logger.addAppender(mockAppender);

    // テスト対象クラスの呼出
    targetService.outputStart();

    // 呼び出し回数の検証,引数の取得
    verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());
    // ログレベルの検証
    assertThat(captorLoggingEvent.getValue().getLevel().toString(), is("INFO"));
    // 出力メッセージの検証
    assertThat(captorLoggingEvent.getValue().getMessage(), is("hoge"));
  }
```

### テストクラスの補足
`ArgumentCaptor`の定義。
モック化したメソッドに渡される引数を検証する際に用いる。
```java
  @Captor
  private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
```

`Appender`はログの出力先の設定を行うために使用されるインターフェース。
```java
  @Mock
  private Appender<ILoggingEvent> mockAppender;
```
getLoggerの引数にテスト対象のクラス名を指定する
`addAppender()`メソッドでloggerのログ出力先をモックにするする。
```java
    Logger logger = (Logger) LoggerFactory.getLogger(LogService.class);
    logger.addAppender(mockAppender);
```
`verify`メソッドにより、モック化したメソッド（ログ出力）が何回呼び出されたかを検証。
またキャプラーで引数を取得し、アサーションを行う。
```java
    verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());
    assertThat(captorLoggingEvent.getValue().getLevel().toString(), is("INFO"));
    assertThat(captorLoggingEvent.getValue().getMessage(), is("hoge"));
```
Pipelineの使い方

## はじめに
今回はPipeLineモジュールについてのメモ。
機械学習モデルのスケーリングについて勉強していた時に出てきて、気になったので調べてみた。

## PipeLineモジュールとは
estimator(学習)とtransformer(予測)を組み合わせて、機械学習パイプラインを作成するAPIである。主に機械学習モデル構築で用いる。

## PipeLineモジュールを用いる利点
例えば、非決定義系モデルを扱う際にスケーリング（正規化や標準化）などの処理を行うことで精度を向上させる手法がある。
そのような際に、スケーリングと機械学習モデルの定義をいちいち別で書くと煩雑なコードになってしまうことが多い。
そこでPipeLineモジュールを用いることでスケーリング部分とモデル定義部分を一つの塊として定義することができる。
さらに、一般的なsklearn上にある機械学習モデルと同じようfitなども行えるため、煩雑になることなく使用することができる。

## 実際の使用方法
今回は例として、ロジスティック回帰と標準化を組み合わせた例を用いる。

```.py
Pipeline([('ss', StandardScaler()), ('model', LogisticRegression(C=0.01, random_state=42))])
```
引数のとしては、主にListを用いて定義する。
transformer・estimatorの並びの通り、estimatorが一番最後になることに注意する。
それぞれの定義の仕方は、(定義名, モデルの関数)とする。

ここで、複数のtransformerを定義することも可能である。

（公式Document : https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html）
pnpmでvite, react, typescriptのprojectを作成する

# pnpmでvite, react, typescriptのprojectを作成する

## Motivation

[pnpmのベンチマーク](https://pnpm.io/benchmarks)が気になったことと、主要なpackageでpnpmを利用していることがあり存在が気になっていた。
nx, lerna以外の monorepoの構成をpnpmで一度試してみたくなったことがこの記事のモチベーションです。

## table of contents

0. 作成しようとしているプロジェクト構成
0. pnpmのworkspace用のconfigファイルを作成する
0. vite, react, typescriptのprojectを作成する
0. 起動してみる

## 1. 作成しようとしているプロジェクト構成

Motivationにもあるとおり、pnpmの[multi-package](https://pnpm.io/workspaces)構成を利用したプロジェクト構成にしようとしています。

```terminal
$ tree . -L 2

├── README.md
├── apps                  application packages
│   └── react-project     vite project
├── node_modules
├── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
```

## 1. pnpmのworkspace用のconfigファイルを作成する

```terminal
$ mkdir vite-react-typescript && cd "$_"
$ npm init -y
$ touch pnpm-workspace.yaml
$ tree . -L 1
.
├── package.json
└── pnpm-workspace.yaml
```

applicationを記載するディレクトリ(/apps)を作成して、pnpm-workspace.yamlに追記します。

```terminal
$ mkdir apps
$ vi pnpm-workspace.yaml
```

```pnpm-workspace.yaml
packages:
  - 'apps/**'
```

追記が完了したら、viteのprojectをapps以下に作成していきます。

## 2. vite, react, typescriptのprojectを作成する

```terminal
$ pwd
/vite-react-typescript/apps

$ pnpm create vite react-project --template react-ts
Library/pnpm/store/v3/tmp/dlx-71354      |   +1 +
Packages are hard linked from the content-addressable store to the virtual store.
  Content-addressable store is at: /Users/XXX/Library/pnpm/store/v3
  Virtual store is at:             Library/pnpm/store/v3/tmp/dlx-71354/node_modules/.pnpm
Library/pnpm/store/v3/tmp/dlx-71354      | Progress: resolved 1, reused 1, downloaded 0, added 1, done

Scaffolding project in /vite-react-typescript/apps/react-project...

Done. Now run:

  cd react-project
  pnpm install
  pnpm run dev
```

vite cliを利用してプロジェクトを作成したあとに、依存関係をインストールします。

```terminal
$ pwd
/vite-react-typescript
$ pnpm install
```

## 3. 起動してみる

project rootディレクトリで、起動などを実施したいため、package.jsonを追記します。

```/vite-react-typescript/package.json
"scripts": {
    "dev": "pnpm  --parallel --filter \"./**\" dev"
  },
```

```terminal
$ pnpm dev
> vite-react-typescript@1.0.0 dev /vite-react-typescript
> pnpm  --parallel --filter "./**" dev

apps/react-project dev$ vite
apps/react-project dev:   VITE v4.0.1  ready in 2028 ms
apps/react-project dev:   ➜  Local:   http://127.0.0.1:5173/
apps/react-project dev:   ➜  Network: use --host to expose
```
![Vite-React-TS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144543/bb496c58-0387-861d-6df9-9b6912002e95.png)