OmniAICreator/Qiita-1.07M huggingface dataset:
SNS型詐欺　写真合成チェッカー　rev.1

## SNS型詐欺（国際ロマンス詐欺や投資詐欺）に使われた写真が合成かどうかを判断してくれるGPT

https://chatgpt.com/g/g-67d04c644a3881918a6927e21fcc479d-photo-forgery-detector

　NPOの詐欺被害の無料相談で時々明らかに編集されたと思われる画像を被害者の方から提供されます。しかし、それが「合成である」ことを説明するのは意外と難しく感じます。ELA分析は[Foto Forensics](https://fotoforensics.com/)や[Forensically](https://29a.ch/photo-forensics/#forensic-magnifier)など、無料で使えるサイトがありますが、真っ暗なELA画像から「この部分は合成っぽい」ということはわかっても「合成です」とはっきり言える自信は持てないこともあります。そこで、Pythonのコードを使ったGPTでELAを分析させるようにしてみました。
 
# 使用環境
**無料版ChatGPTでも使えます。**

# 機能
・SNSやマッチングアプリで知り合った相手が使っている写真に不自然さを感じたときに、ELA（Error Level Analysis)を使って写真が合成かどうかを確認できます。
・鑑識の専門家向けではなく一般のネットユーザー向けですので、分かりやすい文章でELA分析結果を解説しています。

# 使い方
(1)写真をアップロードしてください。
(2)GPTがELA分析をしてくれます。
(3)ChatGPTが内容を分析して回答してくれます。

# 例
**注意:** この例で使った写真は、国際ロマンス詐欺に詐欺によく使われていた、アメリカ合衆国のジョージア州アトランタの政治家の[アレックス・ワン氏](https://citycouncil.atlantaga.gov/council-members/alex-wan#ad-image-0)のものを詐欺師グループが合成して軍服にした合成写真です。本物のワン氏は政治家で軍人ではありませんので、この写真は明らかに編集されて作られたものです。分析の精度を下げないために、顔を隠したり"Used By Scammers"の透かしを入れないようにしていますのでご了承ください。写真の人は詐欺師とは無関係です。

**写真をChatGPTに送ると以下のような文章が出てきます。**
>
>画像の編集の有無を調べるために、Error Level Analysis（ELA）を実行します。少々お待ちください。
>
>![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635312/77bf6726-859f-45fa-8653-27789389507e.png)
>
>上記の画像は、Error Level Analysis（ELA）を適用した結果です。
>
>**解析結果:**
>
>・**ELA画像（右側）**を見ると、一部の領域で異常なエラーレベルの違いが見られます。
>
>・特に顔の部分や**装飾のある箇所（勲章やバッジなど）**でエラーレベルの違いが際立っており、これらの部分が編集された可能性があります。
>
>・一般的に、自然なJPEG画像ではエラーレベルが均一になりますが、編集された部分は異常な輝度を示すことが多いです。
>
>
>この画像は何らかの編集が施されている可能性が高いと考えられます。特に顔の領域が加工された可能性があるため、元の画像と比較して検証することをお勧めします。 ​
>
# Pythonコード（ChatGPTで生成）
```
import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageChops, ImageEnhance

# 画像のパス
image_path = "画像のパス"

# 画像を開く
original = Image.open(image_path).convert("RGB")

# 画像をJPEGで再保存（再圧縮）
temp_path = "/mnt/data/temp.jpg"
original.save(temp_path, "JPEG", quality=90)

# 再保存した画像を開く
compressed = Image.open(temp_path)

# ELA（Error Level Analysis）の計算
ela_image = ImageChops.difference(original, compressed)

# コントラストを強調
enhancer = ImageEnhance.Contrast(ela_image)
ela_image = enhancer.enhance(10)

# ELA画像を表示
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("Original Image")
plt.imshow(original)
plt.axis("off")

plt.subplot(1, 2, 2)
plt.title("ELA Image")
plt.imshow(ela_image, cmap="gray")
plt.axis("off")

# 画像を保存
ela_image_path = "/mnt/data/ela_result.jpg"
ela_image.save(ela_image_path)

plt.show()

```



:::note alert
**免責事項**
ELA画像の判定というのは目視では非常に難しく、ELA画像を見ただけではよくわからないことが多かったのでこのGPTを作りました。明らかに怪しいものは的確に言判定してくれていますが、ChatGPTが間違った判定をすることはあり得ますので、その点はご理解ください。ChatGPTが誤った判断をしてその結果詐欺被害にあったとしても、当方では一切責任を負いません。基本はSNSなどで知らない人にアプローチされたらまず疑ってみることです。
::::
【情報セキュリティマネジメント試験】セキュリティ法務関連

:::note info
「著作権法とは」
思想または感情を創作的に表現したもの。
アルゴリズム、言語、規約は保護されない。

WebページのURLは、書籍の題名などと同様に、著作権法における著作物とはみなされない。
しかし、URLに独自の解釈をつけたリンク集は、その人の思想などが解釈に反映されているので、著作物に該当する。

:::

:::note info
「ステガノグラフィ」とは
画像データなどの著作物に秘密のデータを入れておく技術。
:::

:::note info
「特定電子メール送信適正化法」とは
迷惑メールの送信の規制などを目的として制定された法律。

＜オプトイン方式＞
あらかじめ送信に同意した者だけに対して、メールを送信できる方式。

＜オプトアウト方式＞
送信に同意しない者は事業者にその旨を伝えなければならない。
その旨を伝えていない者には、原則として許可を得ないままメールを送信して良い方式。
:::

:::note info
「不正競争防止法」とは
秘密として管理されているものを保護する法律。

＜営業秘密＞
事業活動上重要な情報のこと。
「秘密として管理されている生産方式、販売方法その他事業活そうに有用な技術上または営業上の情報であって、公然と知られていないもの」
:::

:::note info
「不正アクセス禁止法」とは
不正アクセス行為や、不正アクセス行為を助長する行為を禁止する法律。

＜不正アクセス行為＞
機器の利用権限を持たない第三者が、他人のIDやパスワードなどを悪用して、アクセス制限機能による利用制限を免れて特定電子計算機の利用をできる状態にする行為やそれを助長する行為
:::

:::note info
「サイバーセキュリティ基本法」とは
サイバーセキュリティ対策本部を「内閣」に設置（NISC）し、
国民にサイバーセキュリティに関する施策を総合的かつ効果的に推進する法律。

＜サイバーセキュリティ戦略＞
①情報の自由な流通の確保
②法の支配
③開放性
④自律性
⑤多様な主体の連携
:::

:::note info
「電子署名法」とは
電子署名に関連した電磁的記録の真正性の証明や本人が行ったことを証明する業務などについて定めた法律。
:::

:::note info
「個人情報保護法」とは
・氏名、生年月日など「生存している個人」を特定できる情報
・人種、犯罪の経歴、信条、病歴、障害などを要配慮個人情報という
・個人情報取扱事業者＝個人情報データベースなどを事業に用いてる者
:::

:::note info
「PCI-DSS」とは
クレジットカードなどのカード会員データのセキュリティ強化を目的として制定された基準のこと。
:::




:::note alert
「著作権法による保護の対象となるものは？」
:::

:::note warn
答え：
ソースプログラムそのもの（著作権法で保護対象）
	•	プログラムのソースコード（人が読める形で記述されたプログラム）。
	•	ソースコードは、創作的な表現として扱われ、著作権の対象となる。
	•	例えば、他人のソースコードをコピーして使用すると著作権侵害となる。

＜誤り＞
「データ通信のプロトコル」（著作権法の保護対象外）
	•	プロトコルは、データ通信の手順やルールを定めたもの。
	•	これは「アイデアや仕組み」であり、著作権法の対象にはならない。
	•	ただし、プロトコルの仕様書など文章として表現されたものは、文章の著作物として保護されることがある。

「プログラムに組み込まれたアイデア」（著作権法の保護対象外）
	•	例えば、AIのアルゴリズムや特定の計算ロジック。
	•	著作権法ではアイデアやコンセプトそのものは保護されない。
	•	ただし、アイデアを表現したソースコードや文書があれば、それらは保護対象になる。

「プログラムのアルゴリズム」（著作権法の保護対象外）
	•	アルゴリズムとは、問題を解決するための手順や計算方法。
	•	これも「アイデア」の一種なので、著作権では保護されない。
	•	ただし、新しいアルゴリズムは「特許」の対象になることがある。
:::

:::note alert
「個人情報に関する記述のうち、個人情報保護法に照らして適切なものは？」
:::

:::note warn
答え：
 「構成する文字列やドメイン名によって特定の個人を識別できるメールアドレスは個人情報である。」

＜誤り＞
「個人に対する業績評価は、特定の個人を識別情報が含まれていても個人情報ではない。」（不適切）

業績評価が、特定の個人に紐づく情報である場合、それは個人情報に該当する。
例えば、「○○さんの業績評価はA」などのデータは、個人を特定できる情報のため個人情報として扱われる。

「新聞やインターネットなどで既に公表されている個人の氏名、性別及び生年月日は個人情報ではない。」（不適切）

公開されているかどうかに関わらず、個人を特定できる情報は個人情報に該当する。
たとえ新聞やWebサイトに掲載されていたとしても、その情報が特定の個人と結びついている限り、個人情報として保護される。

「法人の本店所在地、支店名、支店所在地、従業員数及び代表電話番号は個人情報である。」（不適切）

法人に関する情報は個人情報ではない。
個人情報とは「生存する個人」に関する情報を指すため、会社の所在地や支店名、代表電話番号などの法人情報は個人情報には該当しない。
ただし、法人の代表者や従業員の個人名が含まれている場合、その部分は個人情報となる可能性がある。
:::
cscの作法 その572

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題
c#で、コンソールアプリの結果を取得せよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/03f89d2c-1be1-43be-8cda-76b6035e1102.png)


# サンプルコード

```
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;

class form1: Form {
	form1() {
		Text = "Checker";
		ClientSize = new Size(300, 300);
		Process process = new Process();
		process.StartInfo.FileName = "test1.exe";
		process.StartInfo.UseShellExecute = false;
		process.StartInfo.RedirectStandardOutput = true;
		process.EnableRaisingEvents = true;
		process.StartInfo.Arguments = "";
		process.Exited += (s, evt) => {
			process.Dispose();
		};
		process.OutputDataReceived += new DataReceivedEventHandler((_sender, _e) => {
			if (!String.IsNullOrEmpty(_e.Data))
			{
				Console.WriteLine(_e.Data);
				if (_e.Data == "1")
				{
					MessageBox.Show("hit!");
				}
			}
		});
		process.Start();
		process.BeginOutputReadLine();
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}
```

以上。
ZENRINMapsAPI OAuth2.0でデータ取得してみる Python

# はじめに
この記事は ZENRIN Maps APIからOAuth認証を使用して地図情報を検索したい人のための記事です

[前回](https://qiita.com/00b012deb7c8/items/cc07c69258ddbfaf6644)の続きで、
今回はPythonでAPIからデータを取得してみます


ZENRIN Maps API
[無料トライアルページ](https://www.zenrin-datacom.net/solution/zenrin-maps-api/trial?fm_cp=6757baf3203e3a00bb118509&fm_mu=6763a133e0aa7106d83a9c31&utm_campaign=6757baf3203e3a00bb118509&utm_medium=else&utm_source=Qiita63)
2ヶ月間無料で利用できます


# 環境
```terminal:terminal
~ % python -V
Python 3.11.9
```

前回同様にウェブコンソールから以下をメモっておきます
- APIキー
- client_id
- client_secret

[OAuth2.0の有効化](https://qiita.com/00b012deb7c8/items/cc07c69258ddbfaf6644#oauth20%E8%AA%8D%E8%A8%BC%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)

https://qiita.com/00b012deb7c8/items/cc07c69258ddbfaf6644#oauth20%E8%AA%8D%E8%A8%BC%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96


# データ取得
今回は [施設検索](https://developers.zmaps-api.com/v20/reference/webAPI/poi.html) を試してみます

早速、
```Python:sample.py
# coding=utf-8
import json
import requests
import urllib
import base64

## token取得
def get_token():
    url = "https://test-auth.zmaps-api.com/oauth2/token"

    client_id = '自分のclient_id'
    client_secret = '自分のclient_secret'
    # client_idとclient_secretをコロン(:)で連結してbese64エンコード
    auth = base64.b64encode(f'{client_id}:{client_secret}'.encode()).decode()

    # 認証情報をクエストヘッダに設定
    headers = {
            'Authorization' : f'Basic {auth}',
            'Content-Type' : 'application/x-www-form-urlencoded'
    }
    # 送信パラメータ
    params = urllib.parse.urlencode({'grant_type': 'client_credentials'})
    # リクエスト
    res = requests.post(url=url, data=params, headers=headers)

    if res.status_code == 200:
        d = json.loads(res.text)
        return d['access_token']

## 施設検索
def search_poi(token, parameters={}):
    # 施設検索のリクエスト先URL
    url = "https://test-web.zmaps-api.com/search/poi"
    
    # 認証情報をクエストヘッダに設定
    headers = {
            'x-api-key': '自分のAPIキー',
            'Authorization': f'Bearer {token}', # 取得したtoken
            'Content-Type' : 'application/x-www-form-urlencoded'
    }
    params = {
            'genre_pattern': '101' # 必須項目:ジャンルパターン
    }
    # 送信パラメータ　※必須項目と任意項目をマージ
    params = urllib.parse.urlencode({**params, **parameters})
    # リクエスト
    res = requests.post(url=url, data=params, headers=headers)

    if res.status_code == 200:
        return res.text


## token取得
token = get_token()
## 東京駅周辺100mにあるコンビニを検索
print(search_poi(token, {'genre_code': '00140:0014000180', 'proximity': '139.767132,35.681406,100'}))
```

:::note warn
client_id、client_secretなどは環境変数に設定しましょう
:::

実行するとデータを取得することができました
5件ヒットしています
![a4c8abc6b79e2163efc7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4001795/652f6e22-54ed-4e97-b3fd-b6b6fb928bfc.png)

:::note warn
見やすいようにjqコマンドを使っています
:::

# まとめ
- 流れは、まずtokenを取得して、そのtokenを使ってAPI検索
- token取得時
    - client_idとclient_secretをコロン(:)で文字列連結してBase64エンコード
- API検索時
    - 認証情報は、APIキー(x-api-key)と"Bearer [取得したtoken]"(Authorization)
Go言語での時間管理：Time.TickとTime.Afterを完全攻略！

## はじめに

Go言語の標準ライブラリである`time`パッケージには、時間を扱う便利な関数が多数含まれています。その中でも、`Time.Tick`と`Time.After`は、時間に基づいた処理を実現する際に頻繁に使用されます。しかし、それぞれの用途や注意点を理解していないと、思わぬバグや非効率なコードにつながることも。

本記事では、`Time.Tick`と`Time.After`の使い方、違い、そして実際のユースケースを解説します。

## `Time.Tick`とは？

`Time.Tick`は、指定した間隔で値を生成し続けるチャネルを返す関数です。この関数は、定期的に何らかの処理を実行したい場合に便利です。

### 基本的な使用例

```go
package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.Tick(1 * time.Second)
    for t := range ticker {
        fmt.Println("Tick at:", t)
    }
}
```

この例では、1秒ごとに現在の時刻が出力されます。

### 注意点
`Time.Tick`は永続的なチャネルを作成するため、必要がなくなったときに停止する方法がありません。そのため、不要なチャネルが残り続け、メモリリークの原因となる可能性があります。

## `Time.After`とは？

`Time.After`は、指定した時間が経過した後に値を生成するチャネルを返します。特定のタイミングで一度だけ処理を実行したい場合に適しています。

### 基本的な使用例

```go
func main() {
    fmt.Println("Waiting for 3 seconds...")
    <-time.After(3 * time.Second)
    fmt.Println("3 seconds have passed!")
}
```

この例では、3秒間待機してから次の処理が実行されます。

## `Time.Tick`と`Time.After`の違い

| 特徴             | `Time.Tick`                       | `Time.After`                  |
|------------------|-----------------------------------|-------------------------------|
| チャネル生成回数  | 繰り返し生成                     | 1回のみ生成                  |
| 主な用途         | 定期的な処理                     | 単発のタイマー処理            |
| メモリ管理の注意点| 停止しないとメモリリークのリスク | 特になし                      |

---

## 実践例：両者を組み合わせる

実際のアプリケーションでは、`Time.Tick`と`Time.After`を組み合わせることで、柔軟な時間管理が可能です。次の例では、5秒間定期的に処理を実行し、その後停止します。

```go
func main() {
    ticker := time.Tick(1 * time.Second)
    timeout := time.After(5 * time.Second)

    for {
        select {
        case t := <-ticker:
            fmt.Println("Tick at:", t)
        case <-timeout:
            fmt.Println("Timeout reached!")
            return
        }
    }
}
```

## `Time.Tick`の代わりに`time.NewTicker`を使う

メモリリークを避けるために、`Time.Tick`の代わりに`time.NewTicker`を使うことが推奨されます。`NewTicker`は明示的に停止できるため、リソース管理が簡単になります。

### 使用例

```go
func main() {
    ticker := time.NewTicker(1 * time.Second)
    defer ticker.Stop()

    for t := range ticker.C {
        fmt.Println("Tick at:", t)
    }
}
```

`defer ticker.Stop()`を使うことで、プログラム終了時に必ずTickerが停止します。

## まとめ

- `Time.Tick`は定期的な処理に便利だが、メモリ管理に注意が必要。
- `Time.After`は単発のタイマー処理に最適。
- リソース管理が必要な場合は、`time.NewTicker`を優先的に使うべき。

Go言語の時間管理を効果的に使いこなし、安定したコードを書けるようになりましょう！
JAWS DAYS 2025 参加 & 登壇レポート

# はじめに 
みなさん、こんにちは！ 
ポーラ・オルビスホールディングスのITプロダクト開発チームでエンジニアをしている中村です。 先日、JAWS DAYS 2025に参加し、ランチセッションに登壇してきましたので、その様子についてご紹介します。 
 
# JAWS DAYS 2025の概要 
詳細は公式ページ（https://jawsdays2025.jaws-ug.jp/ ）に記載がありますが、簡単に説明すると、AWS-UG（AWS User Group – Japan）という AWS のユーザーグループが主催する AWS に関する技術交流や人材交流を目的としたイベントです。一年に一度、東京で開催される大きなイベントで、様々な職種や役職の方が参加します。 

今回の開催について 
・開催日：2025年3月1日(土) 
・開催場所：池袋のサンシャインシティ 
・主催： JAWS-UG（AWS User Group – Japan） 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827938/7cca51cb-b64b-43cc-8608-d17a54a9833f.png)

# ランチセッションに登壇しました 
`XP時代のPCゲームがAWSで復活！～EC2でクラウドゲーミング～`のタイトルで20分のランチセッションに登壇しました。セッションの概要は以下のページに記載されていますので興味があればご覧になってください。 

https://jawsdays2025.jaws-ug.jp/sessions/C-3 

タイトルにある通り、古いPCゲームを現代のクラウド技術で起動させるまでの過程をセッション内でお話しました。登壇中は聴講者のリアクションを直に感じながら、温かい雰囲気の中でセッションを進めることができました。私が題材にしたPCゲームをご存じの方もいらっしゃったようで、復活させる過程を一緒に楽しんでいただけてよかったです。古いゲームを起動できた場面のスライドを載せておきます。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3827938/fa57b3b5-f5f7-401d-839a-d4fb83f94931.png)


 登壇後に会場内を歩いていると、私のセッションを聴講された方から「ゲームを復活させるお話、とても面白かったです！」とお声をかけていただき、しばらくお話させていただきました。その方からは、子供のころに遊んだゲームをまた遊んでみたい気持ちになり、今度同じ方法で試してみたいとおっしゃっていただきました。このイベントを通じてたくさんの方と交流ができ、とても有意義でした。 

# さまざまなセッションに参加しました 
ランチセッションでの登壇が終わった後は、たくさんのセッションに参加して新しいノウハウをインプットしてきました。業務に直結する技術的な内容から、クイズ大会のようなフランクなセッションまでさまざまあり、どれも興味深かったです。特にWeb APIの品質とセキュリティについてのセクションでは、我々が業務で利用しているAPI Gateway + Lambdaの構成についての言及があり、そこで初めて知ったバリデーションチェックの方法など取り入れてみたいと思いました。 

# まとめ
今までこのようなイベントに登壇する機会がなかったため、とても貴重な経験をさせていただきました。大勢の前で話すことは緊張しましたが、聴講された方に楽しんでもらえる喜びを実感できてよかったです。さまざまなセッションに参加したり、参加者との交流を通じたりして、まだまだ実力不足なことも痛感しましたが、もっと実力をつけていきたいとモチベーションが高まりました。今回の登壇にあたってのスライド作りや発表練習などの準備は楽しく、あっという間に本番を迎えました。アウトプットすることで自分自身にも知識が定着しますし、周囲と相乗効果を生み出していきたいので、このような活動は今後も続けていきたいと思います。
複数の会社で同じOrｇを使う場合




[Salesforce 組織内のデータ セット間に「壁を構築する」ことは可能でしょうか。基本的には、同じ SF 組織、データ構造、ビジネス ロジックを使用する 2 つの会社があるものの、2 つの会社が互いのデータにまったくアクセスできないようにするのでしょうか。既存のデータ (レコード タイプなど) の変更を必要とするソリューションよりも高いレベルではどうでしょうか。](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000VRaW)

:::note
セールスフォースは次のようなさまざまな方法を提案しています。 

1. 部門別にデータを整理する
2. 単一組織と複数組織: 適切な Salesforce 組織戦略を選択する
3. レコード タイプを使用すると、企業を簡単に区別することができます。レコード タイプは、新しいアカウント、商談、連絡先などを最初に作成するときに、最も高いレベルのフィルタリングを行います。 
:::
AIによる仕事の強化——未来のイノベーションと変革を推進

![屏幕截图_12-3-2025_93427_just-agi.com.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538010/6025e669-b891-4296-9142-0994ad000116.jpeg)
JavaScriptの基礎（2）

※この記事は初学者の毎日のアウトプット用に作成している記事です

## `<script>`タグの追加
HTMLドキュメントとJavaScriptプログラムを関連づける必要がある
その際に`<script>`タグが使用される

1,`<script>`〜`<script>`にJavaScriptプログラムを直接記載
2,`<script>`タグに外部のJavaScriptファイルを指定してHTMLに読み込む

`<script>`タグはHTMLドキュメントのどこに記載してもいいが、一般的には`<head>`〜`<head>`の中、もしくは`<body>`タグのすぐ上に記載

## console.log()
console.log()は()内の値をコンソールに出力するメソッド
プログラムの開発中の動作確認でよく用いられる

## ブール値
コンソールに表示されるtrueやfalseはブール値（真偽値）という
下記のconfirmメソッドはOKとキャンセル二つのボタンが表示され、OKをクリックするとtrue、キャンセルをクリックするとfalseを返す
```JavaScript
const result = confirm("本当に削除しますか？");

console.log(result) //コンソールにresultの値を出力
```


## 条件文
なんらかの条件がtrueの場合とfalseの場合で処理を振り分ける構文を条件文という
```JavaScript
const result = confirm("本当に削除しますか？");

if (result) {
    console.log("削除されました"); // OK を押した場合
} else {
    console.log("キャンセルされました"); // キャンセルを押した場合
}
```


参考書籍：

https://www.amazon.co.jp/%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3%81%AEJavaScript%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E7%8B%A9%E9%87%8E-%E7%A5%90%E6%9D%B1/dp/481561802X
【OLVM】Grafana、使用していますか？

みなさん、こんにちは！

Grafana、皆さん知っていますか？
(私はこのOLVMを触るまで知りませんでした...。)
今回はそのGrafanaについて、簡単に機能を紹介していきます。

## Grafanaって何？
Grafanaとは、データの可視化と監視を行うためのオープンソースのツールです。
主にリアルタイムのデータをインタラクティブなダッシュボードで表示することができ、ユーザーがシステムのパフォーマンスやリソースの使用状況を一目で把握することが可能となります。

Grafanaは多くのデータソースと連携することができ、カスタマイズ性が高く、ユーザーが自身のニーズに合わせた
ダッシュボードを簡単に作成・共有することができます。

OLVM（Oracle Linux Virtualization Manager）環境でも、Grafanaを活用することで仮想マシンやホストのパフォーマンスデータを効率的に監視し、運用管理を強化することができます。
これにより、システムの安定性と効率性が向上します。

## [OLVM環境]Grafanaへの接続
OLVM環境では、以下のいずれかでGrafanaへ接続することが出来ます。
 **①URL"https://<ホスト名>/ovirt-engine-grafana/"を直接入力**

 **②OLVMログイン画面の"監視ポータル"を選択**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/bb049f54-9d2d-4fae-b60b-f3c3148f2c08.png)

 **③OLVMダッシュボードのMonitoring Portalを選択**
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/431f9f5b-dc20-40a7-b201-321819f6fc39.png)

ログイン後は、以下の様な画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/69ce21a9-9048-4120-bc17-af75226eb99e.png)

## Grafanaで出来ること
今回はGrafanaで出来ることの一部を紹介いたします。

 **① ダッシュボードの作成**
データを視覚的に表示するためのダッシュボードを自由に作成することが可能で、オリジナルのダッシュボードを作成できます。
※ダッシュボードは、複数のデータや情報を一つの画面にまとめて表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/2852583f-51bb-4e18-add7-62c959a20cc0.png)

OLVMでは、デフォルトのダッシュボードが用意されておりますが、oVirt用のダッシュボードがGithubに用意されており、
それらをインポートするこも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/d798cb03-00d9-4566-b4f1-26829ae8acea.png)

 **②リアルタイムモニタリング**
KVM、OLVM、および仮想マシンなどのパフォーマンスやリソース使用状況をリアルタイムで監視できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/7f8e85dd-ebde-4085-9b87-23eeddada71b.png)

**③ アラート設定**
特定の条件に基づいてアラートを設定し、異常が検出された際に通知を受けることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/d8d5a7e9-1102-46dc-92a8-92fe47cc747b.png)

また、通知先としては以下を設定することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/8f77e9ad-798d-40b1-9927-5ddbcc38bce6.png)

 **④ データのCSVエクスポート**
表示しているデータをCSV形式でエクスポートすることも可能となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956386/282c7659-1751-4c87-8f08-9ade01b5fcee.png)

## まとめ
いかがだったでしょうか。
今回の記事では、OLVM環境で活用できるGrafanaについてご紹介しました。
英語表記という所が難点ではありますが、システムのパフォーマンスやリソース使用状況を視覚的に把握し、
運用管理を効率化することができますので、利用してみてはいかがでしょうか。
the Agentblazer Champion Modules の結果表示がおかしい



+ [AgentBlazer Champion missing 2 milestones](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PW9ds0AD)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/481ec956-2468-442b-8a94-c0a8adf1c08d.png)

:::note
This seems like a recurring problem w/in trailhead. I had this problem a month ago with the "Drive Productivity with Salesforce AI" trail (https://trailhead.salesforce.com/content/learn/trails/drive-productivity-with-einstein-ai) it would not show the "Prompt Builder Templates Superbadge Unit" (https://trailhead.salesforce.com/content/learn/superbadges/superbadge_prompt_builder_templates_sbu?trail_id=drive-productivity-with-einstein-ai) unit as completed even though when I navigated to it, it would show as completed. 

 

I am now getting something similar with the "Agentforce: Agent Planning" module in the "Become an Agentblazer Innovator" trail. 

Seems like the only thing we can do is open a case (https://help.salesforce.com/s/cases).
:::



+ [Completed the Agentblazer Champion Modules but not showing completed?](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000VM4f0AG)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4e1182c5-9464-4f5a-a8c8-a8d1aaf1520f.png)


+ [Innovator Challenge blocked due to Champion saying 94% complete even though all is finished](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000W1jV0AS)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ed963cb4-267b-4425-9cf8-aa2a12666e10.png)

+ [Agetnblazer Innovator trail not updating on Completion](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PWDA20AP)
kintone × AWS Lambda 連携を学んできたのでまとめてみた【devCamp】

こんにちは！かねごん（[@hrbk25](https://x.com/hrbk25)）です！

今回は、**kintone と AWS Lambda を連携する方法** について、**devCamp** で学んだ内容を簡単にまとめました。  
当日の勉強会の内容に加え、座学で学んだ CORS（クロスドメイン制約）の回避方法、Lambda 関数の基本について少しだけ詳しくまとめています。

## どんな人向けの記事か
- devCampでどんな内容が行われているか気になっている人
- kintone と AWS Lambda の基礎を知りたい人


## devCamp とは

devCampとは、エンジニア向けのkintone開発勉強会です。
動画のコンテンツなどもあり、非常に有益な情報がいっぱいあります。

https://page.cybozu.co.jp/-/devcamp/
>devCamp（エンジニア向け kintone 開発勉強会）とは、 kintone 開発案件の対応に必要なスキルが無料で学べる、サイボウズ主催の勉強会です。


## devCamp の概要
今回の devCamp は、座学 + ハンズオンの形式で、kintone と AWS Lambda の連携の基本概念や実装方法を学ぶ勉強会でした。  

### 座学で学んだこと
- CORS（クロスドメイン制約）の回避方法
- Lambda 関数の基本的な仕組みと活用方法

### ハンズオンの内容
#### ① フォームのデータを kintone に登録する
- Lambda 関数の設定がメインで、コードの実装は事前に準備されたものを使用
- フォームから送信されたデータを受け取り、kintone の「問い合わせ管理アプリ」にレコードを登録
- テストの実施は含まれず、設定完了までを学習

#### ② kintone の Webhook を利用して担当者をランダムに割り当て
- Lambda 関数の設定に加え、コードの実装も行う
- プロセス管理や Webhook の設定など、kintone の標準機能も活用
- 新規レコードが登録された際にLambda を利用して、担当者をランダムに割り当て、ステータスを更新する処理を実装

:::note info
今回の内容について
- 初めて AWS Lambda を触る人でも理解しやすい内容
- kintone 開発経験 1 年程度の人なら問題なく取り組める難易度
:::

---

## 座学で学んだことのことの掘り下げ
今回の記事では座学で学んだことを少しだけ掘り下げていきます。


### CORS（クロスドメイン制約）の回避方法
#### CORS とは？
CORS（Cross-Origin Resource Sharing）は、**異なるドメイン間でのリクエストを制御するブラウザのセキュリティ機能** です。  
kintoneで外部サービスとデータをやり取りする際に、この制約によって直接 API を叩けない場面があります。

詳細はメンバーの以下の記事を参照してください。

https://qiita.com/sato-souma/items/16ccac05ca04b2966050

#### **回避方法**
CORS を回避するには、**サーバーを介してリクエストを送信** する方法があります。  
この役割を担うのが AWS LambdaやAPI Gatewayなどです。

**Lambda を利用した CORS 回避の流れ**
1. フロントエンドからLambda（API Gatewayなど）にリクエストを送信
2. Lambdaからkintone APIにリクエストを転送
3. kintone API のレスポンスをLambdaを経由してフロントエンドに返す

AWS Lambdaを「代理サーバー」として使うことで、CORS の制約を回避できるようになります。

---

### Lambda 関数の基本的な仕組みと活用方法
#### そもそも Lambda とは？
AWS Lambda は、**サーバーレスでコードを実行できる環境** です。  
サーバーを管理せず、必要なときにだけ処理を実行できます。

Lambda の特長は以下の内容などがあげられます。
- Lambda関数を使用できる
- イベント駆動型アーキテクチャ
- 実行時間とメモリサイズに応じた従量課金制

それぞれについて以下に内容を記します。

#### Lambda 関数とは？
Lambda関数とは、**AWS Lambda で管理・実行されるプログラムのコードとその設定** のことを指します。  

Lambda関数の設定、例えば環境変数を活用することで、関数の柔軟性やセキュリティを向上させることができます。
また、Lambda関数の実行環境には、必要なライブラリを事前に組み込める Lambda レイヤーも用意されており、  複数の関数間で共通のコードを使い回すことも可能です。


#### イベント駆動型アーキテクチャとは？

イベント駆動型アーキテクチャは、**特定のイベントが発生したときに処理を自動的に実行する仕組み**です。
##### **イベント駆動型アーキテクチャのメリット**
- 必要なときだけ処理を実行し、無駄なリソースを使わない
　→ kintone でデータが登録されたときに Lambda が動き、処理が終われば停止するため、余計なコストが発生しない。
 
- 負荷が増えても自動で対応
 → 大量のデータが一度に登録されても、Lambda は必要な数だけ並行して処理を実行するため、システムが遅くならずスムーズに動作する。

 詳細は以下の記事を参照してください。

https://aws.amazon.com/jp/blogs/news/operating-lambda-understanding-event-driven-architecture-part-1/

#### Lambda 関数のコスト管理は？

AWS Lambda は **実行時間とメモリサイズに応じた従量課金制** です。  
以下のような特徴があります。

- 不要な処理を削減し、実行時間を短縮
- 無料枠があるため、小規模な処理なら無料で運用可能


#### kintone Webhook を活用したイベント駆動の流れ

上記のメリットなどを活用して、kintoneでは、以下のような活用方法があります。

1. kintone で **レコードが追加・更新される**
2. Webhook が発火し、**Lambda にリクエストを送信**
3. Lambda で処理を実行し、**kintone API を通じてレコードを更新**


**セキュリティやコストに注意しながら AWS Lambda を適切に活用することで、より柔軟な kintone 開発の提案が実現できます。**



## まとめ
今回は devCampの内容と、kintone × AWS Lambda の連携に必要な基礎知識（CORS 回避、イベント駆動、Lambda の仕組みなど）についてまとめました！

基礎的な内容が中心でしたが、これを踏まえて、今後さらにkintone × AWS Lambdaの活用方法を深掘りし、情報を共有していきたいと思います。
AWS IoT Events JSONカスタムペイロードのエラーの解決方法

# はじめに

AWS IoT Eventsで、イベント発行時のカスタムペイロードでエラーがなかなか解消できずにはまったので解決方法を紹介する。

# 動作確認環境

* AWS IoT Events

# エラー内容

探知器モデルを保存して発行しようとすると、以下のようなエラーが発生する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638977/59969087-2311-4d8d-8954-9077cd5b04c5.png)

```text
探知器モデルを更新できませんでした。DetectorModelDefinition is invalid due to: We couldn't parse your content expression for the payload of IotTopicPublishAction. Enter a content expression with the correct syntax. Error found in state Shutdown in onInput in event test in action IotTopicPublishAction.
```

# 解決方法

[公式ドキュメント](https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html#API_Payload_Contents
)に以下のような記載がある。

>The content of the payload. You can use a string expression that includes quoted strings ('\<string\>'), variables (\\$variable.\<variable-name\>), input values (\\$input.\<input-name\>.\<path-to-datum\>), string concatenations, and quoted strings that contain \\${} as the content. The recommended maximum size of a content expression is 1 KB.
Type: String
Length Constraints: Minimum length of 1.
Required: Yes

まとめると、カスタムペイロードのcontentExpressionは、以下のように記述する必要がある。

* カスタムペイロード全体をシングルクオーテーション（```'```）で囲む
* 文字列、変数、入力、文字列の連結を利用できる
* 入力や変数を参照する場合は、```${}```で囲む
  * 入力（```$input.<input-name>.<path-to-datum>```）を参照する場合
    * ```${$input.<input-name>.<path-to-datum>}```
      * \<input-name\> : 入力名
      * \<path-to-datum\> : 入力のJSONフィールド名 
  * 変数（```$variable.<variable-name>```）を参照する場合
    * ```${$variable.<variable-name>}```
      * \<variable-name\>: 変数名 
* 文字列型の入力や変数は、ダブルクォーテーション（```"```）で囲み文字列とする
  * 入力（```$input.inputName.stringName```）の場合
    * "${$input.inputName.stringName}"
      * inputName : 入力名 
      * stringName : 文字列のフィールド名
* ペイロードの推奨最大サイズ：1KB

GUIで設定する場合の例を示す。カスタムペイロードを選択すると以下のような設定画面となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638977/cfe7ebfd-271c-43a7-96e3-cb394e3b1346.png)

* ペイロードタイプ
  * 「JSON」を選択
* カスタムペイロード
  * 上述のルールにあるようにペイロードを文字列で記載

```text: カスタムペイロードの例
'
{
  "inputStringName": "${$input.<inputName>.stringName}",
  "variableStringName": "${$variable.<variableName>.stringName}",
  "inputNumberName": ${$input.<inputName>.numberName},
  "variableNumberName": ${$variable.<variableName>.numberName}
}
'
```
* ポイント
  * 文字列型の入力や変数を扱う場合は、ダブルクォーテーション（```""```）で囲む

```json:カスタムペイロード結果の例
{
  "inputStringKeyName": "aaa",
  "variableStringKeyName": "bbb",
  "inputNumberKeyName": 0,
  "variableNumberKeyName": 1
}
```

# まとめ

AWS IoT Eventsにおいて、イベント発行時のカスタムペイロードのエラー解決方法を紹介した。IoT Eventsのカスタムペイロードは記法が独特なので公式ドキュメントをよく読んで正しく設定することが重要。


# 参考

https://docs.aws.amazon.com/iotevents/latest/apireference/API_Payload.html#API_Payload_Contents

https://blog.denet.co.jp/aws-iot-events-sns-custom-payload/

https://qiita.com/kt-yt/items/00af19002c8643639b88

https://dev.classmethod.jp/articles/aws-iot-events-to-lambda-payload/
Spatial Studioで地図上に駅をマッピングしてみた - 実践編

# はじめに
Oracle Spatial Studio は、Oracle Databaseの空間データ（Spatial Data）を可視化・分析するための無償ツール です。SQLの知識がなくても、直感的なUIを使って地理空間データを簡単に操作できます。

本記事は「Spatial Studioで地図上に駅をマッピングしてみた - 環境準備編」の続きとなっております。

https://qiita.com/tdaimon/items/f75322adaeb0182307be

# CSVファイルのDBへのロード

## 駅データのダウンロード
日本の駅データをこちらからダウンロードします。
ダウンロードには会員登録（無料）が必要です。私が試したときにはGmailでは会員登録できなかったのでご注意ください。

https://ekidata.jp/faq.php

こちらの画面より最新の駅データをダウンロードしてください。
![画像26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/1aa20894-122f-4702-adeb-66d998ed8881.png)

## 駅データのロード

左上のハンバーガーメニュー→データセット→データセットの作成をクリックします。
![画像27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/3e28bfc3-db12-4783-aad2-4ba13d05a81c.png)

ローカル・ファイルを選択して先ほどダウンロードしたCSVファイルをドラッグ＆ドロップします。
作成をクリックします。
![画像29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/f32be24a-ca6d-4503-8302-712ebb267de1.png)

表名：STATION
データセット名：STATION
station_cdとstation_g_cdのデータ型をNUMERICに変更します。
送信をクリックします。
![画像30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/53edea49-ec6c-40d7-ba38-25413cc81e30.png)

データセットを作成できましたが、注意表示が出ているので修正します。
![画像31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/8fea9c74-5429-489e-8ec1-5e527271fcbe.png)

データセット列に移動をクリックします。
![画像32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/d591f7e4-4ad7-4b86-ad8c-d66be36e3a89.png)

STATION_CD列のトグルスイッチ[キーとして使用]をONにしてキーの検証をクリックします。
![画像33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/82e939f5-c8ba-481a-9237-5cfa07022f7f.png)

キーの認証が終わったら、適用をクリックします。
![画像34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/df9cc0d7-92a3-491f-b3ef-5af606652014.png)

注意表示が出ているので修正します。
緯度/経度の索引の作成をクリックします。
![画像35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/fcdfc5a0-cc51-458d-b404-65ff6d25536b.png)

OKをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/e22bdccd-d5e3-432e-a703-03968bf69d70.png)

正しく設定できると、アイコンの注意表記が取れてピンのアイコンになります。
![画像36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/0656c450-9c45-4aa7-a76f-4ac7cfd9b3fe.png)

# プロジェクトの作成

右の3点リーダ→プロジェクトの作成をクリックします。
![画像37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/66cb2fef-3e97-450b-b95a-cb613b463399.png)

データセットSTATIONをドラッグ＆ドロップします。
![画像38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/feaa71dc-1647-48a3-ae12-03a66c4b8d57.png)

駅データが地図上にマッピングされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/c2a7ca53-fc9f-4f2a-bca9-10d49d02a7f0.png)

拡大して確認することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3766517/f5e234c9-730e-489b-a936-1ae56505d842.png)

# まとめ
Spatial Studioを使って駅を地図上にマッピングしてみました。
Spatial Studioを使えばこのような地理空間データを直感的に可視化することができます。
今回は可視化だけ行いましたが、次回は分析を行ってみようと思います。
参考にした記事のUIが古いものとなっているためアップデートの意味も込めて記事を作成しています。

# 参考

https://oracle-japan.github.io/ocitutorials/adb/adb214-spatial-studio/
ディレクトリテーブルとは？Snowflake

# ディレクトリテーブルとは

外部ステージの情報をSnowflake側でメタデータとして保持していくもの
外部ステージにあるファイルの最終更新日などを保持しておくことで

そのデータがINSERT対象なのかそうでないかなど判断することができる

デフォルトでは無効になっており、Snowflake側で```TRUE```にしておく必要性がある

CREATE STAGEコマンドの```DIRECTORY```オプションで設定を行うことが可能

```sql
CREATE STAGE my_external_stage 
URL = 's3://my-bucket/path/' 
STORAGE_INTEGRATION = my_integration
DIRECTORY = (ENABLE = TRUE AUTO_REFRESH = TRUE);
```
```AUTO_REFRESH```というオプションが急に出てきましたが、こちらの解説をします。

## AUTO_REFRESH
ディレクトリテーブルは前述の通り、外部ステージにあるファイルのメタデータを管理するものです。
しかしながら、こちらは自動的に更新されるものではなく、ユーザー自身が自動更新を設定するか
```ALTER```コマンドを実行して、手動で更新するかどちらかになります。


### おそらくこのようにAUTO_REFRESHは動いている？？
Snowflakeのドキュメントにも
「クラウドプロバイダーのストレージイベント通知機能を利用している」
との記載がありました。

おそらく以下のような挙動でAUTO_REFRESHは動いているんだなと仮説してます。

①S3に新しいデータがアップロードされる
②S3イベント通知がトリガーされ、SNSトピックやSQSキューに通知が送られる
③Snowflakeのリスナーがその通知を受け取り、対応する外部テーブルやマテリアライズドビューを更新する
この仕組みにより、Snowflakeはデータの変更を即座に検知し、最新のデータに基づいてクエリを実行できるようになっているのではないかなと思っております。

https://docs.snowflake.com/ja/user-guide/tables-external-intro
分割代入（Destructuring Assignment）を極める

### TL;DR

JavaScript の分割代入は、配列やオブジェクトから必要な値だけを取り出すための構文です。スプレッドオペレータ（`...`）を使うと、配列やオブジェクトから「残りの要素」や「残りのプロパティ」をまとめて取得できます。
また、存在しないプロパティに対してデフォルト値を割り当てることもできます。

### 1. 配列の例

#### 基本的な使い方

```js
const colors = ["red", "green", "blue", "yellow", "purple"];

const [primary, secondary, ...restColors] = colors;

console.log(primary); // "red"
console.log(secondary); // "green"
console.log(restColors); // ["blue", "yellow", "purple"]
```

- `primary` には最初の要素 (`"red"`)
- `secondary` には 2 番目の要素 (`"green"`)
- 3 番目以降はすべて `restColors` に配列として格納されます

#### 要素数が足りない場合・デフォルト値の利用

配列の要素数が、分割代入で指定した変数の数より少ない場合には、**対応する変数が `undefined`** となります。  
ただし、**デフォルト値を指定**しておくと、`undefined` が返ってきた場合にデフォルト値が適用されます。

```js
const array = [10, 20];

const [a, b, c = 30] = array;

console.log(a); // 10
console.log(b); // 20
console.log(c); // 30  (配列に3番目がないため、デフォルト値が使用される)
```

#### スプレッドオペレータとの組み合わせ

スプレッドオペレータを使うと、「残りの要素」全体を一括で取得できます。もし配列の要素数が少ない場合は、スプレッド先に空の配列が代入されます。

```js
const array2 = [10, 20];

// 3番目以降を restNumbers で受け取る
const [x, y, ...restNumbers] = array2;

console.log(x); // 10
console.log(y); // 20
console.log(restNumbers); // [] (3番目以降が存在しないため空配列)
```

### 2. オブジェクトの例

次にオブジェクトです。オブジェクトの場合は、プロパティ名を指定して抽出します。スプレッドオペレータを使うことで「まだ分割していない、残りのプロパティ」をまとめて取得できます。さらに、存在しないプロパティに対してデフォルト値を指定することもできます。

```js
const user = {
  name: "Alice",
  age: 25,
  // city は定義されていない
};

const { name, city = "Unknown", ...restProps } = user;

console.log(name); // "Alice"
console.log(city); // "Unknown"
console.log(restProps); // { age: 25 }
```

- `name` には `"Alice"`
- `city` が存在しないため、デフォルト値として `"Unknown"` が適用
- `restProps` には `age: 25` がオブジェクトとして格納されます

もう少し複雑な例として、ネストしたプロパティの一部だけを展開し、残りをまとめることもできます。

```js
const config = {
  host: "localhost",
  port: 3000,
  credentials: {
    username: "admin",
    role: "editor",
  },
};

const {
  host,
  port,
  credentials: { username, ...restCredentials },
  ...restConfig
} = config;

console.log(host); // "localhost"
console.log(port); // 3000
console.log(username); // "admin"
console.log(restCredentials); // { role: "editor" }
console.log(restConfig); // {} （credentials 以外の残りプロパティは何もないので空オブジェクト）
```

### 3. 配列とオブジェクトを混ぜた例

実際のアプリケーションでは、オブジェクトのプロパティが配列であったり、配列の要素がオブジェクトであったりと複雑な構造が一般的です。以下は、そのようなケースでの分割代入の例です。

```js
const data = {
  numbers: [10, 20, 30, 40],
  user: {
    name: "Bob",
    info: {
      age: 28,
      // city プロパティは存在しない
    },
  },
};

const {
  numbers: [firstNum, secondNum, ...restNumbers],
  user: {
    name,
    info: { age, city = "Unknown" },
  },
} = data;

console.log(firstNum); // 10
console.log(secondNum); // 20
console.log(restNumbers); // [30, 40]
console.log(name); // "Bob"
console.log(age); // 28
console.log(city); // "Unknown"（存在しないのでデフォルト値が適用）
```

以上。
#0070（2024/03/11）オペレーター、キュー、エグゼキューター

# Pythonにおけるオペレーター、キュー、エグゼキューター

Webアプリケーションやバックグラウンド処理を構築する際、「オペレーター」「キュー」「エグゼキューター」といったコンポーネントを用いると、効率的で安定した非同期処理が実現できます。この記事では、各コンポーネントの役割とそのPythonによる具体的な実装方法を解説します。

---

## 🔹 各コンポーネントの役割

### 1. オペレーター（Operator）

オペレーターはユーザーまたは他のシステムから送られてきたデータを受け取り、タスクとして整理、検証してキューに投入する役割を持ちます。多くの場合、REST APIなどを通じて外部からデータを受け取ります。

### 2. キュー（Queue）

オペレーターが投入したタスクを一時的に保持するためのデータ構造です。タスクは先入先出（FIFO）の原則に従って順序管理されます。Pythonの標準ライブラリには`queue.Queue`があり、手軽に利用可能です。

### 3. エグゼキューター（Executor）

キューから順番にタスクを取り出し、それらを実際に処理する役割を担います。通常、独立したスレッドやプロセスで動作し、非同期にタスクを処理します。

---

## Pythonを使った実装例

### 実装環境
- Python 標準ライブラリを使用（追加ライブラリ不要）
- Flaskを利用してオペレーターを実装

### ① オペレーター（Flaskで構築）

```python
from flask import Flask, request, jsonify
import queue

app = Flask(__name__)

# タスクを一時保存するキュー
task_queue = queue.Queue()

@app.route('/submit', methods=['POST'])
def submit_task():
    task_data = request.get_json()

    # タスクの検証（必要に応じて追加）
    if not task_data or 'task_id' not in task_data:
        return jsonify({"status": "error", "message": "タスクデータが不正です"}), 400

    task_queue.put(task_data)
    return jsonify({"status": "accepted", "task": task_data}), 202

if __name__ == '__main__':
    app.run(debug=True)
```

### ② キュー（Queueを利用）

- Pythonの標準ライブラリ `queue.Queue` はFIFO（先入れ先出し）のデータ構造を提供します。
- タスクが入った順に取り出され、処理順が保証されます。

```python
import queue

# キューの作成
task_queue = queue.Queue()

# キューへ投入
task_queue.put({"task_id": 1, "content": "画像処理"})
task_queue.put({"task_id": 2, "content": "データ分析"})

# キューから取得（FIFO）
task1 = task_queue.get()  # {"task_id": 1, ...}
task_queue.task_done()
```

### ② エグゼキューター（別スレッドで処理）

```python
import threading
import time

# タスクを処理する関数
def executor(q: queue.Queue):
    while True:
        task = q.get()
        if task is None:  # 停止シグナル
            break
        print(f"処理中: {task}")
        # ここで実際の処理を記述
        time.sleep(2)  # 処理時間をシミュレート
        print(f"処理完了: {task}")
        q.task_done()

# エグゼキューターを別スレッドで起動
executor_thread = threading.Thread(target=executor, args=(task_queue,), daemon=True)
executor_thread.start()
```

終了させるときは、キューに `None` を投入します。
```python
task_queue.put(None)
```

---

## 各コンポーネントのメリット

| コンポーネント | メリット |
|---------------|----------------------------|
| オペレーター  | 入力データを検証・整理して、後続処理へ安全に渡せる |
| キュー        | タスクを一時保存し、処理順序を保証（FIFO）       |
| エグゼキューター | タスクの非同期処理により、効率的な並列処理が可能   |

---

## クライアント側のタスク投入例（Pythonコード）

Flaskサーバにタスクを投入するクライアントの例です。

```python
import requests

url = 'http://127.0.0.1:5000/submit'
payload = {"task_id": 1, "content": "画像処理"}
headers = {'Content-Type': 'application/json'}

response = requests.post(url, json=payload, headers=headers)
print(response.status_code, response.json())
```

---

## まとめ

「オペレーター」「キュー」「エグゼキューター」の構成を用いることで、リクエストの受け付けと処理を非同期に分離でき、システムの安定性とスケーラビリティを高められます。

また、必要に応じてこれらの基本コンポーネントに「ロガー」「バリデーター」「モニター」などを追加すると、より堅牢で保守性の高い設計を実現できます。
Kotlin reflection 

# 概要
(自分メモ) 自動生成されるコードをリンクする要件があったのでお試し。
型安全を台無しにするので普段使ってはいけない(んなやつイネー)

# 環境
- Ubuntu 24.04
- Java JDK 21.0.6
- Kotlin 2.1.20 (jvmプラットフォームのみ確認)

# ソース
指定パッケージ内のクラスをリストする例

```build.gradle.kts
dependencies {
    implementation(kotlin("reflect"))
    implementation("org.reflections:reflections:0.10.2") // https://mvnrepository.com/artifact/org.reflections/reflections
}
```

```kotlin: src/jvmMain/Main.kt
package smpl

fun main() {
    val packageName = "smpl"
    val refs = Reflections(
        ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(packageName))
            .setScanners(SubTypesScanner(false), TypeAnnotationsScanner())
    )
    val classes = refs.getSubTypesOf(Any::class.java).map { it.kotlin }

    classes.forEach { c ->
        println("${c.supertypes.joinToString()}.${c.simpleName}")
        c.members.forEach { println(it) }
    }
}
```

クラスの情報を判別する
```kotlin: src/jvmMain/Main.kt
// リフレクションによりKClass#is~関数のうち引数を与えないものすべて抽出し実行する
inline fun <reified T : Any> listClassInfo(clazz: KClass<T>) {
    KClass::class.members.forEach { m ->
        if (m.name.startsWith("is") && m.parameters.size <= 1) println("${m.name}: ${m.call(clazz)}")
    }

//    すなわち
//    println("isData: ${clazz.isData}")
//    println("isSealed: ${clazz.isSealed}")
//    println("isInner: ${clazz.isInner}")
//    println("isAbstract: ${clazz.isAbstract}")
//    println("isCompanion: ${clazz.isCompanion}")
//    println("isFinal: ${clazz.isFinal}")
//    println("isOpen: ${clazz.isOpen}")
//    println("isFun: ${clazz.isFun}")
//    println("isValue: ${clazz.isValue}")
}
```

[➔ソース](https://github.com/kyoya-p/samples/tree/master/2025/reflection)

# テスト/実行
```shell
sh gradlew jvmRun -DmainClass=smpl.MainKt
```
wslでelixir その158

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題やってみた。

# 練習問題
axonで、sin波を求めよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a165399f-5dc5-4db7-8aa7-4318521d2bc3.png)

# setup

```
Mix.install(
  [
    {:nx, "~>0.9"},
    {:bumblebee, github: :"elixir-nx/bumblebee"},
    {:kino_vega_lite, "~> 0.1.7"},
    {:httpoison, "~> 1.8"},
    {:xla, "~> 0.8", XLA_BUILD: true},
    {:exla, "~> 0.9"},
    {:adbc, "~> 0.1"},
    {:kino, "~> 0.10.0"}
  ],
  config: [
    nx: [default_backend: EXLA.Backend]
  ]
)
```

# サンプルコード

```
defmodule Sin do
  require Axon

  def build_model(input_shape) do
    inp1 = Axon.input("x", shape: input_shape)

    inp1
    |> Axon.dense(8, activation: :tanh)
    |> Axon.dense(1, activation: :tanh)
  end

  defp batch do
    x = Nx.tensor(for x <- 1..100, do: [x / 15])
    y = Nx.tensor(for x <- 1..100, do: [:math.sin(x / 15)])
    {x, y}
  end

  defp train_model(model, data, epochs) do
    model
    |> Axon.Loop.trainer(:mean_squared_error, :sgd)
    |> Axon.Loop.run(data, %{}, epochs: epochs, iterations: 1000)
  end

  def run() do
    model = build_model({nil})
    input_data_100 = batch()

    data =
      Stream.repeatedly(fn ->
        input_data_100
      end)

    model_state =
      train_model(model, data, 10)
      |> IO.inspect(label: "model_state")

    {x1_tensor, y1_tensor} = input_data_100
    x2_tensor = Nx.tensor(for i <- 0..100, do: [i / 15])
    y2_tensor = Axon.predict(model, model_state, %{"x" => x2_tensor})

    View.plotxy(
      Nx.to_flat_list(x1_tensor),
      Nx.to_flat_list(y1_tensor),
      Nx.to_flat_list(x2_tensor),
      Nx.to_flat_list(y2_tensor)
    )
  end
end

Sin.run()
```


以上。
家計簿アプリを作る＃１４

![スクリーンショット 2025-03-12 082845.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4012588/bb2d2a7e-01af-4a6b-ad00-92faee7e7dc9.png)
![スクリーンショット 2025-03-12 083145.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4012588/b8c02ab2-531f-4772-810a-fd227e768ea6.png)

中身は主に、ヘッダー、サイドバー、メインコンテンツで成り立ってます。
ドキュメントセルフチェックポイント

設計書などドキュメントを作成する場合のセルフチェックポイント
・明瞭性
　5W1Hを意識して、特に主語の省略時に意味が通じるかを確認すること
　分かりづらい説明には、補足や図表など別枠を用いること
・可読性
　1行に複数の要素を含まないこと
　可能であれば、箇条書きにする
　決められた場所、決められた様式を確認し、遵守すること
　既定の様式や記載粒度、記載ルールを確認し、順守すること
　表記方法（段落、フォント、行間など）が適切かを再確認すること
・網羅性
　記述前に参照元の資料を明確にしておくこと
　必要な情報が網羅されているかを再確認すること
　必要なモジュールがパッケージされているかを再確認すること
　異常系についても忘れないように
・正確性
　記述前に参照元の資料を明確にしておくこと
　元文書の内容を正しく反映しているかを再確認すること
　曖昧なものについてはその旨を明記するか、確定するまで調査すること
　不明な点や曖昧な点は、関係者への確認や情報収集を行い、正確な情報を記述すること
・一貫性
　用語集を確認し、用語に揺れが無いかを確認すること
　他のドキュメントや全体を見直し、言葉遣いに揺れが無いかを確認すること
　表記方法（段落、フォント、行間など）に揺れが無いかを確認すること
　パッケージする成果物間の関連性に矛盾が無いか再確認すること
　標準規約を確認し、遵守しているかを再確認すること
・最新性
　元の資料が最新かをチェックする
　常に最新のものをチェックアウトしておくこと
　作業分担を意識して、他者が更新中のものが無いかを確認すること
　パッケージする成果物が最新かを再確認すること
　チェットなどで関連の情報を確認し変わっていないかを再確認すること
・保守性
　更新履歴や修正箇所などが正しく更新されているかを再確認する
・突発性
　イレギュラーな状況や初めての対応には特に注意をすること
　 想定されるリスクや影響を洗い出し、対応策を検討すること
　イレギュラーな状況への対応手順を確認し、慎重に対応すること
　過去の事例やトラブルシューティング情報を確認し、問題ないかを再確認すること
ネットワーク入門：MacBookのGoogle ChromeでCookieの保存場所とSQLiteの確認方法

## はじめに
Google ChromeはWebブラウジングにおいて欠かせないツールの一つです。

:::note warn
**多くのWebサイトではCookieを利用してユーザー情報を保存し、ログイン状態の維持やカスタマイズされたコンテンツの提供を行います。**
:::

本記事では、MacBook上のGoogle ChromeにおけるCookieの保存場所や、その中身を確認する方法について詳しく解説します。

## 書こうと思ったきっかけ
最近、「**ChromeのCookieはどこに保存されているのか？**」という質問を受ける機会がありました。

特に、Cookieがどのように格納されているのかや、SQLiteデータベースを利用して中身を確認する方法について興味を持つ人が多かったため、本記事を書こうと思いました。

## Cookieの保存場所
MacBookのGoogle Chromeブラウザでは、Cookieは以下のディレクトリに保存されます。

### デフォルトのプロファイルの場合
```
~/Library/Application Support/Google/Chrome/Default/Cookies
```

### プロファイルごとの保存場所
Chromeは複数のユーザープロファイルを使用でき、それぞれのプロファイルごとにCookieが保存されます。

```
~/Library/Application Support/Google/Chrome/Profile X/Cookies
```
※ `Profile X` の部分は `Profile 1`、`Profile 2` など、使用しているプロファイル名に置き換えてください。
※ デフォルトのプロファイルは `Default` になります。

## Chromeの設定からCookieを確認する方法
1. Chromeを開く。
2. アドレスバーに `chrome://settings/cookies` を入力してEnter。
3. 「すべてのサイトのデータと権限を表示」を開く。
4. 保存されているCookieを確認する。

## Cookieの中身（SQLiteデータベース）の場所
Google ChromeのCookieは SQLiteデータベース (`Cookies` ファイル) に格納されています。

### SQLiteデータベースの場所
デフォルトのプロファイルの場合:
```
~/Library/Application Support/Google/Chrome/Default/Cookies
```
プロファイルごとの場合:
```
~/Library/Application Support/Google/Chrome/Profile X/Cookies
```

## SQLiteデータベースの確認方法（未実施）
1. **ターミナルを開く**。
2. **SQLite3を使ってデータを確認**。

```
sqlite3 "~/Library/Application Support/Google/Chrome/Default/Cookies"
```

3. **テーブル一覧を表示**。
```
.tables
```

### 主なテーブル
- `cookies` … Cookie情報
- `meta` … メタデータ

4. **Cookieのデータを確認**。
```
PRAGMA table_info(cookies);
```
または、特定のデータを取得。
```
SELECT * FROM cookies LIMIT 10;
```

## 注意点（※個人調べ）
- **Chromeを起動していると `Cookies` データベースはロックされる**ので、**Chromeを完全に終了**してから操作する必要があります。
- `cookies` テーブルの `encrypted_value` カラムには**暗号化されたCookieデータ**が格納されています。
  - Macでは `Keychain`、Windowsでは `DPAPI` を使用して暗号化されています。
- Cookieを手動で編集・削除すると、**ブラウザが正常に動作しなくなる可能性**があるので注意してください。

## まとめ（※個人調べ）
- MacBookのChromeでCookieは `~/Library/Application Support/Google/Chrome/` に保存される。
- Cookieのデータは `Cookies` ファイル（SQLiteデータベース）に格納される。
- `sqlite3` コマンドで中身を確認できるが、暗号化されているデータも含まれている。
- 操作時には **Chromeを完全に終了** することが重要。
PythonでBoltを利用してSlack用ボットを作る🤖

# 概要
`Python`で`SlackBolt`を利用して、Slack用のボットを作る。`AWS`の`lambda`にデプロイする想定。

`lambda`で実行、かつ応答に時間がかかることを考慮して、`Lazy listeners`[^1]を使用する。

ここではサンプルとして、`Mention`と`DM`に反応して、`Hello !`と返信させるようにする。
スレッド内から`Mention`されたら、スレッド内に返信させる。


# Slack API の設定

[Slack API](https://api.slack.com/apps)でアプリを作って設定する。

- 必要なキーを取得する
  - `Basic Information`の`Signing Secret`
  - `OAuth & Permissions`の`OAuth Tokens`
- 権限を設定する
  - `OAuth & Permissions`の`Scopes`
    - `app_mentions:read`
    - `chat:write`
    - `im:history`
- ボットのURLを設定する
  - `Event Subscriptions`の`Request URL`
    - あとでDeployするURL
    - `https://xxxx.execute-api.ap-northeast-1.amazonaws.com/prod/app`とかになるはず
- 通知イベントを設定
  - `Event Subscriptions`の`Subscribe to bot events`
    - `app_mention`
    - `message.im`


# コード

``` python
from slack_bolt import App, Ack
from slack_bolt.adapter.aws_lambda import SlackRequestHandler

app = App(
    signing_secret=os.environ["SLACK_SIGNING_SECRET"],
    token=os.environ["SLACK_OAUTH_TOKEN"],
    process_before_response=True,
)

# Mention受信時の処理
def receive_mention(_, event, say):
    if event.get('subtype') == 'bot_message':
        # 自分からのメッセージは無視(無限ループ対策)
        return

    say(text='Hello !', thread_ts=event.get("thread_ts"))


# DM受信時の処理
def receive_message(_, event, say):
    if 'channel_type' not in event or event['channel_type'] != 'im':
        # DirectMessage以外は無視
        return

    say(text='Hello !', thread_ts=event.get("thread_ts"))


def just_ack(ack: Ack):
    ack()

app.event("app_mention")(
    ack=just_ack,
    lazy=[receive_mention]
)

app.event("message")(
    ack=just_ack,
    lazy=[receive_message]
)


def handler(event, context):
    slack_handler = SlackRequestHandler(app=app)
    return slack_handler.handle(event, context)
```

簡単…🥹


[^1]: https://tools.slack.dev/bolt-python/ja-jp/concepts/lazy-listeners/
ダッシュボードの URL ハッキング 



+ [Salesforce ダッシュボードの URL ハッキング (Salesforce ダッシュボード フィルターのプリセット)](https://www.salesforceben.com/url-hacking-for-salesforce-dashboards-preset-salesforce-dashboard-filters/)

+ [【未解決】エクスペリエンスビルダーのダッシュボード検索条件のパラメータURL](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000VVVP)
Google Apps ScriptでLINE Botにメッセージ返信する関数

この関数` sendLineReply `は、**Google Apps Script (GAS)** を使用して **LINEのMessaging API** を介し、指定された `replyToken` に対してテキストメッセージを返信するためのものです

# コードの説明
### 1. チャネルアクセストークンの設定
```javascript:javascript
var channelAccessToken = "YOUR_CHANNEL_ACCESS_TOKEN";
```
* `channelAccessToken` は、LINE公式アカウントの **Messaging API** を利用するための認証トークンです。
* `"YOUR_CHANNEL_ACCESS_TOKEN" `の部分は、実際のLINEのアクセストークンに置き換える必要があります。

---
### 2. LINE API のエンドポイントを指定
```javascript:javascript
var url = "https://api.line.me/v2/bot/message/reply";
```
* ` url` は、LINEの **返信メッセージAPI** のエンドポイントです。
* ここに `POST` リクエストを送ることで、LINE Bot がメッセージを返信します。
---

### 3. 送信するデータ（ペイロード）を作成
```javascript:javascript
var payload = {
  "replyToken": replyToken,
  "messages": [{ "type": "text", "text": message }]
};

```
* `replyToken`: LINEのWebhookから受け取る、一度だけ使用可能な返信トークン。
* `messages`: 返信メッセージのリスト。
   * 今回は `type: "text" `を指定し、単純なテキストメッセージを送る仕様。
---

### 4. HTTPリクエストのオプション設定
```javascript:javascript
var options = {
  "method": "post",
  "headers": {
    "Content-Type": "application/json",
    "Authorization": "Bearer " + channelAccessToken
  },
  "payload": JSON.stringify(payload)
};
```
* `method: "post"` → POSTリクエストを送る。
* `headers`:
   * `Content-Type: "application/json"` → JSONデータを送ることを指定。
   * `Authorization: "Bearer " + channelAccessToken` → LINE APIの認証情報をヘッダーに含める。
* `payload`: 送信するデータ (`payload` オブジェクト) をJSON形式に変換。

### 5. LINE APIへリクエストを送信
```javascript:javascript
try {
  var response = UrlFetchApp.fetch(url, options);
  Logger.log("LINE返信レスポンス: " + response.getContentText());
} catch (error) {
  Logger.log("LINE API送信エラー: " + error.toString());
}
```
* `UrlFetchApp.fetch(url, options)` を使い、LINEのAPIにデータを送信。
* レスポンスの内容を `Logger.log` でログに出力。
* `try-catch` を使い、エラーが発生した場合にログへエラーメッセージを記録。

## まとめ
この関数は、Google Apps Script を使って **LINE Botがユーザーにテキストメッセージを返信** するためのものです。
実際に動作させるには、

* `YOUR_CHANNEL_ACCESS_TOKEN` を有効な チャネルアクセストークン に変更
* `replyToken` にLINEのWebhookイベントから受け取った `replyToken` を渡す
* `message` に返信したいメッセージを入れる
これで、LINE Bot が 受信メッセージに対する返信 を送ることができます！

これで、LINE Bot が 受信メッセージに対する返信 を送ることができます！にこに
競プロ日記#25/03/12

# アルゴ式-[マスの移動 (1)](https://algo-method.com/tasks/303)

- それぞれのマスまでの最小値を格納するための配列Tを定義する
- そのTを使ってT[i-1] + A[i]とT[i-1] + A[i]の小さい方をT[i]とする。
```
T[i] = min(T[i-1] + A[i],T[i-1] + A[i]);
```
# アルゴ式-[マスの移動 (2)](https://algo-method.com/tasks/306)
- 存在するかどうかわからないi-Mに対してi-j >= 0のifを使っている
```
for (int i = 1; i < N; ++i) {
    for (int j = 1; j <= M; ++j) {
        if (i-j >= 0) {
            T[i] = min(T[i], T[i-j] + A[i] * j);
        }
    }
}
cout << T[N-1] << endl;
```
- 以下解説の引用。解説を観れば理解できるがこれに問題を解きながら気づくことはできない。大外のforでT[i]に対して着目して、T[i]の最小値を内側のforでjに対して調べている。ネストのforだけどそれぞれ着目しているものが違うという意味でも少し難しい
> T[i] = min(T[i], T[i-j] + A[i] * j) というように処理していくことで、T[i] には最終的には T[i-1] + A[i], T[i-2] + A[i] * 2, ..., T[i-M] + A[i] * M の最小値が格納されるようになります。
PHPで「while文をネスト」の動作を確認してみた。

# 概要

PHPで「while文をネスト」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/php/for/index2.html

# 実装

以下のファイルを作成しました。

```sample.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
<?php
$i = 0;

while ($i < 3){
  $j = 0;

  while ($j < 3){
    print '(i, j)=('.$i.','.$j.')<br />';
    $j += 1;
  }
  $i += 1;
}
?>
</p>

</body>
</html>
```

以下のコマンドを実行しました。

```
$ php sample.php 
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPテスト</title>
</head>
<body>

<p>PHPのテストです。</p>

<p>
(i, j)=(0,0)<br />(i, j)=(0,1)<br />(i, j)=(0,2)<br />(i, j)=(1,0)<br />(i, j)=(1,1)<br />(i, j)=(1,2)<br />(i, j)=(2,0)<br />(i, j)=(2,1)<br />(i, j)=(2,2)<br /></p>

</body>
</html>
```

# まとめ

何かの役に立てばと。