OmniAICreator/Qiita-1.07M huggingface dataset:
Node-REDでのメール送信に使えるblastengineノードを作成しました

こちらは[Node\-REDのカレンダー \| Advent Calendar 2023 \- Qiita](https://qiita.com/advent-calendar/2023/node-red)、18日目の記事です。

[Node-RED](https://nodered.jp/)はフローベースのプログラミングツールです。ノードをつなげてプログラムを作成します。ノードは、入力を受け取って、処理を行い、出力を返すものです。Node-REDは、IoTの分野でよく使われています。

そんなフローの中で、結果や通知をメールで行えるようになるblastengineノードを作成しましたので、その使い方を紹介します。

## リポジトリ

blastengineノードは、GitHubで公開しています。ライセンスはMITです。

[blastengineMania/node\-red\-contrib\-bemail](https://github.com/blastengineMania/node-red-contrib-bemail)

## インストール

インストールはnpmコマンドで行います。

```bash
npm i node-red-contrib-bemail
```

インストール後は、Node-REDを再起動してください。

## 使い方

### blastengineノードの追加

blastengineノードはネットワークパネルの中にあります。

![blastengine-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c5db2bb5-d27a-c404-3db2-1abb5768174b.jpeg)


### 設定

設定項目は次の通りです。

| 項目名 | パラメーター名 | 説明 |
| --- | --- | --- |
| User name | username | blastengineのユーザー名 |
| API key | apikey | blastengineのAPIキー |
| To | to | 送信先のメールアドレス |
| Subject | subject | メールの件名 |
| From name | fromname | 送信元の名前 |
| From email | fromemail | 送信元のメールアドレス |
| Email body | message | メールの本文 |

入力項目はすべて、前のノードからの出力で上書きできます。たとえば以下のように送れば、メールの件名を変更できます。

```json
{
	"subject": "変更後の件名"
}
```

また、追加で `cc` と `bcc` を追加できます。

```json
{
	"cc": "cc@blastengine.jp",
	"bcc": "bcc@blastengine.jp"
}
```

![blastengine-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/69a9322c-e085-48fa-64a8-d69a4f9329aa.jpeg)


### メール本文について

メール本文では `__キー__` のような形で、前のノードからの出力を埋め込むことができます。たとえば、以下のようなメール本文を設定すると、メール本文に `name` というキーがあれば、その値を埋め込むことができます。

```
お名前: __name__
```

`__input__` というキーは、前のノードからの入力をそのまま埋め込むことができます。JSON Objectではない場合に使ってください。

```
新しい値です
__input__
```

## レスポンス

blastengineノードのレスポンスは、メール送信の結果になります。成功した場合はblastengineの配信IDが返ります。

```json
{
	"deliveryId: 9999
}
```

エラーの場合には、エラーの内容が返ります。

```json
{
	"error_messages": {
		"to": [
			"user@example.com: data is invalid email address."
		]
	}
}
```

![blastengine-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/81891693-76b7-475c-607b-d7ebc871d4a9.jpeg)


## まとめ

Node-RED用のblastengineノードを使えば、Node-REDを使って手軽にメール送信できます。ローカルで立てていても、ちゃんと届くメールが送信できます。また、大量のメール送信でもblastengineならば安定して処理できます。

ぜひ、Node-REDでのメール送信時に役立ててください。

[エンジニア向けメール配信システム「ブラストエンジン（blastengine）」](https://blastengine.jp/)

明日、19日目は[じぇーけーそふと \(@jksoft913\)](https://twitter.com/jksoft913)さんです。
WSL2 docker system prune をしても Ubuntu の容量が減ってくれない時の対処

Windows11 Proで、Docker Desktop は使わず、Ubuntu-20.04 上に docker を入れている。

 * `docker image prune`
 * `docker volume prune`
 * `docker continer prune`
 * `docker system prune`

上記諸々して、 docker system df をすると、減ってくれているはずが、
WSLの容量は引き続きパンパンと出る。

Docker Desktop だと、下記のOptimize-VHDの方法があるようだが、
apt-get で入れた Docker では使えなさそう。

https://qiita.com/sarisia/items/5c53c078ab30eb26bc3b

DockerやWSLをすべて破壊するのも嫌過ぎる…。
という状況で、調べた結果、DiskPart 使った方法で無事うまく容量を空けることができた。

## 手順
### WSLのシャットダウン
管理者権限でPowerShellを開く。
まずは、

```
PS > wsl --shutdown
```

で、WSLをシャットダウンする。

### 該当の `.vsdx` ファイルを探す

```
PS > cd $HOME\AppData\Local\Packages\
PS > ls
```

Packages の配下に `Canonical` から始まる `Ubuntu` を含むディレクトリがあることを確認する
とりあえず Ca 補完すればOK


```
PS > cd CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc
```

ここの配下に、 `LocalState` というディレクトリがあり、その中に、 `.vhdx` ファイルがあることを確認。

```
PS > cd LocalState
PS > ls
```

Pathをコピーする

### VHDファイルの物理サイズを減らす

Path をコピーしたら、 DISKPART を起動
```
PS > diskpart
```

起動したら、 select -> attach -> compact -> detach の順に行う。

```
DISKPART> select vdisk file="コピーした.vhdxのパス"

DiskPart により、仮想ディスク ファイルが選択されました。

DISKPART> attach vdisk readonly

  100% 完了しました。
DiskPart により、仮想ディスク ファイルがアタッチされました。

DISKPART> compact vdisk
DiskPart により、仮想ディスク ファイルは正常に圧縮されました。

DISKPART> detach vdisk
DiskPart により、仮想ディスク ファイルがデタッチされました。

DISKPART> exit
```

### 容量が空いたことを確認
上記実行で、Cドライブの容量が空いたことを確認できた。
Activeなdocker ボリュームやイメージ等は吹っ飛んでいないことも確認できた。


## 補足
インストールされているアプリから確認すると、775GBもUbutu-20.04が使っている状態だったので、compact vdisk は30分ぐらい？待った。ひぃ。

`docker system prune` とかで、dockerで使われたものの掃除自体はできているらしいが、
拡張されたものは、確保されたままになっちゃうということっぽい。。

https://github.com/microsoft/WSL/issues/4699

Cドライブがパンパンになってからこれをしたけど、パンパンになるより前に、ある程度不要なイメージ、builder cache とかは適宜消してあげておく方がよいという感じっぽい。



## 参考
https://01futabato10.hateblo.jp/entry/2022/12/02/095031
AWS CLFの勉強方法メモ

# はじめに
業務でAWSに触れず、予備知識0の状態から3ヵ月ほどでCLFに合格しました。
この記事を見てこれからCLFを勉強する方の参考になれば幸いです。
# 参考書・購入したもの
・[【CLF-C02版】これだけでOK! AWS認定クラウドプラクティショナー試験突破講座（豊富な試験問題300問付き）](https://www.udemy.com/course/ok-aws-e/)
・[【CLF-C02版】この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（6回分390問）](https://www.udemy.com/course/aws-4260/)

CLF合格に向けて購入したものは上記の2つのみになります。
通常7600円のところセールの時は1600円で買えるので、セールの時を狙うのがおすすめです。
# 勉強方法
#### まず自分が実際に行った勉強方法についてまとめます。

1. 解説動画を視聴し、内容をノートにまとめる
1. 模擬試験1周目を解く(解いた後解説を読みもう一度解き直してから次の模擬試験に行く)
1. 正答率70％(本番の合格ライン)を目標に模擬試験を行う。70％を超えたら次の問題へ、超えなかったらもう一度同じ模擬試験を行う。
1. 全ての模擬試験が1回目で70％を超えた辺りから次は90％で同じことを行う。
1. 全ての模擬試験が1回目で90％を超えたら本試験を申し込む。

#### 今振り返ってみて

模擬試験をひたすら繰り返すのが試験合格にむけて一番の近道なんだと実感しました。書いてある通り、9割模擬試験の解き直しで合格できました。

反省としては、ノート作る時間いらなかったんじゃないかな、、、
って思ってます。
範囲が広いので、解説動画を見てノートが完成するまで丸1ヵ月かかりました。~~そんなに使わなかったし~~
模擬試験の解説にも十分すぎるくらい説明が書いてあるので、次の資格勉強の際は最初から模擬試験に取り組もうと考えています。
# 最後に
次はAWS SAAに挑戦しますので、近いうちに勉強方法等について更新したいと思います。
この記事が少しでも受験する方の助けになれば幸いです。
パーミッションの「t」

Linuxのファイルやディレクトリのパーミッションの中には、「t」とかあまり見かけないものも存在する。例えば、/tmpのパーミッションを確認すると以下だ。

~~~bash
$ ls -ld /tmp
drwxrwxrwt. 9 root root 4096 12月 18 15:03 /tmp
~~~

この「t」はティッキービットと呼ばれ、この設定がされているディレクトリでは、そのディレクトリのパーミッションに「w」で書き込み権限があっても、そのディレクトリ配下のファイルをファイルの所有者以外が削除することはできない。以下が詳しい。そして正しい。

https://lpic-master.com/suid-sgid-stickybit

意外とディレクトリのパーミッションの「w」がディレクトリそのものの削除権限だと思っていたり（本当はディレクトリ配下のファイルやディレクトリへの権限となる）、ファイルのパーミッションに「w」がなければ削除ができないと思っていたり（本当はそのファイルが配置されているディレクトリのパーミッションに「w」があれば削除できる）して説明しているサイトが多いので注意。
GitHub GraphQL APIを使ってプルリクを取得してみた

## はじめに

この記事は[NE Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ne)の21日目の記事です。

## GitHub GraphQL APIとは

https://docs.github.com/ja/graphql

## 動機

* 生産性の可視化のためにデプロイ数を集計したかった。
* デプロイ数＝main(master)へのマージ数とした。
* 全期間集計すると大変なので直近マージされたものだけを取得したかった。

こんな動機から今回スクリプト組んで試してみました。

## 作ったもの

https://github.com/yamamoto-hiroya/get_pull_requests

## できること

基本の使い方としてはGitHub側のREADMEに記載してあります。
プルリクエストを集計したいアカウントのユーザー名とアクセストークンを指定することで実行できるようになります。

![スクリーンショット 2023-12-18 14.21.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67471/74a244a5-e87d-e1ec-0250-b0bac74c4d33.png)


アクセストークンは以下の手順で取得できます。
https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens

権限はpullrequestsとcontentsを許可してください。

## GraphQLの叩き方

```
curl -H "Authorization: bearer 自分のアクセストークン" -X POST -d @sample_search_query.txt "https://api.github.com/graphql"
```

```sample_search_query.txt
{
  "query": "query {
    search(first: 100, query: \"user:集計対象のユーザー名 is:pr is:merged merged:2023-12-01..2023-12-25 base:master base:main\", type: ISSUE) {
      nodes {
        ... on PullRequest {
          title
          permalink
          repository{name}
          author{login}
          baseRefName
          mergedAt
          updatedAt
          commits(first: 1){nodes{commit{committedDate}}}
        }
      }
      pageInfo{endCursor hasNextPage}
    }
  }"
}
```

まず基本形はこんな感じで叩くことができます。
このクエリの部分がだいぶ癖があり意図したものを取得するのに苦労しました。
ドキュメントとにらめっこしながら試行錯誤で欲しいものを取得するクエリを構築しました。
https://docs.github.com/ja/graphql/reference/queries#search

### クエリ解説

| クエリ | 解説 |
|:-|:-|
|first: 100|今のカーソル位置から100件取得する。100が上限。|
|after|カーソル位置を指定できる。2ページ目ここからみたいな使い方。|
|is:pr|プルリクエストを対象とする。|
|is:merged|マージ済みのプルリクエストを対象とする。|
|merged|マージされた期間を条件指定する。|
|... on PullRequest|プルリクエストオブジェクトに対して何のフィールドを取得するか指定している。|
|commits|first commitした日を取得している。これによりいつ開始されていつ終了されたかが分かる。|
|base:master base:main|プルリク先がmaster or mainを対象とする。|
|endCursor|現時点での末尾のカーソル位置。これを取得し次の実行のafterに指定する。|
|hasNextPage|次ページがあるかどうか。|

## コード解説

### curl.php

https://github.com/yamamoto-hiroya/get_pull_requests/blob/main/src/curl.php
curlする部分だけを切り抜いたクラス。
curlのオプションは外部から渡す方式にしても良かったかも。
あとUser-Agentは指定しないと叩けない割にhogehogeでも通るから謎。

### github.php

https://github.com/yamamoto-hiroya/get_pull_requests/blob/main/src/github.php
GitHubとの疎通部分を担っているクラス。
結果が複数ページに渡っていたとしてもループでネクストページを取得してくれる君。
結果は「data.csv」というファイルに出力する。
ファイル名とかも外から渡す形式にするか、ファイル出力処理自体を本クラスから切り離しても良かったかも。
あと_get_queryについて。
今後メンテする時に楽なので改行・インデントして見やすいようにしてあるが改行入ってるとうまくクエリ実行できず、仕方なく実行前に改行を削除する処理を挟んだ。
バックラッシュとかでエスケープできるはずなんだけどなぁ、という気持ち。

### main.php

https://github.com/yamamoto-hiroya/get_pull_requests/blob/main/src/main.php
メイン実行部分。
期間を指定することでその期間にマージされたプルリクエストが取得できます。

## まとめ

実はスクリプトが今の形になるまでに2段階くらいステップを踏んでおり
* 最初は期日指定での検索が分からず全期間取得していた。
* 1ファイルにクラス分けとかもなく処理をバーっと書いていた。

そんな状態でした。
期間指定できなくて都度取得するのしんどくなってきたので、改めて調べてリファクタし整形して今の形となりました。
これにより毎週デプロイ数を取得しスプレッドシートに転記→集計と分析を行っています。
今後は定期実行しスプレッドシートへの転記まで自動にするかを悩み中です。

## おわりに

今年のアドカレも佳境です。
引き続き最後までNEのアドカレをおたのしみに〜！
Salesforceのオブジェクトのカスタム項目の作成者、最終変更者を確認する方法【Tooling APIをPostmanから使う】


以下の質問の回答によれば、Toolong APIを使ってFieldDefinitionオブジェクトのCreatedById、LastModifiedByIdを確認すれば可能なようです。

+ [Is there a way to see created by , last modified by in feild definition using tooling api, metadata api or other ways in Apex?](https://salesforce.stackexchange.com/questions/384512/is-there-a-way-to-see-created-by-last-modified-by-in-feild-definition-using-to)
+ [カスタム項目の作成者・作成日を一覧で取得したい](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000O6lB3)


Postmanを使って確かめたいと思います。
PostmanからSalesforceにアクセスする方法は、以下を参考にして下さい。

+ [Postman : Salesforceで初めて使う時の処理手順](https://qiita.com/Keiji_otsubo/items/ac8571db2d836248e9f9)
+ [Postman : Salesforceで使う時の処理手順(既に一度接続した環境に対して)](https://qiita.com/Keiji_otsubo/items/6f493f98422551a946c3)
+ [Postman : Salesforceで使う時の処理手順(Salesforceの接続環境を切り替える)](https://qiita.com/Keiji_otsubo/items/ad4dc5062cdecf01b9a0)

# FieldDefinitionオブジェクトの検索

+ [Tooling API Objects/FieldDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_fielddefinition.htm)


Toolongを展開して、Tooling Queryをクリックして選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3245c463-6d5b-c3ed-cfaa-b85a988effef.png)

qのパラメータに以下を設定します。SOQL文のスペースを+で置き換えた形です。

```
select+id,DeveloperName,EntityDefinitionId,DurableId,LastModifiedById+from+ FieldDefinition+where+DeveloperName='Candidate'
```

エラーになってしまいました。

:::note alert
[
    {
        "message": "FieldDefinition: a filter on a reified column is required [EntityDefinitionId,DurableId]",
        "errorCode": "MALFORMED_QUERY"
    }
]
:::


パラメータに項目の検索条件を指定します。

```
select+id,DeveloperName,EntityDefinitionId,DurableId,LastModifiedById+from+ FieldDefinition+where+EntityDefinition.QualifiedApiName+=+'Candidate__c'+AND+QualifiedApiName+=+'City__c'
```

今度は検索できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7c63d44a-89f9-6167-a40e-037f82256e0c.png)



CreatedById、LastModifiedByIdがIdなので名前に変更できるかな

```
select+id,DeveloperName,EntityDefinitionId,DurableId,LastModifiedBy.Name+from+ FieldDefinition+where+EntityDefinition.QualifiedApiName+=+'Candidate__c'+AND+QualifiedApiName+=+'City__c'
```

usernameも使えそうです


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/1a057d80-5dd3-7366-cf03-802d9f8a7ba6.png)
XCode15系にアプデしたらアプリがLaunchScreenから先に進まなくなった

# はじめに
この記事はand factory.inc Advent Calendar 2023 19日目の記事です。
昨日は @ichikawa7ss さんの「[なんのためにあるの？逆引きスクラムプラクティス](https://qiita.com/ichikawa7ss/items/50eac1c2b859fdfe8c3a)」でした。

# 起こったこと

- XCode14.2で開発を進めていたアプリをXCode15で起動したところ、LaunchScreenを表示した後に真っ暗な画面（black screen）から先に進まなくなった

# 解消方法

- `UISceneConfiguration.delegateClass` を指定したら解消


## 修正前
```swift
    /// this shows black screen with XCode 15.0~. (worked when XCode 14.2)
    func application(
        _ application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
    ) -> UISceneConfiguration {
        return UISceneConfiguration(
            name: "Default Configuration",
            sessionRole: connectingSceneSession.role
        )
    }
```

## 修正後

```swift
	/// this works with XCode 15.0~
	func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        let sceneConfig = UISceneConfiguration(
            name: "Default Configuration",
            sessionRole: connectingSceneSession.role
        )
        sceneConfig.delegateClass = SceneDelegate.self
        return sceneConfig
    }
```

# 学び

- delegateClassを設定しましょう
- [公式ドキュメント](https://developer.apple.com/documentation/uikit/uisceneconfiguration/3197948-delegateclass)に記載されている通り、Info.plistのDelegate Class Nameを指定しているので本来修正前のコードで動くはずなのではと思うのですが…（実際XCode14.2では問題なく動作している）
    > UIKit sets this property’s initial value using the `[UISceneDelegateClassName](https://developer.apple.com/documentation/bundleresources/information_property_list/uiapplicationscenemanifest/uisceneconfigurations/uiwindowscenesessionroleapplication/uiscenedelegateclassname)` key from the appropriate scene in your app’s `Info.plist` file.
    >

# 補足
- 今回の事象ですが、XCode14.2環境で自分が開発を進めていた全てのアプリで起こっているわけではありません
- 発生条件が特定できていないものの、事象の解消はできたので一助になればと思い記事化しています

# 参照
- 今回の検証に用いた検証用アプリのレポジトリは[こちら](https://github.com/ykkd/DelegateClass_sample)です
LLM における In-context Learning って何？

大規模言語モデル (Large Language Models; LLM) の登場によって、プロンプトエンジニアリングといった新しい概念が登場しました。
LLM 登場以前から機械学習を学んでいた身としては、プロンプトエンジニアリングの登場は「学問みたいな顔しているけど、結局モデルの癖では？？」と中々受け入れられなかったのですが、今ではすっかり市民権を得ています。

さて、そんなプロンプトエンジニアリングの文脈で In-context Learning という単語が登場することがあります。
In-context Learning でググると、「要するに In-context Learning とは Few-shot prompting のこと」というようなページが出てくるのですが、「ML における Learning = パラメータの更新」という意識があると、非常に気持ち悪さを感じます。
そこで、今回はこの "In-context Learning" という言葉について確認していきます。

## In-context Learning とは

In-context Learning は、[Language Models are Few-shot Learners](https://arxiv.org/abs/2005.14165)という論文内で登場します（たぶん、この論文が言葉としては初出？）。

論文内では明確に In-context Leaning の定義が語られているわけではなく、何度か単語が登場するのでそこから定義は推し量ることができます。論文内では、以下のように説明されています。

> During unsupervised pre-training, a language model develops a broad set of skills and pattern recognition abilities. It then uses these abilities at inference time to rapidly adapt to or recognize the desired task. We use the term **“in-context learning”** to describe the inner loop of this process, which occurs within the forward-pass upon each sequence. 

訳すと

> 教師なし事前学習時、言語モデルの広範なスキルセットとパターン認識能力が発達する。そして、求められるタスクに迅速に適応したり、認識したりするために、これらの能力を推論時に利用される。このプロセスの内部ループを説明するために、**“インコンテキスト学習”** という用語を我々は使用する。このループは、各シーケンスにおけるフォワードパス中に発生する。

引用部分を図示したものが以下です。

![in-context_learning.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/758571/526ac6d3-1bc6-b9e8-f0fd-6ffb64bb896e.png)
(出典：[Language Models are Few-shot Learners](https://arxiv.org/abs/2005.14165))

わかったようなわからないようなという感じですが、Pre-training 時の 1 文章に含まれる「5+8=13, 7+2=9, ..., 9+8=17」のような内部ループを学習することで、規則的な文章からパターンを認識する能力を獲得することこそが In-context Learning と言えそうです。
（これは Pre-training 時の話なので、パラメータの更新が起きており、Learning と言われてもしっくりきます。）

つまり、「In-context Learning = Few-shot prompting」ではなく、「In-context learning によってできるようになることが Few-shot prompting 」ということです。

## 結論を 3 行で

- "In-context Learning" は、特に大規模な言語モデルにおける学習方法の一つで、モデルが与えられた入力のコンテキストに基づいて新しいタスクを理解し、適応する能力あるいはその能力を学習すること。
- モデルが以前に収集した知識やデータを活用して、特定の例や指示から学び、それに応じて適切な応答を生成することを目的にしている。
- In-context Learning によって Few-shot prompting ができるようになるのであって、狭義の意味では「In-context Learning = Few-shot prompting」は間違い。

というのが、私の中の解釈です。

以上です。皆さんなりの解釈あれば、コメントで教えてください。
ありがとうございました。
SwiftUI Mapkit Search

## view
```

var body: some View {
    HStack {
       Button {
            search(for: "playground")
       } label: {
            Label("Playgrounds", systemImage: "figure.and.child.holdinghands")
       }
       .buttonStyle(.borderedProminet)

        Button {
                    search(for: "playground")
               } label: {
                    Label("Playgrounds", systemImage: "figure.and.child.holdinghands")
       }
       .buttonStyle(.borderedProminet)
       
    }
    .labelStyle(.iconOnly)
}

```




## search
```

@Binding var searchResults: [MKMapItem]

func search(for query: String, region: MKCoordinateRegion? = nil) {
    let request = MKLocalSearch.Request()
    request.naturalLanguageQuery = query
    request.resultTypes = .pointOfInterest

    if let region = region {
        request.region = region
    }
    Task {
        let search = MKLocalSearch(request: request)
        let response = try? await search.start()
        searchResults = response?.mapItems ?? []
    }
}
```
PCにUSB接続できるIO-Link Master

# はじめに 

PCにUSB接続できるIO-Link Masterを使ってみました。
通常であればPLCとプログラムが必要ですが、簡単に使えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/79257851-070f-47f1-bf71-b96a5a497d89.png)




メーカー：TURCK
型式：USB-2-IOL-0002

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/5c98c43a-a740-fe3d-748b-fdd32846d835.png)

製品の情報はこちら

https://www.turck.us/en/product/6825482

# IO-LINKとは

>近年、工場現場で使用されているセンサー(測定器)、アクチュエータ(操作器)は内部にマイクロプロセッサを実装しており、各種パラメータによる設定、診断機能の充実等の機能拡張が図られています。
>「IO-Link」は、工場現場のセンサー・アクチュエータ用デジタル通信規格です。センサー・アクチュエータと制御機器間でやり取りされる測定値、操作値をより高精度に通信できるだけでなく、アナログ通信では伝送できなかったパラメータデータやイベントデータを取り扱うことで、工場のIoT化の実現に貢献します。
「IO-Linkコミュニティ ジャパン」は日本国内でのIO-Linkの普及を促進するため、2017年4月から活動を開始しました。

http://io-link.jp/

# 使い方

ソフトウェアをメーカーホームページよりダウンロードします。

`TAS.exe`を起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/7a21b9de-f2d8-c2e4-9f66-15ff126bca48.png)

色々ありますが、`USB IO-Link Master`より`CONNECT`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/05fbe36f-6714-b1be-2668-9ebd64fcb42e.png)

問題なければつながると思います。

:::note info
センサーの`IODD`ファイルをダウンロードして、ソフトウェアにLoadする必要があります。
:::

`Process Data`→グラフのアイコンをクリックするとデータの可視化が可能です。
例）温度センサーのデータを表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3343142/8fb45f4b-5303-f0bf-68ca-c1b13ba3cee7.png)

# 参考ページ

https://at.azbil.com/mt/product/pdf/turck_IO-Link_install_manual-02.pdf
Azure Container Apps (ACA) で Dapr component を使ってみた感想

## Azure Container Apps & Dapr
今回は [Azure Container Apps](https://learn.microsoft.com/ja-jp/azure/container-apps/overview) (ACA) で Dapr Component を使用してみた感想を紹介する。ACAでのDaprを使うときに参考になる公式ドキュメントは[こちら](https://learn.microsoft.com/en-us/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml)。Dapr には 様々な [Component](https://docs.dapr.io/reference/components-reference/) があり、それらを組み合わせて利用することで、柔軟な構成が可能となっている。

### 良かったこと
- [Azure Storage Queues binding](https://docs.dapr.io/reference/components-reference/supported-bindings/storagequeues/)
  - Queue binding を利用することで、ACAでQueueトリガーが使用可能になった。
  - また、上記bindingがenqueue/dequeueを担ってくれるため、アプリケーションにAzure Blob Storage SDK等をinstallする必要がなくなり、enqueue/dequeue の処理を自分で書かなくて済んだ。
- [Azure Key Vault secret store](https://docs.dapr.io/reference/components-reference/supported-secret-stores/azure-keyvault/)
  - ACA自体にSecret管理機能はあるが、それを使わずに Dapr Secret Component を使った。
  - Dapr Secret Component で Azure KeyVaultを選択すると、kv上のsecretを名称を指定して、Dapr経由で参照できるようになる。
  - ACAのUser Identityに [Key Vault Secrets User](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#key-vault-secrets-user) を与えることで、ACA上のアプリがDapr経由でkv secretにアクセスできるようになる。
  - そのため、secretをKey Vaultで集中管理することができる。
  - なお、`Key Vault Secrets User` を使うことになるため、Key VaultでRBACが使えるようにしてあげる必要がある
  　　- terraformの場合は `enable_rbac_authorization: true` を指定する。
  　　- [azurerm_key_vault](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/key_vault#enable_rbac_authorization)

### 物足りなかったこと
- [Azure Blob Storage binding](https://docs.dapr.io/reference/components-reference/supported-bindings/blobstorage/)
  - Daprでblobの操作をするComponentはあるのだが、単純なCRUDしかできず、Azure Blob Storage SDKで使えるような細かい要求を満たすということができないケースがある。
    - 例えば、blobをstreamで取得したい時など
  - 今回のアプリでは使用を見送った。

### ハマったところ
- queue binding でenqueue(input)/dequeue(output)の両方を実施しようとした場合、ACAのIdentityに [Storage Queue Data Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage-queue-data-contributor) を与える必要がある。
  - 最初は [Storage Queue Data Message Processor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage-queue-data-message-processor)と[Storage Queue Data Message Sender](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#storage-queue-data-message-sender)を与えていたのだが、ACAでenqueue/dequeue時に403エラーが発生したため `Contributor` に変更した。
S3 Express One Zoneについてまとめてみた

# はじめに
[にわのわ](https://twitter.com/niwa_nowa)です。

# S3 Express One Zoneとは
低レイテンシーで高頻度アクセス向けのストレージクラスです。
大本営発表で**最大10倍**のパフォーマンスを発揮すると言われています。

# 値段の比較
保存料金はS3 Standardの約7倍、データアクセス料金はS3 Standardの約半分です。
短いライフサイクルの中で小さなオブジェクトに対してアクセスが多いときにより効果的です。

最も読者が近いであろうTokyoリージョンでの比較です。

| ストレージクラス         | 保存料金（GBあたり） | PUT, COPY, POST, LIST requests | GET, SELECT, and all other requests |
|----------------------|-------------------|-------------------------------|-------------------------------|
| S3 Standard          | $0.025            | $0.0047                       | $0.00037                      |
| S3 Express One Zone  | $0.18             | $0.0024                       | $0.00019                      |


参照

https://aws.amazon.com/s3/pricing/?nc1=h_ls

# 作り方
こちらを参照

https://aws.amazon.com/jp/blogs/news/new-amazon-s3-express-one-zone-high-performance-storage-class/

# アクセス方法
AWS CLIやS3 APIから通常のS3と同様に利用できます。

ただし、IAMポリシーの書き方に注意が必要で、
アクション名が```s3express:*```となります。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-express-security-iam.html

# おわりに
re:Inventで発表されたS3 Express One Zoneについてまとめてみました。
特にDWH辺りとの連携となってくると使う機会があると思うので、頭の片隅に残せられればと思います。
bcp を使用した一括データのインポート ( Azure SQL Database )



## はじめに
検証用にAzure SQL Database上にサンプルテーブルを作成する機会がありました。その際にbcp を使用したサンプルデータの一括インポート実施したので、こちらについて紹介したいと思います。


## テーブルの作成
まず、Azure SQL Database に接続してテーブルを作成します。以下は、簡単なサンプルテーブルの SQL スクリプトとなります。

```CREATE TABLE Employees (
    EmployeeID INT PRIMARY KEY,
    Name VARCHAR(100),
    Position VARCHAR(100),
    Department VARCHAR(100)
);
```

※ この SQL スクリプトを Azure SQL Database に接続されている SQL クライアントツール（例えば、SQL Server Management Studio、Azure Data Studio など）で実行します。



## サンプルデータの準備
ローカル上にサンプルデータを含む CSV ファイルを作成します。`employees.csv` というファイルに以下のような内容を記入します。

```
EmployeeID,Name,Position,Department
1,James Johnson,Software Engineer,Engineering
2,Emily Davis,Marketing Manager,Marketing
3,Michael Smith,Sales Associate,Sales
```

## bcp コマンドを使用してデータのインポート
1. bcpコマンドを実行する環境を整えるために、以下のリンクからSQL Server Command Line Utilitiesのインストールします。
　https://learn.microsoft.com/ja-jp/sql/tools/bcp-utility?view=sql-server-ver15#windows
2. 次に、コマンドプロンプトを開いて、以下のような `bcp` コマンドを実行してデータをインポートします。
```cmd
bcp [YourDatabaseName].[dbo].[Employees] in "C:\path\to\employees.csv" -c -t, -S [YourServerName].database.windows.net -U [YourUsername] -P [YourPassword] -F 2
```
- `[YourDatabaseName]`、`[YourServerName]`、`[YourUsername]`、`[YourPassword]` を適切な値に置き換えます。
- `-c` オプションはデータを文字列として扱うことを指定します。
- `-t,` オプションは、フィールド間の区切り文字としてコンマを指定します。
- `-F 2` オプションは、CSV内の2行目のレコードから挿入します。

## 実行した結果
実行した結果、無事にデータが書き込めました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3340799/704e5746-e495-37e3-714e-13f71a3f5310.png)

Employeesテーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3340799/60b3c1c6-fdd4-844b-6e51-dad6e4c50fa3.png)


## まとめ
この記事では、bcpコマンドを使用してCSVデータをAzure SQL Databaseに追加する手順について詳しく解説しました。この方法は、データの大量インポートを手軽に実施できますので、ぜひ、実施してみてください。

## おわりに
ナレッジコミュニケーションでは「Musubite」というエンジニア同士のカジュアルトークサービスを利用しています。
クラウドAI・VR技術を使ったプロジェクトに携わる現場メンバーと直接話せるサービスですので興味がある方は是非利用を検討してください！

https://recruiting.musubite-job.com/features/company/knowledge-communication
MeCab-python3 ユーザー辞書の作成windows11

windowsでMeCabの辞書に単語を追加する方法です。正規のやり方ではないと思いますが、ネット上の方法では上手く出来なかったので自分なりに見つけた方法を記しました。


# MeCabのインストール
1.pythonのライブラリインストール

```terminal
pip install mecab-python3
```
なお、`conda install` には対応しておらず。

2.Windows版をインストール。[ここ](https://taku910.github.io/mecab/#download)から。
文字コードは`UTF-8`を選択する。

# ユーザー辞書の作成
1. Windows版MeCabのデフォルトの辞書を探す。
例：`C:\Program Files (x86)\MeCab\dic\ipadic`
1. 単語情報が入っているcsvファイルを探す。
1. csvファイルを適当な所にコピーして末尾に単語を追加する。
（そのままだと読み取り専用で編集できないため）
1. 元のファイルと置き換える。管理者権限が必要。
1. スタートメニュー>`MeCab`フォルダから`Recompile UTF-8 Dictionary`を実行する。
1. 更新されたどこかのフォルダに保存されているので探す。<br>例：`C:\Users\***\AppData\Local\VirtualStore\Program Files (x86)\MeCab\dic\ipadic`
1. 見つけたら以下の4つのファイル（中身はたぶん辞書のデータ）を任意のフォルダにコピペする。<br>`char.bin` `matrix.bin` `sys.bin` `unk.bin`
1. `dicrc`をデフォルト辞書のディレクトリからコピペする。


<b>完了</br>

※上記 7.8.において5つのファイルをコピペしたフォルダが、後にpythonから辞書の場所として指定するフォルダである。


# pythonから実行する
```python
import MeCab
tagger = MeCab.Tagger('-r nul -d C:/Users/***/Documents/python/[作成した辞書の場所]')
```

`-r nul`は無くても大丈夫で、`-d`は必要。
ネット上の情報では、ユーザー辞書の指定に`-u`を用いているが、上手くいかず。
代わりに、デフォルトの辞書に指定単語を追加する形で対応している。このため上記でリコンパイルを行っている。

# コード全体
テキストから名詞、動詞（原形）、形容詞（原形）を取り出すコードの例。

```python
def mecab_text(text):
    tagger = MeCab.Tagger('-r nul -d C:/Users/***/Documents/python/[作成した辞書の場所]')
    node = tagger.parseToNode(text)
    #形態素解析した結果を格納するリスト
    wordlist = []

    while node:
        #名詞のみリストに格納する
        if node.feature.split(',')[0] == '名詞':
            wordlist.append(node.surface)
        #他の品詞を取得したければ、elifで追加する
        elif node.feature.split(',')[0] == '動詞':
            wordlist.append(node.feature.split(',')[6])
        elif node.feature.split(',')[0] == '形容詞':
            wordlist.append(node.feature.split(',')[6])
        
        node = node.next
        
    wordlist = [w for w in wordlist if w  not in stopwords]
    
    return wordlist


stopwords =["こと","お","これ","a","b","c","%","以上","もの",
            "する","もの","とも","ある","よる","的","[","]",
           "さん"]
```
Azure OpenAIでほしい回答を入手するために検討したいこと

# はじめに
Azure OpenAIでほしい回答を入手するためにどんなことを検討した方がよいかを整理していこうと思います。コンテンツはこれから用意するので、内容が変更したり公開予定日が変更する可能性がある点はご了承ください。またまとめる内容以外にも検討すべき観点あるかもしれませんが、コメントなどでご指摘いただけると嬉しいです。

ブログの内容は個人の意見・見解の表明であり、所属組織の意見・見解を代表したものではありません。

# Azure OpenAIでほしい回答を入手するために検討したいこと
| 大項目 | 記事の概要 | 公開予定日 |
|:-:|:-:|:-:|
| プロンプトエンジニアリング | [目的に合った回答を生成できるように制限を与える：システムメッセージエンジニアリング](https://qiita.com/k-kimino/items/368b053aafba665574a5) | 公開済み |
|  | [プロンプトエンジニアリングでよい回答を得るために意識したい方針](https://qiita.com/k-kimino/items/543e8292bac581db4108) | 公開済み |
| 外部データを使った回答(RAG) | [【Azure AI Search】外部ソースのデータを活用した生成AIの回答生成の仕組み](https://qiita.com/k-kimino/items/7a35de57e11176dc019c) | 公開済み |
|  | [【Azure AI Document Intelligence】PDFなど非構造型データから生成AIの回答を生成する](https://qiita.com/k-kimino/items/7d31052099ca6e8019c7) | 公開済み |
| 安全に生成AIを活用する | 避けるべき情報が含まれないかチェックする | 2/3 |
|  | モデルの信頼性を評価する | 2/8 |
Salesforceのオブジェクトにカスタム項目が追加できるかを確かめる方法【Tooling APIをPostmanから使う】


以下の質問の回答によれば、Toolong APIを使ってEntityDefinitionオブジェクトのIsCustomizableがtrueならカスタム項目が追加できるオブジェクトとのことです。

+ [Is it possible to create a field on a system object?](https://salesforce.stackexchange.com/questions/392715/is-it-possible-to-create-a-field-on-a-system-object)

Postmanを使って確かめたいと思います。
PostmanからSalesforceにアクセスする方法は、以下を参考にして下さい。

+ [Postman : Salesforceで初めて使う時の処理手順](https://qiita.com/Keiji_otsubo/items/ac8571db2d836248e9f9)
+ [Postman : Salesforceで使う時の処理手順(既に一度接続した環境に対して)](https://qiita.com/Keiji_otsubo/items/6f493f98422551a946c3)
+ [Postman : Salesforceで使う時の処理手順(Salesforceの接続環境を切り替える)](https://qiita.com/Keiji_otsubo/items/ad4dc5062cdecf01b9a0)

# EntityDefinitionオブジェクトの検索

+ [Tooling API Objects/EntityDefinition](https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_entitydefinition.htm)

Toolongを展開して、Tooling Queryをクリックして選択します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3245c463-6d5b-c3ed-cfaa-b85a988effef.png)

qのパラメータに以下を設定します。SOQL文のスペースを+で置き換えた形です。

```
select+id,NamespacePrefix,MasterLabel,QualifiedApiName,DeveloperName,IsCustomizable+from+Entitydefinition+where+DeveloperName='Account'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6b885217-3627-48c4-b524-ab6699226482.png)


検索結果は以下の通りでした。取引先なのでカスタム項目は追加できます。よってIsCustomizableはtrueです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/1496d7e4-70c5-439c-3cee-11be31128c74.png)


# Tooling Queryでのエラー


qパラメータ:where句を省いた検索

```
select+id,NamespacePrefix,MasterLabel,QualifiedApiName,DeveloperName,IsCustomizable+from+Entitydefinition
```

結果の件数が多いのかもしれません

:::note alert
[
    {
        "message": "EntityDefinition does not support queryMore(), use LIMIT to restrict the results to a single batch",
        "errorCode": "EXCEEDED_ID_LIMIT"
    }
]
:::

qパラメータ:取引先と取引先責任者で検索します

```
select+id,NamespacePrefix,MasterLabel,QualifiedApiName,DeveloperName,IsCustomizable+from+Entitydefinition+where+DeveloperName='Account'+OR+DeveloperName='Contact'
```

やはり検索結果の件数が多かったようです。２つのオブジェクトは問題なく検索できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0f2e39a8-002e-667f-eb55-3c878d6d398f.png)


qパラメータ:わざと存在しないオブジェクトを検索

```
select+id,NamespacePrefix,MasterLabel,QualifiedApiName,DeveloperName,IsCustomizable+from+Entitydefinition+where+DeveloperName='Account1'
```

:::note alert
{
    "size": 0,
    "totalSize": 0,
    "done": true,
    "queryLocator": null,
    "entityTypeName": null,
    "records": []
}
:::

qパラメータ:カスタムオブジェクトの場合DeveloperNameでは__cは不要です。

```
select+id,NamespacePrefix,MasterLabel,QualifiedApiName,DeveloperName,IsCustomizable+from+Entitydefinition+where+DeveloperName='Candidate'
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/326e83f5-77a0-45de-5c2d-ab19e0206d28.png)
Python + Matplotlibを使用して単位円を描画する

## 開発環境
- Python 3.12.1
- Visual Studio Code (Version: 1.85.1)
- matplotlib          3.8.2
- numpy               1.26.2

## コード
```python
import matplotlib.pyplot as plt
import numpy as np

CIRCLE_LINE_COLOR = '#0000FF'  # 円周の線の色
X_AXIS_LINE_COLOR = '#000000'  # X軸の線の色
Y_AXIS_LINE_COLOR = '#000000'  # Y軸の線の色
GRID_COLOR = '#AAAAAA'  # グリッドの色

CIRCLE_LINE_WIDTH = 2  # 円周の線の太さ
X_AXIS_LINE_WIDTH = 0.8  # X軸の線の太さ
Y_AXIS_LINE_WIDTH = 0.8  # Y軸の線の太さ
GRID_LINE_WIDTH = 0.5  # グリッドの線の太さ

FIGURE_SIZE = (6, 6)  # 図のサイズ
AXIS_LIMIT = 1.5  # 軸の制限 (どこまでの値を表示するか)
GRID_LINE_STYLE = '--'  # グリッドの線のスタイル
LABEL_FONT_SIZE = 14  # ラベルのフォントサイズ
TITLE_FONT_SIZE = 16  # タイトルのフォントサイズ

OUTPUT_FILENAME = "graph.png" # 保存用ファイル名

theta = np.linspace(0, 2 * np.pi, 1000)  # 0から2πまでの角度
x = np.cos(theta)  # x座標を計算
y = np.sin(theta)  # y座標を計算

plt.figure(figsize=FIGURE_SIZE)

plt.plot(x, y, label='Unit Circle', color=CIRCLE_LINE_COLOR, linewidth=CIRCLE_LINE_WIDTH)  # プロット

plt.title('Unit Circle', fontsize=TITLE_FONT_SIZE)  # タイトルを追加

plt.xlabel('X', fontsize=LABEL_FONT_SIZE)  # x軸のラベル
plt.ylabel('Y', fontsize=LABEL_FONT_SIZE)  # y軸のラベル

plt.axhline(0, color=X_AXIS_LINE_COLOR, linewidth=X_AXIS_LINE_WIDTH)  # X軸
plt.axvline(0, color=Y_AXIS_LINE_COLOR, linewidth=Y_AXIS_LINE_WIDTH)  # Y軸

plt.grid(which="both", color=GRID_COLOR, linestyle=GRID_LINE_STYLE, linewidth=GRID_LINE_WIDTH)  # グリッドを追加
plt.minorticks_on()  # グリッドの補助線を有効化

plt.legend()  # プロットの右上にレジェンドを表示

plt.xlim(-AXIS_LIMIT, AXIS_LIMIT)  # x軸の値がどこまでかを設定
plt.ylim(-AXIS_LIMIT, AXIS_LIMIT)  # y軸の値がどこまでかを設定

plt.savefig(OUTPUT_FILENAME)
```

## 出力された画像
![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611466/56b5f3e7-64ac-4a14-ee57-1f9f1f2ed3f9.png)


## 参考資料
- [Matplotlib: Visualization with Python](https://matplotlib.org/)
- [Python 3 documentation](https://docs.python.org/3/index.html)
2次元配列をフィルターする_VBAで

2次元配列を指定した列・文字でフィルターしてみます。
複雑なフィルター条件するなら、シート上で処理した方が簡単にできると思いますが。
一度配列にデータを入れて、何かの条件でフィルターして、それをまた続けて処理とかする時に、シートに書き出さずに配列のままで出来たらいいなあと思ってやってみました！

新しいエクセルであれば、ワークシートのFILTER関数というのが使えて、これがよさそう。
（職場のPCはエクセル2019。。。）

# 配列をフィルターする関数
- 処理中に配列の行列を逆にしているので`Call 行列の入替え(filterArray)`でそれを戻している
- [行列の入替えについてはこちらの記事](https://qiita.com/gug1msp/items/85b92b84702e41a89582)
``` vb
Private Function 配列をフィルター(myArray, filterCol As Long, filterKey As String, Optional titleFlag As Boolean = False)

    Dim filterArray
    Dim tmpMinRow As Long
    Dim tmpMaxRow As Long
    Dim tmpMinCol As Long
    Dim tmpMaxCol As Long
    Dim i As Long
    Dim j As Long
    Dim skipRow As Long
    
    tmpMinRow = LBound(myArray, 2)
    tmpMaxRow = UBound(myArray, 2)
    tmpMinCol = LBound(myArray, 1)
    tmpMaxCol = LBound(myArray, 1)
    
    '縦横を入れ替えた配列　フィルターして残すものを追加していく
    ReDim filterArray(tmpMinRow To tmpMaxRow, tmpMinCol To tmpMaxCol)
    tmpMaxCol = tmpMaxCol - 1
    
    'タイトルを含めるかどうかの処理
    If titleFlag Then
        tmpMaxCol = tmpMaxCol + 1
        ReDim Preserve filterArray(tmpMinRow To tmpMaxRow, tmpMinCol To tmpMaxCol)
        For j = LBound(myArray, 2) To UBound(myArray, 2)
            
            filterArray(j, tmpMaxCol) = myArray(LBound(myArray, 1), j)
        Next
        'タイトル行分をループ処理に含むかどうか
        skipRow = 1
    End If

    '対象列がフィルター対象だったら一時配列に追加していく
    For i = LBound(myArray, 1) + skipRow To UBound(myArray, 1)
        
        If myArray(i, filterCol) Like filterKey Then
            
            tmpMaxCol = tmpMaxCol + 1
            ReDim Preserve filterArray(tmpMinRow To tmpMaxRow, tmpMinCol To tmpMaxCol)
            For j = LBound(myArray, 2) To UBound(myArray, 2)
                filterArray(j, tmpMaxCol) = myArray(i, j)
            Next
            
        End If
    Next

    Call 行列の入替え(filterArray)
    配列をフィルター = filterArray

End Function
```

## 引数の説明
- myArray　対象とする2次元配列
- filterCol　フィルター対象とする列
- filterKey　フィルターする文字列
  条件の所を、if ~ like としているのでワイルドカードも可
- titleFlag　配列の一行目がタイトルかどうか
  規定値はfalse
  trueにすると一行目はフィルター対象外として必ず含める

  ## 戻り値の説明
- フィルターした結果を2次元配列で返す
- 条件に当てはまるのがなかったら空の配列が返される（エラーにはならない）
  `titleFlag`をtrueにしていたらタイトルだけの配列が返される
  
  # 使用する
- 元表シートにある表から、2列目で"文字文字"でフィルターする
- 一行目はタイトルとして残す
- 結果はフィルターシートに書き出される
``` vb
Sub main()

    Dim myArray
    
    myArray = ThisWorkbook.Worksheets("元表").Range("A1").CurrentRegion
    
    myArray = 配列をフィルター(myArray, 2, "文字文字", True)
    
    With ThisWorkbook.Worksheets("フィルター").Range("A1")
        
        .CurrentRegion.ClearContents
        .Resize(UBound(myArray, 1), UBound(myArray, 2)) = myArray
        
    End With
    
End Sub
```
エイチームでのインターンを振り返る

# はじめに
エイチームフィナジーでの約4か月間のインターンを振り返り、学んだことを簡単にまとめます。
# 普段の業務の概要
主にナビナビ保険という保険比較サイトの改修や機能追加を行っています。

https://www.navinavi-hoken.com/
# 印象に残っていること
コードレビューで指摘をもらうときに毎回視野広すぎ！ と驚いていました。僕が一日かけて考えても見落としていた部分を即座に見つけて指摘されます。

あとはチーム作りについても驚きました。あるプロジェクトが始まり要件を定義していく際にエンジニア、デザイナー、マーケなどいろんな職種の人が集まって議論をしていました。この進め方で要件がまとまるのか？と思っていたのですが、意見が対立した時もお互いの考えをすり合わせより良いアイデアを探っていたり、なぜかデザイナーの方がスクラムマスターをされていて議論をグングン推進されていました。エイチームすごい
# 学んだこと
先輩のような視野の広さを身に付けたいと思いました。そこで視野の広さとは何だろうと考えたのですが、僕から見れば別々の物事だと考えていることが実は深い部分でつながっていて、先輩からすれば体系的に理解している一つの物事になっているんじゃないか、それが視野の広さの正体なんじゃないか？という仮説を持っています。

考えてみれば普段の開発でも困ったらすぐにstack overflowやらQiitaやらで検索してみつかった解決策を当てはめていることが多いです。
このやり方だと全く同じ問題が起きた時には対応できますが、違う問題が発生した時にはまた一から調べ直す必要があり、場当たり的な問題解決になります。

結局やるべきことは時間をかけてでも、その問題が発生した根本の原因が何だったのかを探り、仕組みから理解していくことが大事なんだと学びました。
# まとめ
エイチームの優秀なエンジニアと働くことで技術や考え方を吸収でき、非常に充実した4か月になりました。
個人開発だけでは学べないことがインターンでは学べるので、エンジニアを目指す大学生にはぜひおすすめしたいです。
ESP32のFreeRTOSで10msごとのプリント時刻がずれるときの直し方

# 結論
`millis()`でのプリントを、`micros()/1000`でプリントに変更すると10ms毎に綺麗に表示される

# 背景
FreeRTOSで10msごとに6軸センサの読み取りを行っていたのですが、シリアルプリントすると時刻がたまにずれることがありました。
読み取りはFreeRTOSのタイマータスクで、imuTaskを10msごとに呼び出ししています。

```C++:main.cpp：setup内
handle = xTimerCreate("accel_10ms", (10 / portTICK_RATE_MS), pdTRUE, (void *)0, imuTask);
xTimerStart(handle, 0);
```

```C++:main.cpp : 呼び出される関数
void imuTask(void *pvParameters) {
    imu.read();
    snprintf(report, sizeof(report), "%d,%.3f,%.3f,%.3f,%.1f,%.1f,%.1f",
            millis(), -imu.a.x , imu.a.y , imu.a.z,
             -imu.g.y, imu.g.x, imu.g.z);
    Serial.println(report);
}
```


単位は時間[ms]。揺らしたりすると1msずれる。
```C++:実行結果
29630,-0.383,0.092,0.929,-3.5,-45.1,90.6
29640,-0.448,0.102,0.872,-20.9,-73.8,147.4
29649,-0.485,0.155,0.844,-45.2,-117.2,208.9
29659,-0.436,0.139,0.750,-68.3,-159.5,257.4
29669,-0.326,0.121,0.787,-90.2,-202.0,284.0
29679,0.242,0.198,1.159,-105.6,-201.8,286.7
29689,0.070,-0.094,0.892,-44.6,-136.4,286.7
29700,0.041,-0.059,0.945,5.9,-145.5,286.5
29710,0.099,-0.056,0.963,4.3,-138.6,268.9
29720,0.184,-0.140,0.933,-12.0,-123.3,230.2
```

snprintf内の`millis()`を`micros() / 1000`に変えると揺らしても10ms毎に表示されるようになりました。

```C++:実行結果
17770,0.512,0.185,1.100,176.0,-1.2,-208.5
17780,0.875,0.284,1.337,162.2,-6.1,-201.6
17790,0.716,0.167,0.799,130.1,-27.9,-177.5
17800,0.500,0.209,0.982,126.2,-22.9,-169.7
17810,0.496,0.238,0.996,122.4,-26.4,-176.5
17820,0.550,0.239,0.974,113.4,-28.2,-205.4
17830,0.501,0.303,0.989,110.0,-29.8,-196.9
17840,0.389,0.386,0.989,105.0,-36.4,-174.8
17850,0.393,0.388,0.984,99.5,-42.8,-149.7
17860,0.436,0.414,0.990,92.5,-46.0,-125.0
```
[翻訳]テクニカル・リードとシニア・エンジニアの違いについて

[Dvir Segalさんの記事](https://dev.to/dejavo/on-the-differences-between-being-a-tech-lead-and-a-senior-engineer-1j3f)を翻訳して読んだので備忘として残す

## テクニカル・リードとシニア・エンジニアの違い
当時、エントリーレベルのSWエンジニアだった私と同僚は、個人貢献者のキャリアパスについて興味を持っていた。答えるべき質問はたくさんあるが、頻繁に繰り返される質問もあった。その中には、「技術リーダーになることの意味は？自分が毎日使っている言語、フレームワーク、ドメインのすべてのビットやバイトに精通している経験豊富なチームメンバーであることと、どう違うのか？

シニアは職務上の役割で、テック・リードはチームでの役割だ。あるいは、シニアとは、設計、工数見積もり、コードレビューの実施、他の人の指導など、技術的な仕事をリードできるだけの専門知識を持つエンジニアのことだ。一方、テクニカル・リードは、技術的な決定やアプローチを担当するチーム内の人物で、ソフトウェア・アーキテクトのようなものだ。それに加えて、モチベーションの向上、キャリア指導、調整、計画といったマネジメント業務も行う。嗚呼、そしてあなたは同時に両方になることができる。

この2つのポジションを線引きするのはかなり難しい。両者は同じ資質を共有しているが、1つ大きく異なる点がある。シニアはそれらのスキルを発揮することが示唆されるのに対し、テック・リードはそれらを習得することが期待されるのだ。

以下の段落では、それぞれの役割の違いを強調するいくつかの主要な属性に焦点を当ててみようと思う。

## 専門知識
何を知っていて、それをどの程度知っているか。例えば、プログラミング言語を考えてみよう。先輩ならこう言うだろう：「と言うだろうが、技術リードの場合、期待されることは少し異なる：

- 問題を解決する最適な方法を素早く特定することができる。不具合修正であれ、コードレビューであれ、テックリードは即座に「Yを試すべきだ」と言うだろう。彼は、自分の豊富なドメイン経験、プロジェクトのタイムライン、チームメイトの熟練度（彼女の成長過程を考慮に入れて）に基づいて意見を述べる。
- 知っているだけでは十分ではない。どのように知識を得るかがより重要なのだ。よく考えた上で、適切な技術カンファレンスに参加し、見識のある本を読み、サイドプロジェクトをいくつか立ち上げ、ミートアップに参加し、自分に合ったメンターを見つけるようにする。そうすることで、コンセプトやプラットフォームなど、どんなものでも理解する能力を高め、自分の仕事をより良いものにすることができる。
- ソフトウェアエンジニアリングのトレンド（フレームワーク、プラットフォーム、コンセプト、言語など）に敏感であること。多様な情報源を読んだり、ポッドキャストを聞いたり、あるいは自分にとって適切なアプローチをすること。さらに、SWエンジニアリングのブログの1つにプロフィールを維持し、それらのトレンドに関する質問に答えることで、他の人を助けるだけでなく、自分の理解を広げることができます。あなたは他の人に教える専門家になり、それは学ぶための最良の方法として知られている。
- オンライン・オープンソース・リポジトリの作成。基本的に、言語Xを学ぶためには、サンプルプロジェクトを開発すること、たとえ簡単なHello-worldであっても、自分の手を汚すためだけに開発することは、多くのことを教えてくれるだろう。将来、他の人がコメントしたり、共有したり、貢献するかもしれない。
- 自分自身を前進させる。自分の知らないことを知り、そのギャップを埋めるにはどうしたらいいか、もっと理解するにはどうしたらいいか、毎日考える。
- 最後に、世界的に有名なエキスパートになることではなく、その分野で一流のペルソナを評価し、そのペルソナになるためのステップを踏むことだ。

私の経験では、テクニカル・リードは上記のチェックリストに該当する専門知識を少なくとも3つは持っているはずだ。

## 影響力
シニアとして、あなたの影響力は間違いなく不可欠です。様々な技術的な議論を通じて、また他のチームとのコラボレーションを通じて、あなたはチームメンバーに影響を与える。一方、技術リーダーにはその両方が求められ、顧客や隣接するグループ、組織のリーダーに影響を与えることが求められる。彼は、情報を共有するタイミングと、耳を貸すタイミングを心得ていなければならない。彼の日常的な仕事は、指導と主に傾聴（リーダーとして不可欠なスキル）によって、他者のスキルセットを向上させる手助けをすることだ。

## インパクト
あなたが提供する価値。例えば、あなたはある問題を発見し、それを解決するための解決策を考えることができる。自分で解決したかもしれないが、もっと根本的なことは、納得のいく完成に導くことだろう。また、誰も思いつかなかった新しい取り組みや、製品の品質を向上させる既存コードの大幅なリファクタリングが影響するかもしれない。それらの行動（およびそれ以上）は、大量のビジネス価値に変換される。

技術的な専門知識を主な焦点とし、その領域でトップクラスのソフトウェア・エンジニアとなり、その知識で知られるようになることはできるが、技術的なリーダーにはなれない。これら3つの領域のバランスを取ることが重要であり、それぞれの領域で成長できるようにするのは、貢献者個人の責任である。
UWSCRのchkimg

# chkimg

chkimgの実装はUWSCとは全く違うものになっています。

```php:chkimg定義
[ [X座標, Y座標, スコア], ] = chkimg(
    画像ファイルパス,
    スコア = 95,
    最大検索数 = 5,
    left = EMPTY,
    top = EMPTY,
    right = EMPTY,
    bottom = EMPTY
)
```

第一引数で探したい画像のパスを渡すところはUWSCと同じです。UWSCとは異なりjpgやpngファイルも指定できるようになりました。

第二引数の`スコア`は指定画像に対する一致率の下限で、一致率が指定値を上回る部分の座標のみを結果として返します。

第三引数の`最大検索数`が指定されている場合、見つかった数が指定値に達した時点で検索を打ち切ります。

残りは検索範囲の指定で省略(EMPTY)時はそれぞれ画面全体の左上X座標、左上Y座標、右下X座標、右下Y座標となります。

戻り値は座標情報の配列です。座標情報もまた配列で、`[X座標, Y座標, スコア]`が格納されています。一致した画像範囲の左上部分のX座標およびY座標、そしてスコアはその一致率を示します。

```php
for found in chkimg("hoge.png")
    print "x    : " + found[0]
    print "y    : " + found[1]
    print "score: " + found[2]
next
```

# saveimg

chkimgがjpgやpngに対応したように、saveimgで保存できるファイルフォーマットもbmp, jpgに加えてpngに対応しています。フォーマットは指定したファイルの拡張子に応じて変更されます。また第八引数でjpg画質やpng圧縮率を指定できるようになりました。この引数の初期値および有効数値はフォーマットにより異なります。

```php
// bmpで保存
// 第八引数は無視される
saveimg("hoge.bmp", id)

// jpgで保存
// 第八引数で画質を1-100の範囲で指定、高いほど高画質 (初期値: 95)
saveimg("hoge.jpg", id,,,,,, 100)

// pngで保存
// 第八引数で圧縮度合いを0-9で指定、高いほど圧縮されるが時間もかかる (初期値: 1)
saveimg("hoge.png", id,,,,,, 3)
```
【seleniumクラス】WebDriverについて



## はじめに
【seleniumクラス】WebDriverに関しての備忘録です。
初心者です😅
間違えてる部分が多々あると思います。
もし見つけた場合、ツッコミいただけると助かります🙇
<br>
## 🦁<INS>**結論**</INS>🦁

:::note info
押さえておくべき点
* WebDriverはウェブブラウザの操作を自動化するために使用。
* Pythonだけでなく、Java、C#、Rubyなども使える。
* Chromeだけでなく、Safari、edgeなど様々なブラウザに対応（それぞれの環境でテストできる。）
* エレメント操作（テキストボックス、ボタン、リンクなど）も可能。
* エレメントの読み込みを待つためにwait機能が付いている。
* 処理途中の画面をスクショすることができる。
* 様々なフレームワークと組み合わせ可能。
:::  
***


:::note warn
利用シーン
* 様々な自動化したいテストに最適（一連の動作を決めてイレギュラーなどがないかを確認する）
* スクレイピングなどの自動データ収集にも向いてる。
:::  
***


:::note alert
注意点
* ブラウザのバージョンによってはselenium対応可否がある。
* 各ドライバーの設定が必要。
:::  

***

## メソッド一覧
### <INS>**get(url)**

指定するウェブページを開く（よくURLを引数にして行う。）
```
driver.get("https://www.example.com")
```
***
### <INS>**find_element_by_id(id)**

指定するIDに要素を検索。
```
element = driver.find_element_by_id("element_id")
```
***

### <INS>**find_element_by_name(name)**

指定するname属性の要素を検索。
```
element = driver.find_element_by_name("element_name")
```
***

### <INS>**find_element_by_xpath(xpath)**

XPathに基づいて要素を検索。
```
element = driver.find_element_by_xpath("//div[@class='class_name']")
```
	1.	絶対パス: ドキュメントのルートから始まる完全なパス。例: /html/body/div
	2.	相対パス: 現在の要素からの相対的なパス。例: div/a
	3.	属性による検索: 特定の属性を持つ要素を検索。例: //a[@href='https://www.example.com']
	4.	部分一致: 属性値の一部に基づいて要素を検索。例: //a[contains(@href, 'example')]
	5.	複数条件: 複数の条件を組み合わせた検索。例: //div[@class='example' and @id='uniqueId']

様々な条件などを組み合わせて検索して指定することができる。

***

### <INS>**find_element_by_css_selector(selector)**

指定するCSSセレクタ要素を検索。
```
element = driver.find_element_by_css_selector(".class_name")
```
***

### <INS>**send_keys(value)**

指定する要素にテキストを入力。
例.テキストボックス（検索ボックス）に入力する。
```
input_element = driver.find_element_by_name("name")
input_element.send_keys("Test Text")
```
***

### <INS>**click()**

指定する要素をクリック。
```
button = driver.find_element_by_id("submit_button")
button.click()
```
***

### <INS>**clear()**

テキストフィールドの内容をクリア。
テキストボックスをクリアするなど
```
input_element.clear()
```
***

### <INS>**switch_to.alert**

アラートにフォーカスを移動し操作。
（小さな小窓が出てきたときにOKボタンを押すなど）
```
alert = driver.switch_to.alert
alert.accept()  # アラートを承認
```
***

### <INS>**quit()**

ブラウザを閉じてWebDriverセッションを終了。
```
driver.quit()
```
***
アドベントカレンダーを完走した感想

# はじめに
今年のカレンダーはとある会社のとあるチームで活動した1年間を振り返っていきます

## 登場人物

### ちいかわトミカさん：
先輩で頼りになる方。疲れたらちいかわトミカで遊んでいる？よくダジャレを言う。得意なダジャレは「今日言う共有事項はないです」

### ミュートさん：
先輩で頼りになる方。zoomを繋いでいる際、高確率でミュートのまま話す。よくシステムを自作している。

### かがやく筋肉さん：
筋肉ですべて解決してくれるチームの裏ボス的存在。

### 画面芸人さん：
zoomの画面でネタを仕込むのが得意。個人的にはドライブ映像がお気に入り。

### シャッツォさん：
ちいかわトミカさんに呼ばれているあだ名がシャッツォに似ているのでシャッツォにしました。
デスクにかわいいものを置きたいらしい。

# アドベントカレンダーを完走した感想

ミュートさん「頑張って記事書いてるけどテーマがつきた…」

私「ミュートさんは経験豊富なので何かしら書けるはずです！！」

ちいかわトミカさん「画面芸人さんは記事しっかり書いてますね」

画面芸人さん「これ思ったより時間溶けますね、読みやすさも考慮してもっとコンパクトにした方が良いかもしれないです」

かがやく筋肉さん「私はかんたんにまとめる感じで書いてます！」

---

今年のアドベントカレンダーはチームメンバーも参加しているためかお祭り感があって楽しかったです。
メンバー毎に記事のトピックが異なるので毎日チェックしていて刺激を受けました。

このようなイベントは、記事を書く習慣がなかった人が記事を書くようになるきっかけにもなったりするので今後も開催してほしいです。
(完走したら景品がもらえるのは魅力的です)



# おわりに
来年またお会いしましょう
【JavaScript】特定のコンテナーの中だけマウスストーカーを出現させたい

# はじめに
ページ全体に反映させるのではなく、特定の範囲内だけポインターデザインを変える方法を調べていました。今回はGSAPを使用し、マウスストーカーを作成しています。

# 問題
### ■ カーソル位置がズレる
.containerを基準に位置を取得するため、offsetXやoffsetYを使用したのですが……カーソルが範囲外に出るとマウスストーカーがあらぬ方向に吹っ飛び、思うように追従してくれません。
```html:index.html
<div class="wrapper">
    <div id="container" class="container">
     <!-- この中でのみマウスストーカーを動かしたい -->
		<div id="follower" class="follower"></div>
	</div>
</div>
```
```css:style.css
.wrapper {
	width: 100vw;
	height: 100vh;
	display: flex;
	justify-content: center;
	align-items: center;
}

.contaier{
	width: 400px;
	height: 400px;
}

.follower {
	height: 20px;
	width: 20px;
	border-radius: 50%;
	z-index: 100;
 	/* background: 任意の色; */
 }
```
```javascript:script.js
const el = document,
    follower = el.getElementById("follower"),
    pos = { x: 0, y: 0 };

// チラつき防止
let followerX = gsap.quickTo(follower, "x", { duration: 0.9 }),
    followerY = gsap.quickTo(follower, "y", { duration: 0.9 });

// 座標の取得
window.addEventListener("mousemove", (e) => {
    pos.x = e.offsetX;
	pos.y = e.offsetY;
});

gsap.ticker.add(function () {
	followerX(pos.x);
	followerY(pos.y);
});
```

# 解決方法
### ■ offsetの基準位置が変わっていた
とても分かりやすい例が[こちら](https://qiita.com/yukiB/items/31a9e9e600dfb1f34f76)の記事にありました。
カーソルが.container外にでたとき、カーソルの座標は.wrapperの左上を基準にした値になっていたのでした。

```javascript:script.js
const container = el.getElementById("container");

container.addEventListener("mousemove", (e) => {
    pos.x = e.offsetX;
	pos.y = e.offsetY;
});
```

# おわりに
そもそも実用的なシチュエーションがあるのかは不明なのですが、勉強になったのでまとめることにしました。

# 参考
- GSAP公式ドキュメント
https://gsap.com/
- EvoLab. マウスストーカー(GSAP)
https://evoworx.dev/lab/mouse-stalker-gsap/
- マウスイベントで取得されるカーソル座標パラメータの整理(offset, page, screen, client)
https://qiita.com/yukiB/items/31a9e9e600dfb1f34f76
ディスク容量に関するコマンド

# 問題：/varの空きディスク容量を調べよ。

~~~bash
$ df -h /var
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/xvda4       9.4G  1.7G  7.7G   19% /
~~~

ポイント：
-hオプションで単位を分かりやすくしている。
dfはディレクトリを指定しても、マウントされているファイルシステム（パーティション）ごとにしか表示されない。

# 問題：/varの使用ディスク容量を調べよ。

~~~bash
$ sudo du -sh /var
242M    /var
~~~

ポイント：
sudoで実行して、アクセス権がないフォルダがないようにしている。
-hオプションで単位を分かりやすくしている
-sオプションで合計のみを表示している。

# 問題：/var直下のディレクトリの使用ディスク容量を多い順に並べよ。

~~~bash
$ sudo du -d1 /var | sort -n -r
247244  /var
140660  /var/lib
90224   /var/cache
16336   /var/log
12      /var/spool
4       /var/tmp
0       /var/yp
0       /var/preserve
0       /var/opt
0       /var/nis
0       /var/local
0       /var/kerberos
0       /var/games
0       /var/ftp
0       /var/empty
0       /var/db
0       /var/crash
0       /var/adm
~~~

ポイント：
-d1オプションはディレクトリの一つ目の階層まで集計するという意味。
-hオプションは並べ替えがうまく行かなくなるので使用しない。
sortの-nオプションは数値順、-rは降順（大きい順）に並べ替えるという意味。

# 問題：/var配下の使用ディスク容量の多いファイル上位10個を表示せよ。
~~~bash
$ sudo du -b /var/* | sort -n | tac | head
140038755       /var/lib
118812763       /var/lib/rpm
92210525        /var/cache
90759519        /var/cache/dnf
29330297        /var/cache/dnf/rhel-9-appstream-rhui-rpms-8f1a568bacbcbf4a
29330130        /var/cache/dnf/rhel-9-appstream-rhui-rpms-8f1a568bacbcbf4a/repodata
17047884        /var/cache/dnf/rhel-9-baseos-rhui-rpms-0ae242d3c2853ed8
17047720        /var/cache/dnf/rhel-9-baseos-rhui-rpms-0ae242d3c2853ed8/repodata
16055985        /var/log
14085685        /var/lib/selinux
~~~
Qiitaの記事を一年間書き続けてみて

# はじめに
今年のカレンダーはとある会社のとあるチームで活動した1年間を振り返っていきます

# Qiitaの記事を一年間書き続けてみて
早いものでもう一年が経とうとしています。
当時はチームメンバーに後押しされて記事を書き始めましたが、いつの間にか習慣化していました。
そして今ではチームメンバーほぼ全員が記事を書いています。

記事を書き始めるきっかけや、それを続けられる原動力は人によって違うと思いますが、
私の場合は、

- 学んだことや気づいたことを整理する機会を作りたい
- 似たような作業をするときに参考にしたい
- 景品がほしかった

などです。

記事を書き続けることを経験してみて、きっかけとモチベーションが大事だなと感じました。


# おわりに
今年のアドベントカレンダーでチームメンバーが記事を書き始めたので、いつか皆でお揃いのシャツを着てみるのも面白そうです。
XD からページの一覧を抜き出す

自分用メモ。

仕様検討とかするときに XD の画面一覧がほしいことがある。

XD のグリッド表示画面で以下のスクリプトを実行し、ログ出力された文字列を
Google Spreadsheet に貼り付けることで手っ取り早く一覧を作ることができた。

DOM 構造に依存しており不安定な実装だが、今動けばヨシ

```javascript
const baseURL = location.href.replace('/grid', '/screen');
const ret = Array.from(document.querySelectorAll("li").values()).map(li => {
  const pageId = li.id;
  const ss = li.children[0].children[0].children[0].children[0].src;
  const title = li.children[0].children[1].children[0].innerHTML;
  return `${title}\t${baseURL}/${pageId}\t=IMAGE("${ss}", 1)`;
}).join("\n");
console.log(ret);
```
手っ取り早くWindowsでadbコマンドを利用できるようにする方法

```bat
winget install Google.PlatformTools
```

:::note warn
たまにシステムが古いとエラーになるので、Windows Updateの実施とかストアの更新とか追加コマンドが必要になる場合があるけど、エラーが出た場合の具体的な対処はよくわからん
とりあえずwingetのバージョンを上げておけばええんでないかな
https://forest.watch.impress.co.jp/docs/news/1535509.html
:::

```bat
C:\>winget install Google.PlatformTools
見つかりました Platform Tools [Google.PlatformTools] バージョン 34.0.5
このアプリケーションは所有者からライセンス供与されます。
Microsoft はサードパーティのパッケージに対して責任を負わず、ライセンスも付与しません。
インストーラーハッシュが正常に検証されました
アーカイブを展開しています...
アーカイブが正常に展開されました
パッケージのインストールを開始しています...
パス環境変数が変更されました; 新しい値を使用するにはシェルを再起動してください。
コマンド ライン エイリアスが追加されました: "adb"
コマンド ライン エイリアスが追加されました: "fastboot"
インストールが完了しました
C:\>
```
faster_whisper 実行時に、ある時期からruntime errorが出て動かなくなった。

### Google colaboratoryで音声テキスト化していたが、急にruntime errorで動かなくなった。

ロードしていたモジュール
```
!pip install faster_whisper
!pip install cupy-cuda110
```

#### 出力されたエラー
RuntimeError: Library libcublas.so.11 is not found or cannot be loaded

#### とりあえずの解決策
```
!pip install faster_whisper
#!pip install cupy-cuda110
!apt install libcublas11
```
C# SendKeysを使ったTipsまとめ

# はじめに

キーストロークをアプリケーションに送信する`SendKeys`のTipsです。

# チェックボックス、ラジオボタン

選択には`Enter`ではなく`スペースキー`を使う。

```cs
SendKeys.Send(" ");
```

# 複雑な入力

例) `Shift`を押しながら`TAB`キーを押したい場合、`+()` を組み合わせる。

`Shift` : `+` 
`Ctrl` : `^`
`Alt` : `%`

```cs
SendKeys.Send("+({TAB})"); // `Shift`を押しながら`TAB`
```

`a` を 10 回押す

```cs
{a 10} 
```

# DoEvent

キーストロークをアプリケーションに送信しても受け取ったことを確認できないので
DoEventを使った検証をされています。
タイマーで上手くいかなかった場合はこちらを試してみるのもありかと思いました。

https://qiita.com/sasio/items/edcbf6caa7d79daa66e6

# 参考ページ

https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.sendkeys.send?view=windowsdesktop-7.0

https://qiita.com/ari3/items/a2d695b7971751c5aa67