「Develop」の版間の差分

提供:senooken JP Wiki
(拡張子、サンプルファイル)
 
(同じ利用者による、間の59版が非表示)
51行目: 51行目:
これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。
これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。


== Communication ==
=== Product ===


=== Backlog ===
==== 会員番号の設計 ====
https://grok.com/share/c2hhcmQtMw%3D%3D_db01208a-8222-4d9b-900e-2bb429417296


==== メール通知 ====
ポイントカードは番号だけでためたり、使えたりしちゃう。流出すると不正利用の可能性がある。dポイントとか楽天ポイントとか。既存のポイントシステムは、固定番号を採用している。
[https://yoshikazu-komatsu.com/backlog-notification-customize-guide/ Backlogの通知設定をカスタマイズする手順|チーム効率を2倍にする最適化テクニック | こまろぐ]


[個人設定]-[メール設定] で全体設定する。
アプリでタイムスタンプを付けたら、流出漏洩ガードができる。が、即時性を優先して固定番号も併用している模様。後は、不正監視システムでカバーとか。


ただ、コメント記入時に、[コメントをお知らせしたいユーザー] に入っていると、通知が来る。メールフィルターで対応するしかない。
ポイントは換金性が高いが、そんなに金額が大きくならずに消費される想定だから、リスクはあっても問題ない感じなのだと思われる。


=== Skype ===
==== バーコード ====
[https://support.microsoft.com/ja-jp/skype/%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%82%A8%E3%83%A2%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B3%E3%83%B3%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B-01af0c65-529f-4a4d-8e3a-a393033a359a すべてのエモーティコンのリストはありますか? - Microsoft サポート]


Skyepで使用可能な絵文字の一覧。
* [https://www.keyence.co.jp/ss/products/autoid/codereader/basic-types.jsp?msockid=39c0e5811530653525dcf3e014af64bb バーコードの種類 | バーコード講座 | キーエンス]
* [https://github.com/zxing/zxing/ zxing/zxing: ZXing ("Zebra Crossing") barcode scanning library for Java, Android]


=== Slack ===
形式が複数ある。
{| class="wikitable"
!1D product
!1D industrial
!2D
|-
|UPC-A
|Code39
|QR Code
|-
|UPC-E
|Code93
|Data Matrix
|-
|EAN-8
|Code128
|Aztec
|-
|EAN-13
|Codabar
|PDF 417
|-
|UPC/EAN Extension 2/5
|ITF
|MaxiCode
|-
|
|
|RSS-14
|-
|
|
|RSS-Expanded
|}


==== チャンネル ====
==== 緯度経度の順番 ====
https://slack.com/intl/ja-jp/help/articles/205239967-%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E5%8F%82%E5%8A%A0%E3%81%99%E3%82%8B
https://grok.com/share/c2hhcmQtMw%3D%3D_4f7c43b1-51f2-4cf4-b832-b108d74c7705


===== 一覧表示 =====
地理情報の座標は、緯度経度の順番で表記することが多い。ただ、数学的にはx,yの順番。メルカトル図法の一般的な地図の資格情報的には、経度緯度がx,yと対応する。順番が違うのが気になる。
[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。


==== パーマリンク ====
結論: 外部公開APIは、緯度経度。内部で緯度経度を変換して、x,yにしたら、x,yの順番で扱う。
Slackの投稿パーマリンクをWebブラウザーで開くと、該当箇所にジャンプできない。デスクトップアプリがあると開ける。それでしのぐ。


=== JIRA ===
理由: 地理学的には、経度は特定が難しくて、緯度が先に特定されて、世界で先に使われるようになった。そのため、緯度経度の順番になって、世間で定着している。ISOなどの標準も緯度経度の順番。GeoJSONとかITシステムでは経度緯度の順番。


==== 関連チケット ====
===== チェックイン機能 =====
[修正するバージョン]/[影響するバージョン] のリンクをクリックすると、関連するissueが一覧表示される。これで未クローズチケットを確認するといい。


==== 履歴 ====
====== 方式 ======
[アクティビティ]-[履歴] のタブを選ぶと、変更履歴を確認できる。
<nowiki>https://grok.com/share/c2hhcmQtMw%3D%3D_792c1e8e-5fcd-429b-a7cd-1e116addbf39</nowiki>
 
{| class="wikitable"
=== Confluence ===
|+
ページの中で、 [作成] を選んでページを作ると、階層が勝手にできて、子ページへのリンクもできる。
!方式
!内容
!利点
!欠点
!不正
!対策
|-
|Geolocation API
|店舗でマイページボタン押下
|追加設備不要
|不正完全防止不能
|位置偽装
|ユーザー特定可能なので、運用で不正をカバーする。
|-
|動的QR
|店頭動的QRコードの読取
|不正完全防止
|表示端末設置必要、サーバー追加実装必要
|
|
|-
|固定QR
|店頭固定QRコード読取
|サーバー追加実装不要
|不正完全防止不能
|QRコード撮影持帰
|固定QRを定期更新。
|-
|NFC
|店頭NFC読取
|
|タグ設置必要、端末限定
|
|
|-
|Bluetooth Beacon
|店頭Beacon通信
|
|Beacon設置必要
|
|
|}
 
* 手間最小はGeolocation API。位置偽装がありえるので、アカウントの定期監視は必要。付与の頻度や上限の制限ロックなど必要。
* 不正防止+低コストは固定QR。定期的なQR更新が必要。
* 不正完全防止で手間最小は動的QR。ただし、表示端末設置、追加サーバー実装必要。
 
====== 動的QR ======
https://grok.com/share/c2hhcmQtMw%3D%3D_57855e1c-bae0-4fd9-99f5-622979149ff3


==== ショートカットキー ====
トークン管理用のテーブルを用意。
キーボード ショートカット
CREATE TABLE checkin_history (
    id INT AUTO_INCREMENT PRIMARY KEY,
    store_id INT NOT NULL,
    token VARCHAR(255) NOT NULL,
    checkin_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (store_id) REFERENCES stores(store_id)
);
トークン作成用のAPIを用意。アクセスが来たら、tokenを作って、それや店舗IDを埋め込んだQR/URLを作成 (?store_id=XXX&token=XXX)。


https://ja.confluence.atlassian.com/doc/keyboard-shortcuts-139456.html
該当トークンを検証して、処理実施。GPS不要になる。


===== エディタ =====
== Communication ==


* {code: コードブロック (https://shinkufencer.hateblo.jp/entry/2018/10/17/235900 Confluenceのエディタは { でマクロのショートカット入力ができるし、{ code } でコードスニペット領域が作れる)。
=== Backlog ===


ブロック フォーマット
==== メール通知 ====
{| class="wikitable"
[https://yoshikazu-komatsu.com/backlog-notification-customize-guide/ Backlogの通知設定をカスタマイズする手順|チーム効率を2倍にする最適化テクニック | こまろぐ]
!Windows
 
!操作
[個人設定]-[メール設定] で全体設定する。
!Mac
 
|-
ただ、コメント記入時に、[コメントをお知らせしたいユーザー] に入っていると、通知が来る。メールフィルターで対応するしかない。
|Ctrl + 0
 
|Paragraph
=== Skype ===
|⌘+ 0
[https://support.microsoft.com/ja-jp/skype/%E3%81%99%E3%81%B9%E3%81%A6%E3%81%AE%E3%82%A8%E3%83%A2%E3%83%BC%E3%83%86%E3%82%A3%E3%82%B3%E3%83%B3%E3%81%AE%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B-01af0c65-529f-4a4d-8e3a-a393033a359a すべてのエモーティコンのリストはありますか? - Microsoft サポート]
|-
 
|Ctrl+ (1 ~ 6)
Skyepで使用可能な絵文字の一覧。
|(選択した番号の)見出しレベル
 
|⌘+ (1—6)
=== Slack ===
|-
|Ctrl + 7
|Preformatted
|⌘+ 7
|-
|Ctrl + 8
|Quote
|⌘+ 8
|-
|Ctrl + Shift + B、または


<nowiki>*</nowiki> + Space
==== チャンネル ====
|箇条書きリストを追加
https://slack.com/intl/ja-jp/help/articles/205239967-%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E5%8F%82%E5%8A%A0%E3%81%99%E3%82%8B
|⌘ + Shift + B、または
 
<nowiki>*</nowiki> + Space
===== 一覧表示 =====
|-
[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。
|Ctrl + Shift + N、または
 
<nowiki>#</nowiki> + space
==== パーマリンク ====
|番号付きリストを追加
Slackの投稿パーマリンクをWebブラウザーで開くと、該当箇所にジャンプできない。デスクトップアプリがあると開ける。それでしのぐ。
|⌘ + Shift + N、または
<nowiki>#</nowiki> + space
|-
|Ctrl + Shift + S
|Strikethrough
|⌘ + Shift + S
|-
|Ctrl + Shift +
|Subscript
|⌘ + Shift + ,
|-
|Ctrl + Shift +
|Superscript
|⌘ + Shift + .
|-
|Ctrl + Shift + M
|Monospace
|⌘ + Shift + M
|-
|Ctrl + \
|Clear formatting
|⌘ + \
|}
豊富なフォーマット
{| class="wikitable"
|CTRL + Shift + V


''サファリのみ:''Ctrl + Shift + Alt + V
=== JIRA ===
|書式設定なしでテキストを貼り付け
|⌘ + Shift + V


''Safari のみ:''⌘ + Shift + Option + V
==== 関連チケット ====
|-
[修正するバージョン]/[影響するバージョン] のリンクをクリックすると、関連するissueが一覧表示される。これで未クローズチケットを確認するといい。
|Ctrl+M
 
|Files and images
==== 履歴 ====
|⌘+ M
[アクティビティ]-[履歴] のタブを選ぶと、変更履歴を確認できる。
 
=== Confluence ===
ページの中で、 [作成] を選んでページを作ると、階層が勝手にできて、子ページへのリンクもできる。
 
==== ショートカットキー ====
キーボード ショートカット
 
https://ja.confluence.atlassian.com/doc/keyboard-shortcuts-139456.html
 
===== エディタ =====
 
* {code: コードブロック (https://shinkufencer.hateblo.jp/entry/2018/10/17/235900 Confluenceのエディタは { でマクロのショートカット入力ができるし、{ code } でコードスニペット領域が作れる)。
 
ブロック フォーマット
{| class="wikitable"
!Windows
!操作
!Mac
|-
|-
|Ctrl+K
|Ctrl + 0
|リンク([リンクの挿入] ダイアログが開く)
|Paragraph
|⌘ + K
|⌘+ 0
|-
|-
|Ctrl + Shift + D
|Ctrl+ (1 ~ 6)
|マークアップを挿入([マークアップの挿入] ダイアログが開く)
|(選択した番号の)見出しレベル
|⌘ + Shift + D
|⌘+ (1—6)
|-
|-
|Ctrl+Shift+A
|Ctrl + 7
|マクロ([マクロの選択] ダイアログが開く)
|Preformatted
|⌘ + Shift + A
|⌘+ 7
|-
|-
|Ctrl + Shift + O
|Ctrl + 8
|次のインライン コメントに切り替え
|Quote
|⌘ + Shift + O
|⌘+ 8
|-
|-
|Ctrl + Shift + L
|Ctrl + Shift + B、または
|前のインライン コメントに切り替え
 
|⌘ + Shift + L
<nowiki>*</nowiki> + Space
|箇条書きリストを追加
|⌘ + Shift + B、または
<nowiki>*</nowiki> + Space
|-
|-
|CTRL + Shift + Z
|Ctrl + Shift + N、または
|インライン コメントを閉じる
<nowiki>#</nowiki> + space
|⌘ + Shift + Z
|番号付きリストを追加
|⌘ + Shift + N、または
<nowiki>#</nowiki> + space
|-
|-
|Ctrl + Shift + I
|Ctrl + Shift + S
|
|Strikethrough
|⌘ + Shift + I
|⌘ + Shift + S
|-
|-
|Alt + 上矢印
|Ctrl + Shift +
|行を上に挿入
|Subscript
|Alt + 上矢印
|⌘ + Shift + ,
|-
|-
|Alt + 下矢印
|Ctrl + Shift +
|下に行を挿入
|Superscript
|Alt + 下矢印
|⌘ + Shift + .
|-
|-
|Ctrl + Shift + X
|Ctrl + Shift + M
|行を切り取り
|Monospace
|⌘ + Shift + X
|⌘ + Shift + M
|-
|Ctrl + Shift + C
|行をコピー
|⌘ + Shift + C
|-
|Ctrl + Shift + Y
|行を上に貼り付け
|⌘ + Shift + Y
|-
|Ctrl + Shift + ;
|絵文字メニュー
|⌘ + Shift + ;
|-
|-
|Ctrl + \
|Clear formatting
|⌘ + \
|}
豊富なフォーマット
{| class="wikitable"
|CTRL + Shift + V
|CTRL + Shift + V
|書式設定なしで貼り付け
 
''サファリのみ:''Ctrl + Shift + Alt + V
|書式設定なしでテキストを貼り付け
|⌘ + Shift + V
|⌘ + Shift + V
''Safari のみ:''⌘ + Shift + Option + V
|-
|-
|
|Ctrl+M
|書式設定なしで貼り付け (Safari)
|Files and images
|⌘ + Shift + Option + V
|⌘+ M
|}
|-
 
|Ctrl+K
===== オートコンプリート =====
|リンク([リンクの挿入] ダイアログが開く)
[] が勝手にリンクになるのが困る。
|⌘ + K
 
|-
リンク、ファイル、マクロ、メンション、絵文字のオートコンプリート
|Ctrl + Shift + D
 
|マークアップを挿入([マークアップの挿入] ダイアログが開く)
https://ja.confluence.atlassian.com/doc/autocomplete-for-links-files-macros-mentions-and-emojis-249858190.html
|⌘ + Shift + D
 
|-
オートコンプリートの無効化方法。
|Ctrl+Shift+A
 
|マクロ([マクロの選択] ダイアログが開く)
プロフィール画像を選択-[設定]-[エディター]-[☑️オートコンプリートの無効化]
|⌘ + Shift + A
 
|-
ただ、オートコンプリートの丸ごと無効化は、便利な機能がなくなるので不味い。
|Ctrl + Shift + O
 
|次のインライン コメントに切り替え
一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。
|⌘ + Shift + O
 
|-
|Ctrl + Shift + L
===== 書式なしペースト =====
|前のインライン コメントに切り替え
[https://qiita.com/kentoak/items/fbba0b9e3e735893a35e Confluenceで書式なしペースト(Ctrl+Shift+V)を有効にする #Confluence - Qiita]
|⌘ + Shift + L
[?]-[キーボードショートカット]-[General]-[▫️Enable General Shortcuts] にしてオフにすると有効になる。
|-
[表の上部にペースト] と競合していたらしい。
|CTRL + Shift + Z
==== マクロ ====
|インライン コメントを閉じる
[https://ja.confluence.atlassian.com/doc/macros-139387.html マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
|⌘ + Shift + Z
 
|-
いくつか有用なマクロがある。
|Ctrl + Shift + I
 
|表
* [https://ja.confluence.atlassian.com/doc/children-display-macro-139501.html 子ページ表示マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
|⌘ + Shift + I
* [https://www.ricksoft.jp/blog/articles/001510.html Confluence(コンフルエンス)の一部内容を折りたたみで非表示できる「展開」マクロを使ってみよう - リックソフトブログ]
|-
 
|Alt + 上矢印
==== Other ====
|行を上に挿入
 
|Alt + 上矢印
===== パーマリンク =====
|-
[https://confluence.atlassian.com/confkb/the-differences-between-various-url-formats-for-a-confluence-page-278692715.html The Differences Between Various URL Formats for a Confluence Page | Confluence | Atlassian Documentation]
|Alt + 下矢印
 
|下に行を挿入
Confluenceのページ新規作成時、パーマリンクが自動生成される。規則がある。
|Alt + 下矢印
 
|-
以下の条件にマッチしたら、padeId URLになる。それ以外は、タイトル名のURLになる。
|Ctrl + Shift + X
|行を切り取り
|⌘ + Shift + X
|-
|Ctrl + Shift + C
|行をコピー
|⌘ + Shift + C
|-
|Ctrl + Shift + Y
|行を上に貼り付け
|⌘ + Shift + Y
|-
|Ctrl + Shift + ;
|絵文字メニュー
|⌘ + Shift + ;
|-
|CTRL + Shift + V
|書式設定なしで貼り付け
|⌘ + Shift + V
|-
|
|書式設定なしで貼り付け (Safari)
|⌘ + Shift + Option + V
|}


* [% & ? / ¥ ; " + :] などのようなURLの予約文字。
===== オートコンプリート =====
* 非ラテン文字。
[] が勝手にリンクになるのが困る。
* ページタイトル末尾が英数字以外の場合。


===== ページ履歴 =====
リンク、ファイル、マクロ、メンション、絵文字のオートコンプリート
ページ右上のメニュー-[ページ履歴]から履歴を確認できる。差分も確認できる。


===== ページ移動 =====
https://ja.confluence.atlassian.com/doc/autocomplete-for-links-files-macros-mentions-and-emojis-249858190.html
[https://ja.confluence.atlassian.com/doc/move-and-reorder-pages-146407727.html ページの移動と順序の変更 | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]


ページ右上のメニュー-[移動]
オートコンプリートの無効化方法。


== Tool ==
プロフィール画像を選択-[設定]-[エディター]-[☑️オートコンプリートの無効化]


=== General ===
ただ、オートコンプリートの丸ごと無効化は、便利な機能がなくなるので不味い。


==== Call tree ====
一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。
kcachegrindだったかな。


kscopeもこれか。
===== 書式なしペースト =====
[https://qiita.com/kentoak/items/fbba0b9e3e735893a35e Confluenceで書式なしペースト(Ctrl+Shift+V)を有効にする #Confluence - Qiita]
[?]-[キーボードショートカット]-[General]-[▫️Enable General Shortcuts] にしてオフにすると有効になる。
[表の上部にペースト] と競合していたらしい。
==== マクロ ====
[https://ja.confluence.atlassian.com/doc/macros-139387.html マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]


Doxygen+GraphVizで関数コールグラフ
いくつか有用なマクロがある。


==== kscope ====
* [https://ja.confluence.atlassian.com/doc/children-display-macro-139501.html 子ページ表示マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]
https:/github.com/ivan0124/Linux-programming/wiki/How-to-use-KScope-to-trace-code
* [https://www.ricksoft.jp/blog/articles/001510.html Confluence(コンフルエンス)の一部内容を折りたたみで非表示できる「展開」マクロを使ってみよう - リックソフトブログ]


https:/sourceforge.net/projects/kscope/
==== Other ====


http:/www.lemis.com/grog/software/kscope.php
===== パーマリンク =====
[https://confluence.atlassian.com/confkb/the-differences-between-various-url-formats-for-a-confluence-page-278692715.html The Differences Between Various URL Formats for a Confluence Page | Confluence | Atlassian Documentation]


==== cscope ====
Confluenceのページ新規作成時、パーマリンクが自動生成される。規則がある。
cbrowser/kbrowserというGUIもある。


cscopeの大文字小文字無視検索
以下の条件にマッチしたら、padeId URLになる。それ以外は、タイトル名のURLになる。


<nowiki>http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html</nowiki>
* [% & ? / ¥ ; " + :] などのようなURLの予約文字。
* 非ラテン文字。
* ページタイトル末尾が英数字以外の場合。


DBを別にする必要がありそう。
===== ページ履歴 =====
ページ右上のメニュー-[ページ履歴]から履歴を確認できる。差分も確認できる。


==== expect ====
===== ページ移動 =====
端末の手動操作を自動化するソフト。
[https://ja.confluence.atlassian.com/doc/move-and-reorder-pages-146407727.html ページの移動と順序の変更 | Confluence Data Center 9.2 | アトラシアン製品ドキュメント]


<nowiki>*</nowiki> ^と$は使えない。代わりに、\nを使う。
ページ右上のメニュー-[移動]


<nowiki>*</nowiki> 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。
== Tool ==


<nowiki>*</nowiki> expect文はawkみたいな感じ。
=== General ===


<nowiki>*</nowiki> ただし、expectは注意が必要。最初のexpectにマッチしないと先に進めない。タイムアウトとかするしかない。
==== Call tree ====
kcachegrindだったかな。


expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"
kscopeもこれか。


https:/linuxjm.osdn.jp/html/expect/man1/expect.1.html
Doxygen+GraphVizで関数コールグラフ


```
==== kscope ====
https:/github.com/ivan0124/Linux-programming/wiki/How-to-use-KScope-to-trace-code


sh -eux <<-"EOT"
https:/sourceforge.net/projects/kscope/


expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect aho {send echo aho} +x {send pwd/n}; expect /$; exit"
http:/www.lemis.com/grog/software/kscope.php


expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"
==== cscope ====
cbrowser/kbrowserというGUIもある。


expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"
cscopeの大文字小文字無視検索


expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'
<nowiki>http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html</nowiki>


EOT
DBを別にする必要がありそう。


```
==== expect ====
端末の手動操作を自動化するソフト。


==== GNU screen ====
* <nowiki>*</nowiki> ^と$は使えない。代わりに、\nを使う。
[https://qiita.com/SAITO_Keita/items/b79ebc5af64aad28fc4a#:~:text=%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E7%8A%B6%E6%85%8B%E3%81%A7%E3%82%AD%E3%83%BC,%E6%A8%AA%E3%81%AB%E5%88%86%E5%89%B2%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82 GNU Screenコマンドをつかってみる #screen - Qiita]
* <nowiki>*</nowiki> 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。
* <nowiki>*</nowiki> expect文はawkみたいな感じ。
* <nowiki>*</nowiki> ただし、expectは注意が必要。最初のexpectにマッチしないと先に進めない。タイムアウトとかするしかない。


screenコマンド実行後に、C-a押下後に対応するキーを押して各種操作を実行する。
expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"


キー操作以外に、コマンドも用意されている。C-a :でコマンドラインモードに入る。
https:/linuxjm.osdn.jp/html/expect/man1/expect.1.html
 
sh -eux <<-"EOT"
特に重要な操作。
expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect aho {send echo aho} +x {send pwd/n}; expect /$; exit"
expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"
expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"
expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'
EOT
 
===== 踏み台サーバーログイン =====
expectのオプションに-cで細切れにするのもOK
<nowiki> </nowiki>
connect 'xxx.xxx.xxx.xxx /ssh /auth=password /user=id /passwd=pw'
wait <nowiki>''</nowiki>
sendln 'ssh root@<ここにIPアドレスを記入>'
wait 'Password:'
sendln 'pw'
connect 'ip1 /ssh /auth=password /user=sef19a /passwd=ipscp19a'
wait <nowiki>''</nowiki>
sendln 'expect -c "spawn ssh root@ip2; expect :; send pelican/n; interact"'
sendln 'expect -c "spawn ssh root@ip2" -c "expect :" -c "send pelican/n" -c "interact"'
 
==== GNU screen ====
[https://qiita.com/SAITO_Keita/items/b79ebc5af64aad28fc4a#:~:text=%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E7%8A%B6%E6%85%8B%E3%81%A7%E3%82%AD%E3%83%BC,%E6%A8%AA%E3%81%AB%E5%88%86%E5%89%B2%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82 GNU Screenコマンドをつかってみる #screen - Qiita]
 
screenコマンド実行後に、C-a押下後に対応するキーを押して各種操作を実行する。
 
キー操作以外に、コマンドも用意されている。C-a :でコマンドラインモードに入る。
 
特に重要な操作。


* Help
* Help
401行目: 536行目:
yamlかjsonで作っておくと無難。
yamlかjsonで作っておくと無難。


=== Diff ===
==== YAML ====
差分確認ツール。コードレビューなどで重要。
 
===== About =====
 
* [https://ja.wikipedia.org/wiki/YAML YAML - Wikipedia]
* [https://yaml.org/ The Official YAML Web Site]
 
YAML 1.2.2 (2021-10-01) が最新。2001-05-11が初版。dockerなどの設定ファイルで採用されていて一部で人気。可読性が高くて、コメントを記入できて、データ量も少ない。人が手作業で記入する形式として適しているとの評判。
 
YAML Ain’t Markup Language (YAML™)
 
===== Basic =====
 
====== General ======
インデントで階層構造を表現。インデントはスペースのみ。スペース2個でインデントが主流。
 
<nowiki>#</nowiki>は行コメント。


==== About ====
---は1ファイル内に複数YAML記載時のセパレーター
Macが鬼門。


M1 Macで使用可能なものの選択肢が極端に狭い。
====== リスト ======
ブロック形式とインライン形式/フロー形式の2種類の記載方法がある。
--- # お好みの映画、ブロック形式
- Casablanca
- Spellbound
- Notorious
--- # 買い物リスト、インライン形式、またはフロー形式
[milk, bread, eggs]


https://chatgpt.com/c/678e249e-84f0-800b-b8da-7385d9aaf819
- {name: John Smith, age: 33}
{| class="wikitable"
- name: Mary Smith
|+
  age: 27
!name
ハッシュのリストのブロック形式はバレットが1個しかつかないのでちょっと気持ち悪いので注意。
!OS
 
!Free
====== 連想配列・ハッシュ ======
!GUI
--- # ブロック
!directory
name: John Smith
age: 33
--- # インライン
{name: John Smith, age: 33}
 
men: [John Smith, Bill Jones]
women:
  - Mary Smith
  - Susan Williams
リストのハッシュ。
 
====== Scalars ======
1文字目を|にして改行すると、データ内の改行を維持。>にすると、改行をスペースに置換。
data: |
  There was a young fellow of Warwick
  Who had reason for feeling euphoric
      For he could, by election
      Have triune erection
  Ionic, Corinthian, and Doric
 
data: >
  Wrapped text
  will be folded
  into a single
  paragraph
 
  Blank lines denote
  paragraph breaks
 
===== Other =====
 
====== ブロック/インライン・フローの混在 ======
Swaggerのプロパティーのdescriptionで区分値の説明用に箇条書きを使いたい。
        content:
          application/json:
            schema:
              type: "object"
              required: ["customerNo", "eventNo"]
              properties:
                customerNo: {title: "会員番号", description: "会員番号", type: string}
                actionType:
                  title: アクションタイプ
                  description: |
                    ユーザーのアクション種別。
                    - 1: セミナー申込
                    - 2: 動画視聴,
                  type: integer
                  enum: [1, 2]
                  default: 1
基本はswaggerやyamlはブロック形式が基本になっている。短くてシンプルなところだけインライン・フロー形式を使う。長くなるならブロック形式にする。
 
親のpropertiesのブロック形式にする必要がある。
 
=== Diff ===
差分確認ツール。コードレビューなどで重要。
 
==== About ====
Macが鬼門。
 
M1 Macで使用可能なものの選択肢が極端に狭い。
 
https://chatgpt.com/c/678e249e-84f0-800b-b8da-7385d9aaf819
{| class="wikitable"
|+
!name
!OS
!Free
!GUI
!directory
!image
!image
!comment
!comment
708行目: 932行目:
diff -yかicdiff --line--numbersは2列で表示してくれるから、視認性が高い。
diff -yかicdiff --line--numbersは2列で表示してくれるから、視認性が高い。


== Coding ==
== UML ==


=== タイムゾーン ===
=== Tool ===
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]
https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628


3文字形式は避けたほうが無難。
[https://www.quora.com/What-are-the-best-UML-tools-for-macOS What are the best UML tools for macOS? - Quora]


タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。
* デスクトップ
** StarUML
** ArgoUML
** UMLet
** OmniGraffle
** edraw: 有料。
** Umbrello
** Modelio
* クラウド
** Visual Paradigm
** Lucidchart: 有料。
** Creately: 有料。
** diagrams.net: モデルじゃない。
*その他
**PlantUML


tz databaseのAsia/Tokyoなどの確実性が高い。
UmbrelloとModelioはそれらと比較して何がよかったのだっけ?
=== Regular Expression ===
正規表現。重要。覚えにくいが重要なものをメモしておく。


後ろからマッチ。cが置換対象。
Eclipse Papyrusが動作するならこれがいい。Eclipseは安定しているから、これのプラグインで動作するなら信頼できるだろう。


==== Case ====
papyrusは一度試してダメだった気がするが。
/[^c]*$/: cより右端


===== マッチの前後の挿入 =====
=== Diagram ===
https:/vim.fandom.com/wiki/Power_of_g
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


===== 関数にログ =====
==== クラス図 ====
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
A=自分 (矢印の元)。B=相手 (矢印の先)
考慮するケース
* 継承関係
double currentTime() const override { return m_element->currentTime(); }
** 汎化 (generalization): 実線白矢印。継承。
 
** 実現 (realization): 点線矢印。interfaceの継承。
=== glob ===
* プロパティー単位
**関連 (association): 実線。あるクラスが他のクラスのインスタンスを持つ。ただし、所有までいかない。コンストラクターのDIも含む。人と車のように全体-部分の関係がない場合これ。困ったらこれでもいい。
** 集約 (aggregation): 白菱形実線。関連の特殊系。所有者の方が菱形。所有される側は線。全体-部分の関係。ただし、部分は他の全体からも共有可能。List<T>やSet<T>のメンバー変数があれば集約の可能性が高い。
** コンポジション (composition): 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。部分が他から共有されない。集約の特殊系。
** リンク (link): 実線。クラスのインスタンス間の関係。クラス図ではなく、オブジェクト図で使われる。


* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/glob.html glob]
* メソッド単位
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_13 Shell Command Language]
** 依存 (dependency): 点線矢印。引数か返却値に使っていて、Bの変更が影響を与える場合。
** 使用 (usage): 点線矢印。引数と戻り値に使わず、関数内で一時的に使うだけ。依存の特殊系。


重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。
==== ER図 ====
https://grok.com/share/c2hhcmQtMw%3D%3D_49664566-4833-490d-9309-e69597a6ac12


使用可能な記号は以下3個。以下の3文字は\でエスケープできる。
実態関連モデル。Entity-Relationshp Model。関係データベースを抽象的な表現手法。


* ?: 任意の1文字にマッチ。
格納されたデータが、他のデータとどう関係しているかを表現する。
* *: 任意の0以上の文字にマッチ。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


ファイル名マッチ時には、追加で特殊なルールがある。
1975年にPeter Chenが発表した。


.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)
* Entyty/実体: 現実世界のものや概念相当。オブジェクト指向のオブジェクト相当。DBではテーブル相当。四角形で描画。
* Attribute/属性: Entityの特徴や詳細情報。オブジェクト指向のプロパティー。DBではテーブルカラム相当。楕円で描画。
* Relationship/関係: Entity同士のつながり。オブジェクト指向のメソッド?DBではテーブル間の関係 (外部キーによるリンク相当)。菱形で描画。
* Instance/インスタンス: DBのレコード () 相当。


globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])。
===== Relationship =====
.[!.]* *
https://grok.com/share/c2hhcmQtMw%3D%3D_861bd847-f9c8-4c01-8887-9802dad8f6e3
上記のように.ファイルのマッチとそれ以外を指定する必要がある。


<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。
関係がわかりにくいので整理する。


<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。
Entity (テーブル相当) 動詞の関係をカーディナリティー (多重度) で表現する。3個の関係がある。
{| class="wikitable"
|+
!関係
!関係名
!例
!意味
!
|-
|1:1 (One-to-One)
|<Master> has one <Master>
|Person/Passport: 1人1パスポート。それぞれ重複がない。PassportにPersonの外部キーを持つ。
Employee/EmployeeDetail: EmployeeDetailのEmployeeの外部キーを持つ。
|一方のEntityのインスタンス (行) がもう一方のEntityの1個だけのインスタンスに対応し、逆も同じ場合。情報が密接に関連していて、分離する必要はないが、管理・整理のために分けるケース。
詳細テーブルのパターン。テーブルに持ってもいいが、整理のために別テーブルにしている。
1:多の特殊ケースとみなせる。
実際のところ、1:1が本当に対等ということはほぼない。外部キーを片方に持たせる都合、親子関係がある。子が1個だけという話。逆に、そうできていないなら、Entityの選定・設計の問題を疑ったほうがいい。
|
|-
|1:多 (One-to-Many)
|<Master> has <Transactions>
|Department/Employee: Departmentが親でEmployeeが子。Departmentの1行 (ID=営業部) を、Employeeの複数行 (所属従業員) に対応。1従業員1所属の場合。EmployeeにDepartment IDを外部キーとして持つ。親の部門を削除すると子の従業員も影響を受ける。
Customer/Order: Customer (ID=1のA) はOrderの複数行 (注文1-3) に対応。注文は1顧客だけに連動。
|一方のEntityのInstanceがもう一方のEntityの複数のインスタンスに対応。逆は多:1だが、1:多でどちらも表現。親子関係のような階層構造で使用する。マスター:トランザクションの関係でも使う。
|
|-
|多:多 (Many-to-Many)
|<Master> has many <Master>
|Stundent/Course: Stundentの1行 (ID=1 学生A) はCourseの複数行 (数学、英語) に対応。Courseの1行 (数学) はStundentの複数行 (学生A,B,C) に対応。実装時はEnrollmentテーブル (登録) を作成して、これにStundent IDとCourse IDの相関テーブル+追加情報 (成績) などを入れる。
Product (製品)/Supplier (仕入先): 1商品が複数仕入れ先から調達可能。1仕入れ先が複数商品を供給。
|一方のEntityがもう一方の複数のEntityに対応。逆も同じ。両側が独立して複数関連づく場合。DBでは直接実装不能なので、中間テーブルを通常使う。2個の1:多に分解。
|
|}
マスターテーブルは親的な役割。トランザクションテーブルは子的な関係。通常、マスターテーブル:トランザクションテーブル=1:多。トランザクションテーブルにマスターテーブルの外部キーを持つ。


=== 引用符のネスト ===
関係の命名。業務ロジックにあった命名ができればべストだが、一貫性がない。関係からある程度機械的に名前を決める。
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。


JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。
* 1:1=has one
* 1:多=has
* 多:多=has many


交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。
これがスマート。多対多はis related toもよく使うが、他をhasで表現するなら、こうしないと気持ち悪い。


問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
=== PlantUML ===


二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。
==== About ====
* [https://www.plantuml.com PlantUML Web Server]
* [https://plantuml.com/ja/ シンプルなテキストファイルで UML が書ける、オープンソースのツール]


基本的な方法。
シンプルなテキストでUMLの作成ツール。ツールで機械的に生成できるのがポイント。細かいレイアウトの調整とか、複雑なことをしたい場合、けっこう難しくなる。


# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
そうでなくて、機械的に作成することで、誰がやっても同じで、形式や配置が統一される。それが利点。
# 全体を一重/二重引用符で囲む。


何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。
==== Other ====


[{"ke\y":"valu\e"}] を例として考える。
===== 対話AI =====
自分で作成するより、対話AIにお願いして作ってもらって、それを改造する形で作るのが手っ取り早い模様。


# {"ke\y":"valu\e"}
シーケンス図やクラス図なんかはそれでいける。
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


これでOK。また何か考慮不足があればそのときに考える。
==== VS Code ====


ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
===== About =====
[https://qiita.com/Charotarou/items/10bd47c68a1190061858 Visual Studio CodeでPlantUMLを利用する方法(2020/10/30作成) #Java - Qiita]


例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
さっと書くだけなら、Webだけでもいい。機密情報とか扱う場合、ローカルでやるといい。
echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)
.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。


* [https://stackoverflow.com/questions/15637429/how-to-escape-double-quotes-in-json How to escape double quotes in JSON - Stack Overflow]
VSCodeの拡張機能でインストールする場合、JavaとGraphvizだけでいい。本体は拡張機能インストール時に同梱される模様。
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]


JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。
===== 出力ディレクトリー =====
[https://oboe2uran.hatenablog.com/entry/2025/07/02/215013 VScode PlantUMLで作成するUML画像の出力先を設定する。 - Oboe吹きプログラマの黙示録]


基本的な考え方がある。
デフォルト状態だと、ファイル出力時に以下の形式になる。
out/.puファイル名/@startumlのタイトル.拡張子
最初のoutがうっとうしいのでpuと同じところに出力してほしい。
plantuml.exportOutDir: ".",
plantuml.exportSubFolder: false,
上記設定にするとよい。


# JSON value用に二重引用符"を\"で置換。
==== ステート図/状態遷移図 ====
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
[https://plantuml.com/ja/state-diagram 状態遷移図の構文と機能]
# JSON項目の二重引用符"を\"で置換。
# 全体を二重引用符"で囲む。


こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。
画面遷移図にも使える。


=== ケース変換 ===
===== Alias =====
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]
ステート・状態部分には、スペースや記号を使えない。以下の構文で別名を使って、表示用と内部用をわける。
state "display" as internal


キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。
===== 合成状態 =====
状態は合成可能。ブロックにまとめたりできる。 state 状態名 {} で定義する。
@startuml
scale 350 width
[*] --> NotShooting
state NotShooting {
  [*] --> Idle
  Idle --> Configuring : EvConfig
  Configuring --> Idle : EvConfig
}
state Configuring {
  [*] --> NewValueSelection
  NewValueSelection --> NewValuePreview : EvNewValue
  NewValuePreview --> NewValueSelection : EvNewValueRejected
  NewValuePreview --> NewValueSelection : EvNewValueSaved
  state NewValuePreview {
      State1 -> State2
  }
}
@enduml
共通処理を中でまとめたりするのに便利そう。


=== encode ===
===== 画面遷移図 =====
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]
https://chatgpt.com/share/6867298c-09bc-800b-89ec-de487215192b


日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。
Webアプリケーションの設計書として、画面遷移図が必要なことがある。


* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
UMLでやる場合、アクティビティー図か、ステート図 (状態遷移図) がうってつけ。画面とその遷移アクションの両方を記載できるので申し分ない。
* UTF-8
* base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
* HTMLエンコード: HTMLで特殊な意味を持つ文字を&amp;lt;などに変換する。


==== Percent-encoding ====
他、一覧表もあり。


* [https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0 パーセントエンコーディング - Wikipedia]
実際にいくつか状態遷移図をステートマシン図で書いてみたところ、問題があった。
* [https://developer.mozilla.org/ja/docs/Glossary/Percent-encoding Percent-encoding (パーセントエンコーディング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN]
* [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax]


unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
共通ヘッダーやモーダルの表現が難しかった。コンポーネント化的なことができなくて、同じ画面遷移・状態を複数書く必要があった。モーダルを開いて閉じるというのは、repeatでループで表現できるが、他の画面遷移との併記が難しかった。
上記文字はエンコードの対象外。


==== 英数変換 ====
これを考えると、ステート図のほうが、矢印の方向が柔軟で、共通化なことができた。
[https://stackoverflow.com/questions/28110062/php-how-to-encode-all-characters-with-rawurlencode string - PHP How to encode all characters with rawurlencode - Stack Overflow]


変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。
ステートマシン図の例
[[ファイル:画面遷移図-ステートマシン図での例.png|なし|サムネイル|[*] --> ログイン画面ログイン画面 --> ホーム画面 : ログイン成功


こういう目的だと%エンコーディングが適している。
ログイン画面 --> [*] : ログイン失敗


ただし、一部の記号を許可しているので、自前で変換する。
ホーム画面 --> 設定画面 : 設定をクリック
function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}
$str = 'big ƒüßchen';
print_r(encode_all($str));


==== Term ====
ホーム画面 --> [*] : ログアウト]]
紛らわしい用語がある。
アクティビティー図の例
[[ファイル:画面遷移図-アクティビティー図の例.png|なし|サムネイル|@startuml(*) --> 個人設定一覧


* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])。
個人設定一覧 --> [ヘッダー選択] 共通ヘッダー
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])。
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。


フレームワークの中にライブラリーも含めていいと思う。
個人設定一覧 --> [サイドバー選択] サイドバー


「[https://webbigdata.jp/what-is-ai/page-6804/page-8359/page-12091/ Pythonのモジュールとパッケージとライブラリとフレームワークの違い]」がわかりやすい。
個人設定一覧 --> [リスト選択] センター


フレームワークはライブラリーを含んでいる。ライブラリーで共通でいいと思う。
@enduml]]https://grok.com/share/c2hhcmQtMw%3D%3D_832592cf-86dd-41eb-a0fa-2fbd656e9299


==== Category ====
ステート図で画面遷移図作成時のポイント。
「[https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E5%B7%A5%E7%A8%8B ソフトウェア開発工程 - Wikipedia]」


ソフトウェアの分類、ページ分類時に役立つ。
Webページの場合はURLでやるのがいいと思う。


* 言語
ただ、PlantUML内の状態名は、プログラミング言語の変数名相当だから、_以外の記号は使えない。
* ツール: 静的解析、テスト、文書など。
* フレームワーク


MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。
state <display> as <name> でnameを定義するといい。_をスラッシュとみなして、全小文字とか。
state "www.example.com" as wwww
state "www.example.com/mypage" as www_mypage
[*] -> www
root -> www_mypage
複数サイトになることがあるから、サブドメイン (なければwww) をベースの名前空間にするのがよさそう。


エイリアス名。url内の記号は除去でいい。exmaple.com/user-profile/editとか。www_userprofile_edit。url内のディレクトリーに記号を使うほうが悪い。全小文字区切り文字なしにすべき。短いほうがいいのだから。


* PHP language
===== 矢印の向き =====
* PHP tool
矢印の向きの制御方法がある。
* PHP framework


==== 成功時連続継続処理 ====
* ->: 最短距離。左右になることが多い。
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。
* -right->/-down->/-up->/-left->: 向きを明示。
 
* -->: 長めの矢印。上下になることが多い。
# 処理実行。
* -->/..>: 向きには影響しない。
# 成功ならA、失敗なら終了。
* top to bottom direction: 全体の向きの明示。
# 処理実行。
# 成功ならA、失敗なら終了。


こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
directionで全体の向きを指定しても、->の最短矢印だと、長さが優先される。矢印内で向きを明示するか、-->の長めの矢印を使うとよい。
        /*
        // 無限ループで終了条件でブレイク
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。
===== 条件分岐 =====
<<choice>> ステレオタイプで条件付きの状態を指定できる。
@startuml
state c <<choice>>
Idle --> ReqId
ReqId --> c
c --> MinorId : [Id <= 10]
@enduml
やや使いにくいかもしれない。条件がある場合、矢印に説明を入れるといいかもしれない。


いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。
==== アクティビティー図 ====
[https://plantuml.com/ja/activity-diagram-beta 新しいアクティビティ図のベータ版の構文と機能]


これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。
===== 記法 =====
https://chatgpt.com/share/68675652-ff90-800b-93ff-19285fe8cf21


offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
PlantUMLのアクティビティー図の記法はレガシー記法とモダン記法とで2種類ある。
        $offset = 0;
 
        while (true) {
最大の違いは、分岐。以前は o --> option1, o --> option2で1個のアクティビティーから複数のアクティビティーに分岐できた。が、これがモダン記法だとできない。
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
 
                json_encode([
split forkで明確に管理するようになった。パースとかのしやすさ、構文の曖昧性の排除が目的の模様。
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;
            // 2回目からはヘッダー除去して書き込み。
            $start = strpos($response, "\n") + 1;
            $flat = FILE_APPEND;
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }


        for ($offset = 0;
===== split fork =====
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
アクティビティーの分岐の記法。2種類ある。紛らわしい。
            (function() use (&$offset, $limit, $response) {
                // 2回目からはヘッダー除去して書き込み。
                $start = strpos($response, "\n") + 1;
                $flag = FILE_APPEND;
                if ($offset === 0) {
                    $start = $flag = 0;
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }


=== character ===
splitは条件分岐、forkは並列実行的なイメージになっている。


==== BOM ====
以下の構文。
UTF-8のBOM
\xef\xbb\xbf
この文字を先頭につけるとUTF-8のBOMになる。


=== Convert ===
* split/split again/end split
* fork/fork again/end fork


==== IP/CIDR ====
  @startuml
// JavaScript
  start
<nowiki> </nowiki>  /**
  split
<nowiki> </nowiki>    * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
     :A;
  <nowiki> </nowiki>    * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
  split again
  <nowiki> </nowiki>    */
     :B;
  <nowiki> </nowiki>  toCIDR(ipaddress) {
  split again
<nowiki> </nowiki>     const [address, mask] = ipaddress.split('/')
     :C;
  <nowiki> </nowiki>    const segments = mask.split('.')
  split again
<nowiki> </nowiki>     const CIDR = segments
     :a;
  <nowiki> </nowiki>      .map((e) => Number(e).toString(2))
     :b;
<nowiki> </nowiki>      .join(<nowiki>''</nowiki>)
  end split
<nowiki> </nowiki>      .replace(/0*$/, <nowiki>''</nowiki>).length
  :D;
<nowiki> </nowiki>     return address + '/' + CIDR
  end
  <nowiki> </nowiki>  },
  @enduml
<nowiki> </nowiki>  /**
見た目の問題で、splitのほうがすっきりしている。
<nowiki> </nowiki>    * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
<nowiki> </nowiki>    * @param {number} cidr - ciderの数字。
<nowiki> </nowiki>    * @return {string} x.x.x.x形式のIPアドレス文字列。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  cidrToIp(cidr) {
<nowiki> </nowiki>     const digit = 32
<nowiki> </nowiki>     const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
  <nowiki> </nowiki>    return ip
  <nowiki> </nowiki>      .match(/.{8}/g)
  <nowiki> </nowiki>      .map((e) => parseInt(e, 2))
  <nowiki> </nowiki>      .join('.')
<nowiki> </nowiki>  },


=== Algorithm ===
===== 矢印 =====
矢印にテキストを添えたり、色、線の形式を指定できる。<syntaxhighlight lang="text">
@startuml
:foo1;
-> You can put text on arrows;
if (test) then
  -[#blue]->
  :foo2;
  -[#green,dashed]-> The text can
  also be on several lines
  and **very** long...;
  :foo3;
else
  -[#black,dotted]->
  :foo4;
endif
-[#gray,bold]->
:foo5;
@enduml


==== 再帰処理 ====
</syntaxhighlight>
https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950


配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。
===== モーダル =====
モーダルのような一時的に開いて戻る場合、反復可能なので、repeatで表現するとエレガント。
@startuml
' PlantUMLソースコード
start
repeat :ホーム;
->モーダルを開く;
:モーダル;
repeat while ([閉じる] 選択) is (yes)
stop
@enduml
ただ、モーダル以外の他の画面遷移が少々苦しくなる。repeat内でsplitすればいけなくはないが。


再帰関数で実装するほかに、スタックで処理する方法がある。
モーダルを閉じる動きはstopでいいかもしれない。


再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。
==== ER図 ====


パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。
* [https://plantuml.com/ja/er-diagram Entity Relationship diagram (Chen's notation)]
* [https://plantuml.com/ja/ie-diagram ER図の文法と機能]


最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。
PlantUMLでは2種類のER図に対応している。Chen's notationは2024-04導入の新しい模様 ([https://github.com/plantuml/plantuml/blob/master/CHANGES.md#v120244-april-6-2024 plantuml/CHANGES.md at master · plantuml/plantuml])。


https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5
===== Chen notation =====
[https://plantuml.com/ja/er-diagram Entity Relationship diagram (Chen's notation)]
 
chenの記法がER図そのものできれい。これを使う。ただ、Chen notationはnoteの注釈機能が使えなくて、見た目はいいけど、機能不十分。IEのほうがよさそう。
@startchen
entity "DJ.CUSTOMER" as DJ_CUSTOMER {
  Number <<key>>
  Name
}
entity MOVIE {
  Code <<key>>
}
relationship RENTED_TO {
  Date
}
RENTED_TO =1= DJ_CUSTOMER
RENTED_TO -N- MOVIE
@endchen
https://grok.com/share/c2hhcmQtMw%3D%3D_db38ab26-68a2-4a0b-b1e4-dc231e51279b
 
* entity=テーブル。属性がなくても改行した波括弧が必要。少々気持ち悪いが。
* attribute=属性: entityの波括弧内に記述。<<key>>のステレオタイプでキーを表現。下線がつく。
* relationship=関係: has/belongs_toとかを記載するのが無難。user-order=places/student-courses=enrollsとかわかるなら動詞も。
** 太字 (total participation): 親テーブルに埋め込まれている外部キーがNOT NULLの場合。単独存在がなくて存在必須なので。
entity名に.とかは入れられないのでasで別名で回避 (https://grok.com/share/c2hhcmQtMw%3D%3D_1d81495e-fd3c-4f3c-8fc4-19b2d4f391b2<nowiki/>)。


再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。
https://grok.com/share/c2hhcmQtMw%3D%3D_aa8d7730-69dd-4d58-b88a-8edea922b3c8


JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。
属性はネストできる。これは概念的な話。例えば、住所は市区町村や番地、建物名とかに分解できる。が、物理DBだとこれらは展開済み。グループ化の話。別にネストしなくてもいい。


シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。
====== 親子関係 ======
オブジェクト指向の継承関係を表現できる。


=== Other ===
* ->-: 矢印の方向が親。


==== コメントの著者名 ====
@startchen
https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08
entity CUSTOMER {
}
entity PARENT {
}
entity MEMBER {
}
CUSTOMER ->- PARENT
MEMBER -<- CUSTOMER
@endchen


GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。
====== ステレオタイプ ======
* <<key>>: 主キー。
* <<derived>>: 他の属性からの計算カラム。
* <<multi>>: enum形式。


大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。
===== IE =====
[https://plantuml.com/ja/ie-diagram ER図の文法と機能]


git blameで行単位で編集者が分かる。
Information EngineeringベースのER図。既存のクラス図の拡張記法。クラス図でできることは全部できる。


==== 確率処理 ====
classの代わりにentityを使うところが主な違い。
https://chatgpt.com/share/68145e5c-9d14-800b-9cca-1cd9e46e2dd6


ある確率で処理をしたり、しなかったりしたいことがある。
====== インフォメーションエンジニアリングの関係線 ======
$chance = 30; // 30%の確率
{| class="wikitable"
|'''Type'''
if (mt_rand(1, 100) <= $chance) {
|'''記号'''
    // 30%の確率でここに入る
|-
    echo "当たり!";
|0か1
} else {
|<code><nowiki>|o--</nowiki></code>
    // 70%の確率でこっちに入る
|-
    echo "はずれ...";
|1のみ
}
|<code><nowiki>||--</nowiki></code>
乱数を作成して、それで確率値の超過判定で表現できる。
|-
|0以上
|<code>}o--</code>
|-
|1以上
|<code><nowiki>}|--</nowiki></code>
|}
波括弧}が複数。|が1、oが0を意味する。
 
関係線の記法だけ注意が必要。


== UML ==
====== エンティティ ======
基本はクラス図と同じ文法。他の違い。* は必須を意味する。


=== Tool ===
==== シーケンス図 ====
https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628
[https://plantuml.com/ja/sequence-diagram シーケンス図の構文と機能]


[https://www.quora.com/What-are-the-best-UML-tools-for-macOS What are the best UML tools for macOS? - Quora]
->でメッセージを描く。参加者の明示的な宣言は不要。


* デスクトップ
===== 分類子の宣言 =====
** StarUML
参加者の宣言は不要だが、デフォルトだと四角になる。actorとかDatabaseとか見た目を調整したい場合、participantでを宣言しておく。
** ArgoUML
** UMLet
** OmniGraffle
** edraw: 有料。
** Umbrello
** Modelio
* クラウド
** Visual Paradigm
** Lucidchart: 有料。
** Creately: 有料。
** diagrams.net: モデルじゃない。
*その他
**PlantUML


UmbrelloとModelioはそれらと比較して何がよかったのだっけ?
変数の型名のように、以下の分類子


Eclipse Papyrusが動作するならこれがいい。Eclipseは安定しているから、これのプラグインで動作するなら信頼できるだろう。
* <code>actor</code>
* <code>boundary</code>
* <code>control</code>
* <code>entity</code>
* <code>database</code>
* <code>collections</code>
* <code>queue</code>
* participant (初期値)


papyrusは一度試してダメだった気がするが。
<分類子> <参加者>[ as 別名]


=== Diagram ===
@startuml
participant Participant as Foo
actor      Actor      as Foo1
boundary    Boundary    as Foo2
control    Control    as Foo3
entity      Entity      as Foo4
database    Database    as Foo5
collections Collections as Foo6
queue      Queue      as Foo7
Foo -> Foo1 : To actor
Foo -> Foo2 : To boundary
Foo -> Foo3 : To control
Foo -> Foo4 : To entity
Foo -> Foo5 : To database
Foo -> Foo6 : To collections
Foo -> Foo7: To queue
@enduml


==== クラス図 ====
===== メッセージに付けるノート =====
A=自分 (矢印の元)。B=相手 (矢印の先)
メッセージのすぐ後ろにキーワード note left または note right を使用し、メッセージにノートを付けることが可能です。
* 継承関係
** 汎化 (generalization): 実線白矢印。継承。
** 実現 (realization): 点線矢印。interfaceの継承。
* プロパティー単位
**関連 (association): 実線。あるクラスが他のクラスのインスタンスを持つ。ただし、所有までいかない。コンストラクターのDIも含む。人と車のように全体-部分の関係がない場合これ。困ったらこれでもいい。
** 集約 (aggregation): 白菱形実線。関連の特殊系。所有者の方が菱形。所有される側は線。全体-部分の関係。ただし、部分は他の全体からも共有可能。List<T>やSet<T>のメンバー変数があれば集約の可能性が高い。
** コンポジション (composition): 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。部分が他から共有されない。集約の特殊系。
** リンク (link): 実線。クラスのインスタンス間の関係。クラス図ではなく、オブジェクト図で使われる。


* メソッド単位
end note キーワードを使って、複数行のノートを作ることができます。
** 依存 (dependency): 点線矢印。引数か返却値に使っていて、Bの変更が影響を与える場合。
@startuml
** 使用 (usage): 点線矢印。引数と戻り値に使わず、関数内で一時的に使うだけ。依存の特殊系。
Alice->Bob : hello
note left: this is a first note
Bob->Alice : ok
note right: this is another note
Bob->Bob : I am thinking
note left
a note
can also be defined
on several lines
end note
@enduml
===== メッセージのグループ化 =====


=== PlantUML ===
次のキーワードを使えば、メッセージをまとめてグループ化できます。
alt/else
opt
loop
par
break
critical
group表示するテキスト
ヘッダ部分に文字列を追加することが可能です。(groupについては、後述の「groupの2つ目のラベル」を参照)
グループを閉じるにはキーワード end を使用します。
@startuml
Alice -> Bob: Authentication Request
alt successful case
    Bob -> Alice: Authentication Accepted
else some kind of failure
    Bob -> Alice: Authentication Failure
    group My own label
    Alice -> Log : Log attack start
        loop 1000 times
            Alice -> Bob: DNS Attack
        end
    Alice -> Log : Log attack end
    end
else Another type of failure
    Bob -> Alice: Please repeat
end
@enduml
<code>group</code>では、<code>[</code>と<code>]</code>の間に2つ目のラベルを設定し、ヘッダに表示させることができます。
@startuml
Alice -> Bob: Authentication Request
Bob -> Alice: Authentication Failure
group My own label [My own label 2]
    Alice -> Log : Log attack start
    loop 1000 times
        Alice -> Bob: DNS Attack
    end
    Alice -> Log : Log attack end
end
@enduml


* [https://www.plantuml.com PlantUML Web Server]
===== ライフラインの活性化と破棄 =====
* [https://plantuml.com/ja/ シンプルなテキストファイルで UML が書ける、オープンソースのツール]


シンプルなテキストでUMLの作成ツール。ツールで機械的に生成できるのがポイント。細かいレイアウトの調整とか、複雑なことをしたい場合、けっこう難しくなる。
activateとdeactivateで分類子の活性化を表現。例えば、関数の実行中とかが四角になってわかりやすい。


そうでなくて、機械的に作成することで、誰がやっても同じで、形式や配置が統一される。それが利点。
が、やや記述が複雑になるので注意する。
 
@startuml
==== Install ====
participant User
[https://qiita.com/Charotarou/items/10bd47c68a1190061858 Visual Studio CodeでPlantUMLを利用する方法(2020/10/30作成) #Java - Qiita]
User -> A: DoWork
activate A
A -> B: << createRequest >>
activate B
B -> C: DoWork
activate C
C --> B: WorkDone
destroy C
B --> A: RequestCreated
deactivate B
A -> User: Done
deactivate A
@enduml
autoactivate onにすると勝手に活性化してくれる。returnで解除する。昔はなかった気がする。このautoactivate on。


さっと書くだけなら、Webだけでもいい。機密情報とか扱う場合、ローカルでやるといい。
ただ、これを使うと、途中でif文でreturnする倍とかの表現が面倒になるので注意する。
@startuml
autoactivate on
alice -> bob : hello
bob -> bob : self call
bill -> bob #005500 : hello from thread 2
bob -> george ** : create
return done in thread 2
return rc
bob -> george !! : delete
return success
@enduml
returnを使うと自動的に活性化してくれるのでこれを活用するのがいい。
@startuml
Bob -> Alice : hello
activate Alice
Alice -> Alice : some action
return bye
@enduml


VSCodeの拡張機能でインストールする場合、JavaとGraphvizだけでいい。本体は拡張機能インストール時に同梱される模様。
===== 活性化、非活性化、生成のショートカット記法 =====
対象の分類子を記述した直後に、次の記法を使うことができます。


==== ステート図/状態遷移図 ====
* <code>++</code> 対象を活性化する (続けて[[/plantuml.com/ja/color|色]]を記述することもできます)
[https://plantuml.com/ja/state-diagram 状態遷移図の構文と機能]
* <code>--</code> 起点側を非活性化する
* <code>**</code> 対象のインスタンスを生成する
* <code>!!</code> 対象のインスタンスを破棄する


画面遷移図にも使える。
==== クラス図 ====
[https://plantuml.com/ja/class-diagram クラス図の構文と機能]


===== Alias =====
===== メソッド =====
ステート・状態部分には、スペースや記号を使えない。以下の構文で別名を使って、表示用と内部用をわける。
クラス名:に続けて記載する。他に波括弧。
state "display" as internal


===== 合成状態 =====
丸括弧があればメソッド。なければプロパティー。
状態は合成可能。ブロックにまとめたりできる。 state 状態名 {} で定義する。
  @startuml
  @startuml
  scale 350 width
  Object <|-- ArrayList
  [*] --> NotShooting
Object : equals()
  ArrayList : Object[] elementData
ArrayList : size()
   
   
  state NotShooting {
  @enduml
   [*] --> Idle
 
  Idle --> Configuring : EvConfig
@startuml
   Configuring --> Idle : EvConfig
class Dummy {
   String data
   void methods()
  }
  }
   
   
  state Configuring {
  class Flight {
  [*] --> NewValueSelection
    flightNumber : Integer
  NewValueSelection --> NewValuePreview : EvNewValue
    departureTime : Date
  NewValuePreview --> NewValueSelection : EvNewValueRejected
}
  NewValuePreview --> NewValueSelection : EvNewValueSaved
@enduml
 
  state NewValuePreview {
===== 可視性 =====
      State1 -> State2
{| class="wikitable"
  }
|'''文字'''
|'''可視性'''
}
|-
@enduml
|<code>-</code>
共通処理を中でまとめたりするのに便利そう。
|<code>private</code>
|-
|<code>#</code>
|<code>protected</code>
|-
|<code>~</code>
|<code>package private</code>
|-
|<code>+</code>
|<code>public</code>
|}


===== 画面遷移図 =====
===== 注釈とステレオタイプ =====
https://chatgpt.com/share/6867298c-09bc-800b-89ec-de487215192b


Webアプリケーションの設計書として、画面遷移図が必要なことがある。
===== 注釈の詳細 =====


UMLでやる場合、アクティビティー図か、ステート図 (状態遷移図) がうってつけ。画面とその遷移アクションの両方を記載できるので申し分ない。
===== フィールド(フィールド、属性、メンバー)またはメソッドへの注釈 =====
フィールド (フィールド、属性、メンバー) に注釈を追加できる。


他、一覧表もあり。
left/rightのみ可能。名前空間区切り文字列に::を指定した場合、使用不能。
@startuml
class A {
{static} int counter
+void {abstract} start(int timeout)
}
note right of A::counter
  This member is annotated
end note
note right of A::start
  This method is now explained in a UML note
end note
@enduml


実際にいくつか状態遷移図をステートマシン図で書いてみたところ、問題があった。
以下の書式。
note <direction> of <class>::<attribute>
end note
インラインは不能。


共通ヘッダーやモーダルの表現が難しかった。コンポーネント化的なことができなくて、同じ画面遷移・状態を複数書く必要があった。モーダルを開いて閉じるというのは、repeatでループで表現できるが、他の画面遷移との併記が難しかった。
==== Reference ====
[https://plantuml.com/ja/guide PlantUML Language Reference Guide]


これを考えると、ステート図のほうが、矢印の方向が柔軟で、共通化なことができた。
===== Creole =====
[https://plantuml.com/ja/creole Use creole syntax to style your texts]


ステートマシン図の例
====== 特殊文字 ======
[[ファイル:画面遷移図-ステートマシン図での例.png|なし|サムネイル|[*] --> ログイン画面ログイン画面 --> ホーム画面 : ログイン成功
&#XXXXまたは、<U+XXXX>の構文、または直接記述することで、任意のUnicode文字を使うことができます。


ログイン画面 --> [*] : ログイン失敗
らしいが、&#XXXX形式は解釈されなかった。<U+XXXX>は有効だった。


ホーム画面 --> 設定画面 : 設定をクリック
[https://blog.jawira.com/2022/10/30/escaping-special-characters-in-plantuml.html Escaping special characters in PlantUML | Jawira blog]


ホーム画面 --> [*] : ログアウト]]
noteのブロックの先頭に'を書きたい場合、コメント扱いされてしまう。
アクティビティー図の例
[[ファイル:画面遷移図-アクティビティー図の例.png|なし|サムネイル|@startuml(*) --> 個人設定一覧


個人設定一覧 --> [ヘッダー選択] 共通ヘッダー
<U+0027>でユニコード文字表記にすれば回避できる。


個人設定一覧 --> [サイドバー選択] サイドバー
===== 21 共通コマンド =====
[https://plantuml.com/ja/commons General and common command to handle graphic layout in diagrams.]


個人設定一覧 --> [リスト選択] センター
====== コメント ======


@enduml]]https://grok.com/share/c2hhcmQtMw%3D%3D_832592cf-86dd-41eb-a0fa-2fbd656e9299
* シングルコメント: シングルクォート'で始まる行はコメント。
* ブロックコメント: C言語と同様だが/' '/ で囲む。


ステート図で画面遷移図作成時のポイント。
====== タイトル ======
title タイトル
title
end title
タイトル部分は\nで改行できる。他にブロック形式だと改行を含められる。


Webページの場合はURLでやるのがいいと思う。
====== キャプション ======
captionでキャプション。


ただ、PlantUML内の状態名は、プログラミング言語の変数名相当だから、_以外の記号は使えない。
====== フッターとヘッダー ======
footer/headerブロック。


state <display> as <name> でnameを定義するといい。_をスラッシュとみなして、全小文字とか。
====== 凡例 ======
state "www.example.com" as wwww
legend/end legend
state "www.example.com/mypage" as www_mypage
[*] -> www
root -> www_mypage
複数サイトになることがあるから、サブドメイン (なければwww) をベースの名前空間にするのがよさそう。


エイリアス名。url内の記号は除去でいい。exmaple.com/user-profile/editとか。www_userprofile_edit。url内のディレクトリーに記号を使うほうが悪い。全小文字区切り文字なしにすべき。短いほうがいいのだから。
====== 21.9 メインフレーム ======
mainframe This is a **mainframe*
タイトルみたいに枠で囲んでくれて見た感じがよくなる。


===== 矢印の向き =====
===== 25 前処理 =====
矢印の向きの制御方法がある。


* ->: 最短距離。左右になることが多い。
====== 25.5 プロシージャー [!procedure, !endprocedure] ======
* -right->/-down->/-up->/-left->: 向きを明示。
テキストを出力する。
* -->: 長めの矢印。上下になることが多い。
* -->/..>: 向きには影響しない。
* top to bottom direction: 全体の向きの明示。


directionで全体の向きを指定しても、->の最短矢印だと、長さが優先される。矢印内で向きを明示するか、-->の長めの矢印を使うとよい。
====== 25.6 return関数 [!function, !endfunction] ======
[https://messykitchen.hateblo.jp/entry/2022-05-23_plantuml_function_procedure マクロの扱い [脱W〇rd, 脱E×cel, 脱@st@h : #14] - messyなkitchenなブログ]


==== アクティビティー図 ====
過去の!define相当。テキストの値として使う。
[https://plantuml.com/ja/activity-diagram-beta 新しいアクティビティ図のベータ版の構文と機能]


===== 記法 =====
=== Umbrello ===
https://chatgpt.com/share/68675652-ff90-800b-93ff-19285fe8cf21
 
==== Problem ====
altなどの重なり順番、アクティブの下になっちゃう
 
optの条件が表示されない。


PlantUMLのアクティビティー図の記法はレガシー記法とモダン記法とで2種類ある。
=== Papyrus ===
[https://eclipse.dev/papyrus/download.html Papyrus Dowloads]


最大の違いは、分岐。以前は o --> option1, o --> option2で1個のアクティビティーから複数のアクティビティーに分岐できた。が、これがモダン記法だとできない。
[https://eclipse.dev/papyrus/documentation.html Papyrus Documentation]


split forkで明確に管理するようになった。パースとかのしやすさ、構文の曖昧性の排除が目的の模様。
==== Tutorial ====
公式の[A slide-ware tutorial on Eclipse Papyrus usage for starters (2010-10-01)]を参考に基本的な使い方を学ぶ。


===== split fork =====
[File]-[New]-[Papyrus prooject]
アクティビティーの分岐の記法。2種類ある。紛らわしい。


splitは条件分岐、forkは並列実行的なイメージになっている。
これでプロジェクトを作ると、以下が [Project Explorer] に作られる。


以下の構文。
* <project name>
** <project name>
*** di: ツールメタデータ。モデル作成のエントリーポイント。
*** notation: 画像データ。
*** uml: UMLモデルデータ。


* split/split again/end split
このdiをダブルクリックして描画を開始する。
* fork/fork again/end fork


@startuml
1個のプロジェクトでいろんな図に対応していて、モデルを流用できる形になっている。悪くない。これを使う。
start
 
split
画面構成
    :A;
split again
    :B;
split again
    :C;
split again
    :a;
    :b;
end split
:D;
end
@enduml
見た目の問題で、splitのほうがすっきりしている。


===== 矢印 =====
# Project explorer
矢印にテキストを添えたり、色、線の形式を指定できる。<syntaxhighlight lang="text">
# Model explorer: 一番重要。ここでモデル全体をツリーベースで管理する。
@startuml
# Outline view: アウトライン
:foo1;
# Main toolber: ツールバー。
-> You can put text on arrows;
# Perspective: Model explorerの内容を使って作図する領域。
if (test) then
# Property view: モデルのエディター画面。
  -[#blue]->
  :foo2;
  -[#green,dashed]-> The text can
  also be on several lines
  and **very** long...;
  :foo3;
else
  -[#black,dotted]->
  :foo4;
endif
-[#gray,bold]->
:foo5;
@enduml


</syntaxhighlight>
Model explorerがPapyrusの本質。ここでクラスとかインタラクションを定義しておいて、この定義をperspectiveの作図に使うイメージ。


===== モーダル =====
クラス図やシーケンス図もModel explorerに所属していて、好きなだけ作れる。[New diagram]から作れる。
モーダルのような一時的に開いて戻る場合、反復可能なので、repeatで表現するとエレガント。
@startuml
' PlantUMLソースコード
start
repeat :ホーム;
->モーダルを開く;
:モーダル;
repeat while ([閉じる] 選択) is (yes)
stop
@enduml
ただ、モーダル以外の他の画面遷移が少々苦しくなる。repeat内でsplitすればいけなくはないが。


モーダルを閉じる動きはstopでいいかもしれない。
[New Child] でいくつか重要なモデルがある。


==== Reference ====
* Package: ディレクトリ・フォルダーみたいなもの。これで他のモデルをまとめて整理できる。
[https://plantuml.com/ja/guide PlantUML Language Reference Guide]
* Interaction: シーケンス図表現用のモデル。
* Class: クラス。Interactionの型だったりする。UMLのベースで非常に重要。


===== 21 共通コマンド =====
==== Class ====


====== コメント ======
===== 属性表示 =====
クラス図にクラスモデルを配置しても、プロパティーやメソッドが表示されない。


* シングルコメント: シングルクォート'で始まる行はコメント。
右クリック-[Filters] で制御できる。
* ブロックコメント: C言語と同様だが/' '/ で囲む。


====== タイトル ======
* [Synchronized with Model] を選ぶと同期されて全部表示される。基本はこれで、一部だけ表示したい場合にここを外すのだろうと思う。
title タイトル
* [Show/Hide Contents] で表示可否をチェックボックスで選べる。
title
end title
タイトル部分は\nで改行できる。他にブロック形式だと改行を含められる。


====== キャプション ======
===== Modelへのジャンプ =====
captionでキャプション。
クラス図などからオブジェクトのModel Explorerの元データにジャンプしたいことがある。


====== フッターとヘッダー ======
オブジェクト右クリック-[Navigate]-[Go to ...]-[Model Explorer] を選ぶ。
footer/headerブロック。


====== 凡例 ======
===== Comment =====
legend/end legend
https://chatgpt.com/c/67aec9f8-6be0-800b-b6eb-6300425ad1d4


=== Umbrello ===
メソッドなどにコメントを入れたいことがある。このコメントがわかりにくい。


==== Problem ====
[Properties]-[Comments]-[Owned comments]-[Body] に入力する。初回+で作ったダイアログのBodyに入力したものは反映されなくて、一度空のコメントを作った後に、洗濯後横のBodyに入力すると反映される模様。
altなどの重なり順番、アクティブの下になっちゃう


optの条件が表示されない。
* Applied comments=他のモデルのコメントを取り込みたい場合に使う。
* Owned comments=自分自身のコメント。コメントに対してコメントをつけることもできるので、[Create a new Comment] はさらに [Comments] タブを持っている。このタブがコメントのコメント。基本は使う必要ない。


=== Papyrus ===
[Annotated element] でたぶん、Bodyに入力したコメントを複数の要素に適用したい場合の適用先だと思う。
[https://eclipse.dev/papyrus/download.html Papyrus Dowloads]


[https://eclipse.dev/papyrus/documentation.html Papyrus Documentation]
==== Sequence diagrams ====
https://eclipse.dev/papyrus/resources/PapyrusTutorial_OnSequenceDiagrams_v0.1_d2010100.pdf


==== Tutorial ====
===== 2.2 Adding messages (basic - asynchronous) =====
公式の[A slide-ware tutorial on Eclipse Papyrus usage for starters (2010-10-01)]を参考に基本的な使い方を学ぶ。
コミュニケーションは、メッセージの交換で描写される。


[File]-[New]-[Papyrus prooject]
メッセージはoperationCall (同期/非同期) かsignal (非同期) コミュニケーションとして表現される。


これでプロジェクトを作ると、以下が [Project Explorer] に作られる。
synchronousCall作成時は、replyMessageも期待される。


* <project name>
createMessageとdeleteMesageの指定は、ライフラインの動的な有無を意味する。
** <project name>
*** di: ツールメタデータ。モデル作成のエントリーポイント。
*** notation: 画像データ。
*** uml: UMLモデルデータ。


このdiをダブルクリックして描画を開始する。
Papyrusでのメッセージ作成は以下の手順で構成される。


1個のプロジェクトでいろんな図に対応していて、モデルを流用できる形になっている。悪くない。これを使う。
# パレットからツールを選択。
# ソースLifelineの開始点をクリック。
# ターゲットLifelineの終了点をクリック。
# ポップアップの該当するsignal/operationを選択。
記法


画面構成
* 非同期メッセージは中抜き矢尻 (arrow head)。
* 同期メッセージは塗りつぶし矢尻。
* 返信メッセージは波線 (dashed line)。
* オブジェクト作成メッセージは波線+中抜き矢尻。
* Lost Messageは黒丸矢尻。
* Found Messageは黒丸矢柄。


# Project explorer
====== 2.2.1 Select desired tool from the palette ======
# Model explorer: 一番重要。ここでモデル全体をツリーベースで管理する。
# Outline view: アウトライン
# Main toolber: ツールバー。
# Perspective: Model explorerの内容を使って作図する領域。
# Property view: モデルのエディター画面。


Model explorerがPapyrusの本質。ここでクラスとかインタラクションを定義しておいて、この定義をperspectiveの作図に使うイメージ。
* Message SyncとMessage Replyは [Execution Specifications] がないと使えない。
* Message createはターゲットポイントが存在時に使用可能。


クラス図やシーケンス図もModel explorerに所属していて、好きなだけ作れる。[New diagram]から作れる。
====== 2.2.2 Select source and target points ======
ソースとターゲットポイントは2の異なるライフライン (通常) か、同じライフライン (再帰) が選択可能。


[New Child] でいくつか重要なモデルがある。
ターゲットポイントの制限は、対象の要素に依存する。例えば、Synchronous CallはExecution Specificationから始まる必要がある。


* Package: ディレクトリ・フォルダーみたいなもの。これで他のモデルをまとめて整理できる。
===== 2.3 Adding execution specification =====
* Interaction: シーケンス図表現用のモデル。
ここまでのシーケンス図では、通信シナリオだけを想定してきた。が、実際には、完全な実行トレースを表現できる。Execution Specification (ES) は実行を表す抽象概念で、Action Execution SpecificationとBehavior Execution Specificationの2種類がある。
* Class: クラス。Interactionの型だったりする。UMLのベースで非常に重要。


==== Class ====
PapyrusではライフラインにESをセットして行う。ESをセットしたら、同期メッセージを追加できる。


===== 属性表示 =====
開発プロセスでは、予備設計では全メッセージを非同期とみなしておいて、設計時にESを設定して、同期メッセージをする感じ。
クラス図にクラスモデルを配置しても、プロパティーやメソッドが表示されない。


右クリック-[Filters] で制御できる。
ただ、同期メッセージは、応答メッセージが入ってごちゃごちゃする。単にシーケンス図を書くだけなら、非同期で全部書いてもいいと思う。


* [Synchronized with Model] を選ぶと同期されて全部表示される。基本はこれで、一部だけ表示したい場合にここを外すのだろうと思う。
===== Undoで破損 =====
* [Show/Hide Contents] で表示可否をチェックボックスで選べる。
シーケンス図を作成して、削除のUndoを何回かやると、データが破損して開けなくなる。対応方法不明。GitでPapyrusのファイルを管理しておいて、破損に対応しておいた方がいい。


===== Modelへのジャンプ =====
===== 再帰自己呼び出しシーケンス図 =====
クラス図などからオブジェクトのModel Explorerの元データにジャンプしたいことがある。
シーケンス図の描画に癖があるので、方針を固めて使用する。


オブジェクト右クリック-[Navigate]-[Go to ...]-[Model Explorer] を選ぶ。
# 自己関数の呼び出しはMessage Async/Message Reply。Message Syncは期待通りに配置されないので、自己関数には使わない。他のライフラインには使う。
# 関数の呼び出し期間はAction Execution Specificationを配置。
# 矢印の端にESを配置する形にする。


===== Comment =====
===== オブジェクトの移動 =====
https://chatgpt.com/c/67aec9f8-6be0-800b-b6eb-6300425ad1d4
オブジェクトの移動に癖がある。基本的に、メッセージは始点、終点で別々に移動させるしかない。まとめて選択して一括移動ができない。


メソッドなどにコメントを入れたいことがある。このコメントがわかりにくい。
終点を移動させると、その下のオブジェクトも追随する。追加はこれで対応できる。減らすのは手間になる。


[Properties]-[Comments]-[Owned comments]-[Body] に入力する。初回+で作ったダイアログのBodyに入力したものは反映されなくて、一度空のコメントを作った後に、洗濯後横のBodyに入力すると反映される模様。
シーケンス図が大きくなりすぎないように注意する。


* Applied comments=他のモデルのコメントを取り込みたい場合に使う。
== Coding ==
* Owned comments=自分自身のコメント。コメントに対してコメントをつけることもできるので、[Create a new Comment] はさらに [Comments] タブを持っている。このタブがコメントのコメント。基本は使う必要ない。


[Annotated element] でたぶん、Bodyに入力したコメントを複数の要素に適用したい場合の適用先だと思う。
=== タイムゾーン ===
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]


==== Sequence diagrams ====
3文字形式は避けたほうが無難。
https://eclipse.dev/papyrus/resources/PapyrusTutorial_OnSequenceDiagrams_v0.1_d2010100.pdf


===== 2.2 Adding messages (basic - asynchronous) =====
タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。
コミュニケーションは、メッセージの交換で描写される。


メッセージはoperationCall (同期/非同期) かsignal (非同期) コミュニケーションとして表現される。
tz databaseのAsia/Tokyoなどの確実性が高い。
=== Regular Expression ===


synchronousCall作成時は、replyMessageも期待される。
* [https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE 正規表現 - Wikipedia]
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/basedefs/V1_chap09.html Regular Expressions]


createMessageとdeleteMesageの指定は、ライフラインの動的な有無を意味する。
正規表現。重要。覚えにくいが重要なものをメモしておく。


Papyrusでのメッセージ作成は以下の手順で構成される。
==== BRE ====


# パレットからツールを選択。
===== BREs Matching Multiple Characters =====
# ソースLifelineの開始点をクリック。
複数文字に一致するBREを作成する記法 (量指定子) がある。
# ターゲットLifelineの終了点をクリック。
# ポップアップの該当するsignal/operationを選択。
記法


* 非同期メッセージは中抜き矢尻 (arrow head)。
単一文字、部分式、後方参照のいずれかに一致するBREの後に、'\{m\}', '\{m,\}', '\{m,n\}' の形式の配置で、指定回数の連続に一致する。
* 同期メッセージは塗りつぶし矢尻。
* 返信メッセージは波線 (dashed line)。
* オブジェクト作成メッセージは波線+中抜き矢尻。
* Lost Messageは黒丸矢尻。
* Found Messageは黒丸矢柄。


====== 2.2.1 Select desired tool from the palette ======
* mとnの範囲: 0<=m<=n<={RE_DUP_MAX}の範囲の10進数。
* mは最小出現回数、nは最大出現回数。
* \{m\}: m回出現
* \{m,\}: m回以上
* \{m,n\}: m-n回出現


* Message SyncとMessage Replyは [Execution Specifications] がないと使えない。
例: abababccccccdに対する"c\{3^}"は7-9文字目でマッチ。
* Message createはターゲットポイントが存在時に使用可能。
{| class="wikitable"
|+単一文字の量指定子
|<code>*</code>
|<code>{0,}</code> と同じ
|-
|<code>+</code>
|<code>{1,}</code> と同じ
|-
|<code>?</code>
|<code>{0,1}</code> と同じ
|}


====== 2.2.2 Select source and target points ======
===== POSIXクラス =====
ソースとターゲットポイントは2の異なるライフライン (通常) か、同じライフライン (再帰) が選択可能。
言語によって、アルファベット順が違うことがある。エストニア語ではsの後にzがあり、[a-z]では全ての英字にマッチしない。ロケールに依存する。


ターゲットポイントの制限は、対象の要素に依存する。例えば、Synchronous CallはExecution Specificationから始まる必要がある。
これの排除のために、文字の区分を定義している。
 
{| class="wikitable"
===== 2.3 Adding execution specification =====
|+
ここまでのシーケンス図では、通信シナリオだけを想定してきた。が、実際には、完全な実行トレースを表現できる。Execution Specification (ES) は実行を表す抽象概念で、Action Execution SpecificationとBehavior Execution Specificationの2種類がある。
!POSIXクラス
 
!対応正規表現
PapyrusではライフラインにESをセットして行う。ESをセットしたら、同期メッセージを追加できる。
!意味
 
|-
開発プロセスでは、予備設計では全メッセージを非同期とみなしておいて、設計時にESを設定して、同期メッセージをする感じ。
|<nowiki>[[:upper:]]</nowiki>
|
|
|-
|<nowiki>[[:lower:]]</nowiki>
|
|
|-
|<nowiki>[[:alpha:]]</nowiki>
|
|
|-
|<nowiki>[[:alnum:]]</nowiki>
|
|
|-
|<nowiki>[[:digit:]]</nowiki>
|
|
|-
|<nowiki>[[:xdigit]]</nowiki>
|
|
|-
|<nowiki>[[:punct:]]</nowiki>
|
|
|-
|<nowiki>[[:blank:]]</nowiki>
|[ \t]
|スペースとタブ。
|-
|<nowiki>[[:space:]]</nowiki>
|[ \t\n\r\f\v]
|スペースとタブ+改行類。
|-
|<nowiki>[[:cntrl:]]</nowiki>
|
|
|-
|<nowiki>[[:graph:]]</nowiki>
|
|
|-
|<nowiki>[[:print:]]</nowiki>
|
|
|}
特に以下が重要。


ただ、同期メッセージは、応答メッセージが入ってごちゃごちゃする。単にシーケンス図を書くだけなら、非同期で全部書いてもいいと思う。
* <nowiki>[[:alnum:]]</nowiki>
* <nowiki>[[:space:]]</nowiki>


===== Undoで破損 =====
[:X:]が[]内で使える構文の扱い。組み合わせる場合、[[:upper:]ab]という感じで外側各括弧に収める。
シーケンス図を作成して、削除のUndoを何回かやると、データが破損して開けなくなる。対応方法不明。GitでPapyrusのファイルを管理しておいて、破損に対応しておいた方がいい。


===== 再帰自己呼び出しシーケンス図 =====
==== ERE ====
シーケンス図の描画に癖があるので、方針を固めて使用する。
基本はBREと同じ。エスケープ\が不要になっている。


# 自己関数の呼び出しはMessage Async/Message Reply。Message Syncは期待通りに配置されないので、自己関数には使わない。他のライフラインには使う。
多くのプログラミング言語などでは、EREが基本。grep -E相当。
# 関数の呼び出し期間はAction Execution Specificationを配置。
# 矢印の端にESを配置する形にする。


===== オブジェクトの移動 =====
==== PCRE ====
オブジェクトの移動に癖がある。基本的に、メッセージは始点、終点で別々に移動させるしかない。まとめて選択して一括移動ができない。


終点を移動させると、その下のオブジェクトも追随する。追加はこれで対応できる。減らすのは手間になる。
* [https://www.php.net/manual/ja/reference.pcre.pattern.syntax.php PHP: PCRE 正規表現構文 - Manual]
* [https://www.pcre.org/current/doc/html/pcre2syntax.html pcre2syntax specification]


シーケンス図が大きくなりすぎないように注意する。
EREをさらに以下で拡張したもの。


== Design ==
* POSIXクラスの拡張表現の文字クラス
* 量指定子の追加構文 (+ ?)
* 言明/assertion


=== Architecture ===
===== 量指定子/Quantifiers =====
  ?          0 or 1, greedy
  ?+          0 or 1, possessive
  ??          0 or 1, lazy
  *          0 or more, greedy
  *+          0 or more, possessive
  *?          0 or more, lazy
  +          1 or more, greedy
  ++          1 or more, possessive
  +?          1 or more, lazy
  {n}        exactly n
  {n,m}      at least n, no more than m, greedy
  {n,m}+      at least n, no more than m, possessive
  {n,m}?      at least n, no more than m, lazy
  {n,}        n or more, greedy
  {n,}+      n or more, possessive
  {n,}?      n or more, lazy
  {,m}        zero up to m, greedy
  {,m}+      zero up to m, possessive
  {,m}?      zero up to m, lazy
BRE/EREで登場した量指定子。デフォルトではgreedy (貪欲) マッチで、最長マッチ。


==== About ====
量指定子の末尾に?で最短マッチ (lazy)。
https://grok.com/share/c2hhcmQtMw%3D%3D_d762a384-9703-4539-b8e7-022bc680d88f


* MVC
量指定子の末尾に+で独占的 (possessive)。マッチを消費する。処理の高速化になる。
* MVVM
* クリーンアーキテクチャー


このあたりが有名。MVCが一番無難。MVCでは厳しいような大規模になったら、他を検討する価値がある感じ。
===== 言明/assertion =====


==== Clean Architecture ====
* [https://www.php.net/manual/ja/regexp.reference.anchors.php PHP: アンカー - Manual]
クリーンアーキテクチャー。最近よく聞く設計手法。
* [https://www.php.net/manual/ja/regexp.reference.assertions.php PHP: 言明 - Manual]


* [https://zenn.dev/muno/articles/introduce-clean-architecture クリーンアーキテクチャに入門する]
言明 (assertion) はカレントマッチング位置の直前・直後の文字に対するテスト、条件付け。文字を消費しない。テストのみ。
* https://chatgpt.com/share/6870b175-d394-800b-a885-b41600d128cd


「[https://blog.cleancoder.com/uncle-bob/2011/11/22/Clean-Architecture.html Clean Coder Blog]」で2011-11-22にRobert C. Martinによって提唱さえたアーキテクチャー。ソフトウェアの開発・展開・運用・保守を簡単にして、プログラマーの生産性の最大化が目的。
if文相当。直接マッチしないで、条件へのマッチ。マッチ対象文字を消費しない。


多くのアーキテクチャーでは、関心を分離して、異なる役割や責務を分離して、変更の影響を最小限にしている。これの実現に、ソフトウェアをレイヤー (層) に分けている。クリーンアーキテクチャーは、このアイデアの1個のガイドラインになっている。
正規表現内で、if文相当の条件判定する際に使用する。


中心にビジネスルールがあって、玉ねぎのように、中心から外に向かって、層構造になっている。
BREの段階で^$ (アンカー/anchor) があった。これの大幅拡張。


# エンティティ: ビジネスロジック (ドメイン層)。外部の影響 (FWの更新など) に影響を受けない。
例えば、フォームの検証で「特定文字種が含まれていること」+9-12文字のような複数の条件指定を実現できる。
# ユースケース: アプリのビジネスルール。interface adapterから受け取ったデータをもとに、entityのビジネスロジックを組み合わせて、アプリ特有のロジックを実現。
# Interface Adapter (Controller/Gateway/Presenter): 外部システムと内部システムのデータを変換する。例えば、コントローラーはリクエストをUsecaseが利用できる形式に変換 (4->2) し、プレゼンターはユースケースの出力を外部システムが理解できる形式に変換 (2->4) する。
# Framework/Driver (DB/Device/Web Framework/UI/外部Web API): WebアプリケーションFW、DBなど。外部エージェントとの通信処理。基本的にはライブラリーやFWを使う。


基本はこれだけ。
複雑な言明はサブパターン (言明サブパターン/assetion subpattern) を用いる。カレント位置の先と後とで2種類ある。


既存のMVC型アプリをクリーンアーキテクチャーにする場合の対応。
====== anchors ======
  ^          start of subject
                also after an internal newline in multiline mode
                (after any newline if PCRE2_ALT_CIRCUMFLEX is set)
  $          end of subject
                also before newline at end of subject
                also before internal newline in multiline mode


* Controller: Interface adapter
====== simple assertions ======
* Model: Entity (domain/repository interface)
  \b          word boundary
* View: Framework
  \B          not a word boundary
  \A          start of subject
  \Z          end of subject
                also before newline at end of subject
  \z          end of subject
  \G          first matching position in subject


たまねぎの層構造の表現は、ディレクトリーの親子関係で表現できるときれいなんだけど。層ごとでグループ化したり、継承したりする場合に、ディレクトリーを作れなくて困る。大規模になるならなおさら。
====== LOOKAHEAD AND LOOKBEHIND ASSERTIONS ======
  (?=...)                    )
  (*pla:...)                  ) positive lookahead
  (*positive_lookahead:...)  )
  (?!...)                    )
  (*nla:...)                  ) negative lookahead
  (*negative_lookahead:...)  )
  (?<=...)                    )
  (*plb:...)                  ) positive lookbehind
  (*positive_lookbehind:...)  )
  (?<!...)                    )
  (*nlb:...)                  ) negative lookbehind
  (*negative_lookbehind:...)  )
肯定否定。=で肯定、!で否定。


中小規模や、うまく分割してきれいにまとめられるならあり。
* (?: 先読み。言明の次、右側を判定。
* (?<: 戻読み。言明の前、左側を判定。


一般的には、機能を最上位において、その下で4の層をディレクトリーで配置するというのが多い模様。
先読み言明 (lookahead assertion)
src/
└── Article/
    ├── Domain/
    ├── Application/
    ├── Interface/
    └── Infrastructure/


==== SSR+CSR ====
例えば、以下のパターンはセミコロンが後に続く単語にマッチする。
\w+(?=;)
言明は複数同じ場所に配置可能で、AND条件になる。ORにしたかったら、(?<=abc|abde) のように選択肢にする。


===== About =====
以下はbarが後ろに続かないfooにマッチする。
https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45
foo(?!bar)
以下はfoo以外の後のbarではない。
(?!foo)bar
全部のbarにマッチする。この言明の直後の3文字がbarの場合、(?!foo)が常に真になるから。


バックエンドとフロントエンドの分離の話。
言明の先読みは、基本は右端に配置する。右端の後に何か続ける場合、\w+とか使う。言明自体は文字を消費しないから、言明部分をカバーできるタイプの文字クラスの併用が必要。
echo preg_match('/foo(?=bar)\w+$/', 'foobar.'); # 0


SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部する (CSR) というのが最近の流行。
==== Case ====
後ろからマッチ。cが置換対象。
/[^c]*$/
cより右端


SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。
===== マッチの前後の挿入 =====
https:/vim.fandom.com/wiki/Power_of_g
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


SSRの利点。
===== 関数にログ =====
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
考慮するケース
double currentTime() const override { return m_element->currentTime(); }


* SEO
===== フォーム検証 =====
* 初期表示。
https://grok.com/share/c2hhcmQtMw%3D%3D_0c3a03bf-35f1-4594-a5d8-21673072ada5
* 匿名。


SSRの課題。
英字と数字がそれぞれ1文字以上、かつ9-12文字。


* サーバー負荷: データとHTML作成を同時に行うから。
戻読み言明と量指定を併用する。
* 分散困難:
$password = "123456333d78"; // テスト用のパスワード
$options = [
    'options' => [
        'regexp' => '/^(?=.*<nowiki>[[:alpha:]]</nowiki>)(?=.*\d).{9,12}$/'
    ]
];
if (filter_var($password, FILTER_VALIDATE_REGEXP, $options)) {
    echo "パスワードは有効です。";
} else {
    echo "パスワードが条件を満たしていません。";
ただ、filter_inputだと検証失敗の理由まで特定して取得できない。面倒だが1個ずつやるしかない。関数化すれば1回で済む。


キャッシュの活用がポイントになるとのこと。
=== glob ===


===== リダイレクト =====
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/glob.html glob]
https://chatgpt.com/share/6886c2c2-b5cc-800b-8e03-e301c22d5eff
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_13 Shell Command Language]


CSRでやる場合、最終的にCSRの成果物をstaticに生成して、それをサーバー側のpublicに配置する感じになる。
重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。


npm run generateの生成先をpublicに直接してもOKだと思う。いや、これは既存のindex.phpとかが消えるのでまずい。シンボリックリンクにするとか。
使用可能な記号は以下3個。以下の3文字は\でエスケープできる。


1台でフロントとサーバーの両方を扱う場合、/apiなどサーバーリクエストに使うURLはindex.phpに、それ以外はindex.htmlなどにするようなリダイレクト設定が必要。
* ?: 任意の1文字にマッチ。
* *: 任意の0以上の文字にマッチ。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


以下のようなイメージ。
ファイル名マッチ時には、追加で特殊なルールがある。
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>
    RewriteEngine On
    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_URI} ^/(api|sanctum)(/|$)
    RewriteRule ^ index.php [L]
    # Nuxtのビルド済み静的ファイル (_nuxt/) は除外
    RewriteCond %{REQUEST_URI} ^/_nuxt/
    RewriteRule ^ - [L]
    # RewriteCond %{REQUEST_FILENAME} !-f [OR]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ - [L]
    RewriteRule ^ index.html [L]
</IfModule>


=== Other ===
.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。


==== Atomic Design ====
globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])。
.[!.]* *
上記のように.ファイルのマッチとそれ以外を指定する必要がある。


* [https://atomicdesign.bradfrost.com/chapter-2/ Atomic Design Methodology | Atomic Design by Brad Frost]
<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。
* [https://zenn.dev/bizlink/articles/b5c8985af8407a Atomic Designの概念]


最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。
<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。


* atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
=== 引用符のネスト ===
* molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。
* organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
 
* templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。
* pages: ページ。テンプレートを使用したページ。


==== インターフェイスと抽象クラス ====
交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。


* [https://qiita.com/nogson/items/e6575d6617f854ed6e25 PHPでインターフェイスと抽象クラスを使う #PHP - Qiita]
問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
* https://chatgpt.com/c/6796dd25-2380-800b-9d87-847c60e6f546


オブジェクト指向でよく登場するインターフェイス、抽象クラス、クラスの違い。
二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。
* インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
* インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。


インターフェイス
基本的な方法。


* メソッド宣言のみ。
# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
* static/constの場合に限定して、メソッド定義、定数もOK。
# 全体を一重/二重引用符で囲む。
* 多重継承可能。
* tagのイメージ。
例えば、複数のクラスで共通の処理がある場合、その共通部分をInterfaceにして、それを継承すると良い。その部分だけ取り出して流用できる。


例えば、[Animal<-Duck] のような関係がある時、Duckは空も飛べるし、泳ぐこともできるとしたら、飛べることと泳げることの機能はAnimalの中でも対応がわかれる。こういうところをInterfaceにしておくと、振る舞いを統合できる。
何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。


抽象クラスは一部共通にしたい場合に使う。Interfaceは指定機能を全部共通。
[{"ke\y":"valu\e"}] を例として考える。


ベースは抽象クラス、クラスにしておいて、複数クラスで共通にしたい場合interfaceで定義するときれいに実装できる。
# {"ke\y":"valu\e"}
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


==== Config class ====
これでOK。また何か考慮不足があればそのときに考える。


* [https://softwareengineering.stackexchange.com/questions/197272/best-practice-for-creating-a-global-config-class-used-by-numerous-components c++ - Best practice for creating a 'global' config class used by numerous components - Software Engineering Stack Exchange]
ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
* [https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/114924/config-class-struct-pattern-or-anti-pattern-alternatives?newreg=b46538fc865f46b08f6bf06d317925bf design - Config Class/Struct: Pattern or Anti-Pattern? Alternatives? - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/441985/best-practice-design-pattern-for-working-with-a-config-file json - Best practice/design pattern for working with a config file - Software Engineering Stack Exchange]


アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「[https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]」で特によく議論されている。
例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)
.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。


# シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
* [https://stackoverflow.com/questions/15637429/how-to-escape-double-quotes-in-json How to escape double quotes in JSON - Stack Overflow]
# DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]


2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。
JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。


メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。
基本的な考え方がある。


==== do-while/if ====
# JSON value用に二重引用符"を\"で置換。
複雑なif文と相性がいい。
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
# JSON項目の二重引用符"を\"で置換。
# 全体を二重引用符"で囲む。


for whileの無限ループで最後にbreakでも同じか
こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。
do {
  if (true) break;
} while(false);
if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。


==== GoF ====
=== ケース変換 ===
[https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2) デザインパターン (ソフトウェア) - Wikipedia]
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]


基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。
キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。


これにより、いろんなケースに同じコードで対応できる。
=== encode ===
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]


23パターンある。23パターンのうち16パターンは言語サポートで単純化か除去できる。
日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。


* 生成5個
* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
*# Abstract Factory
* UTF-8
*# Builder
* base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
*# Factory Method
* HTMLエンコード: HTMLで特殊な意味を持つ文字を&amp;lt;などに変換する。
*# Prototype
*# Singleton
* 構造7個
*# Adapter
*# Bridge
*# Composite
*# Decorator
*# Facade
*# Flyweight
*# Proxy
* 振る舞い11個
*# Chain of Responsibility
*# Command
*# Interpreter
*# Iterator
*# Mediator
*# Memento
*# Observer
*# State
*# Strategy
*# Template Method
*# Visitor


特に頻出パターン
==== Percent-encoding ====


* Strategy
* [https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%82%BB%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0 パーセントエンコーディング - Wikipedia]
* Observer
* [https://developer.mozilla.org/ja/docs/Glossary/Percent-encoding Percent-encoding (パーセントエンコーディング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN]
* Decorator
* [https://datatracker.ietf.org/doc/html/rfc3986 RFC 3986 - Uniform Resource Identifier (URI): Generic Syntax]
* Factory Method
* Adapter
* Singleton


このほかに、アーキテクチャーごとに、パターンがある。
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
上記文字はエンコードの対象外。


* Repository: DDD、クリーンアーキテクチャー。Adapterパターン内部で使っているデータ保持用の役割。
==== 英数変換 ====
[https://stackoverflow.com/questions/28110062/php-how-to-encode-all-characters-with-rawurlencode string - PHP How to encode all characters with rawurlencode - Stack Overflow]


===== Factory Methodパターン =====
変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。
[https://blog.ecbeing.tech/entry/2021/01/20/114000 なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)]


コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。
こういう目的だと%エンコーディングが適している。


引数の内容に応じて、異なるクラスを作成する。
ただし、一部の記号を許可しているので、自前で変換する。
  import java.util.ArrayList;
  function encode_all($str) {
import java.util.Arrays;
     $hex = unpack('H*', $str);
import java.util.Collections;
     return preg_replace('~..~', '%$0', strtoupper($hex[1]));
import java.util.Comparator;
import java.util.List;
// Creatorに相当する
abstract class ListPrinter {
     // anOperationに相当する
    public void printList(List<String> list) {
     }
    // factoryMethodに相当する
    protected abstract Comparator<String> createComparator();
  }
  }
   
   
  // ConcreteCreatorに相当する
  $str = 'big ƒüßchen';
class DictionaryOrderListPrinter extends ListPrinter {
  print_r(encode_all($str));
    @Override
    protected Comparator<String> createComparator() {
        return new DictionaryOrderComparator();
    }
}
// ConcreteCreatorに相当する
class LengthOrderListPrinter extends ListPrinter {
    @Override
    protected Comparator<String> createComparator() {
        return new LengthOrderComparator();
    }
}
// メインクラス
public class FactoryMethodSample {
    public static void main(String args[]) {
        List<String> list = Arrays.asList("いちご", "もも", "いちじく");
        System.out.println("五十音順で表示:");
        new DictionaryOrderListPrinter().printList(list);
   
        System.out.println("長さ順で表示:");
        new LengthOrderListPrinter().printList(list);
    }
}
return new <Class> 的なことをするメソッドのパターン。


* オブジェクトの生成処理を1か所に集約できて、生成処理が複雑な場合 (前準備や引数が多い場合など) 使う側をシンプルにできる。
==== Term ====
* 条件によって別の子クラスを返したり、キャッシュを使ったりできる。
紛らわしい用語がある。


ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。
* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])。
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])。
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。


Factory MethodとAdapterを併用すると、OSごとやDBの違いを吸収することができる。
フレームワークの中にライブラリーも含めていいと思う。
 
「[https://webbigdata.jp/what-is-ai/page-6804/page-8359/page-12091/ Pythonのモジュールとパッケージとライブラリとフレームワークの違い]」がわかりやすい。
 
フレームワークはライブラリーを含んでいる。ライブラリーで共通でいいと思う。
 
==== Category ====
「[https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E5%B7%A5%E7%A8%8B ソフトウェア開発工程 - Wikipedia]」
 
ソフトウェアの分類、ページ分類時に役立つ。
 
* 言語
* ツール: 静的解析、テスト、文書など。
* フレームワーク


https://chatgpt.com/share/6876fa52-d850-800b-81f0-78bb0d44a7ba
MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。


FactorySelectorみたいなクラスで、createAdapter的なので、違いを隠蔽して取得するとよさそう。


===== Adapterパターン =====
* PHP language
重要。FWやライブラリーを抽象化するパターン。
* PHP tool
* PHP framework


XxxAdapterというクラスを作って、特定のメソッド経由で、目的のクラスにアクセスする。
==== 成功時連続継続処理 ====
interface ProductPrice{
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。
  public int getPrice();
}
class Product{
  private int cost;
  public int getCost(){
    return cost;
  }
}
class ProductAdapter extends Product implements ProductPrice{
  public int getPrice(){
    return this.getCost();
  }
}
継承の他に、移譲 (Adapter内でのインスタンス生成) でも実現できる。DIと相性がいいかもしれない。
interface ProductPrice{
  public int getPrice();
}
class Product{
  private int cost;
  public int getCost(){
    return cost;
  }
}
class ProductAdapter implements ProductPrice{
  private Product product = new Product();
  public int getPrice(){
    return product.getCost();
  }
}
上記では、Product.getCost (製品価格) をProductAdapter.getPriceのメソッド名でアクセスする。既存のクラスを一切変更することなく、getPriceという別のメソッド名で、目的のメソッドにアクセスする。


例えば、Windows/Mac/Linuxのように、異なるOSでOSのバージョン番号を取得するような場合、Adapter経由でアクセスすれば、同じメソッド名で異なるOSのAPIにアクセスできる。FWやライブラリーのバリエーションの違いを吸収できる。
# 処理実行。
# 成功ならA、失敗なら終了。
# 処理実行。
# 成功ならA、失敗なら終了。


==== Naming ====
こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
 
        /*
===== camelCase =====
        // 無限ループで終了条件でブレイク
https://gnusocial.jp/notice/7694551
        while (true) {
 
            // 処理実行
!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。
            if (失敗) {
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…
forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。


===== getMyVariable() vs myVariable() =====
いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。


* [https://stackoverflow.com/questions/3532828/php-methods-getmyvariable-vs-myvariable naming conventions - PHP methods: getMyVariable() vs myVariable() - Stack Overflow]
これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。
* [https://stackoverflow.com/questions/139427/which-coding-convention-to-follow-for-php Which Coding convention to follow for PHP? - Stack Overflow]


getterとsetterの命名規則。
offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
 
        $offset = 0;
getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。
        while (true) {
 
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。
                json_encode([
 
                    'dbSchemaId' => $table_info['dbSchemaId'],
===== namePrefixed() vs prefixedName() =====
                    'offset' => $offset,
https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;
            // 2回目からはヘッダー除去して書き込み。
            $start = strpos($response, "\n") + 1;
            $flat = FILE_APPEND;
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }


名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。
        for ($offset = 0;
 
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。
            (function() use (&$offset, $limit, $response) {
 
                // 2回目からはヘッダー除去して書き込み。
そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。
                $start = strpos($response, "\n") + 1;
 
                $flag = FILE_APPEND;
PHPでは以下のような命名規則が好まれる。
                if ($offset === 0) {
 
                    $start = $flag = 0;
* 動詞+修飾対象=getPrefixedName/isPrefixed()
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
* 修飾対象+状態/修飾語=prefixdName
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }


getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。
=== character ===


===== map =====
==== BOM ====
連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。
UTF-8のBOM
\xef\xbb\xbf
この文字を先頭につけるとUTF-8のBOMになる。


<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。
=== Convert ===


https://chatgpt.com/c/67ca84e0-9018-800b-9674-035ae9f4bbaf
==== IP/CIDR ====
 
// JavaScript
* [key]_[value]_map
<nowiki> </nowiki>  /**
* [key]_to_[value]
<nowiki> </nowiki>    * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
 
<nowiki> </nowiki>    * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
上記のどちらかがいいだろう。toがkey_valueの区切りが明示的でいいかもしれない。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  toCIDR(ipaddress) {
<nowiki> </nowiki>    const [address, mask] = ipaddress.split('/')
<nowiki> </nowiki>    const segments = mask.split('.')
<nowiki> </nowiki>    const CIDR = segments
<nowiki> </nowiki>      .map((e) => Number(e).toString(2))
<nowiki> </nowiki>      .join(<nowiki>''</nowiki>)
<nowiki> </nowiki>      .replace(/0*$/, <nowiki>''</nowiki>).length
<nowiki> </nowiki>    return address + '/' + CIDR
<nowiki> </nowiki>  },
<nowiki> </nowiki>  /**
<nowiki> </nowiki>    * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
<nowiki> </nowiki>    * @param {number} cidr - ciderの数字。
<nowiki> </nowiki>    * @return {string} x.x.x.x形式のIPアドレス文字列。
<nowiki> </nowiki>    */
<nowiki> </nowiki>  cidrToIp(cidr) {
<nowiki> </nowiki>    const digit = 32
<nowiki> </nowiki>    const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
<nowiki> </nowiki>    return ip
<nowiki> </nowiki>      .match(/.{8}/g)
<nowiki> </nowiki>      .map((e) => parseInt(e, 2))
<nowiki> </nowiki>      .join('.')
<nowiki> </nowiki>  },


===== array/foreach =====
=== Algorithm ===


* [https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
==== 再帰処理 ====
* https://chatgpt.com/c/6747aee4-ab64-800b-88d7-940a5c4201bf
https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950


foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。
foreach (table as $row => $line)
その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。


いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。
再帰関数で実装するほかに、スタックで処理する方法がある。


* 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。
* 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。


上記の命名規則だとわかりやすい。
パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。
$rows = [[]];
foreach ($rows as $row_key => $row_value) {
  foreach ($row_value as $column_key => $column_value) {}
}
foreach ($row_list as $row_key => $row) {
    foreach ($row as $column_key => $column) {
    }
}
foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}
value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。


もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。
最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。


===== Function argument order =====
https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5
関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。<blockquote><nowiki>https://social.senooken.jp/notice/67270</nowiki>


うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…
再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。


int func(入力,変更,出力)
JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。


この順番。理由は,この順番で使うから。
シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。


memcpyとかは例外が多い。
=== Other ===


x = bの語順からきているからとの憶測がある。
==== コメントの著者名 ====
https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08


<nowiki>https://okwave.jp/qa/q4202225.html</nowiki></blockquote>
GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。


===== get/fetch =====
大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。
https://chatgpt.com/c/67bd1a05-d3a0-800b-88d8-f4f47b995560


* fetch=外部から取得する意味。DBや外部Web APIから取得する場合にfetchがいい。
git blameで行単位で編集者が分かる。
* get=手元から取得する意味。プロパティーなど内部から取得する場合。


===== list/data =====
==== 確率処理 ====
fetchList/fetchDataのどちらがいいか?
https://chatgpt.com/share/68145e5c-9d14-800b-9cca-1cd9e46e2dd6


* list=配列。必ず配列。
ある確率で処理をしたり、しなかったりしたいことがある。
* data=全部。配列以外にnullや単一データがあるならこちら。
$chance = 30; // 30%の確率
if (mt_rand(1, 100) <= $chance) {
    // 30%の確率でここに入る
    echo "当たり!";
} else {
    // 70%の確率でこっちに入る
    echo "はずれ...";
}
乱数を作成して、それで確率値の超過判定で表現できる。


基本はfetchListでいいと思う。


===== Order =====
https://chatgpt.com/c/67ca7edf-f92c-800b-8174-9706bfba3ff3


関数実行の順番が大事なときと、そうでないときがある。区別し難い。


順序を明示したい場合、メソッドチェーンを使うのが確実。
=== Architecture ===


他に、前の関数の結果、戻り値を後続の引数に渡すなら、それも悪くない。
==== About ====
https://grok.com/share/c2hhcmQtMw%3D%3D_d762a384-9703-4539-b8e7-022bc680d88f


===== privateの先頭_ =====
* MVC
privateなメソッド、プロパティーで、先頭に_をつけることがある。
* MVVM
* クリーンアーキテクチャー


https://chatgpt.com/c/67da92b1-1650-800b-b347-f16f76fd549a
このあたりが有名。MVCが一番無難。MVCでは厳しいような大規模になったら、他を検討する価値がある感じ。


privateのアクセス権、可視性の機能があるなら、それを使えばいいので、_は不要。むしろないほうがいいらしい。PHPのPSR-12では禁止されている。
==== Clean Architecture ====
クリーンアーキテクチャー。最近よく聞く設計手法。


[https://www.php-fig.org/psr/psr-12/ PSR-12: Extended Coding Style - PHP-FIG]」<blockquote>Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning.</blockquote>Pythonのように、言語的にないなら、やむを得ない。
* [https://zenn.dev/muno/articles/introduce-clean-architecture クリーンアーキテクチャに入門する]
* https://chatgpt.com/share/6870b175-d394-800b-a885-b41600d128cd


PHPは昔privateがなかったので、そういう古いコードとの一貫性の維持が目的なら、先頭_もあり。
「[https://blog.cleancoder.com/uncle-bob/2011/11/22/Clean-Architecture.html Clean Coder Blog]」で2011-11-22にRobert C. Martinによって提唱さえたアーキテクチャー。ソフトウェアの開発・展開・運用・保守を簡単にして、プログラマーの生産性の最大化が目的。


===== 配列の要素数 =====
多くのアーキテクチャーでは、関心を分離して、異なる役割や責務を分離して、変更の影響を最小限にしている。これの実現に、ソフトウェアをレイヤー (層) に分けている。クリーンアーキテクチャーは、このアイデアの1個のガイドラインになっている。
https://chatgpt.com/c/67ecd6ff-b06c-800b-8f44-cfeb9c5768bb


配列の要素数、長さを変数に格納して使うことがけっこうある。その際の変数名。
中心にビジネスルールがあって、玉ねぎのように、中心から外に向かって、層構造になっている。


オブジェクト指向に従うなら、配列名_size/countの接尾辞がいい。
# エンティティ: ビジネスロジック (ドメイン層)。外部の影響 (FWの更新など) に影響を受けない。
# ユースケース: アプリのビジネスルール。interface adapterから受け取ったデータをもとに、entityのビジネスロジックを組み合わせて、アプリ特有のロジックを実現。
# Interface Adapter (Controller/Gateway/Presenter): 外部システムと内部システムのデータを変換する。例えば、コントローラーはリクエストをUsecaseが利用できる形式に変換 (4->2) し、プレゼンターはユースケースの出力を外部システムが理解できる形式に変換 (2->4) する。
# Framework/Driver (DB/Device/Web Framework/UI/外部Web API): WebアプリケーションFW、DBなど。外部エージェントとの通信処理。基本的にはライブラリーやFWを使う。


C++のvectorなどのコンテナーだと.size()でとれる。変数に格納せずにsizeでいい。
基本はこれだけ。


変数にあえて代入するならば、配列名_sizeが自然。
既存のMVC型アプリをクリーンアーキテクチャーにする場合の対応。


ただ、PHPだと、countで要素数を取得する。その都合で、_countがよい。
* Controller: Interface adapter
item_list = [];
* Model: Entity (domain/repository interface)
item_list_size
* View: Framework
item_list_count


==== OOP ====
たまねぎの層構造の表現は、ディレクトリーの親子関係で表現できるときれいなんだけど。層ごとでグループ化したり、継承したりする場合に、ディレクトリーを作れなくて困る。大規模になるならなおさら。


===== 継承とtrait =====
中小規模や、うまく分割してきれいにまとめられるならあり。
https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe


apcとstaticのキャッシュクラスがあって、それとは別にビジネスロジックの共通化をしたい場合、いくつか方法がある。
一般的には、機能を最上位において、その下で4の層をディレクトリーで配置するというのが多い模様。
 
src/
# apc と static を統合した親クラスで trait を use し、子クラスで継承する
└── Article/
# apc と static を子クラスで直接継承し、trait を use
    ├── Domain/
# 継承(extends)ではなく、キャッシュクラスを別のクラスとして利用する という考え方です。
    ├── Application/
    ├── Interface/
    └── Infrastructure/


===== 依存注入(DI)・継承・trait の使い分けまとめ =====
==== SSR+CSR ====
https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe


キャッシュやORMのような、切り替え可能な機能の場合、DIで実装してプロパティーに格納して使うのが使いやすい。DIはテストのしやすさに勝る。
===== About =====
https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45


継承は親子関係が明確な場合。
バックエンドとフロントエンドの分離の話。


===== コンストラクターのアクセス権 =====
SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部する (CSR) というのが最近の流行。
基本はpublicだが、privateとprotectedを指定する場面がある。デザインパターンと関係している。


https://chatgpt.com/c/67fdac9a-2fac-800b-91bf-460c10fd72f5
SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。


* protected: 継承先のみ。ベースクラスや抽象クラスで使用する。ベースクラスや抽象クラスは継承を前提とするから、直接インスタンス生成してほしくないから。ファクトリーパターンと組み合わせる。
SSRの利点。
* private: クラス内部のみ。シングルトン・ユーティリティー (静的ファクトリーメソッド専用クラス) 系クラスで、インスタンスを作って欲しくない、1個だけのように、インスタンスの生成数を制限したい場合。


===== 例外の扱い =====
* SEO
https://chatgpt.com/share/68118e39-40d0-800b-9bd8-43da8908bfcd
* 初期表示。
* 匿名。


DBアクセス系のメソッドは例外を基本的に出す。
SSRの課題。


DBアクセス系メソッドを使って、特定のデータを取得するようなメソッドを使った場合に、例外をどこで処理すべきかという話。
* サーバー負荷: データとHTML作成を同時に行うから。
* 分散困難:


現代的なフレームワークだと、アプリのエントリーポイント (index.php) などにtry-catchが1個あって、そこで自分で処理しなかったらデフォルトの例外処理で処理する形になる。
キャッシュの活用がポイントになるとのこと。


なお、try-catchは並列実行、マルチスレッド環境では問題があったりする。
===== リダイレクト =====
https://chatgpt.com/share/6886c2c2-b5cc-800b-8e03-e301c22d5eff


throwにコストがかかる。だから、頻繁に失敗するような処理は、try-catch (throw) を使わない形で実装したほうがいい。リアルタイム性や超ハイパフォーマンスが必要なところとか。
CSRでやる場合、最終的にCSRの成果物をstaticに生成して、それをサーバー側のpublicに配置する感じになる。


PHPはリクエスト単位で、プロセス・スレッド起動する設計になっている。ApacheやFPMがそういう動作になっているから。だから、マルチスレッドは考えなくていい。並列実行は、別リクエストみたいな扱い。
npm run generateの生成先をpublicに直接してもOKだと思う。いや、これは既存のindex.phpとかが消えるのでまずい。シンボリックリンクにするとか。


APIに複数アクセスする場合、curl_multiで1プロセスでうまくやる方法があるらしい。
1台でフロントとサーバーの両方を扱う場合、/apiなどサーバーリクエストに使うURLはindex.phpに、それ以外はindex.htmlなどにするようなリダイレクト設定が必要。


===== 関数戻値と例外 =====
以下のようなイメージ。
https://chatgpt.com/share/6833c48c-ce58-800b-a4d7-f389d15167e9
<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>
    RewriteEngine On
    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_URI} ^/(api|sanctum)(/|$)
    RewriteRule ^ index.php [L]
    # Nuxtのビルド済み静的ファイル (_nuxt/) は除外
    RewriteCond %{REQUEST_URI} ^/_nuxt/
    RewriteRule ^ - [L]
    # RewriteCond %{REQUEST_FILENAME} !-f [OR]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ - [L]
    RewriteRule ^ index.html [L]
</IfModule>


関数が失敗した場合に、戻り値nullで返すか、戻り値false相当で返すか、例外で返すかという議論。
=== Naming ===


例えば、配列を返すようなメソッドで、処理失敗時に空配列ではなくて、nullを返して失敗を表すか、あるいは例外で返すべきかという議論。
==== Code ====


nullの代わりにデータ型でboolになる値を返す (配列なら[]、数値系なら0、文字列なら<nowiki>''</nowiki>)。
===== camelCase =====
{| class="wikitable"
https://gnusocial.jp/notice/7694551
|+
!項目
!利点
!欠点
|-
|ブール
|型が同じなので扱いやすい。
|失敗と結果を厳密に区別したいときに、できないことがある。
|-
|null
|失敗と結果を厳密に区別可能。
|使う側で常にnullチェック必要。
|-
|例外
|型を統一でき、失敗も区別できる。
|エントリーポイントにtry/catchがないとtry/catch地獄。
|}
基本は型は同じで、どうしても処理失敗の区別が必要なら、例外にする。これにするとシンプルで融通がきく。


例外にする内容。
!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。


* 処理続行が不能な場合 (DBアクセス失敗)
getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…
* ビジネスロジックで意図的に続行不能にしたい場合 (想定外の頻繁アクセス、保安対策?)。
* 期待と異なる場合 (1件取得できないといけないのにできないとき)。


===== DI =====
===== getMyVariable() vs myVariable() =====
https://chatgpt.com/share/682e8fd6-376c-800b-a01e-faa832b0fd07


Dependency Injection。主にテストしやすさを向上させるための手法。
* [https://stackoverflow.com/questions/3532828/php-methods-getmyvariable-vs-myvariable naming conventions - PHP methods: getMyVariable() vs myVariable() - Stack Overflow]
* [https://stackoverflow.com/questions/139427/which-coding-convention-to-follow-for-php Which Coding convention to follow for PHP? - Stack Overflow]


クラスやメソッド内部で、他のクラスを使う場合、コンストラクターや、メソッドで該当クラスを受け取って、プロパティーや変数として参照する。クラス (依存性) を外部から渡す (注入) すること。
getterとsetterの命名規則。


こうすることで、該当メソッドのテスト時に、中で使用する外部クラスを外部から置換できる。これにより、テスト対象メソッドの処理だけをテストできる。
getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。


DIの注入方法で2通りある。
ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。


* コンストラクターDI: public/protectedメソッド向き。一般的にDIという場合これ。
===== namePrefixed() vs prefixedName() =====
* メソッドDI: privateメソッド向き。特定メソッドだけでしか使わない場合、あまり使わない場合。
https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85


使用する外部クラスが複数ある場合、DIでその分指定する。あまりにも数が多い場合、DTOやデリゲートなど複数クラスを保有するクラスを作って、それを引数に渡す。あるいは、依存クラスが多すぎる場合、設計に問題がある。適切に分割した方がいい
名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。


なお、メソッドDIにする場合、DI対象は引数の先頭の方に指定する。必須で省略不能だから。
例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。


==== DB ====
そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。
[http://blog.tojiru.net/article/277021312.html PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note]


DBアクセスのモデル化。行をクラスとすると扱いやすい模様。
PHPでは以下のような命名規則が好まれる。


getterを作ったり、データの妥当性のチェックなどもできる。
* 動詞+修飾対象=getPrefixedName/isPrefixed()
* 修飾対象+状態/修飾語=prefixdName


select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。
getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。


データベース関係のデザインパターンがいくつかある。
===== map =====
連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。


* Active Record
<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。
* Data Mapper


===== Active Record pattern =====
https://chatgpt.com/c/67ca84e0-9018-800b-9674-035ae9f4bbaf


* [https://ja.wikipedia.org/wiki/Active_Record Active Record - Wikipedia]
* [key]_[value]_map
* [https://www.techscore.com/tech/Ruby/Rails/other/designpattern/ デザインパターンから見たActive Record | TECHSCORE(テックスコア)]
* [key]_to_[value]


テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。
上記のどちらかがいいだろう。toがkey_valueの区切りが明示的でいいかもしれない。


シンプルだが、複雑な操作が苦手。
===== array/foreach =====


エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。
* [https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
* https://chatgpt.com/c/6747aee4-ab64-800b-88d7-940a5c4201bf


Ruby on Rails/Laravel+Eloquentなどで採用。
foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
foreach (table as $row => $line)
その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。


===== Data Mapper pattern =====
いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。
[https://gihyo.jp/dev/serial/01/ruby/0014 第14回 DataMapperの使い方 | gihyo.jp]


テーブルのレコードをクラスにするのはARと共通。
* 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
* 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。


ただし、DB操作用のクラスを用意してそちらでDB操作する。
上記の命名規則だとわかりやすい。
$rows = [[]];
foreach ($rows as $row_key => $row_value) {
  foreach ($row_value as $column_key => $column_value) {}
}
foreach ($row_list as $row_key => $row) {
    foreach ($row as $column_key => $column) {
    }
}
foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}
value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。


その都合、1テーブルに2クラス必要。
もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。


User/UserMapperのような対応関係。
===== Function argument order =====
関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。<blockquote><nowiki>https://social.senooken.jp/notice/67270</nowiki>


2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。
うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…


===== JOIN =====
int func(入力,変更,出力)
Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。


基本はエンティティーのプロパティーに持たせる感じ。
この順番。理由は,この順番で使うから。


<blockquote>datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?
memcpyとかは例外が多い。


`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。
x = bの語順からきているからとの憶測がある。


以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。
<nowiki>https://okwave.jp/qa/q4202225.html</nowiki></blockquote>


### 1. マッパークラスでの`JOIN`実装
===== get/fetch =====
https://chatgpt.com/c/67bd1a05-d3a0-800b-88d8-f4f47b995560


`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。
* fetch=外部から取得する意味。DBや外部Web APIから取得する場合にfetchがいい。
* get=手元から取得する意味。プロパティーなど内部から取得する場合。


```python
===== list/data =====
fetchList/fetchDataのどちらがいいか?


class UserMapper:
* list=配列。必ず配列。
* data=全部。配列以外にnullや単一データがあるならこちら。


    def find_user_with_orders(self, user_id):
基本はfetchListでいいと思う。


        sql = """
===== Order =====
https://chatgpt.com/c/67ca7edf-f92c-800b-8174-9706bfba3ff3


            SELECT * FROM users
関数実行の順番が大事なときと、そうでないときがある。区別し難い。


            JOIN orders ON users.id = orders.user_id
順序を明示したい場合、メソッドチェーンを使うのが確実。


            WHERE users.id = %s
他に、前の関数の結果、戻り値を後続の引数に渡すなら、それも悪くない。


        """
===== privateの先頭_ =====
privateなメソッド、プロパティーで、先頭に_をつけることがある。


        results = self.db.execute(sql, (user_id,))
https://chatgpt.com/c/67da92b1-1650-800b-b347-f16f76fd549a


       
privateのアクセス権、可視性の機能があるなら、それを使えばいいので、_は不要。むしろないほうがいいらしい。PHPのPSR-12では禁止されている。


        user = User(results[0]['user_id'], results[0]['user_name'])
[https://www.php-fig.org/psr/psr-12/ PSR-12: Extended Coding Style - PHP-FIG]」<blockquote>Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning.</blockquote>Pythonのように、言語的にないなら、やむを得ない。
 
PHPは昔privateがなかったので、そういう古いコードとの一貫性の維持が目的なら、先頭_もあり。


        orders = [Order(row['order_id'], row['product_name'], user) for row in results]
===== 配列の要素数 =====
https://chatgpt.com/c/67ecd6ff-b06c-800b-8f44-cfeb9c5768bb


        user.orders = orders
配列の要素数、長さを変数に格納して使うことがけっこうある。その際の変数名。


        return user
オブジェクト指向に従うなら、配列名_size/countの接尾辞がいい。


```
C++のvectorなどのコンテナーだと.size()でとれる。変数に格納せずにsizeでいい。


この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。
変数にあえて代入するならば、配列名_sizeが自然。


### 2. リポジトリでの集約
ただ、PHPだと、countで要素数を取得する。その都合で、_countがよい。
item_list = [];
item_list_size
item_list_count


`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。
===== 例外前提関数 =====
https://grok.com/share/c2hhcmQtMw%3D%3D_359ae291-e39d-42cd-9a8f-e6453b388993


```python
APIのパラメーターチェックとかで、チェック関数を何個も書くなら、例外を投げる形にして、それを補足する形が楽になる。
        $result = $this->locationCheck($mbrcode, $latitude, $longitude, $ostype);
        if ($result['status'])
            return ['message' => $result['message'], 'status' => $result['status']];
        $result = $this->isCheckedIn($mbrcode);
        if ($result['status'])
            return ['message' => $result['message'], 'status' => $result['status']];
        $store = $this->isStoreNearby($latitude, $longitude);
        if (!$store['status'])
            return ['message' => $result['message'], 'status' => self::STATUS_STORE_NOT_FOUND];
        $result = $this->addPoint($mbrcode, $ostype, $store['pattern'], $store['shpcode'], $store['point']);
        if (!$result['status'])
            return ['message' => $result['message'], 'status' => self::STATUS_ERROR];


class UserRepository:
        try {
            $this->locationCheck($mbrcode, $latitude, $longitude, $ostype);
            $this->isCheckedIn($mbrcode);
            $store = $this->isStoreNearby($latitude, $longitude);
            $this->addPoint($mbrcode, $ostype, $store['pattern'], $store['shpcode'], $store['point']);
        } catch (Exception $e) {
            return ['status' => $e->getCode(), 'message' => $e->getMessage(), 'point' => 0];
        }
関数の戻り値を都度if文でチェックする必要がなくなってスマートになる。


    def __init__(self, user_mapper, order_mapper):
そういう、例外前提関数の名前。isXXXとかにするとboolを期待する。


        self.user_mapper = user_mapper
assertXXXにするとわかりやすい。assertは例外を投げたり、中断するイメージがあるから。


        self.order_mapper = order_mapper
validateだとどっちもありえるからわかりにくい。


    def get_user_with_orders(self, user_id):
===== 条件のbool変数・関数化 =====
https://grok.com/share/c2hhcmQtMw%3D%3D_dabd40dd-e42b-44be-931c-b1cc18425c5d


        user = self.user_mapper.find(user_id)
if文の条件式の内容は、複雑になるなら基本的に変数・関数に括り出して適切な名前を付けたほうがいい。


        orders = self.order_mapper.find_by_user_id(user_id)
コメントで記載することもできるが、コメントが古くなるリスクがある。


        user.orders = orders
===== 拡張子、サンプルファイル =====
https://grok.com/share/c2hhcmQtMw%3D%3D_d3c100c1-f1be-47c4-8f36-1710af04a2c1


        return user
app/config.php.sampleのように、アプリのデフォルト設定をファイル末尾に追記する形でファイルを用意することがある。これの是非。


```</blockquote>UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。
基本は、app/config.sample.phpのように、拡張子は意味のあるものにする。


結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。
Webアプリの公開ディレクトリーなどで、誤動作を抑止するなら、拡張子を明示的に分ける意味がある。


クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。
が、他のアプリや構文強調などはファイル拡張子で判断するので、普通は困る。


方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。
=== Other ===


==== Other ====
==== Document ====
設計文書を作成する際、MS Word系で作るのが無難。


===== 1対1-多対多 =====
画面系の設計の場合、1画面に入りきらないかもしれないが、部分ごとに分割画像にして、1ページに画像と説明を併記する形にして、縦に長い文書にするほうが管理しやすいと思う。
プログラミング言語でデータの関連付けをすることがある。


1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。
ExcelやPowerpointで1枚丸ごとにしてい気持ちもあるが。だったら、Figmaとかそういうデザインツールとか、Inkscape/LibreOfficeDrawとかだろうか。


多対多の場合。これも配列。二次元配列で基本は0要素目など。
ただ、やっぱり目次とか欲しいからMS Word系がいいと思う。
$array[][]


===== 1対多 =====
==== Atomic Design ====
https://chatgpt.com/share/683faf08-f374-800b-ac40-b96b427d7365


例えば、DBからデータを取得した場合など、1行のデータに複数列あって、列を特定したい場合、連想配列で、バリューをさらに連想配列にするのが普通。ただ、1:1ならただの連想配列でよかったのが、連想配列の配列になるのがイマイチ。
* [https://atomicdesign.bradfrost.com/chapter-2/ Atomic Design Methodology | Atomic Design by Brad Frost]
['row1' => ['col1' => 'value1', 'col2' => 'value2']]
* [https://zenn.dev/bizlink/articles/b5c8985af8407a Atomic Designの概念]
いくつか方法がある。


# ネスト連想配列。無難。
最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。
# 連想配列の代わりにオブジェクト。これができるならこれが素直。
# 連想配列の代わりにリスト。ただし、列の意味が分かりにくい。foreach ($map as $interface => [$property, $defaultClass])
# 値部分を意味のある文字列で使うところで分割とか。


手短にしたいなら、3のリストになるかも。
* atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
* molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
* organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
* templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
* pages: ページ。テンプレートを使用したページ。


==== レガシープロジェクトの立て直し ====
==== インターフェイスと抽象クラス ====
https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002


1. 現状分析
* [https://qiita.com/nogson/items/e6575d6617f854ed6e25 PHPでインターフェイスと抽象クラスを使う #PHP - Qiita]
* https://chatgpt.com/c/6796dd25-2380-800b-9d87-847c60e6f546


(1) ソフトウェアの動作確認
オブジェクト指向でよく登場するインターフェイス、抽象クラス、クラスの違い。
* インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
* インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。


現在の環境でアプリケーションを動作させる。
インターフェイス


どの部分が機能していて、どこが問題かを確認する。
* メソッド宣言のみ。
* static/constの場合に限定して、メソッド定義、定数もOK。
* 多重継承可能。
* tagのイメージ。
例えば、複数のクラスで共通の処理がある場合、その共通部分をInterfaceにして、それを継承すると良い。その部分だけ取り出して流用できる。


必要であればエラーログを確認する。
例えば、[Animal<-Duck] のような関係がある時、Duckは空も飛べるし、泳ぐこともできるとしたら、飛べることと泳げることの機能はAnimalの中でも対応がわかれる。こういうところをInterfaceにしておくと、振る舞いを統合できる。


(2) 依存関係の調査
抽象クラスは一部共通にしたい場合に使う。Interfaceは指定機能を全部共通。


アプリケーションのライブラリやフレームワークのバージョンを調査。
ベースは抽象クラス、クラスにしておいて、複数クラスで共通にしたい場合interfaceで定義するときれいに実装できる。


サポートが終了しているもの、互換性が失われたものを特定。
==== Config class ====


(3) コードベースの状態評価
* [https://softwareengineering.stackexchange.com/questions/197272/best-practice-for-creating-a-global-config-class-used-by-numerous-components c++ - Best practice for creating a 'global' config class used by numerous components - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/114924/config-class-struct-pattern-or-anti-pattern-alternatives?newreg=b46538fc865f46b08f6bf06d317925bf design - Config Class/Struct: Pattern or Anti-Pattern? Alternatives? - Software Engineering Stack Exchange]
* [https://softwareengineering.stackexchange.com/questions/441985/best-practice-design-pattern-for-working-with-a-config-file json - Best practice/design pattern for working with a config file - Software Engineering Stack Exchange]


コードの品質 (可読性、設計、テストカバレッジ) を確認。
アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「[https://softwareengineering.stackexchange.com/questions/386212/best-way-to-provide-configuration-parameters-for-objects-far-away-from-the-start Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange]」で特によく議論されている。


セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。
# シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
# DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。


2. 計画立案
2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。


(1) ゴール設定
メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。


具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。
==== do-while/if ====
複雑なif文と相性がいい。


(2) 優先順位の決定
for whileの無限ループで最後にbreakでも同じか
do {
  if (true) break;
} while(false);
if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。


どの機能を維持し、どの機能を削除または置き換えるか決定。
==== GoF ====
[https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2) デザインパターン (ソフトウェア) - Wikipedia]


ユーザーに直接影響を与える部分を優先。
基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。


(3) リスク評価とバックアップ
これにより、いろんなケースに同じコードで対応できる。


修正に伴うリスクを評価し、現行システムのバックアップを取得。
23パターンある。23パターンのうち16パターンは言語サポートで単純化か除去できる。


3. 環境整備
* 生成5個
*# Abstract Factory
*# Builder
*# Factory Method
*# Prototype
*# Singleton
* 構造7個
*# Adapter
*# Bridge
*# Composite
*# Decorator
*# Facade
*# Flyweight
*# Proxy
* 振る舞い11個
*# Chain of Responsibility
*# Command
*# Interpreter
*# Iterator
*# Mediator
*# Memento
*# Observer
*# State
*# Strategy
*# Template Method
*# Visitor


(1) 開発環境のモダナイズ
特に頻出パターン


ローカル環境やコンテナ (Docker) を用意してテストを容易にする。
* Strategy
* Observer
* Decorator
* Factory Method
* Adapter
* Singleton


CI/CD パイプラインの整備。
このほかに、アーキテクチャーごとに、パターンがある。


(2) 依存関係の更新
* Repository: DDD、クリーンアーキテクチャー。Adapterパターン内部で使っているデータ保持用の役割。


サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。
===== Factory Methodパターン =====
[https://blog.ecbeing.tech/entry/2021/01/20/114000 なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)]


(3) セキュリティの確保
コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。


古いOSSの脆弱性を修正。
引数の内容に応じて、異なるクラスを作成する。
 
import java.util.ArrayList;
HTTPSの導入、認証強化、インプット検証など。
import java.util.Arrays;
 
import java.util.Collections;
4. コードのモダナイズ
import java.util.Comparator;
 
import java.util.List;
(1) リファクタリング
 
// Creatorに相当する
レガシーコードをよりモダンで可読性の高いコードに変換。
abstract class ListPrinter {
 
    // anOperationに相当する
デザインパターンを適用して保守性を向上。
    public void printList(List<String> list) {
 
    }
(2) テストの追加
    // factoryMethodに相当する
    protected abstract Comparator<String> createComparator();
}
// ConcreteCreatorに相当する
class DictionaryOrderListPrinter extends ListPrinter {
    @Override
    protected Comparator<String> createComparator() {
        return new DictionaryOrderComparator();
    }
}
// ConcreteCreatorに相当する
class LengthOrderListPrinter extends ListPrinter {
    @Override
    protected Comparator<String> createComparator() {
        return new LengthOrderComparator();
    }
}
// メインクラス
public class FactoryMethodSample {
    public static void main(String args[]) {
        List<String> list = Arrays.asList("いちご", "もも", "いちじく");
        System.out.println("五十音順で表示:");
        new DictionaryOrderListPrinter().printList(list);
        System.out.println("長さ順で表示:");
        new LengthOrderListPrinter().printList(list);
    }
}
return new <Class> 的なことをするメソッドのパターン。


ユニットテスト、統合テストを導入。
* オブジェクトの生成処理を1か所に集約できて、生成処理が複雑な場合 (前準備や引数が多い場合など) 使う側をシンプルにできる。
* 条件によって別の子クラスを返したり、キャッシュを使ったりできる。


既存の機能が壊れないことを確認するための自動化されたテスト。
ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。


(3) フロントエンド/バックエンドの分離
Factory MethodとAdapterを併用すると、OSごとやDBの違いを吸収することができる。


必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。
https://chatgpt.com/share/6876fa52-d850-800b-81f0-78bb0d44a7ba


5. 機能拡張とデプロイ
FactorySelectorみたいなクラスで、createAdapter的なので、違いを隠蔽して取得するとよさそう。


(1) 新しい機能の追加
===== Adapterパターン =====
重要。FWやライブラリーを抽象化するパターン。


必要に応じて、現代のニーズに合った新機能を実装。
XxxAdapterというクラスを作って、特定のメソッド経由で、目的のクラスにアクセスする。
 
interface ProductPrice{
(2) 運用環境でのテスト
  public int getPrice();
 
}
新しい環境で徹底的にテストし、問題がないことを確認。
 
class Product{
(3) 本番環境にデプロイ
  private int cost;
 
  public int getCost(){
ロールバック計画を準備しつつ、安全にデプロイ。
    return cost;
 
  }
6. 継続的改善
}
 
(1) モニタリングの導入
class ProductAdapter extends Product implements ProductPrice{
  public int getPrice(){
    return this.getCost();
  }
}
継承の他に、移譲 (Adapter内でのインスタンス生成) でも実現できる。DIと相性がいいかもしれない。
interface ProductPrice{
  public int getPrice();
}
class Product{
  private int cost;
  public int getCost(){
    return cost;
  }
}
class ProductAdapter implements ProductPrice{
  private Product product = new Product();
  public int getPrice(){
    return product.getCost();
  }
}
上記では、Product.getCost (製品価格) をProductAdapter.getPriceのメソッド名でアクセスする。既存のクラスを一切変更することなく、getPriceという別のメソッド名で、目的のメソッドにアクセスする。


エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。
例えば、Windows/Mac/Linuxのように、異なるOSでOSのバージョン番号を取得するような場合、Adapter経由でアクセスすれば、同じメソッド名で異なるOSのAPIにアクセスできる。FWやライブラリーのバリエーションの違いを吸収できる。


(2) 定期的なアップデート
==== OOP ====


フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。
===== 継承とtrait =====
https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe


(3) コミュニティへの貢献
apcとstaticのキャッシュクラスがあって、それとは別にビジネスロジックの共通化をしたい場合、いくつか方法がある。


OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。
# apc と static を統合した親クラスで trait を use し、子クラスで継承する
# apc と static を子クラスで直接継承し、trait を use
# 継承(extends)ではなく、キャッシュクラスを別のクラスとして利用する という考え方です。


このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。
===== 依存注入(DI)・継承・trait の使い分けまとめ =====
https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe


== AI ==
キャッシュやORMのような、切り替え可能な機能の場合、DIで実装してプロパティーに格納して使うのが使いやすい。DIはテストのしやすさに勝る。
 
継承は親子関係が明確な場合。
 
===== コンストラクターのアクセス権 =====
基本はpublicだが、privateとprotectedを指定する場面がある。デザインパターンと関係している。
 
https://chatgpt.com/c/67fdac9a-2fac-800b-91bf-460c10fd72f5
 
* protected: 継承先のみ。ベースクラスや抽象クラスで使用する。ベースクラスや抽象クラスは継承を前提とするから、直接インスタンス生成してほしくないから。ファクトリーパターンと組み合わせる。
* private: クラス内部のみ。シングルトン・ユーティリティー (静的ファクトリーメソッド専用クラス) 系クラスで、インスタンスを作って欲しくない、1個だけのように、インスタンスの生成数を制限したい場合。
 
===== 例外の扱い =====
https://chatgpt.com/share/68118e39-40d0-800b-9bd8-43da8908bfcd
 
DBアクセス系のメソッドは例外を基本的に出す。
 
DBアクセス系メソッドを使って、特定のデータを取得するようなメソッドを使った場合に、例外をどこで処理すべきかという話。
 
現代的なフレームワークだと、アプリのエントリーポイント (index.php) などにtry-catchが1個あって、そこで自分で処理しなかったらデフォルトの例外処理で処理する形になる。
 
なお、try-catchは並列実行、マルチスレッド環境では問題があったりする。
 
throwにコストがかかる。だから、頻繁に失敗するような処理は、try-catch (throw) を使わない形で実装したほうがいい。リアルタイム性や超ハイパフォーマンスが必要なところとか。
 
PHPはリクエスト単位で、プロセス・スレッド起動する設計になっている。ApacheやFPMがそういう動作になっているから。だから、マルチスレッドは考えなくていい。並列実行は、別リクエストみたいな扱い。
 
APIに複数アクセスする場合、curl_multiで1プロセスでうまくやる方法があるらしい。
 
===== 関数戻値と例外 =====
https://chatgpt.com/share/6833c48c-ce58-800b-a4d7-f389d15167e9


=== 対話AI ===
関数が失敗した場合に、戻り値nullで返すか、戻り値false相当で返すか、例外で返すかという議論。


==== List ====
例えば、配列を返すようなメソッドで、処理失敗時に空配列ではなくて、nullを返して失敗を表すか、あるいは例外で返すべきかという議論。
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


いろいろある。
nullの代わりにデータ型でboolになる値を返す (配列なら[]、数値系なら0、文字列なら<nowiki>''</nowiki>)。
{| class="wikitable"
{| class="wikitable"
|+
|+
!Name
!項目
!
!利点
!
!欠点
!
|-
|-
|Bing
|ブール
|
|型が同じなので扱いやすい。
|
|失敗と結果を厳密に区別したいときに、できないことがある。
|
|-
|-
|Perplexity AI
|null
|
|失敗と結果を厳密に区別可能。
|
|使う側で常にnullチェック必要。
|
|-
|-
|ChatGPT
|例外
|
|型を統一でき、失敗も区別できる。
|
|エントリーポイントにtry/catchがないとtry/catch地獄。
|
|-
|Google Gemini
|
|
|
|}
|}
基本は型は同じで、どうしても処理失敗の区別が必要なら、例外にする。これにするとシンプルで融通がきく。


==== Grok ====
例外にする内容。


===== Xアカウント =====
* 処理続行が不能な場合 (DBアクセス失敗)。
https://x.com/i/grok/share/oeybkVEqzC4NNpH8whCdM7pl7
* ビジネスロジックで意図的に続行不能にしたい場合 (想定外の頻繁アクセス、保安対策?)。
* 期待と異なる場合 (1件取得できないといけないのにできないとき)。
 
===== DI =====
https://chatgpt.com/share/682e8fd6-376c-800b-a01e-faa832b0fd07
 
Dependency Injection。主にテストしやすさを向上させるための手法。
 
クラスやメソッド内部で、他のクラスを使う場合、コンストラクターや、メソッドで該当クラスを受け取って、プロパティーや変数として参照する。クラス (依存性) を外部から渡す (注入) すること。
 
こうすることで、該当メソッドのテスト時に、中で使用する外部クラスを外部から置換できる。これにより、テスト対象メソッドの処理だけをテストできる。
 
DIの注入方法で2通りある。


grok.comのgrokはスタンドアローン。x.com/i/grokはXアカウントを考慮する。後、xのほうは制限が厳しめ。
* コンストラクターDI: public/protectedメソッド向き。一般的にDIという場合これ。
* メソッドDI: privateメソッド向き。特定メソッドだけでしか使わない場合、あまり使わない場合。


grok.comにXアカウントでログインできる。その場合、多少Xアカウントを考慮したりする。が、設定でオフにもできる。
使用する外部クラスが複数ある場合、DIでその分指定する。あまりにも数が多い場合、DTOやデリゲートなど複数クラスを保有するクラスを作って、それを引数に渡す。あるいは、依存クラスが多すぎる場合、設計に問題がある。適切に分割した方がいい


Xアカウントでログインでいい気がする。
なお、メソッドDIにする場合、DI対象は引数の先頭の方に指定する。必須で省略不能だから。


===== 感想 =====
==== DB ====
https://grok.com/share/c2hhcmQtMw%3D%3D_abb58ded-75b5-470e-a6c3-586a53904071
[http://blog.tojiru.net/article/277021312.html PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note]


==== ChatGPT ====
DBアクセスのモデル化。行をクラスとする (entity/エンティティークラス) と扱いやすい模様。


===== Plan =====
getterを作ったり、データの妥当性のチェックなどもできる。
[https://openai.com/chatgpt/ ChatGPT | OpenAI]


Free/Plusの2のプランがある。
select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。
{| class="wikitable"
|+
!
!Free
!Plus
|-
|金額 [USD/月]
|0
|20
|-
|機能
|基本
|アーリーアクセス
|-
|エンジン
|GPT-4o mini
|GPT-4/GPT-4o/GPT-4o mini
|-
|制限
| -
|GPT-4oの5倍以上のメッセージ送信
|-
|その他
| -
|データ分析、ファイルアップロード、ビジョン、Webブラウジング
|-
|画像生成
| -
|DALL-E
|}
送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。


===== Account =====
データベース関係のデザインパターンがいくつかある。
公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。<blockquote>ChatGPTに会員登録する意味は何ですか?


* Active Record
* Data Mapper


ChatGPTに会員登録する主な利点はいくつかあります。
===== Active Record pattern =====


1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。
* [https://ja.wikipedia.org/wiki/Active_Record Active Record - Wikipedia]
* [https://www.techscore.com/tech/Ruby/Rails/other/designpattern/ デザインパターンから見たActive Record | TECHSCORE(テックスコア)]


2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。
テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。


3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。
シンプルだが、複雑な操作が苦手。


4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。
エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。


5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。
Ruby on Rails/Laravel+Eloquentなどで採用。


興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。
===== Data Mapper pattern =====
[https://gihyo.jp/dev/serial/01/ruby/0014 第14回 DataMapperの使い方 | gihyo.jp]


===== 方法 =====
テーブルのレコードをクラスにするのはARと共通。


====== 質問の分割 ======
ただし、DB操作用のクラスを用意してそちらでDB操作する。
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c


Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
その都合、1テーブルに2クラス必要。


A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。
User/UserMapperのような対応関係。


===== 感想 =====
2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。


====== 2024-11-14 Thu ======
===== JOIN =====
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。
Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。


例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。
基本はエンティティーのプロパティーに持たせる感じ。


[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]
<blockquote>datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?


getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。
`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。


こういう検索エンジンで検索しにくい質問で便利だなと思います。
以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。


検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
### 1. マッパークラスでの`JOIN`実装


大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。
`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。


個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。
```python


同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。
class UserMapper:


一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>
    def find_user_with_orders(self, user_id):


====== 2024-11-19 Tue ======
        sql = """
https://gnusocial.jp/notice/7867350<blockquote>[[/gnusocial.jp/group/28/id|!ai]] ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。


phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? [[/chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85|https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85]]
            SELECT * FROM users


私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。
            JOIN orders ON users.id = orders.user_id


この間、 [[/misskey-square.net/users/9g2o6eycu3|@yuriha]] に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?
            WHERE users.id = %s


対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。
        """


検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。
        results = self.db.execute(sql, (user_id,))


もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。
       


凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>
        user = User(results[0]['user_id'], results[0]['user_name'])


== Shell ==
        orders = [Order(row['order_id'], row['product_name'], user) for row in results]


=== 2 Shell Command Language ===
        user.orders = orders


==== 2.9 Shell Commands ====
        return user


===== 2.9.2 Pipelines =====
```
[https://pubs.opengroup.org/onlinepubs/9699919799.orig/utilities/V3_chap02.html#tag_18_09_02 Shell Command Language]


pipelineは|で区切られた1以上のコマンド群のこと。標準出力を次のコマンドに接続する。
この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。


パイプラインの書式は以下となる。
### 2. リポジトリでの集約
[!] <command1> [ | <command2> ...]
予約語の!がなければ、最後のコマンドの終了ステータスがpipeline全体のステータスになる。!があれば、ステータスの否定になる。つまり、0なら1、0超過なら0になる。


パイプラインだが、ifやtest以外のどこでも使える。
`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。


ただし、対話シェルだと!は履歴置換になることがあるので注意する。
```python


===== 2.9.4 Compound Commands =====
class UserRepository:
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]


====== Case Conditional Construct ======
    def __init__(self, user_mapper, order_mapper):
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


* 未マッチで終了ステータス0。
        self.user_mapper = user_mapper
* pattern部分: シェル展開が有効。他はglob。
* |でOR検索相当。
* 最後のパターンの;;は省略可能。if文のようにも使える。
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。


BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。
        self.order_mapper = order_mapper


=== ワイルドカード ===
    def get_user_with_orders(self, user_id):
ワイルドカードで.始まりのファイルをマッチさせたい。


以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
        user = self.user_mapper.find(user_id)
echo {.*,*}


=== BOM ===
        orders = self.order_mapper.find_by_user_id(user_id)
[https://stackoverflow.com/questions/3127436/adding-bom-to-utf-8-files unicode - Adding BOM to UTF-8 files - Stack Overflow]


ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。
        user.orders = orders
printf '\xEF\xBB\xBF' > with_bom.txt
上記コードでBOMを最初に書き込んで、後は追記する。


=== Command ===
        return user


==== awk ====
```</blockquote>UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]


===== 変数 =====
結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。


====== 特別 ======
クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。
* NF: 列数。列の全表示などで使う基本的で重要な変数。
 
* NR: 行番号。
方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。
 
==== Other ====


====== スコープ ======
===== 1対1-多対多 =====
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]
プログラミング言語でデータの関連付けをすることがある。


関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。
1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。


===== 文/statement =====
多対多の場合。これも配列。二次元配列で基本は0要素目など。
* actions
$array[][]
** if/else
** while/do...while/for
** break/continue
** delete
** next
** exit
* output
** print
** printf


===== 関数 =====
===== 1対多 =====
https://chatgpt.com/share/683faf08-f374-800b-ac40-b96b427d7365


====== 組込関数 ======
例えば、DBからデータを取得した場合など、1行のデータに複数列あって、列を特定したい場合、連想配列で、バリューをさらに連想配列にするのが普通。ただ、1:1ならただの連想配列でよかったのが、連想配列の配列になるのがイマイチ。
* Arithmetic
['row1' => ['col1' => 'value1', 'col2' => 'value2']]
** atan2
いくつか方法がある。
** cos
** sin
** exp
** log
** sqrt
** int
** rand
** srand
* String
** gsub
** index
** length
** match
** split
** sprintf
** sub
** substr
** tolower
** toupper
* I/O
** close
** getline
** system


print/printfは関数ではなく、statement/文扱い。
# ネスト連想配列。無難。
# 連想配列の代わりにオブジェクト。これができるならこれが素直。
# 連想配列の代わりにリスト。ただし、列の意味が分かりにくい。foreach ($map as $interface => [$property, $defaultClass])
# 値部分を意味のある文字列で使うところで分割とか。


===== ヘッダー出力、列別最大長さ出力。 =====
手短にしたいなら、3のリストになるかも。
<nowiki>awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv</nowiki>


===== CSV =====
==== レガシープロジェクトの立て直し ====
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002
# csvparser.awk


## Usage
1. 現状分析
# awk -f csvparser.awk data.csv


# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
(1) ソフトウェアの動作確認
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
 
function callback(row, len, fields,  col, field) {
現在の環境でアプリケーションを動作させる。
    for ( col = 1; col <= len; col++ ) {
 
        field = fields[col]
どの部分が機能していて、どこが問題かを確認する。
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
 
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
必要であればエラーログを確認する。
        print row ":" col " " field
 
    }
(2) 依存関係の調査
}
 
アプリケーションのライブラリやフレームワークのバージョンを調査。
 
サポートが終了しているもの、互換性が失われたものを特定。
 
(3) コードベースの状態評価


BEGIN { row = max_idx = 0 }
コードの品質 (可読性、設計、テストカバレッジ) を確認。
{
    idx = 0
    sub(/\r$/, "")
    while ($0 != "") {
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
            fields[++idx] = ""
        } else if (match($0, /^["]/)) {
            fields[++idx] = substr($0, 2)
            for (;;) {
                if (getline == 0) exit 1
                sub(/\r$/, "")
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
                gsub(/["]["]/, "\"")
                fields[idx] = fields[idx] "\n" $0
            }
            fields[idx] = fields[idx] "\n"
        } else {
            exit 1
        }
        field = substr($0, RSTART, RLENGTH)
        $0 = substr($0, RSTART + RLENGTH)
        lastcomma = sub(/,$/, "", field) > 0
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
        fields[idx] = fields[idx] field
    }
    if (lastcomma) fields[++idx] = ""
    while (idx < max_idx) delete fields[max_idx--]
    callback(++row, idx, fields)
    max_idx = idx
}


</syntaxhighlight>awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。
セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。
tail -c +4 data/101543.csv | awk -f csvparser.awk


==== xargs ====
2. 計画立案


===== About =====
(1) ゴール設定
[https://pubs.opengroup.org/onlinepubs/9699919799.orig/utilities/xargs.html xargs]


xargsは引数リストを構築して、コマンドを呼び出すコマンド。
具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。


標準入力から受け取った行を任意の場所に引数として配置して、後続のコマンドを実行する。並行実行とかもできる。
(2) 優先順位の決定


* -I replstr: 行のプレースホルダー文字列を定義。
どの機能を維持し、どの機能を削除または置き換えるか決定。
* -t: trace mode。実行したコマンドを標準エラー出力に出力する。


ls -A "$1" | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' |
ユーザーに直接影響を与える部分を優先。
    xargs -E "" -I {} -t mv "$1"/{} "$2"/{}


===== 複数コマンド実行 =====
(3) リスク評価とバックアップ
https://chatgpt.com/share/6811d6e4-3cdc-800b-946c-305f03df396d
echo "file1 file2 file3" | xargs -n 1 -I{} sh -c 'echo {}; ls -l {}'
sh -cでshの引数の文字列として構築する。こうしないと、内部の;がパースされてうまく解約されない。


=== Other ===
修正に伴うリスクを評価し、現行システムのバックアップを取得。


==== patch ====
3. 環境整備


===== 文字化け =====
(1) 開発環境のモダナイズ
https://chatgpt.com/share/685cd841-d368-800b-b950-0afc82ea31de


iconvで文字エンコーディングをパッチ適用先ファイルに合わせてから適用する。
ローカル環境やコンテナ (Docker) を用意してテストを容易にする。
iconv -f UTF-8 -t EUC-JP <<'EOF' | patch -p1
--- oldfile.php
+++ newfile.php
@@ -1,3 +1,4 @@
+// これは日本語コメントです
EOF


==== pager ====
CI/CD パイプラインの整備。


===== lessのオプション =====
(2) 依存関係の更新
[https://qiita.com/takc923/items/598a68c4684114ffb102 lessのおすすめオプション #Linux - Qiita]
export LESS="-iMR"


* -i: 検索時に大文字小文字無視。
サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。
* -m: 表示中の%のステータスバーへの表示。
* -M: 表示中の行数・ファイル名などのステータスバーへの表示。
* -R: ANSI Color Escape Sequenceの解釈。


==== 破損リンク ====
(3) セキュリティの確保
https://chatgpt.com/c/68088168-ac54-800b-b78e-e28743b81011
find path/to/scan -type l ! -exec test -e {} \; -exec rm {} \;
find path/to/scan -type l ! -exec test -e {} \; -print


==== binary ====
古いOSSの脆弱性を修正。
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]


バイナリーデータの読込はodコマンド。なければhexdump。
HTTPSの導入、認証強化、インプット検証など。


書込はprintf。
4. コードのモダナイズ


head/tailの-cはPOSIXで使えたか?
(1) リファクタリング


==== root ====
レガシーコードをよりモダンで可読性の高いコードに変換。


===== リダイレクト出力 =====
デザインパターンを適用して保守性を向上。
[https://blog.shaba.dev/posts/redirect-with-sudo sudo権限でリダイレクト処理を行ってファイルに書き込む方法]


リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。
(2) テストの追加


teeコマンドでやる。
ユニットテスト、統合テストを導入。
pwd | sudo tee out.dat
teeコマンド実行する側でsudoが必要。


既存の機能が壊れないことを確認するための自動化されたテスト。
==== ログインシェルの確認 ====
[https://docs.oracle.com/cd/E19683-01/816-3946/customize-89075/index.html 第 10 章 動作環境のカスタマイズ (Solaris ユーザ]
ログインシェルはGUIログインでも内部的にある。ログインシェルが読みこむprofileファイルなどは、ログイン時に、1回だけ実行したい処理の記述場所として最適。
SHELL環境変数にログインシェルのパスが入っている。
echo $SHELL
/bin/bash
==== OSの判別 ====
OSTYPE環境変数に値があるのでこれで判別する。
例えば以下の値が入っている。
linux-gnu
darwin23
これらを検知して判定する。
case $OSTYPE in
  linux*) echo 'linux';;
  darwin*) echo 'Mac';;
esac
==== Configure ====
===== profile =====
[https://blog1.mammb.com/entry/2019/12/01/090000 bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針 - A Memorandum]


# bash_profile
(3) フロントエンド/バックエンドの分離
## profile
## bashrc


環境変数など~/.profileに全部のシェルの共通設定を記述。
必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。


上記サイトではこういう方針でやっていた。
5. 機能拡張とデプロイ


ログイン時に、bash_profileとかzprofileとかがなければ、デフォルトで.profileを読込むようになっている。
(1) 新しい機能の追加


なので、.profile内で、実行シェルを変数で判定して、bashrcやzshrcを読み込むようにするといい。
必要に応じて、現代のニーズに合った新機能を実装。


上から下にする感じ。ubuntu 22.04のprofileがこういう作りになっている。
(2) 運用環境でのテスト
# if running bash, include .bashrc if it exists
[ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"
.profileはログイン時に1回だけ実行すればいいから。


===== rc =====
新しい環境で徹底的にテストし、問題がないことを確認。
rc=run configuration. 実行設定。


シェルごとにいくつかの設定がある。
(3) 本番環境にデプロイ


====== Bash ======
ロールバック計画を準備しつつ、安全にデプロイ。
[https://manpages.ubuntu.com/manpages/focal/en/man1/bash.1.html Ubuntu Manpage: bash - GNU Bourne-Again SHell]


--loginオプションの指定がある場合や、ログイン対話シェルとして呼び出されるかどうかで変わる。、
6. 継続的改善


ログイン対話シェルの場合 (SSHも含む?)
(1) モニタリングの導入


* /etc/profile があれば実行。
エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。
* ~/.bash_profile ~/.bash_login ~/.profile をこの順番で探して、最初に見つけたファイルを実行して終わる。
* シェル終了時か、非対話ログインシェルの場合、exitコマンド実行時に、~/.bash_logoutをあれば実行。


--noprofileオプションを指定した場合、上記の読み込みはしない。
(2) 定期的なアップデート


非ログイン対話シェルの場合。
フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。


* /et/bash.bashrc ~/.bashrcがあればそれぞれ実行。
(3) コミュニティへの貢献


--norcの指定で上記も読み込まない。--rcfileで/etc/bash.bashrcと~/.bashrcの代わりのrcファイルを指定できる。
OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。


非対話シェルの場合、BASH_ENV環境変数を展開して、そのファイルを読み込む。
このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。
  if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
~/.profileをスクリプト実行時にも読み込みたい場合、bash_profileでこの環境変数を設定しておくとよいかも。


== cmd.exe ==
== AI ==


=== Control block ===
=== 対話AI ===


==== for ====
==== About ====
あくまでコマンド。


===== nest =====
===== List =====
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]
いろいろある。
 
{| class="wikitable"
* [https://web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/ web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/]
|+
 
!Name
ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。
!
 
!
=== bitsadmin ===
!
Windowsでのファイルダウンロードコマンド
|-
 
|Bing
Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。
|
 
|
書式:
|
bitsadmin /transfer <job name> <URL> <output path>
|-
<job name>と<output path>は必須なので注意する。
|Perplexity AI
|
|
|
|-
|ChatGPT
|
|
|
|-
|Google Gemini
|
|
|
|}


=== certutil ===
===== 書きかけ送信 =====
Windowsでのハッシュの確認に使える。
https://grok.com/share/c2hhcmQtMw%3D%3D_ca8dab5f-1012-4dd4-841f-7340186071d7
certutil -hashfile file


SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
書きかけの状態で誤送信することがある。
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。


=== rlogin.cmd ===
元の質問を編集するのではなく、続きに「これが正しいです」とか書いて送信すると、AIが認知して対応してくれるらしい。
コマンドキーの送信を自動化できる?
rem rlogin.cmd
@Echo off
Set SERVER=192.168.0.0
Set USERNAME=
Set PASSWORD=
Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 5
Cmdkey /delete:TERMSRV/%SERVER%


=== 実行中プロセスのパスの確認 ===
編集すると、ややこしくなる。
出典: [https://superuser.com/questions/768984/show-exe-file-path-of-running-processes-on-the-command-line-in-windows Show EXE file path of running processes on the command-line in Windows - Super User]。
wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST


=== 簡易編集モード/挿入モード ===
==== Grok ====


* [https://softantenna.com/blog/windows-10-command-prompt-no-stop/ 【Tips】Windows 10のコマンドプロンプトが意図せず止まってしまう問題を回避する方法 | ソフトアンテナ]
===== Xアカウント =====
* [https://superuser.com/questions/419717/windows-command-prompt-freezing-randomly Windows command prompt freezing randomly - Super User]
https://x.com/i/grok/share/oeybkVEqzC4NNpH8whCdM7pl7


Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。
grok.comのgrokはスタンドアローン。x.com/i/grokはXアカウントを考慮する。後、xのほうは制限が厳しめ。


cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。
grok.comにXアカウントでログインできる。その場合、多少Xアカウントを考慮したりする。が、設定でオフにもできる。


そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。
Xアカウントでログインでいい気がする。


[□挿入モード] にすると回避できる模様。
===== 感想 =====
https://grok.com/share/c2hhcmQtMw%3D%3D_abb58ded-75b5-470e-a6c3-586a53904071


== Web ==
==== ChatGPT ====


=== URL ===
===== Plan =====
[https://openai.com/chatgpt/ ChatGPT | OpenAI]


==== クエリー配列 ====
Free/Plusの2のプランがある。
 
{| class="wikitable"
* [https://shinkufencer.hateblo.jp/entry/2019/05/18/163912 クエリストリングで配列を表現をするケースをざっと調べる - コード日進月歩]
|+
* [https://qiita.com/s4kd0R/items/8a11d88099008bb1e9dc PHPでクエリパラメータから配列を受け取る物語 #JavaScript - Qiita]
!
* [https://www.php.net/http_build_query PHP: http_build_query - Manual]
!Free
 
!Plus
やり方がいくつかある。
|-
 
|金額 [USD/]
# CSV文字列で受取後分割: <nowiki>https://www.sakdor.net/test/?var=1,2,3</nowiki> explode(",",$_GET[var]);
|0
# 配列添字
|20
## http://www.sakdor.net/test/?var&#x5B;&#x5D;=1&var&#x5B;&#x5D;=2&var&#x5B;&#x5D;=3
|-
## http://www.sakdor.net/test/?var&#x5B;a&#x5D;=1&var&#x5B;b&#x5D;=2&var&#x5B;c&#x5D;=3
|機能
## http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3
|基本
 
|アーリーアクセス
データが決まっているならcsvがシンプル。
|-
 
|エンジン
==== CGI ====
|GPT-4o mini
https://chatgpt.com/c/67634332-a3b8-800b-87a2-e21bd21a1cfc
|GPT-4/GPT-4o/GPT-4o mini
 
|-
WordPressなどのWebアプリだとファイル拡張子が登場しない。これはいくつかの仕組みが組み合わさって実現されている。
|制限
 
| -
# '''パーマリンク設定''' によるクリーンなURL構造の生成。
|GPT-4oの5倍以上のメッセージ送信
# '''.htaccess(Apache)''' や '''リライトルール''' によるURLの書き換えとルーティング。
|-
# '''index.php''' を起点とする動的な処理。
|その他
# '''テンプレート階層''' に従って適切なPHPファイルを呼び出す。
| -
|データ分析、ファイルアップロード、ビジョン、Webブラウジング
|-
|画像生成
| -
|DALL-E
|}
送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。


.htaccessでindex.phpにリダイレクトして、index.phpから全て処理している。これにより省略できている。
===== Account =====
公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。<blockquote>ChatGPTに会員登録する意味は何ですか?


同じ用に、アプリ側が対応していれば、index.fcgiに全部リダイレクトして、パスを解釈してくれるなら、/でのアクセスもできる気がする。


[https://stackoverflow.com/questions/36405496/how-can-i-run-a-fastcgi-script-in-root-url-without-path apache - How can I run a FastCGI script in root url (/ - without path)? - Stack Overflow]
ChatGPTに会員登録する主な利点はいくつかあります。


==== スペースの扱い ====
1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。
https://grok.com/share/c2hhcmQtMw%3D%3D_9c2c3143-b190-42f7-a985-20444806187e


URLは、RFC3986に従って、特殊文字のエンコードが必要。スペースは特殊文字。
2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。


%20がスペースのエンコーディングだが、+はURLクエリーパラメーター (?key=value) 内のスペース表現で登場することがある。ただ、+はクエリーパラメーター以外の文脈ではスペースとして認知されない。%2Bはスペース時代の%エンコード。
3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。


基本的に、URLクエリーパラメーターに指定する場合、JavaScriptの場合encodeURIComponent (PHP urlencode=クエリー用、rawurlencode=パス用) でエンコードする。これで、スペースや+が適切にエンコードされる。
4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。


ただ、HTMLフォームでgetを使用する場合、Webブラウザーが自動的にクエリーパラメーターをapplication/x-www-form-urlencoded形式にするので、スペースが+になる。
5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。


=== HTTP ===
興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。
[https://www.rfc-editor.org/rfc/rfc9110.html RFC 9110: HTTP Semantics]


==== Content-Disposition ====
===== 方法 =====
[https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Disposition Content-Disposition - HTTP | MDN]


[https://datatracker.ietf.org/doc/html/rfc6266 RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)]
====== 質問の分割 ======
Content-Disposition: inline
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。


==== multipart/form-data ====
Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
rfc7578


* [https://datatracker.ietf.org/doc/html/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data]
A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。
* [https://qiita.com/sivertigo/items/14957200af5ad953d63b Multipart/form-dataの仕様メモ #HTTP - Qiita]


ファイルアップロード用のMIME type。
===== 感想 =====


リクエストヘッダー
====== 2024-11-14 Thu ======
Content-Type: multipart/form-data; boundary=--hogehoge
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。
リクエストボディー
--hogehoge
Content-Disposition: form-data; name="user_name"
Content-Type: text/plain
test
--hogehoge
Content-Disposition: form-data; name="email"
sample@mail.com
--hogehoge
Content-Disposition: form-data; name="gender"
male
--hogehoge
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
Content-Type: image/jpeg
\xff\xd8\....
--hogehoge--
ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。


[https://weblabo.oscasierra.net/curl-post/ curlコマンドでPOSTする, 様々な形式別メモ |]
例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。


curlでの送信理由。
[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]


-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。
getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。
curl -X POST -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
データとテキストを同時送信したい場合、-Fで複数指定する。
curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
curlだと上記のboundaryなどをうまくやってくれるのだと思う。


リクエストボディー全体をファイルデータにする場合。
こういう検索エンジンで検索しにくい質問で便利だなと思います。
curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>


=== IP address ===
検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
出典: [https://glocalnet.jp/vpn/topix/archives/67#:~:text=%EF%BC%94%EF%BC%8E%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%20%E5%8F%96%E5%BE%97%E6%96%B9%E6%B3%95%E3%81%AF%E4%B8%BB%E3%81%AB3%E3%81%A4%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82,%E3%83%BB%E5%A5%91%E7%B4%84%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E3%83%97%E3%83%AD%E3%83%90%E3%82%A4%E3%83%80%E3%81%A7%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%A8%E3%81%97%E3%81%A6%E7%94%B3%E3%81%97%E8%BE%BC%E3%82%80%E6%96%B9%E6%B3%95%20%E3%83%BB%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8BSIM%E3%82%92%E5%A5%91%E7%B4%84%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%20%E3%83%BBVPN%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%9F%E5%9B%BA%E5%AE%9AIP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%81%AE%E6%8F%90%E4%BE%9B%E4%BC%9A%E7%A4%BE%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット]。


自宅サーバーを行う際、固定IPアドレスが必要になる。
大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。


取得方法がいくつかある。
個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。


* 契約しているプロバイダでオプションとして申し込む方法
同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。
* 固定IPアドレスに対応しているSIMを契約する方法
* '''VPNを利用した固定IPアドレスの提供会社を利用する方法'''


VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。
一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>


=== Authentication ===
====== 2024-11-19 Tue ======
認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。
https://gnusocial.jp/notice/7867350<blockquote>[[/gnusocial.jp/group/28/id|!ai]] ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。


==== Basic認証 ====
phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? [[/chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85|https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85]]
出典: [https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC Basic認証 - Wikipedia]


Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。
私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。
GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA{{=}}{{=}}
盗聴や改ざんが簡単だが、シンプルという利点がある。


[https://dev.classmethod.jp/articles/delete-cache-for-basic-authentication/ Basic認証のキャッシュを削除する(ログアウトする) | DevelopersIO]
この間、 [[/misskey-square.net/users/9g2o6eycu3|@yuriha]] に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?


ログアウト時は、hoge@domainのようにパスワードを省略した任意のユーザー名でログインを試みて既存のログイン状況を上書きする模様。
対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。


Digest認証も共通。
検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。


==== Digest認証 ====
もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。
[https://qiita.com/Threen/items/409971705767e2f89fb2 Basic認証・Digest認証・Form認証をざっくり理解 #Security - Qiita]


HTTP標準の認証。Basic認証とほぼ同じ。ただし、パスワードをハッシュ化している。そのため、DBのパスワードが流出した場合に比較的安全。
凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>


==== OAuth ====
=== AI Coding ===
Ref
[https://techblog.lycorp.co.jp/ja/20250626a AIコーディング:「Vibe Coding」からプロフェッショナルへ]


* [https://ja.wikipedia.org/wiki/OAuth OAuth - Wikipedia]
[https://zenn.dev/yoshiko/articles/my-vibe-coding 個人的 Vibe Coding のやりかた]


OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。
雰囲気だけを伝えて、AIにアプリ開発を任せる手法。一切自分でコーディングしなくてもアプリ開発可能。


以下が登場人物。
== Shell ==


* resource owner: あるサイトのユーザー。
=== 2 Shell Command Language ===
* resource server: あるサイトのユーザーのデータの保有サーバー。
* clent: クライアントアプリ。リソースサーバーのデータを使用したい。
* authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。


アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。
==== 2.9 Shell Commands ====


処理の流れ。
===== 2.9.2 Pipelines =====
[https://pubs.opengroup.org/onlinepubs/9699919799.orig/utilities/V3_chap02.html#tag_18_09_02 Shell Command Language]


# client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
pipelineは|で区切られた1以上のコマンド群のこと。標準出力を次のコマンドに接続する。
# client<-resource owner: Authorization Grant。
# client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
# client<-authorization server: Access Token
# client->resource server: Access Token。アクセストークンでアクセス。
# client<-resource server: Access Token


Consumer Key/Secret: アプリ識別用のID/PW。
パイプラインの書式は以下となる。
[!] <command1> [ | <command2> ...]
予約語の!がなければ、最後のコマンドの終了ステータスがpipeline全体のステータスになる。!があれば、ステータスの否定になる。つまり、0なら1、0超過なら0になる。


Access Token: サイトにアクセスするためのパスワード。
パイプラインだが、ifやtest以外のどこでも使える。


=== API ===
ただし、対話シェルだと!は履歴置換になることがあるので注意する。


==== Routing ====
===== 2.9.4 Compound Commands =====
Webアプリを新しく作る際の画面構成。基本的にRoutingと一致のこと。
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]


1機能1ルートみたいな感じ。あとはCRUDに対応したルート。オブジェクト指向になっているとなお良い。
====== Case Conditional Construct ======
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


* /register
* 未マッチで終了ステータス0。
* /login
* pattern部分: シェル展開が有効。他はglob。
* /logout
* |でOR検索相当。
* /users
* 最後のパターンの;;は省略可能。if文のようにも使える。
* /users/books/
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。
* /my/books/
* /books
* /books/new
* /books/:id


CSR形式のアプリの場合、サーバー側には/api/を前置したルートを用意して、そちらにGET/POSTで必要なデータ処理する感じ。
BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。


==== 複数レコードの登録 ====
=== ワイルドカード ===
[https://buddypia.com/2021/11/14/%E8%A4%87%E6%95%B0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89api%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E8%AA%BF%E3%81%B9%E3%81%A6%E3%81%BF%E3%81%9F%E8%A9%B1/ 複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ]
ワイルドカードで.始まりのファイルをマッチさせたい。


既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?
以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
echo {.*,*}


[https://www.yamarkz.com/blog/rest-web-api-practice REST WebAPIのプラクティス | yamarkz.com]
=== BOM ===
[https://stackoverflow.com/questions/3127436/adding-bom-to-utf-8-files unicode - Adding BOM to UTF-8 files - Stack Overflow]


delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。
ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。
printf '\xEF\xBB\xBF' > with_bom.txt
上記コードでBOMを最初に書き込んで、後は追記する。


==== パラメーター ====
=== Command ===
[https://stackoverflow.com/questions/25385559/rest-api-best-practices-args-in-query-string-vs-in-request-body json - REST API Best practices: args in query string vs in request body - Stack Overflow]


パラメーターの指定に3種類ある。
==== awk ====
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]


# リクエストボディー
===== 変数 =====
# クエリー
# パス


パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。
====== 特別 ======
* NF: 列数。列の全表示などで使う基本的で重要な変数。
* NR: 行番号。


ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。
====== スコープ ======
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]


この原則に従うとシンプルだろう。
関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。


* URIには長さの制限がある。
===== 文/statement =====
* ボディー
* actions
** 引数が非常に多い場合。
** if/else
** 画像などバイナリーデータ。
** while/do...while/for
** キー・値構造を持たない場合。
** break/continue
* クエリー文字列
** delete
** 引数を簡単に確認できる。
** next
** 共通の引数の場合。
** exit
 
* output
==== 検索機能のGET/POST ====
** print
 
** printf
* [https://stackoverflow.com/questions/20550514/post-or-get-in-a-search-form .net - POST or GET in a search form? - Stack Overflow]
 
検索機能にGETとPOSTのどちらを使うか?という議論がある。


データ登録するわけなじゃないのだから、GETがいいんじゃない?
===== 関数 =====


POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。
====== 組込関数 ======
* Arithmetic
** atan2
** cos
** sin
** exp
** log
** sqrt
** int
** rand
** srand
* String
** gsub
** index
** length
** match
** split
** sprintf
** sub
** substr
** tolower
** toupper
* I/O
** close
** getline
** system


GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。
print/printfは関数ではなく、statement/文扱い。


ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。
===== ヘッダー出力、列別最大長さ出力。 =====
<nowiki>awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv</nowiki>


==== レート制限対策 ====
===== CSV =====
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
# csvparser.awk


* [https://pikodon.com/note/php/api-cache/ APIの利用制限対策 | Web開発ノート]
## Usage
* [https://keirinomikata.zendesk.com/hc/ja/articles/4404549985945-%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E6%95%B0%E3%81%AB%E3%82%88%E3%82%8B%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E5%88%B6%E9%99%90%E3%81%AE%E5%AF%BE%E7%AD%96%E6%96%B9%E6%B3%95 リクエスト数によるアクセス制限の対策方法 – 請求管理ロボ ヘルプ]
# awk -f csvparser.awk data.csv


いろいろ方法がある。
# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
function callback(row, len, fields,  col, field) {
    for ( col = 1; col <= len; col++ ) {
        field = fields[col]
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
        print row ":" col " " field
    }
}


* cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
BEGIN { row = max_idx = 0 }
* 配列を利用して、1回のリクエストでまとめて取得する。
{
* インターバルを設ける。
    idx = 0
* HTTP 429/413を検知して、リトライする。
    sub(/\r$/, "")
 
    while ($0 != "") {
==== 指数関数的バックオフ ====
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
 
            fields[++idx] = ""
* [https://docs.link.getmoneytree.com/docs/faq-rate-limiting APIレート制限は何か、どのように対処するのか?]
        } else if (match($0, /^["]/)) {
* [[wikipedia:Exponential_backoff|Exponential backoff - Wikipedia]]
            fields[++idx] = substr($0, 2)
* [https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=ja 指数バックオフ  |  Memorystore for Redis  |  Google Cloud]
            for (;;) {
* [https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html バックオフパターンで再試行 - AWS 規範ガイダンス]リトライ時は以下のアルゴリズムがいいらしい。
                if (getline == 0) exit 1
wait_interval = base * 2^n +/- jitter
                sub(/\r$/, "")
 
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
* <code>wait_interval</code> は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
                gsub(/["]["]/, "\"")
* <code>base</code> は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
                fields[idx] = fields[idx] "\n" $0
* <code>n</code> は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、<code>n</code>の値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
            }
* <code>jitter</code> は 0 から <code>base</code> の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し <code>wait_interval</code> の合計に加算するか減算するか、ランダムで選択してください。
            fields[idx] = fields[idx] "\n"
 
        } else {
==== 再送とリロード ====
            exit 1
<nowiki>https://chatgpt.com/c/67e25ec2-26bc-800b-acd9-0aa197476788</nowiki>
        }
 
        field = substr($0, RSTART, RLENGTH)
POSTなどデータ登録系のAPI呼び出しした際、そのままリロードすると、同じ登録処理が再送されてしまう。特に、URLクエリーで登録パラメーターを渡す場合など。
        $0 = substr($0, RSTART + RLENGTH)
 
        lastcomma = sub(/,$/, "", field) > 0
更新後に、リダイレクトでパラメーターを消す。これだと安全でシンプル。
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
 
        fields[idx] = fields[idx] field
あるいは、登録に使ったデータで、表示もする。ただ、処理失敗時や、キャッシュDBとの整合性がややこしいことがある。
    }
 
    if (lastcomma) fields[++idx] = ""
https://grok.com/share/c2hhcmQtMw%3D%3D_6cd6ea6f-48b8-402a-9401-7edda0fded18
    while (idx < max_idx) delete fields[max_idx--]
 
    callback(++row, idx, fields)
二重送信の対策がいろいろある。JavaScriptに依存しない方式。
    max_idx = idx
 
}
# PRGパターン: フォーム送信後、サーバー側での処理完了後にリダイレクト (Post/Redirect/Getパターン)。これにより更新ボタン誤操作による再送信を防止。特に、URLクエリーで登録パラメーターを渡す場合などに有効。
# フォームトークンによる一意性確保: フォーム送信時に一意のトークンを発行し、サーバー側でトークンを検証、処理後に無効化または再生成。同一トークンは拒否。
# サーバー側でのリクエスト制限: 同一ユーザー・セッションからのリクエスト頻度を制限。セッションやDBに最後の送信時刻を記録。
 
1+2がシンプルで効果的とのこと。スパムが懸念される場合に、リクエスト制限を追加。
 
javascript前提でいいなら、submitで実装。


==== API Serverの認証 ====
</syntaxhighlight>awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。
https://grok.com/share/c2hhcmQtMw%3D%3D_3f170c15-108d-44a3-bcc9-c4bfe545c9e9
tail -c +4 data/101543.csv | awk -f csvparser.awk


APIサーバーでは、OAuthのような認証手順を一般的にとる。つまり、最初にトークンを発行する。
==== xargs ====
 
==== Swagger ====


===== About =====
===== About =====
[https://swagger.io/ API Documentation & Design Tools for Teams | Swagger]
[https://pubs.opengroup.org/onlinepubs/9699919799.orig/utilities/xargs.html xargs]


[https://tech.nri-net.com/entry/simple_explanation_of_swagger 【初心者向け】Swaggerとは?シンプルに解説 - NRIネットコムBlog]
xargsは引数リストを構築して、コマンドを呼び出すコマンド。


API管理のためのツールセット。OpenAPI (旧Swagger API) というAPIの文書化の仕様に準拠したAPI文書の作成ツール。
標準入力から受け取った行を任意の場所に引数として配置して、後続のコマンドを実行する。並行実行とかもできる。


具体的には以下の3ツールがある ([https://swagger.io/docs/ Swagger Documentation | Swagger Docs])。
* -I replstr: 行のプレースホルダー文字列を定義。
* -t: trace mode。実行したコマンドを標準エラー出力に出力する。


* Swagger Editor: API文書作成のエディター。YAMLかJSON形式でAPIを記述する。
ls -A "$1" | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' |
* Swagger UI: APIを対話的に操作可能なエディター。Swagger Editorの生成結果的なもの。
    xargs -E "" -I {} -t mv "$1"/{} "$2"/{}
* Swagger CodeGen: 複数のプログラミング言語向けにクライアントやサーバーコードの自動生成ツール。


APIは外部から呼び出しに使われる都合、重要。正確で一貫性のある設計が求められる。
===== 複数コマンド実行 =====
https://chatgpt.com/share/6811d6e4-3cdc-800b-946c-305f03df396d
echo "file1 file2 file3" | xargs -n 1 -I{} sh -c 'echo {}; ls -l {}'
sh -cでshの引数の文字列として構築する。こうしないと、内部の;がパースされてうまく解約されない。


* API設計を統一的な形式で記述でき、開発者間での形式のずれや誤解・不一致を防ぎ、一貫性のあるAPI開発が可能。
=== Other ===
* API文書を自動生成できる。


===== Install =====
==== patch ====
[[https://editor.swagger.io/ Swagger Editor]] のオンラインエディターで始めるのが手っ取り早い。他に、VSCodeの拡張機能で記述する方法もある。


VSCodeだとswaggerで検索してヒットする [OpenAPI (Swagger) Editor] とか。
===== 文字化け =====
https://chatgpt.com/share/685cd841-d368-800b-b950-0afc82ea31de


[https://qiita.com/YoshijiGates/items/413be433c0ba33e8ef3a Visual Studio CodeでOpenAPI(Swagger) Editorを使用する #VSCode - Qiita]
iconvで文字エンコーディングをパッチ適用先ファイルに合わせてから適用する。
iconv -f UTF-8 -t EUC-JP <<'EOF' | patch -p1
--- oldfile.php
+++ newfile.php
@@ -1,3 +1,4 @@
+// これは日本語コメントです
EOF


[Alt-P] (> OpenAPI SwaggerUI preview) でプレビュー表示できる。
==== pager ====


===== OpenAPI =====
===== lessのオプション =====
[https://qiita.com/takc923/items/598a68c4684114ffb102 lessのおすすめオプション #Linux - Qiita]
export LESS="-iMR"


====== About ======
* -i: 検索時に大文字小文字無視。
* -m: 表示中の%のステータスバーへの表示。
* -M: 表示中の行数・ファイル名などのステータスバーへの表示。
* -R: ANSI Color Escape Sequenceの解釈。


* [https://qiita.com/yuya_sega/items/0b87e8e7d494f6fa3d69 今日から始めるswagger入門(最低限書けるようになる) #初心者 - Qiita]
==== 破損リンク ====
* [https://swagger.io/docs/specification/v3_0/basic-structure/ Basic Structure | Swagger Docs]
https://chatgpt.com/c/68088168-ac54-800b-b78e-e28743b81011
<syntaxhighlight lang="yaml">
find path/to/scan -type l ! -exec test -e {} \; -exec rm {} \;
aaaa
find path/to/scan -type l ! -exec test -e {} \; -print


==== binary ====
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]


</syntaxhighlight>以下が基本構成。
バイナリーデータの読込はodコマンド。なければhexdump。
openapi: 3.0.4
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](<nowiki>http://commonmark.org/help/</nowiki>) or HTML.
  version: 0.1.9
servers:
  - url: <nowiki>http://api.example.com/v1</nowiki>
    description: Optional server description, e.g. Main (production) server
  - url: <nowiki>http://staging-api.example.com</nowiki>
    description: Optional server description, e.g. Internal staging server for testing
paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML.
      parameters: # リクエストパラメータ 省略可能。
      - name: test
        in: query
        schema:
          type: string
      responses:
        "200": # status code
          description: A JSON array of user names
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
pathsの中に、APIパスとHTTPメソッドと応答の記載が基本。


====== responses.content ======
書込はprintf。
responses.content以下にmimeType別に応答を書く。同じapiでも複数のmime typeを許容できるからだろう。ただ、実際はapplication/jsonだけのことが多い。


schema以下で応答の種類を書く。基本は以下のどちらかだろう。
head/tailの-cはPOSIXで使えたか?
              schema:
                type: array
                items:
                  type: string
# ["string"]


              schema:
==== root ====
                type: object
                properties:
                  data:
                    type: string
# {data: "string"}


====== リクエストパラメーター ======
===== リダイレクト出力 =====
parameters、requestBodyにリクエストパラメーターを記載。
[https://blog.shaba.dev/posts/redirect-with-sudo sudo権限でリダイレクト処理を行ってファイルに書き込む方法]
# クエリーパラメータ
  /tests:
    get:
      summary: テストAPI(一覧)
      parameters:
      - name: data
        in: query
        schema:
          type: string


  /tests:
リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。
    post:
      summary: テスト登録API
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string


====== Components Section ======
teeコマンドでやる。
pwd | sudo tee out.dat
teeコマンド実行する側でsudoが必要。


* [https://swagger.io/docs/specification/v3_0/components/ Components Section | Swagger Docs]
* [https://qiita.com/maooz4426/items/ccbd7d239f8f8b35843a swaggerでAPIの仕様書を書こう! #初心者 - Qiita]
==== ログインシェルの確認 ====
* [https://qiita.com/teinen_qiita/items/e440ca7b1b52ec918f1b OpenAPI (Swagger) 超入門 #REST-API - Qiita]
[https://docs.oracle.com/cd/E19683-01/816-3946/customize-89075/index.html 第 10 章 動作環境のカスタマイズ (Solaris ユーザ]
* [https://qiita.com/yuya_sega/items/508d623b32fb5faa52e3 現場で必要になるswaggerの知識 #初心者 - Qiita]
ログインシェルはGUIログインでも内部的にある。ログインシェルが読みこむprofileファイルなどは、ログイン時に、1回だけ実行したい処理の記述場所として最適。
SHELL環境変数にログインシェルのパスが入っている。
echo $SHELL
/bin/bash
==== OSの判別 ====
OSTYPE環境変数に値があるのでこれで判別する。
例えば以下の値が入っている。
linux-gnu
darwin23
これらを検知して判定する。
case $OSTYPE in
  linux*) echo 'linux';;
  darwin*) echo 'Mac';;
esac
==== Configure ====
===== profile =====
[https://blog1.mammb.com/entry/2019/12/01/090000 bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針 - A Memorandum]


Swaggerを使うことのかなり大きな利点。Components。
# bash_profile
## profile
## bashrc


APIは、APIのルートパスのオブジェクトを返したり、受け付けたりする。パスごとにこれを何回も書くことになる。SwaggerではこれをComponentとして定義しておいて、その参照で記述を省略できる。
環境変数など~/.profileに全部のシェルの共通設定を記述。
components:
  schemas:
    object名:
      type: object
      properties:
        プロパティ1:
          type: string
          format: string
          description: "プロパティ1の説明"
          example: "プロパティ1の例"
        プロパティ2:
          type: string
          format: string
          description: "プロパティ2の説明"
          example: "プロパティ2の例"
      required:
        - プロパティ1
        - プロパティ2


content:
上記サイトではこういう方針でやっていた。
  application/json:
    schema:
      $ref: '#/components/schemas/object名'
こんな感じで参照して流用できる。


====== Using $ref ======
ログイン時に、bash_profileとかzprofileとかがなければ、デフォルトで.profileを読込むようになっている。
[https://swagger.io/docs/specification/v3_0/using-ref/ Using $ref | Swagger Docs]


APIの文書作成時に、リソースを複数で参照したいことがある。OpenAPI 3.0で相互参照機能が導入された。
なので、.profile内で、実行シェルを変数で判定して、bashrcやzshrcを読み込むようにするといい。


$refキーワードを使う。
上から下にする感じ。ubuntu 22.04のprofileがこういう作りになっている。
  components:
  # if running bash, include .bashrc if it exists
  schemas:
[ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"
    User:
.profileはログイン時に1回だけ実行すればいいから。
      properties:
        id:
          type: integer
        name:
          type: string


responses:
===== rc =====
  "200":
rc=run configuration. 実行設定。
    description: The response
    schema:
      $ref: "#/components/schemas/User"
定義と参照を上記のように行う。


$refはJSON Reference気泡になっている。先頭の#はファイル内参照を意味する。
シェルごとにいくつかの設定がある。


$ref: 'document.json#/myElement' のように記載することで、別のファイル内のコンポーネントを参照できる。
====== Bash ======
[https://manpages.ubuntu.com/manpages/focal/en/man1/bash.1.html Ubuntu Manpage: bash - GNU Bourne-Again SHell]


=== Network ===
--loginオプションの指定がある場合や、ログイン対話シェルとして呼び出されるかどうかで変わる。、


==== 環境変数 ====
ログイン対話シェルの場合 (SSHも含む?)。
https://grok.com/share/c2hhcmQtMw%3D%3D_1fce8739-56a3-47a5-8a8c-55d209a0b37b


ネットワーク関係のツールは、いくつか共通の環境変数を参照する。curlで定義されている環境変数を流用して参照していることが多い。
* /etc/profile があれば実行。
* ~/.bash_profile ~/.bash_login ~/.profile をこの順番で探して、最初に見つけたファイルを実行して終わる。
* シェル終了時か、非対話ログインシェルの場合、exitコマンド実行時に、~/.bash_logoutをあれば実行。


* poxy関係: http_proxy/https_proxy/no_proxyは重要
--noprofileオプションを指定した場合、上記の読み込みはしない。
** http_proxy
** htttps_proxy
** no_proxy
** ftp_proxy
** all_proxy
** RSYNC_PROXY


内部リクエスト時には、proxy設定があると、プロキシーサーバーにリクエストに行って不都合起きることがあるので注意する。
非ログイン対話シェルの場合。


==== ssh ====
* /et/bash.bashrc ~/.bashrcがあればそれぞれ実行。


===== ssh-addの自動登録 =====
--norcの指定で上記も読み込まない。--rcfileで/etc/bash.bashrcと~/.bashrcの代わりのrcファイルを指定できる。
ssh agentに秘密鍵の登録は以下のコマンド。
ssh-add <秘密鍵のpath>
ただし、上記コマンドは再起動すると登録が消えるので毎回必要。


~/.ssh/configに以下の内容を記入しておくと、次回からkeychainから自動で読み込まれるらしい ([https://qiita.com/sonots/items/a6dec06f95fca4757d4a macOS で再起動しても ssh agent に秘密鍵を保持させ続ける二つの方法 #SSH - Qiita])。
非対話シェルの場合、BASH_ENV環境変数を展開して、そのファイルを読み込む。
Host *
  if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
  UseKeychain yes
~/.profileをスクリプト実行時にも読み込みたい場合、bash_profileでこの環境変数を設定しておくとよいかも。
  AddKeysToAgent yes
うまくいかなかった。


[https://aifan.jp/2022/01/25/ssh-add%E3%82%92pc%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E5%BA%A6%E3%81%AB%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E5%AE%9F%E8%A1%8C%E3%81%95%E3%81%9B%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%AD%E5%AE%9A/ ssh-addをPC起動する度に自動的に実行させるための設定 | AIFAN]
== cmd.exe ==


id_rsaの場合はIdentityFileを省略できるが、それ以外は指定が必要な模様。
=== Control block ===
Host *
  UseKeychain yes
  AddKeysToAgent yes
  IdentityFile ~/.ssh/id_ed25519


===== ssh経由でのリダイレクト出力 =====
==== for ====
[https://superuser.com/questions/400714/how-to-remotely-write-to-a-file-using-ssh bash - How to remotely write to a file using SSH - Super User]
あくまでコマンド。


ssh経由で標準入力内容からファイルをリダイレクトで作成したいことがある。
===== nest =====


sshのコマンド部分を文字列にすればOK。
* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]
ssh user@remotehost -T "cat > /remotefile.txt" <<-EOT
Some text
EOT
-Tで擬似端末を無効にしている。
===== パスフレーズの省略 =====
* [https://zenn.dev/luvmini511/articles/65786667221313 SSH パスフレーズ 省略したい!~ config 設定するか Keychain 登録自動化するか ~]
* [https://madoverload.com/2022/04/29/mac-ssh-agent/ Macのssh-agent]
SSH多段接続時とgit cloneでSSH鍵参照時に、パスフレーズを要求される。毎回要求されるのが手間。これを省略する方法がある。
~/.ssh/configに以下の設定を記述する。
Host *
  AddKeysToAgent yes
  UseKeychain yes
  IdentityFile ~/.ssh/id_ed25519
* AddKeysToAgent=yesにすると、ssh-agentの実行時に自動的に鍵を追加する。
* UseKeychain=macOS専用。OSのキーチェーンからパスフレーズの検索を試みる。
* IdentityFile=SSH秘密鍵の絶対パス。デフォルトは~/.ssh/id_rsa。
上記3点で自動入力を試みる。
macOSで行う分には上記だけでパスワードは聞かれない。これをリモートでもやりたいなら、ssh-agentに登録が必要。
ログイン時に1回実行してくれたらいいので、ログインシェルの設定の~/.bash_profileに以下を記述。
echo 'ssh-add --apple-use-keychain' >>~/.bash_profile
これで端末の起動時に鍵を自動登録してくれるので、リモートでもパスフレーズを要求されない。


===== ssh_config =====
* [https://web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/ web.archive.org/web/20230602041631/https://jj-blues.com/cms/wantto-useloop/]
[https://linux.die.net/man/5/ssh_config ssh_config(5): OpenSSH SSH client config files - Linux man page]


重要な設定・構文がある。
ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。


====== TOKENS ======
=== bitsadmin ===
macのman ssh_configに詳しい。
Windowsでのファイルダウンロードコマンド


使用可能な指令が限定されている。
Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。


HostName (Macのみ)
書式:
bitsadmin /transfer <job name> <URL> <output path>
<job name>と<output path>は必須なので注意する。


* %h=リモートホスト名。Hostの指定部。
=== certutil ===
* %p=リモートポート。
Windowsでのハッシュの確認に使える。
certutil -hashfile file


====== WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! ======
SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。


* [https://www.niandc.co.jp/tech/20150729_2464/ ssh接続をする際に「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」と出てつながらない|テクニカルブログ|日本情報通信株式会社]
=== rlogin.cmd ===
* [https://qiita.com/hnw/items/0eeee62ce403b8d6a23c 「SSHホスト鍵が変わってるよ!」と怒られたときの対処 #SSH - Qiita]
コマンドキーの送信を自動化できる?
 
rem rlogin.cmd
ssh example.comなどを実行すると、IPアドレスの振り直しなどで、ホストの公開鍵が変わっていた場合、中間者攻撃への対策として失敗する。
   
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  @Echo off
  @   WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!    @
  Set SERVER=192.168.0.0
  @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
  Set USERNAME=
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
  Set PASSWORD=
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
   
It is also possible that a host key has just been changed.
  Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
  The fingerprint for the RSA key sent by the remote host is
  Start mstsc /v:%SERVER%
  SHA256:.
  Timeout 5
  Please contact your system administrator.
  Cmdkey /delete:TERMSRV/%SERVER%
  Add correct host key in /Users/z.ken.senoo/.ssh/known_hosts to get rid of this message.
  Offending RSA key in /Users/z.ken.senoo/.ssh/known_hosts:1
  Host key for [example.com]:3023 has changed and you have requested strict checking.
Host key verification failed.
Connection closed by UNKNOWN port 65535
  Connection closed by UNKNOWN port 65535
 
$HOME/.ssh/known_hostsの該当行を削除すれば解決する。以下のコマンドでも対応してくれる。
ssh-keygen -R example.com
いや、うまくいかない。~/.ssh/known_hostsに以下の該当ドメインの除外設定が必要な模様。
@cert-authority example.com ssh-rsa
「[https://man.openbsd.org/sshd sshd(8) - OpenBSD manual pages]」に記載がある。<blockquote>The marker is optional, but if it is present then it must be one of “@cert-authority”, to indicate that the line contains a certification authority (CA) key, or “@revoked”, to indicate that the key contained on the line is revoked and must not ever be accepted. Only one marker should be used on a key line.
 
...


When performing host authentication, authentication is accepted if any matching line has the proper key; either one that matches exactly or, if the server has presented a certificate for authentication, the key of the certification authority that signed the certificate. For a key to be trusted as a certification authority, it must use the “@cert-authority” marker described above.</blockquote>https://chatgpt.com/c/67f321e3-3b78-800b-b263-3e7169488367
=== 実行中プロセスのパスの確認 ===
出典: [https://superuser.com/questions/768984/show-exe-file-path-of-running-processes-on-the-command-line-in-windows Show EXE file path of running processes on the command-line in Windows - Super User]。
wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST


通常、known_hostsには、接続済みのホストの公開鍵を記録し、次回以降の接続時の確認に使う。ただ、この場合、IPアドレスが動的に変更する場合や、鍵が頻繁に変更される場合に、警告になる。この対策として、@cert-authorityで、同じ行のホスト鍵を署名したCA鍵を信頼する。これにより、同一のCAの複数ホストを一括で信頼する。
=== 簡易編集モード/挿入モード ===


==== curl ====
* [https://softantenna.com/blog/windows-10-command-prompt-no-stop/ 【Tips】Windows 10のコマンドプロンプトが意図せず止まってしまう問題を回避する方法 | ソフトアンテナ]
HTTPの通信のコマンドラインでの確認でよく使う。
* [https://superuser.com/questions/419717/windows-command-prompt-freezing-randomly Windows command prompt freezing randomly - Super User]


===== Basic =====
Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。
[https://curl.se/docs/tutorial.html curl - Tutorial]
* -X: メソッド指定
* -d/--data-urlencode: リクエストボディー (key=value)を指定。-X POSTも自動指定になる。
curl -H "Content-Type: application/json" -d '{"name":"佐藤", "mail":"sato@example.com"}' localhost:5000/api/v1/users\
curl -H "Content-Type: application/json" -d @body.json localhost:5000/api/v1/users\


JSONで送信する場合、ヘッダー指定が必須。
cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。


<nowiki>*</nowiki>-F: multipart/formのform指定。
そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。
curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
  <nowiki>http://www.example.com/postit.cgi</nowiki>
@でfilename相当の指定。;でmime typeも指定できる。


@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。
[□挿入モード] にすると回避できる模様。


===== curl: (60) SSL certificate problem: self-signed certificate =====
== Vim ==
Ref: [https://linuxfan.info/curl-insecure curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI].


--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。
=== vimdiff ===
[https://maku77.github.io/vim/file/vimdiff.html 2 つのファイルの差分を取る・マージする (vimdiff, vim -d) - まくまくVimノート]


===== curl: Failed writing body =====
vimのdiff機能。ファイル同士の差分のチェック、マージで簡易的に使える。
[https://askubuntu.com/questions/1449492/right-after-piping-to-head-tail-curl-23-failure-writing-output-to-desti pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu]


以下のようにhead -n 1を指定するとcurlがエラーを出力する。
==== diffモードで起動 ====
  curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"        -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"        <nowiki>https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0</nowiki> | head -n 1
  vim -d <file1> <file2>
vimdiff <file1> <file2>


  curl: Failed writing body
==== 起動中のdiffモード ====
curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。
:diffs[plit] <file> " 上下分割
  :vert[ical] diffs[plit] <file> " 左右分割
:diffthis " バッファー同士


対策は、curl -sで出力を抑制するとのこと。これで解決。
==== 移動 ====


==== Teleport ====
* [c=前の差分に移動。
* ]c=次の差分に移動。


* [https://goteleport.com/docs/connect-your-client/teleport-connect/ Using Teleport Connect | Teleport Docs]
==== マージ ====
* [https://speakerdeck.com/gree_tech/greetechcon2023-session-a6 SSH から Teleport へ - Speaker Deck]


踏み台サーバー (Jump server/Jump host) をよりよく管理するためのサーバーソフトウェア。
* dp=diff put。自分の内容を片方に反映。
* do=diff obtain。自分の内容に片方を反映。


アクセスログなどを一元管理できる。商用版とオープンソース版がある。
=== Other ===


基本的にteleportのサーバーを一度経由して、各種の踏み台サーバーにアクセスする。経由先が1個増えるが、そのおかげで監査ログを取得できたり、権限などを一括管理できる。
==== Async ====
https:/github.com/skywind3000/asyncrun.vim


ただ、teleportで監査ログを残すには、基本的にtshを経由する必要があり、既存のIDEなどのssh想定のソフトだと工夫が必要。tsh経由でやったり、rsyncで間にtshを挟むような工夫が必要。
asyncrun.vimは1個のバックグラウンド処理しか対応していない。


===== Install =====
<nowiki>https://github.com/skywind3000/asyncrun.vim/issues/12</nowiki>
[https://goteleport.com/blog/how-to-configure-ssh-certificate-based-authentication/ How to configure SSH Certificate-Based Authentication]


[[https://goteleport.com/download/ Download Teleport: Secure and Easy Infrastructure Access | Teleport]] から自分のパソコンのtshをインストールする。
vim-dispatchならいけるのか?


以下の環境変数を設定する。
==== Binary ====
*TELEPORT_AUTH:  
[https://vim-jp.org/vim-users-jp/2010/03/21/Hack-133.html vim-jp » Hack #133: バイナリファイルを編集する]
* TELEPORT_LOGIN:
* TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。


===== tsh =====
==== grep ====
teleportのコマンドラインクライアント。
非同期でgrepする方法。


tsh loginでteleportにログインする。
<nowiki>https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously</nowiki>


環境変数
<nowiki>https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/</nowiki>


[https://goteleport.com/docs/reference/cli/tsh/ tsh CLI reference | Teleport Docs]
Vim 8の非同期APIはプラグイン用。


* TELEPORT_AUTH:  
<nowiki>*</nowiki> <nowiki>https://github.com/mhinz/vim-grepper</nowiki>
* TELEPORT_LOGIN:
* TELEPORT_PROXY: teleportプロキシーサーバーのアドレス。重要。
上記3個が特に重要。


===== ProxyJump+ProxyCommand =====
<nowiki>*</nowiki> <nowiki>https://github.com/skywind3000/asyncrun.vim</nowiki>
How To Use SSH ProxyJump and SSH ProxyCommand


https://goteleport.com/blog/ssh-proxyjump-ssh-proxycommand/
<nowiki>*</nowiki> <nowiki>https://github.com/tpope/vim-dispatch</nowiki>


~/.ssh/config のProxyJumpとProxyCommandの違いを整理する。
<nowiki>https://wonderwall.hatenablog.com/entry/2017/10/09/210000</nowiki>


どちらも中間サーバーを経由したリモートサーバーアクセスの指令。
asyncrun.vimでやるのがよさそう。


* ProxyJump: 最も簡単な方法。OpenSSH v7,5以上で使用可能。中間サーバーでポート転送対応が前提条件。ProxyJumpは内部でProxyCommandを使う。
==== AnsiEsc ====
* ProxyCommand: ProxyJump搭乗前の方法。中間サーバーを介して標準入力と標準出力を転送して機能。
<nowiki>*</nowiki> https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors


ProxyJumpの方が現代的だが、ProxyCommandの方が柔軟性が高い。
<nowiki>*</nowiki> https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly


ProxyJumpの使用例。
本家は太字に対応していないのでこちらがいいかな。
{| class="wikitable"
|<code>ssh -J <jump server> <remote server>ssh -J <jump server1>,<jump server2>,<jump server3> <remote server></code>
|}
ProxyCommand
{| class="wikitable"
|<code>ssh -o ProxyCommand="ssh -W %h:%p <jump server>"</code> <code><remote server></code>
|}
~/.ssh/configの例。
{| class="wikitable"
|<code>Host remoteserver</code>


<code> HostName 192.168.200.200</code>
- https:/github.com/powerman/vim-plugin-AnsiEsc


<code> User dev</code>
ただし、こちらはgvimでクリック時にカーソル位置がずれる。


<code> IdentityFile ~/.ssh/<your_key></code>
=== program ===


<code> Port 2048</code>
==== C ====
[https://daisuzu.hatenablog.com/entry/2012/05/06/204019 ワシのVimプラグインは百八式まであるぞ - daisuzu's notes]


【C/C++】


<code> ## sample for</code> <code>ProxyJump</code>
     87. a.vim


<code> ProxyJump user@<jumpserver></code>
        C/C++のヘッダとソースを切り替えます。


     88. c.vim


<code> ## sample for</code> <code>ProxyCommand</code>
        C/C++のテンプレートやイディオムの入力をサポートしてくれます。


<code> ProxyCommand ssh -W %h:%p <jumpserver></code>
     89. CCTree
|}
ssh remoteserver で<jumpserver> 経由でremoteserverに接続できる。


一般的に、ProxyJumpが推奨される感がある。ただ、teleportを導入している場合、ProxyJump/ProxyCommandを使うと、tshを経由していないのでteleportにログが残らないらしい。
        cscopeを使って関数のコールグラフを表示してくれます。


===== tsh経由ssh =====
     90. Source-Explorer-srcexpl.vim
ProxyJump/ProxyCommandを使わない場合、以下の形式でtshを使ってアクセスするのが基本。
tsh ssh 踏み台サーバーホスト名
tsh sshでteleportサーバーが管理している踏み台サーバーが見えるので、そこに接続できる。tshの後のsshは基本的に通常のsshと同じなので、sshの後にsshのコマンドを連鎖でき、対象サーバーにも一発でアクセスできる。
tsh ssh -At <jump host> ssh -A <target host>
-tでttyに繋いで標準入出力を接続。-Aはフォワーディング。ローカルのssh-addの情報などを連携できる。


<jump host>の~/.ssh/configを用意しておくことで、<target host>にホスト名を指定したりできる。
        ソース解析ツール、Source InsightのVim版です。


ProxyJump/ProxyCommandと異なり、これだとちゃんとログを残せる。
     91. trinity.vim


===== tsh経由scp =====
        taglist, srcexpl, nerdtreeを同時に起動して


* [https://goteleport.com/blog/teleport-files/ Teleport Files with SCP]
        VimがIDE画面のような画面になります。
* [https://goteleport.com/docs/connect-your-client/tsh/ Using the tsh Command Line Tool | Teleport Docs]


tsh経由の踏み台サーバーへのファイル転送はやや工夫が必要。
     92. cscope-menu


tsh scpというコマンドが一応ある。が、これはネストなどには未対応。やる場合、以下のように2回実行になる。
        cscope用のメニューを表示してくれます。
FR=test.file TO=/path/to/test.file
tsh scp $FR <jump host>:$TO; tsh ssh -At <jump host> scp $TO <target host>:$TO
高ではなく、rsyncを使えば一発でいける。
rsync -e "tsh ssh -A <jump host> ssh" ./test.file <target host>:~/
これが基本。


====== PhpStorm ======
     93. gtags.vim
[https://goteleport.com/docs/enroll-resources/server-access/guides/jetbrains-sftp/ JetBrains SFTP | Teleport Docs]


teleportの公式にマニュアルがあるが、記述が非常に不親切。これだと踏み台サーバーにしかアクセスできない。その先にアクセスできない。
        gtagsを使ってファイルを開けます。


多段SSHの設定を残しておいて、ファイル転送だけrsyncで行う形になる。
     94. DoxygenToolkit.vim


PhpStormのSSH configurationsのホスト名がスクリプトの引数に渡されるので、踏み台からAWSにsshでログインするホスト名やパソコンの~/.ssh/configのHostとの一致必要な点に注意する。
        Doxygenコメントの入力をサポートしてくれます。
USERNAME=
IPV4=
VPCID=
cat <<-EOT >>~/.ssh/config
Host $VPCID
  ForwardAgent yes
  User $USERNAME
  ServerAliveInterval 30
  SendEnv -LC_* -LANG
  ProxyJump $USERNAME@teleport.security:3023
   
Host $USERNAME
    ForwardAgent yes
    ProxyJump $VPCID:22
    User $USERNAME
    Hostname $USERNAME.example.com
    ServerAliveInterval 30
    SendEnv -LC_* -LANG
   
Host $USERNAME.$VPCID
    # for automatic upload by PHPStorm
    LocalForward 22224 $USERNAME.$VPCID:22
    # for XDebug
    RemoteForward 9000 localhost:9000
    ForwardAgent yes
   
Host db-*
  HostName $IPV4
  LocalForward 3307 localhost:22
  ProxyCommand ssh $VPCID -W %h:%p
  ForwardAgent yes
   
Host *
    AddKeysToAgent yes
    PasswordAuthentication no
    User $USERNAME
    ForwardAgent yes
    ServerAliveInterval 30
    IdentityFile ~/.ssh/id_ed25519
    # for macOS
    UseKeychain yes
EOT
こんな感じの多段SSHの設定を用意。
踏み台サーバーにも同じホスト名でアクセスできるように、以下のような内容の~/.ssh/configをまだならば設定しておく。
{| class="wikitable"
|<code>AWS_HOSTNAME=</code>


<code>IPV4=</code>
== Visual Studio Code ==


<code>VPCID=</code>
=== Keybind ===


<code>tsh ssh -A $VPCID "cat >>~/.ssh/config"</code> <code><<-EOT</code>
==== 矩形選択 ====
Ref: [https://mitomito.hatenablog.jp/entry/2021/01/27/073000#:~:text=VS%20Code%E3%81%AE%E7%9F%A9%E5%BD%A2%E9%81%B8%E6%8A%9E%E3%81%A8%E7%9F%A9%E5%BD%A2%E8%B2%BC%E4%BB%98%E3%81%AE%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%201%20%E3%83%9E%E3%82%A6%E3%82%B9%E3%81%A7%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%20shift%20%2B%20alt%20%2B,shift%20%2B%20alt%20%2B%20%E7%9F%A2%E5%8D%B0%E3%81%A7%E4%BB%BB%E6%84%8F%E3%81%AE%E7%AF%84%E5%9B%B2%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%80%81%20%28or%20%E5%88%87%E3%82%8A%E5%8F%96%E3%82%8A%29%E3%81%99%E3%82%8B%20 VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog].


<code>Host $AWS_HOSTNAME</code>
* s-alt-クリック
* c-s-alt-矢印
ジャンプ


<code> HostName $IPV4</code>
* 括弧ジャンプ: C-S-\


<code>EOT</code>
=== Config ===
|}


==== Default terminal ====
Ref: [https://stackoverflow.com/questions/44435697/change-the-default-terminal-in-visual-studio-code bash - Change the default terminal in Visual Studio Code - Stack Overflow].


rsync executable
[F1]-[Terminal: Select Default Profile]


rsyncで使用する (-eオプション)、以下の内容のシェルスクリプトを作成して実行権限を付与して任意の場所 (例: ~/project/tsh_ssh.sh) に配置する。
=== cscope ===
{| class="wikitable"
cscope用のプラグインが何個かある。
|<code>cd ~/project/</code>


<code>cat <<-'EOT'</code> <code>>tsh_ssh.sh</code>
* [https://marketplace.visualstudio.com/items?itemName=xulion.codescope scope4code - Visual Studio Marketplace]
* [https://marketplace.visualstudio.com/items?itemName=SeungukShin.cscope-code cscope-code - Visual Studio Marketplace]


<code>tsh ssh -A <jump host> ssh $@</code>
scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。


<code>EOT</code>
cscope-codeはシンプルだが動作した。こちらを当分使うことにする。


<code>chmod +x tsh_ssh.sh</code>
Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。
|}


=== Vim ===


* [https://marketplace.visualstudio.com/items?itemName=vscodevim.vim Vim - Visual Studio Marketplace]


PhpStorm設定
VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。


PhpStormで以下を設定する。
=== Extension ===
CSS


* [Tools]-[Deployment]-[Configuration]
Tailwind CSS IntelliSense
* [+]-[SFTP]
* [Create New Server]-[New server name: 任意の名前 (例=rsync)]-[OK]
* [Connection] タブを以下に設定。
*# Type=SFTP
*# SSH configuration=以下を設定。
*## Host: <ホスト名> (例: ~/.ssh/configと踏み台サーバーの~/.ssh/configのホスト名と同じにする)
*## User name: ユーザー名
*## Port: 22
*## Authentication type: OpenSSH config and authentication agent
*# Root path=転送先のベース。
*# [☑️Use Rsync for download/upload/sync]
*# Rsync Settings=以下を設定。
*## Shell executable path=tsh_ssh.shのパス (例=~/project/tsh_ssh.sh)
* [Mappings] タブを以下に設定。
*# Local path: ローカルパソコンのディレクトリー
*# Deployment path: /
*# Web path: /
* [Settings]-[Build, Execution, Development]-[Development]-[Options]-[Upload changed files automatically to the default server]=[On explicit save action]
*# ☑️Delete remote files when local are deleted


以上で完了。後は同期したいファイルをPhpStormで開いて、右クリック-[Deployment]-[Upload to]/[Download from] でファイル転送できる。
==== PHP ====
Laravel Blade Snippets


[☑️Use Rsync for download/upload/sync] のチェックを外せば、rsyncを使わないファイル転送になる。
===== PHP Intelephense =====
Ref: [https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client PHP Intelephense - Visual Studio Marketplace].


=== Wireshark ===
VSCodeのPHPの補完拡張として人気が高い。


==== TLS ====
====== Quick Start ======
Ref: [https://www.toyo.co.jp/onetech_blog/articles/detail/id=36994 SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー].
設置後、しておくべき設定がある。


Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。
* Go to <code>Extensions</code>.
* Search for <code>@builtin php</code>
* Disable <code>PHP Language Features</code>. Leave <code>PHP Language Basics</code> enabled for syntax highlighting.


[Preferences]-[Protocols]-[TCP] を選ぶ。
VSCodeの [PHP Language Features] を無効にしておくとのこと。


* ☑Allow subdissector to reassemble TCP stream
後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。
* ☑Reassemble out-of-order semgemnts
"files.associations": { "*.module": "php" }


上記をチェックしておく。デフォルトでチェックされていた。
====== Module ======
peclなどPHPの標準モジュールで一部認識できないものがある。


続いて、セッションごとのPre-Master Secretを登録する。
「[https://stackoverflow.com/questions/62258598/undefined-type-imagick-in-vscodes-intelephense php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow]」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。


Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。
====== Coding ======
Ref: [https://beyondjapan.com/blog/2020/02/intelephense-vscode-php/ VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド].


以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。
intelephenseでコード補完を認識しやすい書き方というのがある。
export SSLKEYLOGFILE=/tmp/sslkey.log
Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。


=== Security ===
まず、型をつけられるものはつける。<syntaxhighlight lang="php">
function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}
</syntaxhighlight>ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。


==== DoS攻撃 ====
====== include Path ======
いくつか対策方法がある。
開発対象コードが、.envなどに記載の環境変数を前提として、動きになっていたりすることがある。そうなると、この環境変数を参照できないと、認識できない。


* [https://lite.ip2location.com/ip-address-ranges-by-country?lang=ja 国別のIPアドレス範囲]
include Pathsに追加する。
* [https://rakko.tools/tools/11/ IPアドレスから住所検索:国、地域の特定 | ラッコツールズ🔧]


サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。
他、.php以外の拡張子は基本的にinluce pathにあっても認識しない。"intelephense.files.associations":に拡張子を追加する。
 
攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。
 
==== バリデーションの実装 ====
 
* [https://teratail.com/questions/81861 フロント側で入力チェックをしていればサーバー側では入力チェックは必要ない?]
* [https://qiita.com/mi2__user/items/f2f415ccbb0a625c8647 フロントエンドの"バリデーション"は最低限の方がいいらしい。 #TypeScript - Qiita]
 
基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。
 
ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。
 
==== 二重送信 ====
 
* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
 
submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。
 
# ボタン連打
# ブラウザーバック
# リロード (PRG)
 
項目ごとにすべき対策が異なる。
 
===== 連打 =====
 
* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
* [https://codezine.jp/article/detail/769 JavaScriptを利用してフォームの二重送信を防止する|CodeZine(コードジン)]
* [https://blog.nisesagi.com/3150/ JavaScriptでformの2重送信を防止する | にせサギ ネットサギ体験ブログ]
* [https://yutaihara.com/archives/569 Javascriptで送信ボタン二度押しによる二重送信を防止する方法 | Yuta Ihara.com]
 
基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。
 
似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。
$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});
停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。
 
==== Other ====
 
===== Access Denied! Your IP address is blacklisted because of malicious behavior in the past =====
Webサイトを開くと、[Access Denied! Your IP address is blacklisted because of malicious behavior in the past] のメッセージが表示されてアクセスできないことがあるらしい。
 
* [https://takublo.net/spamhaus/ Spamhausの解除申請手順~ブラックリスト登録の原因と対策 | takublo-net]
* [https://www.kaufmann-automotive.ch/mod-spamhaus-new.html Apache 2.4.x spamhaus_new module, Anti-Spam]
 
Spamhausというスパムデータのブラックリスト共有サービスがあり、Apache HTTP Serverのspamhaus moduleでこれを使っていて拒否している可能性がある模様。
 
spamhauに解除申請するとすぐに解除してくれて、反映に12時間くらいかかる模様。
 
=== Browser ===
 
==== Bookmarklet ====
 
===== AutoScroll =====
https://chatgpt.com/share/683d5e8b-1744-800b-9fc9-a2e5c05754ca
 
MacのChromeはマウスホイールの中ボタンクリックのオートスクロールに対応していない。
 
面倒なので、ブックマークレットで対応する。
/* AutoScroll */
javascript:(function(){
  if(window.autoScrollInterval){
    clearInterval(window.autoScrollInterval);
    window.autoScrollInterval = null;
    /* alert("⏹ 自動スクロール停止"); */
  } else {
    /* ここでスクロール速度を調整(1 = 遅い、10 = 速い)*/
    const speed = 1;
    window.autoScrollInterval = setInterval(() => {
      window.scrollBy(0, speed);
    /* この間隔も調整可能(ミリ秒) */
    }, 20);
    /* alert("▶ 自動スクロール開始"); */
  }
})();
クリックするたびに、自動スクロールのオン・オフが切り替わる。便利。
 
==== Chromium ====
 
===== Extension =====
Chromme系で愛用拡張機能を列挙する。
 
* [https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm Create Link]:
 
===== Profile =====
https://chatgpt.com/c/67aca944-1fcc-800b-973e-7bf3207b9b91
 
Webサイトのアカウントを切り替えたい場合、Webブラウザーのプロファイル機能で、アカウント情報を分離できる (Googleアカウントではなくて)。
 
これでA用、B用など用途ごとにプロファイルを作って、それでセッションやブックマークなどを分けられる。
 
==== devtool/開発者ツール ====
 
* [https://web.gnusocial.jp/post/2023/05/21/6948/ Webブラウザーの開発者ツールでのJavaScriptデバッグ | GNU social JP Web]
* [https://developer.mozilla.org/ja/docs/Learn_web_development/Howto/Tools_and_setup/What_are_browser_developer_tools ブラウザーの開発者ツールとは]
* [https://developer.chrome.com/docs/devtools/javascript?hl=ja JavaScript をデバッグする  |  Chrome DevTools  |  Chrome for Developers]
 
===== イベントリスナー =====
[https://yuzu441.hateblo.jp/entry/2016/12/12/120000 要素に設定されているイベントを調べよう - ゆずめも]
 
[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。
 
===== イベント監視 =====
[https://stackoverflow.com/questions/3787555/how-to-find-out-which-javascript-events-fired How to find out which JavaScript events fired? - Stack Overflow]
 
monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。
 
===== Network conditions =====
開発者ツールの[Network]タブを開いてリロードしても、[No internet]と表示されることがある。
 
これはオプション設定の問題。上のツールバーの[Disable cache]の右が[Offline] だとこうなる。これを[No throttling]にすると解決する。クリックミスだと思われる。
 
==== Safari ====
 
===== Windows Safari =====
 
* [https://web.archive.org/web/20220220134447/https://jp.techcrunch.com/2012/07/27/20120725apple-safari-for-windows-ends/ Appleは静かにWindows版Safariの開発から手を引いてしまったのだろうか? | TechCrunch Japan]
* [http://web.archive.org/web/20120728130701/https://support.apple.com/kb/DL1531 Safari 5.1.7 for Windows]
 
一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。
 
===== 開発者ツール =====
[https://www.e-bird.biz/blog/dev-ios/ PCでスマホサイトを見る方法 – Safari編|東京渋谷のWeb制作会社・ホームページ制作会社|株式会社イー・バード]
 
Safariの開発者ツールは癖がある。
 
[設定]-[詳細]-[☑️Webデベロッパ用の機能を表示]
 
[開発]-[レスポンシブデザインモードにする]
 
===== スーパーリロード =====
[https://www.support.allmovie.jp/blog/20210527115217/ サポートへようこそ|メールのトラブルやホームページに関するお問い合わせ、 CMS操作方法など各種サポート情報をご案内しております。/各ブラウザでの強制リフレッシュ(スーパーリロード)]
 
Shift-更新ボタン
 
==== Firefox ====
 
===== カメラ =====
https://chatgpt.com/share/680eaa72-118c-800b-b032-34842d9a6c18
 
Firefoxでカメラが機能しないことがある。確認すべき事項がいくつかある。
 
# Firefoxの設定でカメラを有効にする。アプリの再起動必要。
# Webブラウザーのアドレスバー左側でカメラを許可する。1ができていないとカメラの項目が表示されない。
 
=== Other ===
 
==== Tool ====
 
* [https://web-toolbox.dev/ Web ToolBox | 開発者向けのオンラインツール]
* [https://tm-webtools.com/ TM - WebTools]
 
いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。
 
==== localhost ====
 
* [[wikipedia:Special-use_domain_name|Special-use domain name - Wikipedia]]
* [https://ja.wikipedia.org/wiki/.localhost .localhost - Wikipedia]
 
RFC 6761 で規定。RFC 2606<nowiki/>で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。
 
IPv4=127.0.0.1/IPv6=::1とされている。
 
==== DB vs. file ====
https://chatgpt.com/share/67f78855-b640-800b-84c9-ed3ada7fef48
 
データはアクセス元によって、速度や負荷が異なるらしい。それぞれ特徴がある。
 
* ファイル (JSON/php):
* インメモリーDB: Redis
* RDB: 排他処理。検索・集計。書込用。
 
書き込みの最終はRDBとして、そこからよく使うものを、書き込みの少ないものを、インメモリーDBやファイルに引き上げるような感じがする。
 
== Shared Host ==
 
=== Free ===
無料で使用可能な共用ホスティングサービスがある。
 
==== スタードメイン無料サーバー ====
ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。
 
[https://www.star-domain.jp/service/free_server.php 無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~]
 
jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。
 
* ディスク容量 20GB
* DB 1GB
 
ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。
 
=== CORESERVER ===
 
==== Coupon ====
A8.netで自己アフィリエイトがある。これを経由すると少しお得になる。契約初回のみ。更新はだめ。
 
==== リージョン ====
[https://prtimes.jp/main/html/rd/p/000002296.000000136.html GMOデジロック:レンタルサーバー「コアサーバー」、西日本リージョンを新設し、リージョン選択サービスを開始 | GMOインターネットグループのプレスリリース]
 
2018-01-31から西日本リージョンも選べるようになったらしい。適宜分散させるといいかもしれない。
 
==== Pay ====
以下が可能。
 
* クレジットカード
* Amazon Pay
 
Amazon Payが使えるからAmazon PayでOK。
 
[https://www.coreserver.jp/price/ 料金プラン | レンタルサーバー CORESERVER(コアサーバー)]
 
料金表を見る限り、12か月以上がお得。迷ったら12か月でいいと思う。確信やキャンペーンがあるなら24/36も。
 
更新を考えるのが面倒だから、36でいいかも。
 
==== メール ====
 
* [https://www2.bwt.jp/wiki/?Custom_Filter_of_Coreserver Custom_Filter_of_Coreserver - PukiWiki]
* [https://help.coreserver.jp/manual/v2/spam-filter/ スパムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* [https://help.coreserver.jp/manual/v1/customfilter/ カスタムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
 
情報
 
* [https://www2.bwt.jp/wiki/?CoreServer_Mail_Custom CoreServer_Mail_Custom - PukiWiki]
* [https://bwt.blog.ss-blog.jp/2021-03-28 coreserverのメール設定:BWT Lab.:SSブログ]
* [https://qwerty.work/blog/2017/01/valueserver-spammail-filter-rule.php バリューサーバーのフィルター設定でスパムメール(迷惑メール)対策する方法 - QWERTY.WORK]
* [https://awmt.jp/dekirukana/archives/2253 コアサーバー V1にてカスタムフィルターで「ごみ箱」を指定したときの確認方法 – AWMTの、できるかな?]
 
ルールが特殊なので注意する。
 
ゴミ箱に振り分ける場合。
 
順1 で[<code>./.Trash</code>] を指定
 
順2
 
* 条件:  [<code>.*</code>]
* 処理:  <code>./</code>、に振り分ける
 
条件部分には正規表現が使えるように見える。
 
破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。
 
カスタムフィルターにくせがある。
 
* エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」
 
===== ポイント =====
https://chatgpt.com/c/680398be-247c-800b-911e-df207cb6c6a3
 
* 日本語はBASE64でエンコードされているので、そのままだとヒットしない可能性が高い。BASE64でエンコードされたキーワードの指定が必要な可能性が高い。
* 検索範囲=[全体] は全部にANDで入っていることを期待している感じがするので、Subjectに絞り込む。
 
1個目のBASE64が重要な気がする。これで様子を見る。
 
やっぱりうまくいかない。
 
Thunderbirdのメールフィルターで処理する。これが確実。サーバー側で対応していないから、外出先で適用されないのが欠点だが。
 
==== Value Domain ネットde診断 byGMO ====
 
* [https://www.value-domain.com/information/detail/?no=20240606-1 弊社レンタルサーバー上で運用中のドメインにおける自動セキュリティ診断開始のお知らせ | お知らせ - バリュードメイン]
* [https://www.value-domain.com/security/net-de-shindan/ Value Domain ネットde診断 byGMO - バリュードメイン]
 
2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。
 
==== CGI ====
 
* [https://senooken.jp/post/2020/02/21/3905/ CORESERVERでのFastCGI/CGI版PHPの利用手順 – senooken JP]
* [https://help.coreserver.jp/faq/php-fast-cgi/ FastCGI版PHP 各バージョンのPHP設定方法 | よくある質問 | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* [https://help.coreserver.jp/faq/php-cgi/ PHPをCGIとして動かす方法を教えてください | よくある質問 | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* [https://engineer-milione.com/create/python-execution.html レンタルサーバー各社でのPythonの実行方法まとめ]
 
CORESERVERでのCGIの設定方法がある。
{| class="wikitable"
|+CORESERVERのFastCGI版PHPとCGI版PHPの設定方法
!項目
!FastCGI
!CGI
|-
|バージョンの変更
|管理画面
|<code>.htaccess</code>内の
<code>AddHandler application/x-httpd-phpcgiXX .php</code>
|-
|設定ディレクトリー
| colspan="2" rowspan="1" |<code>/virtual/<username>/public_html/.fast-cgi-bin/</code>
|-
|CGIの実行ファイル
|<code>phpXX.fcgi</code>
|<code>phpXX.cgi</code>
|-
|PHPの設定ファイル
|<code>phpXX.ini</code>
|<code>php.ini</code>
|-
|設定の反映タイミング
|バージョン切替時
|即時
|}
~/public_html/.fast-cgi-bin/のphpXX.fcgi phpXX.cgiがCGIの実行ファイル。このファイルか最後の行のexecのパスを変更すると、自前コマンドに変更可能。
 
FastCGIは管理画面からバージョンを変更したタイミングで反映される。ただ、ファイル拡張子が.phpじゃないとこのFastCGIが実行されない模様。
 
CGIは.htaccessに以下の内容を記述してCGI板PHPのバージョンを指定する。
AddHandler application/x-httpd-phpcgiXX .php
cgiのファイルには実行権限が必要。
chmod +x py.py
拡張子がないとダメな模様。加えて、.htaccessに以下の記述。
AddHandler cgi-script .py
これでpy.pyで動作はする。
 
拡張子じゃなくてファイル名で実行したい場合、SetHandlerでしていする ([https://senooken.jp/post/2019/06/01/2333/ AddType, AddHandler, SetHandlerの違い – senooken JP])。
<FilesMatch py$>
    SetHandler cgi-script
</FilesMatch>
これでpyでもアクセスできる。
 
FastCGI版の場合、以下のような設定でファイル名でマッチさせれば実行できそうな気もするが。
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>
500
<FilesMatch gnusocial$>
        SetHandler application/x-httpd-php
</FilesMatch>
pythonがphpとして認識され、テキストがそのまま表示される。
 
SetHandler fcgid-scriptにしたらFastCGIで動作する。プログラムがFastCGI対応になっている必要がある。
<FilesMatch gnusocial$>
        SetHandler fcgid-script
</FilesMatch>
 
==== Function ====
 
===== サーバー間コピー =====
[https://web.gnusocial.jp/post/2023/04/26/6305/ CORESERVERのサーバー間コピー | GNU social JP Web]
 
巨大ファイル・大量ファイルを転送する場合、長時間プロセスになって、サーバーに強制終了される可能性がある。なので、scp/rsyncじゃなくて、レンタルサーバーのファイル転送機能を使う。
 
CORESERVERのサーバー間コピーは、リモート→ローカルの1方向のコピー。
 
「[https://lilylila.hatenablog.com/entry/20120214/1329169978 coreserverのサーバー間コピーで発生したquotaの問題 - 渡米生活。(日記)]」にあるように、ファイル数が多いとコピー漏れがあるので、事前にtarで1ファイルにまとめてからコピーすると検証しやすい。
 
# コントロールパネル-[サイト設定]-[サーバー間コピー]
# [サーバー間でのファイルコピー設定]-[サーバー間コピーの新規作成] で以下を入力して [サーバー間コピーを新規作成する]
#* サーバー間コピー名: コピーのタスク名
#* ローカル: 転送先の現在のサーバーのディレクトリー
#* 転送方式: 更新 (削除なし)。基本はこれで問題なく、他に [ミラー (削除なし)]、[差分 (削除なし)] を用途に応じて選択
#* リモート: 転送元のリモートサーバーの情報を入力。リモートディレクトリーはホームディレクトリーからの相対指定。
 
これでOK。以下の3点に特に注意する。
 
# リモート→ローカルの方向へのコピー。
# リモートディレクトリーはリモートディレクトリーの''中身がコピー''される。指定したディレクトリー自体は転送されない。
# ローカルもリモートもディレクトリーはホームディレクトリーからの相対指定になるが、先頭に/が必要。
 
[サーバー間でのファイルコピー設定] 画面が表示されるので、作成した項目の [アクション] 列の [> (実行ボタン)] を選びます。
 
[サーバー間コピーの実行] の確認モーダルが表示されるので [サーバー間コピーを実行する] を選びます。
 
3分後ほどにコピーが始まります。タスクのログが [/.servercopy.log] に出力されます。
 
 
* 転送先: senooken@m9.coreserver.jp
* ローカルディレクトリ=/public_html/nc.senooken.jp (実体=/virtual/public_html/nc.senooken.jp)
* リモート
** FTPサーバー名=m9.coreserver.jp
** FTPアカウント=
** FTPパスワード
** リモートディレクトリー=/public_html/tmp/ (実体=/virtual/public_html/tmp)
 
== Analytics ==
 
==== Exam ====
<nowiki>##</nowiki> About
 
<nowiki>https://gnusocial.jp/notice/4506679</nowiki>
 
<nowiki>###</nowiki> 全般
 
- マーケティング・ビジネス実務検定
 
- IMA検定
 
- Web検定
 
- ネットマーケティング検定
 
<nowiki>###</nowiki> 解析系
 
- ウェブ解析士
 
- GAIQ
 
- 統計検定
 
- Webアナリスト検定
 
GAIQが無料だしどうせ使うからいいかな。
 
<nowiki>https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/</nowiki>
 
<nowiki>https://www.plan-b.co.jp/blog/seo/12792/</nowiki>
 
<nowiki>##</nowiki> URL
 
- <nowiki>https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/</nowiki>
 
- <nowiki>https://mynavi-creator.jp/blog/article/qualification-for-web-marketer</nowiki>
 
- <nowiki>https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html</nowiki>
 
- <nowiki>https://digitor.jp/textbook/web-analytical-qualification/</nowiki>
 
=== Tool ===
サイト分析用のツールがいくつかある ([https://hidesunblog.com/blog-ranking-sites/ 2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】])。
 
* SimilarWeb
* Ubersuggest
* ahrefs
* Googleキーワードプランナー
 
=== 閲覧数取得 ===
出典: [https://affiliate-jpn.com/archives/5595 GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN]。
 
* [行動]-[サイトコンテンツ]-[全てのページ]
* [表示する行数]=5000
* [エクスポート]=TSV
 
=== 流入元特定 ===
「[https://support.google.com/analytics/thread/252885536/%E4%BC%9A%E5%93%A1%E7%99%BB%E9%8C%B2%E7%94%BB%E9%9D%A2%E3%81%AE%E6%B5%81%E5%85%A5%E5%85%83%E6%8E%A2%E7%B4%A2%E6%96%B9%E6%B3%95%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6?hl=ja 会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ]」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。<blockquote>こんにちは。
 
探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。
 
・自由形式レポートを作成
 
・セグメント作成 > ユーザーセグメント
 
・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定
 
・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存
 
・探索レポートにセグメントを適用
 
・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列
 
・指標:セッション
 
ご確認よろしくお願いいたします。
 
※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。
 
 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。</blockquote>PMProでも似たような回答。<blockquote>Google Analytics 4 can track ecommerce conversions and then assign page value to posts that were a part of their conversion path for that engaged session. </blockquote>
 
== Server ==
 
=== httpd ===
Apache HTTP Server
 
==== About ====
httpdの利用可能な情報。
 
https://chatgpt.com/c/6761f851-df0c-800b-86e9-1624b458d66d
# 使用可能な指令一覧
apachectl -L
httpd -L
# 使用可能なモジュール一覧
apachectl -M
httpd -M
.htaccessで使用可能な指令の一覧。
 
[https://senooken.jp/post/2019/04/19/2010/ .htaccessで使用可能な指令一覧 – senooken JP]
 
==== Operation ====
サーバーの稼働や状態確認などで重要な操作がいくつかある。systemd前提。
 
ログ・状態確認。
sudo systemctl status apache2
sudoをつけないと詳細ログを確認できない。
sudo systemctl restart apache2
sudo systemctl start apache2
sudo systemctl stop apache2
 
==== Access Control ====
 
* [https://httpd.apache.org/docs/2.4/en/howto/access.html Access Control - Apache HTTP Server Version 2.4]
* [https://httpd.apache.org/docs/2.4/en/howto/auth.html Authentication and Authorization - Apache HTTP Server Version 2.4]
* [https://httpd.apache.org/docs/2.4/ja/mod/mod_authz_core.html#logic mod_authz_core - Apache HTTP Server Version 2.4]
 
DoS攻撃対策などで重要な設定。
 
mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。
 
基本構文は以下。
Require host <address>
Require ip <ip address>
1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。
 
Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。
 
==== mod_cgi ====
[https://httpd.apache.org/docs/current/en/mod/mod_cgi.html mod_cgi - Apache HTTP Server Version 2.4]
 
CGIプロトコルのApacheモジュール。cgi-scriptにハンドラーを割り当てるとCGIとして扱う。
 
==== mod_fcgid ====
[https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html mod_fcgid - Apache HTTP Server Version 2.5]
 
FastCGIプロトコルのApacheモジュール。AddHandlerかSetHandlerでfcgid-scriptハンドラーに割り当てられると、FastCGIとして処理される。
 
プログラム側もFastCGIに対応している必要がある。
 
==== Error ====
sudo systemctl status apache2
 
● apache2.service - The Apache HTTP Server
      Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
    Drop-In: /etc/systemd/system/apache2.service.d
              └─privatetmp.conf
      Active: failed (Result: exit-code) since Fri 2024-12-06 15:09:28 JST; 12s ago
        Docs: <nowiki>https://httpd.apache.org/docs/2.4/</nowiki>
    Process: 38461 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: [Fri Dec 06 15:09:28.259153 2024] [core:warn] [pid 38464] AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf.
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00112: Warning: DocumentRoot [/home/gree/frontend/greenet/htdocs_net] does not exist
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: AH00526: Syntax error on line 7 of /etc/apache2/conf-available/rewrite-greenet.conf:
Dec 06 15:09:28 z-ken-senoo apachectl[38464]: RewriteRule: unknown flag 'UnsafeAllow3F'
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: Action 'start' failed.
Dec 06 15:09:28 z-ken-senoo apachectl[38461]: The Apache error log may have more information.
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Dec 06 15:09:28 z-ken-senoo systemd[1]: apache2.service: Failed with result 'exit-code'.
Dec 06 15:09:28 z-ken-senoo systemd[1]: Failed to start The Apache HTTP Server.
 
===== AH00548: NameVirtualHost has no effect and will be removed in the next release /etc/apache2/ports.conf:8 =====
NameVirtualHost指令が廃止予定なので、行を削除して対応する。
 
===== AH00117: Ignoring deprecated use of DefaultType in line 122 of /etc/apache2/apache2.conf. =====
 
* Gentooの~amd64にApache 2.4.1が来たので試してみた https://meihong.work/computer/server-administration/apache/gentoo%E3%81%AEamd64%E3%81%ABapache-2-4-1%E3%81%8C%E6%9D%A5%E3%81%9F%E3%81%AE%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F/
* Upgrading to 2.4 from 2.2 https://httpd.apache.org/docs/2.4/upgrading.html
* DefaultType Directive https://httpd.apache.org/docs/2.4/en/mod/core.html#defaulttype
 
DefaultTypeはnone以外意味がなく、警告表示になる模様。
 
==== .htaccess ====
 
===== directive =====
[https://senooken.jp/post/2019/04/19/2010/ .htaccessで使用可能な指令一覧 – senooken JP]
 
.htaccessで使用不能なよく登場して誤解する指令を整理しておく。
 
* Alias
* ScriptAlias
* Directory/DirectoryMatch
* Location/LocationMatch
逆にOKなもの。
 
* Files/FilesMatch
 
=== E-mail ===
[[https://www.itti.jp/web-direction/spam-blacklist-release/ サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]]
 
MailHog: Go言語製のメールサーバーソフト。
 
=== Debian ===
 
==== PHP8 ====
[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](<nowiki>https://computingforgeeks.com/how-to-install-php-on-debian-linux/</nowiki>)
 
Debian 11の場合、PHP 8には外部リポジトリーが必要なので追加する。
 
sudo apt update
 
sudo apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2
 
PHPパッケージを追加する。
 
echo "deb <nowiki>https://packages.sury.org/php/</nowiki> $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list
 
wget -qO - <nowiki>https://packages.sury.org/php/apt.gpg</nowiki> | sudo apt-key add -
 
sudo apt update
 
これでPHP8を参照できるので、インストールする。
 
sudo apt install php8.2
 
[How to Switch between Multiple PHP Version on Debian 12/11/10 – TecAdmin](<nowiki>https://tecadmin.net/switch-between-multiple-php-version-on-debian/</nowiki>)
 
インストールしたら、PHPのバージョンを切り替える。
 
a2dismod php7.4
 
a2enmod php8.2
 
sudo systemctl restart apache2
 
php 8.2にするとこういうエラー。
 
[Sat Sep 02 11:31:02.558029 2023] [php:error] [pid 25644] [client 133.106.38.37:57181] PHP Fatal error:  Uncaught Error: Undefined constant "DB_DATAOBJECT_ERROR_NODATA" in /var/www/gnusocial/public/index.php:104\nStack trace:\n#0 [internal function]: handleError()\n#1 {main}\n  thrown in /var/www/gnusocial/public/index.php on line 104
 
念のためdockerで起動を試みましたが、同じくトップ画面を開くと同じエラーになります。
 
<<nowiki>https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development</nowiki>> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。
 
私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?
 
==== alternative ====
Ref: [https://wiki.debian.org/DebianAlternatives DebianAlternatives - Debian Wiki].
 
OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。<syntaxhighlight lang="sh">
sudo update-alternatives --display vi
sudo update-alternatives --config vi
</syntaxhighlight>オプションとコマンド名を指定することで、現在の実体と更新ができる。
 
=== XAMPP ===
 
==== ポート番号変更 ====
[https://qiita.com/neneta0921/items/3c2f9ac8ea9b5bcfc6e6 Xamppでポート競合を防ぐ方法 #PHP - Qiita]
 
XAMPP Control PanelのConfigから変更可能。
 
phpmyadminはConfigのphpmyadminで、Servers.portを追加する。
 
== Vim ==
 
=== vimdiff ===
[https://maku77.github.io/vim/file/vimdiff.html 2 つのファイルの差分を取る・マージする (vimdiff, vim -d) - まくまくVimノート]
 
vimのdiff機能。ファイル同士の差分のチェック、マージで簡易的に使える。
 
==== diffモードで起動 ====
vim -d <file1> <file2>
vimdiff <file1> <file2>
 
==== 起動中のdiffモード ====
:diffs[plit] <file> " 上下分割
:vert[ical] diffs[plit] <file> " 左右分割
:diffthis " バッファー同士
 
==== 移動 ====
 
* [c=前の差分に移動。
* ]c=次の差分に移動。
 
==== マージ ====
 
* dp=diff put。自分の内容を片方に反映。
* do=diff obtain。自分の内容に片方を反映。
 
=== Other ===
 
==== Async ====
https:/github.com/skywind3000/asyncrun.vim
 
asyncrun.vimは1個のバックグラウンド処理しか対応していない。
 
<nowiki>https://github.com/skywind3000/asyncrun.vim/issues/12</nowiki>
 
vim-dispatchならいけるのか?
 
==== Binary ====
[https://vim-jp.org/vim-users-jp/2010/03/21/Hack-133.html vim-jp » Hack #133: バイナリファイルを編集する]
 
==== grep ====
非同期でgrepする方法。
 
<nowiki>https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously</nowiki>
 
<nowiki>https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/</nowiki>
 
Vim 8の非同期APIはプラグイン用。
 
<nowiki>*</nowiki> <nowiki>https://github.com/mhinz/vim-grepper</nowiki>
 
<nowiki>*</nowiki> <nowiki>https://github.com/skywind3000/asyncrun.vim</nowiki>
 
<nowiki>*</nowiki> <nowiki>https://github.com/tpope/vim-dispatch</nowiki>
 
<nowiki>https://wonderwall.hatenablog.com/entry/2017/10/09/210000</nowiki>
 
asyncrun.vimでやるのがよさそう。
 
==== AnsiEsc ====
<nowiki>*</nowiki> https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors
 
<nowiki>*</nowiki> https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly
 
本家は太字に対応していないのでこちらがいいかな。
 
- https:/github.com/powerman/vim-plugin-AnsiEsc
 
ただし、こちらはgvimでクリック時にカーソル位置がずれる。
 
=== program ===
 
==== C ====
[https://daisuzu.hatenablog.com/entry/2012/05/06/204019 ワシのVimプラグインは百八式まであるぞ - daisuzu's notes]
 
【C/C++】
 
     87. a.vim
 
        C/C++のヘッダとソースを切り替えます。
 
     88. c.vim
 
        C/C++のテンプレートやイディオムの入力をサポートしてくれます。
 
     89. CCTree
 
        cscopeを使って関数のコールグラフを表示してくれます。
 
     90. Source-Explorer-srcexpl.vim
 
        ソース解析ツール、Source InsightのVim版です。
 
     91. trinity.vim
 
        taglist, srcexpl, nerdtreeを同時に起動して
 
        VimがIDE画面のような画面になります。
 
     92. cscope-menu
 
        cscope用のメニューを表示してくれます。
 
     93. gtags.vim
 
        gtagsを使ってファイルを開けます。
 
     94. DoxygenToolkit.vim
 
        Doxygenコメントの入力をサポートしてくれます。
 
== Visual Studio Code ==
 
=== Keybind ===
 
==== 矩形選択 ====
Ref: [https://mitomito.hatenablog.jp/entry/2021/01/27/073000#:~:text=VS%20Code%E3%81%AE%E7%9F%A9%E5%BD%A2%E9%81%B8%E6%8A%9E%E3%81%A8%E7%9F%A9%E5%BD%A2%E8%B2%BC%E4%BB%98%E3%81%AE%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%201%20%E3%83%9E%E3%82%A6%E3%82%B9%E3%81%A7%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B%E5%A0%B4%E5%90%88%20shift%20%2B%20alt%20%2B,shift%20%2B%20alt%20%2B%20%E7%9F%A2%E5%8D%B0%E3%81%A7%E4%BB%BB%E6%84%8F%E3%81%AE%E7%AF%84%E5%9B%B2%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%80%81%20%28or%20%E5%88%87%E3%82%8A%E5%8F%96%E3%82%8A%29%E3%81%99%E3%82%8B%20 VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog].
 
* s-alt-クリック
* c-s-alt-矢印
ジャンプ
 
* 括弧ジャンプ: C-S-\
 
=== Config ===
 
==== Default terminal ====
Ref: [https://stackoverflow.com/questions/44435697/change-the-default-terminal-in-visual-studio-code bash - Change the default terminal in Visual Studio Code - Stack Overflow].
 
[F1]-[Terminal: Select Default Profile]
 
=== cscope ===
cscope用のプラグインが何個かある。
 
* [https://marketplace.visualstudio.com/items?itemName=xulion.codescope scope4code - Visual Studio Marketplace]
* [https://marketplace.visualstudio.com/items?itemName=SeungukShin.cscope-code cscope-code - Visual Studio Marketplace]
 
scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。
 
cscope-codeはシンプルだが動作した。こちらを当分使うことにする。
 
Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。
 
=== Vim ===
 
* [https://marketplace.visualstudio.com/items?itemName=vscodevim.vim Vim - Visual Studio Marketplace]
 
VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。
 
=== Extension ===
CSS
 
Tailwind CSS IntelliSense
 
==== PHP ====
Laravel Blade Snippets
 
===== PHP Intelephense =====
Ref: [https://marketplace.visualstudio.com/items?itemName=bmewburn.vscode-intelephense-client PHP Intelephense - Visual Studio Marketplace].
 
VSCodeのPHPの補完拡張として人気が高い。
 
====== Quick Start ======
設置後、しておくべき設定がある。
 
* Go to <code>Extensions</code>.
* Search for <code>@builtin php</code>
* Disable <code>PHP Language Features</code>. Leave <code>PHP Language Basics</code> enabled for syntax highlighting.
 
VSCodeの [PHP Language Features] を無効にしておくとのこと。
 
後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。
"files.associations": { "*.module": "php" }
 
====== Module ======
peclなどPHPの標準モジュールで一部認識できないものがある。


「[https://stackoverflow.com/questions/62258598/undefined-type-imagick-in-vscodes-intelephense php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow]」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。
=== Settings ===


====== Coding ======
==== Files: Insert Final Newlines ====
Ref: [https://beyondjapan.com/blog/2020/02/intelephense-vscode-php/ VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド].
[https://devcoops.com/resolve-no-newline-at-end-of-file-github/ Resolve 'No newline at end of line' in GitHub | DevCoops]


intelephenseでコード補完を認識しやすい書き方というのがある。
gitで以下の警告が表示される。
\ No newline at end of file
デフォルトでファイル終端に改行を挿入しないから。設定がある。


まず、型をつけられるものはつける。<syntaxhighlight lang="php">
Settings-Files: Insert Final Newline
function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}
</syntaxhighlight>ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。


====== include Path ======
これをオンにすると、保存時に自動的にファイル末尾に改行を入れてくれる。設定しておくとよい。
開発対象コードが、.envなどに記載の環境変数を前提として、動きになっていたりすることがある。そうなると、この環境変数を参照できないと、認識できない。
 
include Pathsに追加する。
 
他、.php以外の拡張子は基本的にinluce pathにあっても認識しない。"intelephense.files.associations":に拡張子を追加する。


=== Other ===
=== Other ===

2025年10月27日 (月) 09:45時点における最新版

ソフトウェア開発作業全般

Other

ASCIIFlow: 画面構成図などの作成でテキストなので便利かもしれない。

Management

データ管理

https://chatgpt.com/share/680a33a2-159c-800b-8e8f-020f3d9ac921

時間ベースとカテゴリーベースがある。それぞれ利点と欠点がある。

  • カテゴリーベース: 検索・アクセスが有利。プロジェクト、業務単位。長期にわたって使うもの。
  • 時間ベース: 保管・バックアップ効率。経理関係。一時保管など。

基本はカテゴリーベースで、契約書とか、一時保管が必要なものは、時間ベースにも保管する。こうすると、いいかもしれない。

コピーする場合、どこからどこのコピーかわかるように、ショートカットも配置しておく。また、コピーであることがわかるディレクトリーにしておく。

バックアップ

VCSなしの場合のバックアップファイルの命名規則。

https://grok.com/share/c2hhcmQtMw%3D%3D_28297f6a-2ff6-4a9d-af38-5e729e65d9ed

filename.YYYYmmdd.ext

この形式がいい。拡張子の前に日付を入れる。拡張子の後に入れてしまうと、アプリが拡張子を認識できなくて困る。

Project

名簿付きの寄付

  • Vim: https://vim-jp.org/vimdoc-ja/sponsor.html
  • Vim (list): https://www.vim.org/sponsor/hall_of_honour.php
  • KDE: https://relate.kde.org/
  • KDE (list): https://relate.kde.org/civicrm/profile?gid=18&search=0
  • Conservancy (list): https://sfconservancy.org/sponsors/
  • Conservancy: https://sfconservancy.org/donate/

Kanboard

クローズ時に自動移動

[Configure project]-[Automatic actions]

  • action=[Move the task to another project]
  • Event name=Closing a task
  • Column=Done
  • Project=

これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。

Product

会員番号の設計

https://grok.com/share/c2hhcmQtMw%3D%3D_db01208a-8222-4d9b-900e-2bb429417296

ポイントカードは番号だけでためたり、使えたりしちゃう。流出すると不正利用の可能性がある。dポイントとか楽天ポイントとか。既存のポイントシステムは、固定番号を採用している。

アプリでタイムスタンプを付けたら、流出漏洩ガードができる。が、即時性を優先して固定番号も併用している模様。後は、不正監視システムでカバーとか。

ポイントは換金性が高いが、そんなに金額が大きくならずに消費される想定だから、リスクはあっても問題ない感じなのだと思われる。

バーコード

形式が複数ある。

1D product 1D industrial 2D
UPC-A Code39 QR Code
UPC-E Code93 Data Matrix
EAN-8 Code128 Aztec
EAN-13 Codabar PDF 417
UPC/EAN Extension 2/5 ITF MaxiCode
RSS-14
RSS-Expanded

緯度経度の順番

https://grok.com/share/c2hhcmQtMw%3D%3D_4f7c43b1-51f2-4cf4-b832-b108d74c7705

地理情報の座標は、緯度経度の順番で表記することが多い。ただ、数学的にはx,yの順番。メルカトル図法の一般的な地図の資格情報的には、経度緯度がx,yと対応する。順番が違うのが気になる。

結論: 外部公開APIは、緯度経度。内部で緯度経度を変換して、x,yにしたら、x,yの順番で扱う。

理由: 地理学的には、経度は特定が難しくて、緯度が先に特定されて、世界で先に使われるようになった。そのため、緯度経度の順番になって、世間で定着している。ISOなどの標準も緯度経度の順番。GeoJSONとかITシステムでは経度緯度の順番。

チェックイン機能
方式

https://grok.com/share/c2hhcmQtMw%3D%3D_792c1e8e-5fcd-429b-a7cd-1e116addbf39

方式 内容 利点 欠点 不正 対策
Geolocation API 店舗でマイページボタン押下 追加設備不要 不正完全防止不能 位置偽装 ユーザー特定可能なので、運用で不正をカバーする。
動的QR 店頭動的QRコードの読取 不正完全防止 表示端末設置必要、サーバー追加実装必要
固定QR 店頭固定QRコード読取 サーバー追加実装不要 不正完全防止不能 QRコード撮影持帰 固定QRを定期更新。
NFC 店頭NFC読取 タグ設置必要、端末限定
Bluetooth Beacon 店頭Beacon通信 Beacon設置必要
  • 手間最小はGeolocation API。位置偽装がありえるので、アカウントの定期監視は必要。付与の頻度や上限の制限ロックなど必要。
  • 不正防止+低コストは固定QR。定期的なQR更新が必要。
  • 不正完全防止で手間最小は動的QR。ただし、表示端末設置、追加サーバー実装必要。
動的QR

https://grok.com/share/c2hhcmQtMw%3D%3D_57855e1c-bae0-4fd9-99f5-622979149ff3

トークン管理用のテーブルを用意。

CREATE TABLE checkin_history (
    id INT AUTO_INCREMENT PRIMARY KEY,
    store_id INT NOT NULL,
    token VARCHAR(255) NOT NULL,
    checkin_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (store_id) REFERENCES stores(store_id)
);

トークン作成用のAPIを用意。アクセスが来たら、tokenを作って、それや店舗IDを埋め込んだQR/URLを作成 (?store_id=XXX&token=XXX)。

該当トークンを検証して、処理実施。GPS不要になる。

Communication

Backlog

メール通知

Backlogの通知設定をカスタマイズする手順|チーム効率を2倍にする最適化テクニック | こまろぐ

[個人設定]-[メール設定] で全体設定する。

ただ、コメント記入時に、[コメントをお知らせしたいユーザー] に入っていると、通知が来る。メールフィルターで対応するしかない。

Skype

すべてのエモーティコンのリストはありますか? - Microsoft サポート

Skyepで使用可能な絵文字の一覧。

Slack

チャンネル

https://slack.com/intl/ja-jp/help/articles/205239967-%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E5%8F%82%E5%8A%A0%E3%81%99%E3%82%8B

一覧表示

[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。

パーマリンク

Slackの投稿パーマリンクをWebブラウザーで開くと、該当箇所にジャンプできない。デスクトップアプリがあると開ける。それでしのぐ。

JIRA

関連チケット

[修正するバージョン]/[影響するバージョン] のリンクをクリックすると、関連するissueが一覧表示される。これで未クローズチケットを確認するといい。

履歴

[アクティビティ]-[履歴] のタブを選ぶと、変更履歴を確認できる。

Confluence

ページの中で、 [作成] を選んでページを作ると、階層が勝手にできて、子ページへのリンクもできる。

ショートカットキー

キーボード ショートカット

https://ja.confluence.atlassian.com/doc/keyboard-shortcuts-139456.html

エディタ

ブロック フォーマット

Windows 操作 Mac
Ctrl + 0 Paragraph ⌘+ 0
Ctrl+ (1 ~ 6) (選択した番号の)見出しレベル ⌘+ (1—6)
Ctrl + 7 Preformatted ⌘+ 7
Ctrl + 8 Quote ⌘+ 8
Ctrl + Shift + B、または

* + Space

箇条書きリストを追加 ⌘ + Shift + B、または

* + Space

Ctrl + Shift + N、または

# + space

番号付きリストを追加 ⌘ + Shift + N、または

# + space

Ctrl + Shift + S Strikethrough ⌘ + Shift + S
Ctrl + Shift + Subscript ⌘ + Shift + ,
Ctrl + Shift + Superscript ⌘ + Shift + .
Ctrl + Shift + M Monospace ⌘ + Shift + M
Ctrl + \ Clear formatting ⌘ + \

豊富なフォーマット

CTRL + Shift + V

サファリのみ:Ctrl + Shift + Alt + V

書式設定なしでテキストを貼り付け ⌘ + Shift + V

Safari のみ:⌘ + Shift + Option + V

Ctrl+M Files and images ⌘+ M
Ctrl+K リンク([リンクの挿入] ダイアログが開く) ⌘ + K
Ctrl + Shift + D マークアップを挿入([マークアップの挿入] ダイアログが開く) ⌘ + Shift + D
Ctrl+Shift+A マクロ([マクロの選択] ダイアログが開く) ⌘ + Shift + A
Ctrl + Shift + O 次のインライン コメントに切り替え ⌘ + Shift + O
Ctrl + Shift + L 前のインライン コメントに切り替え ⌘ + Shift + L
CTRL + Shift + Z インライン コメントを閉じる ⌘ + Shift + Z
Ctrl + Shift + I ⌘ + Shift + I
Alt + 上矢印 行を上に挿入 Alt + 上矢印
Alt + 下矢印 下に行を挿入 Alt + 下矢印
Ctrl + Shift + X 行を切り取り ⌘ + Shift + X
Ctrl + Shift + C 行をコピー ⌘ + Shift + C
Ctrl + Shift + Y 行を上に貼り付け ⌘ + Shift + Y
Ctrl + Shift + ; 絵文字メニュー ⌘ + Shift + ;
CTRL + Shift + V 書式設定なしで貼り付け ⌘ + Shift + V
書式設定なしで貼り付け (Safari) ⌘ + Shift + Option + V
オートコンプリート

[] が勝手にリンクになるのが困る。

リンク、ファイル、マクロ、メンション、絵文字のオートコンプリート

https://ja.confluence.atlassian.com/doc/autocomplete-for-links-files-macros-mentions-and-emojis-249858190.html

オートコンプリートの無効化方法。

プロフィール画像を選択-[設定]-[エディター]-[☑️オートコンプリートの無効化]

ただ、オートコンプリートの丸ごと無効化は、便利な機能がなくなるので不味い。

一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。


書式なしペースト

Confluenceで書式なしペースト(Ctrl+Shift+V)を有効にする #Confluence - Qiita [?]-[キーボードショートカット]-[General]-[▫️Enable General Shortcuts] にしてオフにすると有効になる。 [表の上部にペースト] と競合していたらしい。

マクロ

マクロ | Confluence Data Center 9.2 | アトラシアン製品ドキュメント

いくつか有用なマクロがある。

Other

パーマリンク

The Differences Between Various URL Formats for a Confluence Page | Confluence | Atlassian Documentation

Confluenceのページ新規作成時、パーマリンクが自動生成される。規則がある。

以下の条件にマッチしたら、padeId URLになる。それ以外は、タイトル名のURLになる。

  • [% & ? / ¥ ; " + :] などのようなURLの予約文字。
  • 非ラテン文字。
  • ページタイトル末尾が英数字以外の場合。
ページ履歴

ページ右上のメニュー-[ページ履歴]から履歴を確認できる。差分も確認できる。

ページ移動

ページの移動と順序の変更 | Confluence Data Center 9.2 | アトラシアン製品ドキュメント

ページ右上のメニュー-[移動]

Tool

General

Call tree

kcachegrindだったかな。

kscopeもこれか。

Doxygen+GraphVizで関数コールグラフ

kscope

https:/github.com/ivan0124/Linux-programming/wiki/How-to-use-KScope-to-trace-code

https:/sourceforge.net/projects/kscope/

http:/www.lemis.com/grog/software/kscope.php

cscope

cbrowser/kbrowserというGUIもある。

cscopeの大文字小文字無視検索

http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html

DBを別にする必要がありそう。

expect

端末の手動操作を自動化するソフト。

  • * ^と$は使えない。代わりに、\nを使う。
  • * 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。
  • * expect文はawkみたいな感じ。
  • * ただし、expectは注意が必要。最初のexpectにマッチしないと先に進めない。タイムアウトとかするしかない。

expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"

https:/linuxjm.osdn.jp/html/expect/man1/expect.1.html

sh -eux <<-"EOT"

expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect aho {send echo aho} +x {send pwd/n}; expect /$; exit"

expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"

expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"

expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'

EOT
踏み台サーバーログイン
expectのオプションに-cで細切れにするのもOK
 
connect 'xxx.xxx.xxx.xxx /ssh /auth=password /user=id /passwd=pw'
wait ''
sendln 'ssh root@<ここにIPアドレスを記入>'
wait 'Password:'
sendln 'pw'

connect 'ip1 /ssh /auth=password /user=sef19a /passwd=ipscp19a'
wait ''
sendln 'expect -c "spawn ssh root@ip2; expect :; send pelican/n; interact"'

sendln 'expect -c "spawn ssh root@ip2" -c "expect :" -c "send pelican/n" -c "interact"'

GNU screen

GNU Screenコマンドをつかってみる #screen - Qiita

screenコマンド実行後に、C-a押下後に対応するキーを押して各種操作を実行する。

キー操作以外に、コマンドも用意されている。C-a :でコマンドラインモードに入る。

特に重要な操作。

  • Help
    • C-a ?
    • Command:help
  • Window
    • C-a c/C-a C/Command:screen=Windowを生成。
    • C-a space/C-a n/C-a C-n/Command:next=次のWindowへ移動。
    • C-a p/C-a C-p/C-a C-h/C-a Backspace/Command:prev=前のWindowへ移動。
  • 画面分割: Regionを分割してそこにWindowを割り当てる。
    • C-a S=横分割
    • C-a |=縦分割
    • C-a TAB/Command:focus=分割画面の移動。
  • クローズ
    • C-a X/Command:remove=現在のRegionを終了。
    • C-a Q/Command:Only=現在以外のRegionを終了。
.screenrc
スタートアップメッセージ
startup_message off
スクロール

linux screen中にマウスホイールでスクロールする方法 - 技術メモ集

デフォルトだとマウススクロールなどに対応していない。以下の設定で対応でき、通常使用で問題なくなる。

termcapinfo xterm* ti@:te@
defscrollback 100000

File

Binary

.so

ソフトウェアの依存関係などの調査で.soファイルの分析を行うことがある。

.soファイルの中のシンボル探し

  • nm
  • ldd
  • string

設定ファイル

https://grok.com/share/c2hhcmQtMw%3D%3D_fb839660-c036-4484-b24f-aa77107db9b3

xml/json/yaml/iniなど設定ファイルの形式がいろいろある。それぞれ長所短所があって使い分けがある。

  • json: パースが高速。コメント未対応。複雑な構文をサポート可能で、データの交換などで使う。
  • xml: 表現力が高い。が、パースはjsonよりは遅い。名前空間など意味論の厳密性が必要な時。
  • yaml: 可読性が高い。コメント対応。人間が頻繁に編集するタイプのデータに使う。
  • ini: シンプルで高速。ネストの表現不能。単純なキーバリューのシンプルな設定だけ。
  • toml
  • HCL (HashiCorp Configuration Language)
  • Protocol Buffers (Protobuf)
  • EDN (Extensible Data Notation)
  • CSV

yamlかjsonで作っておくと無難。

YAML

About

YAML 1.2.2 (2021-10-01) が最新。2001-05-11が初版。dockerなどの設定ファイルで採用されていて一部で人気。可読性が高くて、コメントを記入できて、データ量も少ない。人が手作業で記入する形式として適しているとの評判。

YAML Ain’t Markup Language (YAML™)

Basic
General

インデントで階層構造を表現。インデントはスペースのみ。スペース2個でインデントが主流。

#は行コメント。

---は1ファイル内に複数YAML記載時のセパレーター

リスト

ブロック形式とインライン形式/フロー形式の2種類の記載方法がある。

--- # お好みの映画、ブロック形式
- Casablanca
- Spellbound
- Notorious
--- # 買い物リスト、インライン形式、またはフロー形式
[milk, bread, eggs]
- {name: John Smith, age: 33}
- name: Mary Smith
  age: 27

ハッシュのリストのブロック形式はバレットが1個しかつかないのでちょっと気持ち悪いので注意。

連想配列・ハッシュ
--- # ブロック
name: John Smith
age: 33
--- # インライン
{name: John Smith, age: 33}
men: [John Smith, Bill Jones]
women:
  - Mary Smith
  - Susan Williams

リストのハッシュ。

Scalars

1文字目を|にして改行すると、データ内の改行を維持。>にすると、改行をスペースに置換。

data: |
  There was a young fellow of Warwick
  Who had reason for feeling euphoric
      For he could, by election
      Have triune erection
  Ionic, Corinthian, and Doric
data: >
  Wrapped text
  will be folded
  into a single
  paragraph
  
  Blank lines denote
  paragraph breaks
Other
ブロック/インライン・フローの混在

Swaggerのプロパティーのdescriptionで区分値の説明用に箇条書きを使いたい。

        content:
          application/json:
            schema:
              type: "object"
              required: ["customerNo", "eventNo"]
              properties:
                customerNo: {title: "会員番号", description: "会員番号", type: string}
                actionType:
                  title: アクションタイプ
                  description: |
                    ユーザーのアクション種別。
                    - 1: セミナー申込
                    - 2: 動画視聴,
                  type: integer
                  enum: [1, 2]
                  default: 1

基本はswaggerやyamlはブロック形式が基本になっている。短くてシンプルなところだけインライン・フロー形式を使う。長くなるならブロック形式にする。

親のpropertiesのブロック形式にする必要がある。

Diff

差分確認ツール。コードレビューなどで重要。

About

Macが鬼門。

M1 Macで使用可能なものの選択肢が極端に狭い。

https://chatgpt.com/c/678e249e-84f0-800b-b8da-7385d9aaf819

name OS Free GUI directory image comment
FileMerge Mac x x x Xcode付属ツール。悪くない。が、Mac専用。
P4Merge x x x - x ディレクトリー比較ができないのが惜しい。
DiffMerge x x x x - 悪くない。が開発停止。MacはIntel版のみ。
WinMerge Windows x x x 使いやすい。
Meld Windows/Linux x x x Linux系の標準。悪くない。
kdiff3 Windows/Linux x x x 開発停止。使えなくはない。
vimdiff x x x x - 使いにくい。
Visual Studio Code x x x x x ディレクトリー比較は [Compare Folders - Visual Studio Marketplace] 拡張機能。 画像比較は [Image Preview] らしい。
Intellij IDARE x - x x x
Beyond Compare x - x x x
DiffImg Windows/Linux x x x
PerceptuallDiff x - x
PixelCompare x x

DiffMerge一択になる。ファイルサイズも小さい。大きくても11 MB。

Visual Studio Codeが汎用的だから、こちらでいいかもしれない。

DiffMerge

mac で WinMerge |東京 AI 研究所

FileMerge

Mac純正のファイル差分確認ツール「FileMerge」が使いやすい - Reasonable Code

[/Applications/Xcode.app]-右クリック-[Show content]-[Contents/Applications/FileMerge.app]

コマンドラインからだとopendiff。

Visual Studio Code

About

ディレクトリー比較は [Compare Folders - Visual Studio Marketplace] 拡張機能。 画像比較は [Image Preview] らしい。

VSCode | 2つのファイルの内容を比較して差分を表示する

code -d <file1> <file2>

上記コマンドで差分表示できる。外部の差分ツールとして使う際は、上記コマンドになるように指定する。

GUIからだと、[View]-[Command Pallete]-[Compare] から比較できる。

比較のモードがいくつかある (VS Codeでファイル・ソースコードの差分を比較(diff)する2通りの方法)。

No. 比較モード 用途
1 ファイル: アクティブ ファイルを比較しています...

File: Compare Active File With...

現在のアクティブファイル と 指定したファイル を比較する。
2 ファイル: クリップボードとアクティブ ファイルを比較

File: Compare Active File with Clipboard

Ctrl + Cでクリップボードに保存された文字列 と 現在のアクティブファイル を比較する。
3 ファイル: 新しい無題のテキスト ファイルの比較

File: Compare New Untitled Text Files

比較モードで新規テキストファイルを2つ開いた状態となる。
4 ファイル: 保存済みファイルと作業中のファイルを比較

File: Compare Active File with Saved

未編集状態のアクティブファイル と 前回保存したアクティブファイル を比較する。
5 マージの場合: 現在の競合を比較

Merge Conflict: Compare Current Conflict

Git環境でブランチをマージした時にコンリクト(競合)が発生していないか比較する。

File: Compare Active File Withが素直か。

Diff Folders

VSCode拡張機能「Diff Folders」でフォルダ間の違いを簡単に比較しよう! | UNTIC | Web担当者のための仕事メディア

Diff Foldersの他に、Compare Foldersというのもある。が、Diff Foldersのほうが直感的で使いやすいらしい (is there a compare folders feature in VS Code? - Stack Overflow)。ただ、Compare Foldersのほうがダウンロード数が多い。

標準ではディレクトリー比較はできない。Diff Foldersの拡張機能が必要。

  1. Diff Foldersをインストール
  2. c-P-[Diff Folders]-[New Diff Panel] またはc-L
Compare Folders

VSCodeでフォルダ丸ごと比較する

format

わかりやすい差分(diff)の取り方いろいろメモ #Git - Qiita

diffコマンドの差分表示の形式がいくつかある。

  1. ノーマル
  2. context
  3. unified

contextとunified形式には差分に対象ファイルの情報がある。パッチファイルを作成するなら、この2種にすべきになる。

ノーマル形式は、本当に変更行のピンポイントの情報だけ。

normal
the
quick
brown
fox

jumps
over
the
lazy
dog
the
quick
brown
fox
jumped
over
the

lazy
dogs
% diff a.txt b.txt
5,6c5
< 
< jumps
---
> jumped
8a8
> 
10c10
< dog
---
> dogs

5,6行目と5行目で開業+jumpsのjumpedへの変更 (c=changed)。d=deleted。a=added。こういう形式。

context
% diff -c a.txt b.txt
*** a.txt	2016-08-29 06:43:45.000000000 +0900
--- b.txt	2016-08-29 06:43:59.000000000 +0900
***************
*** 2,10 ****
  quick
  brown
  fox
! 
! jumps
  over
  the
  lazy
! dog
--- 2,10 ----
  quick
  brown
  fox
! jumped
  over
  the
+ 
  lazy
! dogs

2行目から10行目にかけて。

!は変更。+は追加。

unified

diffによるunified形式の意味について - プログラミング以外 - k.bigwheelの日記

gitなど差分ツールでよく使われるunified形式。形式が独特で知っていないと意味不明なので注意する。diff -uオプションでこの形式になる。

$ diff -u test.txt.orig test.txt
--- test.txt.orig       2007-06-10 22:13:55.718311614 +0900
+++ test.txt    2007-06-10 22:54:23.038008776 +0900
@@ -2,9 +2,10 @@
 かきくけこ
 さしすせそ
 たちつてと
-なにぬねの
+なにぬねのん
 はひふへほ
 まみむめも
 やゆよ
 らりるれろ
 わをん
+がぎぐげご

@@の行がが特に重要。

@@ -R +R @@

この書式。-Rが元ファイルの変更箇所、+Rが変更後ファイルの変更箇所。

Rはl,sという形式。lは変更箇所の開始行、sは変更箇所の行数。

-2,9は2行目から9行分変更箇所がある。という意味。

変更箇所の前後の情報を@@で表現している。

ただ、このunified形式は中途半端。視認性重視。

2カラム

diff -yかicdiff --line--numbersは2列で表示してくれるから、視認性が高い。

UML

Tool

https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628

What are the best UML tools for macOS? - Quora

  • デスクトップ
    • StarUML
    • ArgoUML
    • UMLet
    • OmniGraffle
    • edraw: 有料。
    • Umbrello
    • Modelio
  • クラウド
    • Visual Paradigm
    • Lucidchart: 有料。
    • Creately: 有料。
    • diagrams.net: モデルじゃない。
  • その他
    • PlantUML

UmbrelloとModelioはそれらと比較して何がよかったのだっけ?

Eclipse Papyrusが動作するならこれがいい。Eclipseは安定しているから、これのプラグインで動作するなら信頼できるだろう。

papyrusは一度試してダメだった気がするが。

Diagram

クラス図

A=自分 (矢印の元)。B=相手 (矢印の先)

  • 継承関係
    • 汎化 (generalization): 実線白矢印。継承。
    • 実現 (realization): 点線矢印。interfaceの継承。
  • プロパティー単位
    • 関連 (association): 実線。あるクラスが他のクラスのインスタンスを持つ。ただし、所有までいかない。コンストラクターのDIも含む。人と車のように全体-部分の関係がない場合これ。困ったらこれでもいい。
    • 集約 (aggregation): 白菱形実線。関連の特殊系。所有者の方が菱形。所有される側は線。全体-部分の関係。ただし、部分は他の全体からも共有可能。List<T>やSet<T>のメンバー変数があれば集約の可能性が高い。
    • コンポジション (composition): 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。部分が他から共有されない。集約の特殊系。
    • リンク (link): 実線。クラスのインスタンス間の関係。クラス図ではなく、オブジェクト図で使われる。
  • メソッド単位
    • 依存 (dependency): 点線矢印。引数か返却値に使っていて、Bの変更が影響を与える場合。
    • 使用 (usage): 点線矢印。引数と戻り値に使わず、関数内で一時的に使うだけ。依存の特殊系。

ER図

https://grok.com/share/c2hhcmQtMw%3D%3D_49664566-4833-490d-9309-e69597a6ac12

実態関連モデル。Entity-Relationshp Model。関係データベースを抽象的な表現手法。

格納されたデータが、他のデータとどう関係しているかを表現する。

1975年にPeter Chenが発表した。

  • Entyty/実体: 現実世界のものや概念相当。オブジェクト指向のオブジェクト相当。DBではテーブル相当。四角形で描画。
  • Attribute/属性: Entityの特徴や詳細情報。オブジェクト指向のプロパティー。DBではテーブルカラム相当。楕円で描画。
  • Relationship/関係: Entity同士のつながり。オブジェクト指向のメソッド?DBではテーブル間の関係 (外部キーによるリンク相当)。菱形で描画。
  • Instance/インスタンス: DBのレコード (行) 相当。
Relationship

https://grok.com/share/c2hhcmQtMw%3D%3D_861bd847-f9c8-4c01-8887-9802dad8f6e3

関係がわかりにくいので整理する。

Entity (テーブル相当) 動詞の関係をカーディナリティー (多重度) で表現する。3個の関係がある。

関係 関係名 意味
1:1 (One-to-One) <Master> has one <Master> Person/Passport: 1人1パスポート。それぞれ重複がない。PassportにPersonの外部キーを持つ。

Employee/EmployeeDetail: EmployeeDetailのEmployeeの外部キーを持つ。

一方のEntityのインスタンス (行) がもう一方のEntityの1個だけのインスタンスに対応し、逆も同じ場合。情報が密接に関連していて、分離する必要はないが、管理・整理のために分けるケース。

詳細テーブルのパターン。テーブルに持ってもいいが、整理のために別テーブルにしている。 1:多の特殊ケースとみなせる。 実際のところ、1:1が本当に対等ということはほぼない。外部キーを片方に持たせる都合、親子関係がある。子が1個だけという話。逆に、そうできていないなら、Entityの選定・設計の問題を疑ったほうがいい。

1:多 (One-to-Many) <Master> has <Transactions> Department/Employee: Departmentが親でEmployeeが子。Departmentの1行 (ID=営業部) を、Employeeの複数行 (所属従業員) に対応。1従業員1所属の場合。EmployeeにDepartment IDを外部キーとして持つ。親の部門を削除すると子の従業員も影響を受ける。

Customer/Order: Customer (ID=1のA) はOrderの複数行 (注文1-3) に対応。注文は1顧客だけに連動。

一方のEntityのInstanceがもう一方のEntityの複数のインスタンスに対応。逆は多:1だが、1:多でどちらも表現。親子関係のような階層構造で使用する。マスター:トランザクションの関係でも使う。
多:多 (Many-to-Many) <Master> has many <Master> Stundent/Course: Stundentの1行 (ID=1 学生A) はCourseの複数行 (数学、英語) に対応。Courseの1行 (数学) はStundentの複数行 (学生A,B,C) に対応。実装時はEnrollmentテーブル (登録) を作成して、これにStundent IDとCourse IDの相関テーブル+追加情報 (成績) などを入れる。

Product (製品)/Supplier (仕入先): 1商品が複数仕入れ先から調達可能。1仕入れ先が複数商品を供給。

一方のEntityがもう一方の複数のEntityに対応。逆も同じ。両側が独立して複数関連づく場合。DBでは直接実装不能なので、中間テーブルを通常使う。2個の1:多に分解。

マスターテーブルは親的な役割。トランザクションテーブルは子的な関係。通常、マスターテーブル:トランザクションテーブル=1:多。トランザクションテーブルにマスターテーブルの外部キーを持つ。

関係の命名。業務ロジックにあった命名ができればべストだが、一貫性がない。関係からある程度機械的に名前を決める。

  • 1:1=has one
  • 1:多=has
  • 多:多=has many

これがスマート。多対多はis related toもよく使うが、他をhasで表現するなら、こうしないと気持ち悪い。

PlantUML

About

シンプルなテキストでUMLの作成ツール。ツールで機械的に生成できるのがポイント。細かいレイアウトの調整とか、複雑なことをしたい場合、けっこう難しくなる。

そうでなくて、機械的に作成することで、誰がやっても同じで、形式や配置が統一される。それが利点。

Other

対話AI

自分で作成するより、対話AIにお願いして作ってもらって、それを改造する形で作るのが手っ取り早い模様。

シーケンス図やクラス図なんかはそれでいける。

VS Code

About

Visual Studio CodeでPlantUMLを利用する方法(2020/10/30作成) #Java - Qiita

さっと書くだけなら、Webだけでもいい。機密情報とか扱う場合、ローカルでやるといい。

VSCodeの拡張機能でインストールする場合、JavaとGraphvizだけでいい。本体は拡張機能インストール時に同梱される模様。

出力ディレクトリー

VScode PlantUMLで作成するUML画像の出力先を設定する。 - Oboe吹きプログラマの黙示録

デフォルト状態だと、ファイル出力時に以下の形式になる。

out/.puファイル名/@startumlのタイトル.拡張子

最初のoutがうっとうしいのでpuと同じところに出力してほしい。

plantuml.exportOutDir: ".",
plantuml.exportSubFolder: false,

上記設定にするとよい。

ステート図/状態遷移図

状態遷移図の構文と機能

画面遷移図にも使える。

Alias

ステート・状態部分には、スペースや記号を使えない。以下の構文で別名を使って、表示用と内部用をわける。

state "display" as internal
合成状態

状態は合成可能。ブロックにまとめたりできる。 state 状態名 {} で定義する。

@startuml
scale 350 width
[*] --> NotShooting

state NotShooting {
  [*] --> Idle
  Idle --> Configuring : EvConfig
  Configuring --> Idle : EvConfig
}

state Configuring {
  [*] --> NewValueSelection
  NewValueSelection --> NewValuePreview : EvNewValue
  NewValuePreview --> NewValueSelection : EvNewValueRejected
  NewValuePreview --> NewValueSelection : EvNewValueSaved

  state NewValuePreview {
     State1 -> State2
  }

}
@enduml

共通処理を中でまとめたりするのに便利そう。

画面遷移図

https://chatgpt.com/share/6867298c-09bc-800b-89ec-de487215192b

Webアプリケーションの設計書として、画面遷移図が必要なことがある。

UMLでやる場合、アクティビティー図か、ステート図 (状態遷移図) がうってつけ。画面とその遷移アクションの両方を記載できるので申し分ない。

他、一覧表もあり。

実際にいくつか状態遷移図をステートマシン図で書いてみたところ、問題があった。

共通ヘッダーやモーダルの表現が難しかった。コンポーネント化的なことができなくて、同じ画面遷移・状態を複数書く必要があった。モーダルを開いて閉じるというのは、repeatでループで表現できるが、他の画面遷移との併記が難しかった。

これを考えると、ステート図のほうが、矢印の方向が柔軟で、共通化なことができた。

ステートマシン図の例

[*] --> ログイン画面ログイン画面 --> ホーム画面 : ログイン成功 ログイン画面 --> [*] : ログイン失敗 ホーム画面 --> 設定画面 : 設定をクリック ホーム画面 --> [*] : ログアウト

アクティビティー図の例

@startuml(*) --> 個人設定一覧 個人設定一覧 --> [ヘッダー選択] 共通ヘッダー 個人設定一覧 --> [サイドバー選択] サイドバー 個人設定一覧 --> [リスト選択] センター @enduml

https://grok.com/share/c2hhcmQtMw%3D%3D_832592cf-86dd-41eb-a0fa-2fbd656e9299

ステート図で画面遷移図作成時のポイント。

Webページの場合はURLでやるのがいいと思う。

ただ、PlantUML内の状態名は、プログラミング言語の変数名相当だから、_以外の記号は使えない。

state <display> as <name> でnameを定義するといい。_をスラッシュとみなして、全小文字とか。

state "www.example.com" as wwww
state "www.example.com/mypage" as www_mypage

[*] -> www
root -> www_mypage

複数サイトになることがあるから、サブドメイン (なければwww) をベースの名前空間にするのがよさそう。

エイリアス名。url内の記号は除去でいい。exmaple.com/user-profile/editとか。www_userprofile_edit。url内のディレクトリーに記号を使うほうが悪い。全小文字区切り文字なしにすべき。短いほうがいいのだから。

矢印の向き

矢印の向きの制御方法がある。

  • ->: 最短距離。左右になることが多い。
  • -right->/-down->/-up->/-left->: 向きを明示。
  • -->: 長めの矢印。上下になることが多い。
  • -->/..>: 向きには影響しない。
  • top to bottom direction: 全体の向きの明示。

directionで全体の向きを指定しても、->の最短矢印だと、長さが優先される。矢印内で向きを明示するか、-->の長めの矢印を使うとよい。

条件分岐

<<choice>> ステレオタイプで条件付きの状態を指定できる。

@startuml
state c <<choice>>
Idle --> ReqId
ReqId --> c
c --> MinorId : [Id <= 10]
@enduml

やや使いにくいかもしれない。条件がある場合、矢印に説明を入れるといいかもしれない。

アクティビティー図

新しいアクティビティ図のベータ版の構文と機能

記法

https://chatgpt.com/share/68675652-ff90-800b-93ff-19285fe8cf21

PlantUMLのアクティビティー図の記法はレガシー記法とモダン記法とで2種類ある。

最大の違いは、分岐。以前は o --> option1, o --> option2で1個のアクティビティーから複数のアクティビティーに分岐できた。が、これがモダン記法だとできない。

split forkで明確に管理するようになった。パースとかのしやすさ、構文の曖昧性の排除が目的の模様。

split fork

アクティビティーの分岐の記法。2種類ある。紛らわしい。

splitは条件分岐、forkは並列実行的なイメージになっている。

以下の構文。

  • split/split again/end split
  • fork/fork again/end fork
@startuml
start
split
   :A;
split again
   :B;
split again
   :C;
split again
   :a;
   :b;
end split
:D;
end
@enduml

見た目の問題で、splitのほうがすっきりしている。

矢印

矢印にテキストを添えたり、色、線の形式を指定できる。

@startuml
:foo1;
-> You can put text on arrows;
if (test) then
  -[#blue]->
  :foo2;
  -[#green,dashed]-> The text can
  also be on several lines
  and **very** long...;
  :foo3;
else
  -[#black,dotted]->
  :foo4;
endif
-[#gray,bold]->
:foo5;
@enduml
モーダル

モーダルのような一時的に開いて戻る場合、反復可能なので、repeatで表現するとエレガント。

@startuml
' PlantUMLソースコード
start
repeat :ホーム;
->モーダルを開く;
:モーダル;
repeat while ([閉じる] 選択) is (yes)
stop
@enduml

ただ、モーダル以外の他の画面遷移が少々苦しくなる。repeat内でsplitすればいけなくはないが。

モーダルを閉じる動きはstopでいいかもしれない。

ER図

PlantUMLでは2種類のER図に対応している。Chen's notationは2024-04導入の新しい模様 (plantuml/CHANGES.md at master · plantuml/plantuml)。

Chen notation

Entity Relationship diagram (Chen's notation)

chenの記法がER図そのものできれい。これを使う。ただ、Chen notationはnoteの注釈機能が使えなくて、見た目はいいけど、機能不十分。IEのほうがよさそう。

@startchen

entity "DJ.CUSTOMER" as DJ_CUSTOMER {
  Number <<key>>
  Name
}

entity MOVIE {
  Code <<key>>
}

relationship RENTED_TO {
  Date
}

RENTED_TO =1= DJ_CUSTOMER 
RENTED_TO -N- MOVIE

@endchen

https://grok.com/share/c2hhcmQtMw%3D%3D_db38ab26-68a2-4a0b-b1e4-dc231e51279b

  • entity=テーブル。属性がなくても改行した波括弧が必要。少々気持ち悪いが。
  • attribute=属性: entityの波括弧内に記述。<<key>>のステレオタイプでキーを表現。下線がつく。
  • relationship=関係: has/belongs_toとかを記載するのが無難。user-order=places/student-courses=enrollsとかわかるなら動詞も。
    • 太字 (total participation): 親テーブルに埋め込まれている外部キーがNOT NULLの場合。単独存在がなくて存在必須なので。

entity名に.とかは入れられないのでasで別名で回避 (https://grok.com/share/c2hhcmQtMw%3D%3D_1d81495e-fd3c-4f3c-8fc4-19b2d4f391b2)。

https://grok.com/share/c2hhcmQtMw%3D%3D_aa8d7730-69dd-4d58-b88a-8edea922b3c8

属性はネストできる。これは概念的な話。例えば、住所は市区町村や番地、建物名とかに分解できる。が、物理DBだとこれらは展開済み。グループ化の話。別にネストしなくてもいい。

親子関係

オブジェクト指向の継承関係を表現できる。

  • ->-: 矢印の方向が親。
@startchen

entity CUSTOMER {
}

entity PARENT {
}

entity MEMBER {
}

CUSTOMER ->- PARENT
MEMBER -<- CUSTOMER

@endchen
ステレオタイプ
  • <<key>>: 主キー。
  • <<derived>>: 他の属性からの計算カラム。
  • <<multi>>: enum形式。
IE

ER図の文法と機能

Information EngineeringベースのER図。既存のクラス図の拡張記法。クラス図でできることは全部できる。

classの代わりにentityを使うところが主な違い。

インフォメーションエンジニアリングの関係線
Type 記号
0か1 |o--
1のみ ||--
0以上 }o--
1以上 }|--

波括弧}が複数。|が1、oが0を意味する。

関係線の記法だけ注意が必要。

エンティティ

基本はクラス図と同じ文法。他の違い。* は必須を意味する。

シーケンス図

シーケンス図の構文と機能

->でメッセージを描く。参加者の明示的な宣言は不要。

分類子の宣言

参加者の宣言は不要だが、デフォルトだと四角になる。actorとかDatabaseとか見た目を調整したい場合、participantでを宣言しておく。

変数の型名のように、以下の分類子

  • actor
  • boundary
  • control
  • entity
  • database
  • collections
  • queue
  • participant (初期値)
<分類子> <参加者>[ as 別名]
@startuml
participant Participant as Foo
actor       Actor       as Foo1
boundary    Boundary    as Foo2
control     Control     as Foo3
entity      Entity      as Foo4
database    Database    as Foo5
collections Collections as Foo6
queue       Queue       as Foo7
Foo -> Foo1 : To actor 
Foo -> Foo2 : To boundary
Foo -> Foo3 : To control
Foo -> Foo4 : To entity
Foo -> Foo5 : To database
Foo -> Foo6 : To collections
Foo -> Foo7: To queue
@enduml
メッセージに付けるノート

メッセージのすぐ後ろにキーワード note left または note right を使用し、メッセージにノートを付けることが可能です。

end note キーワードを使って、複数行のノートを作ることができます。

@startuml
Alice->Bob : hello
note left: this is a first note

Bob->Alice : ok
note right: this is another note

Bob->Bob : I am thinking
note left
a note
can also be defined
on several lines
end note
@enduml
メッセージのグループ化

次のキーワードを使えば、メッセージをまとめてグループ化できます。 alt/else opt loop par break critical group表示するテキスト ヘッダ部分に文字列を追加することが可能です。(groupについては、後述の「groupの2つ目のラベル」を参照) グループを閉じるにはキーワード end を使用します。

@startuml
Alice -> Bob: Authentication Request

alt successful case

    Bob -> Alice: Authentication Accepted

else some kind of failure

    Bob -> Alice: Authentication Failure
    group My own label
    Alice -> Log : Log attack start
        loop 1000 times
            Alice -> Bob: DNS Attack
        end
    Alice -> Log : Log attack end
    end

else Another type of failure

   Bob -> Alice: Please repeat

end
@enduml

groupでは、[]の間に2つ目のラベルを設定し、ヘッダに表示させることができます。

@startuml
Alice -> Bob: Authentication Request
Bob -> Alice: Authentication Failure
group My own label [My own label 2]
    Alice -> Log : Log attack start
    loop 1000 times
        Alice -> Bob: DNS Attack
    end
    Alice -> Log : Log attack end
end
@enduml
ライフラインの活性化と破棄

activateとdeactivateで分類子の活性化を表現。例えば、関数の実行中とかが四角になってわかりやすい。

が、やや記述が複雑になるので注意する。

@startuml
participant User

User -> A: DoWork
activate A

A -> B: << createRequest >>
activate B

B -> C: DoWork
activate C
C --> B: WorkDone
destroy C

B --> A: RequestCreated
deactivate B

A -> User: Done
deactivate A

@enduml

autoactivate onにすると勝手に活性化してくれる。returnで解除する。昔はなかった気がする。このautoactivate on。

ただ、これを使うと、途中でif文でreturnする倍とかの表現が面倒になるので注意する。

@startuml
autoactivate on
alice -> bob : hello
bob -> bob : self call
bill -> bob #005500 : hello from thread 2
bob -> george ** : create
return done in thread 2
return rc
bob -> george !! : delete
return success

@enduml

returnを使うと自動的に活性化してくれるのでこれを活用するのがいい。

@startuml
Bob -> Alice : hello
activate Alice
Alice -> Alice : some action
return bye
@enduml
活性化、非活性化、生成のショートカット記法

対象の分類子を記述した直後に、次の記法を使うことができます。

  • ++ 対象を活性化する (続けてを記述することもできます)
  • -- 起点側を非活性化する
  • ** 対象のインスタンスを生成する
  • !! 対象のインスタンスを破棄する

クラス図

クラス図の構文と機能

メソッド

クラス名:に続けて記載する。他に波括弧。

丸括弧があればメソッド。なければプロパティー。

@startuml
Object <|-- ArrayList

Object : equals()
ArrayList : Object[] elementData
ArrayList : size()

@enduml
@startuml
class Dummy {
  String data
  void methods()
}

class Flight {
   flightNumber : Integer
   departureTime : Date
}
@enduml
可視性
文字 可視性
- private
# protected
~ package private
+ public
注釈とステレオタイプ
注釈の詳細
フィールド(フィールド、属性、メンバー)またはメソッドへの注釈

フィールド (フィールド、属性、メンバー) に注釈を追加できる。

left/rightのみ可能。名前空間区切り文字列に::を指定した場合、使用不能。

@startuml
class A {
{static} int counter
+void {abstract} start(int timeout)
}
note right of A::counter
  This member is annotated
end note
note right of A::start
  This method is now explained in a UML note
end note
@enduml

以下の書式。

note <direction> of <class>::<attribute>
end note

インラインは不能。

Reference

PlantUML Language Reference Guide

Creole

Use creole syntax to style your texts

特殊文字

&#XXXXまたは、<U+XXXX>の構文、または直接記述することで、任意のUnicode文字を使うことができます。

らしいが、&#XXXX形式は解釈されなかった。<U+XXXX>は有効だった。

Escaping special characters in PlantUML | Jawira blog

noteのブロックの先頭に'を書きたい場合、コメント扱いされてしまう。

<U+0027>でユニコード文字表記にすれば回避できる。

21 共通コマンド

General and common command to handle graphic layout in diagrams.

コメント
  • シングルコメント: シングルクォート'で始まる行はコメント。
  • ブロックコメント: C言語と同様だが/' '/ で囲む。
タイトル
title タイトル
title
end title

タイトル部分は\nで改行できる。他にブロック形式だと改行を含められる。

キャプション

captionでキャプション。

フッターとヘッダー

footer/headerブロック。

凡例

legend/end legend

21.9 メインフレーム
mainframe This is a **mainframe*

タイトルみたいに枠で囲んでくれて見た感じがよくなる。

25 前処理
25.5 プロシージャー [!procedure, !endprocedure]

テキストを出力する。

25.6 return関数 [!function, !endfunction]

マクロの扱い [脱W〇rd, 脱E×cel, 脱@st@h : #14 - messyなkitchenなブログ]

過去の!define相当。テキストの値として使う。

Umbrello

Problem

altなどの重なり順番、アクティブの下になっちゃう

optの条件が表示されない。

Papyrus

Papyrus Dowloads

Papyrus Documentation

Tutorial

公式の[A slide-ware tutorial on Eclipse Papyrus usage for starters (2010-10-01)]を参考に基本的な使い方を学ぶ。

[File]-[New]-[Papyrus prooject]

これでプロジェクトを作ると、以下が [Project Explorer] に作られる。

  • <project name>
    • <project name>
      • di: ツールメタデータ。モデル作成のエントリーポイント。
      • notation: 画像データ。
      • uml: UMLモデルデータ。

このdiをダブルクリックして描画を開始する。

1個のプロジェクトでいろんな図に対応していて、モデルを流用できる形になっている。悪くない。これを使う。

画面構成

  1. Project explorer
  2. Model explorer: 一番重要。ここでモデル全体をツリーベースで管理する。
  3. Outline view: アウトライン
  4. Main toolber: ツールバー。
  5. Perspective: Model explorerの内容を使って作図する領域。
  6. Property view: モデルのエディター画面。

Model explorerがPapyrusの本質。ここでクラスとかインタラクションを定義しておいて、この定義をperspectiveの作図に使うイメージ。

クラス図やシーケンス図もModel explorerに所属していて、好きなだけ作れる。[New diagram]から作れる。

[New Child] でいくつか重要なモデルがある。

  • Package: ディレクトリ・フォルダーみたいなもの。これで他のモデルをまとめて整理できる。
  • Interaction: シーケンス図表現用のモデル。
  • Class: クラス。Interactionの型だったりする。UMLのベースで非常に重要。

Class

属性表示

クラス図にクラスモデルを配置しても、プロパティーやメソッドが表示されない。

右クリック-[Filters] で制御できる。

  • [Synchronized with Model] を選ぶと同期されて全部表示される。基本はこれで、一部だけ表示したい場合にここを外すのだろうと思う。
  • [Show/Hide Contents] で表示可否をチェックボックスで選べる。
Modelへのジャンプ

クラス図などからオブジェクトのModel Explorerの元データにジャンプしたいことがある。

オブジェクト右クリック-[Navigate]-[Go to ...]-[Model Explorer] を選ぶ。

Comment

https://chatgpt.com/c/67aec9f8-6be0-800b-b6eb-6300425ad1d4

メソッドなどにコメントを入れたいことがある。このコメントがわかりにくい。

[Properties]-[Comments]-[Owned comments]-[Body] に入力する。初回+で作ったダイアログのBodyに入力したものは反映されなくて、一度空のコメントを作った後に、洗濯後横のBodyに入力すると反映される模様。

  • Applied comments=他のモデルのコメントを取り込みたい場合に使う。
  • Owned comments=自分自身のコメント。コメントに対してコメントをつけることもできるので、[Create a new Comment] はさらに [Comments] タブを持っている。このタブがコメントのコメント。基本は使う必要ない。

[Annotated element] でたぶん、Bodyに入力したコメントを複数の要素に適用したい場合の適用先だと思う。

Sequence diagrams

https://eclipse.dev/papyrus/resources/PapyrusTutorial_OnSequenceDiagrams_v0.1_d2010100.pdf

2.2 Adding messages (basic - asynchronous)

コミュニケーションは、メッセージの交換で描写される。

メッセージはoperationCall (同期/非同期) かsignal (非同期) コミュニケーションとして表現される。

synchronousCall作成時は、replyMessageも期待される。

createMessageとdeleteMesageの指定は、ライフラインの動的な有無を意味する。

Papyrusでのメッセージ作成は以下の手順で構成される。

  1. パレットからツールを選択。
  2. ソースLifelineの開始点をクリック。
  3. ターゲットLifelineの終了点をクリック。
  4. ポップアップの該当するsignal/operationを選択。

記法

  • 非同期メッセージは中抜き矢尻 (arrow head)。
  • 同期メッセージは塗りつぶし矢尻。
  • 返信メッセージは波線 (dashed line)。
  • オブジェクト作成メッセージは波線+中抜き矢尻。
  • Lost Messageは黒丸矢尻。
  • Found Messageは黒丸矢柄。
2.2.1 Select desired tool from the palette
  • Message SyncとMessage Replyは [Execution Specifications] がないと使えない。
  • Message createはターゲットポイントが存在時に使用可能。
2.2.2 Select source and target points

ソースとターゲットポイントは2の異なるライフライン (通常) か、同じライフライン (再帰) が選択可能。

ターゲットポイントの制限は、対象の要素に依存する。例えば、Synchronous CallはExecution Specificationから始まる必要がある。

2.3 Adding execution specification

ここまでのシーケンス図では、通信シナリオだけを想定してきた。が、実際には、完全な実行トレースを表現できる。Execution Specification (ES) は実行を表す抽象概念で、Action Execution SpecificationとBehavior Execution Specificationの2種類がある。

PapyrusではライフラインにESをセットして行う。ESをセットしたら、同期メッセージを追加できる。

開発プロセスでは、予備設計では全メッセージを非同期とみなしておいて、設計時にESを設定して、同期メッセージをする感じ。

ただ、同期メッセージは、応答メッセージが入ってごちゃごちゃする。単にシーケンス図を書くだけなら、非同期で全部書いてもいいと思う。

Undoで破損

シーケンス図を作成して、削除のUndoを何回かやると、データが破損して開けなくなる。対応方法不明。GitでPapyrusのファイルを管理しておいて、破損に対応しておいた方がいい。

再帰自己呼び出しシーケンス図

シーケンス図の描画に癖があるので、方針を固めて使用する。

  1. 自己関数の呼び出しはMessage Async/Message Reply。Message Syncは期待通りに配置されないので、自己関数には使わない。他のライフラインには使う。
  2. 関数の呼び出し期間はAction Execution Specificationを配置。
  3. 矢印の端にESを配置する形にする。
オブジェクトの移動

オブジェクトの移動に癖がある。基本的に、メッセージは始点、終点で別々に移動させるしかない。まとめて選択して一括移動ができない。

終点を移動させると、その下のオブジェクトも追随する。追加はこれで対応できる。減らすのは手間になる。

シーケンス図が大きくなりすぎないように注意する。

Coding

タイムゾーン

タイムゾーン呪いの書 #timezone - Qiita

3文字形式は避けたほうが無難。

タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。

tz databaseのAsia/Tokyoなどの確実性が高い。

Regular Expression

正規表現。重要。覚えにくいが重要なものをメモしておく。

BRE

BREs Matching Multiple Characters

複数文字に一致するBREを作成する記法 (量指定子) がある。

単一文字、部分式、後方参照のいずれかに一致するBREの後に、'\{m\}', '\{m,\}', '\{m,n\}' の形式の配置で、指定回数の連続に一致する。

  • mとnの範囲: 0<=m<=n<={RE_DUP_MAX}の範囲の10進数。
  • mは最小出現回数、nは最大出現回数。
  • \{m\}: m回出現
  • \{m,\}: m回以上
  • \{m,n\}: m-n回出現

例: abababccccccdに対する"c\{3^}"は7-9文字目でマッチ。

単一文字の量指定子
* {0,} と同じ
+ {1,} と同じ
? {0,1} と同じ
POSIXクラス

言語によって、アルファベット順が違うことがある。エストニア語ではsの後にzがあり、[a-z]では全ての英字にマッチしない。ロケールに依存する。

これの排除のために、文字の区分を定義している。

POSIXクラス 対応正規表現 意味
[[:upper:]]
[[:lower:]]
[[:alpha:]]
[[:alnum:]]
[[:digit:]]
[[:xdigit]]
[[:punct:]]
[[:blank:]] [ \t] スペースとタブ。
[[:space:]] [ \t\n\r\f\v] スペースとタブ+改行類。
[[:cntrl:]]
[[:graph:]]
[[:print:]]

特に以下が重要。

  • [[:alnum:]]
  • [[:space:]]

[:X:]が[]内で使える構文の扱い。組み合わせる場合、[[:upper:]ab]という感じで外側各括弧に収める。

ERE

基本はBREと同じ。エスケープ\が不要になっている。

多くのプログラミング言語などでは、EREが基本。grep -E相当。

PCRE

EREをさらに以下で拡張したもの。

  • POSIXクラスの拡張表現の文字クラス
  • 量指定子の追加構文 (+ ?)
  • 言明/assertion
量指定子/Quantifiers
  ?           0 or 1, greedy
  ?+          0 or 1, possessive
  ??          0 or 1, lazy
  *           0 or more, greedy
  *+          0 or more, possessive
  *?          0 or more, lazy
  +           1 or more, greedy
  ++          1 or more, possessive
  +?          1 or more, lazy
  {n}         exactly n
  {n,m}       at least n, no more than m, greedy
  {n,m}+      at least n, no more than m, possessive
  {n,m}?      at least n, no more than m, lazy
  {n,}        n or more, greedy
  {n,}+       n or more, possessive
  {n,}?       n or more, lazy
  {,m}        zero up to m, greedy
  {,m}+       zero up to m, possessive
  {,m}?       zero up to m, lazy

BRE/EREで登場した量指定子。デフォルトではgreedy (貪欲) マッチで、最長マッチ。

量指定子の末尾に?で最短マッチ (lazy)。

量指定子の末尾に+で独占的 (possessive)。マッチを消費する。処理の高速化になる。

言明/assertion

言明 (assertion) はカレントマッチング位置の直前・直後の文字に対するテスト、条件付け。文字を消費しない。テストのみ。

if文相当。直接マッチしないで、条件へのマッチ。マッチ対象文字を消費しない。

正規表現内で、if文相当の条件判定する際に使用する。

BREの段階で^$ (アンカー/anchor) があった。これの大幅拡張。

例えば、フォームの検証で「特定文字種が含まれていること」+9-12文字のような複数の条件指定を実現できる。

複雑な言明はサブパターン (言明サブパターン/assetion subpattern) を用いる。カレント位置の先と後とで2種類ある。

anchors
  ^           start of subject
                also after an internal newline in multiline mode
                (after any newline if PCRE2_ALT_CIRCUMFLEX is set)
  $           end of subject
                also before newline at end of subject
                also before internal newline in multiline mode
simple assertions
  \b          word boundary
  \B          not a word boundary
  \A          start of subject
  \Z          end of subject
                also before newline at end of subject
  \z          end of subject
  \G          first matching position in subject
LOOKAHEAD AND LOOKBEHIND ASSERTIONS
  (?=...)                     )
  (*pla:...)                  ) positive lookahead
  (*positive_lookahead:...)   )

  (?!...)                     )
  (*nla:...)                  ) negative lookahead
  (*negative_lookahead:...)   )

  (?<=...)                    )
  (*plb:...)                  ) positive lookbehind
  (*positive_lookbehind:...)  )

  (?<!...)                    )
  (*nlb:...)                  ) negative lookbehind
  (*negative_lookbehind:...)  )

肯定否定。=で肯定、!で否定。

  • (?: 先読み。言明の次、右側を判定。
  • (?<: 戻読み。言明の前、左側を判定。

先読み言明 (lookahead assertion)

例えば、以下のパターンはセミコロンが後に続く単語にマッチする。

\w+(?=;)

言明は複数同じ場所に配置可能で、AND条件になる。ORにしたかったら、(?<=abc|abde) のように選択肢にする。

以下はbarが後ろに続かないfooにマッチする。

foo(?!bar)

以下はfoo以外の後のbarではない。

(?!foo)bar

全部のbarにマッチする。この言明の直後の3文字がbarの場合、(?!foo)が常に真になるから。

言明の先読みは、基本は右端に配置する。右端の後に何か続ける場合、\w+とか使う。言明自体は文字を消費しないから、言明部分をカバーできるタイプの文字クラスの併用が必要。

echo preg_match('/foo(?=bar)\w+$/', 'foobar.'); # 0

Case

後ろからマッチ。cが置換対象。

/[^c]*$/

cより右端

マッチの前後の挿入

https:/vim.fandom.com/wiki/Power_of_g

:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/

行頭・行末で引っ掛ける。

関数にログ
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g

考慮するケース

double currentTime() const override { return m_element->currentTime(); }
フォーム検証

https://grok.com/share/c2hhcmQtMw%3D%3D_0c3a03bf-35f1-4594-a5d8-21673072ada5

英字と数字がそれぞれ1文字以上、かつ9-12文字。

戻読み言明と量指定を併用する。

$password = "123456333d78"; // テスト用のパスワード

$options = [
    'options' => [
        'regexp' => '/^(?=.*[[:alpha:]])(?=.*\d).{9,12}$/'
    ]
];

if (filter_var($password, FILTER_VALIDATE_REGEXP, $options)) {
    echo "パスワードは有効です。";
} else {
    echo "パスワードが条件を満たしていません。";

ただ、filter_inputだと検証失敗の理由まで特定して取得できない。面倒だが1個ずつやるしかない。関数化すれば1回で済む。

glob

重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。

使用可能な記号は以下3個。以下の3文字は\でエスケープできる。

  • ?: 任意の1文字にマッチ。
  • *: 任意の0以上の文字にマッチ。
  • [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。

ファイル名マッチ時には、追加で特殊なルールがある。

.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。

globで.ファイルを含めたい場合、工夫が必要 (PHP: glob - Manual)。

.[!.]* *

上記のように.ファイルのマッチとそれ以外を指定する必要がある。

.[!.]* は、...以外の..始まりのファイルにマッチする。

.*を指定すると、./..がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、.*だと. /..はマッチしない。

引用符のネスト

シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。

JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。

交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。

問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。

二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。

基本的な方法。

  1. 既存の一重/二重引用符などをバックスラッシュでエスケープ。
  2. 全体を一重/二重引用符で囲む。

何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。

[{"ke\y":"valu\e"}] を例として考える。

  1. {"ke\y":"valu\e"}
  2. エスケープ: {\"ke\\y\":\"valu\\e\"}
  3. 全体囲み: "{\"ke\\y\":\"valu\\e\"}"

これでOK。また何か考慮不足があればそのときに考える。

ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。

例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。

echo $(cat <<-'EOT'
{"ke\y":"valu\e"}
EOT
)

.envなどで使える技?いや使えない。.envではシンプルなコマンドしか使えず、ヒアドキュメントは使えない模様。

JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。

基本的な考え方がある。

  1. JSON value用に二重引用符"を\"で置換。
  2. \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
  3. JSON項目の二重引用符"を\"で置換。
  4. 全体を二重引用符"で囲む。

こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。

ケース変換

javascript - camelCase to kebab-case - Stack Overflow

キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。

encode

【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ

日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。

  • パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
  • UTF-8
  • base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
  • HTMLエンコード: HTMLで特殊な意味を持つ文字を&lt;などに変換する。

Percent-encoding

unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

上記文字はエンコードの対象外。

英数変換

string - PHP How to encode all characters with rawurlencode - Stack Overflow

変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。

こういう目的だと%エンコーディングが適している。

ただし、一部の記号を許可しているので、自前で変換する。

function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}

$str = 'big ƒüßchen';
print_r(encode_all($str));

Term

紛らわしい用語がある。

フレームワークの中にライブラリーも含めていいと思う。

Pythonのモジュールとパッケージとライブラリとフレームワークの違い」がわかりやすい。

フレームワークはライブラリーを含んでいる。ライブラリーで共通でいいと思う。

Category

ソフトウェア開発工程 - Wikipedia

ソフトウェアの分類、ページ分類時に役立つ。

  • 言語
  • ツール: 静的解析、テスト、文書など。
  • フレームワーク

MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。

  • PHP language
  • PHP tool
  • PHP framework

成功時連続継続処理

一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。

  1. 処理実行。
  2. 成功ならA、失敗なら終了。
  3. 処理実行。
  4. 成功ならA、失敗なら終了。

こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。

        /*
        // 無限ループで終了条件でブレイク
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
        
        // do while
        do {
            処理実行
            if (成功時) {}            
        } while ();

        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */

do-whileは成功・終了判定を2回書く必要がある。

forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。

いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。

これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。

offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?

        $offset = 0;
        while (true) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);

            $response = $service->getApiResultJson();
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;

            // 2回目からはヘッダー除去して書き込み。
            $start = strpos($response, "\n") + 1;
            $flat = FILE_APPEND;
            if ($offset === 0) {
                $start = $flag = 0;
                $path = stream_get_meta_data($fp = tmpfile())['uri'];
            }
            file_put_contents($path, substr($response, $start), $flag);
            $offset += $limit;
            sleep(3);
        }
        for ($offset = 0;
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
            (function() use (&$offset, $limit, $response) {
                // 2回目からはヘッダー除去して書き込み。
                $start = strpos($response, "\n") + 1;
                $flag = FILE_APPEND;
                if ($offset === 0) {
                    $start = $flag = 0;
                    $path = stream_get_meta_data($fp = tmpfile())['uri'];
                }
                file_put_contents($path, substr($response, $start), $flag);
                $offset += $limit;
                sleep(3);
            })()
        ) {
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
                json_encode([
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
            $response = $service->getApiResultJson();
        }

character

BOM

UTF-8のBOM

\xef\xbb\xbf

この文字を先頭につけるとUTF-8のBOMになる。

Convert

IP/CIDR

// JavaScript
    /**
     * サブネットマスクをIPアドレス形式 (x.x.x.x/255.255.255.0) からCIDR形式 (x.x.x.x/24) に変換する。
     * @param {string} ipaddress - IPアドレス文字列 (x.x.x.x/x.x.x.x形式)。
     */
    toCIDR(ipaddress) {
      const [address, mask] = ipaddress.split('/')
      const segments = mask.split('.')
      const CIDR = segments
        .map((e) => Number(e).toString(2))
        .join('')
        .replace(/0*$/, '').length
      return address + '/' + CIDR
    },
    /**
     * サブネットマスクのCIDR形式 (24) をIPアドレス形式 (255.255.255.0)に変換する。
     * @param {number} cidr - ciderの数字。
     * @return {string} x.x.x.x形式のIPアドレス文字列。
     */
    cidrToIp(cidr) {
      const digit = 32
      const ip = ('1'.repeat(cidr) + '0'.repeat(digit)).substr(0, digit)
      return ip
        .match(/.{8}/g)
        .map((e) => parseInt(e, 2))
        .join('.')
    },

Algorithm

再帰処理

https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950

配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。

再帰関数で実装するほかに、スタックで処理する方法がある。

再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。

パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。

最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。

https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5

再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。

JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。

シンプルなケース以外は、再帰関数で処理したほうが結局シンプルな感じがする。

Other

コメントの著者名

https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08

GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。

大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。

git blameで行単位で編集者が分かる。

確率処理

https://chatgpt.com/share/68145e5c-9d14-800b-9cca-1cd9e46e2dd6

ある確率で処理をしたり、しなかったりしたいことがある。

$chance = 30; // 30%の確率

if (mt_rand(1, 100) <= $chance) {
    // 30%の確率でここに入る
    echo "当たり!";
} else {
    // 70%の確率でこっちに入る
    echo "はずれ...";
}

乱数を作成して、それで確率値の超過判定で表現できる。



Architecture

About

https://grok.com/share/c2hhcmQtMw%3D%3D_d762a384-9703-4539-b8e7-022bc680d88f

  • MVC
  • MVVM
  • クリーンアーキテクチャー

このあたりが有名。MVCが一番無難。MVCでは厳しいような大規模になったら、他を検討する価値がある感じ。

Clean Architecture

クリーンアーキテクチャー。最近よく聞く設計手法。

Clean Coder Blog」で2011-11-22にRobert C. Martinによって提唱さえたアーキテクチャー。ソフトウェアの開発・展開・運用・保守を簡単にして、プログラマーの生産性の最大化が目的。

多くのアーキテクチャーでは、関心を分離して、異なる役割や責務を分離して、変更の影響を最小限にしている。これの実現に、ソフトウェアをレイヤー (層) に分けている。クリーンアーキテクチャーは、このアイデアの1個のガイドラインになっている。

中心にビジネスルールがあって、玉ねぎのように、中心から外に向かって、層構造になっている。

  1. エンティティ: ビジネスロジック (ドメイン層)。外部の影響 (FWの更新など) に影響を受けない。
  2. ユースケース: アプリのビジネスルール。interface adapterから受け取ったデータをもとに、entityのビジネスロジックを組み合わせて、アプリ特有のロジックを実現。
  3. Interface Adapter (Controller/Gateway/Presenter): 外部システムと内部システムのデータを変換する。例えば、コントローラーはリクエストをUsecaseが利用できる形式に変換 (4->2) し、プレゼンターはユースケースの出力を外部システムが理解できる形式に変換 (2->4) する。
  4. Framework/Driver (DB/Device/Web Framework/UI/外部Web API): WebアプリケーションFW、DBなど。外部エージェントとの通信処理。基本的にはライブラリーやFWを使う。

基本はこれだけ。

既存のMVC型アプリをクリーンアーキテクチャーにする場合の対応。

  • Controller: Interface adapter
  • Model: Entity (domain/repository interface)
  • View: Framework

たまねぎの層構造の表現は、ディレクトリーの親子関係で表現できるときれいなんだけど。層ごとでグループ化したり、継承したりする場合に、ディレクトリーを作れなくて困る。大規模になるならなおさら。

中小規模や、うまく分割してきれいにまとめられるならあり。

一般的には、機能を最上位において、その下で4の層をディレクトリーで配置するというのが多い模様。

src/
└── Article/
    ├── Domain/
    ├── Application/
    ├── Interface/
    └── Infrastructure/

SSR+CSR

About

https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45

バックエンドとフロントエンドの分離の話。

SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部する (CSR) というのが最近の流行。

SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。

SSRの利点。

  • SEO
  • 初期表示。
  • 匿名。

SSRの課題。

  • サーバー負荷: データとHTML作成を同時に行うから。
  • 分散困難:

キャッシュの活用がポイントになるとのこと。

リダイレクト

https://chatgpt.com/share/6886c2c2-b5cc-800b-8e03-e301c22d5eff

CSRでやる場合、最終的にCSRの成果物をstaticに生成して、それをサーバー側のpublicに配置する感じになる。

npm run generateの生成先をpublicに直接してもOKだと思う。いや、これは既存のindex.phpとかが消えるのでまずい。シンボリックリンクにするとか。

1台でフロントとサーバーの両方を扱う場合、/apiなどサーバーリクエストに使うURLはindex.phpに、それ以外はindex.htmlなどにするようなリダイレクト設定が必要。

以下のようなイメージ。

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_URI} ^/(api|sanctum)(/|$)
    RewriteRule ^ index.php [L]

    # Nuxtのビルド済み静的ファイル (_nuxt/) は除外
    RewriteCond %{REQUEST_URI} ^/_nuxt/
    RewriteRule ^ - [L]

    # RewriteCond %{REQUEST_FILENAME} !-f [OR]
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ - [L]

    RewriteRule ^ index.html [L]
</IfModule>

Naming

Code

camelCase

https://gnusocial.jp/notice/7694551

!it 命名規則のキャメルケース。これ英語前提です。関数名に英語以外を使うと破綻します。

getキーバリュー()みたいな関数の定義。日本語ですると境界がわからなくなるので、getキー_バリューみたいにアンダーバーで区切ったほうが分かりやすい。なるほど…

getMyVariable() vs myVariable()

getterとsetterの命名規則。

getVar()にするか、Var()にするか。C++だと後者のパターンがあったりする。getを省略できるので、省スペースになる。

ただ、コード補完で探しやすさがちょっと変わる。getを前置したほうがわかりやすいか。

namePrefixed() vs prefixedName()

https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85

名詞+修飾語 (形容詞) の場合のメソッドの命名規則。name+修飾語が複数ある場合name+修飾語がいい。オブジェクト指向でnameをオブジェクトとして扱う形に近い。name.methodみたいな。

例えば、nameMax、nameMinのような場合は後ろのほうが都合がいい。ただ、こういう場合はそもそもnameをオブジェクトにしてname.max()、name.min()にしたほうがいいという説がある。

そうではないならば、getPrefixedName()などが自然。getQueryString()など。StringQueryではない。

PHPでは以下のような命名規則が好まれる。

  • 動詞+修飾対象=getPrefixedName/isPrefixed()
  • 修飾対象+状態/修飾語=prefixdName

getPrefixedNameがいいか。後置修飾にしたいならば、そもそもオブジェクト+メソッドにすることを検討する。

map

連想配列とかハッシュ、オブジェクトなどでキーバリュー形式のデータ構造を扱うことがある。そういう変数の命名規則。

map_[key]_[value] のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。

https://chatgpt.com/c/67ca84e0-9018-800b-9674-035ae9f4bbaf

  • [key]_[value]_map
  • [key]_to_[value]

上記のどちらかがいいだろう。toがkey_valueの区切りが明示的でいいかもしれない。

array/foreach

foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。

foreach (table as $row => $line)

その際の変数名は、上記のように$row/$lineにすると、行番号と行の値がはっきりしてわかりやすい。

いいえ。これは問題がある。ネストした場合などに命名規則を維持できない。

  • 配列、コレクション類: 複数形があるなら複数形。困ったらListの接尾辞。
  • 反復時。キーバリュー形式の場合、単数形_key/_value。valueだけの場合、単数形。また、_valueは単数形でもいいかもしれない。

上記の命名規則だとわかりやすい。

$rows = [[]];
foreach ($rows as $row_key => $row_value) {
  foreach ($row_value as $column_key => $column_value) {}
}


foreach ($row_list as $row_key => $row) {
   foreach ($row as $column_key => $column) {
   }
}


foreach ($rows as $row_index => $row_value) {
  foreach ($row_value as $column_index => $column_value) {
  }
}

value部分に単数形を使うと、検索時にkey部分もヒットして、作業しにくいかもしれない。基本はkey/valueの接尾辞がよいと感じる。

もっというなら、接尾辞の文字数が揃うので、keyよりindexのほうがよいかもしれない。ただ、indexは添え字の数字の意味合いが強いので、やっぱりkey/valueでいいか。

Function argument order

関数の引数は入力、変更、出力の順番にする。理由はこの順番で使うから。

https://social.senooken.jp/notice/67270

うーん。今晩は,CODE COMPLETEでC言語の関数の引数の順番を調べたりしていて,勉強時間がないな…

int func(入力,変更,出力)

この順番。理由は,この順番で使うから。

memcpyとかは例外が多い。

x = bの語順からきているからとの憶測がある。

https://okwave.jp/qa/q4202225.html

get/fetch

https://chatgpt.com/c/67bd1a05-d3a0-800b-88d8-f4f47b995560

  • fetch=外部から取得する意味。DBや外部Web APIから取得する場合にfetchがいい。
  • get=手元から取得する意味。プロパティーなど内部から取得する場合。
list/data

fetchList/fetchDataのどちらがいいか?

  • list=配列。必ず配列。
  • data=全部。配列以外にnullや単一データがあるならこちら。

基本はfetchListでいいと思う。

Order

https://chatgpt.com/c/67ca7edf-f92c-800b-8174-9706bfba3ff3

関数実行の順番が大事なときと、そうでないときがある。区別し難い。

順序を明示したい場合、メソッドチェーンを使うのが確実。

他に、前の関数の結果、戻り値を後続の引数に渡すなら、それも悪くない。

privateの先頭_

privateなメソッド、プロパティーで、先頭に_をつけることがある。

https://chatgpt.com/c/67da92b1-1650-800b-b347-f16f76fd549a

privateのアクセス権、可視性の機能があるなら、それを使えばいいので、_は不要。むしろないほうがいいらしい。PHPのPSR-12では禁止されている。

PSR-12: Extended Coding Style - PHP-FIG

Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning.

Pythonのように、言語的にないなら、やむを得ない。

PHPは昔privateがなかったので、そういう古いコードとの一貫性の維持が目的なら、先頭_もあり。

配列の要素数

https://chatgpt.com/c/67ecd6ff-b06c-800b-8f44-cfeb9c5768bb

配列の要素数、長さを変数に格納して使うことがけっこうある。その際の変数名。

オブジェクト指向に従うなら、配列名_size/countの接尾辞がいい。

C++のvectorなどのコンテナーだと.size()でとれる。変数に格納せずにsizeでいい。

変数にあえて代入するならば、配列名_sizeが自然。

ただ、PHPだと、countで要素数を取得する。その都合で、_countがよい。

item_list = [];
item_list_size
item_list_count
例外前提関数

https://grok.com/share/c2hhcmQtMw%3D%3D_359ae291-e39d-42cd-9a8f-e6453b388993

APIのパラメーターチェックとかで、チェック関数を何個も書くなら、例外を投げる形にして、それを補足する形が楽になる。

        $result = $this->locationCheck($mbrcode, $latitude, $longitude, $ostype);
        if ($result['status'])
            return ['message' => $result['message'], 'status' => $result['status']];
        $result = $this->isCheckedIn($mbrcode);
        if ($result['status'])
            return ['message' => $result['message'], 'status' => $result['status']];
        $store = $this->isStoreNearby($latitude, $longitude);
        if (!$store['status'])
            return ['message' => $result['message'], 'status' => self::STATUS_STORE_NOT_FOUND];
        $result = $this->addPoint($mbrcode, $ostype, $store['pattern'], $store['shpcode'], $store['point']);
        if (!$result['status'])
            return ['message' => $result['message'], 'status' => self::STATUS_ERROR];
        try {
            $this->locationCheck($mbrcode, $latitude, $longitude, $ostype);
            $this->isCheckedIn($mbrcode);
            $store = $this->isStoreNearby($latitude, $longitude);
            $this->addPoint($mbrcode, $ostype, $store['pattern'], $store['shpcode'], $store['point']);
        } catch (Exception $e) {
            return ['status' => $e->getCode(), 'message' => $e->getMessage(), 'point' => 0];
        }

関数の戻り値を都度if文でチェックする必要がなくなってスマートになる。

そういう、例外前提関数の名前。isXXXとかにするとboolを期待する。

assertXXXにするとわかりやすい。assertは例外を投げたり、中断するイメージがあるから。

validateだとどっちもありえるからわかりにくい。

条件のbool変数・関数化

https://grok.com/share/c2hhcmQtMw%3D%3D_dabd40dd-e42b-44be-931c-b1cc18425c5d

if文の条件式の内容は、複雑になるなら基本的に変数・関数に括り出して適切な名前を付けたほうがいい。

コメントで記載することもできるが、コメントが古くなるリスクがある。

拡張子、サンプルファイル

https://grok.com/share/c2hhcmQtMw%3D%3D_d3c100c1-f1be-47c4-8f36-1710af04a2c1

app/config.php.sampleのように、アプリのデフォルト設定をファイル末尾に追記する形でファイルを用意することがある。これの是非。

基本は、app/config.sample.phpのように、拡張子は意味のあるものにする。

Webアプリの公開ディレクトリーなどで、誤動作を抑止するなら、拡張子を明示的に分ける意味がある。

が、他のアプリや構文強調などはファイル拡張子で判断するので、普通は困る。

Other

Document

設計文書を作成する際、MS Word系で作るのが無難。

画面系の設計の場合、1画面に入りきらないかもしれないが、部分ごとに分割画像にして、1ページに画像と説明を併記する形にして、縦に長い文書にするほうが管理しやすいと思う。

ExcelやPowerpointで1枚丸ごとにしてい気持ちもあるが。だったら、Figmaとかそういうデザインツールとか、Inkscape/LibreOfficeDrawとかだろうか。

ただ、やっぱり目次とか欲しいからMS Word系がいいと思う。

Atomic Design

最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。

  • atoms: 原子。これ以上分割不能な最小単位。input/label/buttonなど。
  • molecules: 分子。atomsを組み合わせたり、atomsに多少修正したもの。入力フォーム、ナビゲーション、カードなど。
  • organisms: 有機体。分子+アルファ。入力フォーム+ヘッダーなど。複数の分子。
  • templates: テンプレート。複数の有機体。ヘッダー、メイン、フッターなど。
  • pages: ページ。テンプレートを使用したページ。

インターフェイスと抽象クラス

オブジェクト指向でよく登場するインターフェイス、抽象クラス、クラスの違い。

  • インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
  • インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。

インターフェイス

  • メソッド宣言のみ。
  • static/constの場合に限定して、メソッド定義、定数もOK。
  • 多重継承可能。
  • tagのイメージ。

例えば、複数のクラスで共通の処理がある場合、その共通部分をInterfaceにして、それを継承すると良い。その部分だけ取り出して流用できる。

例えば、[Animal<-Duck] のような関係がある時、Duckは空も飛べるし、泳ぐこともできるとしたら、飛べることと泳げることの機能はAnimalの中でも対応がわかれる。こういうところをInterfaceにしておくと、振る舞いを統合できる。

抽象クラスは一部共通にしたい場合に使う。Interfaceは指定機能を全部共通。

ベースは抽象クラス、クラスにしておいて、複数クラスで共通にしたい場合interfaceで定義するときれいに実装できる。

Config class

アプリケーションの設定を管理するクラスの設計方法。いくつか方法があり、議論がある。「Best way to provide configuration parameters for objects far away from the starting point - Software Engineering Stack Exchange」で特によく議論されている。

  1. シングルトン/グローバル変数: ただし、テストなどで並列アクセスが必要な場合に困ることがあるらしい。
  2. DI/設定クラス引数: これがよく支持されている。テストしやすいなど。グローバル変数への参照を渡すようなイメージ。ただし、依存性の伝播のように、上から下に設定を渡す際に、関係ない大量の設定を渡すことがあったりする。

2のDIが最近の主流。引数で値渡し相当にすれば、並列アクセス時も無影響。伝播の問題は設計の問題。

メソッドをmain関数で呼び出すことを想定して、必要なものだけ渡るようにして、余計なものは削除する。上位・下位の関係を明確にすれば、渡すだけのパラメーターを排除できる。

do-while/if

複雑なif文と相性がいい。

for whileの無限ループで最後にbreakでも同じか

do {
  if (true) break;
} while(false);

if文が複雑な場合、do-whileで囲んで、breakでスキップできる。gotoに近い。

GoF

デザインパターン (ソフトウェア) - Wikipedia

基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。

これにより、いろんなケースに同じコードで対応できる。

23パターンある。23パターンのうち16パターンは言語サポートで単純化か除去できる。

  • 生成5個
    1. Abstract Factory
    2. Builder
    3. Factory Method
    4. Prototype
    5. Singleton
  • 構造7個
    1. Adapter
    2. Bridge
    3. Composite
    4. Decorator
    5. Facade
    6. Flyweight
    7. Proxy
  • 振る舞い11個
    1. Chain of Responsibility
    2. Command
    3. Interpreter
    4. Iterator
    5. Mediator
    6. Memento
    7. Observer
    8. State
    9. Strategy
    10. Template Method
    11. Visitor

特に頻出パターン

  • Strategy
  • Observer
  • Decorator
  • Factory Method
  • Adapter
  • Singleton

このほかに、アーキテクチャーごとに、パターンがある。

  • Repository: DDD、クリーンアーキテクチャー。Adapterパターン内部で使っているデータ保持用の役割。
Factory Methodパターン

なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)

コンストラクターの代わりに、インスタンスを生成 (工場=factory) となるメソッドを使うから、FactoryMethodパターン。

引数の内容に応じて、異なるクラスを作成する。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

// Creatorに相当する
abstract class ListPrinter {
    // anOperationに相当する
    public void printList(List<String> list) {
    }

    // factoryMethodに相当する
    protected abstract Comparator<String> createComparator();
}

// ConcreteCreatorに相当する
class DictionaryOrderListPrinter extends ListPrinter {
    @Override
    protected Comparator<String> createComparator() {
        return new DictionaryOrderComparator();
    }
}


// ConcreteCreatorに相当する
class LengthOrderListPrinter extends ListPrinter {
    @Override
    protected Comparator<String> createComparator() {
        return new LengthOrderComparator();
    }
}

// メインクラス
public class FactoryMethodSample {
    public static void main(String args[]) {
        List<String> list = Arrays.asList("いちご", "もも", "いちじく");

        System.out.println("五十音順で表示:");
        new DictionaryOrderListPrinter().printList(list);

        System.out.println("長さ順で表示:");
        new LengthOrderListPrinter().printList(list);
    }
}

return new <Class> 的なことをするメソッドのパターン。

  • オブジェクトの生成処理を1か所に集約できて、生成処理が複雑な場合 (前準備や引数が多い場合など) 使う側をシンプルにできる。
  • 条件によって別の子クラスを返したり、キャッシュを使ったりできる。

ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。

Factory MethodとAdapterを併用すると、OSごとやDBの違いを吸収することができる。

https://chatgpt.com/share/6876fa52-d850-800b-81f0-78bb0d44a7ba

FactorySelectorみたいなクラスで、createAdapter的なので、違いを隠蔽して取得するとよさそう。

Adapterパターン

重要。FWやライブラリーを抽象化するパターン。

XxxAdapterというクラスを作って、特定のメソッド経由で、目的のクラスにアクセスする。

interface ProductPrice{
  public int getPrice();
}

class Product{
  private int cost;
  public int getCost(){
    return cost;
  }
}

class ProductAdapter extends Product implements ProductPrice{
  public int getPrice(){
    return this.getCost();
  }
}

継承の他に、移譲 (Adapter内でのインスタンス生成) でも実現できる。DIと相性がいいかもしれない。

interface ProductPrice{
  public int getPrice();
}

class Product{
  private int cost;
  public int getCost(){
    return cost;
  }
}

class ProductAdapter implements ProductPrice{
  private Product product = new Product();
  public int getPrice(){
    return product.getCost();
  }
}

上記では、Product.getCost (製品価格) をProductAdapter.getPriceのメソッド名でアクセスする。既存のクラスを一切変更することなく、getPriceという別のメソッド名で、目的のメソッドにアクセスする。

例えば、Windows/Mac/Linuxのように、異なるOSでOSのバージョン番号を取得するような場合、Adapter経由でアクセスすれば、同じメソッド名で異なるOSのAPIにアクセスできる。FWやライブラリーのバリエーションの違いを吸収できる。

OOP

継承とtrait

https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe

apcとstaticのキャッシュクラスがあって、それとは別にビジネスロジックの共通化をしたい場合、いくつか方法がある。

  1. apc と static を統合した親クラスで trait を use し、子クラスで継承する
  2. apc と static を子クラスで直接継承し、trait を use
  3. 継承(extends)ではなく、キャッシュクラスを別のクラスとして利用する という考え方です。
依存注入(DI)・継承・trait の使い分けまとめ

https://chatgpt.com/c/67cea053-9f50-800b-b22f-67aea7ac0dfe

キャッシュやORMのような、切り替え可能な機能の場合、DIで実装してプロパティーに格納して使うのが使いやすい。DIはテストのしやすさに勝る。

継承は親子関係が明確な場合。

コンストラクターのアクセス権

基本はpublicだが、privateとprotectedを指定する場面がある。デザインパターンと関係している。

https://chatgpt.com/c/67fdac9a-2fac-800b-91bf-460c10fd72f5

  • protected: 継承先のみ。ベースクラスや抽象クラスで使用する。ベースクラスや抽象クラスは継承を前提とするから、直接インスタンス生成してほしくないから。ファクトリーパターンと組み合わせる。
  • private: クラス内部のみ。シングルトン・ユーティリティー (静的ファクトリーメソッド専用クラス) 系クラスで、インスタンスを作って欲しくない、1個だけのように、インスタンスの生成数を制限したい場合。
例外の扱い

https://chatgpt.com/share/68118e39-40d0-800b-9bd8-43da8908bfcd

DBアクセス系のメソッドは例外を基本的に出す。

DBアクセス系メソッドを使って、特定のデータを取得するようなメソッドを使った場合に、例外をどこで処理すべきかという話。

現代的なフレームワークだと、アプリのエントリーポイント (index.php) などにtry-catchが1個あって、そこで自分で処理しなかったらデフォルトの例外処理で処理する形になる。

なお、try-catchは並列実行、マルチスレッド環境では問題があったりする。

throwにコストがかかる。だから、頻繁に失敗するような処理は、try-catch (throw) を使わない形で実装したほうがいい。リアルタイム性や超ハイパフォーマンスが必要なところとか。

PHPはリクエスト単位で、プロセス・スレッド起動する設計になっている。ApacheやFPMがそういう動作になっているから。だから、マルチスレッドは考えなくていい。並列実行は、別リクエストみたいな扱い。

APIに複数アクセスする場合、curl_multiで1プロセスでうまくやる方法があるらしい。

関数戻値と例外

https://chatgpt.com/share/6833c48c-ce58-800b-a4d7-f389d15167e9

関数が失敗した場合に、戻り値nullで返すか、戻り値false相当で返すか、例外で返すかという議論。

例えば、配列を返すようなメソッドで、処理失敗時に空配列ではなくて、nullを返して失敗を表すか、あるいは例外で返すべきかという議論。

nullの代わりにデータ型でboolになる値を返す (配列なら[]、数値系なら0、文字列なら'')。

項目 利点 欠点
ブール 型が同じなので扱いやすい。 失敗と結果を厳密に区別したいときに、できないことがある。
null 失敗と結果を厳密に区別可能。 使う側で常にnullチェック必要。
例外 型を統一でき、失敗も区別できる。 エントリーポイントにtry/catchがないとtry/catch地獄。

基本は型は同じで、どうしても処理失敗の区別が必要なら、例外にする。これにするとシンプルで融通がきく。

例外にする内容。

  • 処理続行が不能な場合 (DBアクセス失敗)。
  • ビジネスロジックで意図的に続行不能にしたい場合 (想定外の頻繁アクセス、保安対策?)。
  • 期待と異なる場合 (1件取得できないといけないのにできないとき)。
DI

https://chatgpt.com/share/682e8fd6-376c-800b-a01e-faa832b0fd07

Dependency Injection。主にテストしやすさを向上させるための手法。

クラスやメソッド内部で、他のクラスを使う場合、コンストラクターや、メソッドで該当クラスを受け取って、プロパティーや変数として参照する。クラス (依存性) を外部から渡す (注入) すること。

こうすることで、該当メソッドのテスト時に、中で使用する外部クラスを外部から置換できる。これにより、テスト対象メソッドの処理だけをテストできる。

DIの注入方法で2通りある。

  • コンストラクターDI: public/protectedメソッド向き。一般的にDIという場合これ。
  • メソッドDI: privateメソッド向き。特定メソッドだけでしか使わない場合、あまり使わない場合。

使用する外部クラスが複数ある場合、DIでその分指定する。あまりにも数が多い場合、DTOやデリゲートなど複数クラスを保有するクラスを作って、それを引数に渡す。あるいは、依存クラスが多すぎる場合、設計に問題がある。適切に分割した方がいい

なお、メソッドDIにする場合、DI対象は引数の先頭の方に指定する。必須で省略不能だから。

DB

PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note

DBアクセスのモデル化。行をクラスとする (entity/エンティティークラス) と扱いやすい模様。

getterを作ったり、データの妥当性のチェックなどもできる。

select/insert/などはmapperでクラスとDB列名を対応付けて処理する。自前で実装する場合はこういうつくりがいいらしい。

データベース関係のデザインパターンがいくつかある。

  • Active Record
  • Data Mapper
Active Record pattern

テーブルレコードに対応するクラスを用意して、そのクラス自体にDB操作もさせる。

シンプルだが、複雑な操作が苦手。

エンティティーがテーブルと密接なため、例えばテーブル構造が変わった場合に大量に修正必要。

Ruby on Rails/Laravel+Eloquentなどで採用。

Data Mapper pattern

第14回 DataMapperの使い方 | gihyo.jp

テーブルのレコードをクラスにするのはARと共通。

ただし、DB操作用のクラスを用意してそちらでDB操作する。

その都合、1テーブルに2クラス必要。

User/UserMapperのような対応関係。

2クラス必要だが、テーブル構造が変わった場合でも基本はMapperで吸収できる。

JOIN

Active RecordもData MapperもJOIN時の扱いが一番重要。単一エンティティーしか扱わないならどちらも同じ。

基本はエンティティーのプロパティーに持たせる感じ。

datamapperパターンでjoinする場合、エンティティーの扱いはどうなるの?

`DataMapper`パターンで`JOIN`を行う場合、エンティティの扱いは設計次第ですが、いくつかの注意点があります。`DataMapper`パターンは、データベースのテーブルとエンティティの間にマッピングを行い、エンティティはドメインロジックを持ち、データベースアクセスの責務を持たないことが特徴です。そのため、`JOIN`の処理をどの層で行うかを慎重に設計する必要があります。

以下、`JOIN`を行う際のエンティティの扱いと実装方法について解説します。

      1. 1. マッパークラスでの`JOIN`実装

`JOIN`を伴う複雑なクエリが必要な場合、マッパーが直接`JOIN`を使って複数テーブルを組み合わせた結果を取得し、それを複数のエンティティとしてマッピングする方法があります。例えば、ユーザーと注文を持つシステムで、ユーザーとその注文を一緒に取得したい場合、`UserMapper`で`JOIN`を行い、結果セットを`User`と`Order`エンティティに分割してマッピングします。

```python

class UserMapper:

    def find_user_with_orders(self, user_id):

        sql = """

            SELECT * FROM users

            JOIN orders ON users.id = orders.user_id

            WHERE users.id = %s

        """

        results = self.db.execute(sql, (user_id,))

       

        user = User(results[0]['user_id'], results[0]['user_name'])

        orders = [Order(row['order_id'], row['product_name'], user) for row in results]

        user.orders = orders

        return user

```

この方法では、1つのSQLクエリで必要なデータをすべて取得し、エンティティのプロパティにそれぞれのデータを設定します。

      1. 2. リポジトリでの集約

`JOIN`を使わず、各エンティティを個別に取得した後、リポジトリが集約の役割を担う方法もあります。リポジトリが各エンティティの`Mapper`を呼び出し、必要なエンティティ同士を関連付けることで`JOIN`を再現します。例えば、まず`UserMapper`でユーザー情報を取得し、次に`OrderMapper`で該当ユーザーの注文を取得してエンティティ間で関連付けます。

```python

class UserRepository:

    def __init__(self, user_mapper, order_mapper):

        self.user_mapper = user_mapper

        self.order_mapper = order_mapper

    def get_user_with_orders(self, user_id):

        user = self.user_mapper.find(user_id)

        orders = self.order_mapper.find_by_user_id(user_id)

        user.orders = orders

        return user

```

UserテーブルとOrderテーブルがあって、あるユーザーの注文一覧を取得したい場合を考える。

結局、user.ordersみたいな感じで、エンティティーに外部テーブルのレコードを配列で持たせるつくりになる。

クロス集計する場合は、users[0].orderみたいな感じ。メインのエンティティーのプロパティーに持たせる。フラットじゃないのでちょっと気持ち悪い。が、まあ構造としてこうなるのは順当。

方法として、1回のSQLで取得するか、それぞれのエンティティーを取得してマージするか。1回のSQLでやったほうが当然いい。

Other

1対1-多対多

プログラミング言語でデータの関連付けをすることがある。

1対1の場合、配列、連想配列のキーバリュー形式のデータがぴったり。

多対多の場合。これも配列。二次元配列で基本は0要素目など。

$array[][]
1対多

https://chatgpt.com/share/683faf08-f374-800b-ac40-b96b427d7365

例えば、DBからデータを取得した場合など、1行のデータに複数列あって、列を特定したい場合、連想配列で、バリューをさらに連想配列にするのが普通。ただ、1:1ならただの連想配列でよかったのが、連想配列の配列になるのがイマイチ。

['row1' => ['col1' => 'value1', 'col2' => 'value2']]

いくつか方法がある。

  1. ネスト連想配列。無難。
  2. 連想配列の代わりにオブジェクト。これができるならこれが素直。
  3. 連想配列の代わりにリスト。ただし、列の意味が分かりにくい。foreach ($map as $interface => [$property, $defaultClass])
  4. 値部分を意味のある文字列で使うところで分割とか。

手短にしたいなら、3のリストになるかも。

レガシープロジェクトの立て直し

https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002

1. 現状分析

(1) ソフトウェアの動作確認

現在の環境でアプリケーションを動作させる。

どの部分が機能していて、どこが問題かを確認する。

必要であればエラーログを確認する。

(2) 依存関係の調査

アプリケーションのライブラリやフレームワークのバージョンを調査。

サポートが終了しているもの、互換性が失われたものを特定。

(3) コードベースの状態評価

コードの品質 (可読性、設計、テストカバレッジ) を確認。

セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。

2. 計画立案

(1) ゴール設定

具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。

(2) 優先順位の決定

どの機能を維持し、どの機能を削除または置き換えるか決定。

ユーザーに直接影響を与える部分を優先。

(3) リスク評価とバックアップ

修正に伴うリスクを評価し、現行システムのバックアップを取得。

3. 環境整備

(1) 開発環境のモダナイズ

ローカル環境やコンテナ (Docker) を用意してテストを容易にする。

CI/CD パイプラインの整備。

(2) 依存関係の更新

サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。

(3) セキュリティの確保

古いOSSの脆弱性を修正。

HTTPSの導入、認証強化、インプット検証など。

4. コードのモダナイズ

(1) リファクタリング

レガシーコードをよりモダンで可読性の高いコードに変換。

デザインパターンを適用して保守性を向上。

(2) テストの追加

ユニットテスト、統合テストを導入。

既存の機能が壊れないことを確認するための自動化されたテスト。

(3) フロントエンド/バックエンドの分離

必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。

5. 機能拡張とデプロイ

(1) 新しい機能の追加

必要に応じて、現代のニーズに合った新機能を実装。

(2) 運用環境でのテスト

新しい環境で徹底的にテストし、問題がないことを確認。

(3) 本番環境にデプロイ

ロールバック計画を準備しつつ、安全にデプロイ。

6. 継続的改善

(1) モニタリングの導入

エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。

(2) 定期的なアップデート

フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。

(3) コミュニティへの貢献

OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。

このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。

AI

対話AI

About

List

【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM

いろいろある。

Name
Bing
Perplexity AI
ChatGPT
Google Gemini
書きかけ送信

https://grok.com/share/c2hhcmQtMw%3D%3D_ca8dab5f-1012-4dd4-841f-7340186071d7

書きかけの状態で誤送信することがある。

元の質問を編集するのではなく、続きに「これが正しいです」とか書いて送信すると、AIが認知して対応してくれるらしい。

編集すると、ややこしくなる。

Grok

Xアカウント

https://x.com/i/grok/share/oeybkVEqzC4NNpH8whCdM7pl7

grok.comのgrokはスタンドアローン。x.com/i/grokはXアカウントを考慮する。後、xのほうは制限が厳しめ。

grok.comにXアカウントでログインできる。その場合、多少Xアカウントを考慮したりする。が、設定でオフにもできる。

Xアカウントでログインでいい気がする。

感想

https://grok.com/share/c2hhcmQtMw%3D%3D_abb58ded-75b5-470e-a6c3-586a53904071

ChatGPT

Plan

ChatGPT | OpenAI

Free/Plusの2のプランがある。

Free Plus
金額 [USD/月] 0 20
機能 基本 アーリーアクセス
エンジン GPT-4o mini GPT-4/GPT-4o/GPT-4o mini
制限 - GPT-4oの5倍以上のメッセージ送信
その他 - データ分析、ファイルアップロード、ビジョン、Webブラウジング
画像生成 - DALL-E

送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。

Account

公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。

ChatGPTに会員登録する意味は何ですか?


ChatGPTに会員登録する主な利点はいくつかあります。

1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。

2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。

3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。

4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。

5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。

興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。

自分の過去の質問の履歴を見れるだけでも便利かも。

方法
質問の分割

https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c

Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?

A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。

感想
2024-11-14 Thu

https://gnusocial.jp/notice/7806505

!it !ai 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。

例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。

https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2

getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。

こういう検索エンジンで検索しにくい質問で便利だなと思います。

検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。

大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。

個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。

同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。

一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。

2024-11-19 Tue

https://gnusocial.jp/notice/7867350

!ai ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。

phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85

私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。

この間、 @yuriha に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?

対話AIだとお気持ちの配慮いらないし、当たり前ですけど、キチガイ扱いされることもないので、快適です。元々対話AIには懐疑的でしたが、どちらかというと私のようなキチガイが凡人健常者の知識を拝借するためにあるような印象を持ちます。

検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。

もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。

凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。

AI Coding

AIコーディング:「Vibe Coding」からプロフェッショナルへ

個人的 Vibe Coding のやりかた

雰囲気だけを伝えて、AIにアプリ開発を任せる手法。一切自分でコーディングしなくてもアプリ開発可能。

Shell

2 Shell Command Language

2.9 Shell Commands

2.9.2 Pipelines

Shell Command Language

pipelineは|で区切られた1以上のコマンド群のこと。標準出力を次のコマンドに接続する。

パイプラインの書式は以下となる。

[!] <command1> [ | <command2> ...]

予約語の!がなければ、最後のコマンドの終了ステータスがpipeline全体のステータスになる。!があれば、ステータスの否定になる。つまり、0なら1、0超過なら0になる。

パイプラインだが、ifやtest以外のどこでも使える。

ただし、対話シェルだと!は履歴置換になることがあるので注意する。

2.9.4 Compound Commands

Shell Command Language

Case Conditional Construct
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac
  • 未マッチで終了ステータス0。
  • pattern部分: シェル展開が有効。他はglob。
  • |でOR検索相当。
  • 最後のパターンの;;は省略可能。if文のようにも使える。
  • 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。

BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。

ワイルドカード

ワイルドカードで.始まりのファイルをマッチさせたい。

以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。

echo {.*,*}

BOM

unicode - Adding BOM to UTF-8 files - Stack Overflow

ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。

printf '\xEF\xBB\xBF' > with_bom.txt

上記コードでBOMを最初に書き込んで、後は追記する。

Command

awk

The Open Group Base Specifications Issue 7

変数
特別
  • NF: 列数。列の全表示などで使う基本的で重要な変数。
  • NR: 行番号。
スコープ

変数のスコープ

関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。

文/statement
  • actions
    • if/else
    • while/do...while/for
    • break/continue
    • delete
    • next
    • exit
  • output
    • print
    • printf
関数
組込関数
  • Arithmetic
    • atan2
    • cos
    • sin
    • exp
    • log
    • sqrt
    • int
    • rand
    • srand
  • String
    • gsub
    • index
    • length
    • match
    • split
    • sprintf
    • sub
    • substr
    • tolower
    • toupper
  • I/O
    • close
    • getline
    • system

print/printfは関数ではなく、statement/文扱い。

ヘッダー出力、列別最大長さ出力。
awk -F, '{if(NR==1) print $0} {for(i=1; i<=NF; ++i){if (line[i] < length($i)) line[i] = length($i)}} END {for (i=1; i<=NF; ++i) {printf line[i]","}}' data/101542.csv
CSV

シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita

# csvparser.awk

## Usage
# awk -f csvparser.awk data.csv

# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
function callback(row, len, fields,  col, field) {
    for ( col = 1; col <= len; col++ ) {
        field = fields[col]
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
        print row ":" col " " field
    }
}

BEGIN { row = max_idx = 0 }
{
    idx = 0
    sub(/\r$/, "")
    while ($0 != "") {
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
            fields[++idx] = ""
        } else if (match($0, /^["]/)) {
            fields[++idx] = substr($0, 2)
            for (;;) {
                if (getline == 0) exit 1
                sub(/\r$/, "")
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
                gsub(/["]["]/, "\"")
                fields[idx] = fields[idx] "\n" $0
            }
            fields[idx] = fields[idx] "\n"
        } else {
            exit 1
        }
        field = substr($0, RSTART, RLENGTH)
        $0 = substr($0, RSTART + RLENGTH)
        lastcomma = sub(/,$/, "", field) > 0
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
        fields[idx] = fields[idx] field
    }
    if (lastcomma) fields[++idx] = ""
    while (idx < max_idx) delete fields[max_idx--]
    callback(++row, idx, fields)
    max_idx = idx
}

awkのCSVパーサー。先頭のBOMはあると認識できないので、tail -c +4でBOMを除外して使う。

tail -c +4 data/101543.csv | awk -f csvparser.awk 

xargs

About

xargs

xargsは引数リストを構築して、コマンドを呼び出すコマンド。

標準入力から受け取った行を任意の場所に引数として配置して、後続のコマンドを実行する。並行実行とかもできる。

  • -I replstr: 行のプレースホルダー文字列を定義。
  • -t: trace mode。実行したコマンドを標準エラー出力に出力する。
ls -A "$1" | sed -e 's/"/"\\""/g' -e 's/.*/"&"/' |
    xargs -E "" -I {} -t mv "$1"/{} "$2"/{}
複数コマンド実行

https://chatgpt.com/share/6811d6e4-3cdc-800b-946c-305f03df396d

echo "file1 file2 file3" | xargs -n 1 -I{} sh -c 'echo {}; ls -l {}'

sh -cでshの引数の文字列として構築する。こうしないと、内部の;がパースされてうまく解約されない。

Other

patch

文字化け

https://chatgpt.com/share/685cd841-d368-800b-b950-0afc82ea31de

iconvで文字エンコーディングをパッチ適用先ファイルに合わせてから適用する。

iconv -f UTF-8 -t EUC-JP <<'EOF' | patch -p1
--- oldfile.php
+++ newfile.php
@@ -1,3 +1,4 @@
+// これは日本語コメントです
EOF

pager

lessのオプション

lessのおすすめオプション #Linux - Qiita

export LESS="-iMR"
  • -i: 検索時に大文字小文字無視。
  • -m: 表示中の%のステータスバーへの表示。
  • -M: 表示中の行数・ファイル名などのステータスバーへの表示。
  • -R: ANSI Color Escape Sequenceの解釈。

破損リンク

https://chatgpt.com/c/68088168-ac54-800b-b78e-e28743b81011

find path/to/scan -type l ! -exec test -e {} \; -exec rm {} \;
find path/to/scan -type l ! -exec test -e {} \; -print

binary

POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita

バイナリーデータの読込はodコマンド。なければhexdump。

書込はprintf。

head/tailの-cはPOSIXで使えたか?

root

リダイレクト出力

sudo権限でリダイレクト処理を行ってファイルに書き込む方法

リダイレクトはログインユーザーの権限でなされるらしく、root権限のある場所にファイル出力できない。

teeコマンドでやる。

pwd | sudo tee out.dat

teeコマンド実行する側でsudoが必要。


ログインシェルの確認

第 10 章 動作環境のカスタマイズ (Solaris ユーザ ログインシェルはGUIログインでも内部的にある。ログインシェルが読みこむprofileファイルなどは、ログイン時に、1回だけ実行したい処理の記述場所として最適。 SHELL環境変数にログインシェルのパスが入っている。

echo $SHELL
/bin/bash

OSの判別

OSTYPE環境変数に値があるのでこれで判別する。 例えば以下の値が入っている。

linux-gnu
darwin23

これらを検知して判定する。

case $OSTYPE in
  linux*) echo 'linux';;
  darwin*) echo 'Mac';;
esac

Configure

profile

bash の初期化ファイル .profile, .bashrc, .bash_profile の使い分けと管理方針 - A Memorandum

  1. bash_profile
    1. profile
    2. bashrc

環境変数など~/.profileに全部のシェルの共通設定を記述。

上記サイトではこういう方針でやっていた。

ログイン時に、bash_profileとかzprofileとかがなければ、デフォルトで.profileを読込むようになっている。

なので、.profile内で、実行シェルを変数で判定して、bashrcやzshrcを読み込むようにするといい。

上から下にする感じ。ubuntu 22.04のprofileがこういう作りになっている。

# if running bash, include .bashrc if it exists
[ -n "$BASH_VERSION" ] && [ -f "$HOME/.bashrc" ] && . "$HOME/.bashrc"

.profileはログイン時に1回だけ実行すればいいから。

rc

rc=run configuration. 実行設定。

シェルごとにいくつかの設定がある。

Bash

Ubuntu Manpage: bash - GNU Bourne-Again SHell

--loginオプションの指定がある場合や、ログイン対話シェルとして呼び出されるかどうかで変わる。、

ログイン対話シェルの場合 (SSHも含む?)。

  • /etc/profile があれば実行。
  • ~/.bash_profile ~/.bash_login ~/.profile をこの順番で探して、最初に見つけたファイルを実行して終わる。
  • シェル終了時か、非対話ログインシェルの場合、exitコマンド実行時に、~/.bash_logoutをあれば実行。

--noprofileオプションを指定した場合、上記の読み込みはしない。

非ログイン対話シェルの場合。

  • /et/bash.bashrc ~/.bashrcがあればそれぞれ実行。

--norcの指定で上記も読み込まない。--rcfileで/etc/bash.bashrcと~/.bashrcの代わりのrcファイルを指定できる。

非対話シェルの場合、BASH_ENV環境変数を展開して、そのファイルを読み込む。

 if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

~/.profileをスクリプト実行時にも読み込みたい場合、bash_profileでこの環境変数を設定しておくとよいかも。

cmd.exe

Control block

for

あくまでコマンド。

nest

ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。

bitsadmin

Windowsでのファイルダウンロードコマンド

Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。

書式:

bitsadmin /transfer <job name> <URL> <output path>

<job name>と<output path>は必須なので注意する。

certutil

Windowsでのハッシュの確認に使える。

certutil -hashfile file
SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。

rlogin.cmd

コマンドキーの送信を自動化できる?

rem rlogin.cmd

@Echo off
Set SERVER=192.168.0.0
Set USERNAME=
Set PASSWORD=

Cmdkey /generic:TERMSRV/%SERVER% /user:%USERNAME% /pass:%PASSWORD%
Start mstsc /v:%SERVER%
Timeout 5
Cmdkey /delete:TERMSRV/%SERVER%

実行中プロセスのパスの確認

出典: Show EXE file path of running processes on the command-line in Windows - Super User

wmic process get ProcessID,ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST

簡易編集モード/挿入モード

Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。

cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。

そのほか、 git log のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。

[□挿入モード] にすると回避できる模様。

Vim

vimdiff

2 つのファイルの差分を取る・マージする (vimdiff, vim -d) - まくまくVimノート

vimのdiff機能。ファイル同士の差分のチェック、マージで簡易的に使える。

diffモードで起動

vim -d <file1> <file2>
vimdiff <file1> <file2>

起動中のdiffモード

:diffs[plit] <file> " 上下分割
:vert[ical] diffs[plit] <file> " 左右分割
:diffthis " バッファー同士

移動

  • [c=前の差分に移動。
  • ]c=次の差分に移動。

マージ

  • dp=diff put。自分の内容を片方に反映。
  • do=diff obtain。自分の内容に片方を反映。

Other

Async

https:/github.com/skywind3000/asyncrun.vim

asyncrun.vimは1個のバックグラウンド処理しか対応していない。

https://github.com/skywind3000/asyncrun.vim/issues/12

vim-dispatchならいけるのか?

Binary

vim-jp » Hack #133: バイナリファイルを編集する

grep

非同期でgrepする方法。

https://superuser.com/questions/861783/how-to-run-a-grep-in-vim-asynchronously

https://www.reddit.com/r/vim/comments/5ses2e/async_grep_in_vim_8/

Vim 8の非同期APIはプラグイン用。

* https://github.com/mhinz/vim-grepper

* https://github.com/skywind3000/asyncrun.vim

* https://github.com/tpope/vim-dispatch

https://wonderwall.hatenablog.com/entry/2017/10/09/210000

asyncrun.vimでやるのがよさそう。

AnsiEsc

* https:/unix.stackexchange.com/questions/444226/how-to-make-vim-interpret-escaped-characters-as-colors

* https:/superuser.com/questions/358409/how-can-i-tell-vim-to-show-ansi-escape-codes-properly

本家は太字に対応していないのでこちらがいいかな。

- https:/github.com/powerman/vim-plugin-AnsiEsc

ただし、こちらはgvimでクリック時にカーソル位置がずれる。

program

C

ワシのVimプラグインは百八式まであるぞ - daisuzu's notes

【C/C++】

     87. a.vim

        C/C++のヘッダとソースを切り替えます。

     88. c.vim

        C/C++のテンプレートやイディオムの入力をサポートしてくれます。

     89. CCTree

        cscopeを使って関数のコールグラフを表示してくれます。

     90. Source-Explorer-srcexpl.vim

        ソース解析ツール、Source InsightのVim版です。

     91. trinity.vim

        taglist, srcexpl, nerdtreeを同時に起動して

        VimがIDE画面のような画面になります。

     92. cscope-menu

        cscope用のメニューを表示してくれます。

     93. gtags.vim

        gtagsを使ってファイルを開けます。

     94. DoxygenToolkit.vim

        Doxygenコメントの入力をサポートしてくれます。

Visual Studio Code

Keybind

矩形選択

Ref: VS Codeの矩形選択と矩形貼付の操作方法 - mito’s blog.

  • s-alt-クリック
  • c-s-alt-矢印

ジャンプ

  • 括弧ジャンプ: C-S-\

Config

Default terminal

Ref: bash - Change the default terminal in Visual Studio Code - Stack Overflow.

[F1]-[Terminal: Select Default Profile]

cscope

cscope用のプラグインが何個かある。

scope4codeのほうがいろいろできそうだが、うまく動作しなかった。使い方がよくわからない。

cscope-codeはシンプルだが動作した。こちらを当分使うことにする。

Macの場合、control-. sのように、control-.の後に、controlを話してsを押すと発動する。カーソル下のシンボルしか使えない感じなのがネック。まあいい。

Vim

VSCodedでVimのキー操作を使うためのプラグイン。これが一番人気。いや、Vimのエミューレーターは中途半端な感じだから使わないほうがいいかな。

Extension

CSS

Tailwind CSS IntelliSense

PHP

Laravel Blade Snippets

PHP Intelephense

Ref: PHP Intelephense - Visual Studio Marketplace.

VSCodeのPHPの補完拡張として人気が高い。

Quick Start

設置後、しておくべき設定がある。

  • Go to Extensions.
  • Search for @builtin php
  • Disable PHP Language Features. Leave PHP Language Basics enabled for syntax highlighting.

VSCodeの [PHP Language Features] を無効にしておくとのこと。

後は、.php以外の拡張子でPHPファイルがあれば、関連付けを追加するとか。

"files.associations": { "*.module": "php" }
Module

peclなどPHPの標準モジュールで一部認識できないものがある。

php - Undefined type 'Imagick' in VSCode's intelephense - Stack Overflow」にあるように、そういう場合は [Settings]-[Stubs] で追加するとよい。

Coding

Ref: VSCode で PHP 開発するならインテリセンス最強の intelephense を使おう | 株式会社ビヨンド.

intelephenseでコード補完を認識しやすい書き方というのがある。

まず、型をつけられるものはつける。

function superMethod()
{
    /** @var AwesomeService $awesomeService */
    $awesomeService = $this->app->make(AwesomeService::class);
    $awesomeService->awesomeMethod();
}

ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。

include Path

開発対象コードが、.envなどに記載の環境変数を前提として、動きになっていたりすることがある。そうなると、この環境変数を参照できないと、認識できない。

include Pathsに追加する。

他、.php以外の拡張子は基本的にinluce pathにあっても認識しない。"intelephense.files.associations":に拡張子を追加する。

Settings

Files: Insert Final Newlines

Resolve 'No newline at end of line' in GitHub | DevCoops

gitで以下の警告が表示される。

\ No newline at end of file

デフォルトでファイル終端に改行を挿入しないから。設定がある。

Settings-Files: Insert Final Newline

これをオンにすると、保存時に自動的にファイル末尾に改行を入れてくれる。設定しておくとよい。

Other

Remote

【WinSCPはもう不要?】VS Codeのダウンロード/アップロード機能が便利すぎる!! | マスクロドットコム

Visual Studio Code Remote Development

公式拡張機能のVS Code Remote Developmentを使うと、リモートファイルをVS Codeで開いて、ドラッグドロップでファイル送受信ができるらしい。

VSCodeのSSH接続機能で、RaspberryPi内のコードを編集してデバッグ #Python - Qiita

Remote Developmentをインストールすると、左サイドメニューに [Remote Explorer] のマークが追加される。これを選んで [REMOTE EXPLORER]-[Remotes (Tunnnels/SSH)]-[SSH]-[+]-メニューに [usrname@host] の形式で接続情報記入。

左サイドメニューの [SSH] の節に追加される。右の [Connect in New Window...] を選ぶ。

接続先マシンのPlatformをLinux/Windows/macOSから選ぶ。

Git

blame

行単位での最後の修正コミットの表示。標準であるが、デフォルト非表示になっている。

git.blame.editorDecoration.enabled: true

これで有効になる。が、いちいち表示されるのがうざいので、デフォルトfalseでいいと思う。

PhpStorm

Jump

includeなどで参照しているファイルパスのファイルを開く方法がいくつかある。

  • C-b
  • C-LButton
  • C-N/C-O でファイルを開いてファイルパスを貼り付け。

認識できないことがあるので3番目が汎用的。

Encoding

パス単位で文字エンコーディングを設定可能。

[PhpStorm]-[Settings]-[Editor]-[File Encodings] から行う。

Scratch

【New Year Calendar】君はPhpStormのScratch機能を知っているか #NewYearCalendar - Qiita

メモなどの一時ファイルの作成機能。

[File]-[New Scratch File] からファイル形式を選んで作る。困ったらMarkdownで良いだろう。

作成したScratchファイルは [Project]-[Scratches and Consoles]-[Scratches] に格納される。

矩形選択

複数のカーソルと選択範囲 | PhpStorm ドキュメント

方法がいくつかある。

  • Cmd-Shift-8
  • Option-Shift-Middle

Git

Gitツールウィンドウ

C-9か左下のGitマークを選ぶとGitツールウィンドウの表示になる。ブランチとコミットログが表示される。ここから右クリックを使ってブランチ間の比較などができたりする。

ブランチ比較

コードレビューなどでよく使うブランチ同士の比較。

まず現在ブランチを比較対象ブランチに変更しておく。

[Git]-[Branches]-比較対象ブランチ-[Compare with]

これで上下に画面分割して、それぞれのブランチで固有のコミットログの一覧が表示される。派生元と派生先があるならば、片方が空になる。違うブランチ同士のマージ用に、こういう作りになっていると思われる。

差分ファイル一覧を見るには、右側の変更ファイルペーンでC-aを選ぶ。変更のある全ファイルのリストが表示される。

他に、Gitツールウィンドウを開いて、コミットログで右クリック-[Compare with Local]を選ぶとローカルと対象コミットとの比較になる。これがわかりやすい。

ただ、基本は現在ブランチか、現在のワーキングツリーとの比較になる。現在ブランチを変更しておくのが基本になる。そこだけ押さえておけば、まあなんとか使えそう。

元ファイルオープン

差分ビューで差分チェック中に、シンボルや型定義などの確認で元ファイルを開きたいことがある。ジャンプ方法がある。

左上の [Jump to Source C-Down] の鉛筆マークを選ぶ。これでエディター側で元ファイルを開ける。

サブディレクトリー

PHPStormで親のGitリポジトリーの下に、子のGitリポジトリーのディレクトリーがある場合、親ディレクトリーのGitしか認識してくれない。

認識してくれる方法がある模様。

Gitのマルチリポジトリー機能を使うらしい。

[Settings]-[Version Control]-[Directory Mappings]-[+]

以下を選択して [OK] を選ぶ。

  • ◉Directory: Git子ディレクトリーのパス
  • VCS: Git

これで対象ディレクトリーを右クリックでGitを選ぶと良い模様。

Blame

行番号のところを右クリック-[Annotate with Git Blame] で行単位の修正履歴を表示できる。

  • Annotate Revision: 現在の変更コミットを表示。
  • Annotate Previous Revision: 前回のコミットの表示。

過去の修正履歴の調査で役立つだろう。

変更ファイル内の検索

https://chatgpt.com/share/68300fe8-e1cc-800b-8640-66e7c6dc146d

gitでブランチ比較時に、変更ファイル内限定でシンボル検索したいことがある。例えば、使用メソッドに引数追加時の他の場所での確認など。

若干の工夫が必要。まず、ブランチ比較を行う。

その後、ファイル一覧画面で、全ファイル選択。

[Edit]-[Find]-[Find in Files]

Search

https://chatgpt.com/c/6798762a-2c2c-800b-8dab-4a7b8252fe7b

PhpStormの便利ショートカットキー~検索編~

PHPStormでは検索がいくつかある。

ファイル名検索

  • Mac以外=C-N
  • Mac=C-O

スペース区切りでAND検索になる。パスを含めると、ディレクトリーも絞り込める。

Search Everywhere

Shift2回押下。

  • C-f: ファイルない検索。
  • C-F: 全体検索。

Other

tsh経由のファイル転送

About

ローカルパソコンでソースコードを修正して、ファイルアップロードでAWS VMに展開して動作確認するという想定で、PhpStormを設定する。

基本方針として、以下のコマンドによりteleport経由で転送できるので、これをPhpStormにも設定する。IPv4部分は踏み台の~/.ssh/configで設定することで任意の名前を指定可能。

rsync -zare "tsh ssh -A <踏み台> ssh" ./test.file IPv4:~/

これを念頭にPhpStormを設定する。ただし、PhpStormからのログインのために、多段SSHの設定は必要。ファイル送受信時にtshを経由して監査ログは残るのでよしとする。

なお、単にファイルをコマンドで転送するだけなら、泥くさいが以下のようにtsh scpで2回実行する手もある。

FR=test.file TO=/path/to/test.file tsh scp $FR <踏み台>:$TO; tsh ssh -At <踏み台> scp $TO <AWS>:$TO
Official

teleport経由のファイル転送の公式情報は以下。

3番目の「JetBrains SFTP | Teleport Docs」がまさにこれに該当するのだが、説明の記述がわかりにくい。踏み台サーバーへのアクセスしかできないように見える。tsh configやssh_configを工夫すれば、うまくできるような気はする。

ssh_config

PhpStormのSSH configurationsのホスト名がスクリプトの引数に渡されるので、踏み台からAWSにsshでログインするホスト名やパソコンの~/.ssh/configのHostとの一致必要な点に注意する。

USERNAME=
cat <<-EOT >~/.ssh/config
Host dev-jg1
    ForwardAgent yes
    User $USERNAME
    ServerAliveInterval 30
    ProxyJump $USERNAME@<teleport-host>:3023

Host $USERNAME
    ForwardAgent yes
    ProxyJump dev-jg1:22
    User $USERNAME
    Hostname %h.<host>
    ServerAliveInterval 30

Host *
    AddKeysToAgent yes
    PasswordAuthentication no
    User $USERNAME
    ForwardAgent yes
    ServerAliveInterval 30
    IdentityFile ~/.ssh/id_ed25519
    # for macOS
    UseKeychain yes
rsync executable

rsyncで使用する (-eオプション)、以下の内容のシェルスクリプトを作成して実行権限を付与して任意の場所 (例: ~/project/tsh_ssh.sh) に配置する。

cd ~/project/
cat <<-'EOT' >tsh_ssh.sh
tsh ssh -A <host> ssh $@
EOT
chmod +x tsh_ssh.sh
PhpStorm設定

PhpStormで以下を設定する。

  • [Tools]-[Deployment]-[Configuration]
  • [+]-[SFTP]
  • [Create New Server]-[New server name: 任意の名前]-[OK]
  • [Connection] タブを以下に設定。
    1. Type=SFTP
    2. SSH configuration=以下を設定。
      1. Host: <ホスト名> (~/.ssh/configと踏み台サーバーの~/.ssh/configのホスト名と同じにする)
      2. User name: ユーザー名
      3. Port: 22
      4. Authentication type: OpenSSH config and authentication agent
    3. Root path=
    4. [☑️Use Rsync for download/upload/sync]
    5. Rsync Settings=以下を設定。
      1. Shell executable path=tsh_ssh.shのパス (例=~/project/tsh_ssh.sh)
  • [Mappings] タブを以下に設定。
    1. Local path: ローカルパソコンのmonsterディレクトリー
    2. Deployment path: /
    3. Web path: /
  • [Settings]-[Build, Execution, Development]-[Development]-[Options]-[Upload changed files automatically to the default server]=[On explicit save action]
    1. ☑️Delete remote files when local are deleted

以上で完了。後は同期したいファイルをPhpStormで開いて、右クリック-[Deployment]-[Upload to]/[Download from] でファイル転送できる。

[☑️Use Rsync for download/upload/sync] のチェックを外せば、rsyncを使わないファイル転送になる。

保存時自動転送

  • Prefernce(⌘ + ,)から、Build, Execution, Deployment > Deployment > Option
  • Upload changed files automatically to default serverを設定
  • Alwaysでもいいですが重いのでOn explicit save actionがおすすめです。⌘Sでサーバーにコードをsyncします。

Window

プロジェクトを開く、移動、閉じる | PhpStorm ドキュメント

ペーンを分離したり移動したりできる。

ペーン右上[…]-[View Mode]-[Window] を選ぶと、別画面に分離できる。並列時に重宝する。

ディレクトリーの無視

除外されたファイルとフォルダー | PhpStorm ドキュメント

PhpStormでコーディングで使用しないディレクトリを除外してパフォーマンスを改善する | プロガジ.DEV

シンボリックリンクだったりして、同じファイルが違うパスで表示されることがあって困る。ディレクトリーを除外する。

右クリック-[Mark Directory as]-[Excluded] を選ぶ。

Bookmark

ブックマーク | PhpStorm ドキュメント

よく参照するコードの行・ファイル・ディレクトリー、をブックマークに登録して、迅速にアクセスできる。

  1. 左端のプロジェクトツールウィンドウ (C-1) で対象項目を右クリック-[Bookmarks]-[Add Bookmark]
  2. [View]-[Tool Windows]-[Bookmarks] を選ぶと、、サイドバーにBookmarkのボタンが表示される。

Web Browsers and Preview

ウェブブラウザーとプレビュー | PhpStorm ドキュメント

PHPファイルの編集時に、右上にプレビューボタンが表示されて邪魔。以下の設定で非表示にできる。

[Cmd-,]-[Settings]-[Tools]-[Web Browsers and Preview]-[Show browser popup in the editor]-[▫️For HTML files]

ファイル差分

ファイルの差分ビューアー | PhpStorm ドキュメント

ファイル差分の閲覧機能がある。

右クリック-[Compare with Clipboard]

これが手っ取り早い。

PEARの認識

1 pear config-showでphp_dir (=/usr/share/php/) を確認する。

2 このディレクトリーをローカルマシンに保存する (~/projectなど任意の場所)。既存プロジェクトの外に配置した方が都合良いだろう。

3 PHPStormの[Settings]-[PHP]-[include Path] で2で保存したディレクトリーを指定する。

.bashrc

bash - .bashrc not sourced on Intellij IDEA's terminal - Stack Overflow

いくつかの理由で、IntelliJは標準ではBashを対話モードで起動しない。だから.bashrcを読み込まない。

ただし、これは設定で変更可能。

[Settings]-[Tools]-[Terminal]-[Shell path] に-iを追加する。だめなら、--loginとか。

終端スペースの自動除去

PhpStorm removing tabs/spaces on every save - Stack Overflow

PhpStormでファイルを開いて保存すると、勝手に終端スペースを削除する。デフォルトでそういう設定になっている。

[Settings/Preferences]-[Editor]-[General]-[Remove trailing spaces]=on

Templateエンジンでのシンボルジャンプ

https://chatgpt.com/share/6808ae15-1d60-800b-9e86-78aa131ee066

Smartyでは新ポルジャンプできない。

BladeとTwigはシンボルジャンプに対応しているらしい。VSCodeも。じゃあ、こっち優先するか。Laravelは嫌いだからTwig。

重いとき

https://chatgpt.com/share/681ab545-1814-800b-a019-c6cce4f24a3c

PHPStormを起動したら、CPU使用率がめちゃくちゃ高くてまともに動作しないことがある。

PHPStorm自体の更新キャッシュファイルの削除などを行なっている模様。

いくつか対策がある。

  1. [File]-[Power Save Mode] を選ぶとJITとGCが安まり軽快になる。
  2. Help > Diagnostic Tools > Activity Monitorでなんのプロセスの使用率が高いかわかる。
  3. Help > Show Log in Finder/Explorer-idea.logでログがわかる。

JITやGCの使用率が高い場合、メモリー管理やコードの最適化の負荷が高まっている。メモリー不足でGCが頻発していてCPU使用率が高まっている可能性がある。メモリー割り当てを大きくして、GCの頻発を抑えて、処理を完了させるとまともになる。

Help > Edit Custom VM Optionsで以下を設定する。

-Xms1024m
-Xmx4096m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC

8GBの場合。

  • Xms:初期メモリサイズ
  • Xmx:最大メモリサイズ(あなたのPCのRAMが8GB以上なら 4096m でもOK)
  • ReservedCodeCacheSize:JIT用のコードキャッシュ領域
  • UseG1GC:ガベージコレクションにG1GCを使用(モダンで安定)

編集後はPHPStormを再起動する。

ローカルPHPインタープリター

PHPStormが端末などでデフォルトで使うPHPを指定できる。

  1. Cmd-, (Settings) -[PHP] を選ぶ。
  2. [CLI Interpreter] の横の [...] を選ぶ。

左上の[+]から追加したりできる。

OS内で認識しているPHPのリストが表示される。ここで設定したPHPが端末起動時のパスに設定される。