OmniAICreator/Qiita-1.07M huggingface dataset:
指定年月の月初日を求める

--概要　　　：月初を返します
--引数　　　：[@year] …対象年
--　　　　　　[@month]…対象月
--戻り値　　：対象年月の月初
IF (EXISTS(SELECT * FROM sys.objects WHERE (type = 'FN') AND (name = 'fn_getdate_monthstart')))
BEGIN
    DROP FUNCTION fn_getdate_monthstart;
END
GO

CREATE FUNCTION fn_getdate_monthstart
(
    @year INT,
    @month INT
)
RETURNS DATETIME
AS
BEGIN
    DECLARE @strdate VARCHAR(10);
    SET @strdate = CONVERT(VARCHAR, @year) + '-' + CONVERT(VARCHAR, @month) + '-1';

    RETURN CONVERT(DATETIME, @strdate);
END
GO
Tailwindの「whitespace-pre-line」について

## whitespace-pre-lineのあるなしでCSSにどんな違いが出るのか

whitespace-pre-line の あり／なし で CSS の挙動には次のような違いが出ます。

## ✅ white-space プロパティの理解が前提
CSS の white-space プロパティは、空白や改行の扱い方を決めるスタイルです。

**🧩 white-space: pre-line の特徴**
```
white-space: pre-line;
```

🟢 効果：
HTMLソース中の改行 (\n) を表示する

連続スペースは 1 つに縮める（通常の文と同様）

🧪 例：
```
<div class="whitespace-pre-line">
  あさごはん  
  レクリエーション
</div>
```
🟰 表示される内容：
```
あさごはん
レクリエーション
```
❌ white-space を指定しない（または normal）場合
```
white-space: normal;
```
## 🔴 効果：
- 改行は無視される
- 連続スペースは 1 つに縮まる

## 表示される内容：
```
あさごはん レクリエーション
（※すべて 1 行に表示される）
```

🧭 比較表
CSS値	改行 (\n)	連続スペース	用途例
normal	❌ 無視される	🔽 縮まる	通常の段落
pre-line	✅ 改行される	🔽 縮まる	ユーザー入力の再現、改行を保ちつつ整形
pre	✅ 改行される	✅ 保たれる	ソースコード表示など
nowrap	❌ 無視される	🔽 縮まる	一行表示など

✅ Tailwind CSS のクラス対応
CSS	Tailwind クラス
```
white-space: normal;	whitespace-normal
white-space: pre;	whitespace-pre
white-space: pre-line;	whitespace-pre-line
white-space: nowrap;	whitespace-nowrap
```

## 🎯 結論：whitespace-pre-line を使うと…
HTML のテキスト中にある改行 \n を そのまま表示に反映できます。

ただし、連続スペースは通常通り 1つに縮まるため、整形表示には向いていません。
猿でもわかるAIプログラミングシリーズ 🐵💻 データが偏ってるってどういうこと？（バイアス問題）




### 1. はじめに：そのAI、本当に公平ですか？

最近では、AIを活用したサービスが急増しています。レコメンドエンジン、顔認識、スクリーニングなど、私たちの生活に浸透していますが、\*\*「なぜこの結果が出たのか？」\*\*と疑問に思ったことはありませんか？

たとえば、顔認識AIが特定の人種に対して誤認識を起こすケースや、求人スクリーニングAIが男性を優遇してしまう事例など、**AIの「バイアス（偏り）」が原因となる問題**が数多く報告されています。

本記事では、「バイアス」とは何か、なぜ起こるのか、どのように対処できるのかを、**実際のコード例と共に**丁寧に解説していきます。

---

### 2. バイアスとは何か？機械学習における偏りの正体

#### 🔍 定義：バイアスとは

「バイアス」とは、「偏り」や「先入観」を意味します。機械学習においては、**訓練データの分布が現実世界を正確に反映していないこと**を指します。

##### よくあるバイアスの種類

| 種類          | 説明                       |
| ----------- | ------------------------ |
| サンプリングバイアス  | 特定の属性のデータが過剰 or 不足している   |
| 測定バイアス      | 測定方法自体に誤差や偏りがある          |
| アノテーションバイアス | 人間のラベリング作業による先入観         |
| アウトカムバイアス   | 過去の結果がバイアスを含んでいる（例：昇進履歴） |

> ✅ **ポイント：バイアスは学習時だけでなく、データ収集や評価にも存在する！**

---

### 3. 実践：バイアスのあるデータを可視化してみよう

今回は、架空の「求人応募データ」を用いて、性別によるサンプリングバイアスを検出する例を見てみましょう。

#### 📊 サンプルデータの作成

```python
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# 応募者データ（性別・合格フラグ）
data = pd.DataFrame({
    'gender': ['male'] * 90 + ['female'] * 10,
    'passed': [1] * 45 + [0] * 45 + [1] * 5 + [0] * 5
})

# 可視化
sns.countplot(x='gender', hue='passed', data=data)
plt.title("性別と合否の分布")
plt.show()
```

#### 🔍 解説：

* 応募者の9割が男性、1割が女性という**極端な偏り**
* この状態で学習を進めると、AIは「男性の方が受かりやすい」と学習してしまいます

---

### 4. 実務で役立つTips：バイアス検出と対処法

#### ✅ 検出するには？

* **EDA（探索的データ分析）** を丁寧に行うこと
* 属性ごとの分布を **グラフや比率でチェック**
* モデルの出力結果を属性ごとに評価（例：男女別のPrecision/Recall）

#### 🔧 よく使うライブラリ

* [`Fairlearn`](https://fairlearn.org/)
* [`AIF360`](https://github.com/Trusted-AI/AIF360)

#### 🛠️ 対処法の一例

| アプローチ    | 内容                                   |
| -------- | ------------------------------------ |
| 再サンプリング  | 過少データのオーバーサンプリング or 過多データのアンダーサンプリング |
| 属性分離学習   | 属性ごとに別モデルで学習・予測                      |
| 公平性制約の導入 | 学習時に公平性メトリクスを最適化に含める                 |

---

### 5. 応用：公平性を考慮したモデル評価

以下は `Fairlearn` を用いた、性別によるモデル出力の公平性を評価する例です。

```python
from fairlearn.metrics import MetricFrame, selection_rate, false_positive_rate
from sklearn.metrics import accuracy_score

# 予測と実ラベル
y_true = data['passed']
y_pred = [1 if x == 'male' else 0 for x in data['gender']]  # わざとバイアスのある予測

# 属性
sex = data['gender']

# MetricFrameで評価
metrics = MetricFrame(
    metrics={'accuracy': accuracy_score, 'FPR': false_positive_rate, 'Selection Rate': selection_rate},
    y_true=y_true,
    y_pred=y_pred,
    sensitive_features=sex
)

print(metrics.by_group)
```

#### 出力例：

```
          accuracy  FPR  Selection Rate
female       0.50  0.50             0.0
male         0.50  0.50             1.0
```

→ 明らかに「女性をすべて不合格と判断」しており、Selection Rate の差が1.0で極端です。

---

### 6. まとめ：AIの公平性は「使う側」の責任

#### 🔎 本記事のポイント

* バイアスはデータの収集・ラベリング・学習のすべての段階に潜む
* バイアスを無視すると、**信頼されないAI**になる
* 「予測精度が高い」だけでなく、**公平性メトリクス**をチェックする習慣を持とう

#### 📌 最後に：バイアスとの向き合い方

* 完全にバイアスを排除するのは難しい
* だからこそ、**「見える化」して、納得できるレベルまでコントロール**することが重要です

---

 

### ✨ 参考リンク

* [Fairlearn公式](https://fairlearn.org/)
* [AI Fairness 360 (IBM)](https://aif360.mybluemix.net/)
* [The Hidden Bias in AI](https://hbr.org/2021/10/the-hidden-biases-in-ai)

---

**この記事が「なるほど」と思えたらぜひLike・フォローお願いします 🙌**
看護師こそエンジニアになるべき3つの理由

## 看護師こそエンジニアになるべき3つの理由

> 「転職するならITがいいらしい」  
> 「でも私、看護師だし…文系だし…」  
>  
> そう思ったそこのあなた。  
>  
> **実はあなた、すでに“現場力”と“鬼キャッチアップ力”を持った超ポテンシャル人材です！**

---

## 理由①：看護学校で鍛えられた“鋼メンタル”が、現場で光る

- レポート、実習、追試、無限のケーススタディ…  
- 教官の言葉が一言一句違っていたら落ちる記録チェック…  
- 「実習先が怖すぎてメンタル蒸発しかけた」って人も多いのでは？

そんな地獄を耐え抜いたメンタル、  
**SIerの納期前とか余裕です。**

むしろ「仕様変更？了解です😊」って、落ち着いてコード直してる未来が見えます。

---

## 理由②：国家試験に受かった人の“追い上げ力”は異常

- 国試前に「もうやばいかも…」って言いながら、  
- なぜか**最後の2週間で人間じゃない量の問題集を解きまくる能力**。

この“火事場キャッチアップ力”、  
エンジニアでもガンガン活きます！！

> 実際、文系・未経験で始めた人でも「とりあえずReact覚えるか」で1か月後にはToDoアプリ完成させてます。

---

## 理由③：エンジニアも“人間観察”が命です

「エンジニア＝PCカタカタだけ」と思ってませんか？  
ところが：

- 仕様の裏にある“本当のニーズ”を汲み取る  
- バグ報告から状況を“観察・推測”する  
- 一緒に働く人の癖を見抜いて対応を変える

全部、**現場で患者さん相手にやってたこと**と一緒です。

看護師出身のあなたなら、Slackのやりとりでも  
「この人、今日ちょっとイラついてるな」とか、すぐ気づくはず。

---

## 看護師→エンジニアは意外と多い？

実はこれ、けっこうあるあるです。  
これまで関わったプロジェクトの中で、  
「前職、看護師でした」というエンジニアに何人も出会ってきました。

会うたびに看護師友達から、

- 「どうやってエンジニアに転職したの？」
- 「最初って何から勉強した？」
- 「やっぱり医療系システムから入るべき？」

なんて相談をされるそうです。

でも正直、**医療系にこだわる必要はまったくありません。**  
Web制作、業務アプリ、スタートアップ開発──  
**あなたの“気配り力”と“学習力”はどこでも求められます。**

---

## 最後に

- 看護師＝根性ある
- 看護師＝学習スピードが速い
- 看護師＝観察力と対応力が高い

そんな人たちが、キーボード片手に世界を変えていく未来、  
めっちゃありだと思います！！

あなたの次のステージ、IT業界かもしれません。


## 追記
思っていた以上に多くの反響をいただき、驚いています。

毎日、医療現場で人の命と向き合っている皆さんには、本当に頭が下がる思いです。

この記事を書いたのは、医療従事者の方々が持つ“現場でのマインド”が、実はエンジニアの世界にも通じる部分があると思ったからです。

もしこの記事が、「エンジニア」という道を選択肢のひとつとして思い浮かべるきっかけになれば、とても嬉しく思います。
税抜き金額から消費税額を求める

--概要　　　：指定した日付の期間に該当する税抜金額から消費税額を返します。
--引数　　　：[@税抜金額]
--　　　　　　[@対象日付]
--戻り値　　：消費税額
IF (EXISTS(SELECT * FROM sysobjects WHERE (type = 'FN') AND (name = 'fn消費税')))
BEGIN
    DROP FUNCTION fn消費税;
END
GO

CREATE FUNCTION fn消費税
(
    @税抜金額 MONEY,
    @対象日付 DATETIME
)
RETURNS MONEY
AS
BEGIN
    --対象日付に該当する消費税率を消費税率マスタから取得します。
    DECLARE @消費税率 INT;
    SET @消費税率 = 0;
    SELECT @消費税率 = [税率] FROM [消費税率]
    WHERE @対象日付 BETWEEN [開始日付] AND [終了日付];

    --取得した消費税率と税抜金額を乗算して消費税額を求めます。
    RETURN ROUND(@税抜金額 * @消費税率 / 100, 0, 1);
END
GO
税抜き金額から税込金額を求める

--概要　　　：指定した日付の期間に該当する消費税率から税込金額を返します。
--引数　　　：[@税抜金額]
--　　　　　　[@対象日付]
--戻り値　　：税込金額
IF (EXISTS(SELECT * FROM sysobjects WHERE (type = 'FN') AND (name = 'fn税込')))
BEGIN
    DROP FUNCTION fn税込;
END
GO

CREATE FUNCTION fn税込
(
    @税抜金額 MONEY,
    @対象日付 DATETIME
)
RETURNS MONEY
AS
BEGIN
    --対象日付に該当する消費税率を消費税率マスタから取得します。
    DECLARE @消費税率 INT;
    SET @消費税率 = 0;
    SELECT @消費税率 = [税率] FROM [消費税率]
    WHERE @対象日付 BETWEEN [開始日付] AND [終了日付]

    --取得した消費税率と金額を乗算して戻り値として返します。
    RETURN ROUND(@税抜金額 * (100 + @消費税率) / 100, 0, 1);
END
GO
税込み金額から税抜金額を求める関数

--概要　　　：指定した日付の期間に該当する消費税率から税抜金額を返します。
--引数　　　：[@税込金額]
--　　　　　　[@対象日付]
--戻り値　　：税抜金額
IF (EXISTS(SELECT * FROM sysobjects WHERE (type = 'FN') AND (name = 'fn税抜')))
BEGIN
    DROP FUNCTION fn税抜;
END
GO

CREATE FUNCTION fn税抜
(
    @税込金額 MONEY,
    @対象日付 DATETIME
)
RETURNS MONEY
AS
BEGIN
    --対象日付に該当する消費税率を消費税率マスタから取得します。
    DECLARE @消費税率 INT;
    SET @消費税率 = 0;
    SELECT @消費税率 = [税率] FROM [消費税率]
    WHERE @対象日付 BETWEEN [開始日付] AND [終了日付]

    --取得した消費税率と金額を乗算して戻り値として返します。
    DECLARE @消費税額 INT;
    SET @消費税額 = ROUND(@税込金額 * @消費税率 / (100 + @消費税率), 0, 1);

    --税込金額から消費税額を減算し、税抜金額を返します。
    RETURN @税込金額 - @消費税額;
END
GO
Raspberry Pi 4の初期設定（日本語化）

# 概要
今更ですが、手持ちのラズパイ（４）をデスクトップとしてセットアップすることになったので、設定手順を残しておきます。

# 手順
## Raspberry Pi OSのインストール
以下を参考にRaspberry Pi Imagerを使ってインストールします。

https://qiita.com/mmake/items/576a2f60dffcd9291da3

インストール後、以下のコマンドでアップデートしておきます。
```
$ sudo apt-get update
$ sudo apt-get upgrade
```

## 日本語設定
### 表示設定
画面の表示が英語になっているので、日本語に変更します。
1. メニューボタンから「Preferences」「Raspberry Pi Configuration」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/c6052c14-0e2e-491c-a01d-bec372b7d1aa.png)
1. LocationタブのLocaleの「Set Locale...」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/1539838d-b42e-4782-b7c5-46c5b96090ef.png)
1. Languageで「ja (Japanese)」、Character Setで「UTF-8」を選択して「OK」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/ce9eea39-0685-49bf-be29-a36b903a081d.png)
1. 設定画面を閉じると再起動するか聞かれるので、「Yes」をクリックして再起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/def3c403-701e-401c-947e-8634cf49481e.png)
1. 再起動すると、日本語表示されるようになります。

### 入力設定
以下のコマンドでFcitxをインストールし、再起動すると半角/全角キーで日本語入力できるようになります。
```
$ sudo apt install fcitx-mozc
```

### フォント設定
以下のコマンドでTakaoフォントをインストールします。
```
$ sudo apt-get install fonts-takao
```
インストール後、以下の手順でフォントを変更します。
1. メニューボタンから「設定」「外観の設定」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/e8fa7eaf-6172-45a7-af20-b3ef34a71b5c.png)
1. システムタブのフォントのボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/91cc92e2-ba50-43d5-ae93-9612ffbe0f57.png)
1. 検索窓に「takao」と入力し、好みのフォントを選択して、「選択」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/916611/479c3ed4-8cf0-4f88-9ea7-c7cd8a1e2a6a.png)

# 参考記事
https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-input-japanese/

https://raspi.ryo.sc/raspi_japanese_font/

https://note.com/sig_eng/n/nb2124e547369
無料のkintoneプラグインを提供している会社

# 環境
- kintone

# 対象
- 無料のkintoneプラグインを提供している会社を知りたい人

# ⚠️注意
- 無料プラグインは基本的にサポート対象外なので不具合があっても対応されません
それを理解した上で使用しましょう
- 2025年4月現在、無料なプラグインです

# cybozu
- 様々な種類のプラグインをオープンソースで提供している
- プラグインサンプルの意味合いもあるので自分でプラグインを作成する時の資料にもなる

https://cybozu.dev/ja/kintone/tips/development/plugins/sample-plugin/


# Ribbit's works
- こちらも様々なプラグインをオープンソースで提供している
- 汎用的なものからChatGPT連携プラグインなど珍しいものあります

https://ribbit.konomi.app/kintone-plugin/

# ジャパンコンピュータサービス
- コメント欄非表示プラグインなど痒い所に手が届く系がある印象
- 検索プラグインは無料とは思えないほど高性能

https://dx.japacom.co.jp/kintone-plugins/?filter=free

# ジョイゾー
- 他システムとの連携用プラグインを用意してくれています

https://www.joyzo.co.jp/service/plugin_free/

# アディエム
- cybozuのオープンソースのプラグインをブラッシュアップして使いやすくしている印象

https://adiem.jp/kintone-plugin/
Rorkについて

# はじめに
モバイルアプリ開発の世界は急速に進化し続けています。React Nativeの登場により、一つのコードベースでiOSとAndroidの両方に対応できるようになりましたが、それでも開発には多くの専門知識と時間が必要です。そんな中、AI技術を活用してReact Native開発を劇的に効率化するツール「Rork」が注目を集めています。

# Links

https://github.com/rorkai

https://x.com/rork_app

# Rorkとは何か
Rorkは、React Nativeアプリケーション開発に特化したAIアシスタントです。従来の開発プロセスで時間のかかる作業を自動化し、開発者がより創造的な作業に集中できる環境を提供します。単なるコード生成ツールではなく、開発全体のワークフローを理解し、最適な解決策を提案する包括的なパートナーとして機能します。
- 革新的な機能群
- インテリジェントなコード生成
Rorkの最も印象的な機能の一つは、自然言語での要求を理解し、それに基づいて高品質なReact Nativeコードを生成する能力です。「ユーザープロフィール画面を作って」という簡単な指示から、状態管理、フォーム処理、バリデーションまで含んだ完全なコンポーネントを生成できます。
生成されるコードは単に動作するだけでなく、React Nativeのベストプラクティスに従い、パフォーマンスとメンテナンス性を考慮した設計になっています。これにより、経験の浅い開発者でも、プロフェッショナルレベルのコードを書くことができます。

# クロスプラットフォーム最適化
React Nativeの大きな利点の一つは「一度書けばどこでも動く」ことですが、実際にはiOSとAndroidで微調整が必要な場合が多々あります。Rorkはこの問題を解決するため、各プラットフォームの特性を深く理解し、適切な最適化を自動的に適用します。
例えば、iOSでは滑らかなアニメーションを重視したコードを、Androidでは多様なデバイスサイズに対応したレスポンシブなレイアウトを提案します。これにより、開発者は各プラットフォームの細かな違いを意識することなく、統一された開発体験を得られます。

## 問題解決とデバッグ支援
React Native開発では、しばしば複雑なエラーやパフォーマンスの問題に直面します。Rorkは豊富な知識ベースを活用して、これらの問題を迅速に特定し、具体的な解決策を提示します。
メモリリークの検出、レンダリングパフォーマンスの最適化、ネイティブモジュールの統合問題まで、幅広い技術的課題に対応できます。さらに、問題の根本原因を説明し、将来同様の問題を避けるためのベストプラクティスも教えてくれます。

# 開発コミュニティへの影響
Rorkの登場は、React Native開発コミュニティ全体に新しい動きをもたらしています。従来は高度な技術スキルが必要だったモバイルアプリ開発が、より多くの人にとってアクセシブルになっています。
デザイナーがプロトタイプを作成したり、製品マネージャーが機能の実現可能性を検証したりする際にも、Rorkが強力なツールとして活用されています。これにより、チーム全体のコラボレーションが向上し、より良いプロダクトが生まれる土壌が整っています。

# まとめ
Rorkは単なる開発ツールを超えて、React Native開発の新たなパラダイムを提示しています。AI技術の力により、開発者はより創造的で価値の高い作業に集中でき、結果として優れたモバイルアプリケーションをより短期間で世に送り出すことができるようになります。
技術の民主化という観点からも、Rorkのようなツールは重要な意味を持ちます。
プログラミング経験が少ない人でも、アイデアがあれば実際に動くアプリを作ることができる時代が到来していますね。
Functorの定義の f、t の方が良くね？

Haskellを勉強していて、`Functor`の章に入ったんだけど、定義を見てふと思った。

```haskell
class Functor f where
    fmap :: (a -> b) -> f a -> f b
```

この`f`、**functionの`f`**に見えてややこしい。
だって、`fmap`に渡すのは関数（`a -> b`）だけど、`f`に入るのって`Maybe`とか`[]`とかの**型**だし。

だったらこれ、`f`じゃなくて **typeの`t`** にした方がいい。

```haskell
class Functor t where
    fmap :: (a -> b) -> t a -> t b
```

こっちの方がいいよねって話。

---

そんなことを、ChatGPT先生に聞いてみた。

> それ、確かにわかりにくいよね。
でもこの`f`は「Functorのf」として慣習的に使われてるだけで、別に`t`にしても意味はまったく同じなんだよ。初学者は`t`の方がピンとくるかもね。

とのこと。まぁそうですよねって感じ。

---

雑にまとめると、可読性を取るか言語としての美しさを取るかって話なんだと思う。
Pythonなら可読性に寄ってたかもだけど、Haskellはそういう思想じゃないから`f`なんだろうね。おもろいね。
【Python初心者】イテラブル・イテレータを print() する時のルールまとめ

Pythonで `map()` や `reversed()` を使って `print()` したとき、  
中身が表示されずに `<map object at 0x...>` のような謎の表記が出てきて戸惑ったことがありました。

この記事では、なぜそうなるのか、どうすれば中身を確認できるのかを、初心者向けにやさしく整理してみます。

## print() の内部で何が起きているか？

Pythonでは `print(obj)` を実行すると、内部的には `str(obj)` が呼ばれます。  
そして `str(obj)` の処理内容は、そのオブジェクトが `__str__()` を定義しているかどうかで決まります。

- `__str__()` が定義されていれば、人間にわかりやすい形で表示される
- `__repr__()` が定義されてれば、オブジェクトを生成する情報がわかる形で表示される
- どちらも定義されていなければ、`<object at 0x...>` のような文字列が出力される
- listなどの要素は`__repr__()`で表示される

## 表示されるもの・されないもの一覧

| オブジェクトの種類           | print()で中身が見える？ | 例                            | 備考                                 |
|------------------------------|--------------------------|----------------------------------|--------------------------------------|
| list, tuple, str, dict, set | ✅ 見える               | `[1, 2, 3]`                      | `__str__()` が定義されている         |
| range                        | 🔶 範囲のみ見える         | `range(0, 5)`                    | 要素の一覧は表示されない            |
| iter(list)                   | ❌ 見えない             | `<list_iterator object at ...>` | イテレータ                          |
| map, zip, filter             | ❌ 見えない             | `<map object at ...>`           | イテレータ                          |
| reversed                     | ❌ 見えない             | `<list_reverseiterator at ...>` | イテレータ                          |
| enumerate                    | ❌ 見えない             | `<enumerate object at ...>`     | イテレータ                          |

❗ 補足：上の表で「中身が見えない（❌）」とされているオブジェクトは、すべて **イテレータ** です。  
`print()` で中身を確認したい場合は `list()` で展開する必要があります。

## なぜ list() が必要なのか？

イテレータは「1つずつ値を出す装置」です。  
`print()` はその装置を表示しようとしても、中身を直接に表示することはできません。

そこで `list()` で展開すると、その値をすべて取り出して「見るための実体」に変換できます。

```python
m = map(str, [1, 2, 3])
print(m)             # <map object at ...>
print(list(m))       # ['1', '2', '3']
print(list(m))       # [] （2回目は空）
```

## 使い切りに注意（list() は1回限り）

`map()` や `zip()` などのイテレータは、`list()` によって一度展開された時点で**中身が消費されます**。  
よくある誤解が、以下のようなコードです。

```python
z = zip([1, 2], ['a', 'b'])
print(list(z))  # [(1, 'a'), (2, 'b')]
print(list(z))  # []（すでに使い切っているため空）
```

これでは「list() を使っても使い切りになる」と思ってしまいがちですが、  
**問題は list() を繰り返していることではなく、イテレータ z を2回使ってしまっていること**です。

### 🔁 中身を何度も使いたい場合の書き方

```python
z = zip([1, 2], ['a', 'b'])
z_list = list(z)        # 一度だけ展開して保存

print(z_list)           # OK
print(z_list)           # 何度でも使える（これはリストだから）
```

つまり、**イテレータは使い切りだが、`list()` によって得られるリストは繰り返し使える**ということです。

## 実務でのおすすめ判断基準

| 目的                       | 対処法                 |
|----------------------------|------------------------|
| 単に中身を確認したい       | `list(...)` で包む     |
| 何度も繰り返し使いたい     | `list()` で変数に保存  |
| 巨大データを扱っている     | イテレータのまま処理する（`for`文など） |

※「巨大データを扱っている場合」は、イテレータのまま処理することで、必要な分だけ順に処理でき、  
すべてを `list()` で展開してしまうと、メモリを大量に消費してしまうことがあります。  
そのため、`for` 文で少しずつ処理する方が効率的です。

## おわりに

最初は、なぜ `print()` で中身が表示されないのか分からず混乱しました。  
でも「イテレータだから中身が見えない」「`list()` によって中身を取り出してリスト化すれば見える」というルールを知っておくと、だいぶ安心できます。  
`print()` で `<object at ...>` のような表示が出たときは、**それがイテレータである可能性も含めて**、`list()` で中身を確認してみるとよいかもしれません。  
ただし、イテレータ以外でもこのような表示になるオブジェクトはあるため、`type()` や `hasattr(obj, '__next__')` などで確認することが確実です。
PythonでMH-Z19センサーからCO2濃度を1分ごとにCSV保存するプログラム

## 概要


室内環境の空気質をモニタリングするため、CO2濃度を測定することは重要です。MH-Z19はUART通信で簡単に使えるCO2センサーで、Raspberry Piなどと組み合わせて環境計測が可能です。

## プログラムのポイント

* `mh_z19`ライブラリを使ってCO2濃度を取得
* 1分ごと(変更可能)に測定データを取得してCSVファイルに追記保存
* タイムスタンプも一緒に記録して時系列データを管理
* `KeyboardInterrupt`でプログラムを安全に終了可能

## コード全文

```python
import mh_z19
import time
import csv
from datetime import datetime

def read():
    # mh_z19からデータを取得
    out = mh_z19.read(serial_port="/dev/ttyS0")  # シリアルポートは環境に合わせて変更してください

    if out and 'co2' in out:
        return str(out['co2'])  # CO2値を文字列として返す
    return "Error reading CO2"

if __name__ == '__main__':
    header = ['timestamp', 'co2']
    with open('co2.csv', 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(header)

    try:
        while True:
            co2 = read()
            timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            print(f"CO2 Concentration: {co2} ppm")

            with open('co2.csv', 'a', newline='') as f:
                writer = csv.writer(f)
                writer.writerow([timestamp, co2])

            time.sleep(60)

    except KeyboardInterrupt:
        print("Program terminated.")
```

## 実行環境と注意点

* Raspberry PiなどのLinux環境で動作確認済み
* シリアルポート`/dev/ttyS0`は環境により異なるため、適宜修正してください
* `mh_z19`ライブラリは事前に`pip install mh-z19`でインストールしてください

---
カレンダーのfree/busyを理解する

## はじめに
カレンダーのfree/busyの意味を学んでいると、あれ？なんでここでfree/busyの話が出てくるんだ？そもそもfree/busyって空き時間かどうかを判定するプロパティだよな？？ってなりました。学んでいくと、2つの意味があるようです。今回はfree/busyについて学んでいきます。

### 1. 実際のスケジュール状態（Availability）

- **free**: その時間帯に予定（イベント）が入っておらず、空いている状態  
- **busy**: その時間帯に何か予定が入っており、手が離せない状態  

> **例**  
> - 09:00–10:00 に会議が入っていれば → **busy**  
> - 10:00–11:00 に何もなければ → **free**  

PostgreSQL の `tsrange`（時間範囲型）などで表現し、  
RFC 5545 の `VFREEBUSY` コンポーネント、または Google Calendar API の `/freeBusy` エンドポイントで取得できます。

https://developers.google.com/workspace/calendar/api/v3/reference/freebusy/query?utm_source=chatgpt.com&hl=ja

---

### 2. 表示権限としての free/busy（Permission）

- ユーザーA がユーザーB のカレンダーを見るとき、  
  - **full details（詳細表示）**  
  - **free/busy only（予定有無のみ）**  
  - **no access（見る権限なし）**  
 という3段階の見え方を設定できるものが多いです。

| 権限レベル          | 見える情報                     |
|---------------------|--------------------------------|
| **viewer / reader** | イベントのタイトルや場所など詳細 |
| **free/busy only**  | 「busy」（予定あり） or 「free」（予定なし）のみ |
| **no access**       | イベント自体がリストに現れない   |


## さいごに
2つの意味で使われているのですね。結構奥が深く難しいですね。。。😅
カレンダー周りはアクセスコントロールがかなり肝になってくる感じですね。
OCI Email Deliveryのメール送信数をOCI CLIで取得する

## 本記事の内容
OCIのEmail Deliveryはサービスリミットにより一日に送信可能なメール数が決められています。指定した時間の範囲で送信したメール数をOCI CLIで把握する方法を試してみたので、その内容を記載します。

## 確認方法
今回の検証は、OCI ComputeからmailxとEmail Deliveryを用いてメール送信を行い、その結果をOCI CLIで確認するという方法を行っています。

必要な設定は事前に以下ハンズオンを参考に行い、メール送信が可能な状態にしておきます。OCI CLIのインストールはマニュアルを参照して事前に済ませております。
【Email Delivery ハンズオン】
https://oracle-japan.github.io/ocitutorials/intermediates/sending-emails-1/
【OCI CLI】
https://docs.oracle.com/ja-jp/iaas/Content/API/SDKDocs/cliinstall.htm

上記に加え、今回確認するログはEmail Deliveryの配信到達性ダッシュボードのログの有効化が必要になるため、以下マニュアルを参考に設定を行っています。今回は既存のロググループにログを登録するよう設定しました。
【マニュアル】
https://docs.oracle.com/ja-jp/iaas/Content/Email/Reference/dashboard-topic-enabling-logging.htm

## 検証結果
まずは以下コマンドでメールを送信します。
```
echo "メールテスト" | mailx -s "メールテスト" <送信先メールアドレス>
```
メール受信が確認できた後、OCIコンソールのLoggingサービスから、配信到達性ダッシュボードのログの有効化にて設定したロググループでログを確認してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599194/e7971969-15ca-44d6-b349-4c0def9b233f.png)
メールが受信された場合、data.messageが「Accepted email <送信元> → <送信先>」となっていることが分かります。そのため、OCI CLIで検索する際に、以下のように「where data.message = '\\''Accepted*'\\''」とすることで、成功した送信数を取得します。
```
oci logging-search search-logs --search-query 'search "<compartment_ocid>/<log_goup_ocid>" | where data.message = '\''Accepted*'\'' | count' --time-start YYYY-MM-DDT00:00:00Z --time-end YYYY-MM-DDT23:59:00Z
```
検索結果はJSON形式で返されます。
```
{
  "data": {
    "fields": null,
    "results": [
      {
        "data": {
          "count": 1
        }
      }
    ],
    "summary": {
      "field-count": null,
      "result-count": 1
    }
  }
}
```
countが「1」となっていることから、対象範囲の時間帯で送信成功したメールの数が取得できたことを確認できました。

## 最後に
サービスリミットはテナンシに対して課されますが、テナンシ全体のメール送信数を検索する方法は無いようでした。そのため、コンパートメント毎にメール送信数を検索し、それらを集計するようシェルスクリプトを構成することで、指定した検索時間帯でのメール送信数を把握することができると考えられます。
Databricksランタイム17.0における再起的クエリーのサポート

こちらのアップデートです。

https://docs.databricks.com/aws/ja/release-notes/runtime/17.0#recursive-common-table-expressions-rcte-support

> **再帰的共通テーブル式(rCTE)のサポート**
> Databricksでは、[再起的な共通テーブル式(rCTE)](https://docs.databricks.com/aws/ja/sql/language-manual/sql-ref-syntax-qry-select-cte)を用いた階層型データのナビゲーションがサポートされました。再帰的なリレーションシップを辿るには`UNION ALL`と自己参照CTEを使います。

Databricksランタイム17.0を使います。

![Screenshot 2025-05-27 at 9.12.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6588d7c1-83f6-48cc-a443-34ccc885301e.png)

2地点間のルートを表現する一時ビューを作成します。

```sql
-- 一時ビュー 'routes' を作成
CREATE TEMPORARY VIEW routes(origin, destination) AS VALUES
  ('New York', 'Washington'),
  ('New York', 'Boston'),
  ('Boston', 'New York'),
  ('Washington', 'Boston'),
  ('Washington', 'Raleigh');
```

`WITH RECURSIVE`を用いることで、再帰的なクエリーを定義できます。以下では、`SELECT...FROM routes...JOIN destinations_from_new_york`のように自己参照しています。

```sql
-- 再帰的に 'New York' から到達可能な目的地を計算
WITH RECURSIVE destinations_from_new_york AS (
    -- 初期状態として 'New York' を目的地とし、経路に 'New York' を含め、長さを 0 とする
    SELECT 'New York' AS destination, ARRAY('New York') AS path, 0 AS length
    UNION ALL
    -- ルートテーブルと再帰的に結合し、新しい目的地、経路、長さを計算
    SELECT r.destination, CONCAT(d.path, ARRAY(r.destination)), d.length + 1
      FROM routes AS r
      JOIN destinations_from_new_york AS d
        -- 現在の目的地が出発地と一致し、経路に含まれていない場合に結合
        ON d.destination = r.origin AND NOT ARRAY_CONTAINS(d.path, r.destination)
  )
  -- 再帰的に計算された結果を選択
  SELECT * FROM destinations_from_new_york;
```

`New York`を起点としてルートを辿って`path`を構成してます。

|destination|path|length|
|---|---|---|
|New York|["New York"]|0|
|Washington|["New York","Washington"]|1|
|Boston|["New York","Boston"]|1|
|Boston|["New York","Washington","Boston"]|2|
|Raleigh|["New York","Washington","Raleigh"]|2|

なお、ストアドプロシージャでも使用できます。

```sql
-- ストアドプロシージャ 'numbers' を作成
CREATE PROCEDURE takaakiyayoi_catalog.default.numbers(end INT) 
-- SQL 言語を使用
LANGUAGE SQL
-- セキュリティコンテキストを INVOKER に設定
SQL SECURITY INVOKER
-- コメントを追加
COMMENT 'Returns numbers from 1 to end'
-- プロシージャの開始
AS BEGIN
  -- 再帰的な CTE を定義
  WITH RECURSIVE rec(num) AS
    -- 初期値を設定
    (VALUES (1) 
    -- 再帰的に値を生成
    UNION ALL SELECT num + 1 FROM rec WHERE num < end)
    -- 結果を選択
    SELECT * FROM rec;
-- プロシージャの終了
END;
```

![Screenshot 2025-05-27 at 9.14.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/af2d8c14-515c-4545-b395-0deed3727f8b.png)


```sql
CALL takaakiyayoi_catalog.default.numbers(5);
```

|num|
|---|
|1|
|2|
|3|
|4|
|5|

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
[登録不要＆完全無料]画像をアップロードするだけでフォントを特定

以下のサイトは **登録不要＆完全無料**、しかも画像をアップロードするだけでフォントを特定できます。使い勝手に少しずつ個性があるので、気に入ったものをブックマークしておくと便利です。

---

### 1. Font Squirrel 「Matcherator」

* 画像をドラッグ＆ドロップするだけで文字部分を自動抽出し、9 万点超のフォントから候補を提示。
* “Advanced” モードでは文字ごとの切り抜きや傾き補正もでき、手書き風や縦書きでもかなり粘り強く探してくれます。
* 完全匿名で利用でき、検索結果に「Only Free Fonts」フィルタも付いているので、そのまま商用OKの無料フォントを見つけるのも簡単です。([Font Squirrel][1])

---

### 2. Creative Market 「Font Finder」

* 2024年末に公開された軽量ツール。JPEG/PNG（5 MB以下）を放り込むと即解析して候補フォントを一覧表示します。
* ページ中段に “**no signup required**” と明記されており、アカウントなしでも最後まで結果を閲覧可能。
* マッチしたフォントが有料の場合はワンクリックでマーケットの購入ページに遷移できるため、「字体名を知りたいだけ」「すぐに購入して使いたい」のどちらにも向いています。([Creative Market][2])

---

### 3. Adobe Fonts 「Visual Search」

* Adobe IDがなくても **検索までは無料で開放** されており、アップロードした画像からAdobe Fontsライブラリ（3 万書体以上）を横断検索。
* 候補には Google Fonts 由来の無償フォントも含まれるため、実質的に“無料フォント検索機”としても使えます。
* ※フォントを **同期・ダウンロード** したい場合は Creative Cloud 無料プランへのログインが必要ですが、「名前だけ知りたい」用途ならゲストのままで十分です。([Adobe Fonts][3])

---

#### ちょっと補足

| シーン                                | まず試すサイト           |
| ---------------------------------- | ----------------- |
| ラテン文字中心で、無料フォントが欲しい                | **Matcherator**   |
| 有料/無料を問わず幅広い候補をざっと見たい              | **Font Finder**   |
| Adobe Fonts も含めて業務用フォントの正式名称を確認したい | **Visual Search** |

> **日本語・中国語フォントの場合**
> 和文・中文の収録が多い「LikeFont」もおすすめです。ゲストのまま検索できますが、履歴保存には会員登録が必要になります。([en.likefont.com][4])

これらのサイトを使えば、バナーやロゴで見かけた気になる書体をすぐに突き止められます。ぜひ試してみてください！

[1]: https://www.fontsquirrel.com/matcherator "Identify Fonts - The Font Squirrel Matcherator"
[2]: https://creativemarket.com/font-finder "Font Finder - Identify Fonts in Seconds | Creative Market"
[3]: https://fonts.adobe.com/fonts/vs/upload?utm_source=chatgpt.com "Visual search | Adobe Fonts"
[4]: https://en.likefont.com/ "LikeFont-Online image font recognition website	"
Dockerハンズオン①基本動作確認



こんにちは。
今週はDockerハンズオン期間と題して、入門レベルのハンズオンから始めていきます。

## 前提
・VSCodeがインストールされている。

## Docker Desktopのインストール
以下のページからDocker Desktopをインストールして、登録します。
https://www.docker.com/ja-jp/products/docker-desktop/

登録が終わると以下の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/14404fd1-4ab0-4032-8f4b-50104759400d.png)


## Dockerイメージの取得
Dockerから用意されているテスト用のイメージ「hello-world」を取得していきます。
イメージ取得には```pull```コマンドを使用します。

VSCodeで以下のコマンド実行します。
```docker pull hello-world```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/86b5f42f-ac5c-4f61-a54c-730ff7a4193c.png)


次に、Dockerイメージを一覧表示させるコマンドを実行します。
先程取得したイメージ「hello-world」が表示されるはずです。
```docker image ls```
※```ls```=listの意味


先ほど取得したイメージ「hello-world」が表示されていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/bcc91a05-8afd-48dc-b5f0-8341fd47e031.png)


## Dockerイメージからコンテナを起動

取得したイメージ「hello-world」から、コンテナを起動させます。
コンテナ起動の際は```container run```コマンドを使用します。

以下コマンドを実行します。
``` docker container run hello-world```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/6ea3f557-1b6e-4274-8b88-362b5fc0b8a3.png)


Hello from Docker! 
の文字列が表示されており、成功です。


現在ローカルにあるコンテナを一覧表示させるコマンドを実行します。
```docker container ls -a```
※optionの補足　```-a```=```--all```　
allで停止中のコンテ含めてすべて表示させます。先ほどのコンテナ起動してメッセージ表示後、コンテナは自動で停止されます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/c4fbbac5-3550-452b-9a8b-e78864fdb9d2.png)


## Dockerコンテナの削除

コンテナ削除のコマンドを実行します。
```docker container rm <container ID>```

先程コンテナ一覧表示した際にcontainer IDが記載されているので、コピペします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/aedf234b-0f05-4679-ba84-ec1be4806fc4.png)


## Dockerイメージの削除
イメージ削除のコマンドを実行します。
```docker image rm hello-world```

その後```ls```コマンドで一覧を表示すると、hello-worldが表示されなくなりました。
削除されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4084313/9cfe7377-7b37-48f8-880d-a08ef1ebd977.png)


## まとめ
シンプルなコマンドで基本動作ができることがわかりました。
想像していたより簡単でした。
引き続き学習を継続していきます。


## 参考
Cloudtech　AWSレッスン動画コース　【Docker-3】Dockerの動作確認
streamlitを用いた電話番号入力欄の作り方

# Pythonのstreamlitライブラリを用いたWebブラウザ上で電話番号を受け付ける入力欄のサンプルプログラム
![スクリーンショット 2025-05-07 8.03.41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1979979/30727de6-52ea-48b6-a1b7-1a45a61b502e.jpeg)
## ポイント
１．半角でも全角でもOk（半角に自動修正）
２．080，090で始まるものは，（携帯）と表示
３．03で始まるものは，（東京）と表示
４．数字以外の文字は自動で削除

＜実行方法＞
コマンドプロンプトで，以下をタイプして実行
streamlit run disp_tel_num.py

```disp_tel_num.py
# -*- coding: utf_8 -*-
import streamlit as st
import re

def format_phone_number(phone_number):
    """電話番号の形式を変換して表示する関数"""
    st.write(f"入力された電話番号 (raw): '{phone_number}'") # デバッグ用：入力直後の値を出力

    # 全角数字を半角数字に変換
    full_width = [chr(0xFF10 + i) for i in range(10)]
    half_width = [chr(0x0030 + i) for i in range(10)]
    translation_table = str.maketrans(dict(zip(full_width, half_width)))
    half_width_number = phone_number.translate(translation_table)
    st.write(f"半角変換後の電話番号: '{half_width_number}'") # デバッグ用：半角変換後の値を出力

    half_width_number = re.sub(r'\D', '', half_width_number) # 数字以外の文字を削除
    st.write(f"数字以外の文字削除後: '{half_width_number}'") # デバッグ用：数字以外の文字削除後の値を出力

    if re.match(r'^0[789]0\d{8}$', half_width_number):
        return f"{half_width_number[:3]}-{half_width_number[3:7]}-{half_width_number[7:]}（携帯）"
    elif re.match(r'^03\d{8}$', half_width_number):
        return f"{half_width_number[:2]}-{half_width_number[2:6]}-{half_width_number[6:]}（東京）"
    elif re.match(r'^0\d{9}$', half_width_number):
        return f"{half_width_number[:2]}-{half_width_number[2:6]}-{half_width_number[6:]}（その他）"
    elif re.match(r'^0[789]0\d{0,7}$', half_width_number):
        return "携帯電話番号の桁数が足りません"
    else:
        return "正しい電話番号を入力してください"

st.title("電話番号フォーマッター")

phone_input = st.text_input("電話番号を入力してください", "")

if phone_input:
    formatted_number = format_phone_number(phone_input)
    st.write("変換後の電話番号:", formatted_number)
```
mruby-simplehttpでNO_SSL

mrubyの3.4でmruby-printが削除され、mruby-polarsslのビルドが通らなくなっています。

とりあえずissueはあげているのですが、レスがありません。

https://github.com/luisbebop/mruby-polarssl/issues/19

mruby-simplehttpはmruby-polarsslに依存しているので、これもビルドできない状態でした。

我が家ではmrubyでシリアルからBLEの温湿度計のデータを拾って、おうちの中のサーバにhttpしたり、モジュール再起動時にhttpしたりしています。おうちの中なのでhttpsの必要がありません。

polarssl(mbedtsl)は結構大きく入れたものと、外したものを比較してみました。

mruby-polarssl入りmruby 2063204バイト

mruby-polarssl無しmruby 1395436バイト

MIPSモジュールのストレージは8Mと小さいので以前から外したいと思っていました。

ちょうど良い機会なので、@matsumotoryさんに相談してpullreqを取り込んでもらいました。

https://github.com/matsumotory/mruby-simplehttp/pull/31

NO_SSL環境変数にyesなど文字列を設定してmrubyをビルドするとmruby-polarsslが入らなくなりました。
追加ボタンで入力欄を増やして、削除ボタンで消すやつ【React】

# 注意

あらかじめ言っておきますが、筆者は初心者なので、自分なりの解釈でまとめています。「100%信じるぜ！」という気持ちで読まないようお願いします。どうぞよろしく！

# 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter


# 経緯
nextjs,typescript,supabaseを使用して、ポートフォリオを作成しているのですが、よく使用するものがあったので、備忘録として残します

以下の様なケースを想定します。
「献立を追加」ボタンを押下したら、献立カードが１つ増えるといったケースです。

![スクリーンショット 2025-05-26 9.01.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3893783/cc2f645c-5cb6-44d5-99b3-6fd8fea4ff6c.png)

# 前提
```typescript
type MenuItemsType = {
  id: number,
  date: Date,
  meal: {
    breakfast: string,
    lunch: string,
    dinner: string
  }
}

export default function Home() {
  const [menuSchedule, setMenuSchedule] = useState<MenuItemsType[]>([{
    id: new Date().getTime(),
    date: new Date,
    meal: {
      breakfast: '',
      lunch: '',
      dinner: '',
    }
  }])

return (
{menuSchedule.map((menuList, index) => (...
```

現在、`menuSchedule`には、空のデータが入っているので、カードは空白の状態が表示されます。

# 方法
## 増やす
配列を `map` で回してカードを表示しているため、同じ形式の空オブジェクトを追加すれば、カードが増える仕組みになります。
```typescript
const onEmptyMenuAddButtonClicked = () => {
  const newMenu = {
    id: new Date().getTime(), // 一意なID（タイムスタンプ）
    date: new Date(),
    meal: {
      breakfast: '',
      lunch: '',
      dinner: '',
    }
  }
  setMenuSchedule([...menuSchedule, newMenu])
}
```

## 消去
filterを使用すれば良いです。filterは、条件に一致したものを返します。
```typescript
const onMenuDeleteButtonClicked =(id:number)=> {
    const updated = menuSchedule.filter(menu => menu.id !== id)
    setMenuSchedule(updated)  
};

```

# 感想
これは、nextjsやreactでよく使用する方法だと思いますので、覚えます。
ガンガンアプリ開発していこう
プログラミング学習ないない

プログラミング学習中の皆様、こんな事していませんでしょうか？

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/6dcbafbb-4664-47b5-8e69-c7629f5e5c60.png width=50%>

最近では生成AIの登場により、「プログラミングに興味が湧いた」、「AIが助けてくれるなら独学でもやれそう」と、学習をスタートする方も増えたと思います。

しかし、間違った学習方法を続けてしまうと、途中で挫折してしまうことも少なくありません。
次のような行動に心当たりはありませんか？

## エラーで何時間も止まる

「なんでこのエラーが出るんだろう」と悩み続けて、1つのバグで何時間も調べずに手が止まっていませんか？（何時間は言いすぎかもしれませんが）


今の時代はAIがあります。ググったり、AIを使って先に進みましょう。

:::note warn
ただし、[イエローカード！まだプログラミング学習で消耗してるの？](https://qiita.com/python_academia/items/361d1d017c0203589da7)でも書きましたが、エラーは勉強するポイントです。


AIは質問すれば、なぜそのエラーが出るのか、どう修正すればいいのか（修正したコード）を教えてくれますが、ここで重要なのは、返ってきた回答を読むことです。読まずにコピペはやめましょう。
:::

有名なQAサイト

https://teratail.com/

https://stackoverflow.com/questions

## 複数の言語に手を出してしまう

「なんかこの言語違う気がする…」とか言って別の言語に手を出していませんか？

欲張った結果、どれも基礎だけで終わってしまってはもったいないです。まずは1つの言語をしっかり習得することを目指しましょう。

中途半端な知識よりも、1つの言語を通して「プログラミング的思考」を育てるべきです。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/918bd90f-7576-4a67-adcb-587b0701d0f9.png width=70%>


### 勉強する範囲は絞ろう
1つの言語にしても、「とにかく全部学ばなきゃ」と思って、あれこれ手を出すと、情報過多になって挫折しがちです。

意識的に勉強する範囲を絞りましょう。範囲を絞ることで、小さな成功体験が得られやすくなり、それがモチベーションの源になります。

### 全体像を把握しておくとよいかも

プログラミングは学ぶことが多く、自分が今何を勉強しているのか、あるいは勉強している内容が何に繋がるのか分からなくなる場合があります。

漠然とした不安や焦りを減らすためにも、最初に全体のマップを描いておくのは効果的です。

簡単ではありますが（他にももっとあると思いますが）、まとめました。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2638073/018fe246-5ea0-446b-9047-7263fd8e350e.png width=80%>

## 完璧主義で進まない

最初から100％理解しようと思ってはいけません。「だいたい6割分かればOK」と割り切って次に進みましょう。

**学んだ内容は繰り返し触れる中で徐々に身につくものです。**

「写経」でも「小さなアプリを作ってみる」でも、とにかくアウトプットを第一優先で考えましょう。動かしてみてこそ、知識が身につきます。

::: note
車輪の再発明をしよう！

車輪の再発明とは、既に世の中にあって知られている物を、もう一度作ることを言います。


「既にあるものをまた発明する」ということなので、一般的にはネガティブな言葉として捉えられますが、勉強目的であればどんどんやるべきです。



また、再発明したら自分だけのオリジナル機能を加えるのもいいですね。

:::

## おわりに
最後までお読みいただきありがとうございました。
誰かの参考になれば幸いです。

zennで書籍を書いています。
良ろしければPythonの学習にご活用ください。


https://zenn.dev/python_academia/books/6df147d8b82939


https://zenn.dev/python_academia/books/eabcc6b22afff5
スミレ畑、やってみた。 その23

# 概要
日本語プログラミング言語、スミレ畑、見つけたので、やってみた。
迷路、見つけたのでやってみた。

# 参考にしたページ

https://qiita.com/jpl_produire/items/8dfd49fbba6219171b8b

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/33f12ec7-7476-4a63-b400-8bb0113396a9.png)

# サンプルコード

```
【木】と【林】から、迷路を、作る手順
		迷路(木,林)=迷路(木,林)と0b100の論理和
		((迷路(木,林+1)=3または迷路(木+1,林)=3または迷路(木,林-1)=3または迷路(木-1,林)=3))の間繰り返す
			【方向】は、1から4までの乱数
			もし方向が1かつ迷路(木,林+1)=3なら
				迷路(木,林)は、迷路(木,林)と0b101の論理積
				木と林+1から迷路を作る
			他でもし方向が2かつ迷路(木-1,林)=3なら
				迷路(木,林)は、迷路(木,林)と0b110の論理積
				木-1と林から迷路を作る
			他でもし方向が3かつ迷路(木,林-1)=3なら
				迷路(木,林-1)は、迷路(木,林-1)と0b101の論理積
				木と林-1から迷路を作る
			他でもし方向が4かつ迷路(木+1,林)=3なら
				迷路(木+1,林)は、迷路(木+1,林)と0b110の論理積
				木+1と林から迷路を作る
			もし終わり
		繰り返し終わり
終わり

キャンバスをクリアする
盤面余白=10
通路幅=20
【迷路サイズ:座標】は{16,20}
【スタート:座標】は{1,1}
【ゴール:座標】は{迷路サイズの横,迷路サイズの縦}
木を1から迷路サイズの縦+2まで増やしながら繰り返す
	林を1から迷路サイズの横+2まで増やしながら繰り返す
		もし木が1または林が1または木が迷路サイズの縦+2または林が迷路サイズの横+2なら
			迷路(木,林)=15
		そうでなければ
			迷路(木,林)=3
		もし終わり
	繰り返し終わり
繰り返し終わり
ゴールの縦とゴールの横から迷路を作る
キャンバスへ線を描く
その位置と大きさは｛盤面余白+通路幅,盤面余白+通路幅*2,0,(迷路サイズの縦-1)*通路幅｝
その線色を黒に変える
キャンバスへ線を描く
その位置と大きさは｛盤面余白+通路幅,盤面余白+(迷路サイズの縦+1)*通路幅,(迷路サイズの横-1)*通路幅,0｝
その線色を黒に変える
木を2から迷路サイズの縦+1まで増やしながら繰り返す
	林を2から迷路サイズの横+1まで増やしながら繰り返す
		壁横は、(林-1)*通路幅+盤面余白
		壁縦は、(木-1)*通路幅+盤面余白
		もし迷路(木,林)と0b001の論理積が1なら	
			キャンバスへ線を描く
			//その始点は｛壁横,壁縦｝
			//その終点は｛壁横+通路幅,壁縦｝
			その位置は｛壁横,壁縦｝
			その大きさは {17, 1}
			その線色を赤に変える
		もし終わり
		もし迷路(木,林)と0b010の論理積が2なら
			キャンバスへ線を描く
			//その始点は｛壁横+通路幅,壁縦｝
			//その終点は｛壁横+通路幅,壁縦+通路幅｝
			その位置は｛壁横+通路幅,壁縦｝
			その大きさは {1, 17}
			その線色を赤に変える
		もし終わり
	繰り返し終わり
繰り返し終わり
キャンバスを更新する



```

# 実行手順
- サンプルコードをクリックして、コピーする。
- 以下を開く

https://sum.irelang.jp/play/2.1/

- 貼り付けして、実行ボタンを押す。

以上。
Template Methodパターン

## 1. Template Method パターンとは？

- **定義**: アルゴリズムの骨組みを定義し、一部のステップをサブクラスに委譲するデザインパターン
- **目的**: 共通の処理を親クラスで定義し、詳細を子クラスでカスタマイズ
- **カテゴリ**: 振る舞いパターン（Behavioral Pattern）

## 2. どんな時に使う？

- アルゴリズムの構造は同じだが、一部の処理を変更したい場合
- コードの重複を避けたい場合
- サブクラスで特定のステップをカスタマイズしたい場合

## 3. 構造

- **AbstractClass**: テンプレートメソッドと抽象メソッドを定義
- **ConcreteClass**: 抽象メソッドを実装

## 4. サンプルコード（Java）

ドキュメント生成プロセスの例。

```java
// AbstractClass
abstract class DocumentGenerator {
    // テンプレートメソッド
    public void generateDocument() {
        openDocument();
        writeContent();
        closeDocument();
    }
    
    protected abstract void writeContent();
    
    private void openDocument() {
        System.out.println("Opening document");
    }
    
    private void closeDocument() {
        System.out.println("Closing document");
    }
}

// ConcreteClass
class PDFGenerator extends DocumentGenerator {
    protected void writeContent() {
        System.out.println("Writing PDF content");
    }
}

class WordGenerator extends DocumentGenerator {
    protected void writeContent() {
        System.out.println("Writing Word content");
    }
}

// クライアントコード
public class Main {
    public static void main(String[] args) {
        DocumentGenerator pdf = new PDFGenerator();
        pdf.generateDocument();
        
        DocumentGenerator word = new WordGenerator();
        word.generateDocument();
    }
}
```

## 5. メリット

- コードの重複を削減
- アルゴリズムの構造を一貫性のある形で提供
- サブクラスでのカスタマイズが容易

## 6. デメリット

- テンプレートメソッドの変更が難しい
- サブクラスが増えると管理が複雑になる場合も

## 7. 実際の使用例

- フレームワークの処理フロー（例：ServletのdoGet/doPost）
- データ処理パイプライン（読み込み→処理→保存）
- ゲームのメインループ（初期化→更新→描画）

## 8. まとめ

- Template Methodパターンは、アルゴリズムの骨組みを固定しつつ詳細をカスタマイズする場合に有効
- コードの重複を減らし、保守性を向上
- テンプレートの設計時には柔軟性と拡張性を考慮！
Compositeパターン

## 1. Composite パターンとは？

- **定義**: オブジェクトをツリー構造に構成し、個々のオブジェクトと複合オブジェクトを統一的に扱うデザインパターン
- **目的**: 部分-全体の階層構造を単一のインターフェースで操作
- **カテゴリ**: 構造パターン（Structural Pattern）

## 2. どんな時に使う？

- 階層的な構造（例：ファイルシステム、組織図）を扱う場合
- 単一オブジェクトと複合オブジェクトを同じ方法で扱いたい場合

## 3. 構造

- **Component**: 葉と複合オブジェクトの共通インターフェース
- **Leaf**: 末端オブジェクト
- **Composite**: 子コンポーネントを管理する複合オブジェクト

## 4. サンプルコード（Java）

ファイルとフォルダの階層構造の例。

```java
// Component
interface FileSystemComponent {
    void display();
}

// Leaf
class File implements FileSystemComponent {
    private String name;
    
    public File(String name) {
        this.name = name;
    }
    
    public void display() {
        System.out.println("File: " + name);
    }
}

// Composite
class Folder implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components = new ArrayList<>();
    
    public Folder(String name) {
        this.name = name;
    }
    
    public void add(FileSystemComponent component) {
        components.add(component);
    }
    
    public void display() {
        System.out.println("Folder: " + name);
        for (FileSystemComponent component : components) {
            component.display();
        }
    }
}

// クライアントコード
public class Main {
    public static void main(String[] args) {
        Folder root = new Folder("root");
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");
        Folder subFolder = new Folder("subFolder");
        File file3 = new File("file3.txt");
        
        root.add(file1);
        root.add(subFolder);
        subFolder.add(file2);
        subFolder.add(file3);
        
        root.display();
    }
}
```

## 5. メリット

- 階層構造を統一的に扱える
- 新しいコンポーネントの追加が容易
- クライアントコードがシンプルになる

## 6. デメリット

- 葉と複合オブジェクトの役割が曖昧になる場合がある
- 複雑な操作では制限が生じる可能性

## 7. 実際の使用例

- ファイルシステム（ファイルとフォルダ）
- GUIコンポーネント（ボタン、パネル、ウィンドウ）
- 組織図（社員、部署）

## 8. まとめ

- Compositeパターンは、階層構造を統一的に扱いたい場合に有効
- ツリー構造の操作を簡潔にし、拡張性を提供
- 設計時に葉と複合オブジェクトの役割を明確にすることが重要！
ChatGPTを使用したアプリ開発記【投稿一覧画面のモバイル最適化】

## コード
```App.js
<div className="min-h-screen flex items-center justify-center bg-gradient-to-r from-blue-100 to-blue-300 px-4 py-10">
  <div className="w-full max-w-md bg-white rounded-2xl shadow-xl p-6 sm:p-8">
    <h2 className="text-2xl sm:text-3xl font-bold mb-6 text-center text-blue-600">
      Tomomitsu Keruma SNS
    </h2>

    <input
      type="email"
      className="w-full border border-gray-300 rounded-md px-4 py-3 mb-4 text-sm sm:text-base focus:outline-none focus:ring-2 focus:ring-blue-400"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
      placeholder="メールアドレス"
    />
    <input
      type="password"
      className="w-full border border-gray-300 rounded-md px-4 py-3 mb-6 text-sm sm:text-base focus:outline-none focus:ring-2 focus:ring-blue-400"
      value={password}
      onChange={(e) => setPassword(e.target.value)}
      placeholder="パスワード"
    />

    <div className="flex flex-col space-y-3">
      <button
        className="bg-blue-500 text-white px-4 py-3 rounded-full text-sm sm:text-base hover:bg-blue-600 transition duration-200 shadow-md"
        onClick={loginEmail}
      >
        ログイン
      </button>
      <button
        className="bg-blue-500 text-white px-4 py-3 rounded-full text-sm sm:text-base hover:bg-blue-600 transition duration-200 shadow-md"
        onClick={signupEmail}
      >
        登録
      </button>
      <button
        className="bg-blue-500 text-white px-4 py-3 rounded-full text-sm sm:text-base hover:bg-blue-600 transition duration-200 shadow-md"
        onClick={loginGoogle}
      >
        Googleでログイン
      </button>
    </div>
  </div>
</div>
```
|項目|説明|
|-|-|
px-4 py-10（外側）|スマホでも余白を確保し見やすくします
sm:p-8|大きい画面で余白を広げて見やすくします
text-sm sm:text-base|小さい画面では少し小さく表示、PCでは標準サイズ
py-3 ボタンの高さ|指で押しやすいようにボタンを広くしました
rounded-full|視覚的に親しみやすいボタンスタイル



## モバイルUI

![IMG_7425.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1058366/8137afd6-1d92-4a14-b3aa-2ac67d30c37a.jpeg)
AI駆動開発でElixirライブラリをリリース

CursorによるAI駆動開発でElixirライブラリをリリースしました。

## 開発したElixirコードについて

https://github.com/zacky1972/epmd_up

Elixir/Erlangで分散コンピューティングをするときに、Erlang Port Mapper Daemon (`epmd`)というプログラムを仲介するのですが、`epmd`が起動しているかどうか(`active?`)、`epmd`の起動(`activate`)・停止(`deactivate`)、`epmd`のフルパスの取得を行う関数(`find_epmd_executable`)をまとめた`EpmdUp`というモジュールを作成しました。

`EpmdUp`という命名自体も、AIと相談しながら決めました。

`epmd`が起動しているかどうかの判定と、`epmd`の停止は、公式ドキュメント[Distribution Protocol](https://www.erlang.org/doc/apps/erts/erl_dist_protocol.html)に準拠して決めましたので、ロバストなのではないかなと自負しています。

`epmd`の起動に関して、`deamon`モードで起動するのが正式だとは思っています。

## Cursorの設定

Cursorは英語モードで使用しました。設定の仕方は忘れました。

英語モードにした理由は、2つあります。

* OSSとして公開するので、commit logやissueなど、全て英語にしたかったから
* 日本語でプロンプトを書くと、頭や入力モードを英語と日本語に切り替えるのが煩雑だと思ったから

## AIにさせたこと

* commit logの生成: `Check git diff, and generate a commit log`
* PRの生成: `Check git diff main, and generate PR`
* 命名の提案: `Propose a name of ...`
* Issueの生成: `Generate an issue of ...`
* ドキュメントの生成: `Generate document of ...`

## 今回AIにさせなかったこと

* Elixirコードの生成: 何も情報を与えない状態では、Cursorは満足なElixirコードを生成できませんでした。
* テストコードの生成: Cursorは結構まともなテストコードを生成することは知っていましたが、今回作成したプログラムは少し特殊だったので、テストは自分で書きました。

## ふりかえり

* commit logやissue、PRの英文を自動生成してくれるのは、とてもありがたく、生産性と可読性が向上しました！
* 命名の提案もありがたかったです。モジュール名や関数名がとてもわかりやすくなりました。
* 英文ドキュメントの生成も、手間なくできてありがたかったです。要らないこともたくさん書いてくるのですが、削るのは容易ですし、心も痛みません。

P.S. 同じ手法で、続けて2つリリースしました！

https://github.com/zacky1972/get_host

https://github.com/zacky1972/node_activator

後者は @mnishiguchi さんと一緒に書いたバージョンを、`EpmdUp`と`GetHost`を使うようにしてリライトしました。 @mnishiguchi さんの書いたコードのおかげで、あっという間にリリースできました。改めて御礼申し上げます。
vueでテーブル操作してみた



tablesortライブラリを使って色々やってみる。

<template>
  <div>
    <!-- タブ -->
    <div class="tabs">
      <button
        v-for="(label, index) in tabLabels"
        :key="index"
        :class="{ active: appType === index }"
        @click="appType = index"
      >
        {{ label }}
      </button>
    </div>

    <!-- フィルター入力 -->
    <div class="filters">
      <label>
        IDがこの値以上：
        <input type="number" v-model.number="filter.minId" />
      </label>
      <label>
        名前に含まれる文字列：
        <input type="text" v-model="filter.nameContains" />
      </label>
    </div>

    <!-- テーブル -->
    <table v-if="filteredTable.length > 0">
      <thead>
        <tr>
          <th>ID</th>
          <th>名前</th>
          <th>詳細</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in filteredTable" :key="item.id">
          <td>{{ item.id }}</td>
          <td>{{ item.name }}</td>
          <td>{{ item.details }}</td>
        </tr>
      </tbody>
    </table>
    <p v-else>該当するデータがありません</p>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'

const tabLabels = ['タイプ0', 'タイプ1', 'タイプ2', 'タイプ3', 'タイプ4', 'タイプ5']
const appType = ref(0)
const formattedTables = ref([[], [], [], [], [], []])

// フィルター条件
const filter = ref({
  minId: 0,
  nameContains: ''
})

// フィルター済みテーブル（表示用）
const filteredTable = computed(() => {
  return formattedTables.value[appType.value].filter(item => {
    const passesId = item.id >= filter.value.minId
    const passesName = item.name.includes(filter.value.nameContains)
    return passesId && passesName
  })
})

const fetchData = async () => {
  try {
    const response = await fetch('/api/your-endpoint')
    const data = await response.json()
    const newTables = [[], [], [], [], [], []]

    data.forEach(item => {
      const type = item.appType
      if (type >= 0 && type <= 5) {
        newTables[type].push({
          id: item.id,
          name: item.name,
          details: item.details,
        })
      }
    })

    formattedTables.value = newTables
  } catch (error) {
    console.error('データ取得エラー:', error)
  }
}

onMounted(fetchData)
</script>

<style scoped>
.tabs {
  display: flex;
  gap: 10px;
  margin-bottom: 10px;
}
.tabs button.active {
  font-weight: bold;
  background-color: #eee;
}
.filters {
  margin-bottom: 10px;
}
.filters label {
  margin-right: 15px;
}
</style>
【公ド読】ビジネス ロジックの UI コンポーネントからの分離

【公式ドキュメントを読もうシリーズ】ビジネス ロジックの UI コンポーネントからの分離

## シリーズ概要

[https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3](https://qiita.com/yasu_programming/items/cec66f9e8d5d571e9ce3)

## URL

[https://docs.github.com/ja/copilot/copilot-chat-cookbook/refactoring-code/decoupling-business-logic-from-ui-components](https://docs.github.com/ja/copilot/copilot-chat-cookbook/refactoring-code/decoupling-business-logic-from-ui-components)

## 説明

UIコンポーネントとそのロジックを分離してくれる。

## 所感

分離するメリットとしては、
- テストのしやすさの向上
- 再利用性の向上
- 保守性の向上
- 可読性の向上
などがある。

「〇日までにこのサービス作っておいて」と言われると、そのサービスを作ることを最優先にして、きれいなアーキテクチャを保ったまま構築するのが難しいと感じる時がある。
こういうのは助かる。
【2026年サービス終了】AWS IoT Eventsのメリット・デメリット 

# はじめに
　AWS IoT Eventsは、IoT機器の状態遷移管理ができ、サーバーレスで動作する便利なサービスである。一方、IoTルールなど他のサービスと連携して使う前提で作られているようで、デメリットも多い。
　本記事では、筆者が感じたIoT Eventsのメリットとデメリットとその一部の回避策についてまとめる。

:::note warn
**IoT Eventsサービス終了のお知らせ（2026/5/20に完全終了）**
本記事執筆中に、IoT Eventsのサービス終了が発表された。
https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-end-of-support.html

また、2025/5/20以降は新規利用不可能となっている。本記事は、IoT Eventsを利用した記録として残しておく。
:::

# 動作確認環境
* AWS IoT Events

# メリット

* 簡単に状態遷移を作成でき、アクションを定義できる
  * 単純な状態遷移を持つ場合に、マネージドサービスで利用できて良い
* マネージドサービスなので、負荷分散など考慮しなくてよい
  * デバイスごとに一意のキーを設定できるので、各デバイスごとに状態を保持することができる

# デメリット

## 利用できる関数が少ない

利用できる関数は、[こちら](https://docs.aws.amazon.com/ja_jp/iotevents/latest/developerguide/expression-function.html)を参照。IoT Ruleと比べると利用できる関数が少なく、複雑なことを実現するのは難しい。

## 利用できるイベント（アクション）が少ない

利用できるイベント（アクション）は、[こちら](https://docs.aws.amazon.com/ja_jp/iotevents/latest/apireference/API_Action.html)を参照。基本的なものはそろっているが数が少ない。イベント（アクション）で実現できないことは、Lambda関数で処理しなければならないことが多い。

## オブジェクト配列を扱いづらい
### 条件式でオブジェクト配列は扱えない

IoT Eventsの条件式で、MQTTトピック内のオブジェクト配列は扱えない。

### オブジェクトをカスタムペイロードに直接設定できない

オブジェクトをカスタムペイロードで送るには、エスケープ処理する必要がある。

* 参考
  * https://repost.aws/questions/QUyIoZR3gOQNmLjr1PM0XmHQ/iot-events-custom-json-payload-not-working

IoT Coreに送られるオブジェクト配列をIoT Eventsを経由して別のサービスへカスタムペイロードして送信するには、[IoTルールのcast関数](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-sql-functions.html#iot-sql-function-cast)で、オブジェクトをJSON文字列として変換しておく必要がある。JSON文字列は、エスケープ処理されるので、そのままペイロードとして使うことができる。詳細は筆者の以前の記事を参照。

https://qiita.com/ntrlmt/items/07717f8db075b7d95c11


# IoT Events利用のポイント

IoTルールでフィルタしたMQTTトピックを上手く活用すると良い。IoTルールで出来る限り単純なトピックにフィルタした上で、状態遷移を作成するとIoT Eventsで扱いやすくなる。

* 複雑な条件の処理は、IoTルール側でやる
* IoT Eventsでは、処理を単純化しておく
* 上記で解決できない場合は、Lambda関数を併用する


# まとめ

本記事では、AWS IoT Eventsのメリットとデメリットをまとめた。簡単にサーバーレスで利用できる、一方、複雑なことをしようとすると、IoTルールやLambda関数を駆使する必要がある。状態管理をできる便利なサービスで、代替がないためサービス終了（EOL）の発表が悔やまれるが、カスタマイズ性が低く本番サービスで利用するには機能が不足しているのも感じるので致し方ないとも思える。今は、AWSは生成AIをはじめとするサービスに注力しているが、今後、IoT関連のサービスがまた盛り上がってほしい。

# 参考

https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-end-of-support.html

https://docs.aws.amazon.com/ja_jp/iotevents/latest/developerguide/expression-function.html

https://docs.aws.amazon.com/ja_jp/iotevents/latest/apireference/API_Action.html

https://qiita.com/ntrlmt/items/07717f8db075b7d95c11