OmniAICreator/Qiita-1.07M huggingface dataset:
衛星データだけでは因果関係まではわからない。定性的なアプローチと組み合わせてみる

最近道路事業の評価を行う機会が多いです。
今年から来年にかけてネパールの「シンズリ道路の震災復旧」事業の評価を行う予定です。

北はチベットと接するヒマラヤ山脈、南はインドへとつながるネパール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2493722/831e0ffb-f9d8-efb1-8cb3-59b517071e7f.png)
（出所：Government of Nepal Embassy of Nepal Tokyo, Japan）

ネパールの南部地域（インド国境沿いに広がるタライ平原）は、同国の重要な農業地帯ですが、2,000m超級のマハバラッド山脈に囲まれた地域であり、道路はコンクリートではなく、土。首都カトマンズへの主要ルートは大きく迂回しており、雨季には地滑りでたびたび道路が閉鎖されるなど、経済活動が阻害されてきました。

そこでタライ平原の肥沃な農業生産地帯にあるバルバディスと、首都カトマンズ近郊のドリケルをつなぐ（下図のピンクの線）、全長約160kmの「シンズリ道路」が建設されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2493722/881cfde9-5242-8561-72b3-3d0bc573e924.png)
（出所：[JICA「ネパールの悲願「シンズリ道路」が土木学会賞を受賞——高低差1,300メートルを克服し、ネパールの経済発展に寄与」](https://warp.da.ndl.go.jp/info:ndljp/pid/11666283/www.jica.go.jp/topics/2016/20160617_01.html)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2493722/7014680b-af45-dea2-bc74-336a6a6e853c.png)
（道路整備前）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2493722/dc23fdcc-2d14-1746-07e9-13d732ccf354.png)
（道路整備後）
（出所：[安藤ハザマ「ネパール・シンズリ道路建設プロジェクト」](https://www.ad-hzm.co.jp/works/projectstory/detail_01/)）

この道路は1995年に建設が開始し、2015年3月に完工しました。しかし、完工直後の2015年4月25にマグニチュード7.8 のネパール地震が発生し、道路の沈下、亀裂、斜面の一部崩壊等、同道路の約20 箇所が想定外の被害を受けました。

この被害を受け、本事業により、地震で被害を受けた同道路の5か所の地すべり対策工事を実施しました。

この一連の事業により想定される効果を下図のとおり整理してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2493722/416833ab-8f31-5a95-95ad-ecf6ef594f18.png)

想定される効果が発現していると確認できたとして、「事業のおかげ」と断定することはできるのでしょうか？


**いえ、実はそれだけでは、断定できません。**

例えば、経済・社会発展は、政府方針の転換、新規事業の実施、新しいテクノロジーの開発等、事業以外にも様々な要因によって実現します。そのため、経済・社会発展が実現したことを確認できたからといって、事業が引き起こしたと断定できません。

では、どうやって確認すればいいのでしょうか。

バックステップで効果が発現しているかを確認する、という方法があります。

具体的には、受益者へのインタビュー等によって、「収入が増加しているか」→「それはなぜか」→「販売額の増加」のため→「それはなぜか」→「シンズリ道路によって市場にアクセスしやすくなった、輸送費が削減した等」。想定する経路に沿って、効果が発現しているかをバックステップで確認します。

行きつく先に「シンズリ道路の建設・復旧」が出てこなければ、本事業の実施ではなく、他の要因によるものと判断でき、逆に「シンズリ道路の建設・復旧」が出てこれば、本事業の実施のおかげだと言えます。

最初から「シンズリ道路によって収入に変化が起きましたか」と聞くこともできそうですが、これだとバイアスが生じてしまいます。普通、その事業にについて聞かれると、意識してしまいますよね。さらに、日本人あるいは事業関係者から聞かれると、良い印象を与えたい（いいことを言うと、さらに支援があるかもしれない）と考えるのが普通だと思います。

そのため、バイアスが生じないよう、回答者には可能な限り**事業について意識させない**ことが重要です。

また、本事業の評価では、「沿道地域で経済発展が起きたか」に関して、衛星データを活用する予定です。
ですが、衛星データだけでは、事業と経済発展の「因果関係」まではわかりません。
衛星データだけで「因果関係」を検証する方法もあるのですが、それは今回の事業では難しいため、定性的なアプローチも用いることで、因果関係の検証に迫っていきたいと思っています。

本事業での衛星データと定性的なアプローチとを組み合わせた分析結果については、また進捗を共有させていただければと思います。

衛星データ活用方法についても、別の投稿にて共有させていただきます。
絶対的な下痢警報

println("これはテストです。繰り返しますが、これはテストです");
println("それはアラートをいじっているだけです。見る？心配することはありません！怖いミームはありません！");
alert("私は下痢で爆発しているのですが、「sonic.exe」という奇妙な生き物が私を気にせず、爆発を止めた後に私を殺しました。");
Accessのテーブルカラム名を動的に変更する

# はじめに
Accessのテーブルカラム名を動的に変更する方法について説明します。今回は、DAO（Data Access Objects）を使用してすべてのカラム名の最後ににアンダーバーを追加します。


# ソース全体像

1. AccessからVisual Basic Editorを開きます。
2. 新しいモジュールを作成し、その中に以下のVBAコードを記述します。

```vb
Sub ChangeColumnNames()
    Dim db As DAO.Database
    Dim tbl As DAO.TableDef
    Dim fld As DAO.Field
    Dim newFieldName As String
    
    ' データベースオブジェクトを開く
    Set db = CurrentDb
    
    ' 指定したテーブル名を取得
    Set tbl = db.TableDefs("table_name")
    
    ' フィールドごとに処理
    For Each fld In tbl.Fields
        ' 新しいフィールド名を作成
        newFieldName = fld.Name & "_"
        
        ' カラム名を変更
        tbl.Fields(fld.Name).Name = newFieldName
    Next fld
    
    ' データベースオブジェクトを閉じる
    db.Close
    
    Set fld = Nothing
    Set tbl = Nothing
    Set db = Nothing
    
    MsgBox "すべてのカラム名の後ろにアンダースコアが追加されました。", vbInformation
End Sub
```

## 解説
はい、もっと見やすくするために、コードを細分化して説明します。

1. テーブル名を指定する

```vb
Dim tbl As DAO.TableDef
Set tbl = CurrentDb.TableDefs("table_name")
```

2. テーブルのカラム名を変更する

```vba
Dim fld As DAO.Field
For Each fld In tbl.Fields
    Dim newFieldName As String
    newFieldName = fld.Name & "_"
    tbl.Fields(fld.Name).Name = newFieldName
Next
```

3. カラム名の変更を反映する

```vb
tbl.RefreshLink
```

4. オブジェクトを解放する

```vb
Set fld = Nothing
Set tbl = Nothing
```

このマクロを実行すると、指定したテーブルのすべてのカラム名の後ろにアンダースコアが追加されます。
タスクスケジューラーでタスクを右クリックで実行しても実行できない

トリガーを毎日に設定していたつもりが、規定選択の「1回」のままになっている。
毎日に変更する事で、右クリックから実行できるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8284/0227dce6-7b0a-90ec-ed53-85bcded07129.png)

普通は右クリックして画面表示を更新すると「状態」列が変化したり、終了後には「前回の実行時刻」列が更新されたりする。

権限が必要なタスクを作成し、後にパスワードを変更した場合に発生している。
タスクを編集して、パスワード入力画面が表示されるので、新しいパスワードを入力する事で、正常に実行されるようになる。
BIOSとUEFI

## BIOSとは
Basic Input Output Systemの略。ファームウェア（ハードウェアを制御するためのソフトウェア）の一種。マザーボードにあるROMなどの記憶装置に組み込まれている。ファームウェアの中で一番よく知られているのがBIOS。

## BIOSの動き
PCに電源が入るとBIOSが起動する。BIOSのプログラムをもとにそれぞれ接続されている機器が使用可能な状態になる。それぞれの機器が使用可能であることが確認されたのち、HDDやSSDに保存されているOSがメインメモリに呼び出される。

## BIOSにおけるOSの保存方法
OSが起動されていないとHDD(またはそれをはじめとする補助記憶装置)は使えない。のにOSはHDDに保存されている。
OSの起動情報はHDDの最初のセクタに保存されている。（最初に読み込まれるセクタをMBRという。MBRにはOSの情報のほかに基本パーティション情報が含まれる）
MBRを読み込む→OSが保存されているパーティションにアクセス→OS起動　という流れ。

## UEFIとは
BIOSを拡張させるためにOSとBIOSの間に接続するインターフェース。


## パーティション
HDD、SSDを内部の複数の独立した区画に分割。この一つ一つをパーティションと呼ぶ。
WindowsではCドライブ、Dドライブのようにドライブレター単位で分割。
Linuxでは`sda1`, `sda2`のように分割し、それぞれのパーティションが`usr`や`bin`など任意のディレクトリにマウントすることが一般的。`lsblk`パーティションとそのマウントポイントを確認できる。

```bash
$ lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda    254:0    0 59.6G  0 disk 
`-vda1 254:1    0 59.6G  0 part /etc/hosts
                                /etc/hostname
                                /etc/resolv.conf
```
UEFIではGPT(GUID Partition Table)でパーティションを管理する。
AWSで手を動かして勉強できそうなサイト

# 内容

AWSを勉強するうえで手を動かして試せる手順などが載っているサイト

# 実践的チュートリアル出来そうなもの

以下のものは日本語に翻訳されている。

### サーバーレスのウェブアプリケーションを構築する

https://aws.amazon.com/jp/getting-started/hands-on/build-serverless-web-app-lambda-apigateway-s3-dynamodb-cognito/


### Amazon S3 Object Lambda を使用して、取得時に画像に動的にウォーターマークを付ける

https://aws.amazon.com/jp/getting-started/hands-on/amazon-s3-object-lambda-to-dynamically-watermark-images/


### 基本的なウェブアプリケーションを構築する

https://aws.amazon.com/jp/getting-started/hands-on/build-web-app-s3-lambda-api-gateway-dynamodb/?ref=gsrchandson

### Amazon Amplify でウェブアプリケーションをデプロイする

https://aws.amazon.com/jp/getting-started/guides/deploy-webapp-amplify/


# Work shop studio

時間がかかりそう
AWS 日本語ハンズオンから見つけた

### スケーラブルウェブサイト構築 ハンズオン

https://catalog.us-east-1.prod.workshops.aws/workshops/47782ec0-8e8c-41e8-b873-9da91e822b36/ja-JP

### CI/CD on AWS ワークショップ

https://catalog.workshops.aws/cicdonaws/ja-JP


# 資料・リンク集

AWS 日本語ハンズオン

https://aws-samples.github.io/jp-contents-hub/

https://www.cloudbuilders.jp/articles/1889/

https://dev.classmethod.jp/articles/aws-beginner-docs/

https://aws.amazon.com/jp/blogs/news/2022-aws-beginner-learning/
java 2次元配列

# はじめに
2次元配列に1次元配列を格納しようとしたが、理解できていない事が分かった。
忘れてもすぐに思い出せるよう分かった事をまとめた。
（メモリの番地が格納されている事がポイントだと思います。）

## イメージ
例えば 2行3列の配列　int mat[][] = new int[2][3]; を作成した場合
3列の配列が2つ作成され、それぞれの先頭の番地がmat[0]、mat[1]に格納される。
別の見方をするとmat[0]には、1行目の先頭の番地が格納されている。
（例の1行目はmat[0][0]、mat[0][1]、mat[0][2]）

## lengthの結果
mat.lengthは、行数を表す。
mat[0].lengthは、0行目の列数を表す。
        
## サンプルコード
~~~2jigen.java
//2次元配列の初期化
char test[][] = {{'a','b','c','d'},{'e','f','g','h'}};
char toTest[][] = {{'1','2','3','4'},{'5','6','7','8'}};

//testの1行目にtoTestの1行目を格納
//toTest1行目の先頭番地をtest1行目に格納している。
test[0] = toTest[0];

//testの1行目を出力
for (int i=0; i<test[0].length; i++) {
    System.out.println(test[0][i]);
}

//testの行数を出力
System.out.println("testの行数 = test.length = "+test.length);
//testの列数を出力
System.out.println("testの列数 = test[0].length = "+test[0].length);
~~~

~~~結果
1
2
3
4
testの行数 = test.length = 2
testの列数 = test[0].length = 4
~~~

## 参考文献
スッキリわかる Java入門
Webページ上に貼り付けられたクリップボードの内容を読み取る2つの方法

# 概要
Webページ上に貼り付けられたクリップボードの内容を読み取るとき，
- `Clipboard.readText()` を使用する方法
- `ClipboardEvent.clipboardData.getData(format)` を使用する方法

がある．`Clipboard.readText()` を使用するには[権限API](https://developer.mozilla.org/ja/docs/Web/API/Permissions_API)の `clipboard-read` 権限が必要だが，`ClipboardEvent.clipboardData.getData(format)` の使用に権限は必要ない．

# 詳細

以下，それぞれの実装例を示す．

## `Clipboard.readText()`
```html:readtext.html
<label for="editor">右の入力欄にテキストを貼り付けてみてください。</label>
<input id="editor" type="text" />

<h3>ログ:</h3>
<p id="log"></p>

<script>
    async function logPaste(event) {
        let pastedText = "";
        await navigator.clipboard.readText()
                           .then(text => {
                            pastedText = text;
                           });
        log.innerText = `貼り付けされました: ${pastedText}\n${log.innerText}`;
    }

    const editor = document.getElementById("editor");
    const log = document.getElementById("log");

    editor.onpaste = logPaste;
</script>
```
`readtext.html` を開き，入力欄に何らかのテキストを貼り付けると，`clipboard-read` 権限を要求するダイアログが表示される（以下の画像はGoogle Chromeでの表示例）．

![clipboard-read](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478774/24c1ee8f-4a35-cde5-5a6b-f79ce87edc6b.png)

「許可する」をクリックするとクリップボードの読み取りが完了し，結果が画面に表示される．

![実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478774/526711dd-d295-3647-439a-4086cfee0cde.png)

## `ClipboardEvent.clipboardData.getData(format)`
```html:getdata.html
<label for="editor">右の入力欄にテキストを貼り付けてみてください。</label>
<input id="editor" type="text" />

<h3>ログ:</h3>
<p id="log"></p>

<script>
    function logPaste(event) {
        const pastedText = event.clipboardData.getData("text");
        log.innerText = `貼り付けされました: ${pastedText}\n${log.innerText}`;
    }

    const editor = document.getElementById("editor");
    const log = document.getElementById("log");

    editor.onpaste = logPaste;
</script>
```
同じように `getdata.html` を開き，入力欄に何らかのテキストを貼り付けると，今度はダイアログが表示されずにクリップボードの読み取りが完了する．

## なぜ `Clipboard.readText()` には権限が要求されるのか
HTMLファイル中のJavaScript部分をよく見ると，`readtext.html` では `event`（pasteイベント）を利用していない．つまり，`Clipboard.readText()` は**pasteイベントなどとは無関係にクリップボードの値を取得できる**．一方，`ClipboardEvent.clipboardData.getData(format)` はpasteイベントが発生しない限り，クリップボードは取得されない．この違いが，権限の要求有無に影響していると考えられる．

# 参考
- [Clipboard.readText() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Clipboard/readText)
- [ClipboardEvent: clipboardData プロパティ - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/ClipboardEvent/clipboardData)
- [HTMLElement: paste イベント - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/paste_event)
ベクトルデータベース Qdrant をスケールアップしてみた

## はじめに
PDFのファイルを学習させて、PDFの内容についてChatGPTと連携して応答するLINEボットを作りました。
データベースはQdrantを使用。
応答速度についてボトルネックになっていたのが、Qdrantへのアクセスの処理でした。

ボトルネック解消にはいくつかアプローチが考えられますが、まずは手っ取り早く金で解決する方法（サーバーのスケーリング）について、覚え書きを。

### この記事の対象者
- PythonでRetrievalのコードを書いたことがある方
- Qdrantを使っている方
- Retrievalの高速化を模索している方

## Qdrantとは
ベクトル類似検索エンジンおよびベクトルデータベース。
高速で高精度なベクトル検索を実行できます。
例えば歴史上の人物や商品などの類似アイテムを抽出することが可能。

https://qdrant.tech/

他のベクトルデータベースとして、Pineconeがあります。

## PDFの資料をRetrievalするLINEボット
Pythonでコーディングして、GCP(Google Cloud Platform)にデプロイ。
学習させたファイルは2つのPDFファイル(1.8MB 37ページ、1.8MB 24ページ）

![スクリーンショット 2023-11-25 8.18.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/ab59754c-c047-d95e-2d80-5ca0bbf1b6fa.png)

QdrantでRetrievalを行う処理は、こちらの資料を参考にさせていただきました。

https://zenn.dev/ml_bear/books/d1f060a3f166a5

LINEボットとのやりとりはこんな感じ
![LINE_capture_722561033.119873.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/d4b2c84b-deee-1d1f-5769-d3e0c038963a.jpeg)

ベクトルデータベースの諸元はこちらの通り

![スクリーンショット 2023-11-24 8.46.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/c7c1627a-1d9e-5475-77dc-f61a220013b9.png)



## スケールアップ前
使用量に対してRAMやメモリのリソースは余裕なので、スケーリングによるパフォーマンスの向上はそんなに大きくならないかも...
![スクリーンショット 2023-11-24 8.26.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/4e2e009d-1e9a-3298-6be1-7d9c593a37b6.png)

1ヶ月あたりのコストは33ドル（1ドル150円で4,950円）
![スクリーンショット 2023-11-24 8.47.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/108ebde8-40a4-71d2-5557-b060f7883f8f.png)

こちらのやり取り、5回の平均で 47.965秒。
![LINE_capture_722562400.601587.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/bac47bdf-e92b-3088-aa46-24c9448510be.jpeg)

## スケールアップ後
結論から申しまして、コスト 2倍 で 5% の処理時間が短縮。

15文字程度の回答であれば処理時間が
4.38秒　→ 3.93秒　と 10% 改善するケースも。 

|スケールアップ| 前 | 後 |
|:-:|:-:|:-:|
|RAM|2.0 GB|4.0 GB|
|CPU|0.5 Cores|1.0 Cores|
|Disk|8.0 GB|16.0 GB|
|425文字平均回答時間|47.96　秒|45.47　秒|
|15文字平均回答時間|4.38　秒|3.93　秒|
|月額費用|33ドル|67ドル   |

![スクリーンショット 2023-11-24 8.57.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/703e5484-7bef-952f-cb3d-0c07eae2721a.png)
1ヶ月あたりのコストは67ドル（1ドル150円で10,050円）
![スクリーンショット 2023-11-24 8.56.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496109/99e85ec9-1c6c-0d85-d209-d7ce2bcd00de.png)


## 考察
- スケールアップによる速度の向上は確認できたが、2倍のコストに対して5-10%の改善は、コスパ悪い。
- Qdrantは一度スケールアップすると、スケールダウンができない。　もし、スケールダウンする場合は新たにクラスターを作成する必要がある。
- リソースに余裕がある状態では、スケールアップによる改善のアプローチは、コスト面であまり得策ではない。

## おわりに
別のベクトルデータベースのPineconeも試して、パフォーマンスを確認したい。

## 参考資料

https://zenn.dev/ml_bear/books/d1f060a3f166a5
[Go]「...（ピリオド３つ）」の使い方（応用編）

# はじめに
以下の記事の応用編を書いてみました。

https://qiita.com/Yashy/items/a02b74a00136dc5a42c4

# 「...」の使い方（応用編）
## インターフェース型での可変長引数
Goの可変長引数は、インターフェース型を利用することで、異なる型の引数を一つの関数で受け取ることができます。これは特に、ログ出力や汎用的な処理を行う関数を作成する際に便利です。

```go
func WriteMultipleTypes(values ...interface{}) {
	for _, value := range values {
		fmt.Println(value)
	}
}

func main() {
	WriteMultipleTypes(1, "two", 3.0)
}

// 実行結果
1
two
3
```
## 外部からオプションを設定する
外部からオプションを設定する一般的な例として、設定オブジェクトや構造体を初期化する関数を考えてみましょう。このアプローチは、設定が多く、柔軟性が必要な場合に特に有用です。
```go
package main

import (
	"fmt"
)

// Config はアプリケーションの設定を保持する構造体です。
type Config struct {
	Host     string
	Port     int
	IsSecure bool
}

// Option は Config を変更する関数です。
type Option func(*Config)

// NewConfig は新しい Config を生成し、与えられたオプションでカスタマイズします。
func NewConfig(options ...Option) *Config {
	config := &Config{
		Host:     "localhost",
		Port:     8080,
		IsSecure: false,
	}

	for _, option := range options {
		option(config)
	}

	return config
}

// WithHost はホスト名を設定する Option を返します。
func WithHost(host string) Option {
	return func(c *Config) {
		c.Host = host
	}
}

// WithPort はポート番号を設定する Option を返します。
func WithPort(port int) Option {
	return func(c *Config) {
		c.Port = port
	}
}

// WithSecurity はセキュリティの有効化を設定する Option を返します。
func WithSecurity(isSecure bool) Option {
	return func(c *Config) {
		c.IsSecure = isSecure
	}
}

func main() {
	// カスタムオプションを使用して Config を作成
	config := NewConfig(
		WithHost("example.com"),
		WithPort(443),
		WithSecurity(true),
	)

	fmt.Printf("Config: %+v\n", config)
}

// 実行結果
Config: &{Host:example.com Port:443 IsSecure:true}
```
このコードでは、Config 構造体を初期化し、その後に複数のオプション関数（WithHost、WithPort、WithSecurity）を適用しています。これにより、外部から柔軟に設定を変更することが可能になります。

## 外部からオプションを設定する（シンプルver.）
こちらは1つ前のパターンと本質的には同じです。
ここでは、GenerateUserの引数でfunc(data *User)の可変長引数を取る形になっております。

```go
package main

import (
	"fmt"
	"testing"
)

type User struct {
	ID   uint64
	Name string
}

func GenerateUser(options ...func(data *User)) User {
	result := User{
		ID:   1,
		Name: "default",
	}

	for _, option := range options {
		option(&result)
	}

	return result
}

func TestSomething(t *testing.T) {
	defaultUser := GenerateUser()
	updatedUser := GenerateUser(func(data *User) {
		data.ID = 999
		data.Name = "updated"
	})
	fmt.Printf("defaultUser %+v\n", defaultUser)
	fmt.Printf("updatedUser %+v\n", updatedUser)

	// ...
	// add assertions
}

// 実行結果
defaultUser {ID:1 Name:default}
updatedUser {ID:999 Name:updated}

```

# まとめ
これらの例を通して、可変長引数 ... の強力な用途とその応用方法を紹介しました。Go言語におけるこの機能は、コードの柔軟性と再利用性を大いに高めることができます。ぜひあなたのコードで活用してみてください！
MacOSとWindows10のVLAN

# MacOSとWindows10のVLAN
MacとWindows10 PCとにVLANタグを付加して通信させたときの備忘録。

## ネットワーク構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/ad3336de-c272-9ea8-5819-aed68992a518.png)
MacおよびWindows10 PCにはリンクローカルアドレスが割り当てられ、タグID”10”であるVLANを設定する。また、途中の経路にMirroring L2 Switchを設け、Wiresharkが搭載されたPCで、Mac-Windows10 PC間のデータをキャプチャする（見る）。

## 設定
### Windows 10 PC
ネットワークアダプタの詳細設定にて、VLAN IDを設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/7fbb051c-f382-2e27-28f9-491df6990827.png)

### Mac OS
システム環境設定のネットワークから、仮想インターフェースを管理をクリック。
![仮想IFを管理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/970e626f-b0b2-c1f1-d1aa-7d57fa773264.png)
新規VLANクリック。
![仮想IF設定１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/be79e7d5-7757-febc-7098-51baf87e2a97.png)
名称やタグIDを入力。
![仮想IF設定２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/c7f87d30-d1e0-35cd-7309-a0730ed9b95a.png)
![仮想IF設定３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/9d0a634f-405a-0ca7-24a1-034b92c35e03.png)
ただし、VLANを設定するネットワークI/Fを未使用にする必要があるようだ。
![RawIFオフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/e0d4c1f1-08e3-46dc-cf15-9f603365905e.png)
最終的には下記のような状況となる。
![最終形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/f1cb764b-ce06-3404-ee77-bbb9e02091f0.png)
ifconfigの状況は下記。”vlan: 10”が見える。
```
vlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=3<RXCSUM,TXCSUM>
	ether 04:ab:18:yy:xx:zz 
	inet6 fe80::b0:edca:xxf:zzzz%vlan0 prefixlen 64 secured scopeid 0xf 
	inet 169.254.98.55 netmask 0xffff0000 broadcast 169.254.255.255
	nd6 options=201<PERFORMNUD,DAD>
	vlan: 10 parent interface: en6
	media: autoselect (100baseTX <full-duplex>)
	status: active
```

## 検証
MacからWindows10 PCへのpingの実行。

### Wireshark PC
Windows PC利用。VLANタグを見せる（キャプチャする？）には、ネットワークI/Fの詳細設定にて、下記設定が必要。
![ManInTheMiddle設定のコピー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/747c9547-88d7-3895-e700-b52bb6fb5f27.jpeg)
これについては、記事「[RealtekのNICでタグVLANのタグをパケットキャプチャで確認する](http://webdev.seesaa.net/article/386809906.html)」から情報を得た。
実際のキャプチャデータは下記である。
![Wireshark_ManInTheMiddleのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/c211597f-47a4-1fba-9c31-2208691e747b.png)
タグID”10”が見える。

### Mac (169.254.98.55)
MacのWiresharkでは、利用するネットワークI/FとVLAN I/Fとの選択ができる。
![IF選択のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/f41a5af5-e1c3-89f1-8739-15e20c8f35b0.png)
#### 利用するネットワークI/F
![Mac_RawIFのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/86eafed2-78d1-2fd9-4e08-aae6390785f7.png)
VLANタグID”10”が見える。

#### VLAN I/F
![Mac_VLAN_IFのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/1fa46729-a865-907b-e88a-32e50358cffb.png)
VLANタグID”10”が見えない。（これらはWiresharkの仕様なのであろう。）

### Windows 10 PC (169.254.50.205)
Wireshark PCと同じ設定（”優先度およびVLAN無効”）をすると、VLANがオフとなってしまうため、VLAN通信とWiresharkによるタグIDの同時表示は不可。

それなりに奥が深い。

EOF
wslでnerves その32

# 概要
wsl(wsl2じゃない)でnervesやってみる。
qemu(x86_64エミュレータ、ラズパイじゃない)でやってみた。
生成したnerves_livebook.imgを、quemで起動してテストしてみた。
githubにissue上げてみた。

https://github.com/nerves-livebook/nerves_livebook/issues


以上。
パスワード認証付きのリポジトリをvcs importできない場合の対処方法

# 概要
* パスワード認証付きのリポジトリを、vcs importした際の対処方法

vcs import については以下の記事を参照。

https://qiita.com/strv/items/dbde72e20a8efe62ef95

# 方法

* ```--workers=1```オプションをつけて、並列実行を無効にする

```bash
vcs import < your_repos.repos --workers=1
```

# 参考
* https://github.com/dirk-thomas/vcstool/issues/23#issuecomment-576752276
リモートTCPポートをローカルに引き寄せる - SSH tunnel

※23/12/7不正確な記述を削除 @ttdoda(IWAMOTO Kouichi) さんのコメントを参照ください。

```plantuml
participant usr as "User"
participant tc as "Tunnel Client"
participant ts as "Tunnel Server\nusr@svr.com"
participant tg as "Target Service\ntarget.host"

ts ->> ts : sshd.listen(port:80, user:"usr")
tg ->> tg : listen(port:80)
tc ->> ts : ssh usr@svr.com -N -L :1234:target.host:80
tc ->> tc:listen(port:1234) 
usr -> tc : tcp(port:1234)
tc -> ts :
ts -> tg : tcp(port:80)
```


```sh:Tunnel Client - Connect
TNSVR="usr@svr.com"
EXPPORT=1234
TG="target.host:80"
ssh $TNSVR -N -L :$EXPPORT:$TG
```

<details><summary>ssh証明書を指定する場合</summary>

```sh:Tunnel Client
ssh -i ~/.ssh/private.key ...
```
</details>

### 応用例:LAN-Internet-LANの場合
https://qiita.com/shokkaa/items/969e3ea7a5a4547b5d75

との合わせ技で、両側からInternetの中間サーバに向かってトンネルを掘る。
誤ってターゲットサービスをInternetにそのまま露出しないよう注意。

```plantuml
participant c as "<Local LAN>\nClient"
participant tc2 as "<Local LAN>\nTunnel Client"
participant ts as "<Internet>\nTunnel Server\ncloud.host"
participant tc as "<Remote LAN>\nTunnel Client"
participant tg as "<Remote LAN>\nTarget Service\ntarget.host:80"
==services==
ts->ts:sshd.listen(\n port:22,\n user:"svr-usr")
tg<-tg:listen(port:80)
tc<-tc:sshd.listen(\n port:22,\n user:"cli-usr")
==setup==
tc->ts:ssh svr-usr@cloud.host\n -N\n -R 8022:localhost:22
ts->ts:listen(port:8022)
ts<-tc2:ssh cli-usr@cloud.host\n -p 8022\n -N\n -L :8080:target.host:80
tc2->tc2:listen(port:8080)
==use==
tc2<-c:tcp(port:8080)
ts<-tc2
tc<-ts
tg<-tc:tcp(port:80)
```

### 関連
https://qiita.com/shokkaa/items/969e3ea7a5a4547b5d75
mindの研究 その36 - mindでキーボード割込み ESC

# 概要
mindが謎なので調べてみた。
練習問題やって見た。

# 練習問題
mindでescキーを検査せよ。

# サンプルコード

```
メインとは
　結果は　変数
　３を　回数指定して
　　27をつみ
　　"user32"と　"GetKeyState"で　ＡＰＩ呼出し１　結果に　入れ
　　エラー？
　　ならば
　　　エラー文字列を　一行表示し　終り
　　つぎに
　　結果を　数値表示し　改行する
　　二秒待つ
　繰り返す



```

以上。
mindの研究 その35 - mindでwindowsキーを操作

# 概要
mindが謎なので調べてみた。
練習問題やって見た。

# 練習問題
mindでwindowsキーを押せ。

# サンプルコード

```
メインとは
　結果は　変数
　91をつみ
　０をつみ
　０をつみ
　０をつみ
　"user32"と　"keybd_event"で　ＡＰＩ呼出し４　結果に　入れ
　エラー？
　ならば
　　エラー文字列を　一行表示し　終り
　つぎに
　91をつみ
　０をつみ
　２をつみ
　０をつみ
　"user32"と　"keybd_event"で　ＡＰＩ呼出し４　結果に　入れ
　エラー？
　ならば
　　エラー文字列を　一行表示し　終り
　つぎに
　「ok」を　一行表示する。


```

以上。
bcryptGemを用いたパスワードのハッシュ管理

# bcryptGemを用いたパスワードのハッシュ管理

Webアプリケーションのセキュリティを確保する上で、パスワードの安全な管理は重要な役割を果たします。`bcrypt` Gemを使用することで、Railsアプリケーションにおいて、パスワードを安全にハッシュ化し、管理することが可能です。この記事では、`bcrypt` Gemを使用したパスワードのハッシュ化と認証プロセスについて詳しく解説します。

## bcryptGemとは

`bcrypt` Gemは、パスワードのセキュリティを向上させるために使用されるRubyのライブラリです。このGemは、パスワードをハッシュ化することで、データベースに平文のパスワードを保存するリスクを回避します。

### パスワードのハッシュ化

- ユーザーがパスワードを設定すると、`bcrypt` Gemはそのパスワードをハッシュ化します。これにより、実際のパスワードとは異なる、独特な文字列が生成されます。

## has_secure_passwordの利用

Ruby on Railsでは`has_secure_password`メソッドを使用して、モデルにパスワードのセキュリティを簡単に追加できます。

### バリデーションと保存

- `has_secure_password`を使用すると、パスワードの存在確認（presence: true）とハッシュ化されたデータの`password_digest`への格納が自動的に行われます。
- データベースのカラム名は`password_digest`ですが、パスワードの保存は`password`フィールドを用いて行います（例: `User.new(password: params[:password])`）。

### 認証プロセス

- `authenticate`メソッドは、引数として渡されたパスワードをハッシュ化し、その値が対応するユーザーの`password_digest`と一致するかどうかを検証します（例: `if @user.authenticate(params[:password])`）。

## bcryptGemの利点

1. **セキュリティの強化**: ハッシュ化により、データベースに保存されるパスワードの安全性が向上します。
2. **使いやすさ**: `has_secure_password`メソッドを使用することで、パスワードのセキュリティ管理が容易になります。
3. **柔軟性**: `authenticate`メソッドを使用することで、カスタム認証ロジックを簡単に実装できます。

## まとめ

`bcrypt` Gemは、Ruby on Railsアプリケーションにおいて、パスワードの安全性を確保するための強力なツールです。このGemを用いることで、パスワードをハッシュ化し、安全にデータベースに保存することが可能になります。また、`has_secure_password`メソッドと`authenticate`メソッドの使用により、ユーザー認証のプロセスが簡単かつ安全に実装できます。安全なWebアプリケーション開発において、`bcrypt` Gemは不可欠な存在です。
2023/11/25主にITとかセキュリティの記事

開発言語、フレームワークなどの End Of Life （サポート終了日）を API で取得し、一覧化する(11/22)
https://qiita.com/RyoWakabayashi/items/db98e9f65e98c8f99543

マカオ、フィッシング詐欺グループの受け子2人逮捕…QRコード決済アカウント乗っ取り商品購入(11/23)
https://news.yahoo.co.jp/articles/4ac5217dff8cefc4ec40c5eebba32b03725bc2e1?source=rss

北朝鮮 サイバー攻撃で盗んだ暗号資産 過去最高に 国連専門家(11/22)
https://www3.nhk.or.jp/news/html/20231122/k10014266501000.html

サイバー被害の情報共有指針案　経産省公表(11/23)
https://www.nikkei.com/article/DGKKZO76359240S3A121C2EP0000/

NTTやNEC、サイバー防衛人材を育成　年内に団体設立(11/23)
https://www.nikkei.com/article/DGXZQOUC232W60T21C23A1000000/

＜独自＞官民連携でサイバー防衛強化へ　１２月に業界５社が新団体設立(11/22)
https://www.sankei.com/article/20231122-UYFU5XF4OVML3NYB2V7GJSAY5Q/

HECOブリッジが8,300万ドル以上のハッキング被害に遭う(11/23)
https://nextmoney.jp/?p=62450

JCOM、Wi-Fi利用者の個人情報23万件が流出　氏名など(11/22)
https://www.nikkei.com/article/DGXZQOUC22CGU0S3A121C2000000/

アングル：外貨狙う北朝鮮ＩＴ技術者、偽の経歴でリモート就職(11/23)
https://jp.reuters.com/world/security/2XXL3WVITVJXPBQ2OX22KIY4RQ-2023-11-22/

米当局、バイナンスが「ハマスの暗号資産取引」を容認と非難(11/23)
https://forbesjapan.com/articles/detail/67494

【重要】迷惑メール（なりすましメール）に関するお詫びと注意喚起 AOKIグループ(11/23)
https://ir.aoki-hd.co.jp/ja/news/news/news20231123.html

サイバー法整備、24年通常国会は見送り論　薄い危機感(11/23)
https://www.nikkei.com/article/DGXZQOUA09B290Z01C23A1000000/

ノートPC、デスクトップPCを長生きさせるためのメンテナンス方法(11/23)
https://www.gizmodo.jp/2023/11/mac-windows-pc-laptop-desktop-maintained.html

豪州、サイバー防衛570億円 インフラ企業、対策義務　国家戦略(11/23)
https://www.nikkei.com/article/DGKKZO76362620S3A121C2FF8000/

バイナンス、北朝鮮やハマスの「マネーロンダリング」認める…４３億ドルの罰金払い米国撤退(11/23)
https://japanese.joins.com/JArticle/311794?sectcode=330&servcode=300%20title=

【墨汁速報】67億円超えの被害 仮想通貨アグリゲーター”カイバースワップ”ハッキング(11/23)
https://coinchoice.net/dex-aggregator-kyber-swap-hacked-lost-more-than-6billion-yen_bnews/

2014年に破綻したマウントゴックス、債権者への現金弁済まもなく開始へ(11/23)
https://coinpost.jp/?p=493692

アルトコイン「イーサリアム」今月に入り価格高騰…“いまから投資”していいものか【暗号資産アナリストの見解】(11/23)
https://news.yahoo.co.jp/articles/c459ce0e4870dc2bf822f9eb6d82be88812f7a60?source=rss

電子帳簿保存法「電子取引データ保存」に向けた事務処理体制や保存ルール見直しのポイント(11/23)
https://the-owner.jp/archives/18331

電子帳簿保存のメリットと設備投資や導入のポイント(11/23)
https://the-owner.jp/archives/18332

北朝鮮の核・ミサイル開発阻止へ“瀬取り”監視強化 英韓首脳(11/23)
https://www3.nhk.or.jp/news/html/20231123/k10014266791000.html

北「衛星」発射　露の技術支援が暴挙を促した(11/23)
https://www.yomiuri.co.jp/editorial/20231122-OYT1T50311/

定期購入や副業サイトに注意…香川県の消費生活相談　特に30代や20歳未満の相談が増加　23年度上半期(11/23)
https://nordot.app/1100325494885303037

高校「1人1台端末」継続に暗雲、故障とコスト増でGIGA受け皿に危機(11/24)
https://xtech.nikkei.com/atcl/nxt/column/18/00989/112000133/

高齢の親を見守るため実家をスマートホーム化、いくらかかるか(11/24)
https://xtech.nikkei.com/atcl/nxt/column/18/02649/111700004/
からあげ帝国アドベントカレンダー、芸術部門への作品エントリー

※発言は個人の見解に基づくものであり、所属組織を代表するものではありません

# 背景

からあげ帝国アドベントカレンダー、芸術部門への作品エントリーを行います。
からあげ帝国にはこれまで公式発信（？）の芸術部門はなかったかもしれないのですが、せっかくのアドベントカレンダーなので今年度、帝国No.1の芸術野郎を決めるべく勝手にエントリーします。からあげ帝国の皆さま対戦よろしくお願いします。

#からあげ帝国芸術部門

## 作品詳細

ドット絵で帝王のイラストを作成いたしました。

![スクリーンショット 2023-11-25 1.42.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/fafe3643-c238-0800-b107-1de290a5c5b5.png)

[動画](https://www.youtube.com/watch?v=k4Jlk9X_6xQ)も作成いたしました。

https://www.youtube.com/watch?v=k4Jlk9X_6xQ

テトリス風にブロックを操作しながらイラストを完成させます。

## これは何

これまで研鑽してきたスキルを応用した最先端のテトリスアート技術です。
これで帝国の経済成長、競争優位性の確立、ひいては幸福度向上に寄与していきたいです。

> #### テトリスアートについて
> - テトリスのブロックを使ってフィールドに模様を描く取り組み
> - スコアを競うのではなく、フィールド上に模様をどれだけ正確に再現できるかを競う(?)
> - どうやら自動化できるらしいです 「テトリスプリンター」アルゴリズム

https://qiita.com/seigot/items/d6aa67ccf4c85c8b9af4

## 謝辞

@karaage0703 先生：先日はMakerFaireTokyo2023等で大変お世話になりました。今後ともよろしくお願いいたします。
@shi78ge さん：アドベントカレンダー作成ありがとうございます。今後ともよろしくお願いいたします。
@からあげ帝国の皆様：いつもありがとうございます。

## つぶやき

からあげ帝国makerfaireがあれば出展してみたい。

からあげ帝国芸術部門No.1になりたい。

pythonでテトリスブロックを自動制御して動スコアを競い合う大会を開催してみたい。

https://qiita.com/seigot/items/0b42a807217dbe636226
https://qiita.com/seigot/items/e16e9d8f6fc04853855f
https://qiita.com/seigot/items/af3cac69a5272591d4bb

# 参考

https://nlab.itmedia.co.jp/nl/articles/1306/05/news133.html

https://qiita.com/seigot/items/d6aa67ccf4c85c8b9af4

https://qiita.com/seigot/items/0b42a807217dbe636226

https://qiita.com/seigot/items/e16e9d8f6fc04853855f

https://qiita.com/seigot/items/af3cac69a5272591d4bb
閉域網でのみアクセス可能なWebページを作る

要件として話に挙がったので調べたメモ。

## S3のエンドポイントの種類

S3は`REST APIエンドポイント`と`ウェブサイトエンドポイント`の2つのエンドポイントを有する。

### REST APIエンドポイント

- 通常、S3のオブジェクトにアクセスするたいには`REST APIエンドポイント`を利用する。
- オブジェクトURLとも呼ばれるもの。
- アクセス権限が正しく設定できていないとXML形式のエラーが表示されるのを見たことがあるように`REST APIエンドポイント`ではXMLでエラーレスポンスが返る。
- `HTTPS`でアクセスできる。

### ウェブサイトエンドポイント

- S3で静的ホスティングを有効にすると`ウェブサイトエンドポイント`が利用できるようになる。
- `s3-website.<region>.amazonaws.com`といったドメイン名でアクセスでいるようになる。
- `HTTPS`に対応していない。
- インデックスドキュメントを返すことができる。

__参考__
- https://blog.serverworks.co.jp/2022/03/02/100000#REST-API-%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%A8%E3%81%AF
- https://zenn.dev/fdnsy/articles/3c3cb5e4ee5a43
- https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/WebsiteEndpoints.html#WebsiteRestEndpointDiff

## S3静的ホスティングのあれこれ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/2e19fc98-6590-ff04-c885-279fe799dc30.png)

- カスタムドメインを当てたい場合、Route53にCNAMEレコードを設定する。
- HTTPSを利用したい場合、CloudFront、ACMを噛ませる。

## 閉域網からS3でホストするページにアクセスしたい。

- DirectConnectで繋いだオンプレ環境やプライベートサブネットなどからインターネットを介さずHTTPSを利用したアクセスをする場合、CloudFrontは使えない。
- この場合ALBを利用する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/111960f8-ceae-0947-8ab9-149d1f64df0e.png)

__参考__
- https://aws.amazon.com/jp/blogs/news/internal-static-web-hosting/

## 単純にS3にアクセスしたい(オブジェクトURLにアクセスしたい)

### PrivateLink (Interface型エンドポイント) 利用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/e229107e-ddb7-dd7e-1efe-bd5889e11680.png)

__参考__
- https://dev.classmethod.jp/articles/privatelink-for-amazon-s3/

### Gateway型エンドポイント利用

S3がプライベートリンクに対応したことですでに旧来の方法となった。

__参考__
- https://dev.classmethod.jp/articles/how_to_private_connect_s3/

## 動的ページもプライベートに公開したい。

プライベートタイプのAPI Gatewayを利用することでVPCエンドポイント経由でプライベートにAPI GWにアクセスすることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/1f8d77df-ac6c-9029-b781-c63e625feb20.png)

__参考__
- https://dev.classmethod.jp/articles/apigateway-supports-vpc-endpoint/

## 認証をかけたい。

インターネット公開するよくある構成としてCognitoで認証を嚙ますが、現在CognitoはVPCエンドポイントに対応しておらず閉域網での認証には利用できない。

以下のような構成もあるものの実用できるのか、、？

https://blog.serverworks.co.jp/private-cognito
DeviseGemを使わないログイン機能の実装方法

# DeviseGemを使わないログイン機能の実装方法

Webアプリケーションにおいて、ユーザー認証機能はセキュリティとユーザーエクスペリエンスを確保するために不可欠です。しかし、すべてのプロジェクトでDeviseGemなどの認証フレームワークを使用するわけではありません。ここでは、DeviseGemを使わない基本的なログイン機能の実装方法を解説します。

## サインインとログインの基本的な仕組み

### セッションの利用

- ユーザーがログインすると、そのユーザーのIDがセッション変数に保存されます（`session[:user_id] = @user.id`）。
- ブラウザはこのセッション情報を受け取り、以降のリクエストにセッションIDを含めてサーバーに送信します。
- サーバー側はセッションIDを確認し、それに基づいてユーザーがログイン済みであるかどうかを判断します。
- ユーザーログアウトして際は、ユーザーのIDをセッションから剥奪します（`session[:user_id] = nil`）。

### カレントユーザーの設定

- セッションに保存されているユーザーIDを使用して、現在ログインしているユーザー（カレントユーザー）を取得します（`@current_user = User.find_by(id: session[:user_id])`）。

## 権限制御の実装

### ログイン確認

- 各アクションを実行する前に、ユーザーがログインしているかどうかを確認します。例えば、`if @current_user`のように条件分岐を行うことで、ログインしていないユーザーには特定のアクションを制限できます。

### ユーザー特定の権限制御

- 対象のアクションが特定のユーザーにのみ許可される場合、例えばユーザーがその投稿のオーナーであるかどうかを確認します（例: `@post.user_id != @current_user.id`）。これにより、他のユーザーが特定のデータを編集または削除することを防げます。

## まとめ

DeviseGemを使用しないログイン機能の実装は、セッションの管理とカレントユーザーの確認に重点を置きます。これにより、セキュリティを確保しつつ、アプリケーションのユーザー認証システムを独自にカスタマイズできます。また、適切な権限制御により、アプリケーションの安全性を高め、ユーザーのデータ保護に寄与します。
robots.txt入門

# robots.txt

意外と知らないかもしれない`robots.txt`に関して入門してみた。

## 概要

`robots.txt`はウェブクローラーやロボットがウェブサイトをクロールする際に、どのページやディレクトリにアクセスできるか制御するための標準的なプロトコル。このファイルによりクローラーに対して、これはアクセスしていい。もしくはアクセスしてほしくない。などと定義することができます。

## メリット

自分のサイトの重要なコンテンツを中心にクロールさせることでクロールの最適化が望めます。これによりSEO対策につながります。実際にクローラーはページのコンテンツを判断しページランクをなどを作成し検索エンジンに反映させています。

もちろん、検索エンジンには様々な指標が存在しこれらを複合的に判断し検索エンジンで上位に表示させるページを決定しているので、`robots.txt`はその構成要素の判断材料を最適化する方法のひとつでしかありません。

## 書き方

`robots.txt`は次の3つの要素で記述します。

1. User-Agent
1. Disallow（Allow）
1. Sitemap

### User-Agent

クローラーまたはロボットの識別子を指定し、特定のクローラーやロボットに対してルールを設定するために使用する。

```plaintext
User-Agent: Googlebot
User-Agent: Bingbot
User-Agent: * # すべて
```

### Disallow

特定のクローラーに対してアクセスを禁止するページやディレクトリを指定することができる。加えて、パスを指定する際に、ワイルドカード（*）を使用してパターンに一致させることもできる。

```plaintext
Disallow: /secret/
Disallow: /images/*.png
```

逆にAllowを指定することでアクセス許可することもできる。基本的にはDisallowの逆の働きをするが、すべてのクローラーやロボットでサポートされているわけではない。

### Sitemap

必須ではないが、ウェブサイトのサイトマップファイル（通常は sitemap.xml という名前）の場所を指定できる。サイトマップはクローラーにウェブサイト内のページの構造を伝えるのに役立つ。

```plaintext
Sitemap: https://sample.com/sitemap.xml
```

## 便利なツール

[robots.txt テスター](https://www.google.com/webmasters/tools/robots-testing-tool)を使用することで、robots.txt ファイルでサイト内の特定の URL に対して Google のウェブクローラがブロックされているかどうかを確認できます。たとえば、このツールを使用して、Google 画像検索に表示されないようにしたい画像の URL を Googlebot-Image クローラがクロールできるかどうかをテストできます。
[JavaScript]Setオブジェクト

:::note
`Set`オブジェクトはプリミティブ値やオブジェクト参照を問わず、あらゆる型で多数の一意の値を格納することができる。
:::

#### `Set`オブジェクトの特徴
* 値のコレクション
* 重複する値は格納できない
* その要素について挿入順で反復処理を行うことができる
    * 挿入順は、各要素が`add`メソッドで正常に挿入された順番に対応する
* `has`メソッドは、値が`Set`内にあるかどうかをチェックする

#### 関連メソッド
* `Set()`
    * 新しい`Set`オブジェクトを生成する
* `size`メソッド
    * `Set`オブジェクト内の値の数を返す
* `add`メソッド
    * `Set`オブジェクト内に同じ値を持つ要素がまだ存在しなかった場合、指定した値を持つ新しい要素を`Set`オブジェクトに挿入
* `delete`メソッド
    * `value`に関連した要素を取り除き、要素の削除に成功したかどうかを示す論理値を返す

参照

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set
条件次第でレコード分割をするSQL


ちょっと仕事の関係で、条件次第でレコード分割をするSQLを作成する必要があったので、SQLを記載しました。

## 環境
sqlite

# サンプル要件
条件分岐でレコードを増やすSQL
   増殖条件：①山と川がそろう：＝＞連番１では山、連番２では川を表示
   　　　　　②AとBがそろう：＝＞連番１ではA、連番２ではBを表示
   　　　　　③exampleのいずれかを複数持っている。
        　　　　　　　：＝＞ A , B, C の順番にいづれか出力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319265/4a85f3a4-1cfe-9f0c-c720-323d683cdd5c.png)

上記のようなテーブルから、以下の結果を出すような感じのSQLですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319265/b3958d84-a35d-6beb-2150-9dacdfd80de7.png)


## SQL
```sql
/*条件分岐でレコードを増やすSQL
   増殖条件：①山と川がそろう：＝＞連番１では山、連番２では川を表示
   　　　　　②AとBがそろう：＝＞連番１ではA、連番２ではBを表示
   　　　　　③exampleのいずれかを複数持っている。：＝＞ A , B, C の順番にいづれか出力する。
   
*/
WITH seq(num) as ( 
    select
          * 
    from
        (   values (1) 
            union 
            values (2) 
            union 
            values (3) 
            union 
            values (4)))
SELECT
      cast("id" as integer) as id 
    , seq.num as num
    , substr(coalesce("mount",' ')
                  ||coalesce("river",' ')
             , seq.num , 1 ) as "山川" 
    , substr(coalesce("A",' ')
                  ||coalesce("B",' ')
             ,seq.num,1) as AB                               

    , substr(coalesce("example_A",'')
                  ||coalesce("example_B",'') 
                  ||coalesce("example_C",'')
             ,seq.num , 1 ) as example
    , "biko" 

FROM
    "test" as t
   left join seq 
     on seq.num <= (case when
                     --  exampleA～Cが複数ある場合はそれぞれ複数行を返す。(最大3レコード)
                           (case when   t.example_A = 'A' then 1 else 0 end  
                            + case when t.example_B = 'B' then 1 else 0 end
                            + case when t.example_C = 'C' then 1 else 0 end) >= 2
                        AND (case when   t.example_A = 'A' then 1 else 0 end  
                             + case when t.example_B = 'B' then 1 else 0 end
                             + case when t.example_C = 'C' then 1 else 0 end) <= 3 
                        then (case when   t.example_A = 'A' then 1 else 0 end  
                             + case when t.example_B = 'B' then 1 else 0 end
                             + case when t.example_C = 'C' then 1 else 0 end)
                    when 
                     -- AとBが両方そろった場合2レコードを返す（最大2レコード）
                        t.A = 'A' AND t.B = 'B' then 2
                    when 
                     -- 山と川が両方そろった場合2レコードを返す（最大2レコード）
                        t.mount = '山'  AND t.river = '川' then 2
                    else 1
                end) 
                    
order by id, num       

```

ねっ、簡単でしょ。
やってる技術はjoinとsubstrとかだけだからそんな難しくないよ。多分。

説明は……いる？？
多分、説明なくても問題ないと思うけど要望があったら解説する。
モーショントレイルを使って遊ぶ　２

2023年のアドベントカレンダー１つめですね。


さて、去年のアドベントカレンダーのネタでこんなのを書きました

https://qiita.com/9boz/items/0d6520e6999a6ea25347

ここからさらにちょっと手を加えて、軌跡をナーブスカーブで表現させてみます。

まず前回のところまで組んで・・・
-
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/b58cc370-f959-7448-f02b-dbc46956f598.png)

motionTrailノードにあるstartTime / endTime
これをちょっと加工します。

startTimeをendTimeに近づけるとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/7161bda0-5aa5-771a-4d81-09b4a83ea198.png)

endTimeをstartTimeに近づけるとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/fed1daab-f8ce-1663-4bba-77198de9a2f9.png)

これを踏まえた上で

加工
-
今回は尾っぽの様に一定のフレーム分だけカーブを表示させたいので・・・

**endTimeを現在のフレームに設定する**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/d6137536-cefe-c14a-4eed-837da179fee7.png)

**現在の位置から一定フレーム分前だけ表示**
endTimeから一定フレーム数だけ引いたものをstartTimeへ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1484234/cbff7896-1f29-d578-8b41-dd00829d902d.png)

とりあえず15ｆ分くらい尾を引かせてみる
https://vimeo.com/manage/videos/888036076

とりあえずできました
いえーい
https://vimeo.com/manage/videos/888037776

何に使えるかですが・・・・

-車のテールランプの軌跡
-カメラの集中線
-ブラー表現

とかですかねぇ
ま、何かには使えそうですね！
「System.InvalidOperationException: PE image does not have metadata.」が発生したときの対処法

#### 参考記事
https://stackoverflow.com/questions/75907689/cause-for-xabba7009-system-invalidoperationexception-pe-image-does-not-have-m

#### 事象
- .NET MAUIの環境構築で、どっかのタイミングでAndroidを起動しようとしたときに以下のような`PE image does not have metadata.`といったエラーが表示されました。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711955/789abdd0-2a83-1210-c1b2-10085f9826cb.png)

#### 修正方法
- NugetパッケージにインストールしていたSystem.Data.SQLiteを削除するとうまく起動できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711955/00eb3fd8-1f90-5c50-3003-597245c69c72.png)
Java HotSpot仮想マシンの汎用オプション

## -Xmixed
ホット・メソッドのJITコンパイルとバイトコードのインタプリタ実行を両方も有効にする。
## -Xint
ホット・メソッドのJITコンパイルは無効になり、すべてのバイト・コードがインタプリタによって実行される。
## -Xcomp
バイトコードのインタプリタ実行は無効になり、すべてのコードがJITコンパイルによって実行される。
## コマンド確認
- defaultがmixed mode
```shell-session
C:\Users\XXXXX>java -version
java version "11.0.17" 2022-10-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.17+10-LTS-269)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.17+10-LTS-269, mixed mode)
```
- -Xint
```shell-session
C:\Users\XXXXX>java -Xint -version
java version "11.0.17" 2022-10-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.17+10-LTS-269)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.17+10-LTS-269, interpreted mode)
```
- -Xcomp
```shell-session
C:\Users\XXXXX>java -Xcomp -version
java version "11.0.17" 2022-10-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.17+10-LTS-269)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.17+10-LTS-269, compiled mode)
```
- -Xmixed
```shell-session
C:\Users\ts-xinrong.deng>java -Xmixed -version
java version "11.0.17" 2022-10-18 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.17+10-LTS-269)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.17+10-LTS-269, mixed mode)
```
CDの廃棄についての情報

**問：CDを傷つけて捨てるの面倒なんで、そのまま捨てても良いですか？**
CDを切断できるシュレッダーのない場所であがるこんな声もある。
「面倒だし、そのまま捨てれば良いんじゃない」
「機密情報とかないし、そのまま捨てようよ」
***


***回答：それで良いかどうか調べるの時間かかるので、さっさとCDのデータを壊して廃棄した方が無難***
市販のインストールCDでインストールするときプロダクトキーを求められるので、情報が拡散することもないだろうと思ったが
使用上の契約でCDを完全に廃棄する契約がないとは言い切れない。20～30分かけて調べたが、CDの完全廃棄を求める契約の存在を示す記事はネット上に転がっていなかった。
つまりだ、「無い事を証明する」ってのは膨大に時間がかかるので、どちらかというと個別の契約に目を通してCDを廃棄するかどうかが早い。
そして、個別の契約に目を通すよりも、傷をつけるなり、シュレッダーにかけた方が話しは早い。
そんなわけで、CDを捨てるときはシュレッダーにかけるか、ハサミで切断したほうが無難という面白くない結論になった。

****
CDの構造から考える、CDデータの壊し方

**【CDの構造】:記録している層をサンドイッチしている**
CDの素材は、プラスチックと金属(アルミニウム)
本体は、アルミニウムの部分でこいつの前に透明なプラ板が貼ってあり、上から保護層(何かよく分からない)でサンドイッチしている。
つまり、透明なプラスチック越しに反射しているところが本体で、それをレザーで読めるように透明の板と何かの保護膜で守っているようだ。
プラ板は多少傷ついても大丈夫だけど、保護膜の方はあからさまに薄いので、そこを深めに傷つければデータは破損する。

**【CDのデータの壊し方】：ラベル側にキズを入れる**
上記の構造から、ラベル側(光ってない方)をカッターとかはさみで傷をつければデータが壊れる。
もっとも手っ取り早しのはシュレッダー。

****



**参考**
[キヤノンサイエンスラボ CDとDVD](https://global.canon/ja/technology/s_labo/light/003/06.html#:~:text=CD%E3%81%AE%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%81%AF3,%E3%83%A1%E3%83%BC%E3%83%88%E3%83%AB%E3%81%AE%E5%87%B9%E5%87%B8%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)
[CDの捨て方](https://one-up-life.com/single-item/cd-disposal/)
【HTML】fromの外側にsubmitボタンを設置する

以下のように`form`要素の`id`を`button`要素の`form`属性に記述することでフォームと送信ボタンを関連づけられます。

```html
<form id="sample">
  <label>
    メールアドレス
    <input type="email">
  </label>
  <label>
    パスワード
    <input type="password">
  </label>
</form>
<button type="submit" form="sample">送信</button>
```
docker環境でWordPressを立ち上げ→セットアップ画面が出ずに白い画面しか出ない、、

# 環境
- mac m1
- docker-compose v2.17.2

# 作業
以前docker環境でwordpressを立ち上げたことがあるのでサクっと構築できるだとうと思ったらなんか上手くいかなかったので原因と対処法を記事にしました。

とりあえず以前行った通りに作業ディレクトリを作成して、docker-compose.ymlファイルに公式のテンプレに少しアレンジを加えて進行しました。

https://docs.docker.jp/compose/wordpress.html

### ファイル構成
```
作業ディレクトリ
├── docker-compose.yml
└── 保存先ファイル（任意の命名）
```

```docker-compose.yml
version: '3.7'

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress-contant
    depends_on:
      - db
    ports:
      - "8000:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./保存先ファイル名:/var/www/html
  db:
    image: mysql:5.7
    platform: linux/amd64 //mac m1のみ必須
    container_name: wordpress_mysql
    ports:
      - "1255:3306"
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

volumes:
  db_data:
```
いざターミナルで起動！
`$ docker-compose up -d`
しっかり保存先にファイルがダウンロードされているのを確認し、
http://localhost:8000/
にアクセスしたら、、

あれ、セットアップ画面が表示されないどころか、画面が真っ白、、wordpress特有のエラー文が見えないので何が原因か全く分からず、、dockercontainerもしっかり走っているのになぜた。。
とりあえず何回も消しては起動の繰り返しをしていました。。

# 原因と対処法
一晩寝て冷静に考えた結果、以前作成した際のセットアップ設定が残っているせいで表示されないのではと予想した。
なのでパスをhttp://localhost:8000/wp-admin/index.php
管理者画面に直接いくように変換し、アクセス。

![スクリーンショット 2023-11-24 23.38.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627919/2b830a13-85fd-ca78-b860-28ddb021acbc.png)

無事いつもの管理者画面が表示された😭

# 感想
一番最初に、前に設定したセットアップが残らないようにdockerimageなどを削除して作業したのにこのようなことが起こったので、それだけではダメなんだと分かった。このセットアップの情報はどこに保存されているのか。。これについて調べるのはまた今度にしよう。
Elementary-OSでブラウザが真っ白

## 問題
初めてのノートパソコン改造チャレンジで、Elementary-OSを入れたはいいものの、初期状態で入っている「Web」というブラウザ？では検索しかできず、ページを開いても真っ白になるだけだった。

## 解決
どうやら結局ちゃんとしたブラウザを入れたほうがいいらしい。いや後で入れるつもりだったけどさ。

コマンドラインからおなじみのGoogle Chromeをインストールする。


https://www.wikihow.jp/Linux%E3%81%AE%E3%82%BF%E3%83%BC%E3%83%9F%E3%83%8A%E3%83%AB%E3%81%8B%E3%82%89Google-Chrome%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B

こちらの記事を参考にした。

```bash:1. .debファイルをダウンロード
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
```

```bash:2. ダウンロードした.debファイルをインストール
sudo dpkg -i google-chrome-stable_current_amd64.deb
```

途中でエラーになったので、記事のとおり次のコマンドを発行した。
これは依存関係を解決してくれるっぽい。

```bash (3. エラーになったので)
sudo apt-get install -f
```

ここまで実行すると、Chromeを右上の「🔍アプリケーション」から開くことができた。

あとは、Chromeからお好みでEdgeやらFirefoxやらをインストールすればいいと思う。

Microsoftはいい加減に、packages.microsoft...のページ勝手に消すのやめてほしいね。

https://elementary.io/ja/

```
sudo apt-get update
sudo apt-get upgrade
```
も忘れずに（）。
REST APIとは

# REST APIとは
REST API（Representational State Transfer API）は、Webアプリケーションやサービス間のインタラクションを容易にするためのプログラミングインターフェースです。これは、リソース（データや機能）をWeb上で表現し、HTTPメソッド（GET、POST、PUT、DELETEなど）を使用してアクセスすることができます。

# RESTの6つの原則
RESTはHTTPの設計者の1人であるRoy Fieldingが2000年に提唱したAPIの設計の考え方であり、以下の6つ原則があります。
- クライアント/サーバー構造：システムはクライアントとサーバーに分離されており、それぞれ独立して機能します。これにより、フロントエンドとバックエンドの開発が独立して進められます。

- ステートレス:それぞれのリクエストは独立しており、過去のリクエストの情報をサーバーが保持する必要はありません。クライアントからの各リクエストには、それを理解し処理するのに必要なすべての情報が含まれています。

- キャッシュ可能: システムの応答は、パフォーマンス向上のためにキャッシュ可能であるべきです。適切に管理されたキャッシュは、クライアント-サーバー間のやり取りを減らし、効率を高めます。

- 統一インターフェース: シンプルで一貫性のある方法でウェブサービスを利用するためのルールです。この原則に従うことで、異なるシステムやアプリケーションが同じ方法でデータや機能にアクセスしやすくなります。

- 階層化システム: クライアントは通常、エンドポイント以外のネットワークの構造について知らなくても済みます。これにより、システムはより柔軟に構成され、スケールアウトやロードバランシングが容易になります。

- コードオンデマンド: サーバーは必要に応じて実行可能なコード（JavaScriptなど）をクライアントに送ることができます。

# URIとHTTPメソッド
REST APIでは、リソース（例えばデータベース内のレコードや特定のサービス機能）はURI（Uniform Resource Identifier）を通じて識別されます。そして、HTTPメソッド（GET、POST、PUT、DELETEなど）を使用して、それらのリソースに対して操作を行います。以下は各HTTPメソッドの対応表となります。

| HTTPメソッド | 概要                                |
|-------------|------------------------------------|
| GET         | リソースの読み取りや取得に使用    |
| POST        | 新しいリソースを作成するために使用 |
| PUT         | 既存のリソースを更新するために使用 |
| DELETE      | リソースを削除するために使用       |

# REST APIの実装例
例として、「movie」というリソースを対象にしたREST APIを考えます。このAPIでは、映画に関する情報の作成、読み取り、更新、削除（CRUD操作）が可能です。これらの操作は次のようなURIとHTTPメソッドを使用して定義されます。

| URI                | HTTPメソッド | 概要 |
|--------------------|-------------|-------------|
| /movies            | POST        | 映画を作成    |
| /movies            | GET         | 映画のリストを取得    |
| /movies/{movie_id}  | GET         | 特定の映画を取得    |
| /movies/{movie_id}  | PUT         | 特定の映画を更新    | 
| /movies/{movie_id}  | DELETE      | 特定の映画を削除    | 

ここでは、{movieId}は特定の映画を識別するためのユニークなIDを表します。URIはリソースを指し示し、HTTPメソッドはそのリソースに対してどのような操作を行うかを示します。例えば、POST /moviesは新しい映画を作成し、GET /movies/{movieId}はIDに基づいて特定の映画の詳細を取得します。
【Unity】Swift のネイティブプラグインに options を渡す方法

## 本記事について

この記事は [CoreBluetoothForUnity Advent Calendar 2023](https://qiita.com/advent-calendar/2023/core-bluetooth-for-unity) の22日目の記事です。

CoreBluetooth ではいくつかのメソッドにおいてオプションを渡すことができます。

[init(delegate:queue:options:)](https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1519001-init)

```
init(
    delegate: CBCentralManagerDelegate?,
    queue: dispatch_queue_t?,
    options: [String : Any]? = nil
)
```

このような文字列キーの辞書を Unity からネイティブプラグインに渡す方法を説明します。

## 実装

[CBCentralManagerInitOptions](https://github.com/teach310/CoreBluetoothForUnity/blob/0.4.6/Packages/com.teach310.core-bluetooth-for-unity/Runtime/CBCentralManagerInitOptions.cs)

```CBCentralManagerInitOptions.cs
public class CBCentralManagerInitOptions
{
    public static readonly string ShowPowerAlertKey = "kCBInitOptionShowPowerAlert";
    public bool? ShowPowerAlert { get; set; } = null;

    public CBCentralManagerInitOptions()
    {
    }

    internal NSMutableDictionary ToNativeDictionary()
    {
        var dict = new NSMutableDictionary();
        if (ShowPowerAlert.HasValue)
        {
            using var value = new NSNumber(ShowPowerAlert.Value);
            dict.SetValue(ShowPowerAlertKey, value.Handle);
        }
        return dict;
    }
}
```

```CBCentralManager.cs
public CBCentralManager(ICBCentralManagerDelegate centralDelegate = null, CBCentralManagerInitOptions options = null)
{
    if (options == null)
    {
        _handle = SafeNativeCentralManagerHandle.Create();
    }
    else
    {
        using var optionsDict = options.ToNativeDictionary();
        _handle = SafeNativeCentralManagerHandle.Create(optionsDict.Handle);
    }
...
}
```

Options クラスから `ToNativeDictionary` で `NSMutableDictionary` を生成し、そのハンドルを渡しています。
`using` によって使い終わったらすぐ破棄しています。

## ポイント
### キー名の調べ方

[ドキュメント](https://developer.apple.com/documentation/corebluetooth/cbcentralmanageroptionshowpoweralertkey)に載っていないため、print で出力しました。

動的に取得していない理由は、定数を取得するためだけのコードを書くのが手間だったためです。

### NSMutableDictionary

[NSMutableDictionary.cs](https://github.com/teach310/CoreBluetoothForUnity/blob/0.4.6/Packages/com.teach310.core-bluetooth-for-unity/Runtime/Foundation/NSMutableDictionary.cs)

インスタンス作成と同時にアンマネージドなオブジェクトを生成し、インスタンスメソッドによって更新しています。

`IDictionary`等のインタフェースについては得に必要ではなかったため実装していません。

## 参考

Xamarin の [DictionaryContainer](https://learn.microsoft.com/en-us/dotnet/api/foundation.dictionarycontainer?view=xamarin-ios-sdk-12) Class

## おわりに

Foundation について知る前は、どうやってやるのか分かりませんでしたが知った後は割とすんなりできました。
汎用的な仕組みだと思うため、もし似たようなケースあればぜひ利用してみてください！