OmniAICreator/Qiita-1.07M huggingface dataset:
Reactのmemoの基本を抑える

## はじめに
Reactのコンポーネントは、親コンポーネントが再レンダリングされると、子コンポーネントも再レンダリングされます。

しかし、必要もないのに子コンポーネントまで再レンダリングされると、パフォーマンスに影響が出る場合もあります。

その時に使えるのが、Reactのmemoです。

本記事ではmemoの基本的な使い方について解説します。

## memoとは
### 概要
memoはReactのAPIです。`useMemo`という似た処理がありますが、こちらはフックです。
memoはフックではないので、コンポーネントのトップレベル以外の場所でも使用できます。

コンポーネントをmemoでラップすると、その結果が保存されます。
これをメモ化といいます。

コンポーネントのpropsが変化していない場合には、メモ化して取っておいたコンポーネントが使われます。

つまり、親コンポーネントが再レンダリングされても、自身は再レンダリングを行わないません。
コンポーネントに渡されたpropsが変化した場合のみ、新しくコンポーネントをレンダリングします。

### 基本形
```react
memo(Component, arePropsEqual?) 
```
#### 引数
##### Component
任意のReactコンポーネントです。
メモ化したいコンポーネントを指定します。

##### arePropsEqual
省略可能であり、基本的に自分で指定することはないので割愛します。

詳しく知りたい方は以下の公式サイトの説明を参照してください。

https://ja.react.dev/reference/react/memo#parameters

#### 戻り値
第1引数に指定したコンポーネントをメモ化したコンポーネントです。
ほぼ完全に同一のコンポーネントが戻り値として渡されます。
propsの値が変わっていない場合、再レンダリングしないというのが唯一の相違点です。

### 使用例
以下のようなデモを作成しました。
* 親コンポーネントがCount、子コンポーネントが入力フィールドの値を表示する
* Count、入力フィールドの値は親コンポーネントで定義したstate
* 親コンポーネントのレンダリング時は「Rendering Parent」をコンソール出力
* 子コンポーネントのレンダリング時は「Rendering Child - text」を出力

![memo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251137/78ce8cd1-b10a-2dcc-f0b6-0287c67f2445.gif)

このデモを確認するとわかるように、
「Increment Count」ボタンを押下すると、親コンポーネントのみが再レンダリングされます。
入力フィールドの値が変化すると、親と子のどちらのコンポーネントも再レンダリングされます。
つまり、子コンポーネントの再レンダリングがされない場合があるということです。

これがmemoによる効果です。

実際のコードを確認します。
```react
import { useState, memo } from "react";

// メモ化された子コンポーネント
const ChildComponent = memo(({ name }: { name: string }) => {
  console.log(`Rendering Child - ${name}`);
  return <div>{name}</div>;
});

// 親コンポーネント
const ParentComponent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("John");

  console.log("Rendering Parent");

  return (
    <div>
      <h3>Parent Component</h3>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Change name"
      />
      <ChildComponent name={name} />
    </div>
  );
};

export default ParentComponent;
```
`memo`を使用して、ChildComponentをメモ化しています。
ParentComponentでは、メモ化したChildComponentを使用しています。

ChildComponentは「name」を引数として受け取っています。
つまり、「name」が変更されない限りは、子コンポーネントの再レンダリングがされず、メモ化して保存されていたコンポーネントが使われることになります。

これにより、Countが変化しても子コンポーネントは再レンダリングされませんでした。

### memo使用時の注意点
memoは何でもかんでも使えばよい、というものではありません。
使いすぎると、逆にパフォーマンスの低下に繋がります。

今回の例で示したように、入力フィールドを子コンポーネントに渡しており、propsの値が毎度変わるような場合にはmemoを使用するメリットはあまりありません。

子コンポーネントに渡される値がほぼ同一で、かつ頻繁に再レンダリングがされるような場合に有効です。

### 発展的なmemo
memoとよくセットで使われるのが、`useMemo`と`useCallback`というフックです。
`useMemo`は値をメモ化し、`useCallback`は関数をメモ化します。

これらを組み合わせることで、よりmemoは力を発揮します。

長くなるので本記事では割愛しますが、気になる方は調べてみてください。

## まとめ
`memo`というReactの機能について紹介しました。
業務でみたことがあるものの、正しい理解ができていなかったので、基本をしっかり抑えることができてよかったです。
モノレポ構成でReactNativeとNext.jsを実装しようとしたら、ReactNativeの環境構築でつまづいたので違いを考えた件

##  はじめに伝えたいこと
個人開発でNext.jsによるWEBアプリとReact Native(Expo)によるネイティブアプリを実装するにあたり、モノレポで構築することとしました。
その際にReact Nativeの環境構築でいきなり手詰まりをしてしまったので、その内容を伝えるとともに、モノレポは思わぬエラーを発生するリスクがあることをお伝えしたく記事にしました。

## つまづいたこと
React Nativeの実装の際、公式の手順に従ってモノレポ対応に必要なmetro.config.jsを追加したのですが、以下のようなエラーを延々と吐き続けるというエラーに遭遇しました。
![スクリーンショット 2024-09-14 11.49.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2574198/5d17e67d-3c07-22f8-d5de-6fd50825abc7.png)

解決法は
 [monorepo環境でExpoを使っているときに出る Invariant Violation: No callback found with cbID xxxx and callID xxxx for module <unknown>. Args: '[xxxxx]', js engine: hermes を解消する](https://www.deg84.com/expo-monorepo-invariant-violation-no-callback-found-hermes/)
を参考にmetro.config.jsに「config.resolver.disableHierarchicalLookup = true;」を追加することとわかったのでそれで対処できました。

## 何が違ったのか
一言で言えばJSのモジュールバンドラーの性能の違いによるものであるようです。
### Next.js
webpackが使われていますが、webpackではモジュールなどの依存関係を再帰的に検索をするので、特に追加の設定をせずともモノレポでもエラーはしなかった。（近々tubropackになると思われます）
### React Native
metroが使われていますが、webpackと異なり再帰的な解決を行わないため、metro.config.jsファイルで明示する必要があるようです。
  （公式のテンプレートでなぜつまづきポイントの明示がなかったのかは不明。常識だから？）

## 今回のモノレポ構成について改めて考えてみたこと
今回の件を受けて、個人的なモノレポへの見解を整理しました。
### モノレポ採用の主な理由

- UIコンポーネント、エンドポイント、環境変数などの共通化
- 開発効率の向上

### メリット

- コードの再利用性向上
- 一貫性のある開発環境の構築

### デメリット

- 異なるフレームワークを統合することによる思わぬ問題発生のリスク
- 設定の複雑化


## 最後に
実プロダクトにおいてもNext.jsによるWEBアプリとReact Nativeによるネイティブアプリという組み合わせは今後益々増えていくかと思っています。
その際に今回のようにモノレポを採用するか否かといった議論になり得ると思いますが、今回のような思わぬつまづきに遭遇し得るということも念頭に置いておくと良いかと思います。
今回は思わぬところでつまづき時間を要しましたが、色々調べて再考するにはいい機会だったということにしておきます。
投稿 77 Docker Compose 2024/09/15

本日の勉強時間　3H

通常、Dockerのコンテナは複数ある。
複数のコンテナは互いに連携している。

docker compose.yml を使う。雛形で書くことが多い。

docker composeを使うことで、
・フロントエンドのコンテナ
・バックエンドのコンテナ
・ミドルウェアのコンテナ
連携することでアプリを作る、っていうのがよくある流れ。
MacBookAir に BlackArch Linux をインストール

# 主要ポイント
　（略）
 
## 前提
　iso
　　https://blackarch.org/downloads.html#install-iso 
　　　Image名:BlackArch Linux 64 bit Full ISO　(version: 2023.04.01)
　PC
　　macbook air (11inch)

## checksumを確認する
```
$ openssl sha1 [.iso filename]
```
↑出力の情報がWebサイト記載のチェックサム情報と一致することを確認する

## インストール用USBを作成する
```
$ sudo dd bs=512M status=progress if=file.iso of=/dev/sdX
```

## USBから起動→rootログイン右クリックからTerminalを起動→blackarch-install
```
[blackarch ~ ]# lsblk
[blackarch ~ ]# blackarch-install
　Choose an installation mode:2
 　Install from BlackArch Full-ISO (offline)
　Choose a devece: sda
 　lsblkの出力などを参考にして選択する
　Install BlackArch Linux with Windows/Other OS: n
　Create partitions with cfdisk (root and boot, optional swap): y
　　Start with an in-memory zeroed partition table: y
　　Select label type: gpt
　　Disk: /dev/sda　のパーティションについて、下記のように進める
　　Free space　にカーソルを合わせて　New→512M→Type→EFI System と指定して /dev/sda1 を作成
　　Free space　にカーソルを合わせて　New→16G→Type→Linux swap と指定して /dev/sda2 を作成
　　Free space　にカーソルを合わせて　New→残り全て(449.4G) と指定して /dev/sda3 を作成
　　Write→Quit　と進める
　Full encrpted root: n
　EFI System partition (/dev/sdaX): /dev/sda1
　Root partition (/dev/sdaX): /dev/sda3
　Choose a filesystem to use in root partition (ext2, ext3, ext4, btrfs)?: ext4
　Swap partition (/dev/sdaX - empty for now): /dev/sda2
[blackarch ~ ]# shutdown -h now
```

## 必要に応じて、sound関連を調整
```
[blackarch ~ ]# /etc/asound.conf
  defaults.pcm.card 1
  defaults.pcm.device 0
  (defaults.ctl.card 0)
```

## 必要に応じて、Wifi関連を調整
```
[blackarch ~ ]# NetworkManager
[blackarch ~ ]$ nmcli device wifi list
[blackarch ~ ]$ nmcli device wifi connect [ssid] password [password] ifname wlan0
([blackarch ~ ]$ nmcli device status)
([blackarch ~ ]$ nmcli dev disconnect wlan0)
```

# サイトポリシー
当ページをご利用いただくにあたっては、以下の事項に全て同意いただけた場合に限り、ご利用いただけます。
なお、当ページの利用規定を予告なしに変更する場合がありますので、ご了承ください。

### 本ページの目的と利用者責任について
当ページは関連情報の整理を主目的としています。
当ページに掲載された内容のご活用は、ご活用者の責任において行われるものとします。
当ページで提供する情報の内容について、掲載した情報の内容が正確であるか？有用であるか？更新時期が適切かどうか？などを一切保証をするものではありません。
また、掲載された情報をご利用いただいた結果、万一、ご利用者が何らかのトラブル、被害、損失、損害等が発生したとしても、一切責任を負うものではありません。
なお、当ページに掲載されている情報等につきましては、予告なく変更、又は削除されることがありますので、あらかじめご了承ください。
MacBookのキーボード入力で¥を\に変換する方法

# はじめに
MacBookの初期設定でキーボードの¥を\に入力を変更するのに苦労したので、忘備録として残しておく。

# 環境
MacBook M1 (2020)
MacOS Sonoma 14.6.1

# 解決方法
[設定]->[キーボード]からキーボードの設定画面を開く。
キーボード設定の中からテキスト入力の入力ソースを探し[編集]を押す。
![2024-09-15 22.59の画像.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882787/7a3452e4-0934-041c-9176-93fa337d3396.jpeg)


入力ソースで[日本語 - ローマ字入力]を選択し、["¥"で入力する文字]を[\(バックススラッシュ)]にする。
![スクリーンショット 2024-09-15 22.54.17.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882787/a68ded24-2966-10d2-9b91-04b7e6546ae4.jpeg)


[日本語 - ローマ字入力]の入力モードで[英字]を選択する。
入力ソースから[ABC]を削除する。
![スクリーンショット 2024-09-15 22.54.31.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882787/6acf52c3-9d48-ff4d-31f3-0c46ed127b95.jpeg)

最後に[完了]を押すと変更が保存される。

# 終わりに
ABCを消さないと変更が反映されないことに気づくのに少し時間がかかったので、参考になれば幸いです。
ESP32のWiFi出力で使用する電流を舐めていた話。

今回ESP32-C3を使用して製品開発を行った。

しかし、プログラムをインストールして、WiFi.beginをするとESP32がリスタートする。。。
だいたいこういう時は、電源系が不安定になっている時だ。

以下の感じで不適合調査を行った。
・WiFiが起動することで電波が発生し、電源ラインに影響を与えていないか。
・プログラムに間違いはないか
・配線に間違いはないか
・ESP32-C3の初期値に設定しなければいけない設定をできていない？
etc

しかし以上の項目は全て問題なかった。

結果を先にいうとUSBからの5Vが電圧降下を起こしていた。

多分だがESP32がWifiを起動するタイミングで大きな電流を消費する。
その時USBケーブルDIPキットに使用されているポリヒューズが反応して
電源供給を停止し、再起動が行われているようだ。
（400mA以上消費する場合もあるみたい。。。）

具体的には以下

## ハードウェア
・ESP32-C3
・ブレッドボード用マイクロBメスUSBコネクターDIP化キット
https://akizukidenshi.com/catalog/g/g106656/
・専用基板

## ソフトウェア
```c
#include <WiFi.h>

const char SSID[] = "testSSID" ;
const char PASSWORD[] = "testest";

WiFiServer server(80);
byte pins[] = {0, 1, 3, 10, 7, 6,  4, 5, 8};

void setup() {
  for (int i = 0; i < sizeof(pins); i++) {
    pinMode(pins[i], OUTPUT);
  }
  
  pinMode(4, OUTPUT);

  Serial.begin(115200);
  delay(3000);

  WiFi.begin(SSID, PASSWORD);    //ここでエラーが発生して再起動をしていた
  Serial.print("WiFi connecting");

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(100);
  }

  Serial.println(" connected");
}

// the loop function runs over and over again forever
void loop() {

}
```

## 対策
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/2ef6639c-0b07-3381-1971-5d2ce68b5922.png)

470uFの電解コンデンサを設置したら、再起動をしなくなった。
多分こんなに大きなコンデンサは、不要だと思う。
USBコネクタDIP化キットのヒューズが悪さをしているんだと思うが、
それはあとから調査しようと思う。
多分直接PCからヒューズを通さず接続できれば電解コンデンサも
不要だとは思うが、
とりあえずメモということで。

なお今回は以下の記事を参考にさせて頂き、無事今回の問題を解決することができました。
有難うございました。
https://bokunimo.net/blog/esp/3949/#5V%E5%85%A5%E5%8A%9B%E9%83%A8%E3%81%AB%E3%82%B3%E3%83%B3%E3%83%87%E3%83%B3%E3%82%B5%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B
統計検定2級　難易度が高い過去問2018年6月問13　解説

私がZennで記事にしていた内容の転写です。

---
この記事は統計検定2級　2018年6月の問13に関する解説記事です。統計検定2級合格を目指す方向けの記事となります。

## 前提
この問いは第一の過誤、第二の過誤、検定力を単なる文章だけで理解していないかどうかの理解力を問う問題です。これに類する問題は過去問でも比較的多くないので、この問題できっちり理解することが合格への一歩となりそうです。

第一の過誤：
本当は帰無仮説$H_0$を棄却できない（帰無仮説$H_0$が正しい）のに、誤って帰無仮説$H_0$を棄却する（対立仮説$H_1$が正しい）確率。通称$α$で有意水準とも呼びます。

第二の過誤：
本当は帰無仮説$H_0$を棄却できる（対立仮説$H_1$が正しい）のに、誤って帰無仮説$H_0$を棄却出来ない（帰無仮説$H_0$が正しい）とする確率。通称$β$と表記します。

検定力：
帰無仮説$H_0$を棄却できる（対立仮説$H_1$が正しい）要件を正しく棄却する確率。通称$1-β$で計算します。

## 問13(1)
棄却域を$X≦3$とします。この設定によって$H_0$が正しい時の分布Pの確率、$H_1$が正しい時の分布Pの確率を求めます。

$H_0$の分布を考えると、棄却できる領域の確率を計算するので、

$$
0.1+0.1+0.1=0.3
$$

です。

棄却域を$X≦3$と決めているので、$H_1$は$X>3$の領域の確率を計算します。

$$
0.05+0.05+0=0.1
$$

です。

ところで、第一の過誤は$H_0$が正しい条件において、誤って$H_0$を棄却してしまう確率です。いいかえると、$H_0$の条件において、棄却域を$X≦3$で棄却してしまう条件です。
&nbsp;
この「$H_0$が正しい条件において、誤って$H_0$を棄却してしまう確率」という風に第一の過誤の意味と求められている問題を正しく理解できるか？が重要です。
したがって、

$$
α=0.3
$$

また、第二の過誤は、$H_1$が正しい条件において、誤って$H_0$を受け入れる確率です。いいかえると、$H_1$の条件において、棄却域を$X≦3$で棄却しない条件です。これは$X>3$の条件ですので、

$$
β=0.1
$$

です。
&nbsp;
したがって、検出力は

$$
1-β=0.9
$$

です。
この結果をもとに、正しい選択肢を選ぶと、④となります。


## 問13(2)

検定条件を3つ考えたときにそれぞれがどういう関係になっているかを理解する問題です。
### 検定I

$$
α=0.3
$$

$$
β=0.1
$$

$$
検定力=0.9
$$

### 検定II
検定Iが棄却域を$X≦3$としていたのに対し、検定IIは棄却域を$X≦2$とした条件です。検定Iと同様に考えると、与えられている同じ確率分布表から計算して、

$$
α=0.1+0.1=0.2
$$

$$
β=0.2+0.05+0.05+0=0.3
$$

$$
検定力=1-0.3=0.7
$$

### 検定III
検定Iおよび検定IIが棄却域を$X≦3, X≦2$としていたのに対し、検定IIIは棄却域を$X=6$とした条件です。この時棄却しない域は$X\neq6$です。検定I, IIと同様に考えると、与えられている同じ確率分布表から計算して、

$$
α=0.3
$$

$$
β=1 
$$

$$
検定力=1-1=0
$$

### 検定I,II,IIIの比較

|      | 検定I | 検定II | 検定III | 
| ---- | ----- | ------ | ------- | 
| α   | 0.3   | 0.2    | 0.3     | 
| β   | 0.1   | 0.3    | 1       | 
| 1-β | 0.9   | 0.7    | 0       | 

この表をみて、正しい選択肢を選ぶと②となります。


## まとめ

「帰無仮説$H_0$を棄却できない（帰無仮説$H_0$が正しい）のに、誤って帰無仮説$H_0$を棄却する（対立仮説$H_1$が正しい）確率」
&nbsp;
この文章をいいかえると、
&nbsp;
帰無仮説$H_0$を棄却できない（帰無仮説$H_0$が正しい）のに　→　$H_0$の確率分布表において、
誤って帰無仮説$H_0$を棄却する（対立仮説$H_1$が正しい）確率　→　棄却域の確率が発生する
&nbsp;
&nbsp;
「帰無仮説$H_0$を棄却できる（対立仮説$H_1$が正しい）のに、誤って帰無仮説$H_0$を棄却出来ない（帰無仮説$H_0$が正しい）とする確率」
&nbsp;
この文章をいいかえると、
&nbsp;
帰無仮説$H_0$を棄却できる（対立仮説$H_1$が正しい）のに　→　$H_1$の確率分布表において、
誤って帰無仮説$H_0$を棄却出来ない（帰無仮説$H_0$が正しい）とする確率　→　棄却域ではない確率が発生する
&nbsp;
&nbsp;
第一の過誤、第二の過誤ともに、文章全体の構成としては**前半は本来どちらの仮説が正しいか**を示していて、**後半は誤って棄却する/棄却しない確率**を示しています。
QEMU 9.1.0をビルドしてみた

# はじめに

2024/09/03（ドラえもんの誕生日ですね）にQEMU 9.1.0がリリースされていたので、ビルドしてみました。

https://wiki.qemu.org/ChangeLog/9.1

# 評価環境
## Ubuntu Server 24.04
```
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=24.04
DISTRIB_CODENAME=noble
DISTRIB_DESCRIPTION="Ubuntu 24.04.1 LTS"
```

# QEMUのビルドに必要なパッケージのインストール
1. 以下のパッケージをインストールしてください。
   ```sh
   sudo apt install -y \
   cmake \
   curl \
   gcc \
   git \
   gnutls-bin \
   libcapstone-dev \
   libepoxy-dev \
   libfdt-dev \
   libglib2.0-dev \
   libglusterfs-dev \
   libsdl2-2.0-0 \
   libsdl2-dev \
   libsdl2-image-dev \
   libssh-dev \
   ninja-build \
   python3 \
   python3-pip \
   python3-sphinx \
   python3-sphinx-rtd-theme \
   xz-utils   
   ```

# QEMUのビルド
1. qemu-9.1.0.tar.xzをダウンロードしてください。
   ```sh
   curl -O https://download.qemu.org/qemu-9.1.0.tar.xz
   ```
1. ファイルを解凍してください。
   ```sh
   tar Jxvf qemu-9.1.0.tar.xz
   ```
1. qemu-9.1.0のディレクトリに移動してください。
   ```sh
   cd qemu-9.1.0
   ```
1. 以下のコマンドを実行してください。
   ```sh
   ./configure --target-list=aarch64-softmmu
   ```
1. ビルドを実行してください。
   ```sh
   make
   ```
1. buildディレクトリに移動してください。
   ```sh
   cd build
   ```
1. バージョンを確認してください。
   ```
   $ ./qemu-system-aarch64 --version 
   QEMU emulator version 9.1.0
   Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers
   ```

# さいごに
本記事ではQEMU 9.1.0のビルドを試してみました。

# 余談
余談ですが、これまでUbuntu Server 20.04.6 LTSでqemuのビルドをしていたのですが、configure実行時に以下のエラーが出ました。このため、本記事ではUbuntu Server 24.04.1 LTSを使いました。
```
$ ./configure --target-list=aarch64-softmmu
(snip)
../meson.build:926:10: ERROR: Dependency lookup for glib-2.0 with method 'pkgconfig' failed: Invalid version, need 'glib-2.0' ['>=2.66.0'] found '2.64.6'.

A full log can be found at 
(snip)
ERROR: meson setup failed
```
Go lang 勉強メモ

# 参考サイト
* [Goの初心者が見ると幸せになれる場所　#golang #Go - Qiita](https://qiita.com/tenntenn/items/0e33a4959250d1a55045)
* [A Tour of Go (公式チュートリアル)](https://go-tour-jp.appspot.com/welcome/1)

# day1

* プログラムは main パッケージから開始 ([*](https://go-tour-jp.appspot.com/basics/1))
* 規約。インポートパスが "math/rand" のパッケージは、 package rand ステートメントで始まる ([*](https://go-tour-jp.appspot.com/basics/1))
* import の書き方. 1の方が良いスタイル ([*](https://go-tour-jp.appspot.com/basics/2))
```go
import (
	"fmt"
	"math"
)
```
```go
import "fmt"
import "math"
```

* Goでは、最初の文字が大文字で始まる名前は、外部のパッケージから参照できる ([*](https://go-tour-jp.appspot.com/basics/3))
    * `fmt.Println`
    * `math.Pi`
* 関数の引数での型は、変数の後ろにつく ([*](https://go-tour-jp.appspot.com/basics/4))
    * `func add(x int, y int) int {`
* 同じ型の省略版 ([*](https://go-tour-jp.appspot.com/basics/5))
    * `func add(x, y int) int {`   
* 関数で複数の戻り値を返す ([*](https://go-tour-jp.appspot.com/basics/6))
```go
func swap(x, y string) (string, string) {
	return y, x
}
```

* 戻り値に変数をつけることができる。returnに指定不要。短い関数でのみ利用すべき。  ([*](https://go-tour-jp.appspot.com/basics/7))
```go
func split(sum int) (x, y int) {
	x = sum * 4 / 9
	y = sum - x
	return
}
```

# day2

* 変数宣言  ([*](https://go-tour-jp.appspot.com/basics/8))
    * `var c, python, java bool`
    * `var i int`
        * 頭でvar宣言。複数はカンマ区切り。お尻で型宣言。
* 変数の初期化  ([*](https://go-tour-jp.appspot.com/basics/9))
    * `var i, j int = 1, 2`
        * 型の後ろ
    * `var c, python, java = true, false, "no!"`
        * 型宣言省略で初期値セット。初期値の型になる

# day3

* 関数内でのみ、:= でつなぐとvar省略可能  ([*](https://go-tour-jp.appspot.com/basics/10))
```go
func main() {
	var i, j int = 1, 2
	k := 3
	c, python, java := true, false, "no!"
}
```
* 暗黙初期値 ([*](https://go-tour-jp.appspot.com/basics/12))
  * 数値型(int,floatなど): 0
  * bool型: false
  * string型: "" (空文字列( empty string ))
* 型変換 ([*](https://go-tour-jp.appspot.com/basics/13))
```go
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

// or

i := 42
f := float64(i)
u := uint(f)
```
* コメント
```go
// 1行コメント

/*
複数行1
複数行コメント2
*/
```
OllamaとOpen WebUIをまとめて立ち上げる

# 概要
- ホストOSに`ollama`を直接インストールせず`ollama`サーバーと`open-webui`サーバーをdockerで同時に立ち上げるためのリポジトリ。
- gpt-4oで作成しました。
- docker-compose化しました。
- ポートを変更した場合は、`curl`コマンドのURLも適宜変更してください。
- GPUメモリ8GBのWindows 11でWSLを使用し、phi-3とllama3.1モデルが問題なく動作することを確認しました。

# 前提条件

- DockerとDocker Composeがインストールされていること。

# セットアップ手順
1. リポジトリをクローン
    ```
    git clone https://github.com/marcosanyo/ollama-webui-stack.git
    cd ollama-webui-stack
    ```
    
    or 下記`docker-compose.yaml`と`.env`をコピペして作成
    ```yaml: docker-compose.yaml
    version: '3.8'
    services:
      ollama:
        image: ollama/ollama:latest
        container_name: ollama
        ports:
          - "${OLLAMA_PORT}:11434"
        volumes:
          - ollama:/root/.ollama
        deploy:
          resources:
            reservations:
              devices:
                - driver: nvidia
                  count: all
                  capabilities: [gpu]
        restart: always
        
      open-webui:
        image: ghcr.io/open-webui/open-webui:main
        container_name: open-webui
        ports:
          - "${OPEN_WEBUI_PORT}:8080"
        environment:
          - OLLAMA_BASE_URL=http://ollama:11434
        volumes:
          - open-webui:/app/backend/data
        depends_on:
          - ollama
        restart: always
    
    volumes:
      ollama:
      open-webui:
      ```

    ```sh: .env
    # Open WebUI port
    OPEN_WEBUI_PORT=3000
    
    # Ollama port
    OLLAMA_PORT=11434
    ```

1. `.env`ファイルを編集して、使用するポートを設定します。デフォルトの設定は以下の通りです。

   ```env
   # Open WebUI port
   OPEN_WEBUI_PORT=3000

   # Ollama port
   OLLAMA_PORT=11434
   ```

   必要に応じてポート番号を変更してください。

2. Ollamaでモデルをダウンロードします。

   - `docker exec`を使用してダウンロードする場合:

     ```bash
     docker exec -it ollama/ollama:latest ollama pull phi3
     ```

     `phi3`はダウンロードするモデル名です。

   - WebUIの管理者パネルからダウンロードする場合:
     - 管理者パネルにアクセスし、ダウンロードしてください。

3. Docker Composeでサービスをビルドして起動します。

   ```bash
   docker compose up --build -d
   ```

   このコマンドで`ollama`と`open-webui`がバックグラウンドで起動します。

# 推論エンドポイントの利用方法

`ollama`の推論エンドポイントを利用するには、以下のように`curl`コマンドを使用します。

- **逐次メッセージを受け取る場合**:

  ```bash
  curl http://localhost:11435/api/chat -d '{
    "model": "phi3",
    "messages": [
      { "role": "user", "content": "Hello!"}],
    "stream": true
  }'
  ```

  `stream`を`true`に設定すると、メッセージが逐次返ってきます。

- **一度にメッセージを受け取る場合**:

  ```bash
  curl http://localhost:11435/api/chat -d '{
    "model": "phi3",
    "messages": [
      { "role": "user", "content": "Hello!"}],
    "stream": false
  }'
  ```

  `stream`を`false`に設定すると、一度にメッセージが返ってきます。

# Web UIの利用

ブラウザで以下のURLにアクセスすると、`open-webui`のユーザーインターフェースに入ることができます。

```
http://localhost:3000/
```
ローカルLLM｜量子化LLM｜ELYZA

# ELYZAとLlama-3-ELYZA-JPモデルについて

### ELYZAとは

ELYZAは、日本語の大規模言語モデル（LLM）を開発している企業であり、様々なAIソリューションを提供しています。特に日本語に特化したLLMの開発に力を入れており、そのモデルは無料デモとして公開されています。また、商用利用が可能な形での公開も行われており、研究や実務においても活用が期待されています。

#### Llama-3-ELYZA-JP-70B
- **Llama-3-ELYZA-JP-70B**は、Llama 3をベースに日本語で追加学習を行った700億パラメータを持つモデルです。
- 無料デモが提供されており、試してみたい方は[こちら](https://elyza.ai/lp/elyza-llm-for-jp)から利用できます。

#### Llama-3-ELYZA-JP-8B
- **Llama-3-ELYZA-JP-8B**は、80億パラメータを持つモデルで、商用利用が可能な形で一般公開されています。
- このモデルは、[HuggingFace Hub](https://huggingface.co/collections/elyza/llama-3-elyza-jp-667a311d51c8952e07778ecc)からダウンロード可能です。
- ライセンスは、**Llama 3 Community License** に準拠しています。

---

# ELYZAをローカルに構築する手順

ここでは、GPUがない環境で「Llama-3-ELYZA-JP-8B」を使用するための手順を解説します。

## ０．前提条件
- **OS**: Windows 11
- **メモリ**: 32GB
- **CPU**: Intel Core i7
- **GPU**: なし
- **開発環境**: Python

## １．LLMのダウンロード

GPUがない計算リソースの限られた環境を前提として、**4bit量子化**された「Llama-3-ELYZA-JP-8B-GGUF」を利用します。  
以下の手順でダウンロードしてください。

1. HuggingFaceの[モデルページ](https://huggingface.co/elyza/Llama-3-ELYZA-JP-8B-GGUF/tree/main)にアクセスし、「Llama-3-ELYZA-JP-8B-q4_k_m.gguf」をダウンロードします。
   - **ファイルサイズ**: 4.93GB
   - ダウンロードには5分以上かかる場合があります。
   
2. ダウンロード後、モデルファイルを任意のパスに保存します。ここでは、`C:\LLMs\Llama-3-ELYZA-JP-8B-q4_k_m.gguf`に保存したと仮定して進めます。

## ２．LLMの利用方法

ダウンロードしたモデルをPythonスクリプトを使って利用します。以下のコードを任意のファイルに保存し、実行してください。

```python
from llama_cpp import Llama

# モデルのロード
llm = Llama(
    model_path="C:/LLMs/Llama-3-ELYZA-JP-8B-q4_k_m.gguf",  # ダウンロードしたモデルのパス
    chat_format="llama-3",  # Llama 3のフォーマット指定
    n_ctx=1024,  # コンテキストの長さ
)

# チャットのリクエスト
response = llm.create_chat_completion(
    messages=[
        {
            "role": "system",
            "content": "あなたは誠実で優秀な日本人のアシスタントです。特に指示が無い場合は、常に日本語で回答してください。",
        },
        {
            "role": "user",
            "content": "カワウソについて、教えてください。",
        },
    ],
    max_tokens=1024,  # 最大トークン数
)

# 結果の出力
print(response["choices"][0]["message"]["content"])
```

## ３．実行結果

このスクリプトを実行すると、以下のような出力が得られます。実行時間はおおよそ1~2分で、そのうち30秒~1分がモデルのロード時間です。ロード後は、`create_chat_completion()`を繰り返し使うことができます。

出力例：

```
カワウソは、哺乳類の食肉目イタチ科に属する動物です。水生生物を主な食糧源としています。

以下に、カワウソの特徴を挙げます。

1. 外見: カワウソは、体長が約50-100cm、体重が約10-20kgの小型の哺乳類です。
2. 生息地: カワウソは、主にアジアとヨーロッパの河川、湖、湿地帯に生息しています。
3. 食性: カワウソは、魚、エビ、カニ、貝類などを捕食します。水中で泳ぎ回り、獲物を捕らえることができます。
4. 繁殖: カワウソは、春から夏にかけて繁殖期を迎え、1回の出産で2-8頭の幼獣を産みます。
5. 保護状況: カワウソは、絶滅危惧種に指定されています。生息地の破壊、水質汚染、捕獲、交通事故などが原因で、個体数が減少しています。
```

---

# まとめ

この手順を利用すれば、Windows 11環境においてGPUがなくても**Llama-3-ELYZA-JP-8B**モデルを活用できます。ELYZAの日本語モデルは非常に強力であり、商用プロジェクトでも利用可能です。  
より大規模なモデルや日本語に特化したLLMを使いたい方は、ぜひ試してみてください。
GCP でVMインスタンスに外部Diskをマウントする

## やること

Rootボリューム意外に、データ用のボリュームをマウントする

https://cloud.google.com/compute/docs/disks/format-mount-disk-linux

## TerraformでVM+外部Diskを作成

```hcl
resource "google_compute_instance" "instance-ubuntu" {
  name                      = "instance-ubuntu"
  machine_type              = "e2-medium"
  zone                      = "asia-northeast1-c"
  allow_stopping_for_update = true
  desired_status            = "RUNNING" # "RUNNING" or "TERMINATED"

  boot_disk {
    initialize_params {
      image = "ubuntu-os-cloud/ubuntu-2204-lts"
    }
  }

  attached_disk {
    source      = google_compute_disk.external_data.self_link
    device_name = "sdb" # boot disk is sda
  }

  network_interface {
    network    = "default"
    subnetwork = "yoursubnet"
  }

  lifecycle {
    ignore_changes = [
      boot_disk[0].initialize_params, # to prevent from recreating an instance due to new image
      metadata["ssh-keys"],
    ]
  }
}

resource "google_compute_disk" "external_data" {
  name                      = "external-data"
  type                      = "pd-ssd"
  zone                      = "asia-northeast1-c"
  size                      = 50 # Gi
  physical_block_size_bytes = 4096
}
```

`google_compute_disk` で作成して `attached_disk`でdevice_nameを指定すれば良い。

```
terraform apply
```

## mountする

```bash
MOUNT_DIR=test_dir
```

Directoryの作成

```bash
sudo mkdir -p /mnt/disks/$MOUNT_DIR
```

mountする (`sbd`はterraformで作成時のDeviceの名前)

```bash
sudo mount -o discard,defaults /dev/sbd /mnt/disks/$MOUNT_DIR
```

readとwrite permissionを付与 (例では誰でもwrite権限を持っている)

```
sudo chmod a+w /mnt/disks/$MOUNT_DIR
```

## Rebootしたときに自動でMountできるようにする

`/etc/fstab` を編集するのでバックアップを作成

```bash
sudo cp /etc/fstab /etc/fstab.backup
```

`blkid` コマンドでUUIDをゲットする

```bash
sudo blkid /dev/sbd
```

結果例:

```
/dev/sbd: UUID="a9e1c14b-f06a-47eb-adb7-622226fee060" BLOCK_SIZE="4096"
TYPE="ext4" PARTUUID="593b3b75-108f-bd41-823d-b7e87d2a04d1"
```

`/dev/sbd` fileに以下を追加

```
UUID=<確認したUUID> /mnt/disks/<MOUNT_DIR> ext4 discard,defaults,defaults 0 2
```

:::note info
`UUID=UUID_VALUE /mnt/disks/MOUNT_DIR FILE_SYSTEM_TYPE discard,defaults,MOUNT_OPTION 0 2`

- UUID_VALUE: the UUID of the disk, listed in the output of the previous step
- MOUNT_DIR: the directory where you mounted your disk
- FILE_SYSTEM_TYPE: the file system type. For example, ext2, ext3, ext4, or xfs.
- MOUNT_OPTION: specifies what the operating system does if it cannot mount the zonal persistent disk at boot time. For valid values, see The fourth field in the Linux fstab documentation. To let the system boot even if the disk is unavailable, use the nofail mount option.
:::

これで再起動時にも自動でMountされる
BoundRef<'_, '_, PyType> not implemented

## エラー
```classmethod_wrong_first_argument.stderr
the trait bound `i32: From<BoundRef<'_, '_, PyType>>` is not satisfied
```
## コード
```rust
use pyo3::prelude::*;

#[pyclass]
struct MyClass(i32);

#[pymethods]
impl MyClass {
    #[classmethod]
    fn add(a: i32, b: i32) -> i32 {a+b}
}
```
## 解決策
```rust
// 省略
use pyo3::types::PyType;

impl MyClass {
    #[classmethod]
    // 第1引数をclsとする
    fn add(cls: &Bound<'_, PyType>, a: i32, b: i32) -> i32 {a+b}
}
```
## 参考
[invalid_pymethods.rs](https://github.com/PyO3/pyo3/blob/d14bfd0c4285a5b99822edf61c75423bef5c9fd9/tests/ui/invalid_pymethods.rs) 46行目
及び
[invalid_pymethods.stderr](https://github.com/PyO3/pyo3/blob/d14bfd0c4285a5b99822edf61c75423bef5c9fd9/tests/ui/invalid_pymethods.stderr) 182行目
Azure Storageざっくりまとめ

## はじめに
AZ-104の資格勉強にあたって、個人的にストレージサービスがAWSに比べてややこしくて覚えられなかったので、自分用に簡単に整理しました。


## Azure Storage
Azureのフルマネージドストレージサービス。
インフラ環境の整備はAzure側が行うので意識しなくていい。
### サービスの種類
| サービスの種類 | 概要 |
|:-----------|:------------:|
| Azure Blob Storage| 汎用的なストレージサービス
| Azure Files |ファイル共有ストレージサービス
| Azure Queue      | メッセージングキューストレージサービス
| Azure Table|NoSQLデータ保管ストレージサービス
| Azure Disk Storage|VHD形式のマネージドディスク

他にもストレージサービスがありますが、AZ-104では出てこないと思いますので割愛します。
Azure Disk StorageはVMで利用する仮想ハードディスクなので、ストレージサービスとしてはあまり意識しなくてもいいかも知れません。
[MS Learn：Azure Storageの概要](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-introduction "Azure Storageの概要")

### 冗長性

データセンタのハードウェア障害、データセンタ障害、リージョン障害に備えて冗長オプションを選択してデータを保護できます。

|冗長オプション|概要|サポート対象のAzure Storage
|:-----------|:-------------|:-------------|
|ローカル冗長ストレージ<br>(LRS)|1つのリージョン内<br>1つのデータセンタ内に3つのコピー|Azure Blob Storage<br>Azure Files<br>Azure Queue<br>Azure Table<br>Azure Disk Storage
ゾーン冗長ストレージ<br>(ZRS)|1つのリージョン内<br>3つの可用性ゾーンにコピー|Azure Blob Storage<br>Azure Files<br>Azure Queue<br>Azure Table<br>
geo冗長ストレージ<br>(GRS)|プライマリリージョンの1つのデータセンタ内に3つのコピー<br>セカンダリリージョンの1つのデータセンタにも3つのコピー|Azure Blob Storage<br>Azure Files<br>Azure Queue<br>Azure Table
読み取りアクセスgeo冗長ストレージ<br>(RA-GRS)|プライマリリージョンの1つのデータセンタ内に3つのコピー<br>セカンダリリージョンの1つのデータセンタにも3つのコピー|Azure Blob Storage<br>Azure Queue<br>Azure Table
geoゾーン冗長ストレージ<br>(GZRS)|プライマリリージョン内でゾーン冗長ストレージで3つの可用性ゾーンにコピー<br>セカンダリリージョンには1つのデータセンタ内に3つのコピープライマリリージョンの1つのデータセンタ内に3つのコピー<br>セカンダリりージョンの1つのデータセンタにも3つのコピー|Azure Blob Storage<br>Azure Files<br>Azure Queue<br>Azure Table
読み取りアクセスgeoゾーン冗長ストレージ<br>(RA-GZRS)|プライマリリージョン内でゾーン冗長ストレージで3つの可用性ゾーンにコピー<br>セカンダリリージョンには1つのデータセンタ内に3つのコピープライマリリージョンの1つのデータセンタ内に3つのコピー<br>セカンダリりージョンの1つのデータセンタにも3つのコピー|Azure Blob Storage<br>Azure Queue<br>Azure Table

通常のgeo冗長ストレージ(GRS/GZRS)は読取できませんが、
読み取りアクセスのgeo冗長ストレージ(RA-GRS/RA-GZRS)は、セカンダリリージョンでも読取を行うことが可能。
Azure Filesでは読み取りアクセスはサポートされていません。


[MS Learn：Azure Storageの冗長性](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-redundancy?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json)
[MS Learn：Azure Filesのデータ冗長性](https://learn.microsoft.com/ja-jp/azure/storage/files/files-redundancy?source=recommendations)


### ストレージアカウント
ストレージアカウントは、Azure Storageの管理単位です。
HTTP、HTTPS経由でアクセスでき、ストレージアカウント名はグローバルに一意の名前にする必要があります。
ストレージアカウントにもいくつか種類があって、パフォーマンスや可能性などから適切なものを選択。
パフォーマンスレベルはStandard、Premiumから選択可能。

ストレージアカウントの種類によって、利用可能なサービスが異なる。

|種類|サービス|冗長オプション|用途
|:--|:--|:--|:--
|Standard汎用V2|Azure Blob<br>Azure Files<br>Azure Queue<br>Azure Table|LRS<br>ZRS<br>GRS<br>RA-GRS<br>ZGRS<br>RA-ZGRS|汎用的なストレージアカウント
PremiumブロックBlob|Azure Blob|LRS<br>ZRS|ブロックBlobと追加Blob用
Premiumファイル共有|Azure Files|LRS<br>ZRS|ファイル共有専用
PremiumページBlob|ページBlob|LRS|ページBlob特化

レガシーストレージアカウントは推奨されていないため割愛。
非推奨なだけで2024年9月時点では、まだサポートはされています。

[MS Learn：ストレージアカウントの概要](https://learn.microsoft.com/ja-jp/azure/storage/common/storage-account-overview)
Kotlin/Native で生成したSwiftコード を Xcodeプロジェクトに取り入れてみる

# やったこと
（KMPの文脈ではなく）純粋なKotlin/Nativeで生成した Swift（Objective-C）コードを、適当につくったXcodeのAppプロジェクトに取り入れる

# 仕組み
Kotlin/Native は Kotlinのコードを仮想マシンなしで実行できるネイティブ・バイナリにコンパイルする技術で 以下プラットフォームをサポートしている。

- macOS
- iOS, tvOS, watchOS
- Linux
- Windows (MinGW)
- Android NDK

Kotlinから iOS（macOS） 向けには  framework に変換して使う。
また, XCFrameworkへの変換をサポートしてるプラグインも存在している。
（SPM へのサポートはしらべてないです。）

# 取り込み

```kotlin
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
...
kotlin {
    val xcf = XCFramework("shared")
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64(),
        macosArm64(),
        macosX64()
    ).forEach { iosTarget ->
        iosTarget.binaries.framework {
            baseName = "shared"
            xcf.add(this)
        }
    }
}
```

`iosTarget.binaries.framework` で XCFrameworkを生成するプラグインに追加する。
`baseName` と XCFrameworkの指定する 引数（`xcFrameworkName`）は 一致させないとビルドエラー

<br>

```
├── iosArm64
│   ├── debugFramework
│   └── releaseFramework
├── iosSimulatorArm64
│   ├── debugFramework
│   └── releaseFramework
├── iosX64
│   ├── debugFramework
│   └── releaseFramework
├── macosArm64
│   ├── debugFramework
│   └── releaseFramework
└── macosX64
    ├── debugFramework
    └── releaseFramework
```
`build/bin/` 配下に ターゲットごとのFrameworkができる。
<br>


```
build/XCFrameworks
├── debug
│   └── shared.xcframework
└── release
    └── shared.xcframework
```
そこから、`./gradlew assembleSharedXCFramework` で XCFrameworkを生成。
<br>


```sh
codesign -s "Apple Development: Your Name (TeamID)" --force --deep --timestamp --options runtime shared.xcframework
```
生成した xcframework を署名する

オプションは以下👇

- `-s` "Apple Development: Your Name (TeamID)": Apple 開発者証明書を指定して署名を行う
- `--force`: すでに署名されている場合でも、強制的に再署名を行う
- `--deep`: コンテナ内のすべてのファイルやサブコンポーネントにも再帰的に署名する
- `--timestamp`: 署名にタイムスタンプを付けて、後に証明書が失効しても署名が有効であることを保証する
- `--options runtime`: Apple のセキュリティ機能（App Sandbox や SIP）に対応する署名を行う

<br>

あとは Xcode側で General > FrameWorks,Librares, and Embedded Content で 取り込む

![スクリーンショット 2024-09-15 21.27.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700755/b14062e8-9f7b-6487-0c39-c564c4614954.png)

参照するとこんな感じ

```kotlin
object Object {
    val field = "A"
}
```

👇 Xcode で `import sherad` から 見える部分

```Swift

// Kotlinから NSObject にラップするためのコード等
~~
~~

public class Object : KotlinBase {

    
    public convenience init()

    open class var shared: Object { get }

    open var field: String { get }
}
```

# 参考
https://kotlinlang.org/docs/native-overview.html

https://qiita.com/gdate/items/b49ef26824504bb61856

https://kotlinlang.org/docs/multiplatform-build-native-binaries.html#build-xcframeworks

https://qiita.com/4q_sano/items/2ccd47796c5a377cb20d
Arduino UNO 3でカラーLED、Grove - Chainable RGB LEDで遊ぶ(P9813)



参考

![o_coq404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/81aedfce-56fd-48b0-cbd0-925bd856f995.jpeg)

![o_coq405.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/aebd8553-14af-7dc6-ac3d-0fa98a9c1002.jpeg)


![o_coq407.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/62a41386-2110-8843-016f-ee3c5f9a4b5c.jpeg)



https://wiki.seeedstudio.com/Grove_Starter_Kit_for_BeagleBone_Green/


https://www.aitendo.com/product/12927


https://github.com/pjpmarques/ChainableLED

Grove Starter Kit for BeagleBone Green

https://akizukidenshi.com/catalog/g/g109796/

結果

![o_coq408.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/918a5c64-c632-c7a4-885f-3deb6863c34b.jpeg)


プログラム


```c++


//Chainable_LED_UNO_1
//1個専用のカラーRGB LEDのライブラリ


//送信クロックの発生
void clk() {

  digitalWrite(19, LOW);//clk
  delay(20);                       // wait for a second
  digitalWrite(19, HIGH);//clk
  delay(20);                       // wait for a second

}//clk


//1バイトを送信する
void sendByte(int b) {

  for (int i = 0; i < 8; i++) {
    if ( (b & 0x80) == 0) {
      digitalWrite(18, LOW);//data
    } else {
      digitalWrite(18, HIGH);//data
    }//endif
    clk();
    b = b << 1;
  }//for i

}//sendByte


//1個のLED専用
void setColorRGB(int red, int green, int blue) {

  //開始
  sendByte(0);
  sendByte(0);
  sendByte(0);
  sendByte(0);

  //ここから
  int prefix = 0b11000000;
  if( (blue  & 0x80)==0 ) {prefix = prefix | 0b00100000;}
  if( (blue  & 0x40)==0 ) {prefix = prefix | 0b00010000;}

  if( (green & 0x80)==0 ) {prefix = prefix | 0b00001000;}
  if( (green & 0x40)==0 ) {prefix = prefix | 0b00000100;}

  if( (red   & 0x80)==0 ) {prefix = prefix | 0b00000010;}
  if( (red   & 0x40)==0 ) {prefix = prefix | 0b00000001;}
  sendByte(prefix);

  sendByte(blue);
  sendByte(green);
  sendByte(red);
  //ここまで

  //終了
  sendByte(0);
  sendByte(0);
  sendByte(0);
  sendByte(0);

}//setColorRGB


// the setup function runs once when you press reset or power the board
void setup() {
  //GPIOポートの初期化
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(18, OUTPUT); //data
  pinMode(19, OUTPUT); //clk
}//setup


// the loop function runs over and over again forever
void loop() {

  //赤
  setColorRGB(0x55, 0x00, 0x00);
  delay(500);                       // wait for a second

  //緑
  setColorRGB(0x00, 0x55, 0x00);
  delay(500);                       // wait for a second

  //青
  setColorRGB(0x00, 0x00, 0x55);
  delay(500);                       // wait for a second
  
}//loop


```
オープンソース辞書API「Free Dictionary API」

こちらは、非常に便利なオープンソースの辞書API「Free Dictionary API」をご紹介します。
# Free Dictionary API
Web上に無料の辞書APIが存在しなかったため、友人のためにこのAPIを作成しました。
プロジェクトのリンク: https://github.com/meetDeveloper/freeDictionaryAPI

デジタル時代において、正確な語彙の定義を迅速に取得することがますます重要になっています。本日ご紹介するのは、開発者コミュニティによって熱意を持って支えられているオープンソースプロジェクト「Free Dictionary API」です。このAPIは、無料で利用できるオンライン辞書APIで、あなたの検索ニーズに応えるために設計されています。
# プロジェクト概要
Free Dictionary APIは、適切な無料辞書APIが見つからなかった開発者がこの問題を解決するために作成したものです。簡単なHTTPリクエストを送るだけで、任意の英単語の発音、語源、定義、さまざまな品詞での説明を簡単に取得できます。このAPIは、個人開発者にとって使いやすいだけでなく、教育ソフトウェアや語学学習アプリにも統合することができます。
# 説明
APIは、異なるニーズに対応するためにV1およびV2の2つのバージョンを提供しています。V2バージョンは、より解析しやすいJSON構造を採用しており、データの処理が直感的になります。GETメソッドを使用して、https://api.dictionaryapi.dev/api/v2/entries/en/<YOUR_WORD> にアクセスすることで、単語の情報を取得できます。例えば、「hello」の定義を検索するには、https://api.dictionaryapi.dev/api/v2/entries/en/hello にリクエストを送信するだけです。

また、このプロジェクトはHTTPリクエストとクエリメソッドをサポートしており、柔軟にアプリケーションに統合することが可能です。さらに、GitHub上で問題の議論や機能提案に参加したり、Pull Requestを送って直接貢献することもできます。

# 利用シーン
・英語の語彙を学習するための教育アプリを開発
・翻訳ツールの補助機能として詳細な意味を提供
・ブラウザ拡張機能（例：「Dictionary Anywhere」）を作成し、ユーザーがWebページ上の単語をダブルクリックすると意味を確認できるようにする
・自動テストに利用し、テキスト内の単語が正しいかを確認し、定義を提示
# プロジェクトの特徴
・無料かつオープンソース: 誰でも自由に利用でき、コードに貢献できる
・簡単で使いやすい: 明確なHTTPインターフェースと直感的なJSONレスポンスで統合が容易
・高い柔軟性: 2つのバージョンのAPIを提供し、異なるニーズに対応
・強力なサポート: 開発者が積極的に問題に対応し、継続的に改善しており、コミュニティの参加を歓迎

# 最後に
最後に、APIの使用量の増加に伴い、サーバーの維持コストが上昇しています。もしこのAPIを気に入り、依存しているのであれば、ぜひ開発者を応援し、コーヒー1杯分の支援を考えてみてください。この貴重なリソースが持続的に発展するようにご協力をお願いします。

ぜひ今すぐFree Dictionary APIを試してみてください。日々のコーディングや語学学習における頼もしいアシスタントとなることでしょう！
python: uv で trusted-host は、allow-insecure-host

# 背景

trusted-host が必要になった状況で、uv の場合どうなるん？ってのを調べた結論

# 結論：allow-insecure-host を使う

```powershell: trusted-host も一応動く
uv pip install pypi --trusted-host pypi.org
```

のようにしても alias なのか動くけど、project.toml における設定は反応しないので、以下とする

```toml: allow-insecure-host
[tool.uv]
allow-insecure-host = ["example.com"]
```

公式は以下

https://docs.astral.sh/uv/configuration/authentication/#custom-ca-certificates

## truste-host は非対応オプションだよって話は以下

https://docs.astral.sh/uv/pip/compatibility/#pip-command-line-options-and-subcommands

# ちなみに、toml の [tool.uv] で使える設定は以下

```toml: [tool.uv]

python = "",
system = "",
break-system-packages = "",
target = "",
prefix = "",
index-url = "",
extra-index-url = "",
no-index = "",
find-links = "",
index-strategy = "",
keyring-provider = "",
allow-insecure-host = "",
no-build = "",
no-binary = "",
only-binary = "",
no-build-isolation = "",
no-build-isolation-package = "",
strict = "",
extra = "",
all-extras = "",
no-deps = "",
allow-empty-requirements = "",
resolution = "",
prerelease = "",
output-file = "",
no-strip-extras = "",
no-strip-markers = "",
no-annotate = "",
no-header = "",
custom-compile-command = "",
generate-hashes = "",
config-settings = "",
python-version = "",
python-platform = "",
universal = "",
exclude-newer = "",
no-emit-package = "",
emit-index-url = "",
emit-find-links = "",
emit-build-options = "",
emit-marker-expression = "",
emit-index-annotation = "",
annotation-style = "",
link-mode = "",
compile-bytecode = "",
require-hashes = "",
verify-hashes = "",
no-sources = "",
upgrade = "",
upgrade-package = "",
reinstall = "",
reinstall-package = "",
```

# あとがき

ちゃんとしたい場合は以下

https://qiita.com/cartooh/items/0f746b4576af25066943

uv 便利ですね。
一年ぐらい前は、python なんてって言ってたのに、やっぱり使うとなったら・・ね :p
セッションの脆弱性のメモ



## セッション
認証結果などの状態を管理する手段として、セッション管理が用いられている。
主に、クッキーなどにセッションIDという識別子を記憶させて、このセッションIDをキーとしてサーバ側で実情報を保存する方法がとられている。

第三者がセッションIDを知る方法は3つに分類される
- セッションIDの推測
- セッションIDの盗み出し
- セッションIDの強制

### セッションIDの推測
セッションIDの生成方法が不適切な場合、推測できてしまう。

### セッションIDの盗み出し
- クッキー生成の際の属性の不備により漏洩
- ネットワーク的にセッションIDが盗聴
- XSSなどアプリケーションの脆弱性により漏洩
- セッションIDをURLに保存している場合は、Refererヘッダから漏洩

### セッションUDを強制
セッションIDを利用者のブラウザに設定することができれば、攻撃者は利用者のセッションIDを知っている状態になる。

## 脆弱性

### 推測可能なセッションID
1. 対象アプリケーションからセッションIDを収集
1. セッションIDの規則性の仮説を立てる
1. 推測したセッションIDをい対象のアプリケーションで試す

上記のステップで攻撃をする。

- ユーザIDやメールアドレス
- リモートIPアドレス
- 日時
- 乱数

などがありがちなセッションIDの生成方法。
これらを使用すると推測される可能性が高い。

対策は、Webアプリケーション開発ツールが備えているセッション管理機能を使用すること。

### URL埋め込みのセッションID

セッションIDをクッキーに保存せず、URLに埋め込ませる場合がある。
この場合は、Refererヘッダを経由して、セッションIDが外部に漏洩する。

対策としては、URL埋め込みのセッションIDを使用しないこと。

### セッションIDの固定化

1. セッションIDを入手
1. 被害者に対して、入手したセッションIDを強制
1. 被害者が標的アプリケーションにログイン
1. 攻撃者は、被害者に強制したセッションIDでアクセスする

上記の手順で、行う。
外部からセッションIDを強制できることが、脆弱性の原因。

対策は、
- セッションIDをURL埋め込みにしない
- クッキーモンスターバグのあるブラウザを使用しない
- XSS脆弱性をなくす
- HTTPヘッダインジェクション脆弱性をなくす
- その他クッキーを書き換えられる脆弱性をなくす

がある。

後、認証後にセッションIDを変更することが対策としてあげられる。
TISのレビュー記録表テンプレ＆サンプルが役立ちそうなので紹介しておく

## はじめに
プロジェクトの規模が大きくなってくると、レビュー実施して指摘事項が全てクローズされたかどうかを抜け漏れなくチェックすることが大切になってきます。
そういったときに使うのがレビュー記録票ですが、会社やプロジェクトによってはフォーマットが定まっていないこともあるかと思います。そこで今回は、実際にプロジェクトにそのまま使えるレビュー記録票のサンプルを紹介します。
例によって大手SIerのTIS社のサンプルです。


## レビュー記録票（サンプル）
さっそくですが、レビュー記録票のサンプルは以下になります。

※TISで用意されているものには、具体的な入力値が書かれていなかったので、イメージしやすいように私のほうで例を記入しました。

まずは「レビュー実施状況」シートです。
機能によっては複数回レビューを実施するものもあると思いますが、そういったときに誰がどの回で出席したのかが分かるようになっています。

・レビュー実施状況
![レビュー実施状況](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/f9659270-c2ee-840d-9b56-1b87880924a0.png)

次に「レビュー指摘一覧」シートです。
各実施回での指摘事項が一覧になっており、対応内容と対応が完了したかどうかが分かるようになっています。
指摘分類や原因分類、原因工程は記入するのが面倒ではありますが、品質を分析する際に必要になる項目です。

・レビュー指摘一覧
![レビュー指摘一覧](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/85ba7226-b64e-79f8-ac5d-a87a840beacd.png)

そして最後に「設定値」シートです。
プロジェクトの特性や参加メンバーに合わせてプルダウンが設定できるように、このシートで選択肢を設定します。

・設定値
![設定値](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/9923f035-32f1-44d3-30ad-106d62f296f3.png)

## レビュー記録表の集計・分析
前述のレビュー記録票を用いて、プロジェクトの品質管理担当者は、レビューの工数密度や指摘密度を算出したり、指摘分類や原因分類の傾向から、品質不良の傾向を分析し、対策を検討します。

そういった作業の際に、１つずつExcelブックを開いて集計するのが大変になるので、集計ツールを使いたくなります。

先ほどのレビュー記録票に対応した集計ツールが用意されているので、こちらを合わせて活用することでプロジェクトの品質分析作業を効率化することができます。

「指摘事項は全てクローズされているか？」といったチェックにも使えるので便利かと思います。

・レビュー指摘事項抽出ツール
![レビュー指摘事項抽出ツール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/7d0f9a03-84fe-d904-a7f1-01638e6b2b16.png)

使い方を1~2時間ぐらい勉強する必要はありますが、1度分かれば作業が楽になるので利用ガイドシートを読んでみましょう。

![利用ガイド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2739239/650746b6-8f69-f1be-1d09-ec92c13f118b.png)

## レビュー記録表へのリンク
今回紹介した資料のリンクは以下になります。

[Excel設計書レビュー指摘事項抽出ツール（doctool.zip）](https://github.com/Fintan-contents/review-support-tool/releases/latest/download/doctool.zip)

※ツールのZIPフォルダの中にテンプレも用意されています。



## さいごに
今回も大手SIerのTIS社のテックブログから役立ちそうなドキュメントを紹介しました。
またいろいろ漁ってみて良さげなドキュメントがあったら共有したいと思います。
【Laravel】初心者による開発環境構築

# Laravelで開発環境を作る！！
最近Laravelの勉強をしているので、自分用にざっくりとにまとめてみました。

## 前提として
- PHPがグローバルにインストールされているか
- Composerがグローバルにインストールされているか

(グローバルにインストールされている＝どのディレクトリからでも使える状態)

をそれぞれ以下のコマンドで確認する。

```Bash
php --version
```
```Bash
composer --version
```
これらのコマンドを実行して、エラー表示なくバージョン確認ができたらOK

## テンプレートをインストールする
Laravelのテンプレートをインストールする
```Bash
composer create-project laravel/laravel new-project
```
各項目が何を表しているのか？？
**①composer**
→依存関係を管理するComposerを使用するよ！と宣言している。Composerに話しかけているイメージ。

**②create-project**
→読んで字のごとく、プロジェクトを作ってくださいという意味。composerのサブコマンド。

**③laravel/laravel**
→laravelが提供している(laravel/の部分)、laravelというテンプレート(laravelの部分)を使ってくださいという意味になる。
→このテンプレートの使用はマストではないが、使用することでapp/ , public/ , resources/ , routes/ といったディレクトリが生成され推奨されているディレクトリ構造が自動的に組まれるようになるため、かなり負担を軽減させることができる。

**④new-project(任意のディレクトリ名)**
→プロジェクトディレクトリ直下に作成するディレクトリ名を決める。ディレクトリ名の代わりに「.」を入れることでプロジェクトディレクトリ直下にテンプレートをインストールすることができるようだが、Composerはディレクトリを作成する前提で動いているようなので作る方が望ましいのだとか(Chat GPT情報)。

## データベースの設定など
①先ほど作成したディレクトリへ移動する。
```Bash
cd new-project
```

②一旦Bashから離れて、ディレクトリ内の.env(environmentの略。環境変数を設定するファイル。)の中身の設定をする。

```
DB_CONNECTION=sqlite
#DB_HOST=127.0.0.1
#DB_PORT=3306
#DB_DATABASE=
#DB_USERNAME=root
#DB_PASSWORD=
```
となっている部分を以下のように変更する
```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_todo
DB_USERNAME=root
DB_PASSWORD=
```
【変更点】
- sqliteをmysqlにした。
→ MySQLを使用した開発を行いたいため、変更した。ちなみに、SQLiteはテストや簡単なプロジェクトに使用されるデータベースあり、MySQLは大規模なデータベースである。
- DB_HOST以下のコメントされている部分を解除した。
- DB_DATABASEに作成したいデータベースの名前を入力した。
→ Todoリストを作りたいので、laravel_todoと名付けた。

※MySQLのインストール時に設定したパスワードを .env ファイルの DB_PASSWORD に入力してください。

## データベース構造の管理
再びBashに戻り、以下のコマンドを実行する。
```Bash
php artisan migrate
```
各項目が何を示しているのか？？
**①php**
→ 先ほどcomposerと同様で、今回はphpに話しかけている。

**②artisan**
→ phpを通してlaravelのツールであるartisan(=職人)を使うと宣言している。

**③migrate**
→ artisanに何をやらせるのか？というのがこの記述。migration(=移行)を行うように命令している。
→ migrationというのは、データベースの構造を管理することを意味し、使いこなせるとSQLクエリを直接手で書く必要がなくなる便利なツールである。

このコマンドを実行すると、
```
WARN  The database 'laravel_practice' does not exist on the 'mysql' connection.
Would you like to create it? (yes/no) [yes]
```
というメッセージが表示される。これは、MySQLにデータベースを作成していないにもかかわらず、.envにデータベース名の記載があるために表示される。[yes]と回答することで、自動的に.envに記述した名前のデータベースを生成してもらうことができる。(ただし、Laravel 8以降。)

## サーバーを用意する
最後に以下のコマンドを実行する。
```Bash
php artisan serve
```
先ほどと同様に、artisanを用いて今回はserve、つまり開発サーバーを用意してもらっている。
Bash上に表示されたリンクからwelcomeページが確認たら、環境構築は完了！
Secrets Manager

## AWS Secrets Managerとは
機密情報管理サービス。
ライフサイクルを通じてデータベース認証情報、API キー、その他の機密情報を簡単に更新、管理、取得できる。

https://aws.amazon.com/jp/secrets-manager/

## 特徴
- アプリケーションに影響を与えずにシークレットを自動更新できる
- 複数の リージョンにシークレットを自動レプリケーションする
- シークレットを監査・モニタリングできる



## Secrets Managerの安全性について
保管中のシークレットは、ユーザの所有する暗号化キーで暗号化後、KMSに保存され、IAMのポリシーを使用してシークレットへのアクセスを制限できる。
シークレットを取得すると、Secrets Manager でシークレットが復号され、TLS 上でユーザのローカル環境に安全に送信される。

## シークレット更新のタイミングについて
CloudWatch Events を設定すると、Secrets Managerでシークレットが更新された際に通知を受け取ることができる。
また、Secrets Manager コンソールまたは API を使用して、Secrets Manager の直近のシークレット更新を見ることもできる。

## 料金
シークレットあたり 0.40USD/月。
保存期間が1ヶ月未満のシークレットは、時間数に基づいて計算される。
また、10,000 件の API コールあたり0.05USD。

:::note info
30日間、無料トライアルが利用可能。
:::
Postgresqlのバックアップとリストア

misskeyとかFirefishとかIceshrimpとかのサーバーを建てていてアップグレードとか移行に失敗したとき予めpostgresqlをバックアップする方法とそれをリストアする方法です。

# バックアップ
Postgresqlの中身を全部backup.sqlというテキストファイルに出力します。
```
sudo -u postgres pg_dumpall > backup.sql
```

# リストア
まず動かしているFirefishとかを止めます firefish.serviceの部分は
動かしているソフトウェアによって変わります。
```
sudo systemctl stop firefish.service
```

データベースの名前はmisskeyとかCalckeyの時にインストールしたFirefishなんか場合はmk1になっていますが、Firefishの場合はfiefish_dbになっていたりIceshrimpの場合はiceshrimpだったりSharkeyの場合はsharkeyだったりそのソフトウェアの名前になってたり
するのでいっぺん`sudo -u postgres psql`でpostgresqlにログインして`\l`でデータベース一覧を確認してみてください。使っているソフトウェアの名前のデータベースがあったら多分それです。
確認出来たら`\q`でpostgresqlから抜けます。

元あるデータベースを削除(mk1の部分は上記に読み替え）
```
sudo -u postgres dropdb mk1
```

空のデータベースを作成（mk1の部分は上記に読み替え）
```
sudo -u postgres createdb mk1
```

データベースのリストア（先ほどバックアップしたのと同じユーザーのホームディレクトリに置いてあるものとします）
```
sudo -u postgres psql -f ./backup.sql
```

終わったらFirefishとかを再起動します
```
sudo systemctl start firefish.service
```
数学が1ミリもわからないエンジニアが「数学ガールの秘密のノート/学ぶための対話」を読んだ


# はじめに
qiita投稿、1年以上間隔空いた。。
タイトルにある「数学が１ミリもわからない」は比喩でもなんでもなくマジです。
大学に進学せず、中学高校とまともに数学はやってこなかったので、数１とか数Aとか言われても分かりません。現にこの本で復習するまで一次方程式が何かすら忘れてました。

# きっかけ
そんな私がなぜ数学ガールを読もうと思ったか。後輩におすすめしてもらったから以外のなにものでもないのですが、元から数学は学びたいと思っていたのでタイミングだったと思います。
数学が１ミリも分からなくても普通に仕事できるんですよね、今まで数学ができなくて困ったことないですし。ただ、このコンピュータの世界ではありとあらゆるところに数学が使われていて、それが視野に入ることはありました。ソート、探索、グラフ理論・・・等ですね。そういうものを理解していると視点が変わって世界が変わるだろうな。楽しそうだな。と思っていたので数学はいつか学びたいと思っていたわけです。

# 感想
結論、これを機に数学をもっと学びたいと思える良書でした。
数学とは関係なく、学んだり教えたりするときに心得ておきたい知識も副産物として手に入れることができたので良かったです。
「僕」がノナに注意した対話について(P138)、は本タイトルの本質ともいえそうです。

私とノナを照らし合わせながら考えることができたのもスッと理解ができたポイントかもしれません。本書を読んで振り返ると、私は数学が嫌いだと思っていましたが苦手なだけだったと気づきました。理解しようとせず、教科書の公式を赤い枠線で囲って必死に覚えようとしていました。その証拠に、高校時代では新しい単元に入ってすぐ、第一章や二章では問題を解いて答えを出せていましたし、問題を解くことの楽しささえ覚えていました。嫌いではなかったと思います。
それが三章とかになり応用をきかせた単元に入った途端、たちまち分からなくなり、問題を解くことを諦め数学が楽しくなくなり嫌いだと思い込んでいた。理解して解くことができれば、性格的に数学の魅力に取りつかれていたと思います。
苦手なだけで嫌いではなかったと認識できたのが一番の収穫かもしれません。

話は変わって座標平面において、x座標とy座標が等しい点は必ずこの直線上にあり、無限に続いてもそれは変わらない。どこまでいっても一貫性がある。だからこそこの直線を y=x と表現できる。数式がもつパワーを認識できたことも大きな収穫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3427437/0a9f73e6-3d68-d583-c83c-bec54830a945.png)


# これから
本書をきっかけに、数学との向き合い方を学ぶことができました。おすすめしてくれた後輩には感謝です。
向き合い方を学んだだけで終わるのはもったいないですし、「はじめに」で述べた通り、まだまだ学ぶべきトピックは山ほどあるので時間をかけて理解していこうと思います。
数学に慣れる意味でも数学ガールシリーズを読み進めていこうかな。
「数学が１ミリもわからない」から「数学チョットデキル」になれる日を夢見て。

本書(Amazon)
https://amzn.asia/d/6oeGqPd
ディレクトリとフォルダの違い：CLIとGUIの視点から

## はじめに
こんにちは、未経験からエンジニア転職を目指しているものです。
オンラインスクールで本格的に学習して4ヶ月目に入りました。勉強し始めの頃の自分が疑問に思っていたことを整理してみようと思い記事を書いております。勉強していく中で「ディレクトリ」や「フォルダ」という用語をよく見るようになりました。ただ、どのように使い分けているのか分かりませんでした。この記事では、ディレクトリ」と「フォルダ」の違いについて、CLI（コマンドラインインターフェース）とGUI（グラフィカルユーザーインターフェース）の視点でまとめてみました。

## ディレクトリ、フォルダとは？
ファイルシステムの基本的な概念で、ファイルを整理するための手段です。
- `ディレクトリ`とはコンピュータのファイルシステムにおける「フォルダ」を指します。CLI環境では、ディレクトリはファイルを整理するための階層的な構造として表現されます。CLIでは、ディレクトリは以下のようにコマンドラインで表示されます

```bash
$ ls
Documents  Downloads  Pictures  Videos
```

- `フォルダ`は、GUI環境で表示されるディレクトリの視覚的な表現です。GUIでは、ディレクトリはアイコンや四角い箱として表示されています

## CLIとGUIの違い
CLIとGUIでのディレクトリ（フォルダ）の表現方法には違いがあります。

- CLI：ディレクトリはテキストベースで、階層構造をコマンドで表示します。ディレクトリ内のファイルやサブディレクトリをリストアップするためのコマンド（例: ls）を使用します
- GUI：フォルダは視覚的に表示され、アイコンや四角い箱で表現されます。ユーザーはマウスで操作し、ドラッグ＆ドロップなどでファイルを管理します

## 具体的な例
**CLIの例**
以下はCLIでのディレクトリ表示の例です：

```bash
$ cd Documents
$ ls
Projects  Reports  Resume.docx
```

ここでは、「Documents（書類）」というディレクトリの中に「Projects」「Reports」「Resume.docx」というファイルやサブディレクトリが含まれています。

**GUIの例**
以下はGUIでのフォルダ表示の例です：

![スクリーンショット 2024-09-15 18.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846051/138de6c4-1c1e-190f-c03b-a7363a228583.png)


ここでは、「書類(Documents)」フォルダ内に「Resume.docx」「Reports」「Projects」というアイコンが表示されています。

## まとめ
「ディレクトリ」と「フォルダ」は、コンピュータのファイルシステムで使用される同じ概念を指しますが、CLIとGUIでの表現方法が異なります。CLIではテキストベースで階層構造が表示されるのに対し、GUIでは視覚的にアイコンや箱として表示されます。この違いを理解することで、ファイル管理の方法をより効率的に使いこなすことができるでしょう。



最後までご覧いただき本当にありがとうございました！！
[LogicApps]ServiceBusメッセージの取得方法（application/json）

## 背景
メッセージングサービスAzureServiceBusを使用して、メール送信機能をAzureLogicApps（メッセージングキュートリガー）で開発してみました。  
メッセージングキュー実行したとき、AzureLogicApps側でjsonメッセージを受け取る実装で苦労したので、ここにメモしておきます。

## システム構成
![システム構成図_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/e9ce2f90-0998-0c7c-b512-5bc341d07f47.png)

## 前提条件
1. [AzureServiceBusでキューを作成する](https://learn.microsoft.com/ja-jp/azure/service-bus-messaging/service-bus-quickstart-portal)（Basicプラン）
1. 1.で作成したキューにエンキューするjsonのフォーマットのサンプルを下記とする
1. AzureLogicAppsトリガーに「[Connect to Azure Service Bus to send and receive messages.](https://learn.microsoft.com/ja-jp/azure/logic-apps/connectors/built-in/reference/servicebus/)」を設定する
1. 1.で作成したキューにキュータイプ「application/json」とし、2.で記載したjsonファイルと同じフォーマットで送信する
1. 4.でメッセージがキューに送信された後、3.で作成したLogicAppsフローが実行される
### 上記2.のjsonファイルサンプル
```json
{
  "Receiver": "送信したいメールアドレス",
  "Subjects": "送信メール標題",
  "Contents": "送信メール内容1<br>送信メール内容2"
}
```

## AzureLogicApps側実装ポイント
1. 「triggerBody()?」でメッセージングしたメッセージを取得する。キー「ContentData」にメッセージングしたJsonファイルの中身が格納されている
1. メッセージは、AzureLogicApps側にBase64形式で渡されるため、「Base64String(triggerBody()?['ContentData'])」でBase64形式を文字列に変換する
![base64ToString_1_1_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/a38a6732-6350-69f6-d7da-a0607002a93d.png)
![base64ToString_1_2_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/ac765c00-2701-da43-352e-5620eb428491.png)
1. 2.で変換した文字列を[Json形式](https://learn.microsoft.com/ja-jp/azure/logic-apps/workflow-definition-language-functions-reference#json)に整形する
※上記「前提条件」のjsonファイルフォーマットで実行すると、余分な改行コードが入るため、除去する必要がある。そのため、「replace(replace(replace(2.で取得したデータ,'\r\n',''),'\n',''),'\r',''))」などで置換する
1. 「json(3.で変換したjson文字列)」でjson文字列からjsonオブジェクトを取得する
![base64ToString_2_1_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/34529fe4-8a26-0b27-3c16-a2816556cc2e.png)
![base64ToString_2_2_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/40edc115-c1d4-0d57-5520-a03b89b7a9a6.png)
1. 「4.で作成したjsonオブジェクト.キー（4.で作成したjsonオブジェクト.Receiverなど）」で文字列を取得する
![JsonKey_1_1_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/c19e98f0-49e7-d39b-5725-76f3cb3f90c8.png)
![JsonKey_1_2_マスク_投稿.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987347/2ef2888c-56e3-3f54-3bed-beb1e4182230.png)

## まとめ
AzureServiceBusを使用すれば、分離されたシステムとの非同期連携が可能になり、AzureLogicApps、AzureFunctionsをはじめ、様々なAzureサービスのトリガーとして使用でき、便利であると感じました。
AzureLogicApps側の実装手順で様々なコネクター、アクションがあり、慣れていない部分があるため、今後とも根気強く遊んでいきます。
次は、AzureLogicAppsのトリガーをHTTPトリガーにし、AzureManagementAPIなどを使用し、メッセージングキュー実行ではなく、API実行でも遊んでみたいです。

記事一読いただきありがとうございます。上記改善点などご指摘あれば、コメントいただけると幸いです。いいと思った方はいいねいただけると幸いです。定期的に記事を更新していこうと思いますので、引き続きよろしくお願いします。