OmniAICreator/Qiita-1.07M huggingface dataset:
arXivとSlackAPIを利用して論文を定期通知してみた

# おはこん
おはこんばんにちはUniyaです
自身が興味のある分野に関しての論文は読むが，それ以外は調べることが億劫です．そこで毎日何かしらの自身があまり調べない論文テーマに目を通すため,
arXivから曜日別にテーマを指定し，そのテーマの論文をSlackへ定期的に流すプログラムを組んでみました．

この記事では，上記のプログラムの核となる下記の内容を紹介します．
- 論文取得
- Slackへ通知
- 定期実行

## 論文取得

```python
# 論文の取得
def get_arXive_paper(getArticleValue):
    url = "http://export.arxiv.org/api/query"
    payload = {
        "search_query": getArticleValue,
        "max_results": 3,
        "sortBy": "submittedDate",
        "sortOrder": "descending"
    }   
    response = requests.get(url, params=payload)
    return response.content.decode("utf-8")

# 検索する論文な内容をサーチ
for i in range(3):
    entry = random.choice(entries)
    title = entry.find("{http://www.w3.org/2005/Atom}title").text
    authors = [author.find("{http://www.w3.org/2005/Atom}name").text for author in entry.findall("{http://www.w3.org/2005/Atom}author")]
    summary = entry.find("{http://www.w3.org/2005/Atom}summary").text
    message = template.format(title, ", ".join(authors), summary)
```
### 解説
get_arXive_paper関数が引数として受け取るgetArticleValueを定義しています．引数には指定したカテゴリの論文が入っています． 

payloadではAPIに送信するパラメータを定義しています．max_resultsには、検索結果の最大件数を指定します．sortByには，ソート対象となる項目を指定します．sortOrderには、ソートの方向を指定します． 

そして，requestsモジュールを使ってAPIにアクセスし，レスポンスを取得しています．getメソッドにより，URLとパラメータを渡してリクエストを送信し，その結果をresponse変数に格納しています. 

最後に，取得したレスポンスの内容をUTF-8文字列に変換して、呼び出し元に返しています。

## Slackへ通知
```python
client = WebClient(token=Slack_BOT_APIKey)
try:
    response = client.chat_postMessage(
    channel="#テスト",
    text=message
    )
    print("Message sent: ", message)
    except SlackApiError as e:
        print("Error sending message: {}".format(e))
```
### 解説
SlackAPIを用意し，WebClientを作成します．
try文で，任意のチャンネルへchat_postMessageメソッドを使用してメッセージを送信してます．


## 定期実行
```python
def task():
    print("hogehoge")

if __name__ == "__main__":
    schedule.every().day.at("7:00").do(task)
    while True:
        schedule.run_pending()
        time.sleep(1)
```
### 解説
schedule.every()で定期実行するための関数を登録しています．また指定する時間もここで示しておきます． 
schedule.ran_pending()で登録したジョブを実行します．do()内で実行させたい関数を指定しましょう．またこのままでは一回しか実行されないため，無限ループを用いてschedul.run_pending()を呼び出しています．より詳しいscheduleライブラリの利用は参考文献にリンクがあります．

### 課題
今回arXivから論文取得を取得し定期的にSlackの方へ通知するプログラムを作成しました．しかし，本プログラムでは実行シェルを閉じると，プログラムが停止してしまします．これを改善するために，サーバー上で実行するなどの必要があります．そういった点も改善できれば本記事に追記していこうと考えてます．
最後までご高覧くださりありがとうございます．




### 参考文献
- [arXiv APIを用いて論文取得](https://ai-research-collection.com/arxiv-api-tutorial/#toc2)
- [SlackAPI及び任意のチャンネルにボット作成](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message)
- [Python Scheduleライブラリでジョブ実行](https://qiita.com/Kai-Suzuki/items/0c5c0e5cbdb4075fe482)

### 全体コード
今回作成したコードは以下のリポジトリにて公開しています．
コードの全体が見たい方は以下のリンクからアクセスをお願いします
[Githubへのリンク](https://github.com/keigo194547/articleBot)
大規模の読む - 分散データベース

データベースは、様々な使用状況に応じて大量の読み込みが必要な場合があります。そのため、最適化が必要です。私は最近、分散データベースの最適化に取り組んでおり、その技術と説明について説明します。

## インデックス

### ローカルインデックス

分散データベースは大体二通りあて、ローカルインデックスとグローバルインデックス。ローカルインデックスは普通のデータベースによく似って、最後の結果は複数のノードの結果を重合させてから出きます。下の図のように、このクエリは三つのノードから詮索しなければ完全な結果は出ていない。

![local-index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267120/dbc3ed2d-baba-d6ab-5fa6-2696337917cb.png)

### グローバルインデックス

グローバルインデックスの分散データベースはこの状況ではもっと複雑なので、効率はより高いかもしれない。下の図のように、このクエリと`(r4, r5)` が居るノードは全く関係ない。こんな無関係なノードが多い時、グローバルインデックスのパフォーマンスのメリットがある。

![global-index.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267120/7f277263-ad30-18e1-b972-c5f66f742e51.png)

点線のボックスの中には Table Lookup と呼ばれる。グローバルインデックスの利点はインデックスの Key は連続し、ほぼ同じノードにあて、読むことは速いので、この Table Lookup はパフォーマンスの損があるかもしれない、原因は三つ

- Table Lookup の Key は連続ではないの状況は通常ので、Engine の Scan は遅い、RocksDB の場合、Seek のコストは Next より高いです。
- 図のデータベースのノード実は分散データベースのシャード、Table Lookup に関わるシャードの数量が多いの場合、もし強一貫性は必要ならば、オーバーヘッドが多くなる（Raft にとっては Read Index のオーバーヘッド）。
- Table Lookup のバランスは時々悪い、つまり、一つのノードが渋滞する時もある、クラスターの資源があるだが、Table Lookup の性能が悪い。

その中で、二つ目および三番目のは最適化することは可能です。

## 一貫性の利点

一貫性の意味は一つのスナップショットを読んだ `index` と `row` は一対一の関係で、上の例で、`i100->r0->value0` と `i150->r2->value2` の関係です。この利点のおかげで、Table Lookup のサイズはリクエストを送信する前に既に知られています。小さいな Table Lookup リクエストが多い時、実行するプロセスが多くなることができる。

## バッチ処理

Table Lookup を最適化するために、一つの手法はバッチ処理であり、リモートのシャードのデータを読み取るために RPC が必要です。ただし、この RPC のエンコードとデコードのオーバーヘッドは大きく、処理速度に影響を与えます。

![non-batch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267120/a6143e51-44ff-d690-1286-d0dd78a89f2e.png)

図の中で、レプリカがあるデータベースのシャードには、リーダーレプリカシャードとフォロワーレプリカシャードがあります。緑色のシャードがリーダーで、黄色のシャードがフォロワーです。Table Lookup 以外の説明は図の中で省略します。

![batch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267120/a7a9e9ae-0bdb-b3ee-7105-eab001996870.png)

図の中でバッチ処理であり、RPC コンテキストを節約することが出る。`r1->value1` と `r3->value3` を例にとり、二つの RPC を実行する必要があったものを、ひとつの RPC で解決できるようになりました。ご指摘ありがとうございます。`r5`を含むシャードがリーダーではないため、リトライが必要であることを示しています。

筆者はここまで実行することができました。もうひとつの最適化は、RocksDB のスナップショットをバッチのリクエストで共有することです。これにより、パフォーマンスがさらに向上するでしょう。

## Replica Read

通常、最新のデータを取得するには、クエリはリーダーで実行されます。しかし、一部のクエリはバランスが悪いため、すべてのクエリがリーダーで実行されると、そのリーダーのリソース使用率が高くなり、他のノードのリソースは使用できなくなります。この状況をユーザーが見た場合、「クラスターの資源はまだ残っているが、なぜクエリが遅いのか」という質問に困惑することになります。レプリカリードという機能は、昔に近いレプリカのデータを読み込むことで、リモートリードの遅延やトラフィックを避けることができます。

この文章では、レプリカリードを使用して最新のデータにアクセスするために、コンセンサスアルゴリズムをサポートする方法を略します。簡単に言えば、フォローノードから最新のデータを読むためには、コミットとアプライインデックスを確認する必要があります。Raftには「Read Index」というものがありますが、リーダーが忙しい場合、フォロワーでのRead Indexの性能がより高くなります。

![load-based-replica-read.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/267120/6b8dcd7d-2b91-ee3e-39bf-7a884150dc35.png)

レプリカリードを利用するには、ノードが自分の読み込むタスクのキューイング時間を見積もり（[ewma](https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average) 時間）、クエリの待ち時間があまりにも長い場合（`ewma > busy threshold`）、ノードが直接 "busy" を返信して、クライアントがリトライします。リトライ時には、ewma が最も低いノードを選択します。

この設計の巧妙なところは、1 つのノードで複数のリーダーシャードが存在し、そのリーダーシャードのフォロワーの分散が広いことです。例えば、10 ノードのクラスターであれば、1 つのノードが忙しい場合でも、最適な状況では 9 つのノードからサポートを受けることができます。
人狼Onlineにおけるトリップのつけ方

# 前提
トリップについて詳しくは以下の記事でどうぞ。

https://qiita.com/KiwamiTrip/items/863baf9e82064603c22d

# 本題
やっぱりみんなOnline民ならトリップつけて村に入りたいよねっ！
ってことでトリップのつけ方教えちゃいます。

### 1.村を見つける
まずは入りたい村を見つけてロックオンします
![2023-03-22 22.07.57 zinro.net 4a9b35aea3f2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294101/ea8adf88-6433-875b-aae4-5cb7f15ee4ce.png)
![2023-03-22 22.08.05 zinro.net 4a57aefdd8d4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294101/59c472e8-556c-8c9e-a4f3-133a611b8bbb.png)

### 2.名前欄に名前とトリップキーを書く
画像の通りです。なお、人狼Onlineは特殊な仕様のためトリップキーは**半角10文字以上**[^1]である必要があります。
10桁トリップ（別記事で書く予定）については9、10文字目は無視してよいので、`aa`などを適当に着けて10文字にしましょう。
![2023-03-22 22.08.34 zinro.net 7d63ddc053e5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294101/589ec8a0-aad5-7934-ca03-f277c4e3f2b5.png)

### 3.村に入ってトリップがついているか確認する
「村に入る」ボタンを押し、入村出来たらプレイヤーリストの自分の名前のところをクリック/タップしてトリップがついているか確認しましょう。
![2023-03-22 22.09.36 zinro.net fde46409f438.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294101/15b6d58b-ad42-c35c-377f-eb8d21b481da.png)
**大成功！！**

# まとめ（雑）
トリップは`名前#半角10文字のトリップキー`でつけることができます。
皆さんもよい人狼ライフをっ！


[^1]:細かく言えばUTF-8における10byteなのですが、まあ半角10文字でもトリップにならないことはないのでいいでしょう。うん！
AWS Certified Solutions Architect - Professional (SAP-C02) に合格しました


# はじめに
2023/2/5、AWS Solutions Architect - Professional (SAP-C02)にギリギリながら合格しました。
試験の勉強方法と感想について記します。
SAPはすでに多くの体験記がありますが、新版試験(SAP-02)の情報はまだ少ないので、少しでも参考になれば幸いです。

# 前提条件
- 2年前にAssociateの3資格(SAA, DVA, SOA)は取得しています。
- AWSの実務経験としては3年ほどあります。ただし、メインは開発のため、インフラ業務は週に1日未満です。

# 勉強方法
## 期間と時間
期間としては約3ヶ月、集中して勉強したのは最後の1週間です。
総勉強としては 20〜30時間くらいだと思います。

## 学習教材
- [AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル](https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86-AWS%E8%AA%8D%E5%AE%9A%E3%82%BD%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%88-%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB-%E5%B1%B1%E4%B8%8B%E5%85%89%E6%B4%8B/dp/4815609063) ※
- WEB問題集 TechStock (https://techstock.jp)


※ 書籍はSPA-C01向けのものです。2023/2/11現在、SAP-C02に対応した参考書/問題集はありません。



## 学習の進め方
### 試験1週間前まで
書籍巻末の模擬試験を除いた部分までを1周読みました。
各章の演習問題は2周(2周目は間違ったところだけ)解いています。
ここまでは、特に試験を受ける日も決めておらず、ダラダラと進めていました。

### 試験1週間前から
ここから一気に詰め込みました。
流れとしては、以下の通り。
1. 書籍巻末の模擬試験
2. TechStock
3. 試験対象のサービス確認
4. 書籍の読み直し

#### 1. 書籍巻末の模擬試験
巻末についている模擬試験をやりました。
時間を計ったりはせず、1問ずつ答えを確認しながら解いていきました。
この時点での正解率は6割です。

#### 2. TechStock
Udemyの模擬試験もありますが、1問1答形式にできないためTechStockを選びました。
隙間時間で少しずつ進められるのでオススメです。

後の問題の方が新しいので、後ろから12×7=84問解いて行きました。(#74〜#63)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/33fe1c6c-ced5-cd20-19db-a45c1d932846.png)
※ TechStockは7問ずつで問題が区切りられています。
※ 成績良く見えますが、復習すると不正解数0で更新されるため、実際に6〜7割程度の正答率です。

#### 3. 試験対象のサービス確認
試験ガイドの付録(P15〜)で試験対象となるサービス一覧がまとめられています。
見て知らないサービスがあったら、検索して概要を確認します。
しばらく置いて、再確認を数回繰り返しました。
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Exam-Guide_C02.pdf

#### 4. 書籍の読み直し
ある程度、TechStockをやって問題の傾向が見えたところで、書籍を読み直します。
パラパラと気になった所だけ確認していきました。時間としては1時間ほどです。

ここまでやって勉強不足感はあったのですが、一度腕試しに受験してみることにしました。

# 受験体験
普段は自宅オンライン受験を利用していますが、今回は180分の長丁場ということもあり、集中できるテストセンター受験を選択しました。

予定の30分前に受付しましたが、すぐに開始することができました。
トイレ休憩については特に説明はありませんでした。出来るところもあるようなので気になる人は確認しておくと良いかと思います。

時間はギリギリで、見直す余裕は全くありませんでした。
10問毎に目標時間を決めて、スピードを調整しながら解いていきました。

# 試験結果
以前は試験結果がすぐに出ていましたが、最大5営業日かかるようになったようです。
今回は受験後3時間ほどで結果が届きました。

スコアは以下の通り、ギリギリ合格。
受験中は正直ダメかと思っていたので、結果が届いた時にはかなり驚きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/ee7e50a6-3e41-034a-968c-6dd121c9b058.png)

傾向としては組織周りのスコアが低く、「改善が必要」となっていました。
あまり興味な・・・苦手な部分でしたので、納得の結果です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3294382/57622248-6ee7-7d58-96f7-d3f3996242c8.png)

# 感想
基本的にはSAP-C01向けの教材で勉強したため、新バージョンの試験に対応できるのか不安もありましたが、既存の教材で十分に対応できました。対象サービスが増えたくらいで、試験傾向の変更は無いようです。

一番の難関だったのは試験時間でした。これといった対策をせずに挑んだため、「もう少し考える時間があれば解けるのに...」という問題も多かったです。
迷った時は早めに切り上げる、解らない問題はすぐに切り捨てる、といった判断の速さが重要になってきます。

# 最後に
AWS最難関とも言われる資格だけあって難易度は高めですが、ベンダー資格は基本的に「自社製品を使ってもらうための資格」なので、国家試験のように意地悪な引っ掛けはありませんし、しっかり勉強すれば必ず取れます。
評価の高い資格でもあるので、AWSを業務で使っている方や興味のある方はぜひチャレンジしてみてください。
非同期並列実行版 map 関数（Python）

こんにちは。
非同期並列実行版 ```map```関数を、```asyncio``` を利用して作りました（下記ソース内の ```map_async```）。

##### 動作確認
最大並列数（```limit```）を 2 へ指定し、実行時間が 1/2 となることを確かめました。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54617/5a3bcc13-94ec-2a69-e7c4-1f9ac1224c6d.gif)

##### ソース
```test_asyncio.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import asyncio

def map_async(func, data, limit):
	loop = asyncio.get_event_loop()
	async def run_all():	
		sem = asyncio.Semaphore(limit)
		async def run_each(d):
			async with sem:
				return await loop.run_in_executor(None, func, d)
		return await asyncio.gather(*[run_each(d) for d in data])
	return loop.run_until_complete(run_all())  # list

def map_async_test(data, limit):
	def func_blocking(x):
		import time
		print(x)
		time.sleep(x)
		return x
	
	print(map_async(func_blocking, data, limit))

# synchronous
# def map_sync_test(data):
# 	print(list(map(func_blocking, data)))

def main():
	import argparse
	parser = argparse.ArgumentParser()
	parser.add_argument('--limit', type=int, default=2)
	parser.add_argument('data', type=float, nargs='*')
	args = parser.parse_args()
	map_async_test(args.data, args.limit)

if __name__ == '__main__':
	main()
```
アイデアのつくり方

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3121130/7b509281-fafa-a4aa-01b5-398b8e9233f5.png)

## はじめに

本稿は表題の通り、アイデアのつくり方に焦点を当てた内容となっています。
内容は米大手広告マンであるJames Young氏の名著 [A Technique for Producing Ideas](https://www.amazon.co.jp/Technique-Producing-Advertising-Classics-Library-ebook/dp/B004ISL4E6/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=1679116647&sr=8-1)が元になっており、60ページと短い本文のさらに要点だけを抽出しました。
さて、アイデアを作り出す技術を身につけるためには**アイデアの原理**と**その方法**を学ぶ必要があると書かれています。
## アイデアが生まれる原理
アイデアはたった2つの原理から成り立ちます。
- アイデアとは既存の要素の組み合わせである。
- 組み合わせて新しいものを作り出す才能は、事物の関連性を見出そうとする心の働きに依存することが大きい。

つまり、**事実と事実の間の関連性を探ろうという習性**が重要です。
## アイデアを作る方法を理解
アイデアは5つの段階を経過して作られます。その各段階は関連しているので一定の順序で進むことで、先行する段階を完了するまで次の段階に進まないことが大切です。
つまり下記の1が完了して初めて2に進むことができます。
**1. 材料収集**
アイデアは既存の要素の組み合わせなので、材料を収集すればするほど新しい組み合わせを作ることができる可能性も高くなる。
**2. 材料の消化**
収集した材料を組み合わせ、そこから関係性を見出そうと努力してみる。
**3. 孵化**
アイデアを作ることを完全に放棄し、音楽や映画など自分の想像力や感情を刺激するものに心を移す。無意識の心が勝手に材料を組み合わせるように任せる。
**4. アイデアの誕生**
アイデアは、アイデアを探し求める心の緊張を解き、休息とくつろぎのひと時を過ごした後に必ずやってくる。
**5. アイデアの検証と発展**
生まれたアイデアが現実世界に適合するのか検証する必要がある。アイデアに手を加えて現実世界に適合させようとして、理解のある人たちに批判を仰いでもらうと良いアイデアは自ら発展する。


## 終わりに
簡潔な内容でしたが継続して思考（試行）することは難しいですね。。
個人的には日常のルーティンだけがアウトプットを生み出すことができると思うので、いかに継続してこれらの思考作業をすることができるかにかかってるのかなという所感です。
**継続は力なりですね**
## 紹介のあった書籍
[思考の技術](https://www.amazon.co.jp/%E6%80%9D%E8%80%83%E3%81%AE%E6%8A%80%E6%B3%95-%E3%81%A1%E3%81%8F%E3%81%BE%E5%AD%A6%E8%8A%B8%E6%96%87%E5%BA%AB-Graham-Wallas/dp/4480099778)
[科学と方法](https://www.amazon.co.jp/%E7%A7%91%E5%AD%A6%E3%81%A8%E6%96%B9%E6%B3%95%E2%80%95%E6%94%B9%E8%A8%B3-%E5%B2%A9%E6%B3%A2%E6%96%87%E5%BA%AB-%E9%9D%92-902-2-%E3%83%9D%E3%82%A2%E3%83%B3%E3%82%AB%E3%83%AC/dp/4003390229/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2BKEXSKSUH8AS&keywords=%E7%A7%91%E5%AD%A6%E3%81%A8%E6%96%B9%E6%B3%95&qid=1679489127&s=books&sprefix=%E7%A7%91%E5%AD%A6%E3%81%A8%E6%96%B9%E6%B3%95%2Cstripbooks%2C176&sr=1-3)
科学的研究の技術・ビーバリッジ著(リンクなし)
ニコ動のコメント関連API ざっくり解説【nvapi】

## はじめに

この記事ではニコニコ動画の各動画に投稿されたコメントを取得したり、ログインユーザーとして動画コメントを投稿するなど、ニコニコのAPI利用について説明しています。

この記事ではニコニコサービスの**本来は非公開とされるAPI**を紹介しています。

あなたが何かツールを作ろうという時は、必ず**Httpヘッダーのユーザーエージェントにあなた自身の連絡先（メールアドレスなりツイッターIDなり）を記載すること**を推奨します。

ニコニコのサーバー及びサービス運営に対し負荷が掛からないように注意してアプリ・ツールを開発、提供しましょう。

## コメント関連のAPIの全体観

* コメントの取得
  * owner/main/easy の３系統を選択的に取得できます（系統は「Fork」と表現される）
  * owner -> 投稿者コメント、動画投稿者が専用ページで編集したコメント
  * main -> 通常コメント
  * easy -> 「[かんたんコメント](https://dic.nicovideo.jp/a/%E3%81%8B%E3%82%93%E3%81%9F%E3%82%93%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88)」で投稿されたコメント
  * 詳細条件を指定したコメント取得方法は不明
* コメントの投稿
  * 系統ごとに投稿APIが分かれている
  * 投稿には操作キーが要求され、系統ごとに操作キーの取得APIも分かれている
  * 投稿APIはPOSTで送信（操作キーはGet）
* コメントの削除
  * 自ら投稿したコメントを削除できる
  * APIへのパラメータでコメント番号と系統を指定する
  * 削除APIはPUTで送信（操作キーはGet）

この記事では触れていませんが、以下のコメント機能も操作できるかもしれません。

* コメントを「ニコる」
* 投稿者コメントの編集

### コメント取得の流れ

* 動画情報ページにアクセスして initial-watch-data が示すJSONから nvComment を取得する。
* https://**nvcomment**.nicovideo.jp/v1/threads に nvComment のデータをPOSTしてコメント取得完了。

C#+.Netでの実装例は以下から見れます

https://github.com/tor4kichi/NiconicoToolkit/blob/7aafcb49e6c4000804a746a18e55c79d8269fd14/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Get.cs#L28

実装例を実際に使う単体テストはこちら

https://github.com/tor4kichi/NiconicoToolkit/blob/7aafcb49e6c4000804a746a18e55c79d8269fd14/Test/NiconicoToolkit.Shared.Test/VideoWatchTest.cs#L157


### コメント投稿の流れ

* 動画データを取得（コメント取得時と同様）
* （UI上でコメント本文とコメントコマンドを受け取る）
* PostKeyを取得
* コメント投稿APIにスレッドID、動画ID、コメント本文、コメントコマンド、動画時間（マイクロ秒単位）を指定して POST で送信する

以下が実装例です

https://github.com/tor4kichi/NiconicoToolkit/blob/7aafcb49e6c4000804a746a18e55c79d8269fd14/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Post.cs#L28

なお、コメント投稿にはHttpヘッダーの指定とアカウントのログイン処理が必要になるので適宜実装してください。

↓がヘッダーの指定の実装例

https://github.com/tor4kichi/NiconicoToolkit/blob/5c50867a9da210dcae113f71e8a34fa1261e7a3b/NiconicoToolkit.Shared/NiconicoContext.Core.cs#L146

↓こちらがニコニコへのログインの実装例

https://github.com/tor4kichi/NiconicoToolkit/blob/master/NiconicoToolkit.Shared/Account/AccountClient.cs

### かんたんコメントの投稿

通常コメントと流れは一緒ですが、APIのURLなどが一部異なります。

実装例はこちら

https://github.com/tor4kichi/NiconicoToolkit/blob/7aafcb49e6c4000804a746a18e55c79d8269fd14/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Post.cs#L74

### 自ら投稿したコメントの削除

コメント投稿と似た流れで削除も行えます。

1. （投稿と同様にヘッダーの指定とログイン処理）
1. 削除キーの取得
2. 動画ID、スレッドキー、コメント番号、系統（Fork）、削除キーを指定して **PUT** でリクエストを送る

以下が実装例です

https://github.com/tor4kichi/NiconicoToolkit/blob/7aafcb49e6c4000804a746a18e55c79d8269fd14/NiconicoToolkit.Shared/Video/Watch/NV_Comment/NvCommentSubClient.Delete.cs#L28


## その他

.Net 向けのニコニコ動画、生放送のAPIラッパーライブラリ

https://www.nuget.org/packages/NiconicoToolkit
クラス・メソッド・変数などの良い名前の付け方

## はじめに
こんにちは！新人エンジニアのふかこうです！
今回はクラス・メソッド・変数などの良い名前の付け方ついての記事になります。
## この記事の対象者
・初級エンジニア
・エンジニアとして働きたい方
・IT企業に就職する学生
## 筆者のレベル
・新人エンジニア
## 良い名前の基準とは
・誰が見てもどのようなクラスなのか、どのようなメソッドなのかわかるか
・その機能が正しく理解されて、設計されていること
## 悪い名前の付け方
・理解ができない
・読みにくい
・勘違いされやすい
## まとめ
クラスやメソッドに名前をつける際は機能や命名規則に従って正しく、わかりやすいものにしましょう。
誰が見ても、どのような処理が書かれているかわかるような名前の付け方をするなど工夫していきましょう！
技術選定サイトを作ってみて気づいた3つのこと


今回個人で運営しているサービスのアップデートを行いました。

https://flamevalue.hatenablog.com/

その際に加えた「ツール比較機能」を眺めていく中で気づいたことがいくつかあったので共有してみる試みです。



## 流行りには乗っておけ!

https://flamevalue.hatenablog.com/


VueとReactとAngularを比べた際、Angularが頭ひとつ抜けて価値が下がっているように見えました。
Angular自体の初版は2016年でReactの2013年より古いのですが、AngularJsの初版は2009年でAngularの方が古いです。
そうでなくても、Reactは後発のvueに追い抜かれつつあります。

純粋に比べることもできないのですが、**新しい技術についていける方が年収が上がる傾向があると思います**

そして、この傾向はフロントエンドに近づくほど強いです。

他の例

- Typescript vs Javascript

https://flamevalue.hatenablog.com/


## 知名度がないよりある方がいい

https://flamevalue.hatenablog.com/

MySQLとPostgreSQLを比較すると、全体的にMySQLの方が良い条件で提示されています。

これは求人を出す側の都合ですが、マイナーな技術を求めるよりはメジャーな技術を要求するケースが多いと思います。





## 同じ類のツールは皆同じ条件


JavaとC言語を比べたのですが、形状が大まかに似ています。

https://flamevalue.hatenablog.com/

これはApacheとNginxを比べてもそうでした。

https://flamevalue.hatenablog.com/

現状のデータをなんとなく眺めると、同じ類の技術スタックは似たような条件になる可能性が高いです。

逆に言えば、**現状の条件を大きく変えたい場合は、今の技術スタックを大きく変える必要がある**ということです。
ChatGPTに聞きます

**ChatGPTに聞きます。**

Q：

Javaでの例外処理において、try-catchブロックは何をしますか？

A：

Javaでの例外処理において、try-catchブロックは、例外が発生する可能性があるコードのブロックを定義し、例外が発生した場合にそれをキャッチして適切に処理するための仕組みを提供します。

具体的には、tryブロックには例外が発生する可能性のあるコードを記述し、catchブロックには特定の例外をキャッチしてそれに応じた処理を記述します。例外が発生しなかった場合、catchブロックは実行されません。

また、複数のcatchブロックを定義することができ、それぞれのブロックで異なる例外をキャッチして異なる処理を行うことができます。さらに、finallyブロックを使用して、例外の有無にかかわらず必ず実行される処理を定義することもできます。

try-catchブロックは、Javaのプログラムで例外処理を実現するための重要な仕組みであり、プログラムの安定性や可読性を高めることができます。
npm install時に「npm audit」の警告が出るとき


npm installでmicromodalJSをインストールしようとしたら以下のようなセキュリティ警告が表示されました。

![error2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/204b9467-496f-33bf-8e8a-c68f7ebfcc50.png)

参考記事

https://itneko.com/npm-audit-fix/

# 原因

脆弱性の高いライブラリのバーションを使うと警告がでるようです。

# 対処

まずセキュリティ警告のあるライブラリの確認をします。

```
npm audit
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/ade1764b-45f6-64eb-fa2e-cf4e248f0142.png)

node_modules/webpakに問題があるようです。

解決のためのコマンド
警告に従ってコマンドを打ちます。
```
npm audit fix
```

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/5dc0fd06-3aa3-fe09-6973-75e73362e06a.png)

無事に対処できたようです。

# 確認

npm installをもう一度実行してみます。

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/312f64eb-f358-1f71-c821-d76951e37540.png)

package.jsonも確認します。
23行目に追記されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784589/f5270f28-cd69-7dac-4230-4e5e0c5a5987.png)

無事に解決できました。
GeocitiesにあったWMI(WQL)のVBSのサンプルコードの場所

# 古い情報
特にSCSIの扱い方があり、古いPCで対応する場合に必要と思われる。
このジオシティーズのリンク先を4年ほど探していたが、ついに見つけた
VBS for Windows Management Instrumentation
`http://www.geocities.jp/maru3128/wmi.html`
[WebArchive](https://web.archive.org/web/20190314215338/http://www.geocities.jp:80/maru3128/)の下にあったWMIのページ。[WebArchive](https://web.archive.org/web/20181010033516/http://www.geocities.jp/maru3128/wmi.html)
ここは
http://sakura.qp.land.to/
から
https://github.com/sakura-editor
に移行しているがWMIのサンプルは初見では存在がわからない。

# とはいうもののなんのことかわからない
時間がないので、リンクだけ。

## VBSについて
[初心者でも簡単プログラムでWindowsの効率化！VBScriptをやってみよう](https://tonari-it.com/vbs-beginners/)
といっても現在ではこの説明に、「メモ帳で保存するときにASCII形式を指定する（デフォルトがUTF-8に変わっているため）」というのが必要。

## WQLについてわかりやすい
[メモリ・CPUなどハードウェアの構成情報を，バッチで取得しよう　（WSH/JScriptでWMIを使う方法） - 主に言語とシステム開発に関して](https://language-and-engineering.hatenablog.jp/entry/20100906/p1)

## 本家本元は分かりづらい
[WMI の実装](https://learn.microsoft.com/ja-jp/windows-hardware/drivers/kernel/implementing-wmi)
サンプルがないのでわけがわからない。
【SwiftUI】WidgetにURL画像を表示する

# はじめに
WidgetでURLの画像を表示したかったのですが、非同期処理はできないらしく`AsyncImage`を使うことができませんでした。
別の方法でURL画像を表示することができたので記録しておきます。

# 実装
```swift
if let url = URL(string: "https://sample.com/sample.png"),
   let imageData = try? Data(contentsOf: url),
   let uiImage = UIImage(data: imageData) {
    Image(uiImage: uiImage).resizable()
} else {
    Image("placeholder")
}
```

# おわり
Widgetはちょっとクセがあって難しいです。。
[学習メモ]エンジニア探検隊#1 -APIを作ってみる-

# 第一話　はじめての開発　
  - 著者:[takaryo1010](https://github.com/takaryo1010)
  - 協力者:[fukuchy](https://github.com/fukuchy)
  - ここでは、私と、協力者の学習のためのメモを残していきます。ほかの人の学習の助けになれば幸いです。
  - 作るもの：ゲームの結果をデータベース上に保存したい
  - 使用言語：`Python`
  - 必要ナレッジ
      - APIについて
      - requestsあたりについて
      - json形式について
 ## やったこと
### 1. 簡単なAPIを作ってみる
- 使用モジュール　`flask`
- 実際に書いたコード
```api.py
from flask import Flask, jsonify,request
import csv
app = Flask(__name__)

@app.route('/echo', methods=["GET","POST"])
def echo():
    if request.method == "GET":

        return jsonify({'message': "hello"}) 
    
    elif request.method == "POST":
        
        user = request.json["user"]
        date = request.json["date"]
        subject = request.json["subject"]
    #CSVに保存
        # with open("datebase.csv") as f:
        #     writer = csv.writer(f)
        #     writer.writerow([user,date,subject])
    
    with open("database.csv", mode = "w") as file:
        string = user+","+date+","+subject
        file.write(string)
    return jsonify({'user': user, 'date': date,"subject":subject})  
...


if __name__ == "__main__":
    app.run(host='127.0.0.1', port=8888, debug=True)
```

###   メモ（つまったところ）
- おそらく、この`...`は必須。`@app`はdefの上に置く。これらによって一つの関数が決定されている。
    - 複数関数を作りたい場合は、`/echo`のところをほかのものに変更する。
```api（抜粋）.py
@app.route('/echo', methods=["GET","POST"])
def echo():
"～～～～～～～～～～～～～～～"
    return jsonify({'user': user, 'date': date,"subject":subject})  
...
```
  
 - `curl`コマンドを使えば簡単にGETやPOSTができるらしいが、うまくいかなかったのでPythonの`requests`モジュールを利用して投げた。
 - 以下そのコード（POST用）
 ```request.py
import requests

POST_URL = "http://127.0.0.1:8888/echo"

name = input("name:")
date = input("date:")
sub = input("sebject:")

request_body = {"user":name,"date":date,"subject":sub}

res = requests.post(POST_URL,json=request_body)
#res = requests.get(POST_URL)
print("--------------------")
print(res.text)
print("--------------------")

```
- 出力結果
    - `flask`の方のコードを起動しながらリクエスト用のコードを実行。
    - 出力はjson形式で帰ってくるようにした。
```
入力
name:takaryo
date:2023/03/22
sebject:math


出力結果
--------------------
{
  "date": "2023/03/22",
  "subject": "math",
  "user": "takaryo"
}

--------------------
```

## 感想
- flaskについての知識はかなり浅いが、とりあえずjson形式で返せるようなAPIを作れた。
- 次はデータベースを実際に立ててみて、APIを通じてデータの保存、抽出ができるようにしたい。
- `curl`コマンドがうまくいかなかったけど、とりあえず`Python`で動く形になったからよしっ！(よくない)
- `json`の知識が浅いのでそのあたりの理解を深める。
Azureには ChatGPT用の DSLが用意されていた

実際に使ったわけではないのですが、情報をみかけたのでメモです。
(少し試すだけなら、ほぼお金はかからなそうではありますが。。)

Azure では OpenAI の AI　モデルを利用できる Azure OpenAI Services を提供しています。

OpenAI Services 関連のドキュメント(日本語)が結構公開されているようで、その中に ChatGPT 用の DSL のドキュメントがありました。

https://learn.microsoft.com/ja-jp/azure/cognitive-services/openai/how-to/chatgpt

あまりこの辺よく知らなかったのですが、
> チャット マークアップ言語 (ChatML) と呼ばれる一意のプロンプト形式を必要とします。

ChatGPT にプロンプトを与えるために ChatML　という言語を使用するんですね。

ページ中のコードの部分の prompt という引数に ChatML で記述した内容を書いて渡すようになっています。
```python
response = openai.Completion.create(
  engine="gpt-35-turbo",
  prompt="
system\nAssistant is a large language model trained by OpenAI.\n
\n
user\nWhat's the difference between garbanzo beans and chickpeas?\n
\n
assistant\n",
  temperature=0,
  max_tokens=500,
  top_p=0.5,
  stop=["
"])
```

ChatGPT の Web インターフェイスで与えていたのとほぼ同じ内容を利用できるようですが、サービスとして面白いなと思ったのは、下記の Azure のサービスからデータを与えたりできるところです。
> モデルが認識する必要があるデータの量が多い場合は、埋め込み、または Azure Cognitive Search などの製品を使用して、クエリ時に最も関連性の高い情報を取得できます。

でもまあ、触ってみないとよくわかんないですねぇ。。
触れる機会があったら実行結果とか追記します。
memo

gatsby
merukari web
edge computing


## 不要なタグを出力しないフラグメント
```
  <React.Fragment>
    <div>
```

 または
```
import { Fragment } from "react"

  <Fragment>
    <div>
```

## JSXとは

reactによるjavascriptの構文を拡張したもの
 JSXはJSのオブジェクトに変換される

```
<h1>hello world</h1>
```
↓
babelにより変換
↓
javascript オブジェクトに※react要素とも呼ばれる
【Rails7】rspecにおける環境変数のスタブについて【object ENV】

## スタブするのにどの方法がよかったのか

筆者の場合、どのやり方でスタブできたのかをメモ代わりに残します。

### 各種詳細

MacBook Pro (13インチ, M1, 2020)を使用。

```console:Railsプロジェクト
% ruby -v
ruby 3.2.1
% rails -v
Rails 7.0.4.2
```

```ruby:Gemfile
group :development, :test do
  gem 'debug', platforms: %i[mri mingw x64_mingw]
  gem 'factory_bot_rails'
  gem 'pry-byebug'
  gem 'pry-rails'
  gem 'rspec-rails'
end
```

### allowメソッドを使用した方法

rspecにはモック（依存コンポーネントの置き換え）を行うのにブロック渡しを行ってくれる `allow()` メソッドが用意されているそうです。

ですがこちらの参考リンクでは、

https://github.com/rspec/rspec-rails/issues/1279#issuecomment-70275896

英語になりますが、まずそもそもとして、Rails上において `ENV` を参照（keyにしてもvalueにしても）する際に返す値はstringである。

それを `allow(ENV).to receive(:[]).with('some_key').and_return('some_value')` によってスタブする時は、デフォルトのkey値として空のHashを返すことを期待している（投稿者いわく "you've stubbed it to return a blank hash as the default key"）ため、あまり良いプラクティスではない、という議論がされています。

### RubyのENVとは

`ENV` はRails上に存在するものではなく、どうやらRubyの組み込みライブラリだそうです。

https://docs.ruby-lang.org/ja/latest/class/ENV.html

上記については、このページにもはっきりと記載があります。

> 環境変数を表すオブジェクト。Hash と同様のインターフェースを持ちます。ただし、Hash と異なり、ENV のキーと値には文字列しかとることができません。

### ヘルパーモジュールの作成

先程の英語の議論に戻ると、書き込まれた方がとても良さそうなサンプルコードを残されていましたので、私もそれをそのまま使いました。感謝 :pray:

```ruby:設定ファイル内に記述
module EnvHelpers
  def with_env_vars(vars)
    original = ENV.to_hash
    vars.each { |k, v| ENV[k] = v }

    begin
      yield
    ensure
      ENV.replace(original)
    end
  end
end

RSpec.configure do |c|
  c.include EnvHelpers
end
```

今回は環境変数の管理に `dotenv-rails` を使用していますが、おそらくはプロジェクトを起動するタイミングで、gemがRubyのENVに仕込みを行っているのでしょうね。

上記ヘルパーメソッドは、その組み込みライブラリである `ENV` を書き換えているのでしょう。

丁寧に調べたことで知見が積み重なったので嬉しいです。

### ちなみに

そもそもとして `allow()` は、私の場合ではスタブに成功しませんでした。RubyにしてもRailsにしても、以前のバージョンではrspec側の制御でどうにかなっていたのかもしれないです。

### 参考サイト

有名な記事かと思いますが、Githubリンクにしてもこちらに掲載されていました。

https://qiita.com/vivid_muimui/items/5e0bc229a688afefbce2

`allow()` についてはこちら。

https://moneyforward-dev.jp/entry/2022/12/15/rspec-test-tips/
Pythonでさめがめを作った

![samegame.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62130/4f7ad6bd-bd1c-a983-6de1-abcda3c8f7f6.png)

pythonの勉強としてゲーム作ってみようということでpygameを使って簡単に作ってみた。音とか点数計算はできません。また詰んで進めなくなっても終了判定されない雑な作りです。
プログラミングも才能無いけどとりあえず手を動かしていく。


## コード
```samegame.py
#!/usr/bin/env python

import random
import math
from functools import reduce
import pygame
from pygame.locals import *

length = 600
height = 400
ballSize = 20
vBallNum = int(height/(2*ballSize))
hBallNum = int(length/(2*ballSize))

WHITE = (255,255,255)
RED   = (255,0,0)
YELLOW = (255,255,0)
GREEN = (0, 128,0)
BLUE  = (0, 0, 255)
CYAN  = (0,255,255)
BLACK = (0,0,0)

balls = [RED, YELLOW, GREEN, BLUE, CYAN]

screen = pygame.display.set_mode((length,height))

board = [[random.choice(balls) for y in range(vBallNum)] for x in range(hBallNum)]

def drawBalls(bd):
    for x, cs in enumerate(bd):
        for y, c in enumerate(cs):
            pygame.draw.circle(screen,c,(ballSize*(2*x+1), ballSize*((vBallNum - y - 1)*2+1)),ballSize-1)
    return 0

def pickBall(ps,bd):
    print(*ps)
    for p in ps:
        if isValidPos(p,bd): del bd[p[0]][p[1]]
    align(bd)
    return None

def align(bd):        
    for x in reversed([x for x, c in enumerate(bd) if len(c) == 0]):
        del bd[x]
    return None

def selectBall(p):
    x = math.floor(p[0]/(2*ballSize))
    y = vBallNum - 1 - math.floor(p[1]/(2*ballSize))
    return (x,y)

def isValidPos(p, bd):
    if p == None:            return False
    if p[0] < 0 or p[1] < 0: return False
    if len(bd) == 0:         return False
    try:
        bd[p[0]][p[1]]
    except IndexError:  return False
    else:               return True

def markBall(bd,pos):
    if not isValidPos(pos,bd): return []
    ball = bd[pos[0]][pos[1]]
    def marking(p,stck):
        if not isValidPos(p,bd): return stck
        if p in stck:            return stck
        if ball == bd[p[0]][p[1]]:
            stck.append(p)
            return reduce(lambda stk, xy: marking(xy,stk),[(p[0],p[1]+1),(p[0],p[1]-1),(p[0]+1,p[1]),(p[0]-1,p[1])],stck)
        return stck
    return marking(pos,[])

pygame.init()

while True:
    screen.fill(BLACK)
    drawBalls(board)
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == MOUSEBUTTONDOWN and event.button == 1:
            print(event.pos)
            ms = markBall(board,selectBall(event.pos))
            if len(ms) > 1: 
                ms.sort(reverse=True)
                print(ms)
                pickBall(ms,board)
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
```
MySQLのレプリケーション

■mysql生データ
/usr/local/mysql/data

 ■slow log query 
 sudo ls /var/lib/mysql
合計 28696
 -rw-rw----  1 mysql mysql  5242880  9月 18 11:02 2014 ib_logfile0
 -rw-rw----  1 mysql mysql 18874368  9月 18 11:02 2014 ibdata1            ←innodbのデータファイル
 drwxr-xr-x  5 mysql mysql     4096  9月 18 11:02 2014 .
 -rw-rw----  1 mysql mysql      183  9月 18 11:02 2014 mysql-slow.log     ←スローログクエリ
srwxrwxrwx  1 mysql mysql        0  9月 18 11:02 2014 mysql.sock
 -rw-rw----  1 mysql mysql  5242880  9月 18 11:02 2014 ib_logfile1
 drwx------  2 mysql mysql     4096  9月 18 11:02 2014 mysql
 drwx------  2 mysql mysql     4096  9月 18 11:02 2014 performance_schema
 drwx------  2 mysql mysql     4096  9月 18 11:02 2014 test
 drwxr-xr-x 18 root  root      4096  9月 18 10:47 2014 ..

mysqldumpslow -s t mysql-slow.log


■レプリケーション設定手順
・構成内容
書き込み（マスタ）、読み込み（スレーブ）構成

■レプリケーションユーザの作成
・マスタ側設定
192.168.23.0/24内のネットワークで許可する場合
ユーザ名:repl
パスワード：slavepass
mysql > GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.23.0/255.255.255.0' IDENTIFIED BY 'slavepass’;

■マスタ設定
vim /etc/my.cnf

[mysqld]
log-bin=mysql-bin
server-id=1001

※設定後mysqldの再起動
※server-idはint整数値ならOKだがid1,2はデフォルト値とバッティングするので使用しない

■スレーブ設定
[mysqld]
server-id=1002
※mysql設定後は再起動

■マスタデータベースでのmysqldumpによるデータのダンプ
操作の開始前にすべてのDBデータ更新cronなどを停止する

mysql > FLUSH TABLES WITH READ LOCK; 
mysql > SHOW MASTER STATUS;

テーブルをロックした状態で、File（バイナリログ名）とPosition（ファイル内の現在位置）の値をメモしておく

mysql > SHOW MASTER STATUS;
+---------------------------+----------+--------------+------------------+
| File                                     | Position      | Binlog_Do_DB     | Binlog_Ignore_DB |
+---------------------------+----------+--------------+------------------+
| example-replication.000002       |       98       |                       |                  |
+---------------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

※バイナリロギングを行っていなかった場合はEmptyが返るので、Fileは空文字、Positionは4となる

mysqldump -u ユーザ名 -p --all-databases --lock-all-tables > mysqldump.db
※必ずテーブルロック中にやる

mysql > UNLOCK TABLES;

■スレーブの設定
mysql -u ユーザ名 -p < mysqldump.db
ダンプデータからDBを復元する

マスタサーバー情報を設定する
mysql > CHANGE MASTER TO
           MASTER_HOST='example',
           MASTER_USER='repl',
           MASTER_PASSWORD='slavepass',
           MASTER_LOG_FILE='example-replication.000002',
           MASTER_LOG_POS=98;

■レプリケーションの開始
mysql > START SLAVE;
前回に引き続きプリザンターのメール送信APIをPower Autmate(カスタムコネクタ)で自動化してみた

# はじめに

[前回の記事](https://qiita.com/teppei12345/items/7b70bedf79c6ff6c681c)でプリザンターのレコード更新APIをPower Automateで自動化してみました。今回はカスタムコネクタを使って前回の機能を再度実現しながら、更新されたレコードに対してTeamsで通知を送るという機能を自動化していきたいと思います。なお、前回の記事に記載した内容やキャプチャは今回の記事では割愛いたします。

# カスタムコネクタとは・・・？

コネクタとは、他サービスとの連携機能のことです。コネクタを利用することでサービス同士を連携させてより便利にツールを利用することができます。しかし、コネクタが用意されていないサービスとの連携はできません。そこで、カスタムコネクタが登場します。カスタムコネクタとは、コネクタが用意されていないサービスも連携することができるものになります。なお、カスタムコネクタの設定方法は参考資料を参照してください。

# 設定

[前回の記事](https://qiita.com/teppei12345/items/7b70bedf79c6ff6c681c)に下記を付け加えます。  
・レコードが更新される際、更新対象レコードをTeamsに通知

# フローの全体像
 #### 「自動更新」がオフのレコードの「状況」を完了に更新する処理
「items Get」で「状況」が200(=実施中)、かつ「完了」が前日以前、かつ「自動更新」がオフのレコード情報を取得します。「Apply to each」で該当レコードの「状況」を完了に更新します。そののち、「Apply to each 5」によってレスポンスから取得した「タイトル」と該当レコードのURLを通知します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/f7981723-4cbc-82b6-e66c-54f92036a0ae.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/e9d2771b-18d0-f382-91ed-8e99ba8c7e20.png)
 #### 通知結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/fde75959-6cd2-9fd2-156c-da24c135b46a.png)

 #### 「自動更新」がオンのレコードの「完了」を1か月後に更新する処理
「items Get 2」で「状況」が200(=実施中)、かつ「完了」が前日以前、かつ「自動更新」がオンのレコード情報を取得します。「Apply to each 2」で該当レコードの「完了」を1か月後に更新します。そして、「Apply to each 6」によってレスポンスから取得した「タイトル」と該当レコードのURLを通知します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/b4dde6cf-19c6-2f99-c2c3-0ba6992b31a8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/7408f69b-4237-91e5-71ef-29c3436acb0f.png)
 #### 通知結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659914/5efa58b7-a207-9240-5217-571a2efb68fb.png)

# 最後に
この記事では、[前回の記事](https://qiita.com/teppei12345/items/7b70bedf79c6ff6c681c)をベースに追加した箇所を説明しました。少し内容が薄いため理解することは難しいかもしれません。詳しくは[前回の記事](https://qiita.com/teppei12345/items/7b70bedf79c6ff6c681c)を参照してください。また、今回の記事ではTeamsで通知を送りましたが、メールでも通知を送ることは可能です。やり方としては、[前回の記事](https://qiita.com/teppei12345/items/7b70bedf79c6ff6c681c)と同様のやり方で[メール送信API](https://pleasanter.org/manual/api-mail)のJSONを記述していくとメールが送信されます。お試しください。

# 参考資料

https://qiita.com/pierusan2010/items/52576be2091a6d3fda6e
Flutter でSimulator かどうか判定する

今までは、　`device_info_plus` を使って、判定していたんだけど、非同期なのが気に食わなかった。

https://pub.dev/packages/device_info_plus


## 解決策

Simulator 判定には、`kReleaseMode` という定数を使うと良い。

`kReleaseMode == false` なら Simulator です。


詳しくは、

https://api.flutter.dev/flutter/foundation/kReleaseMode-constant.html


https://crieit.net/posts/Flutter-debug-release
Ubuntu 22.04にNode.jsを複数インストールして切り替える方法（nvm）

# はじめに

Vue.jsやReact.jsなどのJavaScriptのフレームワークや、AWSのAmplifyなどを使うときに、Node.jsの環境が必要になることも多いと思います。

この記事では、私がUbuntu 22.04 Serverの環境に、nvmを使って複数のバージョンのNode.jsをインストールし、使用するバージョンに切り替える方法を調べたので、備忘録のために記事として作成します。

# nvmをダウンロード

```bash
git clone https://github.com/creationix/nvm.git ~/.nvm
```

# nvmのパスを有効化

.bash_profileや.bashrc等（環境に合わせて）を編集し、下記を最終行に追記します。
※Ubuntu 22.04の場合は、.bashrcに追記します。

```bash
if [ -s ~/.nvm/nvm.sh ]; then
  source ~/.nvm/nvm.sh
fi
```

追記したら、手動で

```bash
source ~/.nvm/nvm.sh
```

を実行するか、SSH等から一度ログアウトして、ログアウトしなおすと、nvmを使える状態になります。

# インストール可能なバージョンを確認

```bash
nvm ls-remote
```

あるいは、LTS（Long Term Support）を使う場合は、

```bash
nvm ls-remote --lts
```

を実行し、インストール可能なバージョンを表示し、インストールするバージョンを決定します。

# Node.jsをインストール

ここでは、本記事執筆時点において、LTSで最新の `v18.15.0`をインストールします。

```bash
nvm install v18.15.0
```

# 使用するバージョンに切り替える

複数のバージョンをインストールした環境で、これから使用するバージョンに切り替えるには、

```bash
nvm use v18.15.0
```

のように実行することで、切り替えることができます。

次に、

```bash
node -v
```

を実行して、指定したバージョンに切り替わったことを確認します。
C#でVisual Studio 2022でステップ数を計算する

# 1. はじめに
* JavaでEclipseを使用していたようにStepCounterのようにステップ数を計算したい
* 外部ツールではなくVisual Studio 2022上で簡単に表示したい

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

# 3. ステップ数の計算
* [分析] > [コードメトリックスを計算する] > [ソリューション用]を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/a45f0892-cdff-de39-7319-fbb556a4810d.png)

* コードメトリックスの結果の一番右（実行可能コードの行）に表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/350507f3-a3af-df59-04e5-8102fde8a927.png)

# 4. コードメトリックスの見方
## 4.1. 保守容易性指数
コードの保守の相対的な容易さを表す 0 から 100 の範囲の指数値を計算します。 値が大きいほど、保守容易性が向上する
* 0-9 = 赤
* 10-19 = 黄色
* 20-100 = 緑

https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2022

## 4.2. サイクロマティック複雑度
* コードの構造的な複雑さを測定する
* 値が20を超えると複雑度が高い傾向にある

https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-cyclomatic-complexity?view=vs-2022


## 4.3. 継承の深さ
* 基底クラスまでたどって、相互に継承される異なるクラスの数を示す

https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-depth-of-inheritance?view=vs-2022

## 4.4. クラス結合
* クラス結合は 1 つのクラスで使用されているクラスの数を測定している

https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-class-coupling?view=vs-2022

## 4.5. ソースコードの行
* ソース ファイルに存在するソース コード行の正確な数を示す (空白行を含む)。

## 4.6. 実行可能コードの行数
* 実行可能コードの行数または操作数の概数を示す(ステップ数とほぼイコール）

# 5. 参考文献

https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-values?view=vs-2022

https://qiita.com/okazuki/items/11b76524545835e0cf03
Salesforceのキャンペーンについて解説してみた【初級編】

こんにちは。本橋孝昭です

今回はSalesforceの「キャンペーン」や「キャンペーンメンバー」について解説します

SalesforceのキャンペーンはSalesforce認定アドミニストレーター試験の内容でも問われている内容であり、初歩的な内容のようですね

＞リード自動化ツールとキャンペーンマネジメントの機能を説明できる。(例：リード、リードの取引の開始、リード割り当てルール、キャンペーン、キャンペーンメンバー）

※SALESFORCE 認定アドミニストレーター
https://quip.com/5FXlAAIRTrqo

今回はその「キャンペーン」について解説します

今回の内容は動画でも解説しています

https://www.youtube.com/watch?v=RMe4LCyY7GQ


※ほかのキャンペーンの記事はこちら

https://qiita.com/Takaa/items/dde95c248a31bf84c2fa


<iframe width="560" height="315" src="https://www.youtube.com/embed/RMe4LCyY7GQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## キャンペーンって何？

そもそも「キャンペーン」という言葉とはどういう意味でしょうか

三省堂 大辞林によれば
大衆に対する　一定目的をもった、各種組織的な運動や働きかけ
のようです

つまり、
よく東京ビッグサイトなどで行われる商品PRなどの展示会について、皆さんよく見たことがあると思います

あのようなイメージですね

Salesforce用語に置き換えれば
キャンペーンというデータを作り見込み客であるリードを獲得
という感じでしょうか


作成したキャンペーンに紐づくリードや商談作成されると、そのキャンペーンがどれくらいの商談が作成されたか　などが分析できるので、実際にキャンペーンでの成果を確認することが可能です


## Salesforceキャンペーンで出来ること

Salesforceキャンペーンでできることは大きく３つです

### 1.キャンペーンそのものの管理
例えば展示会を開催するごとにキャンペーンレコードを作成すれば、過去にどれくらいのキャンペーンがあったか確認することが可能です
キャンペーンオブジェクトに標準項目で開始日や終了日があるので毎年どれくらいのキャンペーンが開催されたか分析可能です

### 2.キャンペーンメンバーの管理
展示会などが終わった後に展示会でもらった名刺をリードに登録するかと思います。その際にリードとキャンペーンを紐づけることにより、どのリードがどののキャンペーンに参加していたか履歴を取ることが可能です
お客様に提案する場合、どのキャンペーンに参加しているか分かると顧客の興味が把握できますね

### ３.キャンペーン効果測定
キャンペーンにリードを紐づけておくと獲得リード数が分かります
また、リードから取引開始した後に商談件数や成立商談金額などがキャンペーンで記録されます

## キャンペーンメンバーとは

キャンペーンに参加した顧客を管理するオブジェクトです
キャンペーンに参加した人を管理するオブジェクトなのでリードや取引先責任者をキャンペーンメンバーに追加することが可能です
Dateクラスの使い方

#### Dateクラスの読み込みについて

- 日付を扱うためには、Dateクラスというものを用いる。

```ruby
equire "date"
#dateクラスの読み込み
```
#### Dateクラスのインスタンスについて
- Date.newとすることでインスタンスを生成することができる。

```ruby
equire "date"

date1 = Date.new(2023,03,22)
                  #年、月、日
puts date1
```
表示
```
2023-03-22
```
#### Dateクラスのインスタンスメソッドについて
- Dateクラスのインスタンスの日付が、「日曜日かどうか」を真偽値で返すsunday?メソッド。
```ruby
equire "date"

date1 = Date.new(2023,03,22)
                  
puts date1.sunday?
            #↑インスタンスメソッド
```

#### クラスメソッドの処理について
- 例)今日の日付が日曜日の場合にはtrueを返し、そうでない場合にはfalseを返す、という処理

```ruby
class Menu

  def Menu.is_discount_day?

  today = Date.today
   #↑今日の日付を持つ、インスタンス
  end

end

```
Uipath Orchestratorのアセットの種類について

# アセットについて
使用可能な共有の変数または資格情報をになります。
管理できる情報は以下の4つのパターンになります。
- Text
- Bool
- Integer
- Credential

# Text
文字列のみ格納します
引用符（ 「' '」「" "」）は不要です。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/1f9303ae-6967-b341-dbe0-1feb6d9e3296.png)

# Bool
True または False の値を格納します。
アセット登録画面で、TrueかFalseを選択することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/a94b89e2-ce12-e24a-ccda-ac5a3fb1bf94.png)

# Integer
整数値を格納します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/10fdd39b-2e6e-1d56-a205-0af6a509d35c.png)

# Credential
ログインが必要なプロセスを実行する際にロボットが必要なユーザー名とパスワードを格納できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/d528fafb-bd1d-8b74-b33f-3d146e73e150.png)

Credentialのアセットを取得する際は、「資格情報を取得」のアクティビティを使用する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/478c890e-fcb3-f8d4-1a69-2b352fc199e4.png)

パスワードの格納先の変数もSecureStringに格納する必要があります。詳細は[公式リファレンス](https://docs.uipath.com/activities/lang-ja/docs/get-robot-credential)をご確認ください
C#のユーザーコントロールにカスタムイベントを追加する

# 1. はじめに
* C#で作成したユーザーコントロールを使用する側でイベントを定義したい
* そのため、ユーザーコントロールにカスタムイベントを作成したい

# 2. 開発環境
* C#
* .NET 6
* Visual Studio 2022
* Windows 11

# 3. ユーザーコントロールの作成
## 3.1. ユーザーコントロールの追加
* プロジェクトを右クリックして[追加] > [ユーザーコントロール]を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/9a728aa2-80ed-8e36-251b-eab6b7b8d108.png)

* 任意のファイル名を入力した追加ボタンをクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/82127026-a6ab-4a25-2c41-1dfb5a40a0f6.png)

## 3.2. ユーザーコントロールの作成
* 仮にツールボックスからボタンを配置する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/fb57a333-ebcb-5424-478a-a3161c61096b.png)

* ボタンコントロールをダブルクリックする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/59256689-e84b-60ab-07b9-13c78b6bd9c7.png)

* カスタムイベントを追加する
```csharp
public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    // デリゲート設定
    public delegate void Button1ClickEventHandler();
    // Button1クリック時のイベント作成
    public event Button1ClickEventHandler Button1ClickEvent;

    /// <summary>
    /// Button1クリック時
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        Button1ClickEvent?.Invoke();
    }
}
```

## 3.3. ツールボックスへの反映
* 作成したユーザーコントロールをツールボックスに反映するため、[ビルド] > [ソリューションのリビルド]を選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/3abd9a50-28fa-9f2c-9f58-53b94aec4df8.png)

# 4. ユーザーコントロールの使用
* フォームに作成したユーザコントロールを配置する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/9e907791-44b8-9e3d-b93d-b25eda4bdb70.png)

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/2c36fa43-d6b1-cff0-1733-593010667603.png)

* 配置したカスタムコントロールのイベントプロパティにカスタムイベントが追加されたことを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/36afd211-2aae-103a-b2b0-061813703008.png)

* フォームでカスタムイベントにコードを記載する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/8b15afa2-a466-229a-952d-4e331b55bf3c.png)

# 5. 動作確認
* フォームで記述したコードが動作したことを確認した
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/506226a6-3770-32a1-9db9-83d1deed702c.png)

# 6. 参考文献

https://blog.enjoitech.com/article/142
window.openを使って、URL非表示で開く(制約あり)

友達に言われて、こんな感じの実装もありじゃね？という感じのノリで書いている記事です。

## 制約
この実装を使う場合、以下の制約を守らないと上手く動かないと思います。

 - 開くページに遷移がないこと（リンクを踏んで別のページに移動しないこと）
 - 開くページが同じドメイン内であるか、クロスオリジンOKなこと
 - 同じHTTPS/HTTPプロトコルで通信していること

## 実装
```html
URL非表示のページを開くテスト

<button id='btn'>開く</button>

<script>
// 開くボタンが押されたら
document.getElementById('btn').onclick = () => {
  fetch('/supersecret.html', {method: 'GET'})
    .then(data => data.text())
    .then(res => {

        // ウィンドウを作成する
        let w = window.open('','_blank', 'popup=1');

        // 初期状態としてHTMLを直接挿入
        w.document.body.innerHTML = res


        // ページがリロードされた時のハンドラー
        const resetHandler = () => {
          w.addEventListener('beforeunload', () => {

            // もしリロードされたら、0.1秒待ってHTMLを挿入しハンドラーをリセットする
            setTimeout(() => {
              try{
                w.document.body.innerHTML = res;
              } catch(err){
                // クロスオリジンでエラー(URLバーが直接編集されたような場合)は、windowを閉じる
                w.close();
              }
              resetHandler();
            }, 100);
            
          });
        }

        resetHandler();
    })
}

</script>
```

デモ：https://165cmtallboy.github.io/secret-window/

## 解説
fetchで生のHTMLを直接取得し、そのデータをwindow.body.innerHTMLを通して直接ウィンドウに書き込んでいます。
ページ自体を読み込ませているさせているわけではないので、ブラウザ上のURLバーにはURLが表示されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1281879/237ebfc4-4c3a-4822-0d26-cba5b07417e6.png)


## サンプルコード

https://github.com/165cmtallboy/secret-window

そのままWebサーバに置けば動きます

## 注意
ウェブ触ったことある人なら瞬殺でURL取られると思います。
絶対に他の人にURLを渡されたくない、ワンタイムなページを提供したい場合は
リンクに識別のためのパラメータをつけておいて、一度使われたパラメータには２度と見せないとかサーバー側の実装をしないと行けないと思います。

```text
GET: /secretpage?token=929829503201

一度アクセスがあったトークン(929829503201)には403 Forbiddenを返す。みたいな
```
vim操作で重宝するコマンド5選

## はじめに

- `ZZ`コマンドを布教したかっただけの記事です。
- `vi`および`vim`で使用できるコマンド5つを紹介しています。

## 終了(ファイルを閉じる)

- 一般的に、保存して終了するのは`:wq`だが、`ZZ`の方が早い。
- `ZZ`はファイル内に変更があれば保存して終了する。変更がなければ、何もせず終了する。（`:q!`と同じ動き）

### 注意点
- 変更したけどやっぱりやめたい時に`ZZ`を使ってしまうと変更が保存されてしまう。なので、上書きせずに終了したい場合は`:q!`を使う。

## 切り取り・コピー・貼り付け

- [公式](https://docs.oracle.com/cd/E19253-01/816-3946/editorvi-tbl-83/index.html)には`dd`は行削除だが、クリップボードに保存されているので、実質切り取り。
  - 切り取りたい行の先頭にカーソルを合わせること。
- コピーは`yy`。
  - コピーしたい行の先頭にカーソルを合わせること。
- 貼り付けは`P`コマンド（※大文字）を使う。
  - 貼り付けたい行の先頭にカーソルを合わせること。
  - `p`コマンド（※小文字）でも貼り付けは可能ですが、貼り付け位置に注意が必要。

### `p`コマンド（※小文字）を使用する場合の注意点

- 貼り付けしたい位置に注意。以下のように行が並んでいる場合に、`bbb`の直下の空白行(3行目)にカーソルを合わせたまま`p`コマンドを叩くと、4行目に貼り付けされてしまう。

```vim
1 aaa
2 bbb
3 
4
```

- 3行目に貼り付けたい場合は、2行目の先頭行にカーソルを合わせること。


## ファイル内に行番号を表示させる

```vim
:set nu
```

行番号を非表示にしたいときは以下を叩く。

```vim
:set nonu
```

## おまけ
- ファイル内検索も便利
  - 検索したい文字列を`str`とする。
  - `/str` 下方向検索
  - `?str` 上方向検索
- 部分一致。正規表現も使える。

以上
Uipathで業務上よく使う日付の取得（年度の取得/対象曜日の日付取得/月末日の取得）

# 年度の取得
対象の日付から月から-3か月した時の年が年度になります。
　**取得年度 = 対象日.AddMonths(-3).Year**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/9d231fbc-bb3a-d210-be4a-dea2d8901500.png)

# 対象曜日の日付取得
DayOfWeekを活用することで、曜日から日付を取得することが可能です。
**今週月曜.AddDays( DayOfWeek.Monday – 今日日付.dayofweek )**
求めたい曜日によって、Mondayの部分を変更してください
- 月→Monday
- 火→Tuesday
- 水→Wednesday
- 木→Thursday
- 金→Friday
- 土→Saturday
- 日→Sunday
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/b9ed906b-2b27-b572-eae8-d5a11838b734.png)
DayOfWeekで日付がなぜ取得できるのかの詳細は[Microsoft公式リファレンス](https://learn.microsoft.com/ja-jp/dotnet/api/system.dayofweek?view=net-7.0)を確認してください

# 月初日,月末日の取得
**DaysinMonth**を使用することで月末日の取得が可能です。
**DateTime.DaysinMonth(年,月).ToString**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/0f5d0e1f-99a0-00cc-2d26-861b322ce4ad.png)
日付形式で出力されるわけではなく下記スクリーンショットのように、日付だけで出力されるので、注意が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206537/d33e882e-3cea-f075-fbae-c3a597e3b835.png)
ChatGPTに聞きます

**ChatGPTに聞きます。**

![6mMfkmBJhzTeFUzqrRoA8J4KaAY2/f5oqPj9RG1U7tUXQ.jpg](https://firebasestorage.googleapis.com:443/v0/b/type-c1c71.appspot.com/o/6mMfkmBJhzTeFUzqrRoA8J4KaAY2%2Ff5oqPj9RG1U7tUXQ.jpg?alt=media&token=b1cb6e48-d34b-4ccf-9299-7ca0ac893635)
![6mMfkmBJhzTeFUzqrRoA8J4KaAY2/fT3zaEYK0pnRYloM.jpg](https://firebasestorage.googleapis.com:443/v0/b/type-c1c71.appspot.com/o/6mMfkmBJhzTeFUzqrRoA8J4KaAY2%2FfT3zaEYK0pnRYloM.jpg?alt=media&token=0656bd22-322b-4e92-a65e-ea72ae3d46b6)
Go言語のブランクimport(_ "パッケージ名")とは？

### はじめに
他の人が書いたコードの中には`_ "パッケージ名"`という構文があってよくわからなかったので調べてみた。

### ブランクimportって？
ブランクインポート（_ "パッケージ名"）は、Golangで特定のパッケージをインポートする際に使用される特殊な構文です。ブランクインポートは、パッケージ内のすべての宣言を無視し、パッケージの初期化のみを実行します。これは、パッケージが初期化関数（**init関数**）やサイドエフェクトを持っている場合に役立ちます。

Golangでは、通常のインポートとブランクインポートの2種類のインポート構文があります。
```go
// 通常のインポート
import "fmt"
// ブランクインポート
import _ "github.com/lib/pq"
```
通常のインポートでは、インポートされたパッケージの公開された（エクスポートされた）名前（大文字で始まる名前）が、現在のパッケージ内で使用できるようになります。これにより、パッケージ内の関数、変数、型などを利用することができます。

ブランクインポートの場合、アンダースコア（_）がインポートとして使用され、インポートされたパッケージの名前が指定されます。この構文により、インポートされたパッケージのすべての宣言が無視され、パッケージ内の初期化関数（**init()関数**）のみが実行されます。

**init()関数**は、パッケージがインポートされたときに自動的に実行される特殊な関数です。パッケージ内に複数の**init()関数**がある場合、それらは宣言順に実行されます。ブランクインポートは、**init()関数**を実行してパッケージ内のグローバルな状態やサービスを初期化することが主な目的です。

例えば、以下のような状況でブランクインポートが役立ちます。

- パッケージがプラグインやドライバーのようなものを提供し、それらをアプリケーション内で自動的に登録する場合
- パッケージが特定の環境変数や設定ファイルを読み込んで、内部の状態を初期化する場合
- パッケージがアプリケーション起動時に一度だけ実行する必要があるコード（例えば、データベースのマイグレーションやシードデータの投入）を含む場合
- ただし、ブランクインポートは、パッケージ内の初期化処理が不透明であるため、コードの可読性が低下する可能性があります。そのため、ブランクインポートは必要な場合にのみ使用し、適切なコメントやドキュメントでその目的や効果を明確にすることが推奨されます。

以下に、ブランクインポートを使用したサンプルコードを記載。

```go
package main

import (
	_ "database/sql"
	_ "github.com/lib/pq"
	"fmt"
)

func main() {
	fmt.Println("Blank import example")
}
```

この例では、database/sqlパッケージとgithub.com/lib/pqパッケージがブランクインポートされています。これにより、それらのパッケージの**init関数**が実行され、パッケージ内の他の宣言は無視されます。このようにして、必要な初期化や設定が行われることがあります。

https://golangdocs.com/blank-identifier-in-golang

https://stackoverflow.com/questions/26972615/a-use-case-for-importing-with-blank-identifier-in-golang
ChatG PTに聞きます

**ChatGPTに聞きます。**
![6mMfkmBJhzTeFUzqrRoA8J4KaAY2/qbOmNMca6IhlAOi6.jpg](https://firebasestorage.googleapis.com:443/v0/b/type-c1c71.appspot.com/o/6mMfkmBJhzTeFUzqrRoA8J4KaAY2%2FqbOmNMca6IhlAOi6.jpg?alt=media&token=d9867d33-551f-45d3-b59c-4509454b1b7a)