OmniAICreator/Qiita-1.07M huggingface dataset:
Discord Webhook をPythonで使ってみる

Discord Webhookは、外部アプリケーションからDiscordのチャンネルにメッセージを送信するための強力なツールです。自動通知、ログの転送、ボットを使わずにカスタムメッセージを送信するなど、様々な用途で活用できます。

### Webhook の作成

1. Discordサーバーを開き、メッセージを送信したいチャンネルの設定を開きます。
2. 「連携サービス」タブを選択し、「ウェブフック」をクリックします。
3. 「新しいウェブフック」ボタンをクリックします。
4. Webhookの名前、アバター画像、送信先のチャンネルを設定します。
5. 「保存」をクリックすると、Webhook URLが表示されます。このURLは非常に重要なので、安全な場所に保管してください。  **絶対に他人に共有しないでください。**

![webhook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078416/239ed590-a8e7-49b4-6276-6737e9430568.png)


### Webhook URL の構造

Webhook URLは以下のような構造になっています。

```
https://discord.com/api/webhooks/<Webhook ID>/<Webhook Token>
```

* `<Webhook ID>`: Webhookを一意に識別する数値
* `<Webhook Token>`: Webhookへのアクセスを認証するための文字列

### メッセージの送信

Webhook URLを使用して、POSTリクエストを送信することでメッセージを送信できます。リクエストボディはJSON形式で、以下のようなパラメータを指定できます。

* `content`: メッセージのテキスト。DiscordのMarkdown記法が使用できます。
* `username`: Webhookの表示名。
* `avatar_url`: Webhookのアバター画像のURL。
* `embeds`: リッチな埋め込みメッセージを送信するための配列。
* `tts`: メッセージをテキスト読み上げで送信するかどうか (true/false)。
* `allowed_mentions`: メンションの動作を制御するためのオブジェクト。


**シンプルなメッセージ送信例 (Python):**

```python
import requests
import json

webhook_url = "your_webhook_url"

message = {
    "content": "Webhookからのテストメッセージです！"
}

headers = {
    'Content-Type': 'application/json'
}

response = requests.post(webhook_url, data=json.dumps(message), headers=headers)

if response.status_code == 204:
    print("メッセージを送信しました！")
else:
    print(f"エラーが発生しました: {response.status_code}")
```

これを実行するとこのようなメッセージが送信されます。
![webhook_from_discord_simple.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078416/758a3606-1663-df6f-ac63-45a66c5374cf.png)

### 埋め込みメッセージ (Embeds)

埋め込みメッセージを使用すると、よりリッチなメッセージを送信できます。タイトル、説明、画像、フィールドなどを追加できます。

**埋め込みメッセージ送信例 (Python):**

```python
import requests
import json

webhook_url = "your_webhook_url"

message = {
    "embeds": [
        {
            "title": "埋め込みメッセージのタイトル",
            "description": "埋め込みメッセージの説明",
            "color": 0x00ff00, # 色 (16進数)
            "fields": [
                {"name": "フィールド1", "value": "値1"},
                {"name": "フィールド2", "value": "値2"}
            ]
        }
    ]
}

headers = {
    'Content-Type': 'application/json'
}

response = requests.post(webhook_url, data=json.dumps(message), headers=headers)

if response.status_code == 204:
    print("埋め込みメッセージを送信しました！")
else:
    print(f"エラーが発生しました: {response.status_code}")
```

これを実行するとこのようなメッセージが送信されます。

![webhook_from_discord_with_embeds.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3078416/2e38176e-ef4c-e2bc-1dd9-9a0852f82439.png)

### まとめ

Webhookは、Discordと外部アプリケーションを連携させるための便利なツールです。様々なプログラミング言語で簡単に利用できるので、ぜひ活用してみてください。より詳細な情報は、Discord Developer Portalの公式ドキュメントを参照してください。

### 参考文献
- https://discord.com/developers/docs/resources/webhook
PIC32MXでUSBデバイス

[pic32mx_uvc_yuy](https://github.com/yamori813/pic32mx_uvc_yuy)を作るために復習してみました。

使っているライブラリは古いMicrochip Libraries for Applicationsです。

デバイス側のコードの流れはmainの処理と割り込みの二つになります。

mainでは初期化を行って処理ループに入ります。

割り込みの処理はUSER_USB_CALLBACK_EVENT_HANDLERと定義された関数がよばれます。

ホストのlibusbでこのようなコントロール転送のクラスリクエストを発行したとします。

```c
        /* VS_PROBE_CONTROL(0x01), SET_CUR(0x01)  [UVC1.5, p. 161, 158] */
        err = libusb_control_transfer(
                handle, 0x21, 0x01, 0x0100, 0x0001, buf, 26, TIMEOUT);
```

デバイス側ではUSER_USB_CALLBACK_EVENT_HANDLERがEVENT_EP0_REQUESTでよばれ、USBCBCheckOtherReq()->USBCheckVideoRequest()と処理されます。

USBCheckVideoRequest()の中でデータを返す場合はoutPipes[0]にデータを入れるようです。

UVCのようなデバイスからホストにアイソクロナス転送しますが、ホストで受け取る場合libusbの下記の関数をよびます。

```
libusb_fill_iso_transfer(...);
libusb_set_iso_packet_lengths(...);
libusb_submit_transfer(...);
```

デバイス側がデータを投げるとコールバックがよばれます。この処理を行わないと、デバイス側が投げようとしても処理されません。

アイソクロナスのエンドポイントはUSBEnableEndpoint()で有効にします。

デバイス側でデータを投げるのはUSBTxOnePacket()です。この関数の第３引数はサイズなのですが、実際に処理する関数がBYTEで受け取るため255バイトまでしか送信できません。USBの12MのFULL SPEEDのアイソクロナス転送は1023バイトまで送れるのですが。。。ライブラリのサンプルコードにはUVCはないので、アイソクロナス転送の大きなデータの送信はノーチェックだったのだと思われます。

pic32mx_usb_i2sではmainループでアイソクロナス転送を受け取ってDMAバッファに放り込んでいます。

pic32mx_uvc_yuyでテストプログラムなので、mainループで全力でデータを送るようになっています。実際に外部のカメラなどからデータを受け取って送る場合はDMA処理の割り込みでデータを送ることになると思います。
マイGPT入門：使い方とおすすめの活用方法

## はじめに

最近話題のAIアシスタント「マイGPT」について、聞いたことはあるけれど、具体的に何ができるのか、どう使えばいいのか分からない方も多いのではないでしょうか？  
この記事では、**初心者向けにマイGPTの使い方**や、**おすすめの活用方法**を分かりやすく解説します！  

日常生活や仕事、趣味の場面でどのように活用できるかを具体例とともにご紹介しますので、ぜひ最後まで読んでみてください。

---

## マイGPTとは？

マイGPTは、OpenAIが開発した自然言語処理AI「GPT」シリーズをベースにしたカスタマイズ可能なAIアシスタントです。  
ユーザーの指示に応じて柔軟に対応し、以下のような特徴を持っています。

- **対話型のAIアシスタント**として利用可能。  
- **プログラミング、文章作成、学習サポート**など、多岐にわたるタスクに対応。  
- ユーザーの指示や好みに応じた最適な回答を提供。  

例えば、質問や指示をチャット形式で入力すると、AIが即座に回答や提案を行います。文章作成やコードレビューなど、幅広い分野で活躍する頼もしい存在です。

![スクリーンショット 2024-12-09 17.34.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/ac40291d-b99c-05ca-04ae-ec76b343c39f.png)


---

## マイGPTを始めるには？

### 1. アカウント作成
マイGPTを利用するには、まずアカウントを作成します。公式サイトにアクセスし、必要な情報を入力してください。  
公式サイト：[OpenAI](https://www.openai.com)

### 2. サインインと環境設定
サインイン後、以下の初期設定を行いましょう：
- **言語設定**: 日本語で利用する場合は「Japanese」を選択。
- **目的の選択**: 作業効率化や学習サポートなど、自分の目的に合わせて設定。

### 3. 実際に使ってみる
マイGPTの利用方法はとても簡単です。
1. チャットウィンドウに質問や指示を入力。
2. 送信ボタンをクリック。
3. AIの回答を確認。

![スクリーンショット 2024-12-09 17.34.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/14f57284-96f4-81f5-d944-68c3e299fb2a.png)



---

## マイGPTで何ができるのか？

### 1. **文章作成**
- メール、ブログ記事、レポートなど、あらゆる種類の文章作成をサポート。
- 例: 「週報のテンプレートを作成してください。」

### 2. **プログラミングサポート**
- コードの修正や最適化、エラー解決など、初心者から上級者まで対応。
- 例: 「Pythonで簡単なHTTPリクエストのコードを教えてください。」

### 3. **学習サポート**
- 難しい概念の説明や勉強計画のアドバイスを提供。
- 例: 「線形代数の基礎を分かりやすく説明してください。」

### 4. **タスク管理**
- ToDoリストの作成やスケジュール調整のアドバイスを提供。
- 例: 「仕事とプライベートのバランスを取るスケジュールを提案してください。」

![スクリーンショット 2024-12-09 17.34.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/46d9e8e5-0218-765d-7e1c-d91c732cc688.png)


---

## おすすめの使い方

### 1. 日常生活での使い方
**日常のタスクやちょっとした疑問解決に便利です。**

- **買い物リストの作成**  
  指示内容: 「4人家族の1週間分の夕食を考えて、買い物リストを作ってください。」
- **旅行計画**  
  指示内容: 「東京から京都までの2泊3日の旅行プランを提案してください。観光スポットとグルメも含めて。」
- **家事の効率化**  
  指示内容: 「毎日の家事を効率化するスケジュールを教えてください。」

### 2. 仕事での使い方
**仕事の効率化やタスクのサポートに役立ちます。**

- **メールの下書き**  
  指示内容: 「取引先のA社に送る感謝メールの文面を考えてください。」
- **会議資料の作成**  
  指示内容: 「営業会議用のプレゼン資料の構成を提案してください。」
- **データ分析サポート**  
  指示内容: 「以下の売上データを基にPythonで売上推移をグラフ化するコードを作成してください。」  
  *データ例*: 「2024年1月: 500万、2月: 600万、3月: 550万...」

### 3. 学習・趣味での使い方
**スキルアップや趣味を充実させる手助けをしてくれます。**

- **言語学習**  
  指示内容: 「英語の自己紹介を作ってください。趣味や仕事についても触れたいです。」
- **プログラミング学習**  
  指示内容: 「Pythonで簡単なTODOアプリを作るコードとその解説を教えてください。」
- **DIYアドバイス**  
  指示内容: 「自宅のリビングに収納棚を作りたいのですが、初心者でもできる設計と材料リストを教えてください。」

---

## よくある質問 (FAQ)

### Q: マイGPTの利用は無料ですか？
基本的な利用は無料ですが、特定の機能や高頻度の利用には有料プランが必要です。

### Q: プライバシーは守られますか？
はい、データは適切に管理され、ユーザー情報が第三者に公開されることはありません。

---

## まとめ

マイGPTは、**日常生活のちょっとした疑問解決から仕事の効率化まで**、幅広いシーンで活用できるAIアシスタントです。具体的な指示を与えることで、より役立つ回答を得られます。

初心者でも簡単に使えるので、ぜひ一度試してみてください！  
何か疑問があれば、この記事のコメントでお気軽に聞いてください😊
Validについて

Validは役目を終えたものを再利用するような処理。例えばアイテムを複数個作るとき。自分は最初、アイテムが消えたらと認識していて、アイテムがステージ上から消える。つまりプレイヤーがアイテムをとったらその配列にアイテムを生成していた。しかし、アイテムが役を終えるのは、プレイヤーがアイテムを使って効果を終わらせた時である。つまりValidするのはプレイヤーがアイテムを使って"完全に"アイテムが消えて、役目を終えたらValidをすること。(ちなみにプレイヤーがアイテムをとった時に生成するとプレイヤーが持ってるものと同じものが生成され、もう1人のプレイヤーがアイテムをとる=プレイヤーと全くおなじものをとることになり、一方がアイテムを使うともう一方も反応してしまうことになる。)
よく利用するVimショートカットをまとめた

# 概要

個人的によく利用するVimショートカットをまとめました。

## カーソル操作

| コマンド | 説明                                       |
|----------|--------------------------------------------|
| 0    | 行の先頭に移動|
| $    | 行の末尾に移動　|
| w    | 単語単位で次へ移動|
| b    | 単語単位で前へ移動|
| 3w / 3b  | 3つ先(または前)の単語に移動（指定した数値分）                |
| gg       | ファイル先頭へ移動                         |
| G        | ファイル末尾へ移動                       |
| 3G       | 3行目へ移動（指定した行数）           |
| ggVG     | 全行をビジュアル選択モードで選択            |

## ビジュアルモード

| コマンド | 説明                                      |
|----------|-------------------------------------------|
| v        | 文字単位のビジュアルモード開始            |
| V        | 行単位のビジュアルモード開始              |
| Ctrl + v   | 矩形(ブロック)単位のビジュアルモード開始  |
| v + ↑ / v + ↓  | 複数行選択                                 |

## 矩形選択

矩形（くけい）と読みます。

| コマンド‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎ &emsp;&emsp;&emsp;&emsp;| 説明                                                         |
|------------------|------------------------------------------------------------|
| Ctrl + v           | 矩形選択開始                   |
| Ctrl + v + I       | 矩形選択中、選択範囲の先頭にカーソルを移動し挿入モード開始（全行行頭に挿入） |
| Ctrl + v + A       | 矩形選択中、選択範囲の末尾にカーソルを移動し挿入モード開始（全行行末に挿入） |
| Ctrl + v + d    | 矩形選択中、選択範囲の文字列をすべて削除 |
| Ctrl + v + $ + A    | 矩形選択で行末まで拡大後、行末に共通の文字列を追加（長さの異なる複数行にも有効） |

※ 矩形選択の編集時は先頭1行のみ変更されているように見えますが、<br>編集終了時（`escape`）に選択範囲のすべての行に対して、変更が反映されます。

## 入力モード

| コマンド | 説明                                      |
|----------|-------------------------------------------|
| i        | カーソル位置で挿入モード                  |
| I        | 行頭で挿入モード                          |
| A        | 行末で挿入モード                          |
| o        | カーソル行の下に新規行を挿入して挿入モード |
| O        | カーソル行の上に新規行を挿入して挿入モード |

## 編集

| コマンド | 説明                                                    |
|----------|---------------------------------------------------------|
| cc       | 現在行を削除し挿入モード                               |
| yy       | 現在行をコピー                               |
| dd       | 現在行を削除                                 |
| p        | 貼り付け                                   |
| u                 | 直前の操作を取り消す         |
| Ctrl+r            | 取り消した操作をやり直す       |
| cw       | 単語を削除して挿入モードに（`change word`）            |
| c$       | 行末までを削除して挿入モード|
| d$       | 行末まで削除                                           |
| :%d + Enter | ファイル内の全行を削除                                |


## インデント操作

| コマンド | 説明                           |
|----------|--------------------------------|
| >>       | 選択行を右へシフト |
| <<       | 選択行を左へシフト |

## 検索・置換

| コマンド          | 説明                                       |
|-------------------|--------------------------------------------|
| /hoge             | `hoge`を前方へ検索                         |
| ?hoge             | `hoge`を後方へ検索                         |
| n                 | 次の検索結果へジャンプ                     |
| N                 | 前の検索結果へジャンプ                     |
| :%s/old/new/g     | ファイル全体で`old`を`new`に一括置換        |
| :%s/old/new/gc    | ファイル全体で`old`を`new`に置換（都度確認）|

# まとめ

以上です。
Vimコマンドは覚えておくのが大変なのでチートシートを作成しました。
Apsaraテクノロジー Deep-Diveシリーズ：AI革新のためのインフラストラクチャの刷新

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/apsara-technology-deep-dive-series-revamping-infrastructure-for-ai-innovations_601835?spm=a2c65.11461433.0.0.1ade5355QV6MuI)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

![weather_miniature_jpeg](https://yqintl.alicdn.com/1af47894e123e693f234e0e4f439d44a53b6a42a.jpeg)

Apsara Technology Deep-Dive Seriesは、最新版の[Apsara Conference](https://www.alibabacloud.com/blog/exploring-the-future-of-ai-5-takeaways-from-alibaba-clouds-apsara-conference_601637)（2024年開催）で紹介された最先端技術を、近接して専門的な視点から解説するためのシリーズです。これはアリババクラウドの年次旗艦イベントです。生成型人工知能（GenAI）モデルとアプリケーションが、世界中の様々な規模の組織にとってますます重要な位置を占めている中、アリババクラウドは、より効率的で強化されたセキュアなクラウドインフラを提供するため、一連の新しいクラウドネイティブソリューションと機能を導入しました。これにより、顧客やパートナーが次の世代のAIモデルとアプリケーションを構築できるよう支援します。アリババクラウド情報の会長兼CEOであるEddie Wu氏は、[講演](https://www.alibabacloud.com/blog/eddie-wu-discusses-ai-alibaba-cloud-and-more-at-the-2024-apsara-conference_601627)で生成型AIの変革的な影響を強調し、それがデジタル領域にますます浸透するだろうと予測しました。彼は、物理世界がAI能力を得ることで、AI駆動のデジタル世界と連携し、相乗効果を生む新たな世代の製品が登場すると指摘しました。彼はApsaraカンファレンスの基調講演で、「アリババクラウドはAI技術の研究開発とグローバルインフラの構築に対して、これまでにない強度で投資しています」と述べました。

生成型AIアプリケーションを構築するために、安定したAIインフラストラクチャは不可欠であり、パフォーマンス、拡張性、セキュリティ、イノベーションの基盤を提供します。このシリーズの一環として、データベース（データの保存、検索、管理、推論、ファインチューニング、パーソナライズ）、ビッグデータプラットフォーム（データ処理、モデルの訓練とデプロイ、分析と可視化）、セキュリティソリューション、そしてグリーンデータセンターが、生成型AIモデルとアプリケーションを構築するための重要な基盤の一部である理由を探究します。

記事を読む：

- [AIの未来を探る：Apsara Conferenceから学んだ5つのポイント](https://www.alibabacloud.com/blog/601637 target=_blank)
- [AIの成長はインフラの現代化に支えられており：ビジネスが繁栄するためにどう対応すべきか](https://www.alibabacloud.com/blog/ai-growth-is-built-upon-infrastructure-modernization-how-businesses-must-adapt-to-thrive_601814 target=_blank)
- [AI時代におけるセキュリティ強化：多様なクラウド環境向けにアリババクラウドがセキュリティソリューションを披露](https://www.alibabacloud.com/blog/strengthening-security-in-the-ai-era-alibaba-cloud-showcases-security-solutions-for-diverse-cloud-environments_601834 target=_blank)


この記事は、[Alizila](https://www.alizila.com/apsara-technology-deep-dive-series-revamping-infrastructure-for-ai-innovations/)で元々公開され、Alizilaスタッフによって執筆されました。
2大スケマティックエントリーソフトでSymbolを作ってみよう！

# テストベンチとスケマを分けろでこすけ🙇🙇🙇
もしかして知らないんでは？世の人たちは
そうに違いない
ということで
こちら、GIFアニメーションにしたので見てってね
（同じ回路でやればいいのに、やらないあたりご愛敬）

## LTSPICE
![プレゼンテーション1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634655/a7ffb0c2-791e-9faa-ea76-cbf608f418e1.gif)



## Xshcem

大変申し訳ないですが2倍速🙇
![プレゼンテーション2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634655/a80c8bc2-f0a6-e1b3-ce04-9c9e6828345b.gif)


## 誤字脱字があるので
見つけてご指導ご鞭撻のほど…
議事録作成の極意：テンプレート付き実践ガイド

# はじめに
会議が終わると次のアクションをスムーズに進めるために欠かせない「議事録」。正確で分かりやすく、かつ迅速に共有できる議事録の作成方法を学び、実践に活かしてみましょう。この記事では、具体的なテンプレートを提供しつつ、議事録作成のコツを解説します！

ちなみに以前書いた議事録についての記事はこちら
[効果的な議事録の取り方：会議を成功に導くポイント](https://qiita.com/mnoguchi/items/9c2192dd835b8139121c)

---

## 議事録テンプレート

まずは、簡単に使える議事録テンプレートをご紹介します。このテンプレートは、必要最低限の情報を整理しやすい構成になっています。会議の内容に応じてカスタマイズし、ぜひお使いください！

### **議事録テンプレート**
```markdown
[[_TOC_]]

## 日時・場所・メンバー

- **日時:** YYYY/MM/DD (曜日) HH:MM - HH:MM  
- **場所:** [会議ツール名や場所]  
- **メンバー（順不同・敬称略）**  
  - 部署名: 氏名、氏名  
  - 部署名: 氏名、氏名

## 目的

会議の目的を簡潔に記載します。

## アジェンダ

1. トピックA
2. トピックB
3. トピックC

## 宿題 (TODO)

- **担当者: ** Aさん  
  - タスク内容: 締切日 YYYY/MM/DD

## 決定事項

- トピックAについて、○○を決定
- トピックBに関して、○○を採用

## 未決事項

- トピックCについて、次回の検討が必要

## メモ

### トピックA

- 議論内容や補足事項を記載します。

### トピックB

- 同上。

## 参考リンク

- [資料タイトル](https://example.com)
- [スライド名](https://example.com)
```

---

## テンプレートの使い方と改良ポイント

このテンプレートは、以下の特徴を持っています。

1. **視覚的な整理がしやすい**  
   各項目が明確に分かれているため、どこに何を書くべきか迷いません。

2. **リアルタイムでの記録に対応**  
   会議中に記録を進めても、情報をすぐに整理できる構成になっています。

3. **追記・編集が簡単**  
   Markdown形式を採用しているため、エディタやオンラインツールとの親和性が高く、編集が簡単です。

---

## テンプレート活用のヒント

- **事前準備を忘れずに**  
  会議前にテンプレートを用意し、アジェンダや目的を事前に記載しておきましょう。これだけで議事録作成の負担がぐっと減ります。

- **担当者や締切を明記**  
  宿題やTODOは、誰が何をいつまでに行うのかを明確にしましょう。

- **リンクを活用**  
  参考資料やスライドへのリンクを記載することで、会議後のフォローアップがスムーズになります。

---

## おわりに

議事録は単なる記録ではなく、プロジェクトの成功を支える「道しるべ」です。テンプレートを活用しつつ、速報性と正確性を意識した議事録作成を心がけてください。

次の会議でこのテンプレートを使ってみたら、ぜひ感想をお聞かせください！記事が役立ったと思ったら「いいね」をお願いします。 😊
blastengineのメールエラーWebhookをCloudflare Workers + Pythonで処理する

[blastengine](https://blastengine.jp/)はエンジニアフレンドリーなメール送信サービスになります。APIまたはSMTPを使って、簡単にメール送信を行えます。

blastengineではエラーメールに対するWebhook通知をサポートしています。この記事では、その扱い方とデータについてCloudflare Workers + Pythonによる処理を通じて解説します。

というか、Cloudflare WorkersでPythonサポートしているのを知ったので、それを試したくて書いてみました（2024年12月現在、ベータ版とのことです）。

## 設定

Webhook設定はblastengineの管理画面で行います。設定の中にあるWebhookをクリックします。

![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/059adabd-6159-2cd4-12d3-9d98c075b1c2.jpeg)

設定は主に2つです。

- エンドポイントURL
Webhookを受け取るURLです
- 通知イベント
Webhookを受け取るイベントです

エンドポイントURLにはPOSTメソッドで呼ばれます。Content-Typeはapplication/jsonになります。通知イベントは以下の3つが用意されています。

- ドロップ
エラー停止リスト内にあるメールアドレス宛に送信しようとした場合のエラーです
- ハードエラー
ホストがない、ユーザーがいないといった恒久的なエラーです
- ソフトエラー
メールボックスがいっぱいなど一時的なエラーです

## 注意点

2024年11月現在、Webhookはトランザクションメール（即時配信メール）に対してのみ有効です。バルクメール（一括配信）やSMTPリレーは未対応です。

## データを受け取ってみる

では実際にデータを受け取ってみます。今回はPythonで以下のようなコードを書きました。

```python
from js import Response

async def on_fetch(request, env):
    data = await request.json()
    event = data.events[0].event
    print(event.detail.error_message) # 宛先のメールアドレスがありません
    return Response.new("ok")
```

以下はドロップの例です。 `error_message` にエラー内容が入ります。

```json
{
	"events": [
		{
			"event": {
				"type": "DROP",
				"datetime": "2023-01-26T16:17:54+09:00",
				"detail": {
					"mailaddress": "user@drop.example.com",
					"subject": "Test subject",
					"error_code": "554(errors)",
					"error_message": "エラー停止リストに含まれる宛先であるため、配信がドロップされました",
					"delivery_id": 1128
				}
			}
		}
	]
}
```

以下はハードエラーの場合です。ホストがない、ユーザーが存在しないなど恒久的に発生する場合のエラーです。

```json
{
	"events": [
		{
			"event": {
				"type": "HARDERROR",
				"datetime": "2023-01-26T16:22:43+09:00",
				"detail": {
					"mailaddress": "user@harderror.example.com",
					"subject": "Test subject",
					"error_code": "550",
					"error_message": "宛先のメールアドレスがありません",
					"delivery_id": 1129
				}
			}
		}
	]
}
```

## まとめ

データが受け取れれば、後はSlackへ通知したり、データベースと連携するなどが容易になります。配信先リストを自動クリーニングするのにも使えるでしょう。

一例としてZapier経由でSlackへ通知するデモを[blastengineのwebhook機能でメール送信が失敗したらzapier経由でSlackに通知できるようにした。 - Qiita](https://qiita.com/hirosatooooo/items/21573f79fbb8599090d1)にて紹介しています。ご覧ください。

[エンジニア向けメール配信システム「ブラストエンジン（blastengine）」](https://blastengine.jp/)
インプット後のアプリ開発をしてみて

今回JISOUのカリキュラムでudemyでインプットした後に最初のアプリ開発を行いました。
　そもそもjavascriptをほとんど触ったことがない中で、まずインプットの時点で？？の連続でした。udemyでの小規模なアプリ開発もハンズオン形式とはいえ、初見でメカニズムを理解することはできず、2～3回ハンズオンをして、操作の理由を理解することができました。
　その後、udemyと少し違った仕様のアプリ開発です。しかし、全然コーディングできません。動画を見て覚えた気になっていました。動画で説明したところと似たような仕様になっている箇所は、調べてコーディングできますが、インプットの時点で要素が１つだったところが、2つになっているだけでハードルが上がります。これがインプットの効果が低いということか・・・と思いながらとりあえず、仕様を満たしたアプリを作ることができました。
 インプットがダメということではなく、インプットで終わってしまうとほとんど意味がないということでしょう。
  # 今回アプリ開発する上で気を付けたポイント
　JISOU講師のアドバイス通り脳負荷を意識し分からなくてもすぐにAIに頼ることはせず、まず調べて自分なりにコーディングしました。うまく動作しなくてもそれでもOK。大切なのは脳負荷。調べても正解が分からない場合にAIに助けてもらいました。しかし、うまく挙動したからとそれで終了とせず、どうしてこのコーディングをしているのか理解しないと意味がありませんので、AIに根掘り葉掘り聞きまくります。その後、回答が正しいのか自分で調べて納得するまでを繰り返しました。そして、記録に残す！しかも他の人が見ること前提に。ここが結構大切だと思います。ただ自分のためだけの記録では説明も疎かになりがちです。しかし、他の人対象となるとそれなりの説明をする必要があり、書いていることの辻褄があっていないとダメですので、記録に残す作業をしている時も脳の中で考えながら入力します。それにより理解定着が促進されます。
 　ただ疑問に思ったことを深堀し過ぎると迷子になるので、その辺の加減は調整してとりあえず実装した内容は全て理解し、その後記録に残すことを繰り返しました。
 　そして、1回作ったアプリを本当に理解しているのか確認するため、日を変えて再度作り直しました。その時は理解できても、一旦時間を空けると定着していないことが多いからです。現にそうでした。また日を改めて再度作ってみれば、その時に見えなかった部分や更に記憶定着につながると思います。
  　これを行ったおかげで何となく作って終わりのアプリが、身になるアプリ開発になることを実感しました。
   スタートの加速は遅いけど、これの繰り返しで成長速度を止めることなく進むことができるのではないかと思いました。正に今のためではなくこの先のための学習ですね。
   ただこれを自分一人で行うことは大抵の人が無理だと思います。やらなければならない状況に身を置くことでやり遂げることができると実感しました。
   これからもコツコツ進んでいきます。
長くなったので開発していてつまずいたポイントは別記事に投稿します。

# JISOUのメンバー募集中！
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか？
興味のある方は、ぜひホームページをのぞいてみてくださ！
▼▼▼

https://projisou.jp
【マイコン比較】Raspberry Pi Pico W と ESP32 の比較

無線使えるマイコン、**Raspberry Pi Pico W** と **ESP32-WROOM-32** 、**ESP32-C3**を調べたので比較してみます。ただESP32を知らず、先にラズパイを買ってしまいました。

## スペック

### Raspberry Pi Pico W

- **CPU**: Dual-core ARM Cortex-M0+
- **クロック周波数**: 最大 133 MHz
- **RAM**: 264KB
- **フラッシュメモリ**: 2MB
- **Wi-Fi**: あり（Chip: Infineon CYW43439）
- **Bluetooth**:　一応あり
- **価格**: 1,200円　[秋月電子](https://akizukidenshi.com/catalog/g/g117947/)
- **ブレッドボード空き**: 両側2行

### ESP32-DevKitC-32E（ESP32-WROOM-32の開発ボード）

- **CPU**: Dual-core Tensilica LX6
- **クロック周波数**: 最大 240 MHz
- **RAM**: 520KB
- **フラッシュメモリ**: 4MB
- **Wi-Fi**: あり
- **Bluetooth**: あり
- **価格**: 1,600円　[秋月電子](https://akizukidenshi.com/catalog/g/g115673/)
- **ブレッドボード空き**: 片側1行

### ESP32-C3

- **プロセッサ**: ESP32-C3 32bitRISC-V
- **クロック周波数**: 最大 160 MHz
- **RAM**: 400KB
- **フラッシュメモリ**: 4MB
- **Wi-Fi**: あり
- **Bluetooth**: あり
- **価格**: 1,080円　[秋月電子](https://akizukidenshi.com/catalog/g/g117454/)
- **ブレッドボード空き**: 片側2行、もう片側3行

## 所感
ESP32-WROOM-32は性能良さそうだが、いろんな検証例を見てみると、無線使用時は特に消費電力が大きいよう。
そして、400穴ブレッドボードだと片側1行しか空きがない...
でもESP32-C3はラズパイより小型で、性能上回ってしかも安かった。
請求書と税務精算 - 書類処理

現代のビジネス環境において、請求書は取引を記録する重要な書類です。これは、売り手と買い手の間の取引記録であるだけでなく、会計、税務、法的な面でも重要な役割を果たします。

## 請求書 - 精算
請求書は税務精算と共に使用されることが多く、精算業界では効率と正確性が非常に重要です。しかし、多くの機関は依然として煩雑な書類処理やデータ管理の問題に直面しています。従来の精算プロセスは、多くの紙の書類と手動入力を伴い、時間がかかるだけでなく、エラーが発生しやすく、精算の遅延や財務的な圧力を引き起こします。

## 請求書の書類処理
（PDF技術が医療精算[機関の書類処理を簡素化](https://www.compdf.com/blog/faster-prochant-healthcare-reimbursement-processes?utm_source=qiita_20241209&utm_medium=invoiceprocessing)するケース）
現在の精算業界の現状は、多くの機関が手動処理と紙の書類に依存しており、プロセス全体が遅く、エラーが発生しやすいことを示しています。書類処理の困難は以下の点に集中しています：

1. 手動入力エラー：大量の手動操作により、エラーは避けられません。これらのエラーは、精算要求が拒否されたり、遅延したりする原因となります。
2. 処理時間の長さ：紙の書類の送付と処理には多くの時間がかかり、精算サイクルが延びます。
3. データ管理の困難さ：紙の書類の保管と検索は非常に不便で、管理コストと時間が増加します。

これらの困難を克服するために、先進的なPDF技術を採用することが効果的な解決策となります。業務シナリオと組み合わせることで、自動化またはバッチ処理により、精算サービス機関は書類をより効率的に処理し、請求書などの書類を生成して精算準備を行い、人為的なエラーを減らし、承認プロセスを迅速化できます。例えば、PDF技術を使用すると、精算に必要な重要な情報を自動的に抽出および処理でき、処理時間を大幅に短縮できます。

## 請求書とは何ですか？
請求書は、売り手と買い手の間の取引を記録する商業書類です。提供された商品やサービス、数量、単価、総額、支払い条件などが詳細に記載されています。請求書は紙の形式でも電子形式でも存在します。

なぜ請求書が必要なのですか？
請求書はビジネス活動において多くの用途があります：

1. 会計と税務：請求書は会計記録の重要な部分であり、企業が売上と支出を追跡し、税務申告時に必要な証拠を提供するのに役立ちます。
2. 法的保護：請求書は取引の書面記録を提供し、紛争が発生した場合に法的証拠として使用できます。
3. 支払い要求：請求書は買い手が支払うべき金額と支払い期限を明確にし、タイムリーな支払いを確保するのに役立ちます。

## 有効な請求書とは？
有効な請求書には以下の情報が含まれている必要があります：
• 請求書のタイトル（例：「Invoice」）
• 一意の請求書番号
• 請求書の日付と支払い期限
• 売り手と買い手の詳細情報（名前、住所、連絡先を含む）
• 商品やサービスの詳細な説明、数量、単価
• 総額（税金やその他の費用を含む）
• 支払い条件

## 請求書の生成プロセス
請求書の生成は通常、以下のステップを含みます：

1. 請求書の作成：売り手は取引情報に基づいて請求書を作成し、必要な情報がすべて正確であることを確認します。
2. 請求書の送付：請求書は電子メール、郵送、その他の方法で買い手に送付できます。
3. 記録と保管：売り手は将来の参照や監査のために請求書のコピーを保管する必要があります。
4. 支払いの追跡：売り手は請求書の支払い状況を追跡し、タイムリーに支払いを受け取ることを確認する必要があります。
blastengineのメールエラーWebhookをCloudflare Workersで処理する

[blastengine](https://blastengine.jp/)はエンジニアフレンドリーなメール送信サービスになります。APIまたはSMTPを使って、簡単にメール送信を行えます。

blastengineではエラーメールに対するWebhook通知をサポートしています。この記事では、その扱い方とデータについてCloudflare Workers + TypeScriptによる処理を通じて解説します。

## 設定

Webhook設定はblastengineの管理画面で行います。設定の中にあるWebhookをクリックします。

![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/059adabd-6159-2cd4-12d3-9d98c075b1c2.jpeg)

設定は主に2つです。

- エンドポイントURL
Webhookを受け取るURLです
- 通知イベント
Webhookを受け取るイベントです

エンドポイントURLにはPOSTメソッドで呼ばれます。Content-Typeはapplication/jsonになります。通知イベントは以下の3つが用意されています。

- ドロップ
エラー停止リスト内にあるメールアドレス宛に送信しようとした場合のエラーです
- ハードエラー
ホストがない、ユーザーがいないといった恒久的なエラーです
- ソフトエラー
メールボックスがいっぱいなど一時的なエラーです

## 注意点

2024年11月現在、Webhookはトランザクションメール（即時配信メール）に対してのみ有効です。バルクメール（一括配信）やSMTPリレーは未対応です。

## データを受け取ってみる

では実際にデータを受け取ってみます。今回はTypeScriptで以下のようなコードを書きました。

```typescript
// イベントオブジェクト
interface Event {
	type: string;
	datetime: string;
	detail: {
		mailaddress: string;
		subject: string;
		error_code: string;
		error_message: string;
		delivery_id: number;
	};
}

// リクエストで送られるデータ
interface Request {
	events: {
		event: Event;
	}[];
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// リクエストボディをパース
		const json = await request.json<Request>();
		// イベントオブジェクトを取り出す
		const [{ event }] = json.events;
		// イベントオブジェクトの中身を表示
		console.log(event.detail.error_message); // 宛先のメールアドレスがありません
		return new Response('ok');
	},
} satisfies ExportedHandler<Env>;
```

以下はドロップの例です。 `error_message` にエラー内容が入ります。

```json
{
	"events": [
		{
			"event": {
				"type": "DROP",
				"datetime": "2023-01-26T16:17:54+09:00",
				"detail": {
					"mailaddress": "user@drop.example.com",
					"subject": "Test subject",
					"error_code": "554(errors)",
					"error_message": "エラー停止リストに含まれる宛先であるため、配信がドロップされました",
					"delivery_id": 1128
				}
			}
		}
	]
}
```

以下はハードエラーの場合です。ホストがない、ユーザーが存在しないなど恒久的に発生する場合のエラーです。

```json
{
	"events": [
		{
			"event": {
				"type": "HARDERROR",
				"datetime": "2023-01-26T16:22:43+09:00",
				"detail": {
					"mailaddress": "user@harderror.example.com",
					"subject": "Test subject",
					"error_code": "550",
					"error_message": "宛先のメールアドレスがありません",
					"delivery_id": 1129
				}
			}
		}
	]
}
```

## まとめ

データが受け取れれば、後はSlackへ通知したり、データベースと連携するなどが容易になります。配信先リストを自動クリーニングするのにも使えるでしょう。

一例としてZapier経由でSlackへ通知するデモを[blastengineのwebhook機能でメール送信が失敗したらzapier経由でSlackに通知できるようにした。 - Qiita](https://qiita.com/hirosatooooo/items/21573f79fbb8599090d1)にて紹介しています。ご覧ください。

[エンジニア向けメール配信システム「ブラストエンジン（blastengine）」](https://blastengine.jp/)
ランサムウェアの主な感染経路はVPNとリモートデスクトップ

## 情報セキュリティ白書2024によれば、「ランサムウェアの主な感染経路はVPNとリモートデスクトップ」が原因の80%越え

[情報セキュリティ白書2024](https://www.ipa.go.jp/publish/wp-security/2024.html) を今更ながら読み進めていたら興味深い記述発見。

> 警察庁では、ランサムウェア被害の実態を把握するために、ランサムウェアによる被害のあった企業・団体等に
対して、アンケート調査を実施している。2023 年のランサムウェアの感染経路としては、アンケート調査の有効回答
115 件のうち、「VPN 機器からの侵入」が63.5%（73 件）、「リモートデスクトップからの侵入」が18.3%（21 件）を占めており、2022 年に引き続きこれらテレワーク時に利用される機器等からの侵入が80% を超えている。

皆さん、躍起になって、VPNやリモートデスクトップで情報漏洩を防ごうとしているのに、逆に仇になってしまってる感ありますね。

VPNやリモートデスクトップによるセキュリティ対策がムダまでは思わないですが、攻撃者側が対価を得やすい流行のランサムウェア対策としては、あまり効果的ではないのかもしれません。
API Best Practices ~Batch/multi-phase Requestsでの冪等性

## Batch/multi-phase Requestsでの冪等性

https://protobuf.dev/programming-guides/api/#batch-multi-phase-requests

可能な限り、データ変更を１つの不可分な単位にする。
さらに重要なのは、データ変更を冪等にすること。
部分的な失敗の完全な再試行によってデータが破損したり複製されたりしてはならない。

パフォーマンス上の理由から、複数の操作をカプセル化する単一の RPC が必要になることがあります。
部分的な失敗時にどうするか？
一部が成功し一部失敗した場合、クライアントに知らせるのが最善です。

RPCを失敗として設定し、成功と失敗の両方の詳細を RPCステータスプロトに返すことを検討してください。
【M3Mac】docker componse up で nokogiri が cannot load such file -- nokogiri/nokogiri (LoadError) になる

# はじめに
記事を見て下さりありがとうございます。
@hayatohanaoka と申します。
今回は仕事で扱っている `rais` アプリケーションをM3Mac環境で起動しようとしたら `nokogiri` でエラーになったので、その解消法を記事にします。
# 起こったこと
### M3Mac の環境で `rails` のアプリケーションを `docker componse up` したら `cannot load such file -- nokogiri/nokogiri (LoadError)`  になった
※ 先輩のubuntu環境ではうまくいっている様子だったので、Mac特有の問題かもしれません

使用していた `Dockerfile` は以下です。
```dockerfile
FROM ruby:3.2.3-alpine
ENV LANG ja_JP.UTF-8
RUN apk update && \
  apk upgrade && \
  apk add --no-cache bash build-base git libxml2-dev \
  libxslt-dev postgresql-dev linux-headers openssh ruby-dev \
  ruby-json tzdata yaml yaml-dev zlib-dev

# Bundler cache
WORKDIR /tmp
RUN gem install bundler
ADD ./Gemfile Gemfile
ADD ./Gemfile.lock Gemfile.lock
RUN bundle install --jobs 10 --retry 3

WORKDIR /app
```
こいつを `docker compose up` してみると...
```zsh
> docker compose up

〜中略〜

app-1            | => Booting Puma
app-1            | => Rails 6.1.3.2 application starting in development 
app-1            | => Run `bin/rails server --help` for more startup options
app-1            | Exiting
app-1            | /usr/local/bundle/gems/activesupport-6.1.3.2/lib/active_support/dependencies.rb:332:in `require': cannot load such file -- nokogiri/nokogiri (LoadError)
```
`cannot load such file -- nokogiri/nokogiri (LoadError)` になりました。

# 原因
### `alpine`イメージを使用していたため、`glibc` に依存するソースでエラーになっていた
どうやら `alpine` イメージは必要最低限のモノだけを用意したイメージなので、一部ライブラリなどで問題が起こる様子。
...全く知らなかった😇😇😇

https://engineering.nifty.co.jp/blog/26586
# 解決法
以下をdockerfileに追加。
```dockerfile
apk add gcompat
```
https://github.com/Stantheman/gcompat

以下コマンドを実行
```
docker compose build --no-cache
docker compose up
```

# 最後に
みやみに`alpine`を使うと、思わぬところでエラーになるので気をつけよう。
もしエラーになっても上記手順で解決できるが、別のより良い手法を使う方が良さそうな気がする...。
python 組み込みモジュール④ urllib.parse

## モジュール概要
URL を処理するための機能を提供するモジュールです。
このモジュールを使用することで、Python プログラム内で URL を操作し、ネットワークとのやり取りを効率的に行うことができます。


## 主な機能
* URL の解析
* URL の構築
* URL のエンコードとデコード
* URL の構成要素の操作
* URL の標準化


## urllib.parseモジュールでよく使われるメソッド
&nbsp;

### urlparse()
URLをscheme, netloc, path, params, query, fragmentなどに分割します。

scheme, netloc, path, params, query, fragment
スキーム、 ネットロケーション、 パス、 パラメータ、 クエリ、 フラグメント
```python
from urllib import parse

url = 'http://www.example.com/path?name=JohnDoe#fragment'
parsed_url = parse.urlparse(url)
print(parsed_url)

# 出力：ParseResult(scheme='http', netloc='www.example.com', path='/path', params='', query='name=JohnDoe', fragment='fragment')
```


## paramsとqueryについて
params と query は、URL を構成する要素の一部であり、それぞれ異なる役割を持っています。以下はその違いについての説明です。

### 1. params (パラメータ):
* 位置: URL のパス部分に付随する形で記述されます。
* 用途: パスに関連する情報を指定するために使用されます。ウェブアプリケーションや API によっては、リソースを識別したり動作を変更するために使われる場合があります。
* 特徴: パスと密接に関連しており、一般的なクエリパラメータよりも使用頻度が低いです。
```python
例:http://example.com/path;param1=value1;param2=value2
```

### 2. query (クエリ):
* 位置: URL の末尾に ? の後で記述されます。
* 用途: 主にクライアントからサーバーに送信される追加情報を提供するために使用されます。検索条件やフィルタリングの条件などを指定する際に利用されることが多いです。
* 特徴: 一般的にキーと値のペア (key=value) を & で区切る形式で表されます。非常に広く使用されています。

```python
例:http://example.com/path?key1=value1&key2=value2
```

### URL の構造における違い
```python
例:http://example.com/path;param1=value1?key1=value1&key2=value2#fragment
```
* params: ;param1=value1 の部分。
* query: ?key1=value1&key2=value2 の部分。

### 使い分け
* params: リソースの識別やパスと直接関係する設定を行う場合に使用。
* query: クライアントがリクエスト時に指定する条件や追加情報を伝えるために使用。

通常、query の方がより一般的に利用されます。
rails routesが見辛いならexpandedオプションを付けると良い

もう本当に表題通り
友人とRailsガイド読み合わせ会をしていて、良いオプションを見つけたのでメモ

[Rails のルーティング - Railsガイド](https://railsguides.jp/routing.html#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E8%AA%BF%E3%81%B9%E3%82%8B)

個人的に通常の`rails routes`だと特に整形もされておらず、見辛くて好きになれなかったのだが、`--expanded`オプション付けたら結構見やすかったので忘れないようにメモ

通常のrails routes とは違って`Source Location`を出してくれるので、肥大化したroutes.rbの場合はありがたいかも
```bash
$ bin/rails routes --expanded

--[ Route 1 ]----------------------------------------------------
Prefix            | users
Verb              | GET
URI               | /users(.:format)
Controller#Action | users#index
Source Location   | config/routes.rb:261
--[ Route 2 ]----------------------------------------------------
Prefix            |
Verb              | POST
URI               | /users(.:format)
Controller#Action | users#create
Source Location   | config/routes.rb:263
```

ついでに
- `-g`オプションで、`URLヘルパー名(Prefix)`、`HTTP verb(Verb)`、`URLパス`それぞれで絞り込み(grep)できる
- それぞれ**一部分のみ**でも絞り込みができる
- `-c`オプションで、特定のコントローラーのルーティングに絞った検索もできる
```bash
$ bin/rails routes -g new_user # new_ など部分一致OK
$ bin/rails routes -g POST
$ bin/rails routes -g /users/new 
$ bin/rails routes -c users # 部分一致OK
```

参考
https://qiita.com/mt-blue-sou/items/fc4601b603861c2ef326
GASでGmailAPIでエラハンする

この記事は[42Tokyo Advent Calendar 2024](https://qiita.com/advent-calendar/2024/42tokyo) 、9日目の記事です。

## はじめに
syamasawと申します。GoとGASとAPIが好きな42Tokyo生です。
42Tokyoに関わるナイスな記事のアイデアが思いつかなかったので、今回は普通にGASのことを話そうと思います。

## 経緯
GmailをGASで送信する際、GASの関数`sendEmail`でメールを送信すると、そのメール送信が正常に行われたかが不明だった。そのため、レスポンスが帰って来るGmailAPIを用いることで、より良いエラーハンドリングが行えると考えた。

## コード
https://github.com/Sawawa42/gas-sendEmail

```js
function sendEmailByAPI(to, subject, body) {
  try {
    let obj = Gmail.newMessage();
    let message = "From: me\r\n" +
      `To: ${to}\r\n` +
      `Subject: ${subject}\r\n\r\n` +
      `${body}`;
    obj.raw = Utilities.base64EncodeWebSafe(message, Utilities.Charset.UTF_8); // 日本語
    let response = Gmail.Users.Messages.send(obj, "me");
    Utilities.sleep(5000); // バウンス待ちで5秒待機
    let thread = Gmail.Users.Threads.get("me", response.id);
    for (let i = 0; i < thread.messages.length; i++) {
      if (thread.messages[i].payload.headers.some(header => header.value.includes("mailer-daemon@googlemail.com"))) {
        return {"OK": false, "message": "Send failure"};
      }
    }
    return {"OK": true, "message": "Send success"};
  } catch (error) {
    Logger.log(error);
    return {"OK": false, "message": error};
  }
}

function test() {
  let body = "GASのテストだよ〜"
  let response = sendEmailByAPI("yourmail@example.com", "testMail", body);
  Logger.log(response.message);
}
```

## 前提

今回は、GASのサービスから、GmailAPIを選択して使用します。GCP経由でAPIを使用する方法もあるようですが、ここからだとアクセストークン等の認証関連を気にせずに済むメリットがあります。
![Screenshot from 2024-12-09 15-14-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763486/50891587-46e3-f5e5-656a-1226fe2c9ee4.png)

## 解説

このコードの要点は4ステップです。
1. 送信するメールの作成
2. メールの送信
3. 送信したメールが属するスレッドの取得
4. スレッドのチェック

順に見ていきましょう。

### 1. 送信するメールの作成

まず、`Gmail.newMessage()`によってメッセージオブジェクトを作成します。最初の状態ではこのオブジェクトは空っぽのため、ここに情報を付加します。

次に、messageの文字列を作成します。ここでは、From, To, Subject, Body(本文)を記述します。GmailAPIでは、Fromの部分をmeにすることで、メールアドレスをハードコードせずに、関数を使った人のメールアドレスを使用することが出来ます。

そして、`Utilities.base64EncodeWebSafe(data, charset)`を用いて、文字列をbase64にエンコードします。ここで注意したいのは、charsetを省略しないことです。charsetを省略した場合、日本語が文字化けします。

### 2. メールの送信

`Gmail.Users.Messages.send()`を用いてメールを送信します。先程作成したメールのToで、メールアドレスのフォーマットに誤りがある場合(メールアドレスの@を忘れた、等)、この関数は例外をスローします。フォーマットが正しい場合は送信が行われます。

なお、送信先が不明(タイプミス等)の場合、ここではエラーになりません。

### 3. 送信したメールが属するスレッドの取得

`Gmail.Users.Threads.get(userId, id)`を用いて送信したメールのスレッドを取得します。送信失敗した場合、少しのタイムラグの後スレッドに`mailer-daemon@googlemail.com`からバウンスが届くので、これを検索するためにこの関数を使用します。

ここも同様に、userIdをmeにすることで、ハードコードを回避できます。

今回はバウンスのタイムラグを回避するためにsleepを用いましたが、場合によって届くのが遅れる可能性があるので、注意が必要です。(筆者の環境では、5秒で外したことはなかったです)

### 4. スレッドのチェック

各messageオブジェクトのpayloadプロパティ内のheaders配列から、someを用いて`mailer-daemon@googlemail.com`を含むvalueプロパティを持つかをループで順に判定します。trueであった場合にはバウンスが存在するため、エラーを返します。

## おわりに

9割9分の42Tokyo生には縁がない内容になって申し訳ないと思いました。
しかし、javascriptの`Array.prototype.some()`を初めて使う機会になったので、これはこれで良かったのかなと思いました。
querySelector()とgetElementByClassName()の違い

# ◆◆querySelector()とgetElementByClassName()◆◆
DOM操作を学習したときに、つまづいたこの2つ。
getElementById()の使用が多かったため、いざクラス名で要素を取得しようと
したときに再確認したのでまとめます。

# ◆◆querySelector()◆◆
## ◆querySelector()とは
HTML要素を取得するためのメソッドです。
CSSセレクターで要素を取得しますので、カッコ内には『#id名』や『.クラス名』
などで記述をします。
<strong>マッチするCSSセレクターが複数ある場合は、最初にマッチした要素が
取得されます。 </strong>

私は最初にこの説明を読んでもピンとはこなかったのですが、
1ページ中に1つだけのid名と違って、クラス名は1ページ中に複数ある場合が
あります。
なのでクラス名で要素を取得する場合は、マッチするCSSセレクターが複数ある状況が
発生するわけです。

## ◆使用例
```HTML:HTML
    <ul id="list">
      <li class="todo">買い物をする</li>
      <li class="todo">洗濯をする</li>
      <li class="todo">掃除をする</li>
    </ul>
```
```JavaScript:JavaScript
const todo = document.querySelector(".todo")

console.log(todo)
// <li class="todo">買い物をする</li>
```


# ◆◆getElementByClassName()◆◆
## ◆getElementByClassName()とは
querySelectorと同じように、HTML要素を取得するためのメソッドです。
カッコ内はクラス名をそのまま記述することで、指定されたクラス名を持つ全ての
要素を配列風オブジェクト(HTMLCollection)で取得できます。
## ◆使用例
```HTML:HTML
    <ul id="list">
      <li class="todo">買い物をする</li>
      <li class="todo red">洗濯をする</li>
      <li class="todo">掃除をする</li>
    </ul>
```
```JavaScript:JavaScript
const todo = document.getElementsByClassName("todo")

console.log(todo)
// HTMLCollection(3)
// 0:li.todo
// 1:li.todo.red
// 2:li.todo
```
配列風オブジェクトには、for文やforEach()メソッドが使えます。
※forEach()は手を加える必要があります。

インデックス番号を加えると、それぞれの要素にアクセスできます。
また、複数のクラスを持つ要素の取得もできます。
```JavaScript:JavaScript
const todo1 = document.getElementsByClassName("todo")[0]
console.log(todo1)
// <li class="todo">買い物をする</li>

const todo2 = document.getElementsByClassName("todo red")
console.log(todo2)
// HTMLCollection(1)
// 0:li.todo

const todo3 = document.getElementsByClassName("todo red")[0]
console.log(todo3)
// <li class="todo red">洗濯をする</li>
```
要素が1つしかなくても、インデックス番号での指定がなければHTMLCollectionで
返されます。

理解しづらくしているのはクラス名が複数使用されるもので、指定する必要が
あるからでしょうか。
指定の仕方もいろいろありますので、理解のためにも後日まとめようと思います。
Arduinoで使えるコマンドパーサーのテンプレート(関数ポインタ使用)

# 概要
Arduinoで使える　シリアル入力コマンドパーサーのテンプレートです。

# ポイント
コマンドと、そのコマンドに対応する関数をペアにしてリスト化しています。

# 注意事項
* 関数ポインタを受け入れがたい人にはお勧めしません
* 備忘録的な記事なので、細かい解説は割愛させていただきます

# ソースコード
* "on+改行"を入力するとLedOn()関数が呼ばれてLEDが点灯
* "off+改行"を入力するとLedOff()関数が呼ばれてLEDが消灯
* "reset+改行"を入力するとReset()関数が呼ばれてリセットベクタに飛びます

```C++
void LedOn(){
  Serial.println("LED is ON");
  digitalWrite(LED_BUILTIN, HIGH);
}
void LedOff(){
  Serial.println("LED is OFF");
  digitalWrite(LED_BUILTIN, LOW);
}
void Reset(){
  asm volatile("jmp 0"); //リセットベクタ（0番地）に飛ぶ
}
//======================================================================
// 
//======================================================================
typedef void (*pFunc)(void);
//コマンド文字列と関数ポインタをセットにした構造体
struct Command {
  String name;   //コマンド文字列
  pFunc action;  //対応する関数へのポインタ
};
//----------------------------------
//コマンドと対応する関数のリスト
//----------------------------------
Command CommandList[] = {
  {"on" , &LedOn},
  {"off", &LedOff},
  {"reset", &Reset},
};
const int CommandCount = sizeof(CommandList) / sizeof(CommandList[0]); // コマンドの数
String SerialBuffer = "";//シリアル受信バッファ
//==================================================================
//初期設定
//==================================================================
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);//
  Serial.println("--- START PROGRAM ---");
}
//==================================================================
//メインループ
//==================================================================
void loop() {
  CommandCheck();
}
//-------------------------------------------------------------------------------
//シリアルコマンドのチェック
//  シリアル受信した文字を文字列に詰めていく、改行コードが来たらコマンド解析を実行
//-------------------------------------------------------------------------------
void CommandCheck() {
  while(Serial.available()>0){
    char rx = Serial.read();//1バイト読込
    Serial.write(rx);//エコーバック
    if (rx == '\n' || rx == '\r') {// 改行コードでコマンドパース実行
        CommandParse(SerialBuffer);
        SerialBuffer = ""; // バッファをクリア
        return;
    }
    SerialBuffer += rx; //バッファに追加
  }//while
}
//-------------------------------------------------------------------------------
//コマンド解析
//  受信コマンドとコマンドリストをループしながら比較、一致したら関数ポインタで関数を呼ぶ
//-------------------------------------------------------------------------------
void CommandParse(String command) {
  command.trim(); // 前後の空白を削除
  for (int i = 0; i < CommandCount; i++) {
    if (command.equalsIgnoreCase(CommandList[i].name)) {
      (void) (*CommandList[i].action)(); // 対応する関数を呼び出し
      return;
    }
  }//for
  Serial.println("Unknown command.");
}
```
AWSにおける基本的なインフラ構成について

# はじめに
この記事ではAWSにおけるいわゆるベストプラクティスに沿った構成について自分なりの考えをまとめてみようというものです。
インフラ経験がほぼない状態でインフラエンジニアを始めた身として、まずはじめにどのような構成が"良い"とされているのかを学ぶのが良いと考えて色々構成図と睨めっこをしていました。
そこで自分が得たことに関して軽くこの記事でまとめたいと思います。

# アプリケーションの構成
今回はよくあるwebアプリケーションサービスの構成を作るイメージで構成図を作成しました。

![オーソドックスな構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/546781/3df6e198-4ce6-dc5f-1c23-272de89c2210.png)

## 構成の内訳
ざっくりどのようなリソースがあるかを説明していきます。
ここでは各サービスの細かい説明はせず、何がこの構成に存在しているかとどんな役割を担うかを書いていきます。
- route53
    - DNSサービスとしてドメイン名の名前解決をします
    - また、トラフィックのルーティング制御も担うため、internetからの接続は最初にroute53を経由して適切なサービスへとルーティングされていきます

- CloudFront
    - CloudFrontは静的コンテンツの配信を行うものです
    - s3 bucketに静的ファイルを格納し、それを元に配信を行います

- Internet Gateway
    - VPC内のPrivate IPアドレスとPublic IPアドレスの変換を実行します
    - これを置くことにより、VPC内のリソースとインターネットの通信が可能になります

- Application Load Balancer
    - アプリケーション層の通信制御を行います
    - ヘルスチェックをクリアしたEC2にトラフィックを分散します

- Nat gateway
    - プライベートサブネットからの外向き通信を可能にします
    - 外部APIやアップデート時に使用されます

- Availability Zone
    - aws内でのインフラ設備の単位のこと

- Public Subnet
    - インターネットゲートウェイ経由で外部通信が可能なVPC内のネットワークです

- Private Subnet
    - 直接の外部通信が不可能であるVPC内のネットワークです
    - アプリケーション層とデータベース層で別々のsubnetを置くことでデータベース層を完全に隔離することができます


# この構成がベストプラクティスに沿っているかを考えてみる
どうしたらこれがベストプラクティスと言えるのか、それはもちろんサービスごとに異なるのでどのようなパターンでもこれが正解！というものはないと思っています。
ただ、どのような点を抑えればベストプラクティスに近づくのかという指標はあると思っています。それはAWS Well-Architectedフレームワークの5つの柱というものです。
AWS Well-Architectedフレームワークの5つの柱とは運用上の優秀性、セキュリティ、信頼性、パフォーマンス効率、コスト最適化の五つの要素のことであり、これに沿った設計をしているものがいわゆるベストプラクティスに近い構成なのではないかなと自分は考えています。
それでは、上記の構成におけるそれぞれの項目について考えていきます。
## 運用上の優秀性
この構成ではインフラストラクチャをコードとして管理しやすい設計になっています。
各コンポーネントが明確に分離され、責務が明確なため、運用面での優位性が高いと言えます。

例えば以下の点がこの柱に当てはまる構成のポイントと言えます。
- マルチAZ構成により計画的なメンテナンスができること
- ALBによるヘルスチェックで異常検知が自動化されること
- public, privateサブネットにリソースを分離することによりアクセス制御が用意であること

## 信頼性
信頼性ではサービス運営における要素のうち単一障害点を排除することが大切になると思います。
今回の構成の場合以下のような点がこの柱に当てはまる構成と言えます。
- 複数AZにまたがるリソース配置による冗長化
- ALBによる負荷分散
- RDSのマルチAZ構成による自動フェイルオーバーの実現
- CloudFrontによるコンテンツ配信の安定化

## セキュリティ
セキュリティの大事な考えである多層防御にどれくらい基づくかが構成を考える鍵になると思います。
今回行ったセキュリティ対策としては以下の点が挙げられます。
- サブネットの三層構造による境界防御
- 認証認可の一元管理が可能な設計

## パフォーマンス効率
リソースをいかに効率的に利用し要求されるパフォーマンスを実現できるかがここのポイントになります。
パフォーマンスを支える要素として今回取り込まれたのは以下です。
- CloudFrontによるコンテンツのキャッシュと高速配信
- ALBによる負荷分散
- データベース層を分離
- リージョン間のレイテンシー最適化が可能な構成

## コスト最適化
コスト設計は正直プロダクトによると思っていて今回の構成が必ずしも最適かと言われると一番自信がありません。
が、だいたいポイントは以下の点かなと思っているのでそれを示しておきます。
- マルチAZの過剰ではない冗長化
- NAT Gateway共有
- CloudFrontによるオリジンサーバーの負荷軽減
- 開発環境との分離が容易な構成

# この構成に拡張を加えるとすると？
この構成はあくまで基本構成であるので、実際はここを土台に色々生やしていくではないかないかなと思います。
そのアイデアをここに羅列してこの記事を締めたいと思います。

- セキュリティを強化したい場合
    - WAF
    - AWS Shield
    - GuardDuty
    - AWS System Manager Session Managerによる踏み台サーバー

- 可視性の向上
    - CloudWatch
    - AWS X-ray
    - CloudTrail

- パフォーマンス向上
    - ElastiCacheでDBのキャッシュを行う
    - RDS リードレプリカ
    - AutoScalingの導入

(追記)
最新だと6つの柱でしたね…
https://docs.aws.amazon.com/ja_jp/wellarchitected/2022-03-31/framework/the-pillars-of-the-framework.html
昔の5つの柱がなくなるわけではないと思うので、皆さんはサステナビリティについても考慮に入れた構成を考えてみてくださいmm
[stripe] 決済成功後はsuccess_urlプロパティだよ

## 筆者について
21歳、大学4年です。
大学は文系ですが、プログラミング歴はだいたい1年半くらいです。
<ul>
    <li>雀魂で麻雀始めたけど、ルール全く分からん</li>
    <li>国内サッカー好き(柏レイソルサポ・アウェイも行くよ)</li>
    <li>海外サッカー好き(プレミア・セリエAは毎節最低2試合は視聴)</li>
    <li>ゴルフの打ちっぱなしにハマり中(パター買わなきゃ)</li>
    <li>禁煙13日目</li>
    <li>週４ジム通い</li>
    <li>エナドリ中毒(頑張ってやめる)</li>
    <li>週１サウナ</li>
    <li>漫画・アニメ好き(最近は刃牙買いたい)</li>
    <li>ギター始めたい</li>
    <li>ジョージがモチベーター(いつもありがとう)</li>
</ul>
以上が僕の特徴です。
もしこれに共感したのであれば、気軽にコメントしてください、仲良くしましょう。

## stripe決済成功後
本記事では、正確にはStripe Checkoutを用いています。以下ドキュメントです。
https://docs.stripe.com/payments/checkout/how-checkout-works?locale=ja-JP

Stripe Checkoutについてドキュメントには以下のように書かれています。
>Stripe Checkout は事前構築済みの決済フォームであり、ビジネスはこれを使用してオンラインで決済を受け付けることができます。Checkout の構築済み機能を活用することで、開発期間の短縮が可能です。

これはかなり便利です。
UI・バックエンド構築の手間を省けます。決済機能とは大変複雑かつ重要度も高いため、エンジニアにとってはなるべく触れたくありません。
Airbnbの創業メンバー唯一のエンジニア、ネイサン・ブレチャージクが創業初期に構築した決済機能はエンジニア界隈で伝説となっています。

とまあ、Stripeは大変便利でメジャーです。

今回は以下のソースコードを取り上げています。
```
$checkout_session = $stripe->checkout->sessions->create([
    'payment_method_types' => ['card', 'konbini'],
    'payment_method_options' => [
        'konbini' => [
            'expires_after_days' => 7,
        ],
    ],
    'line_items' => [
        [
            'price_data' => [
                'currency' => 'jpy',
                'product_data' => ['name' => $item->name],
                'unit_amount' => $item->price,
            ],
            'quantity' => 1,
        ],
    ],
    'mode' => 'payment',
    'success_url' => "http://localhost/purchase/{$item_id}/success?user_id={$user_id}&amount={$amount}&sending_postcode={$sending_postcode}&sending_address={$sending_address}&sending_building={$sending_building}",
]);

```

Stripe Checkoutのセッションオブジェクトを生成する中で、色々なプロパティがありますが、全ての解説をするのは面倒なので省きます。

今回注目したいのはsuccess_urlプロパティです。
これは決済が成功した場合にリダイレクトするURLを指定しています。
いかにも脳筋パラメータなのでここは反省したいのですが、リダイレクト後も処理を追加したいため、値を渡すために、パラメータに値を含んでいます。

ここでネックになるのが住所と建物名のパラメータです。
ASCIIコードに日本語はないため、住所と建物名はエンコードする必要あります。
僕は雑魚学生エンジニアなので最初は戸惑いましたが、まあフツーに当たり前のことですよね。

APIのドキュメントを見ながら開発を進めること自体あまり経験していなかったので、かなり楽しかったです。

きつい時こそやらなきゃいけないことやろうぜ
アリババクラウド MVPストーリー：Fahd Mirza

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/alibaba-cloud-mvp-story-fahd-mirza_601833?spm=a2c65.11461433.0.0.4ee35355OkrVzm)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

# AIとクラウドのベテランリードエンジニアとしての旅

![Fahd_Mirza](https://yqintl.alicdn.com/f753b8443a17df680154134e0ebab6ed029174bf.png)

AIとクラウド分野で長年の経験を持ち、ビジネス転換を促進するためにクラウド計算とAIの力を活用することに私のキャリアを捧げてきました。クラウド移行、AI導入、コスト最適化などの幅広い実務経験を通じて、多くの企業が目覚ましい成果を上げることができました。知識と専門知識を共有することは私の情熱の一つであり、それがきっかけで<a href=https://www.youtube.com/@fahdmirza target=_blank>AIに特化したYouTubeチャンネル</a>を作成することになりました。このプラットフォームでは、アリババクラウドの最先端の大規模言語モデルやAIツールを深く掘り下げ、視聴者にその可能性と洞察を共有しています。

アリババクラウドとの私の旅は素晴らしいものであり、そのプラットフォームのスケーラビリティ、信頼性、革新的なソリューションに感銘を受けました。特に、自然言語処理(NLP)、コンピュータビジョン、機械学習を含むアリババクラウドのAIサービスと密接に取り組む機会を得ました。これらの技術により、ビジネス価値を高め顧客体験を改善する知能型ソリューションを開発することができました。また、アリババクラウドがオープンソースとコミュニティ主導のイニシアチブにコミットしていることで、活気あるエコシステムが形成され、開発者の協力とイノベーションが促進されています。

私の<a href=https://www.youtube.com/@fahdmirza target=_blank>YouTubeチャンネル</a>と<a href=https://fahdmirza.com/ target=_blank>ブログ</a>を通じて、アリババクラウドの革新的なソリューションの全可能性をビジネスに解き放つための力を与えることを目指しています。アリババクラウドが将来のAI革命を牽引する重要な役割を果たすと考えており、この動きに貢献できることに興奮しています。アリババクラウドの強固なインフラ、AI能力、そしてイノベーションへのコミットメントで共に、より知能的で自動化され、つながった世界を形作ることができる自信があります。

Qwenモデルを使用して、生成型AIに基づく様々な本番環境でのプロジェクトを1年以上続け、最高品質のオープンソースモデルの一つであることが証明されました。ビジュアルからコーディング、要約からRAGまで、Qwenモデルは品質によって私を常に驚かせます。最近では、人間のような思考を持つ内省機能を持つQwen QWQに魅了されています。これらすべてのモデルについては私のチャンネルで詳細に取り上げています。これらのQwenモデルは、生成型AIに基づいたあらゆる本番ユースケースにとって理想的だと考えています。

AI革命の阈りに立つ今、アリババクラウドMVPコミュニティの一員であり、イノベーションと知識共有に対する情熱を共有する同様の思考を持つ人々と一緒にいることに光栄を感じています。アリババクラウドとの私の旅を続けることを楽しみにしていますし、AIの新しい領域を探索し、企業がこれらの変革的技術の力を引き出す手助けをすることをお待ちしています。

## おわりに

物語を共有させていただける機会に感謝いたします！アリババクラウドコミュニティへの貢献を続けて、AI革命を進めるために尽力してまいります。注意事項：ここに述べられている意見は参考にすることを目的としており、必ずしもアリババクラウドの公式見解を代表するものではありません。
アリババクラウドがアジア各地の産業界でAIの強化を推進

> 本記事は[こちらのブログ](https://www.alibabacloud.com/blog/alibaba-cloud-drives-ai-enhancements-across-industries-in-asia_601832?spm=a2c65.11461433.0.0.4ee35355OkrVzm)を参考にしています。
> 翻訳にはアリババクラウドの[ModelStudio](https://www.alibabacloud.com/en/product/modelstudio)([Qwen](https://www.alibabacloud.com/en/solutions/generative-ai/qwen))を使用しております。

#### 顧客が技術開発から医療まで、アリババクラウドのインフラとAIソリューションを活用して産業体験を変革

中国・杭州、2024年12月9日 – AI市場の需要が止まらない中、アリババグループのデジタル技術と知能の基盤であるアリババクラウドは、技術開発からイメージング、旅行、美容、医療まで多様な産業で技術革新を先導し続けています。強力な「Cloud + AI」戦略に基づき、アリババクラウドは外部顧客からの収益に大幅な増加を見せる結果となりました。この成長には、パブリッククラウドサービスの二桁増加と、AI関連製品収益の五分期連続の三位数YoY成長も含まれており、[最新の9月四半期の決算](https://www.alizila.com/alibaba-delivers-solid-q2-results-with-expanding-user-base-and-accelerated-cloud-growth/)によれば顕著です。

2024年、企業はアリババクラウドの最先端のクラウドソリューションを使用して、自社の運営や顧客エンゲージメント戦略を再構築しています。AIインフラの刷新から独自のQwen系列の大規模言語モデル、高度なAI分析まで、これらの技術と製品は単なる業務ツールを超えて進化し、アジア全域で顧客体験と業務効率性を向上させるデジタルトランスフォーメーションの触媒となっています。

![アリババクラウドの独自LLMシリーズQwenが産業体験の変革を支援](https://img.alicdn.com/imgextra/i2/O1CN01ViA9b61MHpTHP6IDB_!!6000000001410-0-tps-8000-5284.jpg)

アリババクラウドの国際ビジネス部長であるユエン・セリナ氏は、「当社の安定したクラウドインフラとAI提供が、多様な産業の顧客と共に2024年にさらに変革を促進することを喜ばしく思います。アジア最大のクラウドサービスプロバイダーとして、当社はお客様が自社の業務を改善し、消費者とのつながりを深めることができるように支援し続けます。また、AIとクラウド技術の可能性をすべての企業に引き出すため、エコシステムパートナーと協力して取り組んでいます。」

### 日本語LLM開発におけるイノベーションの支援

日本では、AI民主化を目指す東京大学のスピンオフ企業であるライトブルーが、画像解析や自然言語処理などのAIソリューションを開発しており、アリババクラウドのQwenを活用して日本語LLMの開発をサポートしています。アリババクラウドの高度なアーキテクチャとトレーニング能力を活用することで、同社は特に日本語を含む東アジア言語に対するサービスを強化しました。また、アリババクラウドのエラスティックコンピュートサービス、サーバーロードバランサー、オブジェクトストレージサービスなど、効率的で安全なクラウドサービスも活用しています。この提携は、アリババクラウドが技術スタートアップのイノベーション目標を支援するというコミットメントを示しています。

ライトブルーの田口俊一ディレクター兼シニア研究員は、「Qwenは日本語をサポートする最も優れたパブリックオプションであり、当社のLLMをQwenで微調整することで、精度が大幅に向上しました。この協力により、当社のAIソリューションが向上し、東アジアでの技術民主化のミッションが前進しました。」

### 柔軟性と画質を革新した画像撮影

マレーシアでは、革新的な写真イメージングソリューションを提供するPictureworksが、アリババクラウドの包括的なAIとクラウドテクノロジーを活用して、高解像度画像の撮影の柔軟性と品質を革新しています。この提携はアジアの主要観光スポット7か所で成功実装され、さらなるプロジェクトが進行中です。特に、アリババクラウドの安定かつセキュアな技術を用いて、香港の受賞歴のあるテーマパークで15万枚以上の写真を制作しました。提供された主要ソリューションには、人工知能プラットフォーム（PAI）、ファンクションコンピュート、オブジェクトストレージサービス（OSS）が含まれます。

PictureworksのCEOであるタセ・シャロン氏は、「アリババクラウドの技術によって、Pictureworksでの画像撮影の手法が根本的に変化しました。従来のグリーンスクリーンのようなセットアップに頼らずに、高品質な写真を生み出すことができる柔軟性を持っています。この革新は、より本物らしさとダイナミズムを持つ写真的な思い出を創出することで、顧客体験を向上させます。」

### 旅行体験の変革とコスト削減

シンガポールのイノベーティブなB2B旅行技術プロバイダーであるAtlasは、アリババクラウドのインフラとAIの進歩を活用し、世界中の旅行セラーと格安航空会社にサービスを提供しています。アリババクラウドのLLM Qwenとモデルスタジオプラットフォームを使用して、24時間体制で顧客サポートを行うデジタルチャットボットを実装しました。アトラスは2021年からアリババクラウドと提携しており、これまでに運営コストを45％削減しました。この協力により、Atlasはシンガポールのスタートアップから業界の指導者に成長し、最先端の旅行プラットフォームで格安航空市場を変革しています。

Atlasの創業者兼CEOであるリー・メアリー氏は、「アリババクラウドのスケーラブルで安全なインフラが、当社の急速な拡大において重要な役割を果たしました。当社は主に開発者フレンドリーなUIに惹かれました。提携は
アリババクラウドの大規模モデル「Qwen」とハレオンが蓄積した長期の内部知識ベースを組み合わせることで、私たちは消費者一人ひとりに合わせた、より適切な栄養と健康に関するアドバイスを提供する一対一のサービスを提供しています」と、ハレオン・グレーターチャイナのデジタル＆テック責任者、劉炳氏は述べました。
Opensearchのreindex APIがエラーで終わらない問題を解消する

## 背景
Opensearchのパフォーマンスが悪化したため、reindex APIを利用して大きくなりすぎたシャードの分割を行いました。
アドベントカレンダー参加を兼ねて、最終的に安定して実行できた内容を備忘録的に残してあります。

## 目的
シャードの分割をされる際にエラーが出てうまくいかなかった際、
一助にしていただけると幸いです。

## 前提条件
データ容量　40GiB
データ件数　200万件
移行前シャード数　プライマリ:1 / レプリカ:3で安定稼働

## 内容
以下、時系列順の作業内容です。

### １．専用マスターノードの追加
4xlargeのデータノードを2台追加するよりも、
largeの専用マスターノードを3台追加する方がクラスタ全体で安定します。

データノードが10台以下の環境では不要と思っていましたが、
高負荷な状況ではコスパよくほぼ必須です。

### ２．データノードの追加
既存のindexingやsearchがreindexに干渉しないよう、
移行後のシャード数に合わせたデータノードを追加します。
シャード数2のindexへ移行する場合、単純に2台追加します。

中身は空の状態で一時的にシャード数が不均衡になり、
前述の専用マスターノードがいないと負荷が跳ね上がります。

### ３．移行先indexの作成
移行先のindexを作成します。
bulkのコストを抑えるため、自動更新の停止とレプリカ数の調整を行います。
```bash
PUT {index_dest}/_settings
{
  "index": {
    "refresh_interval": -1,
    "number_of_replicas": 0
  }
}
```

### ４．シャード割り当ての確認
移行先のindexが割り当てられたノードに、負荷の高いindexが割り当てられていないことを確認します。
シャードの不均衡がなく、既存処理のリクエストが対象ノードへ影響しない状態が理想です。
完全に倉庫番です。

### ５．データ容量を1GiB削減
B/Gデプロイを強制させてきれいなインスタンスに入れ替えます。

### ６．reindexの実行
scrollタイムアウトはデフォルトで5分です。
少なすぎるためscrollを指定して調整します。

バッチあたりのドキュメント数はデフォルトで1000です。
多すぎるためsizeを指定して調整します。

requests_per_secondはバッチ実行後に秒間平均で指定した値になるまで次のバッチを遅延します。
デフォルトは-1（遅延しない）です。
```bash
POST _reindex?wait_for_completion=false&scroll=1h&requests_per_second=50
{
  "conflicts": "proceed", 
  "source": {
    "index": "{index_source}",
    "size": 100
  },
  "dest": {
    "index": "{index_dest}"
  }
}
```

### ７．負荷に合わせて実行速度調整
事前に負荷のかかる時間帯が分かっている場合、rethrottleでバッチ実行間隔を調整します。
```bash
POST _reindex/{task_id}/_rethrottle?requests_per_second=1
```
task_idはreindexのレスポンスを保存するかtask APIから取得します。
```bash
GET _tasks?detailed=true&actions=indices:data/write/reindex
```

### ８．可能な限りリクエストを停止する
reindexと同時にリクエストを流す場合、全体の負荷が上がるだけでなく実行自体も遅くなります。
可能であればメンテナンス計画し、難しい場合でも流量を抑えると効果的です。


### ９．それでもエラーで停止したら
公式のパフォーマンストラブル解決記事が、内容がまとまっていて原因調査の際に非常に参考になります！

https://aws.amazon.com/jp/blogs/news/opensearch-performance-troubleshooting-guide/

# 採用PR
弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください！

https://hrmos.co/pages/vivion/jobs/0000191