OmniAICreator/Qiita-1.07M huggingface dataset:
GitHubPages を活用して長い URL を短縮する

今回は GoogleDrive のリンクなど
長い URL を短くする試みをしようと思います。

URL 短縮サイトは
・サイト側に悪意があった場合に
　勝手に遷移先を差し替えられる可能性がある
・ハッキングで
　勝手に遷移先を差し替えられる可能性がある
といったリスクがありますので
今回の手法で短縮する事を思いつきました。

https://drive.google.com/file/d/1p0nDpyMzszLkRieGlYynvMuA0Supw3cY/view?usp=sharing
という長いリンクを
https://uni928.github.io/URLShortTest/
という比較的短いリンクにする事を目標にします。

https://uni928.github.io/URLShortTest/
を開くと自動で
https://drive.google.com/file/d/1p0nDpyMzszLkRieGlYynvMuA0Supw3cY/view?usp=sharing
に遷移するという事です。


今回は GitHubPages でその仕組みを作成します。

https://ユーザー名.github.io/サイト名
という URL にしてしまいます。

例えば uni928 という
GitHub アカウントを取得して
Sephiroth というサイト名ならば

https://uni928.github.io/Sephiroth
という URL になります。

短縮を目的にしている割には
URL が長いと感じるかもしれませんが
URL 短縮サイトのリスクを考慮すると
妥協する価値はあると思っています。

***

手順 1 GitHub のアカウントを取得する

まずは GitHub のアカウントを取得します。
ユーザー名は

https://ユーザー名.github.io/サイト名
のユーザー名部分になるため
URL に使用しても違和感のない
ユーザー名を登録して下さい。

***

手順 2 プロジェクトを新規作成する

次にプロジェクトを新規作成します。

New を押して
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/80d808a7-bb15-5d75-e0d0-d4d62493e12c.png)

Repository name を設定して
Create repository をクリックします。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/a1f43611-3817-c285-5c9b-fc155327dcc7.png)

Repository name は

https://ユーザー名.github.io/サイト名
のサイト名部分に当たるため
URL に使用しても違和感のない
Repository name を使用して下さい。

***

手順 3 README.txt を作成する

次に README.txt を作成します。

出現した画面で README の部分を
クリックして下さい。
![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/19e3b57b-e22b-c621-7d8c-410c20bf6110.png)

その後出現した画面は
Commit changes... を選択して下さい。
![image4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/71c054a9-5adc-93a3-d008-9601dd7442cf.png)

ダイアログが出現したら
再度 Commit changes... を選択して下さい。

***

html を作成する

次に遷移するための
html ファイルを作成します。

Add file を選択して
Create new file を選択して下さい。
![image5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/2697cff3-4397-2824-f3f1-c1d94f49649e.png)

するとファイル作成画面に入りますので

Name your file... に
index.html と入力して

Enter file contents here に

```html:入力する内容
<script>
  window.location.href = 'https://www.google.co.jp/';
</script>
```

と入力して下さい。

https://www.google.co.jp/
部分は実際の遷移先を入力して下さい。

その後 Commit changes...
を選択して、出現したダイアログでも
Commit changes を選択して下さい。
![image6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/8a496878-241d-4e3b-1f73-0d22971cd8a3.png)

***

Settings を設定する

最後に Settings を設定します。

Settings を開いて
![image7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/58a0bbe3-5f9e-1851-20ff-dc39bfaddd24.png)

Pages を開いて
Branch の None を main に変更して
Save を押します。
![image8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3752886/16db25ca-cd74-ad93-ca1e-1d8b96f018c1.png)

反映に時間がかかるため
10 分程その画面で放置してから
画面を更新する事で

Your site is live at https://uni928.github.io/URLShortTest/
といった文字が出現します。

この文字が出たら作業は完了です。
URL を開くと自動で
遷移先に遷移する事が確認できます。
3Dカメラを使うプロジェクトで、並行処理には何のライブラリ使ってますか？

# 主旨
3Dカメラ・画像認識処理を使うと、遅い処理がボトルネックになって応答性が低下する。
シングルスレッドじゃいけないこともわかっているけど実装が追いついていない。
この記事は、皆さんからのアドバイスを求めるための記事です。

## シングルスレッドだと何がいけないのか
- 画像データの取得の処理の際に、IO待ちの時間にCPUが何もしていないという無駄を生じる。
- 推論処理も同様に処理の時間が大きい。
- 処理結果を画像として表示する際にも描画時間がかかる。
- 描画が処理のルーチンと同じになっている分だけ、処理だけの部分が遅くなる。

## ライブラリの例
trio
[trioによる並行処理 もくじ](https://qiita.com/Kyosuke_Ichikawa/items/b7fdffcbfe00773074a6)
trio-util
https://github.com/groove-x/trio-util

少なくとも1万台以上のロボットで動作している。

## 参考情報
[Pythonの並列処理・並行処理をしっかり調べてみた](https://qiita.com/simonritchie/items/1ce3914eb5444d2157ac)
novncコンテナのfluxbox設定

## 参考

* https://github.com/theasp/docker-novnc
* https://hub.docker.com/r/theasp/novnc/

## fluxboxの起動

* `theasp/novnc` 

が軽くてサイズも小さいため利用させていただきました。
Debian 11ベース。メンテナンスも継続されている様子。

```sh
docker run --rm \
 --name novnc \
 -it \
 -p 8080:8080 \
 -e DISPLAY_WIDTH=1280 \
 -e DISPLAY_HEIGHT=968 \
 -e RUN_XTERM=no \
 theasp/novnc
```

* http://localhost:8080/vnc.html?autoconnect=true

にアクセスすると以下のような画面が表示される。

![22.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/f023fce3-bd6a-8fbe-16db-efc86682a288.png)

* vncviewerをインストールしたい場合はxterm上で以下

```sh
apt update
apt install -y xtightvncviewer
```

もしくはイメージを作成する


### イメージ作成

* Dockerfile

```sh
FROM theasp/novnc

RUN echo 'apt update && apt install --no-install-recommends -y $@ && apt-get clean && rm -rf /var/lib/apt/lists/*' > /usr/local/bin/pkgadd \
 && chmod +x /usr/local/bin/pkgadd

RUN pkgadd xtightvncviewer
```

```
docker build . -t theasp/novnc:custom
```


## 右クリックメニューの設定

* https://wiki.ubuntu.com/HowToFluxboxStyles

VNCサーバーへ接続するランチャーを作成する場合は以下のように設定。
パスワードも自動入力してくれる。

初期のメニュー登録一覧を非表示にしたい場合はincludeをこのようにコメントアウト。

* ~/.fluxbox/menu

```go
[begin] (fluxbox)

   [submenu] (App1) {}
      [exec] (VNC1) {echo password1 | /usr/bin/xtightvncviewer 192.168.1.21 -autopass} <>
      [exec] (VNC2) {echo password2 | /usr/bin/xtightvncviewer 192.168.1.22 -autopass} <>
      [exec] (VNC3) {echo password3 | /usr/bin/xtightvncviewer 192.168.1.23 -autopass} <>
      [exec] (VNC4) {echo password4 | /usr/bin/xtightvncviewer 192.168.1.24 -autopass} <>
   [end]


   #[include] (/etc/X11/fluxbox/fluxbox-menu)
   #[reconfig] (Reconfigure)
   #[restart] (Restart)
   #[exit] (Exit)

[end]
```

## メニューの文字サイズ

初期設定だと文字が小さいため。

* ~/.fluxbox/overlay

```
menu.frame.font: Bitstream Vera Sans-16
menu.title.font: Bitstream Vera Sans-12
toolbar.clock.font: Bitstream Vera Sans-12
toolbar.workspace.font: Bitstream Vera Sans-12
toolbar.iconbar.focused.font: Bitstream Vera Sans-12
toolbar.iconbar.unfocused.font: Bitstream Vera Sans-12
window.font: Bitstream Vera Sans-12
```


## 起動オプションの指定

* menu と overlay を指定して起動したい場合は以下。

```sh
docker run --rm \
 --name novnc \
 -it \
 -p 8080:8080 \
 -e DISPLAY_WIDTH=1280 \
 -e DISPLAY_HEIGHT=968 \
 -e RUN_XTERM=no \
 -v $(pwd)/fluxbox/menu:/root/.fluxbox/menu \
 -v $(pwd)/fluxbox/overlay:/root/.fluxbox/overlay \
 theasp/novnc
 ```


## nginxのproxy下で動かす場合

https://datawookie.dev/blog/2021/08/websockify-novnc-behind-an-nginx-proxy/

```nginx
  server {
    listen 80 default_server;
    
    location / {
      proxy_pass http://127.0.0.1:6080/;
    }
    
    location /websockify {
      proxy_pass http://127.0.0.1:6080/;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      proxy_set_header Host $host;
    }
  }
```
Markdwon AIで今日の献立サイトを作ってみた！

今回は、 **「今日の献立サイト」** を作ってみました！
今まではコーディングに関してはAIに丸投げしていましたが、このサイトは見栄えにもこだわって制作しました。
Markdwon AIは制作者の技術があればよりリッチなサイトを制作できるのも魅力です！
今後のアップデートは拡張Markdwon AIを実装して、より簡単にリッチなサイトを制作できるように開発を進めています。
将来的には、Markdown記法だけでアプリ開発からサイト制作まで行えて、誰でも簡単にAIをサイトに実装できるWebアプリケーションを目指しています。
ご興味がある方は、ぜひMarkdwon AIを触ってみて下さい！

【Markodwn AI_公式アプリ】

https://mdown.ai/

## 今日の献立サイトについて
![ranch_img1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921729/6b1f95ce-534f-317c-1d7b-584567e8f240.png)

献立サイトは、

**運命の一皿を見つける**
- 今日の献立1品をランダムで書き出してくれる

**材料で見つける**
- 入力された食材で作れる料理を書き出してくれる

**カロリーで見つける**
- 入力されたカロリー以内で1日の献立を考えてくれる

上記、３つの内容で作りました。
献立に困っている方やダイエットをしている方にとても便利なサイトとなっているので是非使ってみて下さい！

【今日の献立サイト】

https://mdown.ai/content/566ff4e6-19e2-40dd-be27-6f374588a8c0

## 豪華賞品イベント開催中
また、Qittaで10月25日~11月25日の期間に **【Markdown AIに関する記事を投稿すると豪華商品が貰えるキャンペーン】** を実施して、
**締切まで残り4日**を迫っています。
Markdwon AIについてご興味がある方や豪華賞品が欲しい方はぜひ参加してみて下さい！

https://qiita.com/official-events/6914e7e898953881ef94

Best Technical use賞：1名様
[Dyson Prifire Hot＋Cool Gen1(HP10WW)](https://www.amazon.co.jp/dp/B0CZ9GTDH1?ref=cm_sw_r_cp_ud_dp_7Z2DXCE5QEW1VAMGWK7Z&ref_=cm_sw_r_cp_ud_dp_7Z2DXCE5QEW1VAMGWK7Z&social_share=cm_sw_r_cp_ud_dp_7Z2DXCE5QEW1VAMGWK7Z&_encoding=UTF8&starsLeft=1&skipTwisterOG=1&th=1)

Best Interesting use賞：1名様
[SONY WF-1000XM5(ブラック)](https://www.amazon.co.jp/dp/B0CBKQZXT7?ref=cm_sw_r_cp_ud_dp_GNASEMN82SM3SGH511E8&ref_=cm_sw_r_cp_ud_dp_GNASEMN82SM3SGH511E8&social_share=cm_sw_r_cp_ud_dp_GNASEMN82SM3SGH511E8&starsLeft=1&skipTwisterOG=1)
Amazonギフトカード 15,000円分

Best Playful use賞：1名様
[Anker 521 Portable Power Station](https://www.amazon.co.jp/dp/B09B21M56M?ref=cm_sw_r_cp_ud_dp_8165GXKTD0PB9EANDMDN&ref_=cm_sw_r_cp_ud_dp_8165GXKTD0PB9EANDMDN&social_share=cm_sw_r_cp_ud_dp_8165GXKTD0PB9EANDMDN&starsLeft=1&skipTwisterOG=1)
Amazonギフトカード 10,000円分

イベントでの皆様のフィードバックを基に、より良いサービスへと改良を重ねていきたいので、是非ご意見やご感想をお聞かせください！
AILabTools动漫化ツールで写真をアニメ化！簡単にオリジナルアバターを作成

1. はじめに：AI技術で画像をアニメ化
AI技術の進化により、画像処理はもう手間がかからない時代になりました。AILabTools动漫化ツールは、強力な人工知能技術を利用して、あなたの写真や画像を瞬時に様々なアニメスタイルに変換します。自分をアニメキャラクターに変身させたり、オリジナルアバターを作成したり、簡単に実現できます。
![14f3cfd042ee287d33dc31d3af9d608f_54178.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3940962/5720849a-e736-8321-0b1f-19c46e01336d.png)
2. AILabTools动漫化ツールの主な機能
AILabTools动漫化ツールは、ユーザーが数秒で独自のアニメ風画像を作成できるように設計されています。主な特徴は以下の通りです：
● 写真をアニメに変換する機能
  ○ AILabTools动漫化ツールは、写真全体をアニメ風に変換するだけでなく、顔や頭部部分だけを変換することも可能です。自分の好みに合わせた処理ができます。
  ○ 自撮り写真や全身写真でも、AIが正確で生き生きとしたアニメ効果を生成します。
● 多彩なアニメスタイル
  ○ AILabTools动漫化ツールは、複数のアニメスタイルを提供しています。例えば、レトロ漫画風、香港漫画風、ピクサー風、浮世絵風、さらにはモダンな3Dアニメ風など、さまざまなアートスタイルに対応しています。
  ○ ユーザーは、好みに応じてスタイルを選択し、AIがそのスタイルに基づいたアニメ風画像を生成します。
● 簡単にオリジナルアバターを作成
  ○ このツールは、SNS用の個性あふれるアバター作成にも最適です。写真をアップロードし、スタイルを選ぶだけで、AIがアバターを自動的に生成します。
  ○ AILabTools动漫化ツールで作成したアバターは、SNSプラットフォームで注目を集め、ユニークで目立つ存在になること間違いなしです。
● 顔のディテールを保ちながらアニメ化
  ○ AILabTools动漫化ツールは、アニメ化の過程で顔の特徴をしっかりと保持し、リアルで個性的なアニメ画像を作成します。あなたの顔のディテールが残るため、オリジナリティが際立ちます。
[詳細はこちらで機能についてもっと学びましょう。](https://www.ailabtools.com/ja/face-anime-converter)
![FaceAnimeConverter-3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3940962/0db25ffc-da6c-6003-c97f-b49476b66e96.jpeg)
3. 使用方法：簡単な手順でアニメ化を実現
AILabTools动漫化ツールの使用方法は非常にシンプルです。以下の手順でアニメ風画像を簡単に作成できます：
1. 写真をアップロード：アニメ化したい写真を選んでアップロードします。顔だけでも、全身写真でもOKです。
2. アニメスタイルを選択：自分の好みに合ったアニメスタイルを選びます。AILabTools动漫化ツールには、豊富なスタイルが揃っています。
3. 「変換」ボタンをクリック：選んだスタイルに基づいて、AIが自動的に画像を変換します。数秒で結果が表示されます。
4. プレビューとダウンロード：変換後、画像をプレビューして気に入ったらダウンロードして保存できます。また、SNSにシェアすることもできます。

4. 適用シーン
AILabTools动漫化ツールは、個人の楽しみや社交だけでなく、さまざまな場面でも活用できます：
● SNSアバター作成：自分のSNSアカウントで個性的なアバターを作成したい場合に最適です。AILabTools动漫化ツールを使えば、ユニークなアニメ風のアバターを簡単に作成できます。
  ○ SNSで目立つために個性を表現したいなら、AILabTools动漫化ツールが大きな役立ちます。
● プロフェッショナルな用途：個人用だけでなく、ビジネスや商業の場でも使用できます。例えば、ビジネスプロフィール写真、ポートレートや挿絵作成などに活用可能です。
● クリエイティブ作業に活用：アーティストやクリエイターが自分の作品やキャラクターをアニメ風に変換する際に、AILabTools动漫化ツールは非常に便利です。
5. 特徴と利点：AILabTools动漫化ツールの強み
AILabTools动漫化ツールは、以下の利点により、多くのユーザーに支持されています：
● 迅速で高品質なアニメ化：AI技術を活用して、素早く高品質なアニメ風画像を作成できます。処理速度が速く、仕上がりもリアルです。
● スタイルのバリエーションが豊富：多彩なアニメスタイルが選べるため、ユーザーは自分の好みに合わせて変換できます。AILabTools动漫化ツールは、どんなアートスタイルにも対応可能です。
● 簡単な操作で誰でも使える：難しい操作は一切なく、誰でも簡単に使用できます。アップロード、スタイル選択、変換ボタンをクリックするだけで完成です。
● 多目的に利用できる：SNSアバター作成、ビジネス用のポートレート、創作活動にも利用できるため、さまざまな用途で役立ちます。
6. ユーザーの声
AILabTools动漫化ツールは多くのユーザーから高く評価されています。以下は実際のユーザーの声です：
● さとう みさき：「私は3Dアニメスタイルのアバターを作成しました。効果が素晴らしく、SNSで注目を集めました！」
● たなか だいすけ：「レトロ漫画風の画像を作成したところ、予想以上の完成度でした！顔の特徴がしっかり残っていて、アニメっぽさが最高です。」
● やまもと あやか：「AILabTools动漫化ツールを使って、ビジネス用のプロフィール写真を変換しました。プロフェッショナルでありながら、個性が出ているのでとても満足しています。」
7. まとめと結論
AILabTools动漫化ツールは、高機能で使いやすいオンラインツールです。わずか数秒で写真をアニメ風に変換し、オリジナルのアバターやイラストを作成できます。個人のSNSアバターを作成するだけでなく、ビジネスや創作活動にも活用できます。今すぐ試して、あなたの写真を素敵なアニメ風に変身させましょう！
[AILabTools动漫化ツールを今すぐ試して、あなたのアニメ風画像を作成しましょう.](https://www.ailabtools.com/ja/face-anime-converter)
分岐をどうやって減らすか-共通化という甘い罠-


## 分岐の怖さ
- 人間の頭では３階層程度が限界
- 私は２階層が限界
- （そもそもの話）ネストが深いプログラムは読みにくい（多くの前提を読み手に課す）

## 分岐は大切！
- 分岐のないプログラムはほぼ存在しない
- プログラマの腕の見せ所は分岐を（見かけ上）いかに減らすかと言っても過言ではない

## 分岐の減らし方：基本的方針
- 関数１つの中での分岐を１～２階層にとどめる
- 関数の組み合わせで多数のパターンを実現する

重要なメリットは減らした分岐それぞれでテストできること！

## 分岐の減らし方：具体例
- 状況を限定する
- フラグは忌避
- 早期リターン（疑似分岐減少）
- 不要なチェックはしない
- 関数化・メソッド化・
  ←効果的に使うのは難しいが威力絶大

## 関数化アンチパターン
- 似ているが異なる処理の共通化
- 引数でフラグを渡している
  関数の中が巨大なswitchになっているケースが該当
  別のメソッドにした方がいい

## 関数化の目的
- 処理の共通化・・・だけではない！
- むしろ前提条件を固定した上で処理を分けるのが真骨頂

## 関数化のコツ
- １つことを上手にやる

## 最後に
- ・・・語り切れません。レビュー依頼待ってます。
-
AI Builder のプロンプトで画像、ドキュメントが利用可能になった


# はじめに

Power Platform のサービスの一つである AI Builder では、プロンプトを作成して Power Apps や Power Automate から利用することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/ff575b05-667a-b78c-bf5a-e7c2b74ceaa9.png)

Azure OpenAI の技術が裏で活用されていますが、Azure リソースの準備は不要です。そのため、手軽かつ安全に生成 AI 技術を活用した独自の Power Apps アプリや Power Automate 自動化フローを作成したい市民開発者の方には、AI Builder をお勧めします。

AI Builder の活用例について、これまでいくつかの記事で紹介してきましたが、例えば、以下のように、請求書がメールで届いたら、自動で OCR でテキスト抽出して、そのテキストをプロンプトに渡して必要な情報だけ JSON 形式で抽出し、アプリで最終確認してデータ連携 (例えば、SharePoint リストに登録) するようなことが可能でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/9716e2bd-e195-e8ed-3ac7-3174f0e5ada8.png)

以下は他の活用記事です。

https://qiita.com/Takashi_Masumori/items/07aba9675f3cf576b393

https://qiita.com/Takashi_Masumori/items/5356622854d113ac4e70

そして今回、AI Builder のプロンプトで画像、ドキュメントが利用可能になりました。

::: note warn
パブリックプレビューです。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/280dafa6-2f28-85a8-91a9-07d11caaf481.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/f9374851-2757-af54-19a3-d03cf19aefab.png)

以下はリファレンスで、ファイルサイズ、ファイルの種類、ページ数等に制限がありますが、それなりのことは出来るようになったという認識です。

https://learn.microsoft.com/en-us/ai-builder/add-inputs-prompt

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/855ca4a1-c3b1-459e-8036-e61f8548cadc.png)

今回は、こちらを試してみた内容を整理したいと思います。

まず、上記のようなメールの添付ファイルからテキストを抽出して、最終的に必要な情報を抽出することは、これまでも可能でした。

AI Builder には、OCR のモデルがあり、Power Automate から簡単に利用可能なため、一旦 OCR でテキストを抽出し、そちらの情報をプロンプトに渡す感じでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/afd4c9c2-666c-4886-1565-85e7ba6bb0b9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/7f09aaca-babc-9518-44c0-ce37a520edf0.png)

対して、こちらの新しい機能の場合、OCR を介さずに同じことが実現できるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8be8abfa-27ed-b90d-768e-8be11073a4e0.png)

テストしてみると、良い感じに JSON で出力してくれていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/32f91b7f-21b4-68e6-98be-bc426e62dd0e.png)

```

{
  "invoice_number": "0001",
  "invoice_registration_number": "T2330000000000",
  "issue_date": "2023-10-31",
  "due_date": "2023-11-30",
  "sub_total_amount": 50000,
  "tax": 5000,
  "total_amount": 55000,
  "payment_method": "",
  "billing_to": {
    "name": "株式会社 TAKMASPOWER 御中",
    "address": "******"
  },
  "billed_by": {
    "name": "マイクロソフト株式会社",
    "address": "100-0000 東京都港区"
  },
  "line_items": [
    {
      "description": "Power Apps Premium",
      "quantity": 20,
      "unit_price": "2,500",
      "total_price": "50,000"
    }
  ]
}
```

※架空のデータです

どちらの方法でも同じ結果となりましたが、選択肢が多いに越したことはないと思います。個人的には、元々の OCR 機能で文字さえ抽出出来れば、精度はそれほど変わらない気がしますが、もし片方の方法で精度が出ない場合は、もう片方を試してみるとよいかと思います。

また、画像もアップできるため、以下の記事で紹介したようなアプリも、Azure OpenAI に HTTP リクエストしなくても実現できると思いますし、市民開発者の方が生成 AI の技術を活用した独自の Power Apps アプリや Power Automate 自動化フローを作成出来る幅が広がったと思います。

https://qiita.com/Takashi_Masumori/items/f6461c2dea1d1a7e4cde
品質メトリクスって何だろう？


## 品質メトリクスって何だろう？

品質メトリクスは、ソフトウェアの品質を定量的に評価するための指標です。品質は目に見えないため、「バグの少なさ」や「テストの網羅度」といった指標を使って品質を可視化し、チームで共有することが目的です。今回は、「バグ密度」「テスト密度」「テストカバレッジ」の3つにフォーカスしていきます。

**1. バグ密度：バグの「濃さ」で品質をチェック**

* 定義
バグ密度は、ソースコードの行数あたりのバグの数を示す指標です。
バグ密度によって、品質の状態を評価できるため、チーム全員が把握しておくべき指標です。
* 計算方法
計算式：バグ密度 = バグ件数 / ソースコード行数
例. バグ件数：25件、ソースコード行数：50000行の場合、25/50 = 0.5件/KLOC
※KLOC = Kilo Lines Of Code = ソースコード1000行を表す
* 活用シーン
    - **プロジェクト全体の品質把握**：ソフトウェア全体の品質と安定性を客観的に評価できます。
    - **リファクタリングのタイミング**：バグの多い箇所を特定し、コードの見直しやリファクタリングのタイミングを見極めるのに有用です。
    - **リリースの判断基準**：リリース可否を判断するための品質基準の1つとして活用できます。
* 注意点
「バグ密度が低いから品質が高い」とは言えず、質の低いテストでは、バグ密度が低く見えることがあります。

**2. テスト密度：テストの「濃さ」で品質をチェック**

* 定義
テスト密度は、テストがどれだけ密に行われているかを示す指標です。
テスト密度によって、テストの実施状況を評価できるため、チーム全員が把握しておくべき指標です。
* 計算方法
計算式：テスト密度 = テストケース件数 / ソースコード行数
例. テストケース件数：500件、ソースコード行数：50000行の場合、500/50 = 10件/KLOC
* 活用シーン
    - **開発初期からの品質確保**：テスト密度が高いと早期からバグ発見の可能性が増え、リリース前の安定性が高まります。
    - **開発スピードと品質のバランス**：テスト密度の目標値を設定し、適切なレベルを維持することで、効率的な開発と品質のバランスを取ることが可能です。
* 注意点
「テスト密度が高いから十分なテストを実施した」とは言えず、無駄なテストが多ければテスト密度が高くなります。

**3. テストカバレッジ：テストの網羅度をチェック**

* 定義
テストカバレッジは、コード全体のうち何％がテストでカバーされているかを示す指標です。テストされていないコードが多いと、バグが見逃される可能性が高くなるため、カバレッジを上げることで未実施の部分を減らし、テストの漏れを防ぐことを目指します。
* 計算方法
テストカバレッジ = (テスト済ソースコード行数 / 総ソースコード行数) x 100（％）
例. 総ソースコード：1000行、テスト済ソースコード行数：800行の場合、(800/1000) x 100 = 80%
* 活用シーン
    - **品質のベース作り**：単体テストを増やすことで、潜在的なバグのリスクを低減します。
    - **継続的な品質モニタリング**：テストカバレッジの推移をモニタリングすることで、品質維持の状況を把握できます。
* 注意点
カバレッジが100％でも、テストケースの質が低ければバグを見逃す可能性があるため、テストケースの質も確認することが大切です。

### バグ密度とテスト密度を使用する際の注意点

* どんな関係性がある？
バグ密度とテスト密度は、品質管理の重要な要素であり、密接に関連していますが、それだけでは問題箇所の特定には不十分です。
そこで役に立つのがゾーン分析です。これを活用することで、「どこに重点的にリソースを割くべきか」を明確にすることができます。

### まとめ
品質メトリクスは、プロジェクトの「健康診断」のようなものです。各メトリクスの使い分けを意識することで、開発初期段階から品質向上に効果的に取り組むことができます。チーム全体で品質の可視化と共有を行い、プロジェクト全体の品質向上を目指していきましょう。

### 次回予告
次回は、「ゾーン分析」に迫ってみたいと思います！お楽しみに！
異種混在ネットワークの接続とは何か？

## 異なるネットワークを接続させるもの
>異なるネットワークの最上位に共通の層を追加することによって問題を追加することによって問題を解決する方法である。いずれ場合にも、ネットワークの境界にそのためのデバイスが配置される。当初、これらのデバイスはゲートウェイと呼ばれた。

## TCPとIPが登場する
>既存のネットワークの差異を隠すための共通の層を作ることを提案していた。このアプローチは大きな成功を収めてきており、彼らの提案した層は最終的にTCPとIPという２つのプロトコルに分割された。それからほぼ40年が経ち、IPは現代のインターネットの基礎となっている。

>IPは、すべてのルーターを認識し、ほぼすべてのネットワークを通過できる普遍的なパケット形式を提供している。

## カプセル化によって異種混在するネットワークを渡る
>パケットをMPLSヘッダーでカプセル化した上で仮想回線へと送信する必要がある。仮想回線の宛先へ辿り着くと、MPLSヘッダーは捨てられ、ネットワーク層の次のホップを見つけるためにネットワークアドレスが再びチェックされる。

## 共通のネットワーク層のおかげで巨大なネットワークを構築できる
>ネットワーク間の接続によって巨大なネットワークの構築ができるようになったが、この仕組みが動作するのは、共通のネットワーク層が存在する時のみである。しかし実際には、世の中には数多くのネットワーク層のプロトコルが存在する。

## マルチプロトコル・ルーターがあるが完全ではない。
>複数のネットワーク・プロトコルを扱えるルーターはマルチプロトコル・ルーターと呼ばれる。こうしたルーターは、プロトコル同士を変更するか、より上位の層のプロトコルでコネクションを行うかのいずれかの方法で実現されるが、どちらのアプローチも完全とは言えない。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/

# 感想
TCP,IPのおかげでいろんなネットワークを渡すことができる。
しかし共通のインターネットプロトコルが使われていないと通信することが難しい。
造波装置 with JLC3DP #3

造波装置第三段です。やっと成功と言えるとこまで来ました。
今回も毎度のことですがJLC3DPさんに協力していただいています。

# 1.発注方法(おさらいのおさらい)
↓詳しくはこちら↓

https://qiita.com/kanhina1217/items/0c53dc6ca95f93940385#2-%E7%99%BA%E6%B3%A8

1. ホームページ右上の発注するをクリック
2. 発注したい種類をクリック（3D Print)
3. 3Dファイルを追加からstl等をアップロード
4. 印刷方法・素材を選択
5. カート,注文から住所・配送方法を選択して注文

# 2.発注したもの
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/93874c3c-f7f3-7ece-ac52-e9f9b1eb22ce.png)
ストッパー
歯車を回転させる時外れないために
 <img width="40%" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/0e161f73-c1e1-e627-adad-9c53100fbbf0.png">　<img width="40%" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/7d3d47bf-afe2-73b6-6eb0-57983a3dd832.png">
こんなのをはめます。
そのままだとガバガバで役割を全うできないのでしっかりボンドで止めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/d7a52ecb-539c-1314-6050-e823c2d088d7.png)
前回よりも3mm削って軽量化とコスカットを図っています。
<img width="200px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/075cf687-994c-5b86-9e76-c349b1f3f5db.png">　<img width="200px" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/7577513b-8cae-b9d1-5dc5-2d9a785f1f87.png">
Tの部品はやっと波を作る部分を作りました

# 3.到着
到着までは1週間です。これまでも見てだいたい一週間前後で届きますね。
歯車はいつも通りです。3mm減っても大丈夫👍
![IMG_20241121_114326.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/92609037-0316-9b74-ab85-4e1a4681ed07.jpeg)

# 4.使ってみる
実際に動かした動画はこちらです。
<iframe width="560" height="315" src="https://www.youtube.com/embed/cRkMGGjhul0?si=vyqblr4W73EsssuM" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

上がるときはうまくいくのですが、下がるときに苦しそうな音を出します…
（多分抵抗が高くなるせい）
あとくそうるさいし5V5A消費です。（定格7.2V2A)

結果、波は起こせました。ですがスピードが想定よりも遅いし、軸はぶれるしで設計ミスだらけ
さすがにもう印刷はしないですが、作る方がいたら両面から抑える構造にするべきです。

# 5.改善点と対策
モーターの軸と歯車の穴が空回りする事が多い
→エチレン、ボンド、グルーガンあたりでストッパーの補強もするべきかも

歯車が回転の摩擦に耐えきれていない
→歯車を金属製にして耐久性能向上

水かきが下がる時水の抵抗でスピードが遅くなり苦しそうな音を出す
→トルクを上げる　もしくは　水に入る深さを減らす

スピードが遅い
→回転数を上げる　でもトルクが落ちる

今のメインの問題は
・耐久性
・トルクと回転数の不足
の2つかな

耐久性は接合部の補強や素材の強化でなんとかなりそう（希望的観測）
トルクと回転数に関してはモーターを変えない限り両立は厳しそう
でもモーター変えるとなるとなぁ…
（モーター結構いい値段するしもう土台のはめる部分を削りたくないの意）

# 6.スポンサー紹介
<img width="400" alt="JLCPCBロゴ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580381/230af0e8-e1e1-f77b-8475-9e847468158f.png">

今回もですが、造波装置の印刷をJLCPCB(3DP)さんに協力していただきました!
次は最初のパーツだけ金属にしたいので金属プリントを使わせていただきたいと思います。
[英語発注システム → https://jlcpcb.com/JPV](https://jlcpcb.com/JPV)
[日本語発注システム → https://jlcpcb.com/jp](https://jlcpcb.com/jp)

### 前回

https://qiita.com/kanhina1217/items/9aa3e981271738f1086f

### 次回
【chatGPT 対話備忘録】SQLコマンドガイド

# 私：
SQLとは

# ChatGPT:
SQL (Structured Query Language) は、データベースの作成、管理、操作を行うための標準的なプログラミング言語です。以下に、基本的なSQLのコマンドや概念を紹介します。

基本構文
1. データベースの作成と選択

```:sql

-- データベースの作成

CREATE DATABASE database_name;

-- データベースの選択

USE database_name;
```
2. テーブルの作成

```:sql

CREATE TABLE table_name (
    column1 datatype constraints,
    column2 datatype constraints,
    ...
);
```
例:

```:sql

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
3. データの挿入

```:sql

INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
```
例:

```:sql

INSERT INTO users (name, email)
VALUES ('John Doe', 'john@example.com');
```
4. データの取得

```:sql

SELECT column1, column2, ...
FROM table_name
WHERE condition;
```
例:

```:sql

SELECT * FROM users WHERE name = 'John Doe';
5. データの更新
```

```sql

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
```
例:

```:sql

UPDATE users
SET email = 'john.doe@example.com'
WHERE name = 'John Doe';
```
6. データの削除

```:sql

DELETE FROM table_name
WHERE condition;
```
例:

```:sql

DELETE FROM users WHERE id = 1;
```
SQLの種類
DDL (Data Definition Language): データベースの構造を定義する。

CREATE, ALTER, DROP, TRUNCATE
DML (Data Manipulation Language): データを操作する。

SELECT, INSERT, UPDATE, DELETE
DCL (Data Control Language): 権限の管理。

GRANT, REVOKE
TCL (Transaction Control Language): トランザクションを管理する。

COMMIT, ROLLBACK, SAVEPOINT
条件式と関数
WHERE句の条件式
比較演算子: =, <>, <, >, <=, >=
論理演算子: AND, OR, NOT
範囲指定: BETWEEN ... AND ...
部分一致: LIKE 'pattern%' (%と_を使用)
NULL値チェック: IS NULL, IS NOT NULL
集計関数
COUNT(): 行数をカウント
SUM(): 合計
AVG(): 平均
MAX(): 最大値
MIN(): 最小値

例:


```:sql

SELECT COUNT(*) AS user_count FROM users;
グループ化
```

```:sql

SELECT column, COUNT(*)
FROM table_name
GROUP BY column
HAVING COUNT(*) > 1;
ジョイン (JOIN)
INNER JOIN: 両方のテーブルに一致するデータを取得
```

```:sql

SELECT *
FROM table1
INNER JOIN table2
ON table1.column = table2.column;
LEFT JOIN: 左のテーブルのすべての行を取得し、一致しない場合はNULL
```

```:sql

SELECT *
FROM table1
LEFT JOIN table2
ON table1.column = table2.column;
RIGHT JOIN: 右のテーブルのすべての行を取得
FULL OUTER JOIN: 両方のテーブルのすべての行を取得
```
SQL練習環境
ローカル環境: MariaDB, MySQL, PostgreSQL, SQLite
オンラインツール: DB Fiddle, SQL Zoo
【chatGPT 対話備忘録】Ajaxとは

# 私：Ajaxとは

# ChatGPT:
Ajax（エイジャックス、Asynchronous JavaScript and XML）は、ウェブ開発で使用される技術の集合体であり、以下のような特徴を持つ動的でインタラクティブなウェブアプリケーションを構築するために用いられます。

Ajaxの特徴
非同期通信: サーバーとのデータ通信を非同期で行うため、ページ全体をリロードすることなく、必要なデータだけを更新できます。

ユーザー体験の向上: ページの一部だけを更新することで、高速でスムーズな操作感を提供します。

軽量なデータ通信: 通信データ量を減らし、効率的なサーバーリソースの使用が可能です。

Ajaxの仕組み
ユーザーアクション: ボタンのクリックやフォーム入力など、ユーザーがアクションを行う。

JavaScriptによるリクエスト: JavaScriptのコードがサーバーにリクエストを送信。

サーバー処理: サーバーはリクエストを受け取り、必要なデータや処理結果を返す。

レスポンスの受け取り: サーバーからのレスポンス（通常はJSONやXMLなど）をJavaScriptが受け取る。

ページの部分更新: JavaScriptを用いてページの一部を更新。

Ajaxを実現するための技術
HTML: 基本的な構造の記述。

CSS: スタイリングを定義。

JavaScript: 動的な機能やAjax通信を実装。

XMLHttpRequest（XHR）またはFetch API: サーバーとの通信を行うためのインターフェース。

サーバーサイドスクリプト: （例: PHP, Python, Java, Node.jsなど）サーバー上での処理を実行。

JSONまたはXML: データ形式として使用される。

Ajaxの使用例
Googleマップ: マップのスクロールやズームをスムーズに行う。

Gmail: メールリストや内容の更新がページ全体のリロードなしで行われる。

オンラインフォーム: 入力内容のバリデーションや結果の動的な表示。

Ajaxの利点
高速な操作感を提供。
ユーザー体験の向上。
ネットワークトラフィックの軽減。
Ajaxの課題
JavaScriptが無効な場合には機能しない。
非同期通信のためデバッグが難しい。
サーバー負荷を考慮した設計が必要。
Ajaxは現代のウェブアプリケーションで欠かせない技術ですが、正しく理解し、用途に応じて適切に活用することが重要です。
特定のファイルを転送し終わった際にそのファイルを削除する方法

# はじめに
タイトル通り，特定のファイルを転送し終わった際にそのファイルを削除する方法を説明します．どこで使うんだという話について，私は実験でファイルを転送するのですが，繰り返し実験するために自動化したい時があります．その時既にファイルが転送されているとファイル転送の実験ができないため，初期化のためファイルを削除したいときがあります．そういうときのためのプログラムを紹介します．

# プログラム

```
futa@futa-backup3:~$ cat auto_rm.sh
function auto_remover () {
watch=( -e MOVED_TO -m)
inotifywait ${watch[@]} [消したいファイルの転送先パスを入力] | while read notice
do
if [ "`echo $notice | awk "{print \$2;}" | grep MOVED_TO`" ]
then
    echo "ファイル削除"
    rm [消したいファイルの名前を入力]
else
    echo "削除対象無し"
fi
sleep 10
done
}

auto_remover &
```

入力が必要なのは，[消したいファイルの転送先パスを入力]と，[消したいファイルの名前を入力]の2つの部分です．基本的には，inotifyでファイルを動きを監視し，ファイルが全て転送されたら削除しているだけです．検知にCLOSE_WRITEではなくMOVED_TOを使っている理由は，ファイルを転送し終わったとき，一番最後に検知されるのがMOVED_TOだからです．検知されるファイルの状態はCREATE→OPEN→ATTRIB→MODIFY→CLOSE_WRITE→ATTRIB→MOVED_FROM→MOVED_TOの順番です．

# 出力結果
出力結果は以下の通りです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1814188/3631b5fe-ae0c-e274-ec3e-f3a48993cb65.png)
指定されたファイルしか検知しないので，より汎用的にファイルを削除したい場合は，このプログラムを変更する必要があります．
Xfreeレンタルサーバにお世話になっていた初期ドメインサイトの引っ越し

# はじめに
Xfreeレンタルサーバー廃止、シンアカウントの方に力を入れるということでお知らせが来ました。
場所をお借りしていた弊ホームページもお引越しすることと相成りました。

ところで弊ホームページ、**初期ドメイン**でお世話になっていたんですよね…どうお引越ししたものかな…。ひとまず別のサーバーをお借りし、アカウントを作り、いろいろと調べていい方法を探してみることにしました。
# そもそもドメインの種類
ここから私は怪しいんですけどね。怪しいから調べましょうね。
ドメイン：おおもとのドメイン
サブドメイン：おおもとのドメインの頭に何かつけて派生として存在する。
# 私が使っていたドメインの正体
私が使っていたドメインは以下、初期ドメインです。
```
〇〇.xdomain.jp
```
つまりXFREEさんのドメインのサブドメインですね。XFEEさんのもちもの。ということはXFREEさんサービス終了時に使用できないし、このドメインを使用したままの他サーバーへ引っ越しはできない。
引っ越し先で独自ドメインを作成しましょうね。
# やること
+ 引っ越し先にデータ移動
+ 引っ越し先で独自ドメインを必ず取得
+ 元のアドレスに引っ越ししましたのページをしばらく残す

リダイレクト設定も考えましたがxdomain.jpが使用できなくなることを考えると、使用できなくなるまで、「引っ越ししました」の案内ページを残すのがいいのかもしれないと思いました。Googleのサーチにも載っていたところだけちょっと惜しい。でもブックマークしているかもしれない現ユーザーを優先。
[tips][Java] 変換系

Javaの変換系のまとめです。
プリミティブ型とそのラッパークラスのクラス型の相互変換のメモです。
tipsめも。

# 変換系
## `Integer` <-> `int`

### `int` -> `Integer`

int型をInteger型に変換します。
```java
int i = 2;
Integer i_integer = Integer.valueOf(i);
String type = i_integer.getClass().getSimpleName();
System.out.printf("%s %d",type, i_integer);
```

```java
Integer 2
```

### `Integer` -> `int`

Integer型をint型に変換します。
```java
// Integer -> i
int ii = i_integer.intValue();
System.out.println(ii);
```

## `String` -> `int`

```java
// String -> i
String str = "25";
// 暗黙的に`Integer` -> intに変換します。
int number = Integer.parseInt(str);
System.out.println(number); 
// 暗黙的に`Integer` -> intに変換します。
int bb2 = Integer.valueOf(str);
System.out.println(bb2);
```

```java
25
25
```

## ※`Integer.valueOf`と`Integer.parseInt`の違い

`Integer.valueOf`と`Integer.parseInt`については、前者は`Integer`クラスで返し、後者はプリミティブ型となる`int`型で返しているようです。次で触れる暗黙的変換のため、結果が同じとなってます。


## ※プリミティブ型とそのラッパークラスのクラス型との暗黙的な変換について

```java
// 変数定義
int primitive = 1;
Integer wrapper = null;

// プリミティブ型からラッパークラスへの変換
wrapper = primitive;

// ラッパークラスからプリミティブ型への変換
// （変換が正しく行われればif文の中に入り変数の中身を出力）
if (primitive == wrapper) {
    System.out.println(wrapper);
}
```
データベース設計に役立つExcelの知識

データベース設計の際には、適切なデータ構造の計画と整理が非常に重要です。その過程で、Excelはその柔軟さと視覚的な使いやすさから、効率的なデータベース設計のサポートツールとなります。以下では、データベース設計において覚えておくと役立つExcelの知識をいくつかご紹介します。

# 1. データのサンプルを作成するための表作成

Excelを使って、テーブルのサンプルデータを作成することは、データベース設計の初期段階で非常に有効です。実際のデータの例を使ってテーブルの構造を理解したり、どのようなデータ型が適切かを検討するために、Excelでサンプルデータを作ることができます。

# 2. 正規化のためのデータ整理

データベース設計では、データを効率よく整理する「正規化」が不可欠です。Excelの「フィルター機能」や「重複の削除」を使うことで、冗長なデータを見つけやすくし、正規化の手助けとなります。また、複数のシートを使ってテーブルごとのデータ構造を視覚的に分けて検討することも可能です。

# 3. ER図の作成支援

ER図（エンティティ関係図）をExcelで簡単に表形式で表現することもできます。各シートにテーブルのカラムやリレーションをまとめることで、ER図の下書きを行うことができます。Excelのセルを使って視覚的にエンティティとその属性、リレーションシップを示すことで、ER図作成ツールに移行する前の整理に便利です。

# 4. 仮のキー制約とリレーションの定義

Excelを使用して、主キー（Primary Key）や外部キー（Foreign Key）を仮に定義しておくと、データ同士のリレーションが明確になります。例えば、各テーブルの主キーを色分けしたり、外部キーをリンクセルとして表現することで、データベース全体の構造を視覚化できます。

# 5. データの関係性のテスト

Excelで異なるテーブル間の関係性を確認するのも良い方法です。Excelの「VLOOKUP」や「INDEX/MATCH」関数を使うことで、あるテーブルのデータが他のテーブルと正しく関連付けられているかどうかのテストが行えます。これにより、リレーションシップの確認ができます。

# 6. ピボットテーブルを使ったデータ分析

ピボットテーブルは、大量のデータから有益な情報を引き出す際に役立ちます。データのパターンや頻度を把握するために、Excelのピボットテーブルを使うことで、どのカラムが頻繁に使用されるか、またはどの属性が特に重要かを見極める手助けになります。

# 7. データ入力ルールの設定

Excelでは「データの入力規則」を使って、特定のデータ形式を強制することができます。データベースにおいても入力データの一貫性が非常に重要なので、Excelで事前にどのようなデータが入力されるべきかをシミュレーションしてみるのは有効です。例えば、日付や数値のみを許可する設定を行うことで、データの整合性を保つためのルールを決める練習になります。

# 8. 覚えておくと便利なExcel関数

データベース設計において特に役立つExcel関数をいくつかご紹介します。

VLOOKUP / HLOOKUP: 他のテーブルからデータを検索して取り出すのに役立ちます。

INDEX / MATCH: VLOOKUPよりも柔軟にデータを検索できます。特にテーブルの列や行が変更される可能性がある場合に便利です。

IF / IFS: 条件に応じた値を返すことで、データの分類や確認に使用できます。

COUNTIF / COUNTIFS: 条件に一致するデータの数を数えるのに使います。データの一貫性をチェックするのに有効です。

SUMIF / SUMIFS: 条件に基づいてデータの合計を求めることができます。特定の条件に一致するデータの合計を計算する際に役立ちます。

UNIQUE: 重複を排除して一意の値を抽出するのに使います。正規化の際に非常に役立ちます。

DATA VALIDATION: 入力データの検証を行うことで、特定の値のみが入力されるようにすることができます。

# まとめ

Excelはデータベース設計において、非常に役立つツールです。データの整理、サンプルの作成、リレーションの確認、入力規則のシミュレーションなど、さまざまな面で効率的なサポートを提供します。Excelを使って設計段階でデータをよく理解することで、データベースの構築がスムーズに進むでしょう。


**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**
php artisan -vで出てきたエラーについて

つい先日、自己学習も兼ねてDocker + Laravelで遊ぼうとした時に

```linux
php artisan -v
```

と打った時に出会したエラーとその解決方法を書いていく。

出てきたエラーがこちら

```
[21-Nov-2024 02:57:10 UTC] PHP Warning:  PHP Startup: Unable to load dynamic library 'php_mbstring.dll' (tried: /usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll (/usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll: cannot open shared object file: No such file or directory), /usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll.so (/usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll.so: cannot open shared object file: No such file or directory)) in Unknown on line 0

Warning: PHP Startup: Unable to load dynamic library 'php_mbstring.dll' (tried: /usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll (/usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll: cannot open shared object file: No such file or directory), /usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll.so (/usr/local/lib/php/extensions/no-debug-non-zts-20210902/php_mbstring.dll.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
[21-Nov-2024 11:57:10 Asia/Tokyo] PHP Deprecated:  PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0

Deprecated: PHP Startup: Use of mbstring.internal_encoding is deprecated in Unknown on line 0
```

php_mbstring.dllが見つからなくて後続の処理が止まっているようなのでphp_mbstring.dll関連の処理を外してみる

```php.ini
### Development Setting
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 1G
upload_max_size=1G
post_max_size = 1G
memory_limit = 100G
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8
extension = php_mbstring.dll

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.encoding_translation = Off
mbstring.detect_order = auto
```

をこう
```php.ini
### Development Setting
zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 1G
upload_max_size=1G
post_max_size = 1G
memory_limit = 100G
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8
; extension = php_mbstring.dll

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
; mbstring.language = Japanese
; mbstring.internal_encoding = UTF-8
; mbstring.encoding_translation = Off
; mbstring.detect_order = auto
```

エラーは無くなった。

が果たしてこれで良かったのか、疑問が残るところ
この辺り詳しい方、コメント残してくれると嬉しいです。
GASによるカスタムメニューの作り方

# はじめに

Googleドキュメント、スプレッドシート、スライド、フォームなどの GoogleWorkspaceアプリ では Google Apps Script (GAS) によって独自のメニューを作成することができます。


# カスタムメニューの作成方法

1. GoogleWorkspaceアプリを開く
    新規または既存のGoogleWorkspaceアプリを開いてください。
    <br>
    
1. スクリプトエディタを開く
    メニュー欄から「拡張機能」→「Apps Script」と選択してスクリプトエディタを開きます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939665/62766fee-b4a5-b64c-71d8-96fcb07f4383.png)
    <br>

1. GASを編集する
    任意のファイルで次のような関数を定義してください。

    ```javascript
	function onOpen() {
		var ui = SpreadsheetApp.getUi();
		ui.createMenu('カスタムメニュー')
			.addItem('機能1', 'func1')
			.addSeparator()
			.addSubMenu(ui.createMenu('サブメニュー')
				.addItem('機能2', 'func2'))
			.addToUi();
	}
	
	function func1() {
		SpreadsheetApp.getUi()
			.alert('機能1が呼び出されました');
	}
	
	function func2() {
		SpreadsheetApp.getUi()
			.alert('機能2が呼び出されました');
	}
    ```
    ※ onOpen()：GoogleWorkspaceアプリが開かれたことをトリガーに実行される関数
    <br>

1. GoogleWorkspaceアプリをリロードする
    GASで定義した onOpen関数 を実行させるためGoogleWorkspaceアプリをリロードしてください。
    <br>

1. 動作を確認する
    リロードして数秒待つとメニュー欄にユーザが定義したメニューが表示される。
    以下は試しに「サブメニュー」の「機能2」を選択したときの結果です。
    
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939665/59a8306d-6425-c9c1-bdc0-33a5c146b728.png)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939665/ad6dcfbf-239f-8d0c-7922-912dbf120f62.png)
WSLのフォルダにエクスプローラーからアクセスできない

## 現象
タイトルの通りなのですが、いつものようにエクスプローラーからWSL内のフォルダにアクセスすると以下のようなメッセージが表示されるようになり、アクセスできない状態になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469482/fb07839d-cb09-ab1d-b756-e560a04749f9.png)
> \\wsl.localhostにアクセスできません。このネットワーク リソースを使用するアクセス許可がない可能性があります。アクセス許可があるかどうかこのサーバーの管理者に問い合わせてください。

## 解決策
:::note warn
Windowsのレジストリ編集はOSの動作にさまざまな影響が出る可能性があるためあくまで自己責任で行ってください。
:::
`ファイル名を指定して実行`を開き、`regedit`を起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469482/35c8ffd3-a042-d1e3-be1e-49de7c623d72.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469482/93aa33eb-51b6-6ef1-4c64-be4583b18804.png)

該当のフォルダ`\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order`を開き、その中にある`ProviderOrder`を開きます。

そして「値のデータ」を`cbfs6,P9NP,RDPNP,LanmanWorkstation,webclient`に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469482/359298ff-f3ba-4434-ffa4-558d5c27cc7d.png)


以上でエクスプローラーからWSL内のフォルダにアクセス可能になります！

## 参考
https://qiita.com/rodtang/questions/ec1e6322cf6755f14db1
https://www.superheaoz.top/2021/10/50200/
pythonを用いてDDNSサーバのログをSlackに通知する方法

# はじめに
私が行った研究において，SlackのAPIとPythonを用いてVMからSlackにメッセージを送信する方法について知ることが出来たので，今回得た知識をまとめました．

# 事前準備
- Slack apiからappを作成し，webook URLを取得する
- 取得したURLをメモしておく

# 通知方法
Slackに通知する関数は以下のように作成しました．
```
#slackへの通知をする関数
def send_to_slack(message):
    webhook_url = #事前準備で取得したWebhookのURL
    payload = {
        "channel": "通知したいチャンネル名",
        "username": "通知するユーザ名",
        "text": message,
        "icon_emoji": ":ghost:" #好きなアイコンを記述
    }
    requests.post(webhook_url, json=payload)
```

DDNSサーバのログからslackに通知するメッセージを作成する関数は以下のように作成しました．
DNSマッピングがADDのもののみを通知するようにしています．
私はDDNSサーバをkeaで作成しており，他のソフトウェアで作成した場合，ログの形が違う可能性があるので修正する必要があるかもです．
```
#slackへ通知するためのテキストをログ文から生成する
def generate_message(line):
    global log_time, message_lst, add_remove_flag

    #DNSへの追加が成功していたらそのログの日時を小数点第2位まで取得する
    if "DHCP_DDNS_ADD_SUCCEEDED" in line:
        #4桁の数字（年度），2桁の数字（月）のようにして日時を取得する
        log_time = re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{2}', line).group()
        add_remove_flag = True

    elif "DHCP_DDNS_REMOVE_SUCCEEDED" in line:
        log_time = re.match(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{2}', line).group()
        add_remove_flag = False

    #取得した日時と同じで，FQDNがあれば
    elif "FQDN:" in line and log_time in line:
        message = re.search(r'FQDN: \[(.*?)\.\]', line).group(1)
        message_lst.append(message)

    #取得した日時と同じで，IP Addressがあれば
    elif "Address:" in line and log_time in line:
        message = re.search(r'IP Address: \[(.*?)\]', line).group(1)
        message_lst.append(message)

    #IPアドレス，FQDNが追加されていれば
    if len(message_lst) >= 2:
        #Slackに通知
        fqdn = message_lst[0]
        ip_address = message_lst[1]

        if add_remove_flag:
            #連続でADDされていなければ通知
            if add_and_remove_check(fqdn):
                new_message = f"{fqdn} is binded new client.(ip_addr: `{ip_address}`)"
                send_to_slack(new_message)
                message_lst = []

        else:
            remove_text(fqdn)
            new_message = f"{fqdn} is removed client.(ip_addr: `{ip_address}`)"
            send_to_slack(new_message)
            message_lst = []
```
上記の関数を用いてSlackにメッセージを送信すると以下のように通知されます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562790/f6c79b6b-b78e-b700-9c16-4236efa35a88.png)

# おわりに
本記事では，私が研究を通じて得たpythonを用いてDDNSサーバのログをSlackに通知する方法についてまとめました．
【自分用】個人的に覚えにくいCSS備忘録

[*, *:before, *:after {box-sizing: border-box;}：paddingなどが理由で行送りになるのを、自動的に幅を計算して行送りにさせないようにする](#)
[flex-grow: 1：固定の幅を差し引いた幅を適用する](#)
pandas 2.1.4 と 2.2.0 での 整数型 Series のmap(str)挙動の違いとその対応



## Prerequisite
```python
import pandas as pd

ser = pd.Series([1, 2, 3, None], dtype="Int8")
```

以下のように、NA型を含新しいIntのSeries型を文字列に変更しようとすると、挙動の違いがある。これによりパイプラインが破壊され3時間奪われた。

## 2.1.4

```python
>>> ser.map(str)
0       1
1       2
2       3
3    <NA>
dtype: object
```

## 2.2.0

```python
>>> ser.map(str)
0    1.0
1    2.0
2    3.0
3    nan
dtype: object
```

## 取った対応

現状 pandas を2.2.3まで上げているので明示的に string 型とした。 [PDEP-14によると](https://qiita.com/hkzm/items/57170941d34bcf539467) v3.0 で stringの再編成が行われるが、この指定で問題はない。

```python
>>> ser.astype("string")
0       1
1       2
2       3
3    <NA>
dtype: string
```

以上。
ネットワークの相違点とは何か?

# 異なるネットワーク接続での操作に問題がある
>単一ネットワーク内の操作よりネットワーク間の接続での操作をより困難にしている

# 宛先を見つける問題 
>もし送信元がイーサネット上にあり、宛先がセルラー電話網上にあるときはどうすれば良いだろうか？

>コネクションレス型のネットワークからコネクション型のネットワークへとパケットを横断させる荷なる。このためには、新たなコネクションを短時間で確立する必要があるが、どうしても遅延が発生してしまうし、その子エンクションが他のパケットの送信で利用されない場合はオーバーヘッドが大きくなってしまう

# マルチキャストの際の問題
>マルチキャストを行う際、グループの中にマルチキャストに非対応のネットワークに属するメンバーがいる場合はどうすれば良いだろうか？

>ネットワークごとに最大パケット・サイズが異なる場合も厄介な問題が起こりうる。

# 少しの違いなら覆い隠せるが大きすぎると難しい
>これらの相違点は少しの手間をかけることで覆い隠せる。

>一方ネットワークごとの違いが大きく、調整が難しい場合もある。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/

# 感想
ネットワークごとの相違点が大きすぎると調整が難しい。
どのようにして調整していくのか？
Slack の確認コードの入力を自動化するGoogle Apps Script

```js:コード.gs
function messageToObject(message) {
  return {
    date: message.getDate(),
    subject: message.getSubject(),
    plainBody: message.getPlainBody(),
  }
}


function doGet() {
  const response = GmailApp.search('subject:"Slack の確認コード"').flatMap(thread => thread.getMessages().map(messageToObject))
  return ContentService.createTextOutput(JSON.stringify(response, null, 2)).setMimeType(ContentService.MimeType.JSON)
}
```
Linuxのグループ管理を簡単にするスクリプト

# はじめに
Linuxでグループを作成・管理する際、複数のコマンドを実行する必要があり、少し手間がかかります。そこで、基本的なグループ管理操作をシンプルに行えるスクリプトを作成しました。

## スクリプトの概要
このスクリプトは以下の3つの基本的な機能を提供します：
- グループの作成とユーザー追加
- グループの削除
- グループメンバーの一覧表示

## スクリプトの内容
```group-management.sh
#!/bin/bash

# 使用方法を表示
usage() {
    echo "使用方法:"
    echo "  $0 create <group> <user>    # グループ作成とユーザー追加"
    echo "  $0 delete <group>           # グループ削除"
    echo "  $0 list <group>             # グループメンバー表示"
    exit 1
}

# 引数チェック
[ $# -lt 2 ] && usage

# コマンドと引数の取得
cmd=$1
group=$2
user=$3

case "$cmd" in
    "create")
        # グループ作成とユーザー追加
        [ -z "$user" ] && echo "エラー: ユーザーを指定してください" && exit 1
        
        if ! grep -q "^$group:" /etc/group; then
            sudo groupadd "$group"
            echo "グループ '$group' を作成しました"
        fi
        
        if id "$user" &>/dev/null; then
            sudo usermod -a -G "$group" "$user"
            echo "ユーザー '$user' をグループ '$group' に追加しました"
            getent group "$group"
        else
            echo "エラー: ユーザー '$user' が存在しません"
        fi
        ;;
        
    "delete")
        # グループ削除
        if grep -q "^$group:" /etc/group; then
            sudo groupdel "$group"
            echo "グループ '$group' を削除しました"
        else
            echo "エラー: グループ '$group' が存在しません"
        fi
        ;;
        
    "list")
        # グループメンバー表示
        if grep -q "^$group:" /etc/group; then
            echo "グループ '$group' のメンバー:"
            members=$(getent group "$group" | cut -d: -f4)
            [ -z "$members" ] && echo "メンバーなし" || echo "$members" | tr ',' '\n'
        else
            echo "エラー: グループ '$group' が存在しません"
        fi
        ;;
        
    *)
        usage
        ;;
```

# 使用方法
## スクリプトの保存と権限設定

```
# スクリプトを保存
vim simple-group-manage.sh

# 実行権限を付与
chmod +x simple-group-manage.sh
```


## コマンドの基本形式

```
# グループ作成とユーザー追加
./simple-group-manage.sh create <グループ名> <ユーザー名>

# グループ削除
./simple-group-manage.sh delete <グループ名>

# グループメンバー表示
./simple-group-manage.sh list <グループ名>
```


# 実行例と結果
## グループの作成とユーザー追加

```
$ ./group-management.sh create test-group memberA
ユーザー 'memberA' をグループ 'test-group' に追加しました
test-group:x:1003:memberA
```


## グループメンバーの確認

```
$ ./group-management.sh list test-group
グループ 'test-group' のメンバー:
memberA
```


## グループの削除

```
$ ./group-management.sh delete test-group
グループ 'test-group' を削除しました
```


## エラー時の表示例

```
$ ./group-management.sh create developers
エラー: ユーザーを指定してください

$ ./group-management.sh list test_group
エラー: グループ 'test_group' が存在しません
```


# さいごに
このスクリプトは、日常的なグループ管理作業を効率化することを目的としています。必要最小限の機能に絞ることで、コードをシンプルに保ちながら、実用的な機能を実現しています。
追加機能が必要な場合は、このスクリプトをベースに拡張することも容易です。例えば、複数ユーザーの一括追加や、グループ情報の詳細表示機能なども考えられます。
nexeでパッケージングしたアプリケーションを起動すると、Cannot find moduleとなってしまった時の措置

業務でNode.jsアプリケーションをデプロイする際に、nexeを使用する機会がありました。しかしnexeでパッケージングしたアプリケーションを実行しようとすると、「Cannot find module」というエラーが発生し、起動できない状況に直面しました。
エラーの原因や対処法に関する具体的な記事が見つからなかったため、今回その解決方法を記事としてまとめることにしました。同じ問題で困っている方の参考になれば幸いです。

※結論から言うと根本解決にはなっていないですが、アプリケーションに影響ないレベルのため措置としています。

# nexeとは
 nexeとは、Node.jsのライブラリで、Node.jsのruntimeを含めた形でバイナリファイルにバンドルすることができます。Linux,Windows,macOSなどのプラットフォーム別にバイナリファイルを提供可能です。exeファイル(Windowsの場合）をサーバーに配置するだけで済み、本番環境でのアプリケーションの構築やアプリケーションの更新作業が楽になるため、業務でnexeを使ってみました。

# 実行環境
 * Windows
 * Node.js v20.15.1
 * npm 10.8.1
 * nexe 4.0.0-rc.6

# 事象について
　nexeでは、以下のようにアプリケーションをパッケージングします。
```
 nexe --build -i ./dist/index.js --resource ./dist/public/**/*  -t windows-x64-20.15.1 -o ../bin/MyApp.exe
```
  パッケージングも問題なく成功し、いざ`MyApp.exe`を実行してみると
```
node:internal/modules/cjs/loader
 throw err;
 ^
Error: Cannot find module 'mkdirp'
Require stack:
・・・
 code: 'MODULE_NOT_FOUND',
・・・

```
エラーとなり、思ったように動いてくれません。

# 原因調査
エラーメッセージに表示されたライブラリは、installした覚えがありませんでしたが、`package-lock.json`を見ると、依存ライブラリとしてinstallしていたようです。`node_modules`配下のフォルダからもinstallした形跡を確認できました。
バージョン等の情報は異なりますが、GitHubで類似のディスカッションが複数ありました。

https://github.com/search?q=repo%3Anexe%2Fnexe+Cannot+find+module+&type=issues

根本的な原因はよくわからないですが、ライブラリにバグがあり、node_modules内のライブラリをうまくパッケージングしてくれないことがあるようです。

# 措置策

今回はnexeでパッケージング時に「Cannot find module」となるライブラリを明示的に`resource`で指定する対応をしました。
```
 nexe --build -i ./dist/index.js --resource ./dist/public/**/* --resource ./node_modules/mkdirp/**/* --resource (他にもパッケージングから漏れたライブラリを指定)  -t windows-x64-20.15.1 -o ../bin/MyApp.exe
```
上記でパッケージングした`MyApp.exe`は問題なく起動することを確認できました。
対応する過程で、エラーメッセージに表示されたライブラリを含めてパッケージングすると、別のライブラリがエラーメッセージに表示されたので、エラーメッセージが表示されなくなるまで追加しました。
パッケージング漏れのライブラリの探索が面倒だったので、`--resource ./node_modules/**/*`としたのですが、`node_modules`全体を含めてパッケージングすると、パッケージング後のexeのファイルサイズが2倍近くまで膨れ上がってしまいました。流石に2倍は膨れすぎだと判断し、地道にライブラリを指定しました。
合計4つ程度のライブラリを指定することで収まり、ファイルサイズは1.1倍増位となりました。ファイルサイズ増加のデメリットがありますが、アプリケーションには影響なく動作したので今回はこの措置をとりました。

# 最後に

今回はnexeでパッケージング漏れを起こすライブラリを明示的に`resource`で指定する対応をしました。
また、nexeのGitHubのactivityを見ると活動はあまり活発でないので、今後はnexe以外の選択肢も検討した方がよさそうです。
例えば、Node.jsはv20から[Single executable applications](https://nodejs.org/api/single-executable-applications.html "Single executable applications")を試験的に標準機能として提供し、v21以降は正式リリースとなっています。標準機能で提供があるなら、あえてライブラリに頼らず標準で済ませたくなりますね。
.svgの既定のアプリが変更できない

OS : Windows11 Home

## 問題
.svgのファイルの既定のアプリが変更できなかった。
レジストリ消したりしたけどダメ。どうやらIE11(？)で開こうとしてたっぽい。

## 解決策
Edgeをアンインストールしていたためだった。
Edgeを一時的に再インストールし、既定のアプリを変更してから戻せば大丈夫だった。
インターネットワーキングとは何か？

>２つ以上のネットワークを接続して、インターネットワーク（または単純にインターネット）を形成する際に生じる問題について詳しく検討する

# さまざまなネットワークが存在する
>全員が同じネットワーク技術を利用していれば、ネットワークに加わることはより簡単になる。

>例えばイーサネットと衛星ネットワークは常に異なっているはずである。ケーブルを用いたデータ・ネットワークや電話網、送電線といった既存のシステムを再利用しようとすると、さまざまな制約が発生するため、ネットワークの特性が多様化することは避けられない。

# 大きなネットワークにすることに価値がある
>小さなネットワークに比べて、より多くのコネクションを確立できる大規模なネットワークの方がずっと価値が高いことを意味している。そこで、小さなネットワーク同士を結合して大規模なネットワークを構成したいという動機が生まれる

# インターネットとは他のホストとパケットをやり取り
>インターネットサービスを利用するために、ISPと契約するときには、回線の帯域に応じて支払いを行うことにある。しかし実際には、ユーザーは、インターネットに接続した他のホストとの間えパケットをやり取りする機能に対して対価を支払っている。仮に同じ街の中でしかパケットのやり取りができなかったとしたら、インターネットはここまで普及しなかったであろう

# さらにネットワークを拡大させるために問題を解決する
>パケットを送る上での重要な仕組みがネットワーク間で異なる場合も多いため、あるネットワークから別のネットワークへパケットを送ることはいつも容易というわけではない。また、こうした多様性の問題に対処するだけでなく、インターネットが巨大なネットワークに成長した現在では、スケーラビリティの問題も解決しなければならない。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/

# 感想

>インターネットワーキング（internetworking）
複数のコンピューターネットワークを相互接続することにより、一体化・広域化して機能させること。またはその技術。インターネットは世界規模でTCP/IPネットワークをインターネットワーキングしたもの。

https://kotobank.jp/word/%E3%81%84%E3%82%93%E3%81%9F%E3%83%BC%E3%81%AD%E3%81%A4%E3%81%A8%E3%82%8F%E3%83%BC%E3%81%8D%E3%82%93%E3%81%90-3207380#:~:text=%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AD%E3%83%B3%E3%82%B0%EF%BC%88internetworking,%E3%83%AF%E3%83%BC%E3%82%AD%E3%83%B3%E3%82%B0%E3%81%97%E3%81%9F%E3%82%82%E3%81%AE%E3%80%82

インターネットワーキングを拡大させるためにさまざまな問題を解決して発展させる
CloudWatch Logsにて収集しているログデータを別システムへ転送する

# 概要
CloudWatch Logsにて収集しているログを、リアルタイムで別システムに転送するための仕組み及びセットアップ手順を示します。

# 構成
ログを転送するための仕組みを構成図にすると次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/9c3e0e39-b42f-4fce-7a97-f4921020217b.png)

CloudWatch Logsから直接別のシステムにログを転送することは不可能なため、中継サービスが必要になりますが、今回はそれをLambdaとしています。
CloudWatch Logsの[サブスクリプションフィルター](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/SubscriptionFilters.html)という機能を利用することで、CloudWatch Logsから次のAWSサービスにログを転送することができます。
　・Amazon OpenSearch Service
　・Kinesis Data Streams
　・Amazon Data Firehose
　・Lambda
この中でAmazon Data FirehoseとLambdaが外部へHTTP POSTすることができます。
ただしサブスクリプションフィルターを利用すると、ログが"base64 でエンコードされ、gzip 形式で圧縮される"という仕様になっています。
最終的な転送先システムでは圧縮及びエンコードされていないログを受け取りたく、Amazon Data Firehoseでは実現不可能のため、Lambdaを利用してデータ変換処理することにしました。

# 前提
・CloudWatch Logsのロググループが作成済みであること
・ロググループのログストリームにてログが受信できていること

# 手順
## Lambdaセットアップ
Lambda関数はPythonで記述します。

HTTP POST送信するのにrequestsモジュールを使いたいですが、Lambdaに標準搭載されていないので使えるようにする必要があります。レイヤーと呼ばれる機能でモジュールをアップロードします。

### レイヤー作成
[こちら](https://sebenkyo.com/2021/05/21/post-1979/)のページが非常に参考になると思います。
zipファイルを作成し、レイヤー作成時にzipファイルをアップロードしてください。

### 関数作成
Lambda関数を作成します。
作成時のパラメータは次の設定にて動作確認しています。基本的にデフォルト設定です。
```
関数名：任意の名前
Pythonランタイム：3.13
アーキテクチャ：x86_64
アクセス権限：新規でロール作成
Additional Configurations：すべてOFF
```

関数のコードを記述してください。こちらのコードはサンプルになります。
`<URL>`と`<Token>`の箇所は転送先システムの情報を入力して下さい。

```
import json
import requests
import os
import base64
import gzip
from io import BytesIO

def lambda_handler(event, context):
    # 転送先システムのエンドポイント
    url = '<URL>'

    # 認証トークン
    auth_token = '<Token>'

    # ヘッダーに認証トークンを追加
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {auth_token}'
    }
    
    # デコード処理
    decoded_data = base64.b64decode(event['awslogs']['data'])
    
    # gzipを解凍
    json_data = json.loads(gzip.decompress(decoded_data))

    # ログを1件ずつループして外部システムに送信
    for log in json_data['logEvents']:
        # HTTP POSTリクエストを送信
        response = requests.post(url, json=log, headers=headers)

        # レスポンスステータスコードが200（HTTP OK）でなければエラーをログに出力
        if response.status_code != 200:
            print(f"Failed to send POST request. Status code: {response.status_code}")
```

記述出来たらデプロイして下さい。
また、先ほど作成したレイヤーを関数に追加してください。
Lambdaのセットアップは以上で完了です。

## サブスクリプションフィルター設定
CloudWatch Logsのロググループ画面に移動し、Lambdaサブスクリプションフィルターを作成します。
Lambda関数には先ほど作成したものを指定してください。
その他はデフォルト設定で構いません。

## 動作確認
転送先システムにて、次のようにログが受信できることが確認できればセットアップ完了です。
```
{
   "id": "38628348948545520451557491645803902238867625204600930304",
   "timestamp": 1732155073952,
   "message": "<ログメッセージ>"
}
```

ご参考情報ですが、ログが生成されてから転送先システムにて受信するまでの時間を複数回測定したところ、1秒～10秒ほどで受信できたことを確認しています。

# 参考
https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/SubscriptionFilters.html
https://sebenkyo.com/2021/05/21/post-1979/
https://bbh.bz/2019/09/14/link-cloudwatchlogs-to-lambda/