OmniAICreator/Qiita-1.07M huggingface dataset:
パスワード作成　Mapの柔軟性

Paizaの指定されたルールに則ってパスワードを作る問題を解いた！
「value＝数値」という固定観念を打破した気づきは、Mapの強みを理解する大事な一歩だった！

<br>

## 🔍 問題概要

問題：「N文字のパスワードを作れ。ただしQ個の位置と文字が決まってて、残りはCで埋めること。」

例：N = 5, Q = 1, 指定「2文字目 = "T"」、C = "K" → KTKKK

入力例
```
5
1
2 T
K
```
出力例
```
KTKKK
```
<br>

https://paiza.jp/works/mondai/string_primer/advance_step6



## <br><br> NG例：初めのコード
```js
const rl = require('readline').createInterface({input:process.stdin});
const lines = [];

rl.on('line',(input)=>{
    lines.push(input);
});

rl.on('close',() => {
    const N = Number(lines[0]);
    const Q = Number(lines[1]);
    const C = lines[Q+2];
    
    const linesQ = lines.slice(2,Q+2).map(line => line.split(' '));
    
    const password = [];
    for(let i = 1; i <= N; i++){
        if(linesQ.includes(String(i))){
            password.push(linesQ[i][1]);
        }
        
        else{
            password.push(C);
        }
    }
    
    console.log(password.join(''));
});
```
### ❌ 問題点
`linesQ.includes(String(i))` は常に `false` であること。

- `linesQ` は `[ [ '1', 'A' ], [ '3', 'Z' ] ]` のような「配列の配列」(２次元配列)。

- `includes(String(i))` で "1" のような文字列を探しても、`linesQ` の中にそのような単一の文字列要素はないため `false` になる。

<br><br><br>

## ✅ OKコード（Mapで解決）
```js
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];

rl.on('line', (input) => {
    lines.push(input);
});



rl.on('close', () => {
    const N = Number(lines[0]);
    const Q = Number(lines[1]);
    const C = lines[Q + 2];

    const queries = lines.slice(2, Q + 2).map(line => {
        const [index, char] = line.split(' ');
        return [Number(index), char];
    });

    // インデックスを key、文字を value にする Map を作成
    const map = new Map();
    queries.forEach(([index, char]) => {
        map.set(index, char);
    });

    // パスワードを構築
    const password = [];
    for (let i = 1; i <= N; i++) {
        if (map.has(i)) {
            password.push(map.get(i));
        } else {
            password.push(C);
        }
    }

    console.log(password.join(''));
});
```
解説:

- `Map` で `key` : 位置 → `value` : 文字 として保存

- `map.has(i)` で存在チェック、なければ `C` を入れる

- `join('')` でパスワード完成！

<br>

## ✏️ 気づきメモ

- `配列.includes()` で多次元配列の中身は探せない（配列ごと一致する要素しか探せない）

- キー検索には `Map` やオブジェクトが向いてる

<br>

💡 `Map`では、キーだけでなく値（`value`）にも数値以外の「文字列」「オブジェクト」「関数」などが入れられる！ 
 → 僕は「`value` ＝ 数値」っていう固定観念にとらわれてたけど、完全に誤解だった(´;ω;｀)

<br><br>

## 🏁 まとめ
初心者の僕でも、`Map`を使えばスッキリ解けました。
失敗は成功のもと、というより失敗こそが教材。`Map`の柔軟性を知れたのは大きな一歩！

<br><br>
[
🐈僕の失敗談と解決話！🐻](https://paizabeginner.wordpress.com/2025/05/05/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc%ef%bc%9a%e3%83%91%e3%82%b9%e3%83%af%e3%83%bc%e3%83%89%e4%bd%9c%e6%88%90%e3%80%80map%e3%81%ae%e6%9f%94%e8%bb%9f%e6%80%a7/)
配列はいらないけど配列の中身は欲しい時

## 答え
splat演算子を使う

##　例1
```ruby
t, *s = [1,2,3]
puts *s
# 2
# 3
```
配列ではなく単体の数値が出力される

##　例2
```ruby
jp = ['japan', '日本']
 country = '日本'
 case country
 # *により配列が展開され、when 'japan', '日本'と書いたのと同じ意味になる
 when *jp
   'こんにちは'
 end
 #=> "こんにちは”
```
抜粋:
Software Design plusシリーズ プロを目指す人のためのRuby入門［改訂２版］ 言語仕様からテスト駆動開発・デバッグ技法まで
伊藤　淳一

## 引用元
Software Design plusシリーズ プロを目指す人のためのRuby入門［改訂２版］ 言語仕様からテスト駆動開発・デバッグ技法まで
Go言語 数値の書式(オリジナル関数)

# 数値の書式
Go言語では、数値をカンマ区切りするのは、ローカライズで作れる。"golang.org/x/text/language"を参照
日本で数値を読む場合は、一,十,百,万のように4桁区切りが使われる。3桁カンマ区切りだと非常に読みづらい。
そこで、区切り位置,区切り文字を自由に設定できる関数を作ってみた。

# FtoA関数
※注意: 指数表現(ex E03)には対応していない。
引数2(kind)のパターン (引数1 f64 = 1234567.890123 の場合)
 0: 1,234,567.890 123 (ISOモデル 英, 日本など).
 1: 1 234 567,890 123 (仏など).
 2: 1.234.567,890 123 (独など).
 3: 1'234'567,890 123 (スイスなど).
-1:  123'4567.8901 23 (今回の目的 4桁 区切り).

小数点以下の区切りが必要ない場合は、変数esを""にすれば良い。

```go:
import (
	"strconv"
	"strings"
)

func FtoA(f64 float64, kind int) string {
	var result string
	var wl int
	var sl int
	var ps string
	var ss string
	var es string

	switch kind {
	case 0: //[0] ISO,en,ja: 1,234,567.890
		sl = 3
		ps = "."
		ss = ","
		es = " "
	case 1: //[1] fr: 1 234 567,89
		sl = 3
		ps = ","
		ss = " "
		es = " "
	case 2: //[2] de: 1.234.567,89
		sl = 3
		ps = ","
		ss = "."
		es = " "
	case 3: //[3] ch: 1'234'567,89
		sl = 3
		ps = "."
		ss = "'"
		es = " "
	case -1: //[-1] ja4: 123'4567.890
		sl = 4
		ps = "."
		ss = "'"
		es = " "
	}

	w := strconv.FormatFloat(f64, 'f', -1, 64)

	sign := false
	if w[:1] == "-" {
		sign = true
		wl = len(w)
		w = w[1:wl]
	}
	wl = len(w)

	point := strings.Index(w, ".")
	if point < 0 {
		point = len(w)
	}
	ww := strings.Split(w, "")

	for i := range ww {

		if i < point {
			result = result + ww[i]

			j := point - i - 1
			if (j%sl == 0) && (j > 0) {
				result = result + ss
			}
		} else if i == point {
			result = result + ps
		} else {
			result = result + ww[i]

			j := i - point
			if (j%sl == 0) && (i+1 < wl) {
				result = result + es
			}
		}
	}

	if sign {
		result = "-" + result
	}

	return result
}
```
整数型(int,int8 ... int64)の場合は、float64(int)で変換する
```go
  i64 := int64(123456789)
  num := FtoA(float64(i64), -1)
  fmt.Println(num)
```

出力結果は 1'2345'6789 となる。
日本語の読みは、1億 2千 3百 4十 5万 6千 7百 8十 9とかになる。
読む時に 1億2千万円 とか、下の桁を省略しやすくなる。

# AtoF関数
FtoA関数の逆も欲しい。
※注意: 指数表現(ex E00)には対応していない。
```go
func AtoF(s string, kind int) float64 {
	var result float64
	var w string
	var ww []string
	var ps string

	switch kind {
	case 0: //[0] ISO,en,ja: 1,234,567.890
		ps = "."
	case 1: //[1] fr: 1 234 567,89
		ps = ","
	case 2: //[2] de: 1.234.567,89
		ps = ","
	case 3: //[3] ch: 1'234'567,89
		ps = "."
	case -1: //[-1] ja4: 123'4567.890
		ps = "."
	}

	ww = strings.Split(s, "")

	if ww[0] == "-" {
		w = ww[0]
	}

	for i := range ww {
		switch ww[i] {
		case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
			w = w + ww[i]
		case ps:
			w = w + "."
		}
	}

	result, _ = strconv.ParseFloat(w, 64)
	return result
}
```

この AtoF関数は、単位などが含まれていてもOK!

```go
  s := "123,456.789(kg)"
  f64 := AtoF(s, 0)
  fmt.Println(f64)
```

出力結果は 123456.789 となる。
秋月電子のGPSモジュール【GT-505GGBL5-DR-N】の推測航法/DRについて (仕様　設定)

d# DR（デッドレコニング）とは?
Wikipediaによると...

推測航法のこと。GPSからの電波が途絶えても、位置を推測していくこと
推測航法（すいそくこうほう）とは航行した経路や進んだ距離、起点、偏流などから、過去や現在の位置を推定し[1]、その位置情報をもとにして行う航法のこと。

らしいです。

https://ja.wikipedia.org/wiki/%E6%8E%A8%E6%B8%AC%E8%88%AA%E6%B3%95

# 参照元(元の情報)
このモジュール(GT-505GGBL5-DR-N)のデータではありませんが、使用しているチップ(AG3335A)が同じモジュールのでデータが有りました。
そこのデータシートから火っぱてきた情報になります。

https://www.locosystech.com/en/product/dr-module-rtk-1612ad-dr.html

サイトの下部にダウンロードリンクがあります。 参照しているのは17~18ページです

# モジュールのDRについて
GT-505GGBL5-DR-Nにはデッドレコニング機能があります。
今回はその機能について調べてみました。
# 有効化する
初期段階で有効になっているかもしれませんが、以下のコマンドをモジュールに送信しましょう
```
$PAIR060,500*25\r\n
```
GPSからの信号が途絶えたとき、推測航法を500回出力します。
という意味です。(1Hzで出力している場合 500秒=約8分間 推測による位置の出力を続けます)
# 校正
**私は試していないので以下の情報はネットによる情報ですが、校正ができることはわかっています**

校正が完了すると、10hzで出力を始めます

:::note info
車に搭載して以下を行う必要があります

:::
## IMUの初期化 ~ステップ1~
**信号がいい環境**で**180秒(3分間)静止**させる
このとき、出力するデータは以下になります。
```
$PAIRMSG,90,hhmmss.sss,1*CS
```
**1**になっていたらステップ1が終わりです。

## IMUキャリブレーション ~ステップ2~
**直線道路**(500m 屋外)を**10km/h~50km/h**の範囲で走行する。
少なくとも、**5分間加減速を5回以上**繰り返す。

このときは以下のデータが出力されています。
```
 $PAIRMSG,90,hhmmss.sss,2*CS
```
**2**になっていたらステップ2が終了です。
### INSの初期化 ~ステップ3~
空が開いた環境を10km/h~50km/hの範囲で移動する。
直角の左折、右折を2回以上行う。
ここまで完了すると以下のメッセージが出力されているはずです。
```
$PAIRMSG,90,hhmmss.sss,3*CS
```
**3**になっていれば成功です!


**以上で推測航法の準備ができました。**

これからも情報を探っていきます!!
バイナリで見る tar の中身と権限のしくみ

# これは何？

実際にバイナリがどうなっているのか色々と見ていくものです。
今回はTarコマンドなどを利用して遊んでいきます。

※ セキュリティや低レイヤについての学習を目的としています。悪用目的等では行わないでください。

tarとは複数のファイルを一つにまとめる形式の一種です。
tar化すると圧縮っぽく見えることもありますが、今回の場合はファイルを圧縮する内容よりもtar化した際の方が大きくなります。

理由としてはファイル圧縮時に必要な情報も生成しているからです。

何が違うのか、その差分を実際に見ていきましょう

まず最初にファイルを作り上げていきましょう。

```bash
% echo "hello world" > hello.txt
% tar cf hello.tar hello.txt    
% ls
hello.tar       hello.txt 
```

この二つがあるとします

実際にその二つのファイルのバイナリを見ていきましょう

```bash
% hexdump -C hello.txt
00000000  68 65 6c 6c 6f 20 77 6f  72 6c 64 0a              |hello world.|
0000000c
```
合計でファイルサイズは 12バイトとなります

```bash
% hexdump -C hello.tar | tail -n 1
 hexdump -C hello.tar | tail -n 1
00001000
```
となっており計算すると4096バイトとなります。

明らかにサイズが増えてますよね。

それは必要なメタ情報なども含めてまとめているからです。

実際に中身をバイナリとしてみるとその差を感じます。
(長いので抜粋)

```bash
% hexdump -C hello.tar | head -n 2
00000000  2e 5f 68 65 6c 6c 6f 2e  74 78 74 00 00 00 00 00  |._hello.txt.....|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

```

このような形で色々と書かれています。


## バイナリを見ながら色々

hello.txtについての実行権限も確認しておきましょう
```bash
% stat -f "%A %Sp %N" hello.txt
644 -rw-r--r-- hello.txt
```

このように
所有者は書き込み権限、読み取り権限
グループの権限は、読み取り
その他、読み取り
となっており、実行権限は誰にもついていない現状です。

これを一回バイナリで見てみましょう。
これは
```bash

% hexdump -C hello.tar | grep 00000060

00000060  00 00 00 00 30 30 30 36  34 34 20 00 30 30 30 37  |....000644 .0007|
```

  
ここには、tarファイルのmode（権限）が記録されています。

  

tar形式では、**100バイト目（0x64）からの8バイトがmodeフィールド**です。

この場合：

  - 100バイト目から `30 30 30 36 34 34 20 00` があり

  - これは ASCII で `"000644"` を意味します

  
つまりこのtarアーカイブのファイルは、権限 `644`（rw-r--r--）が設定されていることが分かります。

次に権限を変更してみたらバイナリがどのように変更されるのかやってみましょう。

```bash
% chmod 755 hello.txt
```
としてみて

```bash
% stat -f "%A %Sp %N" hello.txt
755 -rwxr-xr-x hello.txt
```
これは

- 7 -rwxr 自分は全権限
- 5 - xr グループは実行と読み取り権限
- 5 -x 他は実行権限のみ

と変更しました。

さて先ほどのバイナリはどのように変化するでしょうか

```bash
% hexdump -C hello.tar | grep 00000060 
00000060  00 00 00 00 30 30 30 36  34 34 20 00 30 30 30 37  |....000644 .0007|
```

あれ？何も変わってない！？
まぁそうですよね...
だって、変更前のものをアーカイブしているものですから。

てなわけでもう一回、tarファイルを生成します。

```bash
% hexdump -C hello.tar | grep 00000060
00000060  00 00 00 00 30 30 30 37  35 35 20 00 30 30 30 37  |....000755 .0007|
```

このようにしてバイナリが変更されていることがわかります。

少し補足しておくと、直接バイナリを変更することもできるのですがその場合はチェックサムの数値が合わなくなりエラーを吐きます。
ので、チェックサムを再計算してバイナリ側の辻褄を合わせる必要があります。
(今回はここまでしません)

### 最後に

ここまで見てくださってありがとうございました。
なかなか低レイヤまで見ることもないのでいい機会にもなりました。
何度も言いますが、悪用は厳禁です。
docker上のPostgreSQLでベクトルデータを利用する環境を構築する

# はじめに
生成AIの応答精度を高めるRAGを利用するためにベクトルデータベースを利用する必要がある。
ベクトルデータベースとしては、Qdrantのように特化して設計されたものもあるが、今回はタイトル通りDocker上のPostgreSQLを使って環境構築を行う。
[過去に書いているpg_ivmの記事](https://qiita.com/naozo-se/items/9b7b56e3dc9653a1e27f)と考え方は同じ。

# 確認環境
- WSL2(Ubuntu22.04.3 LTS)
- PostgreSQL 17.4-1
- Docker (27.5.1)
- Docker Compose(v2.32.4)
- vector (0.8.0)

# フォルダ構成
```
[projectfolder]
 ├─ compose.yml
 ├─ Dockerfile
 └─ docker-entrypoint-initdb.d
    └─ 90_vector.sql (extentionを登録するSQL)
```

# ソース
```yaml:compose.yml
services:
  db:
    image: postgres-vector-plugin:1.0
    build:
      context: .
    restart: always
    volumes:
      - postgresql:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    tty: true

volumes:
  postgresql:
```

```Dockerfile:Dockerfile
# postgresのバージョン17最新
from postgres:17.4-bookworm

# パッケージ更新＆パッケージのビルドで必要なもの
RUN apt-get update && apt-get install -y \
    git \ 
    make \ 
    gcc \
    postgresql-server-dev-17

# ------ pgvector導入
RUN git clone https://github.com/pgvector/pgvector.git /usr/src/pgvector \
    && cd /usr/src/pgvector \
    && make \
    && make install \
    && cd / 

# EXTENTION登録SQLをコピー
COPY ./docker-entrypoint-initdb.d/90_vector.sql /docker-entrypoint-initdb.d

# 使わないので削除
RUN apt-get purge -y \
    git \ 
    make \ 
    gcc \
    postgresql-server-dev-17
# ファイルも使わないので一応削除
RUN rm -rf /usr/src/pgvector 
```

```sql:docker-entrypoint-initdb.d / 90_vector.sql
CREATE EXTENSION IF NOT EXISTS vector;
```

# 起動コマンド
```shell
docker compose up -d
```

# ざっくり解説
- composeファイルのimage名は何でもよいが、初期化するとき等に便利
- 
- Dockerfileでビルドして、拡張機能登録用のSQLファイルを/docker-entrypoint-initdb.d にコピーしてコンテナ作成時に実行している（バインドマウントでフォルダ共有しても良い）



# Extensionが導入されているかの確認
```sql
postgres=# SELECT * FROM pg_extension;
  oid  | extname | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition
-------+---------+----------+--------------+----------------+------------+-----------+--------------
 13569 | plpgsql |       10 |           11 | f              | 1.0        |           |
 16384 | vector  |       10 |         2200 | t              | 0.8.0      |           |
 ```

# おまけ
Dockerfileで、postgresのイメージを利用して、必要なパッケージを利用して…という方法で展開しているが、イメージに [`pgvector`](https://hub.docker.com/r/pgvector/pgvector)を利用(`from pgvector/pgvector:latest`)して、構築することも可能らしい（動作は未確認）

# 終わりに
この環境に対して、LlamaIndexを利用したpythonコードを展開する予定です。
KubernetesのPodにshellがない時のデバッグ方法

# はじめに
`kubectl exec -it`でコンテナに入ろうとすると、時々`/bin/bash`や`/bin/sh`がない時があって困ったので、その場合の対処方法。[kubernetesのマニュアル](https://kubernetes.io/ja/docs/tasks/debug/debug-application/debug-running-pod/#ephemeral-container-example)に全部書いてあった。

# 流れ
対象のPodでcontainerを立ち上げ、そのcontainerをPodにアタッチする模様。
デバッグしたいPodが`ephemeral-demo`で、そのPodに`/bin/bash`がインストールされていない場合の例として、kubernetesマニュアルでは`busybox:1.28`のコンテナを接続する例を記載していたが、自分の使いたいコンテナならなんでも良さそう。

**ephemeral-demoのPodにbusyboxのコンテナをアタッチする例**
```shell
kubectl debug -it ephemeral-demo --image=busybox:1.28 --target=ephemeral-demo
```
うまくいけば対象のPodにログインできる。
```
Defaulting debug container name to debugger-r58ht.
If you don't see a command prompt, try pressing enter.
root@ephemeral-demo:/# 
```

ただし、デバッグ用のコンテナは`get pod`しても見えない
```
$ kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
ephemeral-demo   1/1     Running   0          44m

#Readyなコンテナが一つだけ、busyboxのコンテナは何処に・・・
```

# まとめ
知らなかったのは私だけ？
【React初心者メモ】grid 行や列の自動配置

gridでは、grid-cols-*とgrid-rows-*で列数と行数を指定する。
単体で指定した場合の行数と列数の自動調整が少しややこしいので、まとめておきます。

### gridのみを指定した場合・・・
1列 × 自動行（要素が増えると自動的に行が追加される）
### grid-cols-*のみを指定した場合・・・
*列の数 × 自動行（要素が増えると自動的に行が追加される）
### grid-rows-*のみを指定した場合・・・
1列 × *行の数
Linucレベル１勉強メモ　＃２１

＃ 第二章　ファイル・ディレクトリの操作と管理

練習問題2.6
カレントディレクトリにあるファイルlinuxtestのシンボリックリンクlinuctest.linkを作成するコマンドを選択してください。

A. ln linuctest linuctest.lnk

B. ln linuctest.lnk linuctest

C. ln -s linuctest linuctest.lnk

D. ln -s linuctest.lnk linuctest

（解答）C

（解説）
lnコマンドは、オプションなしの場合はハードリンクを作成し、-sオプションを付けるとシンボリックリンク作成します。したがって、-sオプションのない選択肢AとBは不正解です。lnコマンドは、リンク元（実体）、リンク先（リンクファイル）の順に指定します。

ハードリンク
linuxでは、ファイルをディスクに保存すると、重複しないiノード番号が割り当てられます。すべてのファイルには対応するiノードが存在し、iノードにはディスク上のファイルに関する属性情報が格納されています。ディレクトリは特殊なファイルの形態であり、所属するファイル名と所属するファイル名とiノードを関連づけています。ファイルの実体（ディスク上に保存されているデータ）が１つでも、その実体を参照するファイルが複数あれば、それぞれのファイル名で同一の実体を参照することができます。これがハードリンクです。
ハードリンクでは、元のファイルと、リンクとして作成したファイルの区別がつけられません。どちらもiノード番号が同じだからです。ファイルをコピーした場合は、いずれかを変更しても他方に影響はありませんが、ハードリンクの場合は、いずれのハードリンクファイルに変更を加えても、同一の実体に対して変更を加えることになります。

ハードリンクが複数作成されている場合、そのすべてを作成するまでは、ファイルの実態は削除されません。リンクが作成されている数は、lsコマンドで確認することができます。

特徴としては、ハードリンクは元のファイルが存在しているファイルシステムと異なるファイルシステム上に作成することはできません。他には、ディレクトリにハードリンクを作成することはできません。

シンボリックリンク
シンボリックリンクはリンク元の場所をさし示します。シンボリックリンク自身が持っているのは、リンク元へのポインタです。そのためシンボリックリンクを残したまま、リンク元のファイルを蚊駆除することも可能です。この場合、シンボリックリンクにアクセスすると、実体ファイルが見つけられずエラーになります。ハードリンクと違うことは、別のファイルシステムにもリンクを作成することができるのと、ディレクトリのリンクも作成することができます。
ungoogled-chromiumの無効化URLの確認

# 走り書き

使う機会が多そうなのに無くしそうなのでメモ残しときます。

[ungoogled-chromium](https://github.com/ungoogled-software/ungoogled-chromium/)を使っていると、末尾がドメイン名 ".qjz9zk" のページに飛ばされることが、まぁまぁある。

正規のchromeやchromiumへ参照しないように、アクセスを抑止するために一括置換されているのは認識済みだったのだけど、具体的に実サイトへの対応が分からないと不便（developer toolsのリリースノートとか）なこともあって、識別する方法ないのかなと調べたら、すぐに以下が見つかった。

https://github.com/ungoogled-software/ungoogled-chromium/blob/master/domain_regex.list

テキストファイルでの正規表現定義でまとめられているんですね。

facebookやyoutubeのエントリもあるのは意外でした。

簡単ですが以上です🙇
NotionのDBをObsidianに1レコード1ファイルで移行する

### はじめに

NotionのWeb Clipperで記事を収集して、DBとして管理していたのですが、Obsidianで一元管理したくなったため、移行を試みました。目的は、NotionのDBに登録されていた**1レコード1記事を、Obsidianで個別ファイルとして管理できるようにすること**です。

### 最初に試した方法：Importerプラグイン

Obsidianの「Importer」プラグインを試してみました。NotionからHTML形式でエクスポートしたデータを取り込めるのですが、**DBのビューがそのままHTMLとして再現されるだけ**で、各レコードが独立したMarkdownファイルにはなりませんでした。

そのため、ObsidianのZettelkasten的な使い方をしたい自分には合いませんでした。

### やりたかったこと：1レコード＝1ファイル

やりたかったのは、Notionで1レコードとして格納されていた各記事を、**MarkdownファイルとしてObsidianのVault内に個別保存すること**です。各記事を参照したりタグをつけたかったので、1ファイルずつ存在していてほしかったのです。

### 実際の移行方法

結論としては、Notionから「Markdown & CSV」でエクスポートして、`mv`コマンドでObsidianのディレクトリに配置する、という原始的ですがシンプルな方法でうまくいきました。

以下は手順です：

1. Notionで対象のDBを開く
    
2. 「…」メニューから「Export」→「Markdown & CSV」でエクスポート
    
3. 解凍すると、各記事がMarkdownファイルとして保存されている（`PageName.md`など）
    

ObsidianのVaultパスがわからないときは、以下で探せます：

```sh
find ~ -type d -name ".obsidian" 2>/dev/null

```

Vaultの中に `notion_imports` などのフォルダを作って移動します：

```sh
mv ~/Downloads/NotionExport/*.md ~/Library/Mobile\ Documents/.../Obsidian/YourVault/notion_imports/
```

これで、**Obsidian上で各レコードが個別ファイルとして扱えるようになります**。

### おわりに

Importerプラグインでは思ったように移行できませんでしたが、Notionのエクスポート機能とUnixコマンドを組み合わせるだけで、シンプルかつ柔軟に移行できました。
【個人学習】とりあえず動けばOK！3日坊主が3日だけ手を動かすことにチャレンジする記録

## はじめに
### 記事の趣旨
待ちに待ったGW！
（祝日問わず情報基盤を支えているエンジニアの方々、ありがとうございます。）

しかし、私はあまり人混みが得意ではないので
せっかくの機会に何か作ってみようということで、記事を書き進めています。

### アウトプットを重視したかった動機
恥ずかしながら動機は以下の著書に感化され、
「自分もまずは手を動かしてみよう！」と思い立ったためです。

https://www.amazon.co.jp/%EF%BC%83100%E6%97%A5%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8-%E6%AF%8E%E6%97%A5%E9%80%A3%E7%B6%9A100%E6%9C%AC%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%89%E4%BA%BA%E7%94%9F%E3%81%8C%E5%A4%89%E3%82%8F%E3%81%A3%E3%81%9F-%E5%A4%A7%E5%A1%9A%E3%81%82%E3%81%BF/dp/4296071068


私は、「とりあえず手を動かすって何をすれば良いんだ...」「完璧に理解してからアウトプットしよう」と考えがちで、いつまでも手が付けられない状況に陥ることが多々あります。

そして完璧に理解する前に挫折をすることもしばしば。
資料作成も「8割で見せればいいのに」っていつも自分に言い聞かせてます（笑）

そこで、まとまった時間を確保出来たこの機会を利用して何か作ってみよう。
「やってみれば知識や学びも後から得られるっしょ」くらいの感覚でスタートしています。

特に学習し始めの方は共感できる部分が多少あるのではないでしょうか。
同じ悩みを抱える方に、この取り組みが少しでも参考になれば幸いです。

## 目標
- とりあえず手を動かしてみる
- あまり触ったことのないAWSサービスを使ってみる
- 「EC2 AZ別サポート & 価格比較ダッシュボード」を作ってみる
- 振り返りとアウトプットを行う

## 概要
各内容については、それぞれの記事をご覧ください。

- Day １：
    - CI/CDパイプラインを作ってみる
        - Git , GitHub
        - CloudFormaition
        - AWS CDK

https://qiita.com/n0mura/items/cddd7335ff43d97849a0


- Day ２：
    - 「EC2 AZ別サポート & 価格比較ダッシュボード」を作ってみる
        - Lambda
        - S3
        - QuickSight

https://qiita.com/n0mura/items/1fff467079e521b33fdd


- Day ３：記事まとめ（振り返り）
    - Day 1,Day 2 で実施した内容を記事にまとめる
    - 総括は本記事にて
:::note
本来はCI/CDのパイプラインを構築したのち、それを利用して「EC2 可用性 & 価格ダッシュボードツール」のデプロイまでをイメージしていました。

しかしながら、イメージした構成と最終構成が作成の過程で変わり、色々と試行錯誤する中で作成を行ったため、Day 1とDay２の内容に繋がりはありません。
:::

## 総括（個人の感想）
### 今回で得た知識・スキル（完璧とは言ってない）
- ローカル開発環境の整備
    - NVM管理下でのNode.js npm 、Python 仮想環境による依存分離
    - GitとGitHub CLIの活用
- AWS CDKを使ったプロジェクト構築
    - `cdk init`によるディレクトリ構成の自動作成
    - CDKブートストラップスタック（CDKTookit）の理解
- QuickSightでのダッシュボード作成
    - S3を利用したデータセットの登録からピボットテーブルでの分析
- ドキュメント化・アウトプット
    - Mermaid 図によるアーキテクチャ可視化
    - アウトプット時の情報整理

### とりあえず実践してみて良かった点
**自己肯定感が上がる（モチベーションの維持）**
頭の中だけで構想を練っている段階では、完成したイメージが曖昧で「本当にできるのだろうか」という不安もありました。実際に私自身最初のイメージからハードルを下げて実践した部分もあります。
しかし、粗削りでも「できた！」という感覚はモチベーションの維持に繋がりました。

**自身の理解度確認**
実際に手を動かすことで、理解が曖昧な部分や理論と実践でのギャップを把握することが出来ました。
今回はあまり座学を行っていない部分もあったり、とりあえず「これ設定してみるか」くらいで進めていた部分があるので、なぜその操作・設定が必要だったのかを後からでも学ぶことで体験と知識が紐づき、理解を深めることが出来ました。

### 気を付けようと思ったポイント
これは学習目的であることが前提での意見です。

私もやりがちですが「出来た！」で終わってしまわないように気を付けようと感じました。
一部、ドキュメントやAIを活用して、書いてある通りに実施した部分もあります。
これ自体は悪いことだと思いません。
※むしろ「出来た！」だけでも凄いことですし、その体験は忘れないようにしたい。

しかし、「書いてある通りに実施して出来たからOK」で終わってしまうと、学習にはならないと感じました。
ただこの点においては人それぞれ手を動かしてみる目的が異なるため、あくまで私の今回の取り組みに対する自身への言葉です。

## おわりに
もし今回の記事をご覧の方の中には新入社員でこれから勉強する！絶賛勉強中！って方もいらっしゃるかと思います。

手を動かすって、私も最初は何をしたら良いか分かりませんでした。
AWS コンソールの画面でサービスを確認するだけでも、手を動かすことの一歩だと思います。
AWSでは沢山のハンズオン教材もありますので、もし座学に行き詰まったらハンズオン動画を見ながら手を動かしてみるというアプローチも取り入れてみると良いのかなと思います(^▽^)/

https://aws.amazon.com/jp/events/aws-event-resource/hands-on/
AWS完全初心者がAmazon Pollyで遊んでみた話 Part1

## はじめに
こんにちは。Tsukasaです！
今日はAWS完全初心者の自分がAmazon Pollyを使用して遊んでみた話を記事にしていきたいと思います。
Pollyに文章を直接入力して、音声化することもできますし、S3バケットに文章ファイルをアップデートして、Lamabda関数を用いて、音声化することもできます。
私は今回両方試したので、今回と次回の2回に分けて、その時の内容について書いていこうと思います。
それでは早速見ていきたいと思います！

## そもそもAmazon Pollyとは？
Amazon Pollyとは一言で言うと文章を音声化するAWSのサービスになります。
最近話題の生成AIの1つでもあり、初心者でもアウトプットがわかりやすいものとなっており
ハンズオン学習としてもやりやすいものだと思います。
以下にAWS公式のページがありますので、気になる方は是非ご覧ください！

https://aws.amazon.com/jp/polly/

## 早速やってみた
手順としては非常にシンプルです。
まずはコンソールでPollyと検索します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2478024/36d85405-67a2-46a6-9326-78b394c630f3.png)

その後左上のハンバーガーボタンをクリックすると、一番上に「テキスト読み上げ機能」と言うボタンがあるので、こちらをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2478024/dfe40621-df0a-41cf-ad73-2ca5644986af.png)

そうすると、下にテキストを入力できるようになるので、音声化した文章を入力します。
ニューラルかスタンダードを選択できます。
ニューラルの方が、より自然な人間に近い音声になります。
その他にも言語や音声を男性か女性かも選択することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2478024/e9eadb0e-a287-4b2d-a412-b37411211b1f.png)

こちらが実際の音声ファイルになりますので
聞ける環境の方は是非聞いてみてください。

https://drive.google.com/file/d/1r4gjYTsf1dIoWUbcEdpKF8Ic9uPX5UG3/view?usp=sharing


他にも色んな国の言語があるので気になってやってみました。まずは英語です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2478024/9ac83b9b-85ba-4fc2-bc36-89752e638b4b.png)

https://drive.google.com/file/d/1XdRUFUojdOiA4GxtUg27mXfHYf_Z05BH/view?usp=sharing

キャプチャを撮り忘れたのですが、やはり英語は音声の種類が沢山ありました。

後は韓国語もやってみました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2478024/1f65ffe6-6486-4027-822c-091e78517936.png)

https://drive.google.com/file/d/1R7rEz1Kfjb1zcqulDnbGbcdUh-wEqTXd/view?usp=sharing

## 終わりに
いかがでしたでしょうか？
AWS初心者でも簡単にPollyを使って文章を音声化することができました。
こういうアウトプットがわかりやすいものは手を動かしていても楽しいので、是非やってみてください！
Web技術の基本的な仕組み

Web技術の基本的な仕組みの中で下記の用語を学んだので、わかりやすくまとめてみました。
- ステートレスな通信
- ステートフルな通信
- リクエスト
- レスポンス
- プロトコル
- クッキー
- ポート番号


# ステートレスな通信

ステートレスな通信とは、前のやりとりを覚えていない通信。
サーバーはユーザーの情報を保持しない。

例えば、AさんがAmazonにアクセスしログインするとする。

しかし、次のページに進むとまたログインを求められてしまう。
その後、ページを切り替えるごとにログインを求められる。

これはサーバーが「この人が誰か」を覚えていないの原因。

このような通信をスタートレスな通信という。

# ステートフルな通信

ステートフルな通信とは
通信とクライアントをセットで管理して識別できる通信のこと。

例えば、上記のステートレスの通信の例で考えると‥

AさんがパソコンからAmazonにアクセスしログインするとする。

すると、サーバーが「この人ログイン済み」だと記録する。

その後、どのページに移動しても再度ログインをする必要はなくなる。

なぜなら、サーバーがあなたの「ログイン情報」を覚えて、状態を保持しているから。

これをスタートフルな通信という。

# リクエスト
ブラウザからサーバへ命令を送ること。

例えば、ブラウザで「韓国　ファッション」と検索する。

すると、ブラウザからWebサーバへ「韓国のファッション情報をくれ」という命令が送られる。

この命令のことをリクエストという。

# レスポンス
ブラウザから来た命令に対して情報を返すこと。

例えば、ブラウザで「韓国　ファッション」と検索する。


すると、ブラウザからWebサーバへ「韓国のファッション情報をくれ」という命令が送られる。

Webサーバは、
命令を受け取るとデータベースサーバから「韓国のファッション情報」を取得する。

その情報をブラウザに返す。この``情報をブラウザに返すこと``をレスポンスという。

# クッキー

クッキーは、HTTPがステートレスな通信であるため、それをステートフルな通信のように扱うための解決策。

### 【クッキーが生まれた背景】

HTTPはスタートレスな通信方式なので、サーバーはクライアントごとの情報（誰が誰か）を記憶できない。

例えば、一度AさんがAmazonにログインしても、次のページアクセスで「この人がAさんだ」と識別する手段がない。

もしこのままだと、ログインしたユーザーが誰かを特定できず、セキュリティ的にも問題が生じる。

そこで、HTTPに「ユーザー識別の手段」を持たせるために、クッキーという仕組みが生まれた。

### 【クッキーがクライアントを識別する仕組み】

クライアントがサーバーにリクエストを送ると、サーバーはレスポンスの中に「クッキー」という小さなデータ（識別子）を含めて返す。

このクッキーはクライアント（ブラウザ）に保存され、以降の通信では自動的にサーバーへ送信されるようになる。

クッキーには一意の識別番号が含まれており、サーバーはそれをもとに
「この人はAさんだ」「この人はBさんだ」と見分けることができる。

これにより、HTTPというスタートレスな仕組みをスタートフルのように振る舞わせることができるようになる。

# プロトコル
プロトコルとは
コンピュータ同士が通信をする際のルールや基本形式のようなもの。

これがあることで、ソフトウェアやハードウェアが大きく異なっていてもネットワークで接続することができる。

逆に、別のプロトコルであると通信ができない。

例えると、翻訳機のようなもの。

日本とアメリカでは日本語と英語で言語が違うので、
基本的に意思疎通はできない。


しかし、翻訳機があることでお互いの言語を翻訳し意思疎通が取れるようになる。

プロトコルはこの翻訳機のような役割を担っている。


具体的に世界では、どういうプロトコルが使われているかというと、``TCP/IP``というプロトコルが使われている。


TCP/IPは大きく分けると４つの階層がある。
- 第４層：アプリケーション層
- 第３層：トランスポート層
- 第２層：インターネット層
- 第１層：ネットワークインターフェイス層

馴染みがあるのは、アプリケーション層なので
それを元に説明をする。

**アプリケーション層**には下記のような主要プロトコルがある。
<dl>
 <dt>HTTPS</dt>
 <dd>Webページの閲覧する際のプロトコル</dd>
 <dt>FTP</dt>
 <dd>ファイルの転送する際のプロトコル</dd>
 <dt>SMTP</dt>
 <dd>メールの送信する際のプロトコル</dd>
 <dt>POP</dt>
 <dd>メールの受信する際のプロトコル</dd>
 <dt>DNS</dt>
 <dd>IPアドレスとドメインを紐づける名前解決する際のプロトコル</dd>
 <dt>SSH</dt>
 <dd>遠隔操作する際のプロトコル</dd>
</dl>

というように、私たちが普段何かしらのサービスを利用する際にはサービスに該当するプロトコルが使われているのである。

# ポート番号
ポート番号は
情報がコンピュータに入ってくる際の入口のようなもの。

コンピュータ内には、情報が入るための入り口がたくさんあり、情報はその決められた入口を通って入ってくる。

IPアドレスがコンピュータを特定する番号であるのに対して、
ポート番号はコンピュータ内のプログラムを特定する番号である。

例えば、HTTPSは443番。FTPは20番。SMTPは25番。POPは110番。SSHは22番。

というように振り分けられている。
miiboからZapier MCP経由でGmailを取得する

miiboでLINE Bot作成を試してますが、ZapierのMCPを経由することでAPIなどの設定をせずに連携先のサービスを呼び出すことが可能です。

完成イメージ

https://x.com/n0bisuke/status/1918627652090659072

## 連携手順

### 1. ZapierのMCP作成画面へ

https://mcp.zapier.com/mcp/servers 

Zapier

> ![CleanShot 2025-05-05 at 16.29.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/e1d10797-5061-4d26-960d-d704243e1d0b.png)

`Add tool`から連携したいサービスを追加します。取り急ぎここではGmail連携をしました。

> ![CleanShot 2025-05-05 at 16.46.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/62c53281-0e61-4860-aaa8-4e02108dee45.png)

`Connect`のタブでServr URLが確認できるので`/sse`で終わるURLをコピーします。

> ![CleanShot 2025-05-05 at 16.47.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/52c7f2b9-8eca-40b0-a997-63a0694a70ba.png)

Zapier側は一旦OKです。

### 2. miiboのWebhook設定

miiboのWebhook設定にて、連携タイプで`MCP SSE`を選択し、名前をつけて先ほどの`/sse`で終わるURLを貼り付けます。

> ![CleanShot 2025-05-05 at 16.49.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/4ced85bd-c112-4220-afa6-475c2efcf31a.png)

Function NameはFunction Callingで呼び出されやすいように`get_gmail_from_zapier`などGmail呼び出しっぽい名前を書いておきました。

以上！

### 3. 試す

`Gmailから2025/5/3のスターバックスの注文を調べて`などLINE Botに送ると自身の連携したGmailの受信フォルダからメールを探して回答してくれます。

### デバッグ

`Gmailから今日のスターバックスの注文を調べて`と書いたら最初上手くいきませんでした。

> ![CleanShot 2025-05-05 at 16.42.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/33c4c33a-b1c1-4e6e-bae4-99f2470e95d1.png)

Historyのタブから確認できますが、

> ![CleanShot 2025-05-05 at 16.43.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/9eedee2f-c36e-43aa-967a-8425ab52de96.png)

なぜか`after: 2023-10-30`で調べようとしてました。 **今日がいつか認識できなかった** けどなんとか探そうとしてくれてる感じ。

> ![CleanShot 2025-05-05 at 16.44.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/6376e965-3294-4397-ab34-a54c2db96e6a.png)

今日を日付指定にしたらあっさり取得できました。便利。
ログも確認しやすくて良いですね。

> ![CleanShot 2025-05-05 at 16.45.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/def8d926-d235-4a95-af24-20e2ae8284eb.png)

> ![CleanShot 2025-05-05 at 16.45.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/75f32657-091d-49f5-a404-002becdd5590.png)


## 補足 - ClaudeやCursor、Windsurfも

選べるみたいですね。

> ![CleanShot 2025-05-05 at 16.30.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/be3bc3c2-bd9a-41ce-a108-82e9a2932e09.png)

ClaudeはWeb版もMCP対応の話題があるのでさらに熱いですね。

https://dev.classmethod.jp/articles/shuntaka-claude-web-model-context-protocol-mcp/
SELECT文の日付フォーマットを変更したい

SELECT文の日付フォーマットを変更したい場合、NLS_DATE_FORMATを利用します。

このパラメータの変更方法はいくつかあります。まずは`ALTER SESSION`で利用する方法があります。

```
$ sqlplus devuser/Passw0rd@oracle-db-host:1521/XEPDB1

SQL*Plus: Release 21.0.0.0.0 - Production on Sun Jun 30 16:06:51 2024
Version 21.14.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Sun Jun 30 2024 15:57:48 +00:00

Connected to:
Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY/MM/DD HH24:MI:SS';

Session altered.

SQL> SELECT SYSDATE FROM DUAL;

SYSDATE
-------------------
2024/06/30 16:08:17
```

環境変数で設定することも可能です。

```
$ env NLS_LANG=Japanese_Japan.AL32UTF8 NLS_DATE_FORMAT='YYYY/MM/DD HH24:MI:SS' sqlplus devuser/Passw0rd@oracle-db-host:1521/XEPDB1

SQL*Plus: Release 21.0.0.0.0 - Production on 日 6月 30 16:14:41 2024
Version 21.14.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

最終正常ログイン時間: 日 6月  30 2024 16:14:18 +00:00


Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
Version 21.3.0.0.0
に接続されました。
SQL> SELECT SYSDATE FROM DUAL;

SYSDATE
-------------------
2024/06/30 16:14:50
```


**参考**

https://docs.oracle.com/cd/F19136_01/refrn/NLS_DATE_FORMAT.html#GUID-FC23EEEE-AA9F-4B3C-8CBB-888C9C0CA27F

**環境情報**

- Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
- SQL*Plus 21.14.0.0.0
【プラクティス紹介】1分でさらっと分かる「複数チームでのスプリント計画」

## プラクティス名（別名）
複数チームでのスプリント計画　（スプリントプランニング1&2）

## プラクティスの目的・狙い
* 複数チームで協働してスプリント計画を立てる
* チーム間で必要な共同作業を計画する

## どんな時に使うか
* 複数チームでスクラム（LeSS）を行う際、どのチームがどのPBIに取り組むかを決める

※各チームのスプリント期間＆開始日が同一であることが前提
※PBLは全チーム共通で１つという前提

## 実施手順
スプリントプランニングを以下の2部構成にする

| イベント | 参加者 |　実施内容　|
|:-:|:--|:--|
|第１部 |POと全チームが一緒に行う |どのPBIにどのチームが取り組むかを決める |
|第２部 |各チームごと個別に行う　|自分たちのPBIを Done にするためのSprint計画を立てる |

【第１部】
1. POから全チームにReadyとなったPBIを提示する（不明点はその場で質疑応答）
1. 全チームで話し合って、どのチームがどのPBIに取り組むかを決める。その際、チーム間で協働した方がよい箇所を特定する。
1. スプリントゴールを決める

【第２部】
1. 各チームは担当PBIをDoneにするための計画を立てる（＝SBLに落とし込む）
1. その際、密接に関連するチームは、同じ場所でプラニングを行う（＝相互理解を深め、必要なら一緒に取り組む）

:::note info
第２部の計画は通常のスクラムとほぼ同じものですが、例えば他チームと同じコンポーネントを変更する場合や双方のPBIが関連する場合などは、一緒に計画を立て、積極的にコラボレーションするようにします
:::

## アレンジ例
* 全チームが集まれる広い部屋を用意し、第１部は部屋の中央で、第２部は部屋の四隅に分かれて行う（＝いつでも他チームと会話できる状況を作る）

## アンチパターン
* どのPBIをどのチームが取り組むかをPOが直接指示する。

:::note warn
PBI分配をPOが直接行うと、各チームは割り当てられたPBIにしか興味を持たなくなります。それを避けるため、POはPBIの優先順位を示すに留め、どのチームが受け持つかは各チームの選択に任せることが推奨されています。
:::

## 参考情報

LeSS公式WEBサイト

https://less.works/jp/less/framework/sprint-planning-one

なお以前のLeSSルールでは、プランニング１の参加者はPOと全チーム**またはチームの代表**、となっていたそうですが、参加者を「チームの代表」に絞ることで弊害もあったということで、その文言は削除されたようです。変更のいきさつについては@tymsbowieさんの[記事](https://qiita.com/tymsbowie/items/fea622bdd3a92c1f8a52)に詳しく載っています。（共有、感謝です！）

## こぼれ話（私的コメント）
どのPBIを拾うかは各チームに選ばせる、という方式は、各チームがフィーチャーチームであること（＝どのチームでも、どのPBIを担当することが可能）が前提となっています。ただ実際の現場ではメンバーの得意領域や経験値の違いから、このPBIはあのチーム担当かな～、と半自動的に決まるケースも多いのではないかと思います。そのあたりのある種の"空気読み"が上手くできるかが機能するカギかな、と。逆に多少なりともそういった合理的な理由があった方がどれ拾うかで揉めなくてよいかものかもしれません。

---
　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
IPアドレスはなぜ32ビットなのかをなるべく暗記せず理解する

## インターネット以前
インターネット以前の時代、ネットワークは個々に存在していました。例えばARPANETは、UCLA、スタンフォード大学などの特定の研究機関を接続する実験的なネットワークでだった。これとは別に、IBM、Appleなどの各コンピューターメーカーも独自の通信規格を開発し、自社製品間でのみ通信可能なネットワークを構築していました。

これらのネットワークはそれぞれ独自の通信方式を持っており、異なるシステム間での通信は不可能でした。

この分断状態を解消するため、異なるネットワーク同士を接続する共通言語（プロトコル）の開発が進められました。その成果として誕生したのがTCP（Transmission Control Protocol）です。TCPは、異なるネットワーク間でも確実にデータをやり取りするための仕組みを提供しました。

## IPアドレスの32ビット構造の起源
当時のネットワークでは、各コンピューターを識別するために通常16〜24ビットのアドレス空間が使用されていました。異なるネットワークを統合するにあたり、各ネットワークを識別するための「ネットワーク部」と、そのネットワーク内の各コンピューターを識別する「ホスト部」の両方が必要になりました。

こうした要件から、ホスト識別用に24ビット、ネットワーク識別用に8ビットを割り当て、合計32ビットのアドレス体系が設計されました。この構造が、現在のIPv4アドレスの基礎となっています。

ARPANETには「10」というネットワーク番号が割り当てられ、これが現在のクラスAプライベートアドレス（10.0.0.0/8）の起源となりました。


> RFC 791っていうのが，今のIPプロトコルの元になっている仕様です。
ここで32ビット，A/B/CクラスというIPアドレスの考え方が記載されています。
しかし，IPプロトコルは何もないところから突然登場したわけではなく，
いくつかの改良を加えられながら発展してきたものでした。
その一つ前のバージョンであるRFC760では，
A/B/Cというクラスの考え方はなく，
ネットワーク番号が8ビット，ホスト番号が24ビットで固定されています。
クラスという考え方はありませんが，このときすでに32ビットだったんですね。
では，なぜ32ビットになったかというと，
その辺の理由はIEN 115を見るとわかります。
ARPANET，SATNET，PRNET，LCSNET，EDN，DCNs
といったインターネットを構成するネットワークがあり，
そこで使っていたアドレスをホスト番号にマッピングするためには24ビット必要だった，
そして，そこにネットワーク番号を8ビット付加すると32ビットになった，
ということのようです。
## 参考文献
http://tonetsutomu.com/tone/node/198
https://www.sri.com/ja/press/story/sri%E3%81%AE75%E5%B9%B4%E9%96%93%E3%81%AE%E3%82%A4%E3%83%8E%E3%83%99%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%EF%BC%9A%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D/
https://www.rfc-editor.org/rfc/rfc796.html
£を#にするJSON

MacBookのUKキーボードの `option + 3`　の　`#` を　`shift + 3` にする設定です。
karabiner-elementsのcomplex modificationに貼り付けます。

```json
{
    "description": "Remap Left Option + 3 to Left Shift + 3",
    "manipulators": [
        {
            "from": {
                "key_code": "3",
                "modifiers": { "mandatory": ["left_shift"] }
            },
            "to": [
                {
                    "key_code": "3",
                    "modifiers": ["left_option"]
                }
            ],
            "type": "basic"
        }
    ]
}
```
【JavaScript】JavaScriptのシャローコピーとディープコピーの違いについて

# はじめに
スプレッド構文を使ってオブジェクトをコピーした際に「シャローコピーとは何か」が分からず、挙動に戸惑ったため、調べた内容をまとめました。

:::note warn
***この記事は<font color="Red">個人的なアウトプット</font>を目的として作成したものです。そのため、誤った情報や不足している内容が含まれている可能性があります。もし間違いや気になる点がございましたら、ぜひご指摘いただけますと幸いです***。
:::

# シャローコピー
MDNでは以下のように説明されています。

> オブジェクトのシャローコピーとは、コピーがコピー元のオブジェクトとプロパティにおいて同じ参照を共有する（同じ基礎値を指す）コピーのことを指します。その結果、コピー元とコピー先のどちらかを変更すると、もう一方のオブジェクトも変更される可能性があります。そのため、意図せずにコピー元やコピー先に予期しない変更が発生してしまう可能性があります。この挙動は、ソースとコピーが完全に独立しているディープコピーの挙動とは対照的です。

https://developer.mozilla.org/ja/docs/Glossary/Shallow_copy

つまり、コピー元とコピー先は参照を共有しているため、ネストされたプロパティなどを変更すると、もう一方にも影響が出ます。

## シャローコピーで影響が出ないパターン（第1階層）

```js
const object = { name: "soccer" };
const newObject = { ...object }; // {name: "soccer"}
newObject.name = "baseball"; // {name: "baseball"}
```
この場合、コピーしたのは第1階層のみで、nameはプリミティブ値のため参照共有ではありません。したがって元のobjectには影響がありません。

## シャローコピーで影響が出るパターン（ネストあり）

```js
  const object = {
    name: "soccer",
    like: {
      team: "yokohama",
    },
  };
  const newObject = { ...object };

  newObject.name = "baseball"; // ← 第1階層（影響なし）
  newObject.like.team = "losangeles"; // ← 第2階層（元にも影響する）

  console.log(object); // { name: "soccer", like: { team: "losangeles" } }
  console.log(newObject); // { name: "baseball", like: { team: "losangeles" } }
```
このように、第2階層のlike.teamが共有されていたため、片方を変更するともう一方も変わってしまいます。

# ディープコピー
ディープコピーは、コピー元とコピー先が完全に独立した参照を持つコピーです。そのため、片方を変更してももう一方には影響しません。

MDNでは以下のように説明されています。
> オブジェクトの ディープコピー とは、コピー先のオブジェクトのプロパティがコピー元のオブジェクトのプロパティと同一の参照（同じ値を指す）で共有しないコピー方法のことです。結果として、コピー元かコピー先のどちらかを変更しても、もう一方オブジェクトにも変更を及ぼしていないことを保証できます。すなわち、コピー元かコピー先に意図せずに予期しない変更が加えられるこはありません。この振る舞いはシャローコピーとは対照的です。シャローコピーでは、コピー元かコピー先のどちらかを変更するともう一方のオブジェクトも変更される可能性があります。

## lodashを使ったディープコピー
ディープコピーの方法は複数ありますが、ここでは`lodash`というライブラリの`cloneDeep`を使用した例を紹介します。

```js
  const object = {
    name: "soccer",
    like: {
      team: "yokohama",
    },
  };
  
  const newObject = _.cloneDeep(object);
  newObject.name = "baseball";
  newObject.like.team = "losangeles";

  console.log(object); // { name: "soccer", like: { team: "yokohama" } }
  console.log(newObject); // { name: "baseball", like: { team: "losangeles" } }
```
このように、元のオブジェクトはまったく変更されていないことが確認できます。

# 終わりに
シャローコピーとディープコピーの違いを正しく理解することは、オブジェクトの操作で思わぬバグを防ぐ上で非常に重要だと感じました。2つの使い分けについてはまだしっかり理解できていないのでこれからこの2つについてさらに理解を深めていきたいです。
「アイテムが作成または変更されたとき」トリガーで変更前のレコード内容を取得する

## 概要
SharePointリストの「アイテムが作成または変更されたとき」トリガーは便利ですが、取得できるJSONデータは変更後のレコード内容のみです。この記事では、変更前のデータを取得する方法を解説します。

SharePointリストのアイテムはバージョン管理されており、各変更ごとにバージョン番号が付与されます

Power Automateの標準機能だけでは変更前データは取得できないため、SharePoint APIを活用する必要があります

### 実装手順
#### 1. 変更情報の取得
「アイテムやファイルの変更を取得する(プロパティのみ)」アクションを使用します。

![スクリーンショット 2025-04-28 235032.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713277/ae75cd9c-3319-44f2-a037-8b88e1257a79.png)

以降: 「アイテムが作成または変更されたとき」の「ウィンドウ開始のトークンのトリガー」を指定

実行結果からは以下の情報が取得可能:
・開始バージョン番号
・変更された列の情報

![スクリーンショット 2025-05-02 152544.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713277/516469ed-cd66-45db-917e-3b028ad98e3f.png)

#### 2. SharePoint APIを使用したバージョン情報取得
「SharePointにHTTP要求を送信します」アクションを使用して、直接APIを呼び出します。
取っつきにくいかもしれませんが、マスターすればAutomateの標準アクションではできないことでも手が届くようになります

![スクリーンショット 2025-05-05 153204.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713277/a05726a4-086c-4caa-ba24-2b90785b643a.png)

リクエスト設定：
```
//URI
_api/web/lists/getByTitle('リスト名')/items(レコードID)/versions(バージョンID)

//ヘッダー
{
  "accept": "application/json"
}
```

注意点：
バージョンIDは「アイテムやファイルの変更を取得する(プロパティのみ)」の動的コンテンツに出てこない場合があります。
出てこない場合は式から直接指定しましょう
![スクリーンショット 2025-05-05 152957.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713277/939633b5-ea89-4656-8744-f18473c69c9c.png)


### 実行結果
APIリクエストの結果、変更前のレコードデータを取得できます。
![スクリーンショット 2025-05-05 155101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3713277/e54c6ed0-e29e-4b1a-9dae-f690bcada324.png)
Metasploitable3 特権昇格

Metasploitable3にログインして、特権昇格を行います。
Metasploitable3のIPアドレス：192.168.56.123
## クレデンシャル情報の取得
[Metasploitable3 exploit Drupal](https://qiita.com/tsuko5963/items/5dd6439e07d3173055ab)を使用して、Metasploitable3にログインします。
/var/www/html/payroll_app.phpを確認すると、ユーザー名、パスワードでログインして、自分の給料が表示されるシステムとなっています。
攻撃端末で、payroll_app.phpをログインせずに、全ユーザーのパスワードを表示するように修正します。
修正したアプリを、[Metasploitable3 ファイルアップロードの脆弱性](https://qiita.com/tsuko5963/items/db7e7d617274e434d120)を使って、uploadsフォルダにアップロードします。
ブラウザから、```http://192.168.56.123/uploads/payroll_app.php```にアクセスします。
![スクリーンショット 2025-05-05 152738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3770088/4ead0f07-78bc-4788-a808-3e1cefff0f88.png)
## ログイン
表示されたユーザー名、パスワードで、sshでログインしてみます。
ユーザー名：leia_organa
パスワード：help_me_obiwan
```
$ssh leia_organa@192.168.56.123
leia_organa@192.168.56.123's password: 
Welcome to Ubuntu 14.04.6 LTS (GNU/Linux 3.13.0-170-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
New release '16.04.7 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

Last login: Mon May  5 03:28:39 2025 from 192.168.56.10
```
leia_organaの所属するグループを確認します。
```
leia_organa@metasploitable3-ub1404:~$ groups
users sudo
```
leia_organaは、sudoグループに所属しているので、sudoのリストを確認します。
```
leia_organa@metasploitable3-ub1404:~$ sudo -l
[sudo] password for leia_organa: 
Matching Defaults entries for leia_organa on metasploitable3-ub1404:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User leia_organa may run the following commands on metasploitable3-ub1404:
    (ALL : ALL) ALL
```
## 特権昇格
全アプリで、sudoが許可されています。
```su -```で、rootになります
```
leia_organa@metasploitable3-ub1404:~$ sudo su -
root@metasploitable3-ub1404:~# 
```
証券会社のセキュリティ強化についてAIに聞いてみた

# 楽天証券の多要素認証とフィッシング対策の課題

## はじめに

楽天証券が多要素認証を導入するというニュースがありましたが、これが実際にフィッシング対策として有効なのかについて考察します

## フィッシング対策としての多要素認証の弱点

楽天証券が導入した多要素認証は、メールで送られてくる画像と画面上の画像を照合するものですが、これには以下の問題があります：

1. **中間者攻撃に弱い構造**: フィッシングサイトが本人の入力情報を中継することで、正規サイトへのログインが可能です
2. **独自仕様の検証**: 標準的な多要素認証（TOTPなど）と異なり、セキュリティの定石から外れています
3. **画像選択の偏り**: 独自に作成された画像認証システムの場合、選択肢の偏りがないか第三者による検証が難しい

## 様々な認証方式とその強度

### TOTP認証の限界

一般的なTOTP（Time-based One-Time Password）認証も、リアルタイムフィッシング攻撃に対しては完全な防御とはなりません：

- コードの有効期限が短い（通常30〜60秒）のは利点
- しかし、攻撃者がユーザーから取得したTOTPコードをリアルタイムで中継すれば突破可能

### パスキー（FIDO2/WebAuthn）の優位性

パスキー（FIDO2/WebAuthnに基づく認証技術）は、現在最も強力なフィッシング対策として注目されています：

- **ドメイン検証**: 認証時にアクセス中のドメインを厳密に検証
- **物理的セキュリティ**: 生体認証や専用のセキュリティキーを使用
- **秘密情報の非送信**: 認証情報がデバイスから外部に送信されない

これにより、偽サイトへの誤った認証そのものを防ぐことができます

## 真に強固なフィッシング対策

フィッシングに強い本人確認方法の最適解：

- **パスキー（FIDO2/WebAuthn）**: スマートフォンの生体認証や物理セキュリティキーを活用
- **複数要素の組み合わせ**: 知識・所持・生体情報の複合利用
- **標準化された技術**: 独自仕様ではなく国際標準に準拠した認証方式

## スクレイピングユーザーのための対応策

多要素認証が導入されても資産情報の自動取得を継続する方法：

```
1. メール受信時に該当メールをサーバーに自動転送
2. サーバー側で画像を抽出・保存
3. スクレイピングプログラムが抽出画像を取得
4. 画面表示された画像と転送された画像の類似度を分析
5. 類似度の高い画像を選択・クリック
```

なお僕の環境では毎回以下の画面が表示されており、毎回同じブラウザでアクセスしているのにまともな判別が出来ていないように感じます
このあたりも楽天証券のセキュリティ対策に不安を覚える点になっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/ef881073-7af4-4adb-b2c1-a54bc84e00bb.png)

こちらは自宅Asteriskサーバーを用意し、SIPで制御することで自動化しました
リードオンリーで資産情報の詳細を返すAPIがあればこんなことしないで良いのですが、あるのでしょうか……
取引のAPIとかじゃなくて全然問題ないんですよ
日々の資産額がわかればいいので

## まとめ

楽天証券の二段階認証は一定のセキュリティ向上は見込めるものの、フィッシング対策としては十分とは言えません
真に効果的なセキュリティのためには、パスキー（FIDO2/WebAuthn）のような国際標準に則った認証方式の導入が望まれます
金融機関には、顧客資産を守るために最高水準のセキュリティ技術の採用が期待されます

### ちなみに

奇しくも有価証券は英語で[security](https://www.aizawasec-univ.jp/article/9970bf42281345fd365a972a42cf60f55b99c518.html)です

---

それでは良いNISAライフを
notebooklm を使ってみた感想

## はじめに
最近話題の notebooklm（Google Labs 提供の AI ノートサービス）を試用してみました。ドキュメントをサクッと読み込み、要約・音声出力・マインドマップ生成まで一気通貫でこなしてくれる優れもの。実際に触ってみて感じたポジ・ネガを以下にまとめます。

## 概要
資料のインポート → 要約
PDF やテキストをアップロードすると、AI が自動で内容を解析し、短く噛み砕いた要約を返してくれます。

音声概要
ポッドキャスト風のナレーションで要点を「聴く」ことが可能。移動中や作業中のインプットに最適。

マインドマップ生成
要約したキーワードや構造を元に、自動でマインドマップを作成。視覚的に全体像を俯瞰できるので、複雑な資料でも理解が捗ります。

## アピールポイント
インプット効率の最大化
テキストを読む・一覧化する・聴く・俯瞰する、という一連の流れがワンストップで完結。

ドキュメント内限定の情報処理
「アップロードした資料の範囲内」だけを参照して回答を生成してくれるため、知らない外部情報を持ち込むハルシネーションが起きにくい印象。

音声アウトプットの没入感
人間の声に近いナレーションで、まるで自分だけのポッドキャストが流れているかのよう。語尾の間も自然で、聴き疲れしにくいです。

## 良い点 👍
局所的な情報参照
AI が勝手に Web 全体をサーチせず、手元の資料だけで要約・Q&A を行う安心感。

マインドマップで瞬時に全体像把握
テキストだと追いきれない「構造」を、ビジュアル化することでスピーディーに理解できる。

## 改善してほしい点 👎
音声要約のフリガナ誤り
事前に読み仮名を指定しても、途中から別の読みでナレーションされるケースあり

## 無料版と有料版の違い
notebooklmに関しては、一日に生成できる量が違う。
無料版だと4回程度で音声概要のリミットに当たった記憶。

## まとめ
notebooklm は「資料インプット → 要約 → 聴取 → 俯瞰」という一連のインプット作業を劇的に効率化してくれるツール。特に移動中やながら学習が多いエンジニアにとっては、ポッドキャスト感覚で資料をインプットできるのが最高です。

音声出力の読み仮名誤り以外は非常に高機能なので、今後のアップデートで細かなチューニングが可能になればさらに手放せない存在になりそう。まずは無料枠から試してみて、自身の学習フローに組み込んでみてはいかがでしょうか。
Linucレベル１勉強メモ　＃２０

＃ 第二章　ファイル・ディレクトリの操作と管理

練習問題2.5
圧縮されたファイルを解凍することのできるコマンドをすべて選択してください。

A. gzip

B. gunzip

C. bzip2

D. bungip2

E. dd

（解答）A ,B ,C ,D

（解説）
gzipコマンドで圧縮されたファイルは、gzip -dコマンドもしくは、gunzipコマンドで解凍できます。また、bzipコマンドで圧縮されたファイルは、bzip2 -dコマンドもしくは、bunzip2コマンドで解凍できます。ddコマンドでは、圧縮ファイルの展開はできません。
統計検定1級　2023　統計数理　問3　解説

[5]はギブアップです。
![img20250428_16551276.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/63042048-1803-4232-91c5-096a9b9e9ddc.jpeg)
![img20250428_16554562.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576811/1abceb00-1084-4934-83d7-8dcb74695266.jpeg)
PADの備忘録

UipathのツールをPADに移管する際の注意点を備忘録として記載する。

# 変数の定義
UiPathはCtrl＋Kで変数の新規作成ができたが、
PADではアクションで変数を作成する必要があり、アクション数が多くなる。

# 変数の型の定義
PADでは指定できない。
一部は型の変更が可能（例えば、「テキストを数値に変換」アクションなど）。

# Excelの起動
UiPathではExcelを使用するのに、Excelアプリケーションスコープを定義する。
PowerAutomateDesktopでは「Excelの起動」アクションを使用し、シートは別アクションで指定する必要がある。

# Excelの起動終了間を並列処理にする必要がある場合、現行のPADには並列処理を行うためのアクションが存在しない
対策：
ループ処理や必要に応じて画面表示の取得などで判定する。

# テキスト内に改行コードを入れられない
対策：
「テキストに行を追加」アクションを使用する。

# メールの下書き保存
PADのアクションに存在しない。
対策：
HTTP要求を送信するアクションを使用して下書き保存できる。

# フローチャート型がない
PADはUiPathでいうところの「シーケンス型」しかないので、「フローチャート型」で分岐した先を自由につなぎ変えるみたいなことができない。
対策：
サブフローを作成することでMainから好きなタイミングでサブフローを実行することは可能。

# コメントが途中までしか表示されない
UiPathは表示・非表示を選べたが、各コメントを開かないと表示されず、各アクションを開かないと全文が表示されない。

# アクションのブックマークや最近使用したアクションの表示がない
いちいち検索する必要がある。

# メソッドが少ない
UipathでいうVB.NETメソッドが、PADはあまり実装されていない。※バージョン 2.5500176.25087

例えば、PADのテキスト型ではToLower（テキストを小文字に変換）やLength（文字列の長さを取得）は存在するが
StartsWith（テキストの先頭に、特定のフレーズが含まれているかどうかをチェック）やStrConv（文字列を半角・全角に変換）するメソッドは存在しない。

一方で、ログイン中のユーザ名の取得は、UipathではEnvironment.UserNameで取得できるが、同様の処理をPADで実現するには「Windows環境変数を取得」アクションを追加したうえで生成された変数を使用する必要があるなど、
別のアクションを追加することで代替することが可能な場合も存在する。
【React初心者メモ】===と＝＝の違い

JavaやPythonなどの他言語では、条件分岐の等価演算子として==をよく使います。
しかし、Reactでは===をよく見かけます。違いは何なのでしょうか？
### ==
値だけ比較する（型が違っても比較する）
```
'1' == 1     // true：型が違っても値が同じとみなされる
false == 0   // true：型変換で一致する
null == undefined   // true（特例）
```
### ===	
型も値も比較する（型が違えば false）
```
'1' === 1    // false：型が違うので一致しない
false === 0  // false：型が違う
null === undefined  // false
```
### 結論
==：値のみの比較（抽象的等価）
===：型も値も比較（厳密等価）

== は自動的に型を変換して比較するため、思わぬバグが発生しやすいです。
こういった予測できない動作を避けるために、
現代のJavaScriptでは常に ===を使うのがベストプラクティスとなっています。
Linucレベル１勉強メモ　＃１９

＃ 第二章　ファイル・ディレクトリの操作と管理

練習問題2.4
data.tar.bz2を展開しようとしています。下線部に当てはまるオプションを３つ選択してください。

$ tar_____ data.tar.bz2

A. c

B. x

C. z

D. f

E. j

（解答）B, D, E

（解説）アーカイブを展開するにはxオプションを指定します。また、アーカイブファイルはfオプションで指定します。設問にあるファイルは、拡張子が「.bz2」ですから、bzip2で圧縮されているとわかります。bzip2で圧縮されたファイルの展開にはjオプションを使います。cオプションはbzip2ではなくgzipに対応するオプションです。

アーカイブとは、複数のファイルをまとめたファイルのこと、ディレクトリ単位で圧縮を行う場合は、まずディレクトリのアーカイブを作る必要があります。

tarコマンドの書式
tar [オプション] ファイル名あるいはディレクトリ名

tarコマンドの主なオプション
* -c, --create<br> アーカイブを作成する
* -x, --extarct<br>アーカイブからファイルを取り出す。
* -t, --list<br>アーカイブの内容を確認する
* -f, --file ファイル名<br>アーカイブファイル名を指定する
* -z, --gzip<br>gzipによる圧縮/展開を行う
* -j, --bzip2<br>bzip2による圧縮/展開を行う
* J, --xz<br>xzによる圧縮/展開を行う
* -v, --verbose<br>詳細な情報を表示する
* -u, --update<br>アーカイブにある同名のファイルより新しいものだけを追加する
* -r, --append<br>アーカイブにファイルを追加する
* -N<br>指定した日付より新しいデータのみを対象とする
* --delete<br>アーカイブからファイルを削除s
PHP備忘録：Laravelの初期マイグレーションファイルって何？初心者が疑問に思ったこと

## はじめに

Laravelでアプリケーション開発を学習中に、最初からプロジェクト内に存在していたマイグレーションファイルに疑問を持ちました。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

これは何のためのファイルなのか、自分で作成したマイグレーションとの違いは何かを調べた内容を記録しておきます。

## 書こうと思ったきっかけ

個人的にPHPのキャッチアップをしたくて、勉強している初学者による備忘録としてください。マイグレーションの一覧を見て「すでにあるファイルは何なのか？」という素朴な疑問から調査を始めました。

## 内容

以下は `php artisan migrate:status` を実行した際に表示されたマイグレーション一覧です：

```
 0001_01_01_000000_create_users_table
 0001_01_01_000001_create_cache_table
 0001_01_01_000002_create_jobs_table
 2025_05_05_010232_create_messages_table
```

**参考文献**

https://qiita.com/masuda-sankosc/items/2a6999cca62de4facd45

それぞれの意味は以下の通りです：

### create\_users\_table

Laravelがデフォルトで用意しているユーザー管理用のテーブルで、ログインや登録などの認証機能で使用されるみたいです

```php
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});
```

### create\_cache\_table

キャッシュ機能をデータベースで管理する際に使われるテーブルです。
Laravelで `CACHE_DRIVER=database` の設定時に活用されます。

### create\_jobs\_table

キュー処理用のテーブルで、非同期処理（メール送信や重いタスクなど）をデータベース上で管理するために使います。

### create\_messages\_table

これは自分で作成したマイグレーションファイルで、フォーム送信などで入力されたデータ（名前など）を保存するためのテーブルです。

![Screenshot 2025-05-05 at 15.08.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/ab50b173-92f3-4697-b274-0fceb1691f0f.png)

## まとめ

Laravelではプロジェクト作成時から認証やキュー処理、キャッシュのためのマイグレーションが準備されており、必要に応じてこれらを有効活用できることが分かりました。

:::note alert
**自分で追加したマイグレーション（messagesなど）はその目的に応じて設計する必要があります。**
:::

次は、`messages` テーブルにカラムを追加してフォームデータを保存できるように実装を進めていきます...！
Azure AI Searchの検索手法実装まとめ(なるべくシンプルに)

Azure AI Searchには、フルテキスト検索やベクトル検索といったいくつかの検索手法が用意されていますが、それらの切り替えは単にオプションの値を変えれば良いというものではなく、事前に準備しなければいけないものがあったりします。そういったことは資料としてまとまってはおらず、自分としても混乱したため備忘録としてもここに残しておきます。

まず前提として以下のようなインデックスがAI Searchに定義されているとします。
![スクリーンショット 2025-05-05 14.34.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2708192/0e57e654-4cc6-43d7-9172-f7f10a30c92f.png)

その上で以下の下準備を行います。
```python
import os
from dotenv import load_dotenv
from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizedQuery
from azure.core.credentials import AzureKeyCredential
from openai import AzureOpenAI

dotenv_path = '.env'
load_dotenv(dotenv_path=dotenv_path)

credential = AzureKeyCredential(os.getenv("SEARCH_API_KEY"))
search_client = SearchClient(endpoint=os.getenv("SEARCH_ENDPOINT"),
                      index_name=index_name,
                      credential=credential)

index_name = "portfolio" # 検索したいインデックス
TOP=3 # 取得するドキュメント数

# 検索したいクエリ
query_text = "四条河原町住みで、3年以上の開発経験があり、コミュニケーションがしっかり取れる。"

# フルテキスト検索で検索したいフィールド
search_fields=["name", "address","academic_background","certification","career"]
# ベクトル検索で検索したいフィールド
vector_search_fileds=["self_introduce"], 
# 検索結果で取得したいフィールド
output_field = ["name", "address","academic_background","certification","career"]
```

# フルテキスト検索
```python
results = search_client.search(
    search_text=query_text, # フルテキスト検索したいクエリ
    search_fields=search_fields, # 検索対象のフィールド
    top=TOP, # 取得したいドキュメント数
    select=output_field,  # 出力結果に含めるフィールド
)
```
# ベクトル検索
まずは検索クエリのベクトル化を行う。
ここのベクトル化は、インデックスに格納されているドキュメントのベクトルフィールドをベクトル化したものと同じものを使うことに注意する。
```python
# 埋め込みの例
client = AzureOpenAI(
  api_key = os.getenv("AZURE_OPENAI_API_KEY"),  
  api_version = "2024-02-01",
  azure_endpoint =os.getenv("AZURE_OPENAI_ENDPOINT") 
)

response = client.embeddings.create(
    input = query_text,
    model= "text-embedding-3-large"
)

vector = response.data[0].embedding
```
ベクトル化した検索クエリで検索をかける。
```python
results = search_client.search(
    search_text=None,# フルテキスト検索の検索クエリは、ベクトル検索時にはNoneにする
    vector_queries = [VectorizedQuery(vector=vector, k_nearest_neighbors=TOP, fields=vector_search_fileds)] if vector else None, # ベクトル検索したいクエリ
    select=output_field,  # 出力結果に含めるフィールド
)
```
# ハイブリッド検索
`vector`はベクトル検索の時と同様に、すでにベクトル化したものを想定している。
```python
results = search_client.search(
    search_text=query_text, # フルテキスト検索したいクエリ
    search_fields=search_fields, # 検索対象のフィールド
    top=TOP, # 取得したいドキュメント数
    vector_queries = [VectorizedQuery(vector=vector, k_nearest_neighbors=TOP, fields="vector")] if vector else None, # ベクトル検索したいクエリ
    select=output_field,  # 出力結果に含めるフィールド
)
```
# セマンティックハイブリッド検索
セマンティックハイブリッド検索を行うには、AI Searchの費用とは別に費用のかかるセマンティックランカーを使う必要があることに注意。
なお、セマンティックランカーはAI Searchのfreeプランでは使うことができない。

`vector`はベクトル検索の時と同様に、すでにベクトル化したものを想定している。
```python
results = search_client.search(
    query_type="semantic",# セマンティックランカーを使うことを宣言
    search_text=query_text, # フルテキスト検索したいクエリ
    top=TOP, # 取得したいドキュメント数
    vector_queries= [VectorizedQuery(vector=vector, k_nearest_neighbors=TOP, fields="vector")] if vector else None, # ベクトル検索したいクエリ
    select=output_field,  # 出力結果に含めるフィールド
)
```
[Qiitaマークダウン] 見出しをリンクにすると、文字が消える件

# この記事は

Qiitaの見出しについて検証
見出しをリンク形式にしても昔はいけてた気がするのは気のせい？

## 2025/5/6 20:48 追記

本記事のコメントでご指摘いただきました。
本件についてGitHubのディスカッションに起票されていました

https://github.com/increments/qiita-discussions/discussions/984

## 参考リンク

https://qiita.com/degudegu2510/items/a4dbf82d15d80d8bd17e

---

～～～検証用はじめ～～～
NG例

# [Qiitaマイページ](https://qiita.com/t13801206)

## [Qiitaマイページ](https://qiita.com/t13801206)

[Qiitaマイページ](https://qiita.com/t13801206)
=

[Qiitaマイページ](https://qiita.com/t13801206)
-


OK例

[Qiitaマイページ](https://qiita.com/t13801206)

#[Qiitaマイページ](https://qiita.com/t13801206)

見出し1
=

見出し2
-

～～～検証おわり～～～

## 検証箇所の生データ

```text
～～～検証用はじめ～～～
NG例

# [Qiitaマイページ](https://qiita.com/t13801206)

## [Qiitaマイページ](https://qiita.com/t13801206)

[Qiitaマイページ](https://qiita.com/t13801206)
=

[Qiitaマイページ](https://qiita.com/t13801206)
-


OK例

[Qiitaマイページ](https://qiita.com/t13801206)

#[Qiitaマイページ](https://qiita.com/t13801206)

見出し1
=

見出し2
-

～～～検証おわり～～～
```

## 結論

- 見出しをリンクにすると、見出し文字が消える
- 文字は消えるが、見出しとしては認識されているようだ（目次には文字が現れるため）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/3392e2ed-3899-4a8e-8c3b-eb57c2763323.png)