OmniAICreator/Qiita-1.07M huggingface dataset:
きちんとCSSの重ね合わせを勉強した話

# 初めに
この記事は[フラー株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/fuller-inc)の25日目の記事になります。
24日目は[yoRyuuuuu](https://qiita.com/yoRyuuuuu)さんで[急に PC が壊れることに備えよう](https://zenn.dev/yoryuuuuu/articles/b1eacb82ad7934)でした。


重ね合わせについては数年前から勉強自体はしていましたが、この機会にアウトプットをしておこうと思います。

CSSの重ね合わせについては多くの人が解説をしているので、私は勉強して感じたことを書こうと思います。
（つまりただのポエムです。）


# CSSの重ね合わせに対する問題意識

どこでも言われている話ではありますが、重ね合わせで問題になってくるのは、重ね合わせのルールが複雑で、「実際に表示される際の重ね合わせ順が想定通りにいかない」というところだと思っています。
特にz-indexの扱いは難しいなと思っています。

今のWebアプリの開発ではコンポーネントからページを作るのが当たり前になっているので、コンポーネントにz-indexを持っていると、コンポーネントの組み合わせによって意図しない重ね合わせが発生してしまう可能性があります。

それぞれのコンポーネントのz-indexをうまく調整してあげれば重ね合わせの順序を調整できますが、後から追加開発や仕様変更でコンポーネントのz-indexを触る必要が出てきたときに、他のコンポーネントへの影響を意識する必要が出てきます。
そうなってしまうと、開発がやりづらくなってしまいます。

この辺りについて初心者のころから悩まされ続けてきたため、「なるべく重ね合わせもわかりやすい設計を意識していこう」と思い、勉強するに至りました。
（勉強する経緯については、先輩エンジニアの方に重ね合わせについていろいろ指摘されてきたという背景もありますが......。）


# CSSの重ね合わせの勉強方法

MDNの[CSS の z-index を理解する](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index)の中身をきちんと読んだくらいです。

それだけではありますが、普段開発するのに必要な知識としては十分かなと感じています。

# 一通り勉強して感じたこと

一通り記事を読んで、押さえておくべきは、
- z-indexなしの重ね合わせのルール
- 重ね合わせコンテキスト

の2つかなと思っています。

自分が先輩エンジニアから言われていたことではありますが、「まずz-indexを使わずに何とかできないか検討する」というのが重ね合わせを考える上で大事だと思っています。
その考えを実現するうえでz-indexなしの重ね合わせは重要だなと思っています。

基本的に位置指定要素であるかどうか、HTMLでの出現順によって重ね合わせ順が変わるという話であり、ここさえ押さえてしまえばある程度z-indexに頼らなくてもレイアウトを実現することができると思っています。

ただ、それでも無理な時は無理です。
（HTMLの出現順を捻じ曲げればz-indexなしで重ね合わせ順をコントロールできる場合もありますが、タブフォーカスの順序に影響してきたりするのでアクセシビリティ的によくない場合があります。そういう時は素直にあきらめましょう。）

そんなときに重ね合わせコンテキストが生きてくると思います。

[MDNの重ね合わせコンテキストの説明ページ](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context)に書かれていますが、重ね合わせコンテキストの子要素のz-indexはその親要素にしか意味がありません。
この特性を生かして、z-indexを含むコンポーネントについては重ね合わせコンテキストを作って、z-indexの影響範囲をコンポーネントに閉じ込めてしまうことができます。

そうすることで、作ったコンポーネントを別のコンポーネントで配置する場合、作ったコンポーネント内部の重ね合わせを考慮する必要がなく、コンポーネント同士の重ね合わせだけ気にすればよくなります。

以上のような感じで、
- z-indexなしの重ね合わせのルール
- 重ね合わせコンテキスト

を押さえておけば、
- z-indexなしである程度重ね合わせをコントロールできるようになる
- z-indexを使う場合でも、z-indexの影響範囲を適切に制限できる

という風になれるかなと思っています。

それができれば、重ね合わせで苦しむことは少なくなるのかなと思います。

## これからの課題
「なるべく重ね合わせもわかりやすい設計を意識していこう」という目標を目指したとき、z-indexなしの重ね合わせはある程度実践できるかなと思っています。

問題は重ね合わせコンテキストの方で、重ね合わせコンテキスト自体が分かりにくいので、一緒に開発しているエンジニア、コードを引き継ぐエンジニアに意図が伝わるかという点です。
（だからこそz-indexを使わないでコントロールできるのが一番よいのだと感じています。）

自分は今回勉強したことで何となくつかめましたが、全員が全員重ね合わせコンテキストを知っているわけではありません。

自分はよくisolationプロパティを使って重ね合わせコンテキストを作成しようとしますが、エンジニア始めたてのころ自分がそんなコードを見ても「おまじないか何かかな？」と思ってしまう自信があります。

こればかりはCSSの仕様を理解してもらうしかないので、コードレビューや勉強会の場で理解を得るのが一番だと思っていますが、なんか他にいい伝え方がないかなーと考え中です。


# 最後に

今年の[フラー株式会社 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/fuller-inc)はこれでおしまいです。
毎年そうですが、カレンダーに参加してくれる方には感謝しかありません。
来年もこうして続けられればなと思います。

# 参考
- https://developer.mozilla.org/ja/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index
VS Codeで個人的によく使用するショートカットキー

## 本記事について
- 「技術系の記事での社内のアドベントカレンダー作成」に向けた記事ですが、残念ながら私は開発に関わっておらず、エンジニアの皆様が書くような記事を書くことができません...
- ただ、よく使用するツールであるVS Codeのショートカットキーについてご質問を受ける機会が社内で何度かあったため、この記事で個人的によく使用するショートカットキーについて、使っている範囲で記載しようと思います。

:::note warn
私はWindowsを使用しているため、本記事もWindowsに向けたものとなります。
ご了承ください。
:::


## 個人的によく使用するショートカットキー
### マルチカーソル
1.  `Ctrl` + `Alt` + `↑` / `Ctrl` + `Alt` + `↓`
    - 現在選択しているカーソル位置の真上 / 真下に新しいカーソルを1つ追加します。
2. `Shift` + `Alt` + `右クリックしながらマウスカーソルを上下に移動`
    - 現在選択しているカーソル位置の真上 / 真下に新たなカーソルを一気に追加します。
3. `任意の文字列を選択` + `Ctrl` + `D`
    - 選択した場所以降に該当文字列があった場合、その文字列の直後にカーソルを追加します。
    - 1つずつのカーソル追加となるため、全ての該当文字列の直後にカーソルを追加したい場合は次のショートカットを使用してください。
4. `任意の文字列を選択` + `Ctrl` + `D`
    - 選択した場所以降に該当文字列があった場合、その文字列すべての直後にカーソルを追加します。

### カーソルの移動
1. `Home` / `End`
    - 行の先頭 / 末尾にカーソルを移動します。
2. `Ctrl` + `Home` / `Ctrl` + `End`
    - ファイルの先頭 / 末尾にカーソルを移動します。
3. `Ctrl` + `↑` / `Ctrl` + `↓`
    -文字列の先頭 / 末尾にカーソルを移動します。

### エディタ関連
1. `Ctrl` + `N`
    - 新規エディタを開きます。
2. `Ctrl` + `Shift` + `N`
    - 新規ウィンドウを開きます。
3. `Ctrl` + `W`
    - アクティブエディタを閉じます。
4. `Ctrl` + `Shift` + `W`
    - ウィンドウを閉じます。
5. `Ctrl` + `B`
    - サイドバーを開きます。既にサイドバーを開いている場合、サイドバーを閉じます。

## 終わりに
- 今回は個人的によく使用するショートカットキーをご紹介させて頂きましたが、簡単なものばかりだったかもしれません。
- 他にもたくさんショートカットキーがVS Codeでは用意されています。色んなショートカットキーを使って、作業の時間短縮などに役立てちゃいましょう！
【Go言語】エラーに自分で情報を追加する方法

## pkg/errorsについて

`pkg/errors` は、エラーハンドリングを強化するために使うパッケージです。今回はこれを使います。

Go1.13からは標準の `errors` パッケージというのが標準パッケージに追加されたのですが、`errors`は未だにいろんなところで見かけるので、今回は `pkg/errors` を使います。

移行についても紹介します。

### go getする

```bash
go get github.com/pkg/errors
```

###  errors.Wrapを使ってエラーに情報を追加する

`errors.Wrap` は、エラーに情報を追加するための関数です。

以下のようにerrにエラーが入っているときに、`errors.Wrap` を使うとエラーに情報を追加することができます。
以下のように関数がエラーを返すときにWrapで情報を追加してあげることができます。

```go
package main

import (
	"fmt"
	"io/ioutil"

	"github.com/pkg/errors"
)

func main() {
	err := someTimesError()
	if err != nil {
    fmt.Println(err)
		return
	}
}

func someTimesError() error {
	if err != nil {
		return nil, errors.Wrap(err, "someTimesError")  // ここでエラーに情報を追加
	}
	return
}
```


## errorsへの移行について

`fmt.Errorf`を使用することでWrapと同じようにエラーに情報を追加することができます。

`Errorf`自体はエラーを作成する関数ですが、`%w`を使うことで、エラー文の中に現在のエラーを埋め込むことができるので、これを使うことでWrapと同じようにエラーに情報を追加することができます。


```go
fmt.Errorf("message %w", err)
```
Flutter on the Web 勘所

## Flutter on the Web とは

Flutter on the Web とは Flutter で作成したアプリケーションを Web 上で動かせるようにする機能です。

ここでは、Flutter on the Web のアプリケーション開発を行うための前提知識をまとめます。

## Flutter on the Web の仕組み

Dart で書かれたアプリケーションは JS にビルドされ、レンダラは Web Assembly にビルドされます。

レンダリング方式は HTML と CanvasKit の２種類があります。HTML 方式の方が初期ローディング時間が短く、CanvasKit 方式の方がレンダリングパフォーマンスが高いとされています。

レンダリング方式には auto もあり、これはモバイル向けブラウザの場合に HTML 方式でレンダリングを行い、デスクトップ向けブラウザの場合に CanvasKit 方式でレンダリングされるダイナミックな方式になります。

## Web 向けのコードの書き方

Flutter のコマンドから Flutter プロジェクトに web 向けの asset を追加することができます。

Web 上で動作するコードでは、 Platform class を使用することができません。そこで、 Platform class が使用されている箇所は kIsWeb という定数の値によって処理の分岐を行います。

その他 Web に互換性のないコードについては基本的に kIsWeb の値による分岐を行う必要があります。

### ライフサイクル

Web のレンダラが初期化を完了するタイミングで任意のメソッドを実行させることができます。Flutter on the Web にアクセスされてからレンダラの初期化が完了されるまでのローディング時間にローディングUIを表示させるなどの処理を走らせることができます。

処理を書くには、index.html のインラインスクリプトにて、onEntrypointLoaded に関数を実装します。

## ビルドの方法

Flutter on the Web でビルドすると build/web ディレクトリ配下に各種 web 向けの asset が生成されます。

下記のコマンドからモード別のビルドを行うことができます。

release mode

```bash
flutter build web --release --web-renderer $RENDERER --dart-define=flavor=$FLAVOR
```

profile mode

```bash
flutter build web --profile --web-renderer $RENDERER --dart-define=flavor=$FLAVOR
```

上記のコマンドによって dart コードは dart2js によって js にコンパイルされます。

## ホスティングの方法

ビルドによって生成された build/web ディレクトリ配下のファイル全てを任意の Web サーバーにホスティングすることによって配信することができます。
AWS Secrets ManagerとSystems Manager Parameter Storeの使い分け

# はじめに
AWS Secrets ManagerとSystems Manager Parameter Storeは
どちらも認証情報、パスワード、ライセンスキーなどの重要な設定データの
整理や管理をするのに役に立つ機能。
その為どう使い分けたらいいのか？
また、AWS Systems Manager の機能である Parameter Store は Secrets Manager と統合されたため、パラメータからSecrets Manager シークレットを取得することもできる。

# それぞれの特徴
## AWS Systems Manager Parameter Store
- 階層型のパラメーターに保管可能
- バージョン管理が可能で、過去のパラメーター値にロールバックできる
- IAMポリシーを使用してアクセスが可能
- 暗号化され、KMSに保存
- 無料（KMSのAPI呼び出しに料金がかかる）

## AWS Secrets Manager
- 自動的に機密情報のローテーションが可能
- シークレットにキーと値のペアを保管可能
- IAMポリシーを使用してアクセスが可能
- 暗号化され、KMSに保存
- 有料

# どう使い分けたらいいのか？
:::note info
設定とシークレットにひとつのストアが欲しい場合、パラメータストアをお使いください。ライフサイクル管理を備えたシークレット専用のストアが欲しい場合、シークレットマネージャーをお使いください。
:::
Parameter StoreはさまざまなAWSサービスと連携できるのに対して、
Secrets Manageは多少制限がある。
ただ、Secrets Manageはシークレットのローテーションをすることができる。
どちらもKMS キーを用いて保管中の暗号化をサポートしている為、セキュリティに関する違いはない。

# Parameter Store を使用して Secrets Manager のシークレットを参照する場合
- パラメータへの参照が既にサポートされている他の AWS のサービスを使用するときに、Secrets Manager シークレットを取得できる。
（EC2、ECS、Lambda、CloudFormation、CodeBuild、CodeDeploy、およびその他の Systems Manager 機能が含まれる）
- GetParameter および GetParameters API オペレーションを使用して取得できるのは、Secrets Manager のシークレットのみ
- Parameter Store を使用してシークレットを取得するには、AWS Command Line Interface (AWS CLI)、AWS Tools for Windows PowerShell、および SDK を使用できる
- Parameter Store では、Secrets Manager のシークレットにアタッチされた AWS Identity and Access Management (IAM) ポリシーが尊重される
- Secrets Manager のシークレットを参照するパラメータは、Parameter Store のバージョン管理機能または履歴機能を使用できない
- Parameter Store は、Secrets Manager のバージョンステージを尊重する

## 終わりに
どちらも似ているのでこんがらかりそうになりますが、セキュリティに関する違いはないとのこと。
用途に合わせた使用方法とコスト面からParameter Storeを検討した上で用途がカバーできない場合はより細かい設定ができるSecrets Managerの利用するのを検討するのが良さそうです。


## 参考
- <a href="https://aws.amazon.com/jp/systems-manager/faq/">AWS Systems Manager のよくある質問</a>
- <a href="https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/integration-ps-secretsmanager.html">Parameter Store パラメータからの AWS Secrets Manager シークレットの参照</a>
MacOS USキーボードでの入力ソース切り替え

# 内容

USキーボードにおける、入力ソース切り替えについて、自分がやっていることを書きます。

_本内容は、Appleシリコン・Intelマック共通です。_


# 背景

自分は、M1 Mac mini をメインPCに、[Air60（赤軸）キーボード](https://nuphy.com/collections/keyboards/products/air60)を使用しています。超コンパクトで打ちやすいく気に入ってます。

<img width="300" alt="NuPhy-Air-60.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/347e46c5-5b7f-4b21-e409-71904e6b4481.jpeg" />

見ての通りUS配列ですが、日本語をローマ字入力するために、入力ソース切り替えをします。

USキーボードにおける入力ソース切り替えは、`control + space`か`fn`キーを使用し、`control + space`は、押す度に、`A`→`あ`→`A`→`あ`と切り替わります。
_`fn`キーも似たようなものですが、自分は`fn`キーによる入力ソース切り替えは`off`にしています。_

 ここで不便なのが、日本語キーボードの`英数`・`かな`キーのように、入力ソースの<b><i>直接</i></b> 指定ができないことです。
現在の入力ソースは、メニューバーに表示されていますが、27"モニターを使っていることもあり、視線をメニューバーに向けるのが嫌なので、頭の中にある現在の入力ソースから変更しようとして、`control + space`を押すと、想いと違うモードになってしまうことがあり、何度も`control + space`を押すことがよくあるのです。_頭が弱い??_

<img width="300" alt="MK2A3J.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/393bb6e4-5378-1be6-3272-8abcfbcdb340.jpeg" />

日本語キーボードであれば、スペースバーの左右にある `英数`キーで「`A`」、`かな`キーで「`あ`」と、<b><i>直接</i></b> 切り替えできます。
これなら打ち間違いが無い。そこで、片手キーボードの登場です。

# 片手キーボードにキーを割り当てる

<img width="100" alt="sikaicase6key.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/531a2daf-842f-74a7-aece-b11465d2b40b.jpeg" />

以前、↓こちらの記事で書いた「6キー片手キーボード」に、日本語キーボードの`英数`・`かな`キーを割り当てて使うことにしました。

https://qiita.com/nak435/items/389f62a41efc72c804a8


ついでに、Air60は60%キーボードのため、バッククォート（`` ` ``）とチルダ（`~`）が`escape`キーと同じキーで`fn`キーを押しながらタイプするようになっていて、これも少々不便のため「6キー片手キーボード」に割り当てました。

<img width="74" alt="esc.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/6e38b5bf-ce4f-1b74-f063-af713b4db5d3.jpeg" />


## 6キー片手キーボードのキーとノブの割り当ては以下のとおり

|key1|key2|key3|
|-|-|-|
|バッククォート3連（` ``` `）| screen `` `chooserial` `` 115200 [^1] |チルダ（`~`）|
|**key4**|**key5**|**key6**|
|`英数`|`かな`|バッククォート（`` ` ``）|

|ノブ左回り|ノブ押し込み|ノブ右回り|
|-|-|-|
|command + shift + G（前検索）|command + F（検索）|command + G（次検索）|

ちなみに、キーコードは以下のとおり。

- `英数` : 0x91
- `かな` : 0x90

自作したMac用の設定コマンド[^2]で割り当てました。
（純正の設定アプリでは、割り当てできません。多分）

6キー片手キーボードは、Air60の左横に置き、左手（小指）で操作しています。
これで、すこぶる快適になりました。

以上


[^1]: [シリアルポート選択 chooserial コマンドを自作](https://qiita.com/nak435/items/7ad479867d3e7e7e84e6)
[^2]: いずれまた別な記事で紹介したいと思います
ebayのカードカテゴリ商品のコンディション設定について

## はじめに
eBayにおいて、カードカテゴリに商品を出品する際には通常のコンディション設定（newやusedなど）とは異なり、カードカテゴリ特有のコンディションとそれに付随する情報を設定する必要があります(設定しないと出品できないです)。

この記事では、対象となるカテゴリやコンディションの設定方法、そしてそれに関連するテーブル構成について簡単に説明します。

## 対象カテゴリ
通常とは異なる設定が必要になるカードカテゴリは以下の3種類です。

・Sports Memorabilia, Cards & Fan Shop > Sports Trading Cards > Trading Card Singles (CategoryID: 261328)
・Collectibles > Non-Sport Trading Cards > Trading Card Singles (CategoryID: 183050)
・Toys & Hobbies > Collectible Card Games > CCG Individual Cards (CategoryID: 183454)

## 設定するコンディション
上記カテゴリで設定できるコンディションは以下の通り。

・Graded（ID:2750、鑑定機関による鑑定済み）
・Ungraded（ID:4000、鑑定無し）

## 各コンディションに対する付加情報(ConditionDescriptor)
上記コンディションに対して必須となる付加情報は以下の通り。
※GradedとUngradedで異なります

【Graded（ID:2750）】
・Professional Grader (ID:27501)
・Grade (ID:27502)

【Ungraded（ID:4000）】
・Card Condition (400010)

GradedのProfessional GraderやGradeの種類は多岐に渡るため[こちら](https://qiita.com/ebayjp_kumajoi/items/064e6c3ab64ffb396ef9)の記事をご参照ください(とてもわかりやすく私も参考にさせていただきました)。

## テーブル構成
テーブル構成は以下の通りです。

【categoryテーブル】
・CategoryID (Primary Key)
・CategoryName

【professional_graderテーブル】
・GraderID (Primary Key)
・GraderName
・GraderValue

【gradeテーブル】
・GradeID (Primary Key)
・GradeName
・GradeValue

【category_professional_graderテーブル(中間テーブル)】
・CategoryID (Foreign Key references category)
・GraderID (Foreign Key references professional_grader)

【professional_grader_grade テーブル (中間テーブル)】
・GraderID (Foreign Key references professional_grader)
・GradeID (Foreign Key references grade)

各categoryに対して複数のprofessional_graderが存在し、
各professional_graderに対して複数のgradeが関連付けられている多対多の構造となっています。

## リクエスト方法
コンディション設定のリクエストは、XML形式で以下のように行います(本記事の内容部分のみ抜粋)。
```request.xml
<Item>
　<PrimaryCategory> 
　　<CategoryID>183050</CategoryID>
　</PrimaryCategory>
　<ConditionID>27501</ConditionID>
　<ConditionDescriptors>
　　<ConditionDescriptor>
    　<Name>27501</Name>
    　<Value>275010</Value>
　　</ConditionDescriptor>
　　<ConditionDescriptor>
   　 <Name>27502</Name>
    　<Value>275022</Value>
　　</ConditionDescriptor>
　</ConditionDescriptors>
</Item>
```
この例では、
・categoryが Trading Card Singles（カテゴリID: 183050）
・conditionがGraded（ID: 27501）
・Gradedコンディションに対してConditionDescriptorというタグでProfessional Grader (PSA(Name:27501 Value:275010))と、Grade(9(Name:27502 Value:275022))を指定しています。
・Gradedの場合はConditionDescriptorsタグの中にConditionDescriptorタグを複数記載する形となっています（[Add_itemのドキュメント](https://developer.ebay.com/devzone/xml/docs/reference/ebay/AddItem.html)にはConditionDescriptorsの中のリクエスト方法が詳しく書かれていなかったので参考になれば幸いです）。
CentOS7 VirtualBoxでphpldapadminを構築してみた

# はじめに
phpldapadminを構築してみました。

以下のサイトを参考にしました。
https://infracollege.vamdemicsystem.black/linux/%e6%a7%8b%e7%af%89%e7%b7%a8/20-%e3%83%a6%e3%83%bc%e3%82%b6%e3%83%bc%e8%aa%8d%e8%a8%bc%e7%ae%a1%e7%90%86openldap/


# 前提条件
OpenLDAPサーバーは以下のサイトの手順通りで構築済みです。
https://qiita.com/gama1234/items/2dfd363a79d18f1e0ba2

# 構築手順
### apacheサービスをインストールした
```
yum -y install httpd
```
### apacheサービスを起動しました。またapacheサービスを自動起動する設定にしました
```
systemctl start httpd
systemctl enable httpd
```
### apacheのポートを許可する
```
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
```
### PHPインストール
```
yum -y install php php-mbstring php-pear
```
### phpldapadminのインストール
```
yum -y install epel-release
yum --enablerepo=epel -y install phpldapadmin
```
### IPアドレス許可設定
Reuire ipに自宅のLANのCIDRblockを追記する
自宅のLANのCIDRblockは各自環境によってIPアドレスが異なるため、確認してください。
```
vi /etc/httpd/conf.d/phpldapadmin.conf
```
```
#
#  Web-based tool for managing LDAP servers
#

Alias /phpldapadmin /usr/share/phpldapadmin/htdocs
Alias /ldapadmin /usr/share/phpldapadmin/htdocs

<Directory /usr/share/phpldapadmin/htdocs>
  <IfModule mod_authz_core.c>
    # Apache 2.4
    Require local
    Require ip 102.168.0.0/24 ←左記の設定を追加した
    Require all granted ←左記の設定を追加した
  </IfModule>
  <IfModule !mod_authz_core.c>
    # Apache 2.2
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1
    Allow from ::1
  </IfModule>
</Directory>
```

私の環境のIPアドレスコマンドプロンプトを開き以下のコマンドを実行して確認。
CIDRblockは192.168.0.0であることが分かりました。
```
ipconfig
   IPv4 アドレス . . . . . . . . . . . .: 192.168.0.24
   サブネット マスク . . . . . . . . . .: 255.255.255.0
   デフォルト ゲートウェイ . . . . . . .: 192.168.0.1
```

### 認証方法を変更する
```
vi /etc/phpldapadmin/config.php
```

```
$servers->setValue('login','attr','dn');
// $servers->setValue('login','attr','uid');
```
### phpldapadminにアクセスしました。
以下のIPアドレスでブラウザでアクセスしました
```
http://phpldapadminのIPアドレス/phpldapadmin/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/6401ac7f-fa83-b391-3d61-66878ca49d05.png)

ログイン成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/f1173445-d4dd-1752-0691-b611197e7e1d.png)

#### 補足情報
誤ったユーザー名又はパスワードを入れると以下のエラー画面が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/b58ff013-e0dc-f680-f0df-4537c6a65cfb.png)
SOLID原則の学習順番をS→I→D→O→Lにしたら理解度が増した気がする話

この記事は[設計こばなし Advent Calendar 2023](https://qiita.com/advent-calendar/2023/software_design_talk)の23日目です。

# 概要
2023年度、設計力アップのためSOLID原則を学び、社内・社外向け勉強会を開催・発信してきました。
SOLID原則を学習する順番をスペルとおりの順番ではなく、

1. **S**ingle-responsibility principle（単一責務の原則）
2. **I**nterface segregation principle（インターフェース分離の原則）
3. **D**ependency inversion principle（依存性逆転の原則）
4. **O**pen/closed principle（開放閉鎖の原則）
5. **L**iskov Substitution Principle（リスコフの置換原則）

にしました。
この順番で学んだ理由、感想について書きます。


# SOLID原則の学習順番をS→I→D→O→Lにした理由
SOLID原則について学び始めた時に@taktt7さんのQiita記事を見ました。

[オブジェクト指向習得のための５ステップ【SOLID原則】](https://qiita.com/taktt7/items/af90960f580373f3bb9b)

そのときの説明の順番が個人的にしっくりきてわかりやすく感じました。
そのため、この記事の順番でSOLID原則を学ぶことに決めました。


# 1番目にS（単一責務の原則）を学習した感想
単一責務の原則はつぎの原則です。

* クラスは1つの責任のみを持っている
* クラスの変更理由はひとつ

この原則はクラスを形づくる基本だと思います。
原則自体もシンプルで（実践して使いこなすのは難しいと個人的に思っている）、わかりやすくはじめに学習する原則として良いと思います。

# 2番目にI（インターフェース分離の原則）を学習した感想
インタフェース分離の原則はつぎの原則です。

* 相手に必要なことだけ見せるようにする。必要ないことを見せると関連が必要ないクラスと関連を持ってしまったり変更の影響が大きくなってしまう。

単一責務の原則で1つの責任をもつクラスが理解できていればそれほどインターフェース分離の原則に難しさを感じないと思います。
逆にいうと単一責務の原則のつぎに学ぶと比較的理解しやすい原則かと個人的に思いました。

# 3番目にD（依存性逆転の原則）を学習した感想
依存性逆転の原則はつぎの原則です。

* 上位レベルのモジュールは下位レベルのモジュールに依存しないようにする。上位も下位も抽象に依存すべきである。

わたしは原則の名前から推測するといきなり高度な内容になると感じました。
ただ、なぜ抽象に依存すべきなのか?、に注目すると理解しやすい原則かと思います。
この依存性逆転の原則がなぜ3番目なのかですが、4番目の開放閉鎖の原則に則るために必要な考え方をこの原則で学ぶからだと考えています。
そういった意味で依存性逆転の原則は3番目に学ぶのが良いと感じました。

# 4番目にO（開放閉鎖の原則）を学習した感想
開放閉鎖の原則はつぎの原則です。

* 拡張に開かれており（Open）、変更に閉じられていること （Closed）。機能拡張（追加）の際にクライアントコード（機能追加したコードを使う側）に変更が発生しないこと。

この原則に則るために機能追加側のコードは依存性逆転の原則を使います。これでクライアントコードは変更が発生しない構造をつくることが可能になります。


# 5番目にL（リスコフの置換原則）を学習した感想
リスコフの置換原則はつぎの原則です。

* サブタイプのオブジェクトはスーパータイプのオブジェクトの仕様に従わなければならない
* 基底型オブジェクトを派生型オブジェクトで型安全に代替できること

個人的にSOLID原則の中で一番難しいのがリスコフの置換原則だと思っています。
ただ、この原則も開放閉鎖の原則を学んでいると理解しやすいと思います。

書籍: [テスト駆動開発による組み込みプログラミング―C言語とオブジェクト指向で学ぶアジャイルな設計](https://www.oreilly.co.jp/books/9784873116143/)につぎの記載があります。

> 11.1.3 リスコフの置換原則（Liskov Substitution Principle）
> リスコフの置換原則（LSP）はオープン・クローズドの原則（OCP）と同じように聞こえるかもしれない。
> これはオープン・クローズドの原則（OCP）とリスコフの置換原則（LSP）がコインの裏表の関係にあるためだ。

開放閉鎖の原則を先に学んでいるとリスコフの置換原則も理解しやすいと思います。


# 作成資料一覧
SOLID原則の勉強会の資料はこちらに保存しています。よければ参照ください。

| No | 開催日 | 勉強会タイトル&資料リンク | Xスペース録音URL |
|:-----------|:------------|:------------|:------------|
| 1       | 2023/7/20        | [#1 単一責務の原則](https://www.docswell.com/s/juraruming/K98M19-2023-07-20-143150)         | -         |
| 2       | 2023/8/28        | [#2 インターフェース分離の原則](https://www.docswell.com/s/juraruming/KJLWEM-2023-08-28-005645)         | [URL](https://twitter.com/i/spaces/1lDGLnPowBZxm?s=20)         |
| 3       | 2023/9/28        | [#3 依存性逆転の原則](https://www.docswell.com/s/juraruming/5EN9ME-2023-09-28-065704)         | [URL](https://twitter.com/i/spaces/1YqKDoZgMvzxV)         |
| 4       | 2023/10/26        | [#4 開放閉鎖の原則](https://www.docswell.com/s/juraruming/5LL836-2023-10-26-074605)         | [URL](https://twitter.com/i/spaces/1nAKEaOpWzVKL)         |
| 5       | 2023/11/30        | [#5 リスコフの置換原則](https://www.docswell.com/s/juraruming/Z6Y8X7-2023-11-30-081051)         | [URL](https://twitter.com/i/spaces/1rmGPMWRdQdJN)         |
Phoenix LiveView で mouseenter 、 mouseleave イベントを扱う

## はじめに

Elixir の Web フレームワーク Phoenix LiveView では `phx-click` などのバインディングによって Web 上のイベントを Elixir に伝えます

https://hexdocs.pm/phoenix_live_view/bindings.html

しかし、マウスカーソルが要素に入ったときのイベント mouseenter や要素から出たときのイベント mouseleave はバインディングに存在しません

少し工夫が必要になります

Elixir forum の以下の提案を参考に実装しました

https://elixirforum.com/t/phoenix-liveview-request-proposal-mouse-events/31213

## どういうときに必要か

そもそも、単に Web 上の見た目を変えるだけなから TailwindCSS の `hover:` を使うだけで十分です

https://tailwindcss.com/docs/hover-focus-and-other-states#hover-focus-and-active

また、ちょっとした動作の制御であれば Alpine.js で `x-on:mouseenter` と `x-on:mouseleave` で事足ります

https://alpinejs.dev/

無駄にややこしくする必要はないので、基本的には TailwindCSS と Alpine.js だけで実装してしまう方がいいでしょう

Elixir 側での制御、ソケットで管理している値に介入する必要がある場合のみ、以下の実装が必要になります

## 実装

マウスイベントを拾いたい要素にフックを紐づけます

イベントで渡したい引数（`%{"some_key" => "some_value"}`）があれば `data-` で持たせておきます

Heex
```heex
<div
  id="some-element"
  phx-hook="MouseHook"
  data-some_key="some_value"
/>
```

フックでは `mounted` の中で `mouseenter` と `mouseleave` のイベントリスナーを追加します

`pushEvent` の第2引数に `event.target.dataset` に `data-` で指定した引数が入っています

JS
```javascript
const MouseHook = {
  mounted () {
    this.el.addEventListener('mouseenter', event => {
      this.pushEvent('mouseenter', event.target.dataset)
    })
    this.el.addEventListener('mouseleave', event => {
      this.pushEvent('mouseleave', event.target.dataset)
    })
  }
}
```

Elixir では `pushEvent` で JS から来たイベントを `handle_event` で受け取ります

Elixir
```elixir
...
  @impl true
  def handle_event("mouseenter", %{"some_key" => some_value}, socket) do
    ...
    {:noreply, socket}
  end

  @impl true
  def handle_event("card_mouseleave", %{"some_key" => some_value}, socket) do
    ...
    {:noreply, socket}
  end
...
```

## まとめ

基本的に Hooks を通した JS との連携でなんとでもなります

ただし、 Elixir でやるべきことと JS でやるべきことは上手く線引きしないと、どんどんややこしい実装になるので注意しましょう

基本的には JS を多用しすぎない方がいいです
LLMの知識習得と固有表現認識について

## はじめに
大規模言語モデル（LLM）の開発において、事前学習とファインチューニングは不可欠なプロセスです。これらのステップにより、LLMは新しい知識を効率的に習得し、より高度なタスクに対応できるようになります。

LLMの知識習得の効果を評価する方法の一つは、特定の知識を必要とする問題を解かせてみることです。さらに、LLMが情報をどのように理解しているかは、**固有表現認識**で明らかにできます。

本記事では、固有表現認識を中心に解説してきます。

### 固有表現認識(NER)とは
固有表現認識（NER）は、テキスト内の特定の情報（人名、地名、組織名など）である**固有表現**を自動的に識別し、カテゴリーに分類する技術です。

固有表現は、(1)MUCの定義(2)IREXの定義(3)拡張固有表現階層の定義など様々な定義があります。
以下でそれぞれについて解説していきます。

### MUC

まずは最もシンプルなMUCの定義を述べます。MUCは以下の7つのカテゴリーで固有表現を定義されます。


| MUCのカテゴリー       | 具体例1                              | 具体例2                          | 具体例3                                |
|----------------|-----------------------------------|-----------------------------|-----------------------------------|
| 人名 (Person)  | 「田中太郎」は日本の学生です。        | 「アンジェリーナ・ジョリー」が新しい映画に出演します。 | 「バラク・オバマ」はアメリカの元大統領です。   |
| 場所 (Location) | 「東京タワー」は日本のランドマークです。 | 「エベレスト山」は世界で最も高い山です。    | 「セントラルパーク」はニューヨークにあります。  |
| 組織 (Organization) | 「Google」は技術企業です。          | 「国際連合」は国際機関です。             | 「東京大学」は日本の大学です。              |
| 日付 (Date)     | 「2023年1月1日」に新年が始まります。   | 「7月4日」はアメリカの独立記念日です。    | 「第二次世界大戦」は「1939年9月1日」に始まりました。 |
| 時間 (Time)     | 「午前9時」に会議が始まります。        | 「夜8時半」に映画が始まります。           | 「午後3時15分」に電話会議があります。         |
| 金額 (Money)    | 「500ドル」で新しいスマートフォンを購入しました。 | 「1000円」で昼食を食べました。         | 「2万5千ユーロ」は車の価格です。            |
| パーセンテージ (Percentage) | 「50%」の割引が適用されました。       | 「10%」の増税が予定されています。       | 「成績が25%向上」しました。                |

また固有表現認識は、**入れ子を考慮するかどうか**で手法が異なります。

入れ子を考慮する場合は、「東京タワー」という言葉に対して「東京」「東京タワー」という２つの重複した固有表現を許容します。

以降では入れ子を考慮せずに固有表現認識を行っていきます。

:::note 
入れ子を考慮する場合の固有表現認識はNested NER、考慮しない場合はFlat NERといいます。
:::

### IREX
IREXはMUCに固有物名(ARTIFACT)を加えた8つのカテゴリーで固有表現が定義されます。
固有物名とは人間が作り出した具体物•抽象物であり、「モナ・リザ」「吾輩は猫である」「ロミオとジュリエット」などが固有物名となります。

:::note warn 
ただ固有物名は、定義が難しいです。例えば「吾輩は猫である」は固有物名ですが、文脈（ここでは時代といった方がわかりやすいかも）によっては「吾輩」「猫」というように固有表現を定義できます。

固有物名の定義の困難さについては以下の論文で詳述されています。

:::

https://www.anlp.jp/proceedings/annual_meeting/1999/pdf_dir/B2-1.pdf


### 拡張固有表現階層
MUCやIREXの定義は7,8カテゴリーと数が少なく、詳細な固有表現は定義できていません。例えばMUCやIREXでは先述した「東京タワー」と「エベレスト」では、場所という性質で同一の固有表現で定義されますが、実際にLLMの知識習得の確認をしたい場合は、もっと細かく固有表現を分けて欲しいです。

拡張固有表現階層は、大きく名前、時間表現、数値表現に分かれた固有表現を階層化したものです。

拡張固有表現階層現在も更新されており、2023年12月最新版(バージョン9)は以下になります。

![ 2023-12-25 0.00.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/388e0b70-4ed0-f698-7085-b345f64052b3.png)

http://ene-project.info/ene9/

上図より、拡張固有表現階層はMUCやIREXに比べて固有表現の種類が非常に多いことがわかります。先述した「東京タワー」と「エベレスト」についても「施設名」「地名」というように、しっかり分類できることがわかります。

また固有表現の粒度を荒くしたい場合は、ある固有表現の一つ上の階層の固有表現を参照すれば良いので、簡単に調整は可能です。

以上より、LLMが情報をどのように理解しているかは拡張固有表現階層をベースにした固有表現認識が最も有効だと考えられます。

## おわりに
本記事では固有表現認識に解説し、LLMが情報をどのように理解しているかの確認では、拡張固有表現階層をベースにした固有表現認識が有効であると述べました。

次回以降、拡張固有表現階層をベースにした固有表現認識を実践ベースで紹介していきます。
(本当はアドベントカレンダーに間に合わせたかったのですが、間に合いませんでした。無念。。。)
【Sidekiq】特定のジョブだけ排他制御

https://rubygems.org/gems/sidekiq-unique-jobs/versions/8.0.3?locale=ja

これを使います。

# コード
```ruby
class Worker
  include Sidekiq::Workers

  sidekiq_options lock: :while_executing, on_conflict: :hogefuga_strategy,
                  lock_args_method: :lock_args
  def perform(id, piyo)
    # Do work
  end
end
```

このコードでは、`id`, `piyo` が同一のジョブが並列実行されないように制御されます。もし衝突が発生した場合、`hogefuga_strategy` が呼び出されてジョブは消費されます。

## 衝突時

```lib/strategies/hogefuga_strategy.rb
module Strategies
  class HogeFugaStrategy < SidekiqUniqueJobs::OnConflict::Strategy
    def call
      Worker.perform_async(
        item['args'][0],
        item['args'][1]
      )
    end
  end
end
```

このようなコードを組むと、衝突したらまたキューに詰めなおすという戦略になります。重複するジョブが多い場合はパフォーマンスに影響を与えますが、同じジョブが同時に実行されることはなく、ジョブが消失することもありません。

# おわり
普通に考えると、並列するとまずいやつ用のキューを用意して直列実行できるような構成を取るべきですね。泣
Goのベンチマークをとる

# ベンチマーク
Goには標準関数でベンチマークを計測するものがあるので、試してみます。
ベンチマーク対象はフィボナッチ数列を計算する関数です。

## フィボナッチ数列の計算

```go:main.go
package main

func Fibonacci(n int) int {
	if n <= 1 {
		return n
	}
	return Fibonacci(n-1) + Fibonacci(n-2)
}

```

## ベンチマーク関数の作成
```go:main_test.go
package main

import "testing"

func BenchmarkFibonacci(b *testing.B) {
	for i := 0; i < b.N; i++ {
		Fibonacci(10)
	}
}
```
特徴は`*testing.B`型を渡していること、関数名の接頭辞が`Benchmark`であることです。


## ベンチマーク実行
```bash
$ go test -bench=BenchmarkFibonacci
```

### 結果
```bash
$ go test -bench=BenchmarkFibonacci
goos: darwin
goarch: arm64
pkg: app
BenchmarkFibonacci-10    	 6455626	       186.2 ns/op
PASS
ok  	github.com/shuyaeer/learn-go/app/day23	1.492s
```

この関数は6455626回呼び出され、１回の呼出しは186.2 ns程のようです。
すべての回数呼び出すのに1.492sかかったということを表しています。

テストだけではなく、ベンチマークを取ることでパフォーマンス改善にやくだてられそうですね。
クリスマスプレゼント

こんにちは、こんばんんわ！！
カレンダー２５日が空いていたのでポエムで締めたいと思います。

Symbolはオープンソースなので法人、個人問わずに自由に使ったら良く
足りないところは開発に参加すれば良いと思います。

ブロックチェーンはファウンダーの信頼の元に続きます。
信頼が失われた場合はフォークする事になります。

コミニュティの力が推進力です。
実際ビットコインの開発者、サトシは撤退しています。

これがブロックチェーンネイティブのルールだと思います。
ファウンダーに期待するのは虚像だと思います。
真のブロックチェーン開発者が作りたいのはサービスでは無いのです。

Symbolコア開発者がそうなのかは分かりませんがこの船に乗っています🚢
船長は船を出しましたが乗組員にはそれぞれの目的地があります。

このカレンダーには素晴らしいクリスマスプレゼントが沢山あります。
プレゼントを読んで是非Symbolを学びチャレンジしてみてください。

それでは皆様メリークリスマス🎵 2023-Bootarou
M5Stackのメモリ不足（mbedTLS）

# はじめに

以前作成したM5Stackの通信アプリを2年ほど運用してきて、改修の必要がありビルドし直したところ、これまで動いていたアプリが動かなくなってしまいました。（M5Stackあるある）

アプリはWebSocket通信を行うものですが、認証用のトークンの取得/更新のhttpsリクエストを行い、モノの管理やログ出力にMQTTを使っています。最大3つのhttpsセッションを張ることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/ce3adc18-a25a-0e65-53d8-f5a9c93a0f4b.png)

M5Stackのライブラリーが更新されたことで、メモリー不足になってしまいました。特にWiFiClientSecure+mbedTLSでだいたい90Kbyteくらい空きのヒープが必要なようです。

これは build_flags = -DCORE_DEBUG_LEVEL=5 を指定して詳細なログを出力させないとわかりませんでした。

# 回避策

今回は運用中のアプリということもあり、時間が限られる中の対応となりました。結論を言えば、mbedTLSの代わりに [SSLClient](https://github.com/OPEnSLab-OSU/SSLClient) ライブラリーを使用しました。

#### PubSubClient

MQTTには [PubSubClient](https://github.com/knolleary/pubsubclient) を使用していたので、WiFiSclientSecureに代えてSSLClientを指定します。

```C++:前
WiFiClientSecure https_client;
PubSubClient mqtt_client(https_client);
```

```C++:後
WiFiClient base_client;
SSLClient https_client(base_client, TAs, (size_t)TAs_NUM, rand_pin);
PubSubClient mqtt_client(https_client);
```

#### SSLClient

httpsのPOSTリクエストはWiFiClientSecureライブラリーだと簡単に記述できますが、SSLClientは少しコード量が増えます。

SSLClientは証明書に代えて、[TrustAnchors](https://github.com/OPEnSLab-OSU/SSLClient/blob/master/TrustAnchors.md#generating-trust-anchors) を使用します。 [BearSSL Trust Anchors Generator](https://openslab-osu.github.io/bearssl-certificate-utility/) のWebサイトで生成することができますので、これをincludeして利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/e24c9298-ac89-1433-02c7-bf17ae32e905.png)

# まとめ

結果、なんとか3つのセッションのうち2本をSSLClientに切り替えることで、応急処置することができました。空きのヒープは少し増えましたが、ファームウェアのサイズ（フットプリント）は少し増えました。
現時点でSSLClientはTLS1.3にはまだ対応していなかったり、どこかのタイミングで改めて見直しが必要になるかもしれません。

# 2023/12/31追記

しばらく運用していると下記のようなエラーが出力されて接続できなくなりました

```
20:53:51.515 -> (SSLClient)(SSL_WARN)(connect): Arduino client is already connected? Continuing anyway...
20:53:51.515 -> (SSLClient)(SSL_WARN)(m_run_until): Terminating because the ssl engine closed
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_start_ssl): Failed to initlalize the SSL layer
20:53:51.515 -> (SSLClient)(SSL_ERROR)(m_print_br_error): Certificate is expired or not yet valid.
```

イシューがありました。時刻の表記の問題らしい。
https://github.com/OPEnSLab-OSU/SSLClient/issues/27

```cpp:
unsigned long RTCTime = time(nullptr);
sslClient.setVerificationTime((uint32_t)((RTCTime / (SECS_PER_DAY)) + 719528UL), (uint32_t)(RTCTime % (SECS_PER_DAY)));
```
かんたん（涙）消しゴム機能モデルLamaをpip packageで使う

# 消しゴム機能が泣けるほど簡単に
画像加工アプリとかでよくある消しゴム機能。
画像のいらない部分を消せるあの機能が数行のコードで使える。3150。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/33d2f92c-3cef-e127-ebbf-d66ca155ca8d.gif width=300>

# 消しゴム機能を使ってみるColabデモ

https://colab.research.google.com/drive/1nmg_5wx2ojImv_NWW7vvJOcY44hrWkP_?usp=sharing

# 使い方

#### インストール

```shell
pip install simple-lama-inpainting
```

#### 実行

画像と、消したい部分を白く塗ったマスク画像（グレースケール）を用意して実行します。
上の画像の例で言うと、ネックレスを消すので、

１、画像↓
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/aef86899-5b3e-5054-d2f9-e72d73689eab.jpeg width=300> 

２、マスク画像↓
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/307e568d-2a82-2640-1739-f3c417ea6f91.png width=300>

となります。

```python
from simple_lama_inpainting import SimpleLama
from PIL import Image

simple_lama = SimpleLama()

img_path = "image.jpg"
mask_path = "mask.png"

image = Image.open(img_path)
mask = Image.open(mask_path).convert('L')

result = simple_lama(image, mask)
result.save("inpainted.png")
```

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/c7900e97-361d-9f9e-0d45-ad20db389066.png width=300>

とってもかんたんでしょ？

🐣
****
フリーランスエンジニアです。
AIについて色々記事を書いていますのでよかったらプロフィールを見てみてください。

もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…

いずれも中間コストを省いたリーズナブルな価格でお請けできます。

お仕事のご相談はこちらまで
rockyshikoku@gmail.com

機械学習やAR技術を使ったアプリケーションを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
phpldapadminにブラウザでアクセスするとForbidden You don't have permission to access /phpldapadmin/on this serverが表示される

## ldapadminにアクセスすると403 forbiddenが表示される

### 前提条件
CentOS7でOpenLDAPにphpldapadminをインストールした環境です。

phpldapadminにアクセス出来ない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/90919cda-55e1-5d0a-06f2-6536c674f970.png)


### 解決策
#### apacheのログを確認した
phpldapadminにブラウザからアクセスした際にアクセスログの更新日時が
ブラウザからアクセスした日時になっているため、アクセス自体は出来ていることが分かりました。
```
[root@localhost httpd]# ls -ltr
合計 20
-rw-r--r-- 1 root root  3129 12月 24 23:46 error_log
-rw-r--r-- 1 root root 12335 12月 24 23:48 access_log ※アクセスした日時になっていることを確認した。
```

apacheのアクセスログを確認した。
```
less /var/log/httpd/access_log


[Sun Dec 24 23:38:26.955881 2023] [lbmethod_heartbeat:notice] [pid 1680] AH02282: No slotmem from mod_heartmonitor
[Sun Dec 24 23:38:26.966327 2023] [mpm_prefork:notice] [pid 1680] AH00163: Apache/2.4.6 (CentOS) PHP/5.4.16 configured -- resuming normal operations
[Sun Dec 24 23:38:26.966349 2023] [core:notice] [pid 1680] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'
[Sun Dec 24 23:38:53.025627 2023] [authz_core:error] [pid 1682] [client 192.168.0.24:52535] AH01630: client denied by server configuration: /usr/share/phpldapadmin/htdocs/
[Sun Dec 24 23:39:01.251828 2023] [authz_core:error] [pid 1683] [client 192.168.0.24:52536] AH01630: client denied by server configuration: /usr/share/phpldapadmin/htdocs/
[Sun Dec 24 23:39:04.076830 2023] [authz_core:error] [pid 1683] [client 192.168.0.24:52536] AH01630: client denied by server configuration: /usr/share/phpldapadmin/htdocs/
[Sun Dec 24 23:39:04.834566 2023] [authz_core:error] [pid 1683] [client 192.168.0.24:52536] AH01630: client denied by server configuration: /usr/share/phpldapadmin/htdocs/
[Sun Dec 24 23:40:38.547631 2023] [authz_core:error] [pid 1684] [client 192.168.0.24:52560] AH01630: client denied by server configuration: /usr/share/phpldapadmin/htdocs/
```
#### phpldapadminの設定ファイルを確認した

Require all granted は「全てのユーザーに対してアクセスを許可する」設定をしました。

参考にしたサイト
https://kakakazuma.hatenablog.com/entry/2015/03/19/234754
```
vi /etc/httpd/conf.d/phpldapadmin.conf
```

```
#
#  Web-based tool for managing LDAP servers
#

Alias /phpldapadmin /usr/share/phpldapadmin/htdocs
Alias /ldapadmin /usr/share/phpldapadmin/htdocs

<Directory /usr/share/phpldapadmin/htdocs>
  <IfModule mod_authz_core.c>
    # Apache 2.4
    Require local
    Require ip 102.168.0.0/24
    Require all granted ←左記の設定を追加した
  </IfModule>
  <IfModule !mod_authz_core.c>
    # Apache 2.2
    Order Deny,Allow
    Deny from all
    Allow from 127.0.0.1
    Allow from ::1
  </IfModule>
</Directory>
```
#### apacheの文法チェックしました

```
httpd -t 
Syntax OK
```
#### apacheのサービスを再起動しました
```
systemctl restart httpd
```
#### phpldapadminにアクセス出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/353c98bb-c1e2-eaf1-0443-70b22232b265.png)
量子計算機シミュレータを用いた素因数分解

この記事は Fujitsu Advent Calendar 2023 13日目の記事です。

量子計算機シミュレータを用いて大規模な素因数分解実験を行ったので、改めて情報を整理したいと思います。

# 背景
## 素因数分解 vs 計算機
素因数分解とは、合成数を素数の積に変形することです。$15$ や $21$ のような小さい合成数ならば暗算でも素因数分解できますが (ちなみに $15=3 \times 5, 21=3 \times 7$)、これが $20231213$ や $2023121320231223$ のように大きくなってくると暗算では厳しくなってきます。それでも通常の計算機を使えばそれぞれ 
$20231213=53 \times 89 \times 4289$ 
や 
$2023121320231213=1229 \times 1646152416787$ 
のように素因数分解できます。しかしこれが $200$ 桁ともなると、通常の計算機を使っても素因数分解は難しくなってしまいます。このような「巨大な合成数の素因数分解は極めて難しい」という性質を利用して公開鍵暗号やデジタル署名が開発され、インターネットの安全性を支えるために世界中で広く使用されるに至っています。

なお通常の計算機を使った具体的な素因数分解アルゴリズムや素因数分解の記録については、私が以前に書いた「[素因数分解の現状 (古典計算編)](https://qiita.com/izutetsuya/items/ff0347d26d1699ae3a94)」という記事を参照ください。

## 素因数分解 vs 量子計算機
ところが量子計算機が登場すると状況が一変します。1994 年に Peter Shor が開発した Shor アルゴリズムを用いると、量子計算上で素因数分解を簡単に解けるようになるのです。合成数の大きさを大きくしたとしても、Shor アルゴリズムが必要とする量子計算のリソースはあまり増加しないため、現在使用されている公開鍵暗号やデジタル署名は Shor アルゴリズムによって解読されてしまうことを意味しています。
【React】textareaを特定のキーで確定できるようにする方法


以下のように記述すると`cmd` + `Enter`または`ctl` + `Enter`で`textarea`の内容をsubmitできます。

```tsx
// ...
export function Sample() {
  // ...

  const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
      // submitのための処理
    }
  }

  return (
    <form onSubmit={handleSubmitWrapper} onBlur={handleBlur}>
      <textarea
        onKeyDown={handleKeyDown}
      />
    </form>
  )
}
// ...

```
コミットメッセージの書き方の一例

この記事は[ドワンゴ Advent Calendar 2023](https://qiita.com/advent-calendar/2023/dwango)の  24 日目の記事です。

ドワンゴ教育事業部でインターンとして参加させていただいている乗算記号と申します。

今回はAngular commit messageを基にコミットメッセージの書き方について紹介いたします。

## Angular commit message
Angular commit messageとは、JavaScriptフレームワークであるAngularのレポジトリ内で使用されているコミットメッセージのフォーマットのことを指します。
構造は**header**, **body**, **footer**からなります。
```
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```

https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format

https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit

## Header
以下に[Commit Message Header](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit-message-header)を翻訳したものを示します。

```
<type>(<scope>): <short summary>
  │       │             │
  │       │             └─⫸ 現在形で簡潔な要約, 大文字でない, 最後にピリオド(句点)なし
  │       │
  │       └─⫸ コミットの影響範囲: animations|bazel|benchpress|common|compiler|compiler-cli|core|
  │                          elements|forms|http|language-service|localize|platform-browser|
  │                          platform-browser-dynamic|platform-server|router|service-worker|
  │                          upgrade|zone.js|packaging|changelog|docs-infra|migrations|
  │                          devtools
  │
  └─⫸ コミットの種類: build|ci|docs|feat|fix|perf|refactor|test
  ```

### Type
以下のいずれかから選択:

- **build**: ビルドシステムまたは外部の依存関係に影響を及ぼす変更(例: gulp, broccoli, npm等)
- **ci**: CI設定ファイルやスクリプトの変更 (例: CircleCi, SauceLabs等)
- **docs**: ドキュメントのみの変更 (例:コメント,TSDoc等)
- **feat**: 新機能の実装・スタイルの付与
- **fix**: 表示崩れ・バグ・不具合等の修正
- **perf**:パフォーマンスを向上させるコードの変更
- **refactor**: バグ修正や機能追加を含まないコードの変更、実装方法の変更
- **test**: 不足しているテストの追加や既存のテストの修正
- **chore**: コアコード以外のコード (test,story等 ※*最新のangularでは廃止*)

### Scope
コミットの変更箇所を記載、変更したファイル名や上位のディレクトリ名等を記載、記載しないこともある。

### Summary
- 現在型を用いて簡潔に述べる
- (.)や(。)で終わらない
- このコミットを適用した際にどうなるのかを簡潔に説明する
❌悪い例: Propsを受け取った際の挙動を実装
⭕️良い例: Propsを受け取った際にコンポーネントの色をPropsに応じて変更するように実装

## Body
変更を行なった動機やなぜこの変更を行うのかを記載する。
Summaryと同じように現在形を用いて簡潔に述べる。
小さな変更だと記載しないこともある。

## 終わりに
インターンに参加してコミットメッセージを書く際に戸惑った経験があるため、記事にさせていただきました。
稚拙な文章ですので、ご意見ご指摘等あればコメントをお願いします。

また、レポジトリごとのルールに差があるかと思いますので困った際はレポジトリの規約に詳しい方に聞いてみてください。

## 参考
https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commit-message-format

https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit

https://zenn.dev/szn/articles/angularjs-commit-messeage-convention-jp
[メモ]Spring Boot 3.xでSpring Data JPAを使用する（Hibernate, MySQL）

Spring Boot 3.x(Spring Framework 6.x)＋Hibernate＋MySQLでSpring Data JPAを使おうとすると、バージョンによって動作しないことがあり、調べても明確に設定が書かれた記述を見つけられなかったので、メモを残しておきます。

## 使用したライブラリの組み合わせ

使用したライブラリは以下の組み合わせになります。

- Spring Boot 3.2.1
- Spring Framework 6.1.2
- Hibernate 6.3.1
- MySQL JDBC Driver 8.1.0

`build.gradle`の設定で書く以下のようになります。

## 結論

ライブラリのバージョンの指定（Gradleの場合）と`application.properties`の設定は以下のようになります。

``` build.gradle
dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa:3.2.1'
    implementation 'org.hibernate:hibernate-core:6.3.1.Final'
	runtimeOnly 'com.mysql:mysql-connector-j:8.1.0'
}
```

``` application.properties
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
```

調べた限りでは余計な設定をすると起動時にエラーが出るため、その点については後述しています。

## 設定のポイント

試した結果わかったポイントは以下の2点です。

### Spring Frameweork 6.xではJakartaEE 9+をサポートするようになっているため、Hibernate 6.xを使用する必要がある

Spring Framework 6.xでHibernate 5.xを使用すると、起動時に以下のエラーが発生します。

```
Class org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider does not implement the requested interface jakarta.persistence.spi.PersistenceProvider
```

このため、Sprnig Framework 6.xを使用する場合は、Hibernate 6.xを使用する必要が出てきます。

### `spring.jpa.database=mysql`を指定すると、MySQL57Dialectを参照しにいく

`application.properties`で`spring.jpa.database=mysql`を指定すると、以下のエラーが発生します。

```
defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: org/hibernate/dialect/MySQL57Dialect
```

Hibernate 5.xではMySQL57Dialectは存在しますが、Hibernate 6.xでは削除されており、MySQLDialectを使用するように変わっています。

`spring.jpa.database=mysql`の設定は、`spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect`の設定よりも優先されるようで、`spring.jpa.database=mysql`の設定を行うと、`spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect`の設定を行っても`MySQL57Dialect`を探しにいくようです。

## どうすればいいのか

先に設定を示しましたが、設定のポイントは

- Spring Framework 6.xでSpring Data JPAを使用し、JPA ProviderとしてHibernateを使用する場合は、6.xを使用する
- dialectの指定を有効にするためには`spring.jpa.database=mysql`の設定は使用してはいけない

の2点になります。

新規構築時もそうですが、Spring Framwork 5.xから6.xへバージョンアップする際にもはまりそうなポイントだと思いました。
フレームワーク(Ruby on Rails)を触って出てきた横文字たちの正体とは？


# はじめに
自分は10月よりAPPRENTICE SHIP(内定直結型エンジニア学習プログラム)のカリキュラムに２期生として参加しています。
今回はRuby on Railsを学び始めて謎の横文字が多く出てきます。
その中で特に覚えておきたいけど、毎度詳細を聞かれると調べ直しているものをピックアップしてまとめました。

# MVCモデル
## MVCモデルとは？
MVC（Model-View-Controller）モデルは、ソフトウェア開発のための「設計パターン」の一つになります。

## M(モデル)
モデルはアプリケーションのデータやビジネスロジックを管理します。
データベースへのアクセスやデータの操作、バリデーションなどが含まれます。

## V(ビュー)
ビューはユーザーに対する表示やインターフェースを担当します。
ユーザーが見ることができる部分やユーザーとの対話が含まれます。
Railsだとerb(テンプレートエンジン)を用いて各場所がビューに該当します。

## C(コントローラー)
モデルとビューの制御を担う場所になります。
コントローラーはユーザーからの入力を受け取り、それに基づいてモデルの状態を変更し、最終的にビューを更新します。ユーザーとモデル、ビューの仲介役です。

## 何が良いのか？
各部分が独立しているため、変更がしやすく保守性が高い。
そのため開発が分業しやすく、同時進行での開発が容易になります。
つまり複数人での開発に向いているということになります。
チーム開発にはもってこいと言うわけです。

## デメリット
学習した方なら思われると思いますが、MVCモデルの理解や実装に時間がかかることがあります。
現在学習中ではありますが、おおまかな流れは理解できましたが、そのフレームワーク特有の書き方に学習コストが掛かると思うのが自身の感じたところではあります。

## MVCモデルが採用されているフレームワーク
- Ruby on Rails (Ruby)
- Laravel (PHP)
- Express (Node.js)
- Django (Python)
- Spring (Java)


# REST API

## まずAPIとは
API（Application Programming Interface）は、ソフトウェア同士が相互に通信するためのインターフェースです。
WEB開発では主にWEB APIのことを指すことが多くあります。

## REST API
REST（Representational State Transfer）は、上記のAPIを用いてシンプルにWEBシステムを作るための「設計思想」になります。
これについてはREST APIの4原則というものがあり、それを満たすとRESTFULなシステムと呼ばれます。

## REST APIの4原則とは
- 統一インターフェース
- アドレス可能性
- 接続性
- ステートレス性
 の４つです。
### 統一インターフェース
- 標準的なHTTPメソッド（GET、POST、PUT、DELETEなど）を使用すること
- JSON,XMLなどの形式のデータを使うこと

### アドレス可能性
- URLが意味を持ち理解しやすいこと、つまりURLを見ただけでおおよその意味を推察できるものにすること
- 階層的な構造にすること

### 接続性
- リソースに含まれるリンクをもとに別のリソースに接続可能となる(遷移可能となる)性質のこと

### ステートレス性
- クライアントの前回の要求や状態をサーバーが保存しない仕組みにすること
- 全てのHTTPリクエストが完全に分離している性質のこと


# TDD(テスト駆動開発)
## TDDとは
TDD（Test-Driven Development）は、開発者がまずテストを書き、その後そのテストをパスするようにコードを実装していく「開発手法」です。

## 具体的な方法
### 1.テストの作成（Red）
開発者はまず、実装しようとしている機能や機能の一部に対するテストケースを書きます。

### 2.テストを通る最小のコードを実装（Green）:
開発者はそのテストを通過する最小のコードを実装します。目標は、テストをパスさせるだけのコードを書くことです。

### 3.リファクタリング（Refactor）:
テストがパスしたら、コードをリファクタリングして可読性や保守性を向上させます。この段階では新しい機能を追加しないように注意します。

### 4.テストの追加（Repeat）:
新しい機能や修正が必要な場合、または既存の機能に対する仕様が変更された場合、新しいテストケースを追加します。この時点でテストは再び赤い状態になります。

### 5.テストを通る最小のコードを実装（Repeat）:
テストが赤い状態になったら、再び最小のコードを実装してテストをパスさせます。
このサイクルを繰り返すことで、徐々にアプリケーションが機能し、かつ信頼性のあるコードベースが構築されていきます。 

# 感想
今回はフレームワークを触る上でよく出てくる物に焦点を当ててみました。
テスト駆動開発などはまだ触れられていない部分があり、今後の実装でも積極的に取り入れていくべきだと感じました。
現在の開発では必須知識と聞くので、自分も理解を深めて早く活用できるよにして行きたいです。
【UEFN】 マップインジケーターの仕掛けをVerseで扱ってみる

## 背景
チュートリアルやタイクーンなどでとてもよく使われているデバイスになります。どのように利用するか知りたかったので調査しました。

## やること
トリガーを押して順番に次の目標を指すようにする

### 動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/ceqtgRE-oI8?si=lJLk78EOerpsM9Sh" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## 実装

### 利用するDevice
トリガー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/5ea34a5b-01d2-1995-9831-e8989e644f70.png)
マップインジケーターの仕掛け
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/0480c00c-8a38-3ccd-b50e-3d1e001f8412.png)

デフォルトの設定のまま使います。

#### 配置
トリガーそれぞれの位置にインジケータを重ねて配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692976/353d67c1-9522-dd5a-9e15-89fdf58cb09d.png)


### 全体コード
```
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }

map_indicator_controller_device := class(creative_device):

    @editable
    Initial:trigger_device=trigger_device{}

    @editable
    SecondIndicator:map_indicator_device=map_indicator_device{}

    @editable
    ThirdIndicator:map_indicator_device=map_indicator_device{}

    @editable
    Second:trigger_device=trigger_device{}

    @editable
    Third:trigger_device=trigger_device{}

    OnBegin<override>()<suspends>:void=
        Initial.TriggeredEvent.Subscribe(Initialize)
        Second.TriggeredEvent.Subscribe(ActivateSecond)
        Third.TriggeredEvent.Subscribe(ActivateThird)

    Initialize(QAgent:?agent):void=
        if (Agent:=QAgent?):
            SecondIndicator.ActivateObjectivePulse(Agent)

    ActivateSecond(QAgent:?agent):void=
        if (Agent:=QAgent?):
            SecondIndicator.DeactivateObjectivePulse(Agent)
            ThirdIndicator.ActivateObjectivePulse(Agent)

    ActivateThird(QAgent:?agent):void=
        if (Agent:=QAgent?):
            ThirdIndicator.DeactivateObjectivePulse(Agent)

```

Initialトリガーでインジケータの矢印を有効化しセカンド、サードトリガーでインジケータの有無効化して順番に次の目標を指すように設定しています。

## まとめ
タイクーンの場合だとインジケータデバイスの量が膨大になってしまいそうなので何とかして少なくしてみたいと考えています。こちらもAgentさえ取得できれば簡単にできそうですね。

## 余談
この度UEFN/Verseに関するオープンコミュニティサーバーを建ち上げました。ちょっとでも興味があれば奮ってご参加くださいませ。

https://discord.gg/MehcNhyxdq
WebSocket通信 - クライアント側サンプル

```html
<!DOCTYPE html>
<html>
<head>
    <title>WebSocket Chat</title>
</head>
<body>
    <input id="message_input" autocomplete="off" /><button id="send">Send</button>
    <ul id="messages"></ul>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
    <script type="text/javascript">
    
        const socket = io.connect('/demo')

        socket.on('message', (data) => {
            console.log('message', data)
            const li = document.createElement('li')
            li.appendChild(document.createTextNode(data))
            document.getElementById('messages').appendChild(li)
        })

        document.getElementById('send').addEventListener('click', (e) => {
            const message_input = document.getElementById('message_input')
            const message = message_input.value
            socket.emit('message', message)
            message_input.value = ''
        })

        document.getElementById('message_input').addEventListener('keydown', (e) => {
            if (e.keyCode === 13) {
                const message_input = document.getElementById('message_input')
                const message = message_input.value
                socket.emit('message', message)
                message_input.value = ''
            }
        })
    </script>
</body>
</html>
```
闘魂Elixir ── Advent of code 2023 Day 2 Part 2 を Livebook で楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>

https://qiita.com/advent-calendar/2023/elixir

## はじめに

@torifukukaiou さんの ~~パク~~ リスペクト記事です

https://qiita.com/torifukukaiou/items/e4c4eb6e3f75b79bcd57

Elixir Livebook で Advent of Code 2023 の問題を解いてみます

https://adventofcode.com/2023

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/aoc/2023/2023_day2_part2.livemd

問題はこちら

https://adventofcode.com/2023/day/2

Part 1 はこちら

https://qiita.com/RyoWakabayashi/items/8cdf59ecd003027b9364

## セットアップ

Kino AOC をインストールします

```elixir
Mix.install([
  {:kino_aoc, "~> 0.1.5"}
])
```

Kino AOC の使い方はこちらを参照

https://qiita.com/RyoWakabayashi/items/3d3abcf9134cee4dff05

## 入力の取得

Day 2 の入力を取得します

![スクリーンショット 2023-12-24 22.44.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/adc1ffea-130c-b2af-b9ba-92aaf6406fee.png)

## 私の答え

私の答えです。
折りたたんでおきます。
▶を押して開いてください。

<details><summary>details</summary>

ゲームのパースは Part 1 と同じです

```elixir
games =
  puzzle_input
  |> String.split("\n")
  |> Enum.into(%{}, fn line ->
    [title, items] = String.split(line, ":")

    game_num =
      title
      |> String.replace("Game ", "")
      |> String.to_integer()

    game =
      items
      |> String.split(";")
      |> Enum.map(fn subsets ->
        subsets
        |> String.split(",")
        |> Enum.into(%{}, fn subset ->
          [_, number, color] = String.split(subset, " ")
          {color, String.to_integer(number)}
        end)
      end)

    {game_num, game}
  end)
```

各ゲームについて最低限必要な各色の数を求めるため、色毎に各ゲームでの最大値を取得し、掛け合わせて合計します

```elixir
games
|> Enum.map(fn {_game_num, game} ->
  ["red", "green", "blue"]
  |> Enum.map(fn color ->
    game
    |> Enum.map(&Map.get(&1, color, 0))
    |> Enum.max()
  end)
  |> Enum.product()
end)
|> Enum.sum()
```

</details>

## まとめ

Part 2 ですが、そんなに意地悪なこともなく解けました
シンプルなCLIパスワードマネージャー、pass

passは、コマンドラインで使えるシンプルなパスワードマネージャーです。

## 依存関係
```shell
$ apt-cache depends pass
pass
  Depends: gnupg
  Depends: tree
  Recommends: git
  Recommends: qrencode
  Recommends: xclip
  Recommends: wl-clipboard
  Suggests: libxml-simple-perl
  Suggests: perl
  Suggests: <python>
  Suggests: python3
  Suggests: ruby
```
基本はgnupgとtreeだけ入っていれば使えるというシンプルさ。

## インストール
LinuxやMacならほとんどの場合、標準のパッケージマネージャーに入っているよう。
UbuntuやDebian系では、
```shell
$ sudo apt install pass
```

## 基本的な使い方
#### 0.gpg鍵の作成
```shell
$ gpg --gen-key
```
暗号化に使うgpg鍵を生成しておく（既存のものを流用してもよい）。
#### 1.初期化
```shell
$ pass init <gpg-id>
```
\<gpg-id\>はgpg鍵生成時に入力したid、もしくはメールアドレスに置き換えること。
これでパスワード管理用ディレクトリが生成される（デフォルトだと`~/.password-store`）
#### 2.パスワードの保存
```shell
$ pass insert <pass-name>
```
\<pass-name\>の部分は、設定するパスワードの名前に置き換えること。対話的にパスワードを登録できる。
名前に`/`を使うことで階層構造も表現できる（たとえば、`passlist/pass`ならpasslistフォルダとpassという名前のパスワードを保存する）

`pass`で階層構造を一覧できる。
```shell
$ pass
Password Store
├── pass
└── passlist
    ├── pass2
    └── pass3
```



ランダムなパスワードを生成したいなら、
```shell
$ pass generate -n <pass-name> [pass-length]
```
[pass-length]はパスワードの長さ（省略可能、デフォルトは25文字）。アルファベット（大文字小文字）＋数字のランダムなパスワードを生成して保存する。

`-n`オプションをつけないと記号が含まれるパスワードが生成されるが、残念ながら、使えない可能性の高い記号を含んでしまう（'とか`とか）のでオススメしない。

#### 3.パスワードの表示
```shell
$ pass <pass-name>
```
このとき、gpg鍵生成時にパスワードを設定していれば、パスワードの入力を求められる。（gpg-agentがパスワードをキャッシュしてくれるので、一度入力したら10分間は再度入力しなくて良い）

`-c`オプションをつければ、パスワードはクリップボードにコピーされ、一定時間後に自動で削除される（xclipが必要）。
```shell
$ pass -c <pass-name>
```
`-q`を指定するとqrコードで出力される（qrencodeが必要）。
```shell
$ pass -q <pass-name>
```
## Gitによる同期
Gitを使うことでバックアップ・共有が可能。
#### 共有リポジトリ作成（サーバー上などで）
```shell
$ git init --bare --shared
```
#### ローカル側での設定
```shell
$ pass git init
$ pass git remote add origin <共有リポジトリURL>
$ pass git push -u --all
```
`git add`や`git commit`は自動でやってくれるので不要だが、それ以外は基本的なGitの使い方と同じ。
設定後は、ローカルで更新するたびに`pass git push`で同期し、別のPCから更新した場合は`pass git pull`で変更を取り込んでいけば良い。

## 参考リンク
公式サイト : <https://www.passwordstore.org/>
（WireGuardの開発者さんと同じ人が開発してるみたいです）
man : <https://git.zx2c4.com/password-store/about/>
ArchWiki : <https://wiki.archlinux.jp/index.php/Pass>