OmniAICreator/Qiita-1.07M huggingface dataset:
OCS2023で教育SGの取り組みを紹介しました


## イントロダクション
こんにちは、米嶋です。先日のOpen Compliance Summit 2023において、我々教育SGの活動発表を行いました。

![IMG_0900 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778231/85c45038-70b8-952d-3cb9-704e2693ece3.jpeg)

教育SGはOpenChain JWGの有志グループで、OSSに関わる教育資料を策定しています。

この1年間、我々は教育資料の応用編と英語版の作業を進めてきました。その活動が一段落ついたところで、今回のイベントをお披露目の場として活用させていただきました。

教育SG自体に関しては、7日に公開された[小泉さんから説明](https://qiita.com/koizumistr/items/e2efcaafe3660cc574b0)がありますので、ぜひそちらもご覧ください。

**講演情報**
[Creating OSS Educational Materials for Developers Who Actually Use OSS](https://ocs2023.sched.com/event/1Tbwz/panel-discussion-regional-activity-creating-oss-educational-materials-for-developers-who-actually-use-oss-ayumi-watanabe-hitachi-hiroyuki-fukuchi-sony-group-corporation-satoru-koizumi-olympus-corp-yoshiko-ouchi-fujitsu-taishi-yoneshima-nec-co?iframe=no)
講演資料はページ内に添付されています。

## 今回の講演メッセージ
大まかに以下の通りです。
1. 活動の背景
2. 各章のトピック
3. 今後の展望

順に説明していきます。

## 教育資料作成の背景
この点は7日の記事でも触れていますが、OSSに関する共有知を集めてオープンにすることが、私たちの教育資料作成のモチベーションです。教育SGには各社から多様な立場のメンバーが集まっており、OSS教育の基礎編や応用編の各プログラムを検討してきました。当初検討の際は、各社から既存資料を持ちより活用する始め方をしましたが、以後の新たな部分を検討する際は各有識者に執筆してもらう進め方にしています。

**取り組んでいる教育資料**
[OpenChain-JWG](https://github.com/OpenChain-Project/OpenChain-JWG/tree/master)
Education_Materialに順次格納していきます。

私自身、社内でOSS教育資料を検討する立場にありますが、こういった共有知は非常に有益だと思っていて、うまく役立ててもらえればよいものだと考えています。

## 資料の特色
発表で説明した内容から、以下2点の特色を紹介します。

**・セキュリティ、SBOMの領域に踏み込んだ内容**
OSSを活用する際にそのライセンスの理解が一つ課題としてあり、このライセンスに関する教育資料は教育SGから過去に公開を行ってきたことがあります。今回の資料ではこのOSSライセンス問題の他、OSSのセキュリティに踏み込んだ内容になっています。昨今、著名なOSSの脆弱性問題からOSSのセキュリティに対する関心が高まっていますので、それに対する教育資料として活用を検討していただければ良いと思います。SBOMに関しても知識習得の需要はあがっているので同様に活用を検討してみてください。


**・初心者を想定した教育資料**
これらの資料は、OSSの取り扱いに長けていない方にも有益に使って頂けるよう、クイズ形式としたり、イメージし易いよう図で示したり、優しい資料の作成を心がけています。またユースケースを想定した構成としていて、例えばライセンスの観点ではライセンスの調査方法や製品文書や各契約書類に記載すべき内容も記載しています。

一方で、個社で対応や解釈が分かれるような内容はこれらの資料内には記載がされていませんので、こういった特色を理解してご活用を検討してみてください。


## 今後の展望
来春を目処に今回発表した応用編の完成を目指しています。また今回の発表をきっかけに英語圏の方からの協力も得て、多言語対応もできたら良いということも発信しました。コンテンツ自体の拡充も継続的な展開を行っていきたいと考えています。


## さいごに
OpenChainはオープンなコミュニティ形成を目指しており、私たち教育SGもそのポリシーのもと活動を展開しています。フィードバックは大歓迎です。また、私たちの活動に興味がある方がいらっしゃいましたら、お気軽に声をかけてください。

さいごに、今回の教育資料策定に尽力頂いた皆様、そして今回の素晴らしい講演を一緒に作り上げてくださった皆様、ありがとうございました。
Goで実装する基本ソートアルゴリズム

## アルゴリズムとは

アルゴリズムはある目的を達成するための決まった操作のことです。

例えば目的を任意の3つの整数の中で最大のものを取得するとした場合、以下の操作で目的が達成できます。

1. 各整数を任意の順に並べる
1. １つ目と２つ目の整数の大小を比較して大きい方を取り出す
1. 取り出した整数と３つ目の整数の第上を比較して大きい方を取り出す

これも立派なアルゴリズムです。

上記の整数の個数が10でも100でも3の操作を整数の個数分繰り返して行くと最大が得られます。

## ソートアルゴリズム

アルゴリズムの中でデータを一定の規則に従って並べるアルゴリズムです。

複数の整数がランダムに並んだ状態からある順番に並べ直す

先ほど紹介した最大を取得するを少し発展させて昇順に並べ替えることを目的としてGoのコードを見ていきます。

## ソートアルゴリズムの種類

今回はすべて昇順になるように並べます

### バブルソート

最も基本的なソートアルゴリズムで、隣接する要素を比較して順序が間違っていれば交換するという操作をします。これを繰り返すことで、最大の要素がリストの一方の端に"浮かび上がる"ことからこの名前がついています。

Goのソースコードは以下のようになります。

```go
func bubbleSort(numbers []int) {
	for i := 0; i < len(numbers)-1; i++ {
		for j := 0; j < len(numbers)-i-1; j++ {
			if numbers[j] > numbers[j+1] {
				numbers[j], numbers[j+1] = numbers[j+1], numbers[j]
			}
		}
	}
}
```

バブルソートは他の配列などのメモリが必要がないin-placeアルゴリズムで、計算量は最悪/平均ともにO(n ^ 2)です。

### 選択ソート

リストの中から最小の要素を見つけ、それをリストの一方の端に移動します。移動済みの要素はソート済みとしてソートしていないリストに対してこれを繰り返すことで、リスト全体がソートされます。

Goのソースコードは以下のようになります。

```go
func selectionSort(numbers []int) {
	lenNumbers := len(numbers)
	for start := 0; start < lenNumbers; start++ {
		tmpIndex := start
		for i := start; i < lenNumbers; i++ {
			if numbers[tmpIndex] > numbers[i] {
				tmpIndex = i
			}
		}
		if tmpIndex != start {
			numbers[tmpIndex], numbers[start] = numbers[start], numbers[tmpIndex]
		}
	}
}
```

選択ソートはin-placeアルゴリズムで、計算量は最悪/平均ともにO(n ^ 2)です。

### 挿入ソート

リストをソート済み部分と未ソート部分に分け、未ソート部分の要素を一つずつソート済み部分の適切な位置に挿入していきます。

Goのソースコードは以下のようになります。

```go
func insertionSort(numbers []int) {
	lenNumbers := len(numbers)
	for i := 1; i < lenNumbers; i++ {
		temp := numbers[i]
		j := i - 1
		for j >= 0 && numbers[j] > temp {
			numbers[j+1] = numbers[j]
			j--
		}
		numbers[j+1] = temp
	}
}
```

挿入ソートはin-placeアルゴリズムで、計算量は最悪/平均ともにO(n ^ 2)です。

## 動作チェック

[Playground](https://go.dev/play/p/KnSMaJH-kZZ)にソースを置いておきました。

興味ある方は動かしてみてください。
ローコード開発の未来：AIとの融合と市場の拡大

## はじめに
最近、ソフトウェア開発の世界で注目を集めているのが「ローコード開発」です。
この記事では、ローコード開発の現状と未来の展望について、特にAIとの融合と市場の拡大に焦点を当てて考えてみたいと思います。

## ローコード開発とは？
ローコード開発は、できる限りソースコードを書かずにシステムやアプリケーションを開発する手法です。
GUI上であらかじめ用意された画面の部品やロジックの部品を組み合わせることで、迅速かつ効率的に開発を進めることができます。
必要に応じてコードを書くことも可能で、カスタマイズ性も備えています。

## 市場の拡大
近年、ローコードの採用は企業レベルで増加しており、ミック経済研究所の報告によると、2023年にはローコード開発市場が4560億円に達し、年平均16.3%の成長が見込まれています。
これはIT人材不足やデジタルトランスフォーメーション（DX）の推進がこの背景にあります。

## ローコードとAIの融合
ローコードは学習コストが低く、非技術者にも開発の門戸を開いていますが、ある程度のIT知識を要するのが現状です。
しかし、近年目覚ましい成長を遂げるAIと組み合わせて活用することで、ローコード開発はさらに手軽になり、より多くの人々が開発に参加できるようになると予想されます。
例えば、AIに自然言語で指示を出せば、アプリの開発から実行までをAIが担う日も近そうですね。

**AIを組み込んだツールの例**

|   | Power Apps | Copilot	SQL AIアシスタント（Dash Comb） | AppSheet | 
| ---- | ---- |---- |---- |
| できること | ・会話形式でのアプリ開発<br>・会話形式でのアプリ分析 |・SQLクエリの生成<br>・自然言語によるSQLクエリの改善 | ・会話形式でのアプリ開発<br>・脆弱性やエラーの特定から修正まで<br>・サービスや開発手法に関するアドバイス| 
| 対応プラットフォーム | ・Power Apps<br>・Microsoft 365 | ・Dash Comb <br>・SQLデータベース | ・AppSheet <br>・Google Workspace |

[参考：ローコードとGenerative AIの融合](https://weel.co.jp/media/generative-ai-by-low-code)



## まとめ
この記事では、ローコード開発の基本から将来の展望、特にAIとの融合に焦点を当てて紹介しました。
ローコード開発の未来は、AIとの統合によって大きな変革を遂げようとしており、エンジニアだけでなく、幅広い層にとっても、ローコード開発の可能性は大きく広がっています。

しかし、複雑なアプリの開発にはまだ時間がかかるのが現状です。
多様なツールが登場している黎明期なので、どのツールが市場で生き残るかなどの動向も注視しながら効果的に活用していきたいですね。
この記事がローコード開発の現状と将来性についての理解を深める一助となれば幸いです。

## 参考資料
[ローコード開発市場は2023年度に4560億円、年平均16.3％で成長─ミック経済研究所](https://it.impress.co.jp/articles/-/19734)
[ローコードとGenerative AIの融合]()
5分で完全に理解するKerberos認証

~この記事はかろ噴水・ゆるゆる Advent Calendar 2023 に参加しています~
https://adventar.org/calendars/9062

# はじめに
この記事は「ケルベロス認証の名前は知っているけれど、仕組みはよくわからない」という人向けの記事です。
身近な例を使って仕組みを解説をします。具体的には、スーパー銭湯の例を使います。

厳密な解説は既に多数あるので、後述の参照も見てみてください。

## Kerberos認証とは
オンプレミスのActive Directroyで用いられる認証です。（Azure ADとは別物です）
一度ログインすれば、次回以降はIDとパスワードの入力なしでログインし、サービスを利用できるようになります。

## Kerberos認証のイメージ
認証フローを図解すると以下のようになります。
複雑で読み込むのには時間がかかるので、Kerberos認証っぽい別のイメージを流用して理解した方が早いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411116/ded732f5-424c-1e3e-e0d4-c0517a6b8f40.png)
https://learn.microsoft.com/ja-jp/troubleshoot/windows-server/windows-security/kerberos-authentication-troubleshooting-guidance

## Kerberos認証っぽいもの
突然ですが、スーパー銭湯の認証はKerberos認証によく似ています。
### Kerberos認証
一度ログインすれば、次回以降はIDとパスワードの入力なしでログインし、サービスを利用できるようになります。

### スーパー銭湯の認証
一度入館時に身分証や会員証を提示すれば、以降は提示無しで岩盤浴やマッサージなどのサービスを利用できます。

## スーパー銭湯の認証のイメージ

スーパー銭湯で岩盤浴などを利用する時の認証フローを書きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411116/9f5a6368-0aaa-95f5-e658-a61a2d23668d.png)

### Kerberos認証との対比

Kerberos認証では、一度PCログイン時にパスワードを入力すると、端末内にTGTチケットが保存されログイン済みであることが記録されます。
その後、IIS/メールサーバ/ファイルサーバ などのサービスを使う際には端末内のTGTをADに見せると、ADはサービスを利用するためのそれぞれのTGSチケットを引き渡します。
ただし、ユーザがサービス利用権限を持っていない場合は無効なTGSチケットを引き渡します。

スーパー銭湯の認証では、一度入館すると腕輪や入館券が渡されて、入館手続き済であることが記録されます。
その後、岩盤浴などを利用する際は別途チケットをもらいます。

## まとめ
Kerberos認証ではユーザにTGTチケットとTGSチケットを渡します。
TGTチケットはパスワード入力が必要です。
TGSチケットはTGTチケットをADに見せる（自動）だけでよいのでパスワード入力不要です。
IIS/メールサーバ/ファイルサーバ　などの各サービス毎にTGSが引き渡されます。


# おまけ

## AS-REP Roasting攻撃
一般ユーザとは異なる、サービス管理アカウントなどに対しては、パスワードなし（つまりユーザ名のみ）でTGTチケットを引き渡す運用にしているケースがあります。
それを利用し、TGTを入手する攻撃をAS-REP Roasting攻撃と呼びます。

これはスーパー銭湯で例えると、「清掃員は顔パスで入館チケットを与える」ようなイメージです。
「清掃員です」と名乗ったらスーパー銭湯に入館できるようなものです。

## Kerberoasting攻撃
ポイントは2つあります。

### ポイント1
ユーザがADにTGSチケットを要求した際に、ユーザがサービス利用権限を持っていない場合は無効なTGSチケットを引き渡します。
無効ですが、TGSチケットはもらえるというのがポイントです。

### ポイント2
TGSチケットには無効/有効のステータスやタイムスタンプなどの情報が含まれており、当然暗号化されています。
更に、暗号化の仕様上、サービス管理アカウントのパスワードハッシュがTGSには含まれます。


### 攻撃フロー
ポイント1・2を組み合わせると以下の攻撃フローが考えられらます。
1. TGTを入手する
1. TGSを入手する（無効でもよい）
1. TGSの中のサービス管理アカウントのパスワードハッシュを解析しパスワードを入手する
1. サービス管理アカウントのユーザ名・パスワードを利用してログインする


# 参照
https://learn.microsoft.com/ja-jp/windows-server/security/kerberos/kerberos-authentication-overview
https://qiita.com/sathis/items/42ba8157537becdb9788
https://wa3.i-3-i.info/word15908.html
Mobile Safariでinput type="file"をjsのclick()で開くと、onchangeが発火しない問題

## 環境
iPhone 11 Pro
iOS 17.1.2

## 発生している問題の概要
Mobile Safariでカメラロールから読み込むための`<input type="file">`を、
JSから`click()`で発火すると、onchangeが発火しない

## やりたいこと
iPhoneから画像をアップする

読み込みボタンを押すなりしたら読み込みダイアログを出して、
選んだ画像を返すようなメソッド、`showOpenImageDialog()`を作る

## 動かないソース
```
function showOpenImageDialog() {
	return new Promise(resolve => {
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = 'image/*';
		input.addEventListener('change' , (event) => {
			resolve(event.target.files[0]);
		});
		input.click();
	});
}
```

### やっていること
`input`の`DOM`を作り、`type`を`file`、今回は画像なので`accept`に`image/*`を設定。
`onchange`の中にはファイルを返して`resolve`する処理を記述
その後`click()`で発火する

## 発生事象
`input.click()`で読み込みダイアログは開く
カメラロールから画像を選択は出来るが、何のエラーも出ず、
ただただ`onchange`の内容が発火しない。

※他のブラウザでは問題ない

## 動いたソース
```
function showOpenImageDialog() {
	return new Promise(resolve => {
		const input = document.createElement('input');
		input.type = 'file';
		input.accept = 'image/*';
		input.addEventListener('change' , (event) => {
			resolve(event.target.files[0]);
		});
		input.click();
		document.body.onfocus = () =>{
			setTimeout(() =>{
				if(input.value == ""){
					resolve(null);
				}else if(input.value == null){
					resolve(null);
				}else {
					
				}
				document.body.onfocus = null;
			},1000);
		}
	});
}
```

## なぜこれで動くか
謎です。だれか教えてください。

推測ではMobile Safari(たまにSafariでも)ではフォーカス状態のままになってしまい、
フォーカスが解除されないと、値が変化せず`onchange`は発火しないのでは？と思います。

ので、1秒後とかにフォーカスを外す処理を挟むことで、値の変化が反映される？

## 2023/12/06 追記
`change`ではなく`input`を使えば動くとのことでした。
フォーカスの機構を外して試してみると、動いたり動かなかったり、たまに検知漏れするようです。
changeと違って動くこともあるので、inputの方が良いかもしれませんが、、
AWSのStepFunctionsを利用してLambdaを動的並列処理させる方法

# 概要

前処理にて終了パラメータ個数分Lambdaを並列処理実行させることを実装するにはどうしたらいいかと調べつつできたのでメモしておく。

例えば、前処理にてS3へPUTしたファイルの複数のパスを後続へ渡し、各Lambdaがそれぞれの1つのファイルパスを受け取り処理をしたい場合に有効である。
今回はこちらを例にして説明する。

# StepFunctionsのワークフロー
![スクリーンショット (334) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/355599/65b14f3f-b04e-8e0e-4e58-e23ea5717645.png)
イメージは先ほども言ったが、

①Lambda Invokeで分割した複数ファイルをS3へPUTしたKeyをパラメータで後続に渡す

②並列処理を実行するパラメータをそれぞれLambda Invoke_2に渡す

③Lambda Invoke_2の処理を実行する

# 実装方法

## 1. test_Invokeの作成

```python
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': 'Hello from Lambda!',
        'count_list': [
                    {"count":"3"},
                    {"count":"21"},
                    {"count":"39"},
                    {"count":"40"},
                    {"count":"52"},
                    {"count":"60"}
                    ]
    }
```

<aside>
⚠️ StepFunctionsにて設定するMapが受け取れるのはリスト型のみ。
なのでKey:Value型で後続が受け取りたい場合は上記のcount_listのようにリスト形式にすること

</aside>

## 2. test_Invoke_2の作成

```python
import json

def lambda_handler(event, context):
    
    print(event["count"])

    # return {
    #     'statusCode': 200
    # }
```

今回は前処理で渡ってきたパラメータを受け取り出力する。（6個のtest_Invoke_2が並列で起動する想定）

## 3. StepFunctionsのステートマシーンの作成と設定

今回は「**test_function**」という名前でステートマシーンを作成する。

①「ステートマシーンの作成」をクリック

②タイプは標準で「次へ」

③ワークフロー設計にて１つめのAWS Lambda InvokeをD&D

<設定>

状態名：Test Invoke

API パラメータのFunction nameの入力を選択して**test_InvokeのARN**をC&P

その他の入力・出力・エラー処理設定はそのまま。

④ワークフロー設計にてTest Invokeの下にMapをD&D

<設定>

状態名：Map

項目ソースの項目配列へのパスを指定 - *省略可能にチェックを入れ以下を入力*

<aside>
💡{% $states.input.Payload.count_list%}

</aside>

その他の入力・出力・エラー処理設定はそのまま。

⑤ワークフロー設計にて２つめのAWS Lambda InvokeをD&D

<設定>

状態名：Test Invoke 2

API パラメータのFunction nameの入力を選択して**test_Invoke_2のARN**をC&P

その他の入力・出力・エラー処理設定はそのまま。

## 実行

StepFunctionsのステートマシーン**test_function**の「実行の開始」をクリックして実行し、CloudWatchよりログを確認してみる。無事に受け取ったパラメータ個数分のLambdaが起動していて各パラメータを出力できていることが確認できるはず。
【Devise】メーラーのテンプレートパスをカスタマイズする

# はじめに
Deviseを使用する中で、特定の状況においてConfirmationメールの送信に使われるテンプレートのパスを変更する必要が生じました。[Deviseの公式Wikiにはガイドライン](https://github.com/heartcombo/devise/wiki/How-To:-Use-custom-mailer)が記載されていましたが、Rails7ではなぜかその方法では解決できなかったため、Deviseのソースコードを分析し、別の解決策を探りました。

# 方法 1: headers_for メソッドのオーバーライド
Deviseでは、`Devise::Mailer`の`Helpers`モジュール内にある`headers_for`メソッドを通じて、メール送信に必要な全てのヘッダ情報を生成します。このメソッドは、メールの件名(`subject`)、受信者(`to`)、送信者(`from`)、返信先アドレス(`reply_to`)、テンプレートパス(`template_path`)、そしてテンプレート名(`template_name`)を含むハッシュを作成します。

**Devise::Mailersヘルパーのheaders_forメソッド**
https://github.com/heartcombo/devise/blob/main/lib/devise/mailers/helpers.rb#L31
```ruby
module Devise
  module Mailers
    module Helpers
      ...
      protected

      def headers_for(action, opts)
        headers = {
          subject: subject_for(action),
          to: resource.email,
          from: mailer_sender(devise_mapping),
          reply_to: mailer_reply_to(devise_mapping),
          template_path: template_paths,
          template_name: action
        }.merge(opts)
        @email = headers[:to]
        headers
      end
      ...
    end
  end
end
```

`DeviseMailer`で`headers_for`メソッドをオーバーライドし、`super`と`merge!`を使用してテンプレートパスを変更できます。

**DeviseMailerのheaders_forメソッド**

```ruby
class DeviseMailer < Devise::Mailer
  include Devise::Controllers::UrlHelpers
  
  def headers_for(action, opts)
    super.merge!({template_path: 'my_mailer'}) # app/views/my_mailer
  end
end
```
この方法では、`headers_for`メソッド内で`super`を呼び出し、`Devise::Mailer`の`Helpers`モジュール内の`headers_for`メソッドを実行してから、結果を受け取ります。その後`merge!`メソッドを使用して返されたハッシュの`template_path`を希望のパス（例：'my_mailer'）に更新します。これによりDeviseに新しいディレクトリでのメールテンプレートを使用するよう指示します。

# 方法 2: template_paths メソッドのオーバーライド
次はもっと直接的で簡単な方法です。Deviseは`template_paths`メソッドを使用してメールテンプレートのパスを決定します。`template_paths`メソッドは、文字列で構成されたパスを要素とする配列を返します。

**Devise::Mailersヘルパーのtemplate_pathsメソッド**
https://github.com/heartcombo/devise/blob/main/lib/devise/mailers/helpers.rb#L58
```ruby
module Devise
  module Mailers
    module Helpers
      ...
      protected

      def template_paths
        template_path = _prefixes.dup
        template_path.unshift "#{@devise_mapping.scoped_path}/mailer" if self.class.scoped_views?
        template_path # ["devise_mailer', 'devise/mailer']
      end
      ...
    end
  end
end
```
`template_paths`メソッドをオーバーライドし、戻り値を変更することで、メールテンプレートのパスを簡単に変更できます。

**DeviseMailerのtemplate_pathsメソッド**
```ruby
class DeviseMailer < Devise::Mailer
  include Devise::Controllers::UrlHelpers

  def template_paths
    ['my_mailer'] # app/views/my_mailer
  end
end
```
この方法では、簡単に希望するパスを配列に入れて返すだけです。

## 結論
Deviseのテンプレートパスを変更する方法として、`headers_for`メソッドのオーバーライドと`template_paths`メソッドのオーバーライドの2つの方法を見てきました。プロジェクトの状況に応じて適切に使用してください。
危険物取扱者試験　乙４類　合格体験記

# はじめに

危険物取扱者試験（乙４類）の国家試験に合格したので、記念として残します。フィジカルセキュリティということで「Security」関連の記事としても参考にしていただけたらと思います。

# Who am i ?

しがないエンジニア（IT関係）です。化学関係は高校の時以降は触れてすらいないです。理科は物理を中心に勉強していたこともあって、正直基本的なこと以外は覚えてません。

# なぜ受験しようと思ったのか？

CISSPというセキュリティの資格があるのですが、データセンタ関係のフィジカルセキュリティ（セーフティに近い話ではあるが）を勉強したことがきっかけで、より理解を深めたいと思ったからです。日本国には危険物取扱者という免許制度があり、その中で乙4類が最適かと思って受験を決意しました。

なお、CISSPについてはこちらで記事を書いていますので、もしご興味がある方がいれば参考にして頂けると嬉しい限りです。

https://qiita.com/forest_moririri/items/4a1dfdacc89d67ff1985

「フィジカルセキュリティ」という点で共通点を感じました。

# 本題

危険物取扱者試験についてはこちらのサイトが詳しいです。

https://www.shoubo-shiken.or.jp/kikenbutsu/

勉強方法ですが、以下の問題集が大変役に立ちました。これがなかったら受かってなかったと思います。

https://www.amazon.co.jp/%E3%83%9B%E3%83%B3%E3%83%88%E3%81%AB%E3%82%88%E3%81%8F%E5%87%BA%E3%82%8B%E4%B9%994%E9%A1%9E%E5%8D%B1%E9%99%BA%E7%89%A9%E8%A9%A6%E9%A8%93%E5%95%8F%E9%A1%8C%E9%9B%86-LICENCE-BOOKS-%E9%88%B4%E6%9C%A8-%E5%B9%B8%E7%94%B7/dp/4274211665/ref=zg_bs_g_3192951_sccl_49/356-3045480-1247915?psc=1

また下記は一部誤植もありますが、全体を通して見る分には良い参考書だと思います。（少々古いかなというのが個人的な難点です。）

https://www.amazon.co.jp/%E4%B9%99%E7%A8%AE%E7%AC%AC4%E9%A1%9E%E5%8D%B1%E9%99%BA%E7%89%A9%E5%8F%96%E6%89%B1%E8%80%85%E5%90%88%E6%A0%BC%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86-%E5%9D%82%E4%BA%95%E7%BE%8E%E7%A9%82/dp/4471210564/ref=sr_1_50?crid=2T894VFNHYJQM&keywords=%E5%8D%B1%E9%99%BA%E7%89%A9%E5%8F%96%E6%89%B1%E8%80%85+%E4%B9%994&qid=1700886239&s=books&sprefix=%E5%8D%B1%E9%99%BA%E7%89%A9%2Cstripbooks%2C173&sr=1-50

また俗に言うピンク本は使いませんでした。というより時間がなかったので参考程度にしました。

https://www.amazon.co.jp/%E4%B9%99%E7%A8%AE%EF%BC%94%E9%A1%9E-%E5%8D%B1%E9%99%BA%E7%89%A9%E5%8F%96%E6%89%B1%E8%80%85%E8%A9%A6%E9%A8%93-%E4%BB%A4%E5%92%8C%EF%BC%96%E5%B9%B4%E7%89%88-%E5%85%AC%E8%AB%96%E5%87%BA%E7%89%88/dp/4862752551/ref=mp_s_a_1_4?crid=DBGFGOIF3KZS&keywords=%E5%8D%B1%E9%99%BA%E7%89%A9%E5%8F%96%E6%89%B1%E8%80%85+%E4%B9%994&qid=1701832078&sprefix=%E5%8D%B1%E9%99%BA%E7%89%A9%2Caps%2C207&sr=8-4

仕事をしつつという所もありましたので、勉強期間としては4週間程度かかりました。最初の2週間で内容をさっとさらって、最後の２週間で問題演習という感じでしょうか。トータルで30h～40h程度あれば十分かなと思います。

# 勉強する際の注意点

化学や物理（熱力学、理論化学、有機化学）の基本的な部分に関しては中学校や高校で一通り習ったこともあり、ベースは頭に入っているつもりでしたが、「危険物取扱者としてどんな所に気をつけなければいけないか？」という部分は知識の有無に関係なく勉強が必要です。参考書や問題等で抑えておくポイントはそういう所だと個人的に思っておりますので、頭の片隅に置いておくと勉強が捗るのではないかと思います。
また、危険物のそれぞれのセクション（法令、物理・化学、性質・消火）は「見えない所で繋がっている」という所に気づくとかなり理解が進むと思います。

# 今後話題になってきそうな内容

危険物取扱者（乙４類）と言うと、ガソリンスタンドや塗料など、その周辺が主な話題として取り上げられることが多いのですが、近年リチウムイオンバッテリの取扱に関する法規制の検討が進んでいます。リチウム自体は乙４類に該当します。

https://www.fdma.go.jp/singi_kento/kento/items/post-137/01/shiryou1-1.pdf

https://www.fdma.go.jp/singi_kento/kento/items/kento080_10_1-9.pdf

試験の話題としても取り上げられるようになるかもしれませんね。

（追記）
「リチウムイオン蓄電池に係る危険物規制に関する検討会」というものが発足されており、こちらで議論がなされているようです。

https://www.fdma.go.jp/singi_kento/kento/post-137.html

# 最後に

普通自動車免許の学科試験のように一見変わった問題を見ることもあるのですが、個人的には普通自動車免許の学科試験の方がとっつきにくかったです（ひっかけも多いし）。
こちらにも記載しましたが、運転免許証は身分証明書のデファクトスタンダード的な立ち位置にあると思っていますので、身分証としては運転免許証の方が優れていると個人的に思います。ただ、身分証明書はマイナンバーカードに一本化されていくんですかね？

https://qiita.com/forest_moririri/items/c062f1c3f806b08a6c55

他の乙種も勉強してみたいですね。久々に化学をちゃんと勉強して楽しかったです。
.NET SDK 8.0でPublishTrimmedしようとすると失敗する場合がある話

# はじめに

内々で使っているツールでPublishTrimmed(PublishAotではない)している場所が存在しているが、
.NET SDK 8.0でエラーが出るようになったので原因と回避方法の解説を行う。
PublishTrimmedに関しての解説は下記公式ドキュメントを参照すること。
[Microsoft Learn - Trimming options](https://learn.microsoft.com/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-8-0)

なお、今回書いた内容はPublishAotでも大体当てはまる(多分もっと制限がきつい)

# 前提条件

まず、このエラーが出る条件としては、

* .NET SDK 8.0を使用している
* net6.0以降のEXEプロジェクトが存在する(app1とする)
* EXEプロジェクトがnetstandard2.0あるいは2.1のライブラリプロジェクト(lib1とする)をProjectReferenceしている
    * アナライザープロジェクトでも該当する
    * PackageReferenceの場合は試してないが同じようなことになったらもっと多くの人が気づいてると思うので大丈夫だと思う

# 現象発生

この状態で、app1を `dotnet publish [app1.csprojファイルパス] -r win-x64 --self-contained -c Release -p:PublishTrimmed=true` すると以下のようなエラーが出て失敗する

```
C:\Program Files\dotnet\sdk\8.0.100\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): error NETSDK1124: アセンブリをトリミングするには、.NET
 Core 3.0 以降が必要です。 [D:\src\gitrepos\dotnet-sandbox\trimlabs2\lib1\lib1.csproj]
 ```

 # 原因

`dotnet publish`は、依存プロジェクトがある場合はそれを先にビルドするような動作をする。
`-p:PublishTrimmed=true`はmsbuildプロパティをビルド全体に適用するオプションとなる(msbuild由来)。
つまり、lib1を"PublishTrimmed=true"プロパティ付きでビルドしようとすると、lib1でもPublishTrimmed=trueが適用されて、上記のNETSDK1124エラーが出る。

これはSDK側のバージョンアップによる動作変更なので、app1.csprojのTargetFrameworkをnet6.0に下げても変わらない

# 対策

## global.jsonで使用する.NET SDKのバージョンダウンを行う

この動作は.NET SDK 8.0からなので、使うSDKのバージョンを7.0以前に下げれば対応は可能。
ただし、 **バージョンダウンなのでTargetFrameworkにnet8.0が使えなくなる** 事には注意。
具体的にはリポジトリルートに下記の内容で"global.json"というファイルを作成する

```json: global.json
{
  "sdk": {
    "version": "7.0.200"
  }
}
```

"version"要素の仕様を含むglobal.jsonの詳しい仕様は下記公式ドキュメントを参考にすること

[Microsoft Learn - global.json overview](https://learn.microsoft.com/dotnet/core/tools/global-json)

## csprojの書き換え

net8.0を使いたい場合ではどうするかというと、コマンドラインで指定するのではなく、csprojの中で指定する必要がある。

csprojに下記内容を追加する

```xml: app1.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <!-- 途中省略 -->
  <PropertyGroup>
    <PublishTrimmed>true</PublishTrimmed>
  </PropertyGroup>
  <!-- 途中省略 -->
</Project>
```

ある条件の場合だけ有効にしたい場合は、下記のようにCondition属性を付ける

```xml
<PropertyGroup Condition="'$(Runtime)' != ''">
  <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
```

# 終わりに

今回の内容はSDKの動作仕様の変更なので、ソースやプロジェクト等の設定を一切変えてなくても、
**VSのアップデートを行うだけで出るようになってしまう場合がある**ため注意が必要。

アナライザープロジェクトを参照してもこれが出るので、可能ならばその辺りはどうにかして欲しい所。
なお、この問題と類似ケースが下記で議論されている。
[Build error NETSDK1124 with NET8 RC2 when multiple TargetFrameworks](https://github.com/dotnet/runtime/issues/94406)
【トラブル対応】Linuxの高負荷プロセス探し

top -d 0.5でまずはリソース状況とプロセスの移り変わりを確認。
ps -auxとかgrepを追加したりとかでとりあえずどんなもんか確認。
プロセスの親子関係が確認したければfも足すと良い。
問題プロセスやゾンビがいたらkill {PID}で落とす。
ひとまず下書きとしてはこのくらい。
若手エンジニア奮闘記⑨新人エンジニアがぶつかった壁

# 目次
[・はじめに](#はじめに)
[・第一話「言語の壁」](#第一話言語の壁)
[・おわりに](#おわりに)

# はじめに

こんにちは、新入社員の長澤です！
4月に入社し、3か月の研修期間を経て、7月から配属され、現在は日々一生懸命業務に取り組んでおります！

さて、若手奮闘記、、、
せっかく執筆できる機会を頂いたので、何について書こうかなと考えまして、、、。

奮闘記というタイトルなので、私が文字通り”奮闘した”、
「業務で当たった壁集」を連載していこうと思います！

これからエンジニア業務に携わる方はこんなこともあるのかと参考にして頂いて、
またエンジニア歴が私よりも長い先輩方は、そんなこともあるよなぁと共感しながら読み進めて頂ければ嬉しい限りでございます！

# 第一話「言語の壁」

冒頭で述べたように7月から配属された私ですが、配属された部署ではServiceNowというサービスを取り扱っております。
　
　配属されてから1か月間近くはServiceNowから提供されているラーニングプランを進めて理解を深めておりました。
　満ち溢れたやる気を携え、ラーニングプランに取り組むぞと意気揚々とページを開いた1日目。
「え、全部英語やないか～い！」
 基本的に、ラーニングプランや公式ドキュメントは英語のオンパレードでした。公式ドキュメントの言語設定では日本語に対応しているのですが、自動翻訳ベースだったりして新人エンジニアがスムーズに理解するには大きな山でした。
　「フィールド」が「畑」と変換されたり、翻訳アプリによって「するべき」「しない方がいい」の相反する翻訳がされ、どっちだ？！となったり、、、
　そんなこんなありましたが、今はChromeの翻訳機能を使いながらなんとか必要な知識や情報を吸収してます(翻訳機能が無い時代だったらどうなっていたことやら…)
　
エンジニアだからプログラミングさえできるようになれば大丈夫だろう、なんて安直な考えを学生時代は持っていましたが、英語読めるって結構大事なことかもしれません。

# おわりに

　エンジニアとして成長するために、英語をスムーズに読めるようになることも大事だと感じたことが今回紹介した壁から学んだことです。
　日本で広く普及されていないサービスだと日本語対応していないし、技術的な記事も英語で投稿されている数の方が圧倒的に多いですからね。

最後まで読んでいただきありがとうございました。次回のブログをお楽しみに！
【ChatGPT無】がこちらの意図を理解しているのか、確認します。


　どうも、カーブミラーです。

　今回は、与える指示をChatGPTが意図を理解しているのかを明確化します。

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　与えた指示プロンプトから
　　ChatGPTさんが、
　　　こちらの意図を
　　　　どう解釈したのか、
　　　　　気になりませんか？

　こっちの意図とは
　　異なる回答をされることが
　　　それなりにありますよね。

　そこで、
　　“どうして、その回答にしたのか”
　　　と問うと、前のプロンプトに
　　　　引きずられて、
　　　　　欲しい回答を
　　　　　　得られることが
　　　　　　　できません。
***
　ならば、
　　回答をもらう前、
　　　つまり、指示プロンプトを
　　　　与えたところで、
　　　　　質問すれば、
　　　　　　引きずられません。

　そこで、
　　指示プロンプトを編集して、
　　　プロンプトの意図を
　　　　どう解釈したのかを
　　　　　聞きます。

　残念ながら、
　　アプリ版には、
　　　プロンプトの編集機能が
　　　　ないので、NewChatして
　　　　　新たなセッションでの
　　　　　　質問になります。

　とりあえず、
　　そのPromptが、
　　　こちら。

　✘✘✘に質問を
　　入れる形です。
```Text:
質問「✘✘✘」

上記の質問は、どんな質問だと思いますか？　ユーザーの意図を言語化してみてください。
回答は箇条書き（可能性の高い順、番号付き）でお願いします。
```

　やり取りは、
　　こちら。
***
***User***
質問「新しいカレンダーが欲しい」

上記の質問は、どんな質問だと思いますか？　ユーザーの意図を言語化してみてください。
回答は箇条書き（可能性の高い順、番号付き）でお願いします。

***ChatGPT***
理解しました！ユーザーが「新しいカレンダーが欲しい」と言っている意図を言語化すると以下のようなものですね：

1. **カレンダーの購入希望**: 新しいカレンダーを購入したいと考えている可能性があります。形式や種類に関する情報が必要かもしれません。
2. **デジタルカレンダーの希望**: デジタル形式のカレンダー（アプリやソフトウェア）を探している可能性があります。特定の機能やプラットフォームに関する情報が求められているかもしれません。
3. **カレンダーのデザインへの関心**: 新しいデザインのカレンダーを見つけたいと思っている可能性があります。特定のスタイルやデザインのカレンダーを探しているかもしれません。

これらの可能性の中から、ユーザーが何を求めているのか追加の質問を通じて明確にすることができますね！
***
　やり取りというほどでも
　　ありませんねw

　とにかく、
　　ここからスタートも
　　　できますし、
　　　　指示プロンプトを
　　　　　磨くことも可能です。

　そこは、
　　みなさんに
　　　お任せします。

　今回は、ここまで。
GithubにSSH接続出来なくなった時に対応したこと（Mac/Sourcetree）

つい先日まで、GithubにSSH接続をして、Pull/Pushやcloneなどをしていました。
Macで ツールはSourcetreeを使用しています。

数日ぶりに、SourcetreeでPushをしようとしたところ、突然以下のエラーが表示されました。

```
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
```
はっきりとした理由は分からなかったのですが、鍵が壊れたのではないかと推測し、鍵の作り直しをしました。

既存の鍵は念のため残しておきたいと思い、別の名前[github_rsa_for_xxx]で作成しました。
```
cd ~/.ssh
ssh-keygen -t rsa -f github_rsa_for_xxx
```
作成された公開鍵```github_rsa_for_xxx.pub```の中身をGithubの[SSH keys](https://github.com/settings/keys)の画面で登録します。

その後、
```
ssh-add ~/.ssh/github_rsa_for_xxx
```
することで、無事にGithubにSSH接続が出来るようになりました！
data_getヘルパで連想配列から値を取り出そう！

## 概要
data_get関数は「ドット」記法を使用し、ネストした配列やオブジェクトから値を取得します。
値が存在しない場合はnullを返却し、第三引数に値が存在しなかった場合に返却する値を設定できます.


## 例
```php
$threeDimensionalArray = array(
    'first_level' => array(
        'first_level_key_1' => 'Value 1',
        'first_level_key_2' => 'Value 2',
        'second_level' => array(
            'second_level_key_1' => 'Value 3',
            'second_level_key_2' => 'Value 4',
            'third_level' => array(
                'third_level_key_1' => 'Value 5',
                'third_level_key_2' => 'Value 6',
            ),
        ),
    ),
    'second_level' => array(
        'first_level_key_3' => 'Value 7',
        'first_level_key_4' => 'Value 8',
        'second_level' => array(
            'second_level_key_3' => 'Value 9',
            'second_level_key_4' => 'Value 10',
            'third_level' => array(
                'third_level_key_3' => 'Value 11',
                'third_level_key_4' => 'Value 12',
            ),
        ),
    ),
);

dd(data_get($threeDimensionalArray, 'first_level.first_level_key_1'));
//Value 1
```

オブジェクトでも使用できます
```php
$threeDimensionalArray = (object) array(
    'first_level' => (object) array(
        'first_level_key_1' => 'Value 1',
        'first_level_key_2' => 'Value 2',
        'second_level' => (object) array(
            'second_level_key_1' => 'Value 3',
            'second_level_key_2' => 'Value 4',
            'third_level' => (object) array(
                'third_level_key_1' => 'Value 5',
                'third_level_key_2' => 'Value 6',
            ),
        ),
    ),
    'second_level' => (object) array(
        'first_level_key_3' => 'Value 7',
        'first_level_key_4' => 'Value 8',
        'second_level' => (object) array(
            'second_level_key_3' => 'Value 9',
            'second_level_key_4' => 'Value 10',
            'third_level' => (object) array(
                'third_level_key_3' => 'Value 11',
                'third_level_key_4' => 'Value 12',
            ),
        ),
    ),
);

dd(data_get($threeDimensionalArray, 'second_level.second_level.third_level.third_level_key_4'));
//Value 12
```

## 参考
https://readouble.com/laravel/10.x/ja/helpers.html#method-data-get
とにかくシンプルなマイクロサービスをECS Service Connectで作る

# はじめに
こんにちは、GxPの杉山です。
こちらはグロースエクスパートナーズ Advent Calendar 2023の7日目の記事です。

個人開発中のプロダクトをマイクロサービスで開発をしており、その際にECS Service Connectを試しました。
その際にいくつかはまったので整理のため、とにかくシンプルなサンプルで記事を書きます。

なお、今回はterraformとgo echoのアプリを使用しています。
```
Terraform v1.5.2
go version go1.21.4
```
ソースはこちらです
https://github.com/Xmagnum2/service-connect-sample

システム構成は以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952084/c3269081-cd76-95ec-c4f2-50739224ce77.png)

# セキュリティグループの設定
service-aとservice-bにはお互いのresource-groupを許可する設定を入れます。
```
resource "aws_security_group_rule" "a_from_b" {
  type                     = "ingress"
  from_port                = 8080
  to_port                  = 8080
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.service_b.id
  security_group_id        = aws_security_group.service_a.id
}

resource "aws_security_group_rule" "b_from_a" {
  type              = "ingress"
  from_port         = 8081
  to_port           = 8081
  protocol          = "tcp"
  source_security_group_id = aws_security_group.service_a.id
  security_group_id = aws_security_group.service_b.id
}
```
*_from_anyは手元で確認する用なので別で確認する方法があれば必要ありません。

# タスク定義
タスク定義のポートマッピングにECS Service Connect用の設定を追記します。
```
      portMappings = [
        {
          name          = "service_a"
          containerPort = 8080
          protocol      = "tcp"
          appProtocol   = "http"
        }
      ]
```
このnameがDNSとなります。

# ECSサービス
ECSサービスにもservice_connect_configurationを追加します。
```
  service_connect_configuration {
    enabled = true
    service {
      client_alias {
        port = 80
      }
      port_name = "service_a"
    }

    namespace = aws_service_discovery_http_namespace.qiita.arn
  }
```
ここのポートは80である必要はありません。好きなポートを指定してokです。勝手に紐づいてくれます。

# apply
今回は非常にシンプルな構成のためここまででECS Service Connectを利用する準備が整いました。
最後に`terraform apply --var-file=env.tfvars`で実行するとリソースが作成されるため、goのコードをビルドしてecrへイメージをpushすれば疎通を確認することができるはずです！

serviceA
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952084/667bd4e5-f5ec-9cad-5f40-21e39ad626b3.png)
serviceB
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952084/6c49c47f-d237-9d72-a14a-93c4efbf3411.png)

# まとめ
いかがだったでしょうか。
最初に概要を知って試したいとなったときにまずは動くものをっと思うのですが、ここまでシンプルな構成ってありそうであまりないんですよね。
同じような方の助けとなれば幸いです！
【Java】instanceofした後のキャストが要らない件（Java 16）

# はじめに
`instanceof`を使う時って、↓のようにキャストすることあるじゃないですか。
```java
if (obj instanceof String) {
    
    String s = (String) obj;
    
    // do anything
}
```
これがJava 16からキャスト不要だったらしいです。

https://openjdk.org/jeps/394

「そんなん知ってるわ」って方は以下読む必要ないです。

# こうなる
`instanceof`のパターンマッチングと言います。

最初のコードは↓のように書けます。

```java
if (obj instanceof String s) {
    
    // do anything
}
```
この1行で↓が行われます。
1. `obj`が`String`だった場合は`String`にキャスト
1. 変数`s`に代入（ここでは`s`のことをパターン変数と呼びます）

よって、後続の処理では`s`を使っていろいろと処理が書けるわけです。

## パターン変数のスコープ

パターン変数のスコープは、以下のように述べられています。
> A pattern variable is only in scope where the compiler can deduce that the pattern has definitely matched and the variable will have been assigned a value. 

「パターン変数は、パターンが確実にマッチしていて、その変数に値が代入されているとコンパイラが推測できる場合にのみスコープに入る。」

つまり、、、パターン変数のスコープは変数に値が代入されて意味を持つときだけとなります。（これを`flow scoping`といいます、多分）

例えば、以下のようになります。
```java
public class Sample {

	void foo(Object obj) {

        // (1)
		if (obj instanceof String a) {

            // objがString型の場合、パターン変数aのスコープ内
		}

        // (2)
		if (obj instanceof Boolean a) {
    		
            // objがBoolean型の場合、パターン変数aのスコープ内
		}

        // パターン変数aのスコープ外
	}
```

このコードでは`(1)`と`(2)`で同じパターン変数`a`を使っています。
`instanceof`で型と一致した場合はそれぞれの`if`ブロック内に`a`はスコープを持ち、マッチしない場合はスコープがないです。

`!`を使ったらスコープは逆になります。
```java
public class Sample {

	void foo(Object obj) {
        
        if (!(obj instanceof String s)) {
        
            // objはString型ではなくsのスコープ外
        } else {

            // objはString型でsのスコープ内
        }
        
        // sのスコープ外
    }
}
```

もう1つ`!`のサンプルをば。
```java
public class Sample {

	void foo(Object obj) {
        
        if (!(obj instanceof String s)) {
            
            throw new IllegalArgumentException("Must be a string");
        }

        // sのスコープ
        var s = "hoge"; // コンパイルエラー
    }
}
```
`if`文が終わった後はスコープ変数`s`が`String`型を持つことが保証されているので、`if`の後が`s`のスコープになります。
なので、`s`を再度宣言しようとするとコンパイルエラーになります。

また、例外をスローしていますが、例外をスローしない場合は、`s`が`String`型をもつことが保証できないため、スコープ外となり宣言できます。

## ちなみに
フィールド変数を`shadowing`（重複するスコープで同じ名前の変数を使って、低レベルスコープの変数が高レベルスコープの変数をオーバライドすること）できます。

```java
class Example {

	String s;

	void test(Object o) {

		if (o instanceof String s) {

			System.out.println(s); // shadowing
			s = s + "\n"; 
		}

		System.out.println(s);
	}
}
```
これを以下のコードで実行すると`hoge`、`null`と表示されます。
```Main.java
public class Main {

	public static void main(String[] args) {

		Example e = new Example();
		e.test("hoge");
	}
}
```


## 使い道
例えば、Java 16より前だと`equals`で↓のようなコードを書くこともあったと思います。
```java
public class Foo {

	int i;

	@Override
	public boolean equals(Object obj) {

		if (!(obj instanceof Foo)) {

			return false;
		}
        
        // instanceofで確認した後にキャスト
		Foo other = (Foo) obj;

		if (other.i != this.i) {

			return false;
		}

		return true;
	}
}
```
`Foo`オブジェクトの変数`i`が等しい場合に`true`を返す`equals`メソッドです。

↑がこう↓書けます。
```java
public class Foo {

	int i;

	@Override
	public boolean equals(Object obj) {

		return (obj instanceof Foo other) && other.i == this.i;
	}
}
```

# おわりに
まちがっていたり、補足があればご指摘いただけるとうれしいです。
【AWS】ユーザーデータ，起動テンプレートetc

# ユーザーデータ
EC2インスタンス起動時に任意のスクリプトを実行できる。
実行権限はrootユーザー権限。

形式は以下の2通りある。
| 形式 | 説明 |
| ---- | ---- |
| シェルスクリプト形式 | 1行目が#!で始まる。 |
| cloud-init形式 | 1行目が#cloud-configで始まる |

# 起動テンプレート
インスタンス起動フローの一連の設定をテンプレート化して実行。AMIのID，インスタンスタイプ，キーペア，セキュリティグループ，EC2インスタンスを起動するのに必要なパラメータが含まれている。

# ハードウェア専有オプション
自身が専有するAWSアカウントで，インスタンスが配置されるハードウェアを専有できるオプション。

| オプション | 説明 |
| ---- | ---- |
| 専有ハードウェアインスタンス | AWSアカウント単位でハードウェアを占有するオプション。インスタンス単位で課金。 |
| 専有ホスト | インスタンスの起動単位でハードウェアを専有するオプション。ホスト単位で課金 |

# インスタンスメタデータ
インスタンスに関するデータで、実行中のインスタンスを設定または管理するために使用。目的によって使用するコマンドが異なる。

| 形式 | 説明 |
| ---- | ---- |
| プログラムで使用 | curlコマンド |
| EC2にログインして情報を目視確認 | ec2-metadataコマンド |

# キーペア
EC2へログインするために使用する秘密鍵(.pem)，公開鍵のペア。公開鍵はAWSが保管
秘密鍵の再作成する場合は，AMIとしてバックアップを取って，起動時にキーペアを再作成する。

# プレースメントグループ
EC2インスタンスの実行時にAWSのAZの物理的な配置戦略を選択できる機能。

| 配置戦略 | 説明 |
| ---- | ---- |
| Cluster | 単一のAZ内のできるだけ近い位置でインスタンスを配置 |
| Spread | EC2インスタンスは別々のハードウェアに分散して配置 |
| Partition | インスタンスは同一のハードウェアを共有しない論理的なパーティションに分割し手配置 |


# 参考
https://aws.amazon.com/jp/ec2/pricing/dedicated-instances/
https://www.youtube.com/watch?v=IhIGppxveTc&list=PL2nCE2iR-lpkKekqLv6Z4tDfC6n0FLJos&index=3
AWSの基本・仕組み・重要用語が全部わかる教科書
QGIS,GRASSGIS v.sampleで作る断面図その２

# はじめに
2021年のアドベントカレンダーに「QGIS,GRASSGIS v.sampleで作る断面図」という記事を投稿しました。これはポイント位置のラスタ値を内挿補完で取得できるgrassのv.sampleを使って標高ラスターとポリラインから断面図を作るQGISのグラフィカルモデラーを作ったという内容でした。

https://qiita.com/mooya/items/22d97535048fb1860778

ただ、Windowsのインストーラがexeからmsiに変わったv3.16から、grassが動作しなくなり使えなかったのですが、最近のQGIS（3.32以降？）では動くようになりました。ありがとう。

https://github.com/qgis/QGIS/pull/49226

と思っていたら、v3.34.1ではまたgrassが動かないようですが、これは次のバージョンでは直りそうです。
この記事は、またgrassが動くようになったので、いろいろ手を加えていったことを書きます。

# 断面図とは
断面図は、測線（ポリライン）に沿って標高DEM（地形標高のラスター）の値を取得したものです。
断面図の例。データは国土地理院 基盤地図情報 数値標高モデルです。
![断面図.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/096a71b7-7d74-39c5-17be-6733f7cf50bb.png)

# QGIS グラフィカルモデラーとは
QGIS グラフィカルモデラーは、入力データ（ベクター、ラスター）とそれに対するプロセッシング（処理）を視覚的に定義できるもので、簡易的なプログラムのようなものです。昨年のアドベントカレンダーにグラフィカルモデラーの記事がありましたのでリンクを張ります。

https://qiita.com/fukuoka1960/items/bda803d691acc513b05c

# 地理座標での内挿補完
主に国土地理院のいわゆる5m(0.2")DEM（地理座標）を念頭に置いた話ですが、断面図を作る前処理として、地理座標のDEMを投影座標に変換すると、セルサイズが変わるので、内挿補完によりデータが変質します。以下の画像は地理座標DEMとそれを変換して投影座標DEMから作成した等高線ですが、若干ずれています。

![contour.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/69bf7654-25a3-9dd8-b487-df80ad061c6b.png)

それに対してポイント（ベクター）は、DEMのような変質はありません。このため、入力ラインを投影変換してDEMのCRSで内挿補完することで、前処理のDEMの投影変換を不要にしてデータの変質をなくしました。
なお、ライン、DEMのCRSが正しく設定されていれば同一のCRSでも地理座標と投影座標が逆でも問題ありません。

# 水際の内挿補完
v.sampleの内挿補完はnearest（近傍値）、bilinear（線形）、bicubic（双三次補間）があります。
滑らかな断面を作るため、bicubicを使ったのですが、bicubicは、周囲2ピクセルnodata（水面）があると値が取得できないため、一昨年の処理モデルでは、bilinear（周囲1ピクセルに値が必要）、nearestの値で埋めていました。そうすると、例えば水際のセルに2点のポイントがあると同じ近傍値が連続して水平な線分ができて不自然でしたが、良い解決方法が思いつきませんでした。
今回、DEMにgdalの「nodata値を内挿値で埋める」で水際付近の水面を埋める方法で、水際の内挿値が自然になりました。

![水際の改善.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/e2596ffb-ca94-70ed-9529-8abb47d008f0.png)

また、内挿補完方法をオプションで選択できるようにしました。

# 断面図の出力
断面図の出力はポイントで属性値はsagaの「profile from line」にならっており、断面図を作成するには、水平距離DISTと標高Zを使います。QGISではポイント（ベクタ）の順番が保証されないので、属性値を表計算にコピペしてPoint_IDフィールドで昇順でソートするとCAD等の入力として使える断面の数値データになります。

![フィールド.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/99851f1e-2456-719f-02c8-7054fd4059a2.png)

今回、斜距離「DIST_SURF」を計算するようにしました。ただ、これをフィールド計算機で計算しようとすると、個々のポイントの計算で全体のポイントが処理対象になるので、ポイントが増えると加速度的に重たくなります。。

# 標高断面図での表示
新しく追加された標高断面図を使って、作成した断面を表示することができます。表示するには作成したポイントのレイヤプロパティで、「地物の絶対位置」、「連続的サーフェス（等高線など）」を選択します。

![標高プロパティ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/b4a6927b-eec9-608f-410b-d4219b9d340a.png)

その後、ビュー→標高断面図を開いて、標高断面図のレイヤ一覧で対象レイヤを選択後、標高断面図の「地物から曲線をキャプチャ」アイコンを選択してキャンバスの断面図の入力ラインを選択します。先に標高断面図のウインドウを開いてからポイントレイヤを作成しても標高断面図のレイヤ一覧に表示されないので、その場合は標高断面図を一旦閉じて開きなおします。
DEMを直接表示することもできますが、拡大するとピクセルのガタガタが目立ちます。

![標高断面図.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2259894/beb85bc1-11e2-2c63-eef4-2b5449a6b80a.png)


# グラフィカルモデラーファイル
QGISグラフィカルモデラーのファイルは下記に保存しています。ポイントをDEMの格子との交点で作るものと、等間隔のものがあります。

https://github.com/motohirooya/profile_grass_v_sample/tree/main

# おわりに
いくつかのソフトで断面図を作ると全部出力が違うのは何故だろうと思ってこれを作り始めました。ポイントの取り方と内挿補完の方法で、出力が変わってくるので、最近傍値のガタガタは良くないなあと思うものの、どれが正解というのもないので、最後は趣味の問題と思います。
チャット履歴を使って、特定な人を模倣するようなチャットボットを作ってみました（GPTs+wechatmsg）

昨日、GitHubのトレンドを見ていたところ、top1の「wechatmsg」というossを気づきました。
「wechatmsg」は、WeChat（中国のLINEみたいなチャットアプリ）のチャット履歴をsqlite、csv、またはword形式にまとめられるツールです、ある程度のデータ分析もできます。
開発者は、人間のチャット履歴も重要なデータであり、感情分析や言語モデルのトレーニングに役立てると考えて、このツールを開発しました。

チャット履歴をLLMとRAGして、prompt文を「質問に回答する前にこの人のチャット履歴を参照してください」でチューニングすれば、LLMがその人のように質問を回答できるではないかと思って試してみました。

まずは自分のWeChatのチャット履歴をバックアップし、wechatmsgでCSV形式に変換してみました。履歴が意外に多くて、10万件以上ありました。

できたcsvファイルは下図のようです。変数としては、チャットの相手、チャット内容、メッセージ送った時間、絵文字など、さまざまな情報が含まれています。

![123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/61ce8a5b-a4d2-d878-e9a8-b478b4950983.png)


モデルが理解しやすくなるために、簡単な前処理も行いました。（絵文字などの読み取れない情報を削除するとか）

今回使ったLLMはGPT4で、GPTsのpromptを使ってchatbotを作りました。
RAGしたknowledgeは私の一部のチャット履歴です。
prompt文は"質問回答する前に、私のチャット履歴csvを参照し、できるだけ私のように回答してください"です。
500件程度のデータを渡せた後、モデルの回答も若干の変化が見られました。2000件くらいになると、私の中国語の口癖も模倣するようになりました。
![12-6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/6b776a33-6a69-9d3c-e266-cf3fa806c744.png)

すべてのチャット履歴はあまり渡したくないので、試してなかったですが、おそらく数万件あれば結構うまく模倣できるようになると思います。
【React】useContext使ってみた

## useContextの使い方
`useContext`は、Reactコンテキストを介してグローバルな状態を共有するためのものです。以下は、`useContext`の基本的な使い方です。
Counterアプリをcontextを使って実装します

### 1. 型定義

```tsx:src/types/counter.tsx
import { Dispatch, SetStateAction } from "react";

export interface CounterContextProps {
  count: number;
  setCount: Dispatch<SetStateAction<number>>;
}
```

### 2. コンテキストを提供するコンポーネントの作成

```tsx:components/CounterContext/CounterContext.tsx
import { createContext, ReactNode, useState } from "react";
import { CounterContextType } from "../../types/counter";

const CounterContext = createContext<CounterContextType | null>(null);

const CounterProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [count, setCount] = useState<number>(0);

  const contextValue: CounterContextType = {
    count,
    setCount,
  };

  return (
    <CounterContext.Provider value={contextValue}>
      {children}
    </CounterContext.Provider>
  );
};

export { CounterContext, CounterProvider };
```

### 3. useContextを使用するコンポーネント

```tsx:components/CounterContext/CounterControls.tsx
import React, { useContext } from "react";
import { CounterContextType } from "../../types/counter";
import { CounterContext } from "./CounterContext";

const CounterControls: React.FC = () => {
  const { count, setCount } = useContext(CounterContext) as CounterContextType;

  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default CounterControls;
```

### 4. 表示用コンポーネント
```tsx:components/CounterContext/CounterDisplay.tsx
import React, { useContext } from "react";
import { CounterContext } from "./CounterContext";
import { CounterContextType } from "../../types/counter";

const CounterDisplay: React.FC = () => {
  const { count } = useContext(CounterContext) as CounterContextType;

  return (
    <div>
      <p>Count: {count}</p>
    </div>
  );
};

export default CounterDisplay;
```

### 5. Appコンポーネントで提供されたコンテキストを使用

```tsx:App.tsx
import React from "react";
import "./App.css";
import { CounterProvider } from "./components/CounterContext/CounterContext";
import CounterControls from "./components/CounterContext/CounterControls";
import CounterDisplay from "./components/CounterContext/CounterDisplay";

const App: React.FC = () => {
  return (
    <div className="App">
      <CounterProvider>
        <CounterDisplay />
        <CounterControls />
      </CounterProvider>
    </div>
  );
};

export default App;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/f7835aba-6aa6-cc27-6d77-21cf3bff2628.png)

## まとめ

`useContext`はReactアプリケーションの開発において非常に強力なツールです。`useContext`を使用してコンポーネント間で状態を共有することで、アプリケーションの保守性と可読性を向上させることができます。様々なHooksを使いこなして、より効率的で使いやすいReactアプリケーションを構築しましょう

この記事では、初心者大学生がReact Nextを理解するためのアウトプット資料です。
間違いや意見などコメントお待ちしております！
WindowsのイベントビューアーでセキュリティログをLogonProcessNameでフィルターしようとしたらハマった件

Windowsのイベントビューアーのセキュリティログで、失敗の監査のうちログオンプロセスが「Advapi」以外のものを抽出しようとしてハマったのでメモして共有します。

結論としては以下でできました。
「現在のログをフィルター」ダイアログでXMLタブを選択。「手動でクエリを編集する」にチェックを入れて以下XMLを入力しました。

```xml:フィルター
<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[band(Keywords,4503599627370496)]
and EventData[Data[@Name="LogonProcessName"]!="Advapi  "]]</Select>
  </Query>
</QueryList>
```

フィルタの条件の「Advapi  」のところ、最後にスペースが2つついているのですが、イベントビューアーではこれが確認できなかったためドハマりしました。
試行錯誤中にイベントをテキストとしてコピーして、テキストエディタに貼り付けたときにこのスペースを発見。フィルタの条件にも追加したら無事に抽出できました！
docker compose をV2にしたら、ネットワークの設定がエラーになったので修正してみました

## 概要

docker-composeのV1が非推奨になっていたのを、やっとV2にバージョンアップしました。

さっそく`docker-compose up`から`docker compose up`に変更して起動してみると、以下のようなエラー

```bash
WARN[0000] network default: network.external.name is deprecated in favor of network.name
```

が出ましたので、docker-compose.ymlを修正してみました。

## 変更箇所

エラーの元になった箇所
```yaml
networks:
  default:
    external:
      name: bridge
```

これを以下のように変更

```yaml
networks:
  default:
    name: bridge
    external: true
```

これで、無事に起動しました。

※参考 https://github.com/docker/compose-cli/issues/1856

ありがとうございます。
WordPressでCSSやJavaScriptにつくバージョン情報を差し替える

WordPressで構築しているサイトをセキュリティ診断したところ、リスクレベルはないもののバージョン情報を隠蔽することを推奨されました。

## 非表示にするもの

functions.phpに記述することでWordPressのバージョンを非表示にすることができます。

### metaタグのgenerarator

```php
remove_action('wp_head', 'wp_generator');
```

### RSSのgenerarator

```php
function remove_rss_version() {
	return '';
}
add_filter('the_generator', 'remove_rss_version');
```

そのほか、wp-links-opml.phpにアクセスするとバージョン情報が表示されるので、このファイルは削除やアクセス制限などをするといいかもしれません。

## CSSやJavaScript等に付与されるバージョン情報

WordPressではCSSやJavaScriptの読み込む時にバージョン情報が自動で付与されます。

### 例

```html
<link rel='stylesheet' id='wp-block-library-css' href='https://example.com/wp-includes/css/dist/block-library/style.min.css?ver=6.4.1' type='text/css' media='all' />
```

### 非表示にするには

```php
function remove_version_scripts_styles($src) {
    if (strpos($src, 'ver=')) {
        $src = remove_query_arg('ver', $src);
    }
    return $src;
}
add_filter('style_loader_src', 'remove_version_scripts_styles', 9999);
add_filter('script_loader_src', 'remove_version_scripts_styles', 9999);
```

ただ、CSSやJSに付与されているバージョン情報はキャッシュ対策にもなっていると思うので、非表示でいいのか？という疑問もあります。

## バージョン情報を何かに差し替える

バージョン情報 `6.4.1` 部分をこれを元に何かに差し替えてみれば、キャッシュ対策にもなるのではないかと思いました。

### 例えばchr関数を使って数値を英字にする

```php
function changeNumberToAlphabet($text)
{
    if (is_numeric($text)) {
        $text = (int) $text;
        return chr($text + 97); // 97を足して小文字の英字にする
    } else {
        return chr(ord($text));
    }
}
function remove_version_scripts_styles($src)
{
    if (strpos($src, 'ver=')) {
        // バージョン情報の取得
        $parameter = parse_url($src)['query'];
        parse_str($parameter, $queries);
        $version_str = $queries['ver'];
        $version_str = str_replace('.', '', $version_str); // ドットの削除
        $version_arr = str_split($version_str);

        // バージョン情報の数字を英数字にする
        $version_str = '';
        foreach ($version_arr as $text) {
            $version_str .= changeNumberToAlphabet($text);
        }

        // verのパラメータを削除
        $src = remove_query_arg('ver', $src);

        // 新たにverのパラメータを追加
        $src = add_query_arg('ver', $version_str, $src);
    }
    return $src;
}
add_filter('style_loader_src', 'remove_version_scripts_styles', 9999);
add_filter('script_loader_src', 'remove_version_scripts_styles', 9999);
```

## 参考記事

https://webpick.jp/wordpress-hide-version-info/

https://mw-s.jp/wordpress-ver-delete/

https://qiita.com/kouta1206/items/a31c74ed7ab6688d1747
Google Cloud Professional Cloud Architect 認定資格 を更新しました

# はじめに
Google Cloud Professional Cloud Architectが失効間近のため更新しました。

# 教材
1. [Cloud License | (旧)AWS WEB問題集で学習しよう](https://cloud-license.com/exam/pca/)
    - 有償のおなじみのやつです。
1. [Udemy Google Cloud 認定 Professional Cloud Architect 模擬問題集](https://www.udemy.com/course/google-cloud-professional-cloud-architect-i/)
    - 問題集です。
1. [試験問題サンプル](https://docs.google.com/forms/d/e/1FAIpQLScpVCxsKSrqMBmqJ4fiYrJfCSlMhJVIFaW_v3MD4xEd6NW0Bw/viewform)
    - 無料の公式の試験問題サンプルです。

# 感想
- 難しくは無く「Cloud License」で対策しておけば、難なく解けるかと思います。Udemyは念のためぐらいで良いです。両模擬試験ではサービス名が古いため、新しい名称をおさえておく必要があります。
Terraform is 何？


# 概要
こちらの記事ではIaCツールでお馴染みのTerraformについて調べてみた結果をまとめてみました。

## Terraformってなに？
Terraformというツールを端的にまとめるとこんな感じです

- 米カリフォルニア州にあるHashiCorp社のIaCツール
- 定義ファイルを書くだけでインフラの構築から廃棄までまるっと管理できる
- Go言語で書かれており、AWS SDK for GOの中のややこしいSDKコードを抽象化してくれる
-  AWSに限らず、さまざまなクラウドで使うことができるツール

### HashiCorpの始まり
>Mitchell HashimotoとArmon Dadgarは 2012 年に HashiCorp を設立しました。これは、組織が強力なアプリケーションをより迅速かつ効率的に作成および提供できるようにすることを目的として、インフラストラクチャ管理における最も困難で最も重要な問題のいくつかを解決することを目的としています。
>
>参照元
>https://www.lac.co.jp/lacwatch/service/20200903_002270.html​
>https://www.hashicorp.com/about
>https://www.publickey1.jp/blog/17/hashicorp_interview01.html​

インタビュー記事の中で、橋本氏の発言がおおよそのツールを使う理由になるのかな～と個人的に考えています。該当部分を抜粋するとこんな感じです。

#### インタビュー
記者「Terraformと競合ツールの差別化って？」​

橋本氏「AWSだけ使うなら、Cfnとかでええやん。けどな、マルチクラウド使うんでっしゃろ？」​

橋本氏「ほな、うちのツール使ったら、同じ使い勝手で​色々管理できて便利でっせ」

記者「なるほど・・」​


## Terraformの使い方（概要）
おおよその使い方概要は下記の通りです。

1. インフラ構築
    1. terraform init​
        - 環境の初期化
    1. terraform plan​
        - IaCコードの適用に問題がないかdry-runする
    1. terraform apply​
        - IaCコードの適用
1. インフラの廃棄​
    1. terraform destroy
        - IaCコードで作成した環境を全て削除する

## TerraForm定義ファイルについて
### 定義ファイルの概要
定義ファイルの主要なものは以下の３つです。

- main.tf​
    - コード本体を入れるファイル
- variables.tf​
    - 変数を入れるファイル​
    - ※無くても動くが用意することが推奨​
- outputs.tf​
    - サブ関数で得た結果をメイン関数に返す場合に使う
    - ※ファイル分割してモジュール化する場合に使う​
    - ※無くても動くが用意することが推奨

### 定義ファイルの構成要素
#### main.tf　の構成要素​
##### terraform（必須）
どのような関連モジュールを使用するかという定義をします。
※下記はAWS環境の場合の例
```
terraform {​
  required_providers {​
    aws = {​
      source  = "hashicorp/aws"​
      version = "~> 3.0"​
    }​
  }​
}
```
##### provider（必須項目）
主にクラウド環境へのアクセス設定などに使用します。
※下記はAWS環境の場合の例
```
provider "aws" {​
    access_key = "ACCESS_KEY"​
    secret_key = "SECRET_KEY"​
    region = "ap-northeast-1"​
}
```
##### variable（任意項目）​
早い話が変数のことです​。
この項目は使っても使わなくても構いません。
```
variable “variable_name_here" {​
  description = “description here"​
  type = string​
  default = “default value here" ​
}
```
##### resource （必須項目）​​
どのようなリソースをどのように作成するかという設定です。
リソースの詳細設計はHashiCorpのドキュメントを参照してください。
```
resource "aws_ec2_host" "test" {
  instance_type     = "t2.micro"
  availability_zone = "ap-northeast-1"
  host_recovery     = "on"
  auto_placement    = "on"
}
```
参照元
https://registry.terraform.io/providers/hashicorp/aws/latest/docs

# まとめ
Terraformの概要について記事にまとめてみました。どなたかのお役に立てれば幸いです。

## お知らせ
Terraformでの登録で使用していたアドカレを急遽別のものに登録する必要が出たため、代わりの記事を登録するために新しく記事を作成しました。AWS周りやその他技術的要素が高い記事は[会社のブログ](https://blog.serverworks.co.jp/search?q=shiono)にも記載していますので、興味があれば読んでいただけると嬉しいです。