「Develop」の版間の差分

提供:senooken JP Wiki
(Other コメントの著者名)
(Kallithea)
 
(同じ利用者による、間の18版が非表示)
28行目: 28行目:
これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。
これでDoneをclose時にアーカイブ用のプロジェクトに移動できる。


=== Communication ===
== Communication ==


==== Skype ====
=== 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 サポート]
[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で使用可能な絵文字の一覧。
Skyepで使用可能な絵文字の一覧。


== Tool ==
=== Slack ===


=== General ===
==== チャンネル ====
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


==== Call tree ====
===== 一覧表示 =====
kcachegrindだったかな。
[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。


kscopeもこれか。
=== Confluence ===
ページの中で、 [作成] を選んでページを作ると、階層が勝手にできて、子ページへのリンクもできる。


Doxygen+GraphVizで関数コールグラフ
==== ショートカットキー ====
キーボード ショートカット


==== kscope ====
https://ja.confluence.atlassian.com/doc/keyboard-shortcuts-139456.html
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
* {code: コードブロック (https://shinkufencer.hateblo.jp/entry/2018/10/17/235900 Confluenceのエディタは { でマクロのショートカット入力ができるし、{ code } でコードスニペット領域が作れる)。


==== cscope ====
ブロック フォーマット
cbrowser/kbrowserというGUIもある。
{| class="wikitable"
!Windows
!操作
!Mac
|-
|Ctrl + 0
|Paragraph
|⌘+ 0
|-
|Ctrl+ (1 ~ 6)
|(選択した番号の)見出しレベル
|⌘+ (1—6)
|-
|Ctrl + 7
|Preformatted
|⌘+ 7
|-
|Ctrl + 8
|Quote
|⌘+ 8
|-
|Ctrl + Shift + B、または


cscopeの大文字小文字無視検索
<nowiki>*</nowiki> + Space
|箇条書きリストを追加
|⌘ + Shift + B、または
<nowiki>*</nowiki> + Space
|-
|Ctrl + Shift + N、または
<nowiki>#</nowiki> + space
|番号付きリストを追加
|⌘ + 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


<nowiki>http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html</nowiki>
''サファリのみ:''Ctrl + Shift + Alt + V
|書式設定なしでテキストを貼り付け
|⌘ + Shift + V


DBを別にする必要がありそう。
''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
|}


==== expect ====
===== オートコンプリート =====
端末の手動操作を自動化するソフト。
[] が勝手にリンクになるのが困る。


<nowiki>*</nowiki> ^と$は使えない。代わりに、\nを使う。
リンク、ファイル、マクロ、メンション、絵文字のオートコンプリート


<nowiki>*</nowiki> 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。
https://ja.confluence.atlassian.com/doc/autocomplete-for-links-files-macros-mentions-and-emojis-249858190.html


<nowiki>*</nowiki> expect文はawkみたいな感じ。
オートコンプリートの無効化方法。


<nowiki>*</nowiki> ただし、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
一時的に回避したい場合、[の直前に何か文字があれば解釈されない。スペース開けて[があるとオートコンプリート扱いになる。


```
== Tool ==


sh -eux <<-"EOT"
=== General ===


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"
==== Call tree ====
kcachegrindだったかな。


expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"
kscopeもこれか。


expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"
Doxygen+GraphVizで関数コールグラフ


expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'
==== kscope ====
https:/github.com/ivan0124/Linux-programming/wiki/How-to-use-KScope-to-trace-code


EOT
https:/sourceforge.net/projects/kscope/


```
http:/www.lemis.com/grog/software/kscope.php


== Coding ==
==== cscope ====
cbrowser/kbrowserというGUIもある。


=== タイムゾーン ===
cscopeの大文字小文字無視検索
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]


3文字形式は避けたほうが無難。
<nowiki>http://vim.1045645.n5.nabble.com/how-to-search-with-cscope-ignoring-case-td5715043.html</nowiki>


タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。
DBを別にする必要がありそう。


tz databaseのAsia/Tokyoなどの確実性が高い。
==== expect ====
=== Regular Expression ===
端末の手動操作を自動化するソフト。
正規表現。重要。覚えにくいが重要なものをメモしておく。


後ろからマッチ。cが置換対象。
<nowiki>*</nowiki> ^と$は使えない。代わりに、\nを使う。


==== Case ====
<nowiki>*</nowiki> 文字列の囲みに一重引用符 (') は使えない。二重引用符 (") のみ有効。
/[^c]*$/: cより右端


===== マッチの前後の挿入 =====
<nowiki>*</nowiki> expect文はawkみたいな感じ。
https:/vim.fandom.com/wiki/Power_of_g
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


===== 関数にログ =====
<nowiki>*</nowiki> ただし、expectは注意が必要。最初のexpectにマッチしないと先に進めない。タイムアウトとかするしかない。
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
考慮するケース
double currentTime() const override { return m_element->currentTime(); }


=== glob ===
expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"


* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/glob.html glob]
https:/linuxjm.osdn.jp/html/expect/man1/expect.1.html
* [https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_13 Shell Command Language]


重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。
```


使用可能な記号は以下3個。以下の3文字は\でエスケープできる。
sh -eux <<-"EOT"


* ?: 任意の1文字にマッチ。
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"
* *: 任意の0以上の文字にマッチ。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


ファイル名マッチ時には、追加で特殊なルールがある。
expect -c "set timeout 5; spawn ssh senooken@senooken-linux; expect :; send ieneko/n; expect + {send pwd/n}; expect /$; exit"


.から始まるファイル名へのマッチには、.が必要。つまり、*?は先頭の.にはマッチしない。[!a] のような否定形の各括弧記法も.にはマッチしない。加えて、先頭の[.]もマッチするかは不定(unspecified)。
expect -c "set timeout 5; spawn cat cat.txt; expect \nFAIL {send pwd/n; expect :; exit}"


globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])。
expect -c 'set timeout 10; spawn cat cat.txt; expect "aa F" {set AAA "abc"}; expect FAIL {send "$AAA/n"; expect " "; exit}'
.[!.]* *
上記のように.ファイルのマッチとそれ以外を指定する必要がある。


<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。
EOT


<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。
```


=== 引用符のネスト ===
== Coding ==
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。


JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。
=== タイムゾーン ===
[https://qiita.com/dmikurube/items/15899ec9de643e91497c タイムゾーン呪いの書 #timezone - Qiita]


交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。
3文字形式は避けたほうが無難。


問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。


二重引用符は、内部で変数展開が可能。この都合で、バックスラッシュ\によるエスケープが有効。
tz databaseのAsia/Tokyoなどの確実性が高い。
=== Regular Expression ===
正規表現。重要。覚えにくいが重要なものをメモしておく。


基本的な方法。
後ろからマッチ。cが置換対象。


# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
==== Case ====
# 全体を一重/二重引用符で囲む。
/[^c]*$/: cより右端


何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。
===== マッチの前後の挿入 =====
https:/vim.fandom.com/wiki/Power_of_g
:g/GST_.*("/s/^/LOG(INFO) << "DEBUG";/r/
行頭・行末で引っ掛ける。


[{"ke\y":"valu\e"}] を例として考える。
===== 関数にログ =====
:%s/([^")]*)/) /([a-z]* /)*{/&/rLOG(INFO) << "/1";/r/g
考慮するケース
double currentTime() const override { return m_element->currentTime(); }


# {"ke\y":"valu\e"}
=== glob ===
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


これでOK。また何か考慮不足があればそのときに考える。
* [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]


ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
重要。正規表現とは似ているが異なる、パターンマッチング記法 (Pattern Matching Notation)。主に、globで採用されており、ディレクトリー・ファイルのマッチングで使われる。


例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
使用可能な記号は以下3個。以下の3文字は\でエスケープできる。
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]
* ?: 任意の1文字にマッチ。
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]
* *: 任意の0以上の文字にマッチ。
* [: []内の1文字にマッチ。正規表現の各括弧と同じ。ただし、先頭の否定が^ではなく、!。


JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。
ファイル名マッチ時には、追加で特殊なルールがある。


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


# JSON value用に二重引用符"を\"で置換。
globで.ファイルを含めたい場合、工夫が必要 ([https://www.php.net/manual/ja/function.glob.php PHP: glob - Manual])。
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
.[!.]* *
# JSON項目の二重引用符"を\"で置換。
上記のように.ファイルのマッチとそれ以外を指定する必要がある。
# 全体を二重引用符"で囲む。


こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。
<code>.[!.]*</code> は、<code>.</code>と<code>..</code>以外の.<code>.</code>始まりのファイルにマッチする。


=== ケース変換 ===
<code>.*</code>を指定すると、<code>.</code>/<code>..</code>がマッチするので注意する。最近のシェルは、シェル側で気を利かせているようで、<code>.*</code>だと<code>.</code> /<code>..</code>はマッチしない。
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]


キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。
=== 引用符のネスト ===
シェルやプログラミング言語で、文字列リテラルの表現などで、一重引用符'と二重引用符"を使う。


=== encode ===
JSON作成や変数展開などで、これらをネストさせたいことがある。その基本的な考え方を整理する。
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]


日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。
交互にしていい場合は簡単二重。引用符内に一重引用符を配置、一重引用符内に二重引用符を配置すればいい。


* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
問題はこれがNGな場合。特にありがちなのが、JSONの生成。JSONの引用符は二重引用符のみ。一重引用符の中だと、二重引用符の変数展開が使用不能。外側を二重引用符にする必要がある。
* 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 / "-" / "." / "_" / "~"
# 既存の一重/二重引用符などをバックスラッシュでエスケープ。
上記文字はエンコードの対象外。
# 全体を一重/二重引用符で囲む。


==== 英数変換 ====
何かAwkの本か何かで、基本的な考え方の説明の記載があった気がする。
[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] に変換したいことがある。
[{"ke\y":"valu\e"}] を例として考える。


こういう目的だと%エンコーディングが適している。
# {"ke\y":"valu\e"}
# エスケープ: {\"ke\\y\":\"valu\\e\"}
# 全体囲み: "{\"ke\\y\":\"valu\\e\"}"


ただし、一部の記号を許可しているので、自前で変換する。
これでOK。また何か考慮不足があればそのときに考える。
function encode_all($str) {
    $hex = unpack('H*', $str);
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
}
$str = 'big ƒüßchen';
print_r(encode_all($str));


==== Term ====
ただ、元データに修正が必要なので、そのまま行きたい。ヒアドキュメント的なものが使えるならそれを使うのがいい。
紛らわしい用語がある。


* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])
例えば、シェルなら、catコマンドとコマンド置換で生テキストを使える。
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])。
echo $(cat <<-'EOT'
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。
{"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]
* [https://stackoverflow.com/questions/64011248/how-to-handle-double-quotes-in-json-value python - How to handle double quotes in JSON value? - Stack Overflow]


==== Category ====
JSONのvalue部分に適用したい場合。データの二重引用符をバックスラッシュでエスケープする。これはこうするしかない。JSONが二重引用符しか認めないから。
「[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]」


ソフトウェアの分類、ページ分類時に役立つ。
基本的な考え方がある。


* 言語
# JSON value用に二重引用符"を\"で置換。
* ツール: 静的解析、テスト、文書など。
# \"がPHP/JavaScriptで二重引用符に扱いにならないように、\を\\に置換。
* フレームワーク
# JSON項目の二重引用符"を\"で置換。
# 全体を二重引用符"で囲む。


MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。
こういう感じ。JSONはawkでも任意の最終データで考える。途中にプログラミング言語でのパースがあるので、それを考慮する必要がある。


=== ケース変換 ===
[https://stackoverflow.com/questions/63116039/camelcase-to-kebab-case javascript - camelCase to kebab-case - Stack Overflow]


* PHP language
キャメルケースをチェインケースにしたり、逆にしたりなどケース変換したいことがある。正規表現を駆使して実現する。
* PHP tool
 
* PHP framework
=== encode ===
[https://www.sejuku.net/blog/25909 【PHP入門】URLエンコードする方法(urlencode) | 侍エンジニアブログ]
 
日本語や記号を他のコードに変換 (エンコード) する方式が何通りかある。把握しておくと役立つ。


==== 成功時連続継続処理 ====
* パーセントエンコーディング/URLエンコード: URLで使用不能な文字を%16進数で連結。
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。
* UTF-8
* base64: 全データを「A-Z」「a-z」「0-9」「+」「/」の64文字で表現。文末に=を使うので実質は65文字。
* HTMLエンコード: HTMLで特殊な意味を持つ文字を&amp;lt;などに変換する。


# 処理実行。
==== Percent-encoding ====
# 成功ならA、失敗なら終了。
# 処理実行。
# 成功ならA、失敗なら終了。


こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
* [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]
        while (true) {
 
            // 処理実行
  unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
            if (失敗) {
上記文字はエンコードの対象外。
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
   
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。
==== 英数変換 ====
[https://stackoverflow.com/questions/28110062/php-how-to-encode-all-characters-with-rawurlencode string - PHP How to encode all characters with rawurlencode - Stack Overflow]


いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。
変数名への変換などで、日本語や記号を英数字 [0-9a-zA-Z] に変換したいことがある。


これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。
こういう目的だと%エンコーディングが適している。


offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
ただし、一部の記号を許可しているので、自前で変換する。
        $offset = 0;
function encode_all($str) {
        while (true) {
    $hex = unpack('H*', $str);
            $currentReturnCode = $service->sendRequest(Raku2Config::API_TYPE_CSV_EXPORT, Raku2Config::CONFIG_API_URL_MULTI_API, [
    return preg_replace('~..~', '%$0', strtoupper($hex[1]));
                json_encode([
}
                    'dbSchemaId' => $table_info['dbSchemaId'],
                    'offset' => $offset,
                    'limit' => $limit,
                ])
            ]);
   
   
            $response = $service->getApiResultJson();
$str = 'big ƒüßchen';
            // 終了条件: 戻り値が成功以外、か応答本体が1行 (ヘッダーのみ) の時。
print_r(encode_all($str));
            if (($currentReturnCode !== Raku2Config::EXIT_SUCCESS) || (substr_count($response, "\n") <= 1)) break;
 
==== Term ====
            // 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;
* ミドルウェア: 名前通り中間のソフトウェア。DBやアプリケーションサーバーなどが該当。単独で動作が重要なポイント ([https://sackle.co.jp/blog/detail/1248-2 ミドルウェアとは何か?代表的な製品や使用例とあわせて解説! - サックルMAGAZINE]、[https://system-kanji.com/posts/middleware-development ミドルウェアとは?アプリ・システム開発との関係・仕組み・役割・具体例を解説【2024年最新版】 | システム幹事])
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
* フレームワーク: 単体で動作しない。アプリ開発のテンプレート。Django/Ruby on Rails/Vue.jsなど ([https://www.pentasecurity.co.jp/pentapro/entry/framework_library 【3分ITキーワード】 フレームワークとライブラリの違いは? - ペンタPRO:ペンタセキュリティが提供するセキュリティ情報まとめサイト])
            (function() use (&$offset, $limit, $response) {
* ライブラリー: 単体で動作しない。よく使われるコードの集まり。機能単位。jQuery/Numpy/matplotlib/Qtなど。
                // 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 ====
==== Category ====
UTF-8のBOM
「[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]」
\xef\xbb\xbf
 
この文字を先頭につけるとUTF-8のBOMになる。
ソフトウェアの分類、ページ分類時に役立つ。
 
* 言語
* ツール: 静的解析、テスト、文書など。
* フレームワーク
 
MediaWikiのページ名は全体で固有が条件なので、言語名+分類名でページを作るといい。
 


=== Convert ===
* PHP language
* PHP tool
* PHP framework


==== IP/CIDR ====
==== 成功時連続継続処理 ====
// JavaScript
一度の取得件数の上限が決まっていて、終了・失敗するまで取得を継続したいという処理がそれなりに発生する。
<nowiki> </nowiki>  /**
<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形式)。
<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>  },


=== Algorithm ===
# 処理実行。
# 成功ならA、失敗なら終了。
# 処理実行。
# 成功ならA、失敗なら終了。


==== 再帰処理 ====
こういうパターン。いくつか実装方法があるが、while (true) のパターンが重複がなくてベストだと思う。
https://chatgpt.com/c/673d9bfe-2414-800b-9922-f94be6dbe950
        /*
 
        // 無限ループで終了条件でブレイク
配列の配列、オブジェクトのオブジェクトなど、再帰的な構造はけっこう遭遇する。
        while (true) {
            // 処理実行
            if (失敗) {
                break;
            }
            成功時処理
        }
       
        // do while
        do {
            処理実行
            if (成功時) {}           
        } while ();
        // for (初期化; 継続判定・終了判定; 成功時式) {
            処理実行
        }
        */
do-whileは成功・終了判定を2回書く必要がある。


再帰関数で実装するほかに、スタックで処理する方法がある。
forだと成功処理を式でしか書けない。成功処理を関数や即時実行関数式などで書くなら悪くはないし、ベストになりえる。


再帰関数のほうが簡単に実装できるが、関数呼び出しのオーバーヘッドがある。ネスト10-100程度くらいなら問題ない。
いや、成功時処理内の処理の結果次第で反復の終了条件などが追加で入るならNGになる。なので、やっぱりwhile(true)が無難。コード行数もそんなに変わらない。


パフォーマンスや再帰中の細かい制御が必要なら、スタックが有利。ただし、実装がやや複雑。
これにさらに初回だけ、ヘッダーの取得、書き込み処理などが発生する場合、初回だけループの外でやるのがきれいだろうか?初回処理が2回登場することになるけれど。


最初は再帰関数で実装して、後でボトルネックになったらスタックというのも手。
offsetなどで初回の判定が反復内でできるから、それで分けるのがいいか?
 
        $offset = 0;
https://chatgpt.com/c/6745228f-8b20-800b-8a41-bdaece8c03f5
        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);
        }


再帰関数とスタックの他に、JSONなどの文字列にシリアライズして、文字列処理で対応するという手もある。
        for ($offset = 0;
 
            ($currentReturnCode === Raku2Config::EXIT_SUCCESS) && (substr_count($response, "\n") > 1);
JSONPath/XPathなどの方法もあるが、基本的には外部ライブラリーが必要。
            (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 ===


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


==== コメントの著者名 ====
=== Convert ===
https://chatgpt.com/c/67469d8d-7e64-800b-b82d-8c74f4e13c08


GNU socialのソースコードのコメントに著者名が大量にあった鬱陶しい。
==== IP/CIDR ====
// JavaScript
<nowiki> </nowiki>  /**
<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形式)。
<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>  },
 
=== 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に任せて、本文には記載しなくていいと思う。
大規模プロジェクトになると、編集者が膨大になる。VCSに任せて、本文には記載しなくていいと思う。
563行目: 728行目:
<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。
<code>map_[key]_[value]</code> のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。


===== foreach =====
===== array/foreach =====
[https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
 
* [https://wiki.senooken.jp/PHP#Name_2 PHP - senooken JP Wiki]
* https://chatgpt.com/c/6747aee4-ab64-800b-88d7-940a5c4201bf


foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
foreach系のfor文ではキーとバリューを変数に格納して反復する。ファイルや配列に対して行うことが多い。
  foreach (table as $row => $line)
  foreach (table as $row => $line)
その際の変数名は、上記のように$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 =====
===== Function argument order =====
714行目: 907行目:
  $array[][]
  $array[][]


== AI ==
==== Project ====
 
===== レガシープロジェクトの立て直し =====
https://chatgpt.com/c/67481a93-adc0-800b-81c4-20d763133002
 
1. 現状分析
 
(1) ソフトウェアの動作確認
 
現在の環境でアプリケーションを動作させる。
 
どの部分が機能していて、どこが問題かを確認する。
 
必要であればエラーログを確認する。
 
(2) 依存関係の調査


=== 対話AI ===
アプリケーションのライブラリやフレームワークのバージョンを調査。


==== List ====
サポートが終了しているもの、互換性が失われたものを特定。
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


いろいろある。
(3) コードベースの状態評価
{| class="wikitable"
 
|+
コードの品質 (可読性、設計、テストカバレッジ) を確認。
!Name
 
!
セキュリティリスクを特定する (例えば、脆弱性が放置されていないか)。
!
 
!
2. 計画立案
|-
|Bing
|
|
|
|-
|Perplexity AI
|
|
|
|-
|ChatGPT
|
|
|
|-
|Google Gemini
|
|
|
|}


==== ChatGPT ====
(1) ゴール設定


===== Plan =====
具体的な目標を設定 (例: パフォーマンス改善、保守性向上、セキュリティ強化)。
[https://openai.com/chatgpt/ ChatGPT | OpenAI]


Free/Plusの2のプランがある。
(2) 優先順位の決定
{| 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に会員登録する意味は何ですか?


(3) リスク評価とバックアップ


ChatGPTに会員登録する主な利点はいくつかあります。
修正に伴うリスクを評価し、現行システムのバックアップを取得。


1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。
3. 環境整備


2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。
(1) 開発環境のモダナイズ


3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。
ローカル環境やコンテナ (Docker) を用意してテストを容易にする。


4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。
CI/CD パイプラインの整備。


5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。
(2) 依存関係の更新


興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。
サポートされていないライブラリやフレームワークをアップグレードまたは置き換える。


===== 方法 =====
(3) セキュリティの確保


====== 質問の分割 ======
古いOSSの脆弱性を修正。
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c


Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
HTTPSの導入、認証強化、インプット検証など。


A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。
4. コードのモダナイズ


===== 感想 =====
(1) リファクタリング


====== 2024-11-14 Thu ======
レガシーコードをよりモダンで可読性の高いコードに変換。
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。


例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。
デザインパターンを適用して保守性を向上。


[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]
(2) テストの追加


getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。
ユニットテスト、統合テストを導入。


こういう検索エンジンで検索しにくい質問で便利だなと思います。
既存の機能が壊れないことを確認するための自動化されたテスト。


検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
(3) フロントエンド/バックエンドの分離


大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。
必要に応じてモノリシック構造を分離し、モダンなアーキテクチャ (SPA、Microservices など) に移行。


個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。
5. 機能拡張とデプロイ


同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。
(1) 新しい機能の追加


一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>
必要に応じて、現代のニーズに合った新機能を実装。


====== 2024-11-19 Tue ======
(2) 運用環境でのテスト
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]]
新しい環境で徹底的にテストし、問題がないことを確認。


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


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


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


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


もはや技術とか、ただの暗記の神経衰弱は別にいらないです。一般企業の上長とか、士業のように、単純知識でマウント取るタイプの仕事はこれで確かに駆逐されます。どうせ対話AIのほうが賢いのだから。知識量で勝てるわけないです。全世界の情報の集積結果なんだから。
エラーログやパフォーマンスを監視し、迅速に対応できる仕組みを導入。


凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>
(2) 定期的なアップデート


== VCS ==
フレームワークやライブラリを継続的に更新し、レガシー化を防ぐ。


=== List ===
(3) コミュニティへの貢献
Comparison of issue-tracking systems - Wikipedia <nowiki>https://en.wikipedia.org/wiki/Comparison_of_issue-tracking_systems</nowiki>


BTS。GitHubみたいな。PHP製の以下がよさそう。
OSSとしての性質を活かし、変更内容をコミュニティに共有することでフィードバックを得る。
 
* Tuleap
* Phabricator/Phorge
* MantisBT
* FusionForge
* GLPI
* Faveo Helpdesk
* [https://sourcehut.org/ sourcehut - the hacker's forge]: Python製。FSF推奨。


VCSとの統合状況がまちまち。
このプロセスを通じて、安定した動作を保ちながら徐々に近代化することが可能です。特に、「現状分析」と「環境整備」をしっかり行うことで、後続の作業がスムーズになります。


=== Git ===
== AI ==


==== Commit ====
=== 対話AI ===


===== マージコミット後のコミット追加 =====
==== List ====
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。
[https://notepm.jp/blog/24168 【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM]


git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
いろいろある。
{| class="wikitable"
|+
!Name
!
!
!
|-
|Bing
|
|
|
|-
|Perplexity AI
|
|
|
|-
|ChatGPT
|
|
|
|-
|Google Gemini
|
|
|
|}


しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。
==== ChatGPT ====


===== コミットオプション =====
===== Plan =====
[https://git-scm.com/docs/git-commit Git - git-commit Documentation]
[https://openai.com/chatgpt/ ChatGPT | OpenAI]


コミットメッセージ指定のためのオプションがある。
Free/Plusの2のプランがある。
 
{| class="wikitable"
* -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
|+
* -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
!
* -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
!Free
* -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。
!Plus
 
|-
基本は-m。-mの複数指定。
|金額 [USD/月]
 
|0
===== 過去コミットのメールアドレスの変更 =====
|20
 
|-
* [https://www.git-tower.com/learn/git/faq/change-author-name-email How can I change the author (name / email) of a commit? | Learn Version Control with Git]
|機能
* [https://zenn.dev/flyingbarbarian/articles/241627cae5988a Gitのcommitの名前やメールアドレスを過去からまとめて変更する]
|基本
 
|アーリーアクセス
単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。
|-
git commit --author="John Doe <john@doe.org>"
|エンジン
--amendと併用することで、過去コミットも変更できる。
|GPT-4o mini
|GPT-4/GPT-4o/GPT-4o mini
|-
|制限
| -
|GPT-4oの5倍以上のメッセージ送信
|-
|その他
| -
|データ分析、ファイルアップロード、ビジョン、Webブラウジング
|-
|画像生成
| -
|DALL-E
|}
送信可能なメッセージ数、エンジン、画像生成などが大きな違いだろう。


数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。
===== Account =====
公式サイトにアカウントの意味の説明がない。しかたないので、ChatGPTに質問。<blockquote>ChatGPTに会員登録する意味は何ですか?


===== 第一コミットの変更 =====


* [https://dev.classmethod.jp/articles/git-rebase-from-root/ [Git] 最初のコミットを含めてrebase -iする方法 | DevelopersIO]
ChatGPTに会員登録する主な利点はいくつかあります。
* [https://git-scm.com/docs/git-rebase Git - git-rebase Documentation]


通常、第一コミットはammend以外では変更できない。
1. **パーソナライズされた体験**: 登録すると、あなたの好みや過去のやり取りに基づいて、よりカスタマイズされた応答が得られます。


rebase --root [branch] でブランチの第一コミットも参照して改変可能。
2. **履歴の管理**: 過去のチャット履歴を保存し、いつでも見返すことができるため、情報の確認が簡単になります。


===== マージコミットの打ち消し =====
3. **新機能へのアクセス**: 登録ユーザーは新しい機能やアップデートを優先的に利用できる場合があります。
マージコミットは扱いがやや特殊。
git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前
どちらか。


==== stash ====
4. **プレミアム機能**: 一部のサービスでは、会員登録をすることで、より高度な機能やサポートが提供されることがあります。


===== 復元 =====
5. **セキュリティとプライバシー**: アカウントを持つことで、データの管理やプライバシーの設定をより細かく調整できます。
[https://qiita.com/generosity-naman/items/237338f8fe5b7e3b9a76 Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita]


git stash drop実行時に、削除したコミットのSHA1が表示される。
興味があれば、ぜひ登録を検討してみてください!他に質問があればお知らせください。</blockquote>自分の過去の質問の履歴を見れるだけでも便利かも。


そのSHA1をapplyで指定すれば、取り込める。
===== 方法 =====
git stash apply [stash_hash]


===== リモート =====
====== 質問の分割 ======
[https://qiita.com/mather314/items/a1536c52a2eb0426b2b5 gitの不要なブランチを消すコマンド #Git - Qiita]
https://chatgpt.com/c/673bdc0d-e0e0-800b-a22b-4fa19e64476c
git fetch -p/--prune
リモートの削除済みブランチをローカルに同期する。


===== リモートの最新タグ =====
Q. chatgptで質問するとき、連続して質問すると、同じURLで複数の質問が表示される。リロードして質問を分けたほうがいいのか?
https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git


git ls-remote --tag --sort=taggerdate
A. どちらでも問題ない。が、質問が関連しているなら同じチャットで継続したほうがいい。直前の質問も文脈を考慮できる。完全に話が異なるなら分けたほうが後で整理したり、URLを共有したときにわかりやすい。


date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。
===== 感想 =====


https:/git-scm.com/docs/git-ls-remote.html
====== 2024-11-14 Thu ======
https://gnusocial.jp/notice/7806505<blockquote>[[/gnusocial.jp/group/32/id|!it]] [[/gnusocial.jp/group/28/id|!ai]] 業務でPHPの開発作業をしていて、ChatGPTを使いだして便利に感じています。検索エンジンの代わりに使っています。


https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning
例えば、「laravel eloquentでリレーション先のテーブルの主キー名の取得方法は?」と質問します。


git rev-listでいけそう。
[[/chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2|https://chatgpt.com/c/67354314-fbdc-800b-a4e4-65f96d1a8fb2]]


https:/gist.github.com/rponte/fdc0724dd984088606b0
getRelatedというややマニアックなメソッドを教えてくれます[eloquent getrelated] で検索してもなかなかたどり着けないです。


===== 差分ファイル抽出 =====
こういう検索エンジンで検索しにくい質問で便利だなと思います。
情報源: [https://qiita.com/kaminaly/items/28f9cb4e680deb700833 gitで差分ファイルを抽出する #Git - Qiita]。


git archiveとgit diffを組み合わせる。
検索エンジンで検索すると、的外れな情報も大量にヒットします。対話AIはそのごみの混ざった検索結果を分析した結果をコンパクトに返してくれます。対話AI使わなくても、検索エンジンで時間かければわかりますが、大幅に時間短縮できます。
git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip
ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。


git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?
大量の凡人健常者が取り組んだ方法論として決まりきったものは、記憶の問題、ただの神経衰弱です。こういうのを検索エンジンの改良版としてAIに任せるのはいい使い方だと思います。


例:
個人的に、ただの知識、事実は重要度高くないと思いますが、一般社会では評価する側の頭が悪いので、これが重宝されます。
mkdir -p archive
git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/


===== core.autocrlf =====
同僚や先輩に聞くより対話AIのほうがよほど頭いいです。話すことないです。聞くほうが時間の無駄なので。凡人はどんどん要らなくなります。
<blockquote>warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it</blockquote>Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf


* true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
一方、私みたいなキチガイのデータは少ないので、検索エンジンやAIに聞いても出てこないです。世界で自分だけのオリジナルに専念するのがたぶんいいです。</blockquote>
* false=変換しない。
* input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。


わかりにくい。基本はfalseで良いと思われる。
====== 2024-11-19 Tue ======
https://gnusocial.jp/notice/7867350<blockquote>[[/gnusocial.jp/group/28/id|!ai]] ChatGPTが検索エンジンの改良版としてやっぱり便利。さっきこういう質問しました。


===== gitkの文字化け対策 =====
phpのメソッド名で、英単語の修飾語は前と後ろどちらがいい?例えば、namePrefixed()とprefixedName()のどちらがいい? [[/chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85|https://chatgpt.com/c/673bd358-3dc8-800b-8ec9-d745cc0eba85]]
[https://www.pistolfly.com/weblog/2010/02/gitk.html gitkのエンコーディングを設定する - Pistolfly]


gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。
私はこのレベルの細かい疑問がすぐ浮かぶのです。これを人間にきくと、頓珍漢な回答だったり、そもそも回答してもらえないし、何ならこういう質問した私がなぜかキチガイ扱いされて、微妙な雰囲気になって、質問できなくなって、ストレスが溜まって、居づらくなって早期退職になるんです。意味不明です。ただの質問にお気持ちの配慮とか面倒なので。
git config --global gui.encoding utf-8


===== ファイル名などの文字化け対策 =====
この間、 [[/misskey-square.net/users/9g2o6eycu3|@yuriha]] に突っ込まれた件も、たぶん対話AIとお互い会話したほうが有意義だったんじゃないかとすら思います。相手も私に突っ込む前に対話AIと会話したほうが自分の主張の自己矛盾、頓珍漢さに気づけたんじゃないかとすら思えます。私が突っ込んでまーた私がキチガイ扱いされるのも回避されます。対話AIからの客観的な指摘なら、同じ内容であっても、キチガイの私が言うより納得しやすいでしょう?同じ内容なら対話AIのほうが凡人健常者にとっては、信じ込みやすいでしょ?
[https://qiita.com/kumazo/items/2169e1ee7be278f82b94 Git for Windows で日本語を使いたい #Vim - Qiita]
git config --global core.quotepath false
git config --global gui.encoding utf-8


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


* [https://qiita.com/yukimura1227/items/fbb076db61a2e43a32e3 gitでrename&modifyしたファイルのログを追跡できるようにしたい場合 #Git - Qiita]
検索エンジンでも調べることはできますが、めちゃくちゃ時間かかるんです。自分で複数の意見をみつけて、頭の中で比較検討して整理するので。これを一瞬でやってくれるのが楽。途中のデータ整理、目視は単純作業に近いのです。他のことに頭使えます。
* [https://zenn.dev/yoichi/articles/how-git-handles-renaming Gitはファイルのリネームをどう扱うか]


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


-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。
凡人健常者の知識を拝借して、世界でだれにも真似できないキチガイ部分に専念できます。GNU socialの開発もこれでいけると思います。</blockquote>


===== 差分無視 =====
== VCS ==
[https://qiita.com/odekekepeanuts/items/8a056b87c9e481e07e57 git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita]


-wでインデント違いを無視してくれる。
=== List ===
Comparison of issue-tracking systems - Wikipedia <nowiki>https://en.wikipedia.org/wiki/Comparison_of_issue-tracking_systems</nowiki>


===== squash =====
BTS。GitHubみたいな。PHP製の以下がよさそう。
squashすると、squash対象コミットが、対象の直前のコミットに含められる。


===== gitignore =====
* Tuleap
[https://git-scm.com/docs/gitignore/en Git - gitignore Documentation]
* Phabricator/Phorge: 共用サーバー不能。
* MantisBT
* FusionForge
* GLPI
* Faveo Helpdesk
* [https://sourcehut.org/ sourcehut - the hacker's forge]: Python製。FSF推奨。
* Fossil
 
VCSとの統合状況がまちまち。
 
phorgeがダメだったので、Mantis/Fossil/sourcehutあたりが共用サーバーで検討可能か。


====== Format ======
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869
記述方法を整理する。


* 空行は無視。
他に以下がある。
* #始まりの行はコメント扱い。
* 終端スペースは無視。
* !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
* /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
** 先頭と中間の/は相対パスを意味する。
** それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
** 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
* *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
* **は特殊な意味がある。
** **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
** /**=配下のすべてにマッチ。
** a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。


後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。
* Gitea
* Cgit
* Gitlab
* SourceHut: Python
* GitBucket: Java


反転の!と/の扱いに特に注意が必要。
Gitlabは共用サーバーで可能なのか?無理。cgitの他、gogsもある?


先頭スラッシュをつけないと、再帰的になる。
CGIで利用可能なもの。
    $ cat .gitignore
 
    # ディレクトリ foo/bar 以外のすべてを除外
* Cgit: gitの出力を見れるだけ。issueはない。
    /*  
* Gitweb: cgit同様。
    !/foo
* ViewGit:
    /foo/*
* Kallithea: 有力。[https://kallithea-scm.org/ Kallithea]
    !/foo/bar


====== 空ディレクトリーの維持 ======
=== Git ===
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow]


gitは空ディレクトリーを履歴管理できない。何かファイルが必要。
==== Commit ====


logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
===== マージコミット後のコミット追加 =====
!.gitignore
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。


====== 指定ファイルのみ除外 ======
git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
*
!.gitignore
ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。


===== gitattributes =====
しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。
[https://git-scm.com/docs/gitattributes Git - gitattributes Documentation]


gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。
===== コミットオプション =====
[https://git-scm.com/docs/git-commit Git - git-commit Documentation]


* text
コミットメッセージ指定のためのオプションがある。
* eol
* working-tree-encoding
* ident
* filter
* diff
* merge
* conflict-marker-size
* whitespace
* export-ignore: git archiveなどに含めないことをマーク。
* export-subst
* delta
* encoding


===== ファイルのインデックスのみ削除 =====
* -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。
* -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
git rm --cached
* -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
* -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。


==== gitk ====
基本は-m。-mの複数指定。


===== problem =====
===== 過去コミットのメールアドレスの変更 =====
ブランチ名が長いと、右クリックしにくい


==== Other ====
* [https://www.git-tower.com/learn/git/faq/change-author-name-email How can I change the author (name / email) of a commit? | Learn Version Control with Git]
* [https://zenn.dev/flyingbarbarian/articles/241627cae5988a Gitのcommitの名前やメールアドレスを過去からまとめて変更する]


===== 他のブランチとの同一化 =====
単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。
  git diff HEAD master | patch -p 1
  git commit --author="John Doe <john@doe.org>"
patchの他にgit applyでもいい。
--amendと併用することで、過去コミットも変更できる。


===== .netrc =====
数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。
https://social.senooken.jp/conversation/1573147#notice-2217499


Gitのパスワード入力の省略方法に~/.netrcがある。
===== 第一コミットの変更 =====


しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。
* [https://dev.classmethod.jp/articles/git-rebase-from-root/ [Git] 最初のコミットを含めてrebase -iする方法 | DevelopersIO]
* [https://git-scm.com/docs/git-rebase Git - git-rebase Documentation]


In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
通常、第一コミットはammend以外では変更できない。


せのお (妹尾 賢)せのお (妹尾 賢) in reply to
rebase --root [branch] でブランチの第一コミットも参照して改変可能。


理由が分かった。
===== マージコミットの打ち消し =====
マージコミットは扱いがやや特殊。
git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前
どちらか。


1. Gitはhttpとhttpsの通信にcURLを使っている。
==== stash ====


<nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki>
===== 復元 =====
[https://qiita.com/generosity-naman/items/237338f8fe5b7e3b9a76 Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita]


2. cURLが.netrcにも対応しているから。
git stash drop実行時に、削除したコミットのSHA1が表示される。


<nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki>
そのSHA1をapplyで指定すれば、取り込める。
git stash apply [stash_hash]


=== GitHub ===
===== リモート =====
[https://qiita.com/mather314/items/a1536c52a2eb0426b2b5 gitの不要なブランチを消すコマンド #Git - Qiita]
git fetch -p/--prune
リモートの削除済みブランチをローカルに同期する。


==== Account ====
===== リモートの最新タグ =====
Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.
https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git
ユーザー名は、英数字と-のみが使用可能。


組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。
git ls-remote --tag --sort=taggerdate


=== Fossil ===
date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。
* [https://gigazine.net/news/20231231-why-sqlite-does-not-use-git/ SQLiteがバージョン管理システムとしてGitを採用しない理由 - GIGAZINE]
* [https://gigazine.net/news/20201229-fossil/ GitとGitHubの機能をひとつのバイナリに詰め込んだ「Fossil」レビュー - GIGAZINE]


外部依存を排除しており、CGIでも動作するという点が非常に良い。気になる。Phorgeの検討が不要になる。
https:/git-scm.com/docs/git-ls-remote.html


=== Phorge ===
https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning
[https://we.phorge.it/ Home]


PhorgeはPhabricatorのフォーク。
git rev-listでいけそう。


==== About ====
https:/gist.github.com/rponte/fdc0724dd984088606b0


===== Introduction =====
===== 差分ファイル抽出 =====
[https://we.phorge.it/book/phorge/article/introduction/ ◉ Introduction]
情報源: [https://qiita.com/kaminaly/items/28f9cb4e680deb700833 gitで差分ファイルを抽出する #Git - Qiita]


以下が主な機能。
git archiveとgit diffを組み合わせる。
git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip
ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。


* コードレビューツール=Differential
git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?
* リポジトリーブラウザー=Diffusion
* バグトラッカー=Maniphest
* ウィキ=Phiriction


GitHubの自己ホスト。
例:
mkdir -p archive
git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/


===== Phabricator =====
===== core.autocrlf =====
[[wikipedia:Phabricator|Phabricator - Wikipedia]]
<blockquote>warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it</blockquote>Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf


PhabricatorはもともとFacebook社内のBTSシステム。PHP製。2021-06-01に開発終了。
* true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
* false=変換しない。
* input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。


主なユーザー。
わかりにくい。基本はfalseで良いと思われる。


* AngularJS
===== gitkの文字化け対策 =====
* Discord
[https://www.pistolfly.com/weblog/2010/02/gitk.html gitkのエンコーディングを設定する - Pistolfly]
* Facebook


==== Install ====
gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。
[https://we.phorge.it/book/phorge/article/installation_guide/ ◉ Installation Guide]
git config --global gui.encoding utf-8


[https://ipv6.rs/tutorial/Ubuntu_Server_Latest/Phorge/ Self Host with IPv6rs - IPv6 Provider - How to Install Phorge on Ubuntu Server Latest]
===== ファイル名などの文字化け対策 =====
[https://qiita.com/kumazo/items/2169e1ee7be278f82b94 Git for Windows で日本語を使いたい #Vim - Qiita]
git config --global core.quotepath false
git config --global gui.encoding utf-8


===== Requirement =====
===== 改名と修正 =====
LAMP環境で動作する。


共用ホストでも動作するが、一部機能しない。通常コンピューターを推奨している。
* [https://qiita.com/yukimura1227/items/fbb076db61a2e43a32e3 gitでrename&modifyしたファイルのログを追跡できるようにしたい場合 #Git - Qiita]
* [https://zenn.dev/yoichi/articles/how-git-handles-renaming Gitはファイルのリネームをどう扱うか]


* MySQL: 5.5以上。
改名と修正を同時にすると、改名を検知できない。
* PHP 7.2以上
* git: 2.5.0以上。
* PHP extension: mbstring, iconv, mysql (or mysqli), curl, pcntl


ドメインはサブディレクトリーはだめで、サブドメインじゃないとダメ。
-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。


===== Download =====
===== 差分無視 =====
以下のコマンドで取得する。
[https://qiita.com/odekekepeanuts/items/8a056b87c9e481e07e57 git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita]
$ cd somewhere/ # pick some install directory
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/arcanist.git</nowiki>
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/phorge.git</nowiki>
gitの設定。
$ sudo git config --system --add safe.directory somewhere/arcanist
$ sudo git config --system --add safe.directory somewhere/phorge
phorge用のDBを作っておく。
cp /var/www/html/phorge/phabricator/conf/local/local.json.example /var/www/html/phorge/phabricator/conf/local/local.json


"mysql.host": "localhost", "mysql.user": "phorge", "mysql.pass": "password", "mysql.port": 3306, "mysql.charset": "utf8", "mysql.database": "phorgedb"
-wでインデント違いを無視してくれる。
後は開くだけ。


===== Config =====
===== squash =====
[https://we.phorge.it/book/phorge/article/configuration_guide/ ◉ Configuration Guide]
squashすると、squash対象コミットが、対象の直前のコミットに含められる。


以下のコマンドでユーザーを認識させる。
===== gitignore =====
phorge/ $ ./bin/storage upgrade --user <user> --password <password>
[https://git-scm.com/docs/gitignore/en Git - gitignore Documentation]


==== Diffusion ====
====== Format ======
記述方法を整理する。


===== Hosting =====
* 空行は無視。
[https://we.phorge.it/book/phorge/article/diffusion_hosting/ ◉ Diffusion User Guide: Repository Hosting]
* #始まりの行はコメント扱い。
* 終端スペースは無視。
* !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
* /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
** 先頭と中間の/は相対パスを意味する。
** それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
** 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
* *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
* **は特殊な意味がある。
** **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
** /**=配下のすべてにマッチ。
** a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。


== Shell ==
後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。


=== Shell Command Language ===
反転の!と/の扱いに特に注意が必要。


==== Compound Commands ====
先頭スラッシュをつけないと、再帰的になる。
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]
    $ cat .gitignore
    # ディレクトリ foo/bar 以外のすべてを除外
    /*
    !/foo
    /foo/*
    !/foo/bar


===== Case Conditional Construct =====
====== 空ディレクトリーの維持 ======
case word in
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow]
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


* 未マッチで終了ステータス0。
gitは空ディレクトリーを履歴管理できない。何かファイルが必要。
* pattern部分: シェル展開が有効。他はglob。
* |でOR検索相当。
* 最後のパターンの;;は省略可能。if文のようにも使える。
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。


BREでは未対応な|のORマッチに対応しているのが最大の特徴。文法なのでコマンドを実行せず早い。grepを使わずにできるだけこちらを使ったほうがいい。
logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
!.gitignore
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。


=== ワイルドカード ===
====== 指定ファイルのみ除外 ======
ワイルドカードで.始まりのファイルをマッチさせたい。
*
!.gitignore
ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。


以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
===== gitattributes =====
echo {.*,*}
[https://git-scm.com/docs/gitattributes Git - gitattributes Documentation]


=== BOM ===
gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。
[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をファイルにつけたい。
* text
printf '\xEF\xBB\xBF' > with_bom.txt
* eol
上記コードでBOMを最初に書き込んで、後は追記する。
* working-tree-encoding
* ident
* filter
* diff
* merge
* conflict-marker-size
* whitespace
* export-ignore: git archiveなどに含めないことをマーク。
* export-subst
* delta
* encoding


=== awk ===
===== ファイルのインデックスのみ削除 =====
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]
git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。
git rm --cached
 
==== gitk ====
 
===== problem =====
ブランチ名が長いと、右クリックしにくい


==== 変数 ====
==== Other ====


===== 特別 =====
===== 他のブランチとの同一化 =====
* NF: 列数。列の全表示などで使う基本的で重要な変数。
git diff HEAD master | patch -p 1
* NR: 行番号。
patchの他にgit applyでもいい。


===== スコープ =====
===== .netrc =====
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]
https://social.senooken.jp/conversation/1573147#notice-2217499


関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。
Gitのパスワード入力の省略方法に~/.netrcがある。


==== 文/statement ====
しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。


* actions
In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
** if/else
 
** while/do...while/for
せのお (妹尾 賢)せのお (妹尾 賢) in reply to
** break/continue
 
** delete
理由が分かった。
** next
 
** exit
1. Gitはhttpとhttpsの通信にcURLを使っている。
* output
 
** print
<nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki>
** printf
 
2. cURLが.netrcにも対応しているから。


==== 関数 ====
<nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki>


===== 組込関数 =====
=== GitHub ===


* Arithmetic
==== Account ====
** atan2
Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.
** 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/文扱い。
組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。


==== ヘッダー出力、列別最大長さ出力。 ====
=== Fossil ===
<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>
* [https://gigazine.net/news/20231231-why-sqlite-does-not-use-git/ SQLiteがバージョン管理システムとしてGitを採用しない理由 - GIGAZINE]
* [https://gigazine.net/news/20201229-fossil/ GitとGitHubの機能をひとつのバイナリに詰め込んだ「Fossil」レビュー - GIGAZINE]


==== CSV ====
外部依存を排除しており、CGIでも動作するという点が非常に良い。気になる。Phorgeの検討が不要になる。
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
# csvparser.awk


## Usage
[https://fossil-scm.org/home/doc/trunk/www/index.wiki Fossil: A Coherent Software Configuration Management System]
# awk -f csvparser.awk data.csv


# CSV の論理的な一行毎に呼び出されるコールバック関数(サンプル)
いくつか癖があるので注意する。
# row: 行番号(最初の行は1) len: フィールド数 fields: フィールドデータ
 
function callback(row, len, fields, col, field) {
https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86
    for ( col = 1; col <= len; col++ ) {
 
        field = fields[col]
複数のリポジトリーを取り扱うことは可能。ただし、Web UI上からリポジトリーの新規作成はできない。リポジトリーの新規作成はあくまでコマンドラインから行う必要がある。ここは集中的。
        gsub(/\\/, "&&", field) # \ は \\ にエスケープする
 
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
==== Install ====
        print row ":" col " " field
 
    }
===== Binary =====
}
[https://fossil-scm.org/home/doc/trunk/www/index.wiki Fossil: A Coherent Software Configuration Management System]
 
ソースコードからコンパイルするか、コンパイル済みバイナリーを配置するだけ。
VER=2.25
mkdir -p ~/.local/stow/fossil-$VER ~/.local/bin
cd ~/.local/stow/fossil-$VER
curl -O [https://fossil-scm.org/home/uv/fossil-linux-x64-2.25.tar.gz https://fossil-scm.org/home/uv/fossil-linux-x64-$VER.tar.gz]
  tar -xf fossil-$VER.*
ln -fns ../stow/fossil-$VER/fossil
 
===== Server =====
[https://fossil-scm.org/home/doc/tip/www/server/any/cgi.md Fossil: Serving via CGI]
 
CGIで実行するにはいくつか手順がある。
 
CGIディレクトリーに以下の内容のCGIスクリプトを用意する。
#!/usr/bin/fossil
repository: /home/fossil/repo.fossil
repositoryの部分は指定方法がいろいろある。単一リポジトリーのホストなら上記でいいが、複数のリポジトリーを取り扱いたければ、リポジトリー群の格納ディレクトリーをdirectory: で指定する。
 
また、リポジトリーが不在の場合のリダイレクト先を指定するnotfound:もある。
  #!/usr/bin/fossil
directory: /home/fossil/repos
notfound: <nowiki>http://url-to-go-to-if-repo-not-found/</nowiki>
CGIスクリプトをcgi-bin/repoとした場合、展開後は [http: //mydomain.org/cgi-bin/repo/XYZ] のようなURLで [/home/fossil/repos/XYZ.fossil] にアクセス可能。


BEGIN { row = max_idx = 0 }
CGIで展開されると。
{
    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を除外して使う。
fossil.cgiにする。
tail -c +4 data/101543.csv | awk -f csvparser.awk


=== Other ===
https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86


==== binary ====
fossilのweb uiではリポジトリーの新規作成ができない。新規作成だけはコマンドラインから行う必要がある。これだけがいまいち。保留。
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]
=== Phorge ===
[https://we.phorge.it/ Home]


バイナリーデータの読込はodコマンド。なければhexdump。
PhorgeはPhabricatorのフォーク。


書込はprintf。
==== About ====


head/tailの-cはPOSIXで使えたか?
===== Introduction =====
[https://we.phorge.it/book/phorge/article/introduction/ ◉ Introduction]


== cmd.exe ==
以下が主な機能。


=== Control block ===
* コードレビューツール=Differential
* リポジトリーブラウザー=Diffusion
* バグトラッカー=Maniphest
* ウィキ=Phiriction


==== for ====
GitHubの自己ホスト。
あくまでコマンド。


===== nest =====
===== Phabricator =====
[[wikipedia:Phabricator|Phabricator - Wikipedia]]


* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]
PhabricatorはもともとFacebook社内のBTSシステム。PHP製。2021-06-01に開発終了。


* [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/]
主なユーザー。


ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。
* AngularJS
* Discord
* Facebook


=== bitsadmin ===
==== Install ====
Windowsでのファイルダウンロードコマンド


Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。
* [https://we.phorge.it/book/phorge/article/installation_guide/ ◉ Installation Guide]
* [https://ipv6.rs/tutorial/Ubuntu_Server_Latest/Phorge/ Self Host with IPv6rs - IPv6 Provider - How to Install Phorge on Ubuntu Server Latest]
* https://chatgpt.com/c/6749041b-a1b4-800b-a134-96a8029c086e


書式:
===== Requirement =====
bitsadmin /transfer <job name> <URL> <output path>
LAMP環境で動作する。
<job name>と<output path>は必須なので注意する。


=== certutil ===
共用ホストでも動作するが、一部機能しない。通常コンピューターを推奨している。
Windowsでのハッシュの確認に使える。
certutil -hashfile file


SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
* MySQL: 5.5以上。
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
* PHP 7.2以上
CertUtil: -hashfile コマンドは正常に完了しました。
* git: 2.5.0以上。
* PHP extension: mbstring, iconv, mysql (or mysqli), curl, pcntl


=== 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%


=== 実行中プロセスのパスの確認 ===
===== Download =====
出典: [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
$ cd somewhere/ # pick some install directory
  wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/arcanist.git</nowiki>
wmic process where "name='mysqld.exe'" get ProcessID, ExecutablePath /FORMAT:LIST
somewhere/ $ git clone <nowiki>https://we.phorge.it/source/phorge.git</nowiki>
gitの設定。
$ sudo git config --system --add safe.directory somewhere/arcanist
$ sudo git config --system --add safe.directory somewhere/phorge
phorge用のDBを作っておく。
  cp /var/www/html/phorge/phabricator/conf/local/local.json.example /var/www/html/phorge/phabricator/conf/local/local.json


=== 簡易編集モード/挿入モード ===
"mysql.host": "localhost", "mysql.user": "phorge", "mysql.pass": "password", "mysql.port": 3306, "mysql.charset": "utf8", "mysql.database": "phorgedb"
後は開くだけ。


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


Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。
こういうディレクトリー構成想定。
public_html
+ phorge.gnusocial.jp 公開ディレクトリー。
+ phorge phorge関係の格納場所。
  + phorge
  + arcanist
取得。
TAG=2024.35
mkdir phorge
cd phorge
PKG=phorge
git clone --depth 1 [https://we.phorge.it/source/phorge.git https://we.phorge.it/source/$PKG.git]
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..
PKG=arcanist
git clone --depth 1 [https://we.phorge.it/source/arcanist.git https://we.phorge.it/source/$PKG.git]
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..


cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。
git config --add safe.directory arcanist
git config --add safe.directory phorge
phorge/webrootが公開ディレクトリーになるので、これをシンボリックリンクで公開ディレクトリーにリンクする。
DOMAIN=phorge.gnusocial.jp
ln -fns phorge/phorge/webroot ../$DOMAIN
[https://we.phorge.it/book/phorge/article/configuration_guide/ ◉ Configuration Guide]」に記載のあるリダイレクト設定をする。


そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。
以下相当の設定を行う。
<VirtualHost *>
  # Change this to the domain which points to your host.
  ServerName phorge.example.com
  # Change this to the path where you put 'phorge' when you checked it
  # out from the upstream when following the Installation Guide.
  #
  # Make sure you include "/webroot" at the end!
  DocumentRoot /path/to/phorge/webroot
  RewriteEngine on
  RewriteRule ^(.*)$          /index.php?__path__=$1  [B,L,QSA]
</VirtualHost>
<Directory "/path/to/phorge/webroot">
  Require all granted
</Directory>
具体的には、phorge/webroot/.htaccessに以下を記載して、ファイルがなければ作成する。
cat >phorge/webroot/.htaccess <<-'EOT'
RewriteEngine on
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
EOT
上記設定後phorge.gnusocial.jpにアクセスすると以下のエラーになる。
Request parameter '__path__' is not set. Your rewrite rules are not configured correctly.


[□挿入モード] にすると回避できる模様。
* [https://stackoverflow.com/questions/25368612/phabricator-rewrite-rules-configuring-issue apache - Phabricator rewrite rules configuring issue - Stack Overflow]
* [https://stackoverflow.com/questions/49344737/phabricator-install-rewrite-rules-are-not-configured-correctly php - Phabricator install. Rewrite rules are not configured correctly - Stack Overflow]


== Web ==
上記が少し参考になる。require指令を指定していないのが問題。


=== URL ===
うーん。この問題を解決できない。調べても解決例が出てこない。断念する。他のソフトにする。


==== クエリー配列 ====
===== Config =====
[https://we.phorge.it/book/phorge/article/configuration_guide/ ◉ Configuration Guide]


* [https://shinkufencer.hateblo.jp/entry/2019/05/18/163912 クエリストリングで配列を表現をするケースをざっと調べる - コード日進月歩]
以下のコマンドでユーザーを認識させる。
* [https://qiita.com/s4kd0R/items/8a11d88099008bb1e9dc PHPでクエリパラメータから配列を受け取る物語 #JavaScript - Qiita]
phorge/ $ ./bin/storage upgrade --user <user> --password <password>
* [https://www.php.net/http_build_query PHP: http_build_query - Manual]


やり方がいくつかある。
==== Diffusion ====


# CSV文字列で受取後分割: <nowiki>https://www.sakdor.net/test/?var=1,2,3</nowiki> explode(",",$_GET[var]);
===== Hosting =====
# 配列添字
[https://we.phorge.it/book/phorge/article/diffusion_hosting/ ◉ Diffusion User Guide: Repository Hosting]
## 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がシンプル。
=== Kallithea ===
[https://kallithea-scm.org/ Kallithea]


=== HTTP ===
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869
[https://www.rfc-editor.org/rfc/rfc9110.html RFC 9110: HTTP Semantics]


==== Content-Disposition ====
Python 3.6でCGIでも動作する管理ソフト。
[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)]
[https://kallithea.readthedocs.io/en/stable/index.html Kallithea Documentation — Kallithea 0.7.0 documentation]
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。


==== multipart/form-data ====
==== Administrator guide ====
rfc7578


* [https://datatracker.ietf.org/doc/html/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data]
===== Installation on Unix/Linux =====
* [https://qiita.com/sivertigo/items/14957200af5ad953d63b Multipart/form-dataの仕様メモ #HTTP - Qiita]
[https://kallithea.readthedocs.io/en/stable/installation.html Installation on Unix/Linux — Kallithea 0.7.0 documentation]
 
====== Installing a released version in a virtualenv ======
いくつか方法があるが、virtualenvが推奨されている。


ファイルアップロード用のMIME type。
coreserver v1のpythonはpython 3.6だった。
cd public_html/
DOMAIN=kallithea.gnusocial.jp
cd $DOMAIN
python3 -m venv venv
python3 -m venv venvの実行時に以下のエラー。
Error: Command '['/virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 2.
[https://qiita.com/sin9270/items/7a17d21ccd7c2531ac41 cimg/pythonでvenvによる仮想環境の作成がエラーになる #Python - Qiita]


リクエストヘッダー
pipが見つからないのが原因の模様。--without-pipでインストールして、仮想環境内にpipを直接インストールする。
  Content-Type: multipart/form-data; boundary=--hogehoge
  python3 -m venv --without-pip venv
リクエストボディー
. venv/bin/activate
  --hogehoge
  curl https://bootstrap.pypa.io/pip/<nowiki>$(python3 -V | grep -o '[0-9].[0-9]')/get-pip.py -o get-pip.py</nowiki>
Content-Disposition: form-data; name="user_name"
  python3 get-pip.py
Content-Type: text/plain
  pip install --upgrade pip
   
OK。以下のコマンドで基本要件を確実にする。
  test
  pip install --upgrade pip "setuptools<67"
--hogehoge
Kallitheaをインストール。
  Content-Disposition: form-data; name="email"
  pip install --upgrade kallithea
なんかエラーが出る。
sample@mail.com
  ERROR: Command errored out with exit status 1:
  --hogehoge
    command: /virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3 -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"'; __file__='"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /export/tmp/pip-pip-egg-info-kjtbdngw
Content-Disposition: form-data; name="gender"
        cwd: /export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/
  Complete output (3 lines):
male
  /usr/lib64/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'convert_2to3_doctests'
--hogehoge
    warnings.warn(msg)
Content-Disposition: form-data; name="user_profile" filename="image.jpeg"
  error in FormEncode setup command: use_2to3 is invalid.
Content-Type: image/jpeg
  ----------------------------------------
WARNING: Discarding <nowiki>https://files.pythonhosted.org/packages/2f/53/707c2b9b65ea6bedde67c21cbf7c71394f4a198620d4e9c1771214b91dcc/FormEncode-1.3.1.tar.gz#sha256=ada2f51792b1b484e5bb7b6cc14acfc1bc11fafc967cf015cd57e856053ca7f6</nowiki> (from <nowiki>https://pypi.org/simple/formencode/</nowiki>). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
\xff\xd8\....
Collecting kallithea
--hogehoge--
[error in FormEncode setup command: use_2to3 is invalid.]
ヘッダーでmultipart/form-dataを明記して、ボディーでデータを指定する。


[https://weblabo.oscasierra.net/curl-post/ curlコマンドでPOSTする, 様々な形式別メモ |]
[https://qiita.com/nkmr_RL/items/85edc2ee68c01ec5582e 急にpip installで一部のライブラリのインストールが失敗するようになった件 #Python3 - Qiita]


curlでの送信理由。
setuptoolsを58.0.0未満にすればいいらしい。
pip install setuptools==57.4.0
この実行後pip install --upgrade kallitheaが成功。


-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。
====== Prepare front-end files ======
  curl -X POST -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
以下のコマンドでフロントエンドを用意。
データとテキストを同時送信したい場合、-Fで複数指定する。
  kallithea-cli front-end-build
  curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
事前にnpmが必要な模様。
curlだと上記のboundaryなどをうまくやってくれるのだと思う。
  FileNotFoundError: [Errno 2] No such file or directory: 'npm': 'npm'
npmをインストールしたら解決。


リクエストボディー全体をファイルデータにする場合。
===== Setup =====
curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
[https://kallithea.readthedocs.io/en/stable/setup.html Setup — Kallithea 0.7.0 documentation]


=== IP address ===
====== Setting up a Kallithea instance ======
出典: [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【公式】| 株式会社グローカルネット]。
まず以下のコマンドでmy.iniを作成する。
kallithea-cli config-create my.ini http_server=waitress
http_serverのところで使用するHTTPサーバー種別を指定する。waitress, gearbox, gevent, gunicorn, or uwsgi.を指定可能。


自宅サーバーを行う際、固定IPアドレスが必要になる。
ひとまずデフォルトのこれで。


取得方法がいくつかある。
続いてDBを作成する。PostgreSQL/SQLIte/MariaDB/MySQLに対応。最初はSQLiteを使用しておいて、後で他のDBへのアクセスが推奨されている。


* 契約しているプロバイダでオプションとして申し込む方法
が、共用サーバーだと書き込みでプロセス削除されると嫌なので最初からMariaDBにする。まず以下のコマンドでドライバーを取得。
* 固定IPアドレスに対応しているSIMを契約する方法
  pip install mysqlclient
* '''VPNを利用した固定IPアドレスの提供会社を利用する方法'''


VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。
  OSError: mysql_config not found
mariadbは違う模様。以下の開発パッケージが必要らしい。
  sudo apt-get install libmysqlclient-dev
不明。一旦スキップ。


=== Authentication ===
SQLite以外を使う場合、my.iniでsqlalchemy.urlのコメントアウトを解除してDBのユーザー名とパスワードを記入しておく。
認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。
#########################
##      DB CONFIG      ##
#########################
#sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
#sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
#sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
sqlalchemy.url = mysql://[username]:[password]@localhost/kallithea?charset=utf8mb4
## Note: the mysql:// prefix should also be used for MariaDB
https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869


==== Basic認証 ====
次回、ディレクトリー構成を整理。
出典: [https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC Basic認証 - Wikipedia]。


Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。
== Shell ==
GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA{{=}}{{=}}
盗聴や改ざんが簡単だが、シンプルという利点がある。


==== OAuth ====
=== Shell Command Language ===
Ref


* [https://ja.wikipedia.org/wiki/OAuth OAuth - Wikipedia]
==== Compound Commands ====
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/utilities/V3_chap02.html#tag_18_09_04 Shell Command Language]
 
===== Case Conditional Construct =====
case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac


OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。
* 未マッチで終了ステータス0。
* pattern部分: シェル展開が有効。他はglob。
* |でOR検索相当。
* 最後のパターンの;;は省略可能。if文のようにも使える。
* 全パターンの捕捉は最後に*。空でもマッチする。?は最低1文字必要。


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


* resource owner: あるサイトのユーザー。
=== ワイルドカード ===
* resource server: あるサイトのユーザーのデータの保有サーバー。
ワイルドカードで.始まりのファイルをマッチさせたい。
* clent: クライアントアプリ。リソースサーバーのデータを使用したい。
* authorization server: クライアントにサイトへのアクセスを認証するサーバー。アクセストークンを発行して行う。


アクセストークンが実質的なパスワードのようなものだが、resource serverのパスワードを直接渡していない点が重要な違い。パスワードを直接渡さないことで、機能別に権限を細かく利用可否を制御できる。
以下ならマッチするが、ブレース展開 (brace expansion) はPOSIX shでは使えなかった気がする。
echo {.*,*}


処理の流れ。
=== BOM ===
[https://stackoverflow.com/questions/3127436/adding-bom-to-utf-8-files unicode - Adding BOM to UTF-8 files - Stack Overflow]


# client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
ExcelでUTF-8ファイルを開けるように、UTF-8のBOMをファイルにつけたい。
# client<-resource owner: Authorization Grant。
printf '\xEF\xBB\xBF' > with_bom.txt
# client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
上記コードでBOMを最初に書き込んで、後は追記する。
# client<-authorization server: Access Token
# client->resource server: Access Token。アクセストークンでアクセス。
# client<-resource server: Access Token


Consumer Key/Secret: アプリ識別用のID/PW。
=== awk ===
[https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/ The Open Group Base Specifications Issue 7]


Access Token: サイトにアクセスするためのパスワード。
==== 変数 ====


=== API ===
===== 特別 =====
* NF: 列数。列の全表示などで使う基本的で重要な変数。
* NR: 行番号。


==== 複数レコードの登録 ====
===== スコープ =====
[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 | 個人開発ブログ]
[http://www.fukano.jp/study_of_awk/basic/basic08.htm 変数のスコープ]


既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?
関数の仮引数のみ、ローカル変数扱いで、それ以外はグローバル変数。


[https://www.yamarkz.com/blog/rest-web-api-practice REST WebAPIのプラクティス | yamarkz.com]
==== 文/statement ====


delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。
* actions
 
** if/else
==== パラメーター ====
** while/do...while/for
[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]
** break/continue
** delete
** next
** exit
* output
** print
** printf


パラメーターの指定に3種類ある。
==== 関数 ====


# リクエストボディー
===== 組込関数 =====
# クエリー
# パス


パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。
* Arithmetic
 
** atan2
ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。
** cos
 
** sin
この原則に従うとシンプルだろう。
** exp
 
** log
* URIには長さの制限がある。
** sqrt
* ボディー
** int
** 引数が非常に多い場合。
** rand
** 画像などバイナリーデータ。
** srand
** キー・値構造を持たない場合。
* String
* クエリー文字列
** gsub
** 引数を簡単に確認できる。
** index
** 共通の引数の場合。
** length
** match
** split
** sprintf
** sub
** substr
** tolower
** toupper
* I/O
** close
** getline
** system


==== 検索機能のGET/POST ====
print/printfは関数ではなく、statement/文扱い。


* [https://stackoverflow.com/questions/20550514/post-or-get-in-a-search-form .net - POST or GET in a search form? - Stack Overflow]
==== ヘッダー出力、列別最大長さ出力。 ====
<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>


検索機能にGETとPOSTのどちらを使うか?という議論がある。
==== CSV ====
[https://qiita.com/ko1nksm/items/19407c1c53cbbc50569a シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応) #ShellScript - Qiita]<syntaxhighlight lang="awk" line="1">
# csvparser.awk


データ登録するわけなじゃないのだから、GETがいいんじゃない?
## Usage
# awk -f csvparser.awk data.csv


POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。
# 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
    }
}


GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。
BEGIN { row = max_idx = 0 }
 
{
ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。
    idx = 0
 
    sub(/\r$/, "")
==== レート制限対策 ====
    while ($0 != "") {
 
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
* [https://pikodon.com/note/php/api-cache/ APIの利用制限対策 | Web開発ノート]
            fields[++idx] = ""
* [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 リクエスト数によるアクセス制限の対策方法 – 請求管理ロボ ヘルプ]
        } 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


* cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
=== Other ===
* 配列を利用して、1回のリクエストでまとめて取得する。
 
* インターバルを設ける。
==== binary ====
* HTTP 429/413を検知して、リトライする。
[https://qiita.com/ko1nksm/items/dc8f247cdc5b7b58b736 POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita]


==== 指数関数的バックオフ ====
バイナリーデータの読込はodコマンド。なければhexdump。


* [https://docs.link.getmoneytree.com/docs/faq-rate-limiting APIレート制限は何か、どのように対処するのか?]
書込はprintf。
* [[wikipedia:Exponential_backoff|Exponential backoff - Wikipedia]]
* [https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=ja 指数バックオフ  |  Memorystore for Redis  |  Google Cloud]
* [https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html バックオフパターンで再試行 - AWS 規範ガイダンス]リトライ時は以下のアルゴリズムがいいらしい。
wait_interval = base * 2^n +/- jitter


* <code>wait_interval</code> は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
head/tailの-cはPOSIXで使えたか?
* <code>base</code> は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
* <code>n</code> は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、<code>n</code>の値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
* <code>jitter</code> は 0 から <code>base</code> の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し <code>wait_interval</code> の合計に加算するか減算するか、ランダムで選択してください。


=== curl ===
== cmd.exe ==
HTTPの通信のコマンドラインでの確認でよく使う。


==== Basic ====
=== Control block ===
[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
JSONで送信する場合、ヘッダー指定が必須。


<nowiki>*</nowiki>-F: multipart/formのform指定。
==== for ====
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を指定する。
===== nest =====


==== curl: (60) SSL certificate problem: self-signed certificate ====
* [https://chicagopile1-75.hatenablog.com/entry/2018/05/23/143502 バッチファイルで2重ループ - ハムスターに飼われる院生のブログ]
Ref: [https://linuxfan.info/curl-insecure curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI].


--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。
* [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/]


==== curl: Failed writing body ====
ネストはできない。二重ループしたければ、関数にしてそれを呼び出す。
[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がエラーを出力する。
=== bitsadmin ===
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
Windowsでのファイルダウンロードコマンド


curl: Failed writing body
Windows 7以降ではbitsadminコマンドがあり、これがwget相当となる。
curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。


対策は、curl -sで出力を抑制するとのこと。これで解決。
書式:
bitsadmin /transfer <job name> <URL> <output path>
<job name>と<output path>は必須なので注意する。


=== Wireshark ===
=== certutil ===
Windowsでのハッシュの確認に使える。
certutil -hashfile file


==== TLS ====
SHA1 ハッシュ (対象 C:\moconavi\windows\Moconavi\ext\chromium\moconavium.exe):
Ref: [https://www.toyo.co.jp/onetech_blog/articles/detail/id=36994 SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー].
e0da85b04b6970ac1f0c33db7a9ad607fdbd44eb
CertUtil: -hashfile コマンドは正常に完了しました。


Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。
=== 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%


[Preferences]-[Protocols]-[TCP] を選ぶ。
=== 実行中プロセスのパスの確認 ===
出典: [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


* ☑Allow subdissector to reassemble TCP stream
=== 簡易編集モード/挿入モード ===
* ☑Reassemble out-of-order semgemnts


上記をチェックしておく。デフォルトでチェックされていた。
* [https://softantenna.com/blog/windows-10-command-prompt-no-stop/ 【Tips】Windows 10のコマンドプロンプトが意図せず止まってしまう問題を回避する方法 | ソフトアンテナ]
* [https://superuser.com/questions/419717/windows-command-prompt-freezing-randomly Windows command prompt freezing randomly - Super User]


続いて、セッションごとのPre-Master Secretを登録する。
Windows 10のcmd.exeは [簡易編集モード] が有効になっており、コマンドプロンプトを左クリックすると、テキストの選択が始まる。テキスト選択中はコマンドの実行が止まる。長時間かかるコマンドの実行中に誤操作で止まると困るので、これは無効にしたほうがよい。


Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。
cmd.exeを起動-左上のアイコンをクリック-[規定値]/[プロパティ]-[オプション]-[□簡易編集モード] を選ぶ。


以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。
そのほか、 <code>git log</code> のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。
export SSLKEYLOGFILE=/tmp/sslkey.log
Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。


=== Security ===
[□挿入モード] にすると回避できる模様。


==== DoS攻撃 ====
== Web ==
いくつか対策方法がある。


* [https://lite.ip2location.com/ip-address-ranges-by-country?lang=ja 国別のIPアドレス範囲]
=== URL ===
* [https://rakko.tools/tools/11/ IPアドレスから住所検索:国、地域の特定 | ラッコツールズ🔧]


サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。
==== クエリー配列 ====


攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。
* [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]


==== バリデーションの実装 ====
やり方がいくつかある。


* [https://teratail.com/questions/81861 フロント側で入力チェックをしていればサーバー側では入力チェックは必要ない?]
# CSV文字列で受取後分割: <nowiki>https://www.sakdor.net/test/?var=1,2,3</nowiki> explode(",",$_GET[var]);
* [https://qiita.com/mi2__user/items/f2f415ccbb0a625c8647 フロントエンドの"バリデーション"は最低限の方がいいらしい。 #TypeScript - Qiita]
# 配列添字
## 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


基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。
データが決まっているならcsvがシンプル。


ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。
=== HTTP ===
[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://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 ()ユーフィット]
[https://datatracker.ietf.org/doc/html/rfc6266 RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)]
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。


submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。
==== multipart/form-data ====
rfc7578


# ボタン連打
* [https://datatracker.ietf.org/doc/html/rfc7578 RFC 7578 - Returning Values from Forms: multipart/form-data]
# ブラウザーバック
* [https://qiita.com/sivertigo/items/14957200af5ad953d63b Multipart/form-dataの仕様メモ #HTTP - Qiita]
# リロード (PRG)


項目ごとにすべき対策が異なる。
ファイルアップロード用のMIME type。


===== 連打 =====
リクエストヘッダー
Content-Type: multipart/form-data; boundary=--hogehoge
リクエストボディー
--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://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
[https://weblabo.oscasierra.net/curl-post/ curlコマンドでPOSTする, 様々な形式別メモ |]
* [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での無効化。
curlでの送信理由。


似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。
-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。
  $("form").submit(function() {
  curl -X POST -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
  var self = this;
データとテキストを同時送信したい場合、-Fで複数指定する。
  $(":submit", self).prop("disabled", true);
curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>
  setTimeout(function() {
curlだと上記のboundaryなどをうまくやってくれるのだと思う。
    $(":submit", self).prop("disabled", false);
  }, 10000);
});
停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。


=== Browser ===
リクエストボディー全体をファイルデータにする場合。
curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg <nowiki>https://xxxxx.net/xxxxxx</nowiki>


==== Chromium ====
=== IP address ===
出典: [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【公式】| 株式会社グローカルネット]。


===== Extension =====
自宅サーバーを行う際、固定IPアドレスが必要になる。
Chromme系で愛用拡張機能を列挙する。


* [https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm Create Link]:
取得方法がいくつかある。


==== devtool/開発者ツール ====
* 契約しているプロバイダでオプションとして申し込む方法
* 固定IPアドレスに対応しているSIMを契約する方法
* '''VPNを利用した固定IPアドレスの提供会社を利用する方法'''


===== イベントリスナー =====
VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。
[https://yuzu441.hateblo.jp/entry/2016/12/12/120000 要素に設定されているイベントを調べよう - ゆずめも]


[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。
=== Authentication ===
認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。


===== イベント監視 =====
==== Basic認証 ====
[https://stackoverflow.com/questions/3787555/how-to-find-out-which-javascript-events-fired How to find out which JavaScript events fired? - Stack Overflow]
出典: [https://ja.wikipedia.org/wiki/Basic%E8%AA%8D%E8%A8%BC Basic認証 - Wikipedia]


monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。
Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。
GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA{{=}}{{=}}
盗聴や改ざんが簡単だが、シンプルという利点がある。


==== Other ====
==== OAuth ====
Ref


===== Windows Safari =====
* [https://ja.wikipedia.org/wiki/OAuth OAuth - Wikipedia]


* [https://web.archive.org/web/20220220134447/https://jp.techcrunch.com/2012/07/27/20120725apple-safari-for-windows-ends/ Appleは静かにWindows版Safariの開発から手を引いてしまったのだろうか? | TechCrunch Japan]
OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。
* [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。
以下が登場人物。


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


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


* [https://web-toolbox.dev/ Web ToolBox | 開発者向けのオンラインツール]
処理の流れ。
* [https://tm-webtools.com/ TM - WebTools]


いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。
# client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
# 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


==== localhost ====
Consumer Key/Secret: アプリ識別用のID/PW。


* [[wikipedia:Special-use_domain_name|Special-use domain name - Wikipedia]]
Access Token: サイトにアクセスするためのパスワード。
* [https://ja.wikipedia.org/wiki/.localhost .localhost - Wikipedia]


RFC 6761 で規定。RFC 2606<nowiki/>で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。
=== API ===


IPv4=127.0.0.1/IPv6=::1とされている。
==== 複数レコードの登録 ====
[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 | 個人開発ブログ]


== Shared Host ==
既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?


=== Free ===
[https://www.yamarkz.com/blog/rest-web-api-practice REST WebAPIのプラクティス | yamarkz.com]
無料で使用可能な共用ホスティングサービスがある。


==== スタードメイン無料サーバー ====
delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。
ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。


[https://www.star-domain.jp/service/free_server.php 無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~]
==== パラメーター ====
[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]


jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。
パラメーターの指定に3種類ある。


* ディスク容量 20GB
# リクエストボディー
* DB 1GB
# クエリー
# パス


ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。
パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。


=== CORESERVER ===
ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。


==== メール ====
この原則に従うとシンプルだろう。


* [https://www2.bwt.jp/wiki/?Custom_Filter_of_Coreserver Custom_Filter_of_Coreserver - PukiWiki]
* URIには長さの制限がある。
* [https://help.coreserver.jp/manual/v2/spam-filter/ スパムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
* ボディー
* [https://help.coreserver.jp/manual/v1/customfilter/ カスタムフィルターの設定 | マニュアル | サポート | レンタルサーバー CORESERVER(コアサーバー)]
** 引数が非常に多い場合。
** 画像などバイナリーデータ。
** キー・値構造を持たない場合。
* クエリー文字列
** 引数を簡単に確認できる。
** 共通の引数の場合。


情報
==== 検索機能のGET/POST ====


* [https://www2.bwt.jp/wiki/?CoreServer_Mail_Custom CoreServer_Mail_Custom - PukiWiki]
* [https://stackoverflow.com/questions/20550514/post-or-get-in-a-search-form .net - POST or GET in a search form? - Stack Overflow]
* [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の、できるかな?]


ルールが特殊なので注意する。
検索機能にGETとPOSTのどちらを使うか?という議論がある。


ゴミ箱に振り分ける場合。
データ登録するわけなじゃないのだから、GETがいいんじゃない?


順1 で[<code>./.Trash</code>] を指定
POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。


順2
GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。


* 条件:  [<code>.*</code>]
ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。
* 処理:  <code>./</code>、に振り分ける


条件部分には正規表現が使えるように見える。
==== レート制限対策 ====


破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。
* [https://pikodon.com/note/php/api-cache/ APIの利用制限対策 | Web開発ノート]
* [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 リクエスト数によるアクセス制限の対策方法 – 請求管理ロボ ヘルプ]


カスタムフィルターにくせがある。
いろいろ方法がある。


* エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」
* cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
* 配列を利用して、1回のリクエストでまとめて取得する。
* インターバルを設ける。
* HTTP 429/413を検知して、リトライする。


==== Value Domain ネットde診断 byGMO ====
==== 指数関数的バックオフ ====


* [https://www.value-domain.com/information/detail/?no=20240606-1 弊社レンタルサーバー上で運用中のドメインにおける自動セキュリティ診断開始のお知らせ | お知らせ - バリュードメイン]
* [https://docs.link.getmoneytree.com/docs/faq-rate-limiting APIレート制限は何か、どのように対処するのか?]
* [https://www.value-domain.com/security/net-de-shindan/ Value Domain ネットde診断 byGMO - バリュードメイン]
* [[wikipedia:Exponential_backoff|Exponential backoff - Wikipedia]]
* [https://cloud.google.com/memorystore/docs/redis/exponential-backoff?hl=ja 指数バックオフ  |  Memorystore for Redis  |  Google Cloud]
* [https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/cloud-design-patterns/retry-backoff.html バックオフパターンで再試行 - AWS 規範ガイダンス]リトライ時は以下のアルゴリズムがいいらしい。
wait_interval = base * 2^n +/- jitter


2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。
* <code>wait_interval</code> は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
* <code>base</code> は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
* <code>n</code> は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、<code>n</code>の値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
* <code>jitter</code> は 0 から <code>base</code> の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し <code>wait_interval</code> の合計に加算するか減算するか、ランダムで選択してください。


== Analytics ==
==== バックエンドとフロントエンドの分離 ====
https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45


==== Exam ====
SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部するというのが最近の流行。
<nowiki>##</nowiki> About


<nowiki>https://gnusocial.jp/notice/4506679</nowiki>
SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。


<nowiki>###</nowiki> 全般
SSRの利点。


- マーケティング・ビジネス実務検定
* SEO
* 初期表示。
* 匿名。


- IMA検定
SSRの課題。


- Web検定
* サーバー負荷: データとHTML作成を同時に行うから。
* 分散困難:


- ネットマーケティング検定
キャッシュの活用がポイントになるとのこと。


<nowiki>###</nowiki> 解析系
=== curl ===
HTTPの通信のコマンドラインでの確認でよく使う。


- ウェブ解析士
==== Basic ====
[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
JSONで送信する場合、ヘッダー指定が必須。


- GAIQ
<nowiki>*</nowiki>-F: multipart/formのform指定。
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を指定する。


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


GAIQが無料だしどうせ使うからいいかな。
--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。


<nowiki>https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/</nowiki>
==== curl: Failed writing body ====
[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]


<nowiki>https://www.plan-b.co.jp/blog/seo/12792/</nowiki>
以下のようにhead -n 1を指定するとcurlがエラーを出力する。
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


<nowiki>##</nowiki> URL
curl: Failed writing body
curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。


- <nowiki>https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/</nowiki>
対策は、curl -sで出力を抑制するとのこと。これで解決。


- <nowiki>https://mynavi-creator.jp/blog/article/qualification-for-web-marketer</nowiki>
=== Wireshark ===


- <nowiki>https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html</nowiki>
==== TLS ====
Ref: [https://www.toyo.co.jp/onetech_blog/articles/detail/id=36994 SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー].


- <nowiki>https://digitor.jp/textbook/web-analytical-qualification/</nowiki>
Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。


=== Tool ===
[Preferences]-[Protocols]-[TCP] を選ぶ。
サイト分析用のツールがいくつかある ([https://hidesunblog.com/blog-ranking-sites/ 2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】])。
 
* ☑Allow subdissector to reassemble TCP stream
* ☑Reassemble out-of-order semgemnts
 
上記をチェックしておく。デフォルトでチェックされていた。
 
続いて、セッションごとのPre-Master Secretを登録する。
 
Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。
 
以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。
export SSLKEYLOGFILE=/tmp/sslkey.log
Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。


* SimilarWeb
=== Security ===
* Ubersuggest
* ahrefs
* Googleキーワードプランナー


=== 閲覧数取得 ===
==== DoS攻撃 ====
出典: [https://affiliate-jpn.com/archives/5595 GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN]。
いくつか対策方法がある。


* [行動]-[サイトコンテンツ]-[全てのページ]
* [https://lite.ip2location.com/ip-address-ranges-by-country?lang=ja 国別のIPアドレス範囲]
* [表示する行数]=5000
* [https://rakko.tools/tools/11/ IPアドレスから住所検索:国、地域の特定 | ラッコツールズ🔧]
* [エクスポート]=TSV


=== 流入元特定 ===
サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。
「[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>こんにちは。
 
 
攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。
探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。
 
 
==== バリデーションの実装 ====
・自由形式レポートを作成
 
 
* [https://teratail.com/questions/81861 フロント側で入力チェックをしていればサーバー側では入力チェックは必要ない?]
・セグメント作成 > ユーザーセグメント
* [https://qiita.com/mi2__user/items/f2f415ccbb0a625c8647 フロントエンドの"バリデーション"は最低限の方がいいらしい。 #TypeScript - Qiita]
 
 
・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定
基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。
 
 
・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存
ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。
 
 
・探索レポートにセグメントを適用
==== 二重送信 ====
 
 
・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列
* [https://www.youfit.co.jp/archives/4545 フォームの二重送信を防止する方法 - 福岡・東京のシステム開発会社 (株)ユーフィット]
 
* [https://qiita.com/syobochim/items/120109315f671918f28d さいきょうの二重サブミット対策 #JavaScript - Qiita]
・指標:セッション
 
 
submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。
ご確認よろしくお願いいたします。
 
 
# ボタン連打
※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。
# ブラウザーバック
# リロード (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);
});
停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。
 
=== Browser ===
 
==== Chromium ====
 
===== Extension =====
Chromme系で愛用拡張機能を列挙する。
 
* [https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm Create Link]:
 
==== devtool/開発者ツール ====
 
===== イベントリスナー =====
[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でも監視できるらしい。
 
==== Other ====
 
===== 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。
 
=== 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とされている。
 
== Shared Host ==
 
=== Free ===
無料で使用可能な共用ホスティングサービスがある。
 
==== スタードメイン無料サーバー ====
ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。
 
[https://www.star-domain.jp/service/free_server.php 無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~]
 
jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。
 
* ディスク容量 20GB
* DB 1GB
 
ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。
 
=== CORESERVER ===
 
==== メール ====
 
* [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>、に振り分ける
 
条件部分には正規表現が使えるように見える。
 
破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。
 
カスタムフィルターにくせがある。
 
* エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」
 
==== 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からバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。
 
== 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
 
==== Access Control ====


 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。</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>
* [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]
== Server ==
* [https://httpd.apache.org/docs/2.4/ja/mod/mod_authz_core.html#logic mod_authz_core - Apache HTTP Server Version 2.4]
 
=== httpd ===
Apache HTTP Server
 
==== Access Control ====
出典: [https://httpd.apache.org/docs/2.4/en/howto/access.html Access Control - Apache HTTP Server Version 2.4]


DoS攻撃対策などで重要な設定。
DoS攻撃対策などで重要な設定。

2024年12月5日 (木) 07:59時点における最新版

ソフトウェア開発作業全般

Other

ASCIIFlow: 画面構成図などの作成でテキストなので便利かもしれない。

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時にアーカイブ用のプロジェクトに移動できる。

Communication

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

一覧表示

[ホーム]-[チャンネル]-[管理する]-[チャンネル一覧] でチャンネル一覧を閲覧可能。

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

オートコンプリートの無効化方法。

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

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

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

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

```

Coding

タイムゾーン

タイムゾーン呪いの書 #timezone - Qiita

3文字形式は避けたほうが無難。

タイムゾーン名で判定する実装があるので、UTC-9なども避けたほうがいい。

tz databaseのAsia/Tokyoなどの確実性が高い。

Regular Expression

正規表現。重要。覚えにくいが重要なものをメモしておく。

後ろからマッチ。cが置換対象。

Case

/[^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(); }

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

紛らわしい用語がある。

フレームワークの中にライブラリーも含めていいと思う。

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で行単位で編集者が分かる。

UML

Tool

https://chatgpt.com/c/67441feb-d004-800b-96fd-0d9b04ffc628

  • デスクトップ
    • StarUML
    • ArgoUML
    • UMLet
  • クラウド
    • Lucidchart: 有料。
    • Creately: 有料。
    • diagrams.net: モデルじゃない。

UmbrelloとModelioはそれらと比較して何がよかったのだっけ?

Umbrello

Problem

altなどの重なり順番、アクティブの下になっちゃう

optの条件が表示されない。

Modelio

クラス図

  • 汎化 (generalization): 実線白矢印。継承。
  • 実現 (realization): 点線矢印。interfaceの継承。
  • 集約: 白ひし形。
  • コンポジション: 黒ひし形。子が単体で存在できない場合。親と生存期間が同一の場合。
  • 関連: 実線矢印。メソッド内インスタンスなど。
  • 依存: 点線矢印。引数やローカル変数、返却値。

Design

Atomic Design

最近のUIのコンポーネントの組み方。UIコンポーネントを粒度に分けて、ディレクトリー分けして流用するという考え方。

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

インターフェイスと抽象クラス

PHPでインターフェイスと抽象クラスを使う #PHP - Qiita

  • インターフェイスは、クラスに複数実装できるが、抽象クラスは1つしか継承できない。→不特定のクラスで、共通のメソッドを定義したい場合。
  • インターフェイスは、実装のあるメソッドを持つことができないが、抽象クラスは、実装のあるメソッドを持つことができる。→抽象クラスは、複数のクラスの、共通処理の中に、一部違う処理が入る場合、プロパティーが必要な場合などに使用する。

インターフェイス

  • メソッド宣言のみ。
  • static/constの場合に限定して、メソッド定義、定数もOK。

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

基本的に、具象クラスを使わずに、インターフェイスや抽象クラスを使ってインスタンスを生成するというのが、共通する基本パターン。

これにより、いろんなケースに同じコードで対応できる。

Factory Methodパターン

なぜあんなに難しい?Factory Methodパターン - ecbeing labs(イーシービーイング・ラボ)

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

引数の内容に応じて、異なるクラスを作成する。

ただ、Factory Methodパターンを採用すると、コード量が増えて複雑になる。

複雑でややこしいだけなので、基本的に使わなくてよいと思う。

Naming

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] のような形式にすると、キーとバリューが何を意味するか分かってわかりやすい。

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

DB

PDOの真の力を開放する - PHPでデータベースを扱う(3): Architect Note

DBアクセスのモデル化。行をクラスとすると扱いやすい模様。

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[][]

Project

レガシープロジェクトの立て直し

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

List

【2024年版】対話型AIサービスおすすめ11選を徹底比較!チャットボットとの違い・メリット・課題・選び方なども紹介 - NotePM

いろいろある。

Name
Bing
Perplexity AI
ChatGPT
Google Gemini

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の開発もこれでいけると思います。

VCS

List

Comparison of issue-tracking systems - Wikipedia https://en.wikipedia.org/wiki/Comparison_of_issue-tracking_systems

BTS。GitHubみたいな。PHP製の以下がよさそう。

  • Tuleap
  • Phabricator/Phorge: 共用サーバー不能。
  • MantisBT
  • FusionForge
  • GLPI
  • Faveo Helpdesk
  • sourcehut - the hacker's forge: Python製。FSF推奨。
  • Fossil

VCSとの統合状況がまちまち。

phorgeがダメだったので、Mantis/Fossil/sourcehutあたりが共用サーバーで検討可能か。

https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869

他に以下がある。

  • Gitea
  • Cgit
  • Gitlab
  • SourceHut: Python
  • GitBucket: Java

Gitlabは共用サーバーで可能なのか?無理。cgitの他、gogsもある?

CGIで利用可能なもの。

  • Cgit: gitの出力を見れるだけ。issueはない。
  • Gitweb: cgit同様。
  • ViewGit:
  • Kallithea: 有力。Kallithea

Git

Commit

マージコミット後のコミット追加

マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。

git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。

しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。

コミットオプション

Git - git-commit Documentation

コミットメッセージ指定のためのオプションがある。

  • -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
  • -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
  • -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
  • -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。

基本は-m。-mの複数指定。

過去コミットのメールアドレスの変更

単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。

git commit --author="John Doe <john@doe.org>"

--amendと併用することで、過去コミットも変更できる。

数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。

第一コミットの変更

通常、第一コミットはammend以外では変更できない。

rebase --root [branch] でブランチの第一コミットも参照して改変可能。

マージコミットの打ち消し

マージコミットは扱いがやや特殊。

git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前

どちらか。

stash

復元

Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita

git stash drop実行時に、削除したコミットのSHA1が表示される。

そのSHA1をapplyで指定すれば、取り込める。

git stash apply [stash_hash]
リモート

gitの不要なブランチを消すコマンド #Git - Qiita

git fetch -p/--prune

リモートの削除済みブランチをローカルに同期する。

リモートの最新タグ

https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git

git ls-remote --tag --sort=taggerdate

date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。

https:/git-scm.com/docs/git-ls-remote.html

https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning

git rev-listでいけそう。

https:/gist.github.com/rponte/fdc0724dd984088606b0

差分ファイル抽出

情報源: gitで差分ファイルを抽出する #Git - Qiita

git archiveとgit diffを組み合わせる。

git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip

ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。

git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?

例:

mkdir -p archive
git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/
core.autocrlf

warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it

Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf

  • true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
  • false=変換しない。
  • input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。

わかりにくい。基本はfalseで良いと思われる。

gitkの文字化け対策

gitkのエンコーディングを設定する - Pistolfly

gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。

git config --global gui.encoding utf-8
ファイル名などの文字化け対策

Git for Windows で日本語を使いたい #Vim - Qiita

git config --global core.quotepath false
git config --global gui.encoding utf-8
改名と修正

改名と修正を同時にすると、改名を検知できない。

-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。

差分無視

git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita

-wでインデント違いを無視してくれる。

squash

squashすると、squash対象コミットが、対象の直前のコミットに含められる。

gitignore

Git - gitignore Documentation

Format

記述方法を整理する。

  • 空行は無視。
  • #始まりの行はコメント扱い。
  • 終端スペースは無視。
  • !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
  • /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
    • 先頭と中間の/は相対パスを意味する。
    • それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
    • 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
  • *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
  • **は特殊な意味がある。
    • **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
    • /**=配下のすべてにマッチ。
    • a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。

後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。

反転の!と/の扱いに特に注意が必要。

先頭スラッシュをつけないと、再帰的になる。

    $ cat .gitignore 
    # ディレクトリ foo/bar 以外のすべてを除外
    /* 
    !/foo 
    /foo/* 
    !/foo/bar
空ディレクトリーの維持

How do I add an empty directory to a Git repository? - Stack Overflow

gitは空ディレクトリーを履歴管理できない。何かファイルが必要。

logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。

!.gitignore

.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。

指定ファイルのみ除外
*
!.gitignore

ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。

gitattributes

Git - gitattributes Documentation

gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。

  • text
  • eol
  • working-tree-encoding
  • ident
  • filter
  • diff
  • merge
  • conflict-marker-size
  • whitespace
  • export-ignore: git archiveなどに含めないことをマーク。
  • export-subst
  • delta
  • encoding
ファイルのインデックスのみ削除

git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。

git rm --cached

gitk

problem

ブランチ名が長いと、右クリックしにくい

Other

他のブランチとの同一化
git diff HEAD master | patch -p 1

patchの他にgit applyでもいい。

.netrc

https://social.senooken.jp/conversation/1573147#notice-2217499

Gitのパスワード入力の省略方法に~/.netrcがある。

しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。

In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink

せのお (妹尾 賢)せのお (妹尾 賢) in reply to

理由が分かった。

1. Gitはhttpとhttpsの通信にcURLを使っている。

https://github.com/git/git/blob/master/INSTALL#L141

2. cURLが.netrcにも対応しているから。

https://ec.haxx.se/usingcurl-netrc.html

GitHub

Account

Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.

ユーザー名は、英数字と-のみが使用可能。

組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。

Fossil

外部依存を排除しており、CGIでも動作するという点が非常に良い。気になる。Phorgeの検討が不要になる。

Fossil: A Coherent Software Configuration Management System

いくつか癖があるので注意する。

https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86

複数のリポジトリーを取り扱うことは可能。ただし、Web UI上からリポジトリーの新規作成はできない。リポジトリーの新規作成はあくまでコマンドラインから行う必要がある。ここは集中的。

Install

Binary

Fossil: A Coherent Software Configuration Management System

ソースコードからコンパイルするか、コンパイル済みバイナリーを配置するだけ。

VER=2.25
mkdir -p ~/.local/stow/fossil-$VER ~/.local/bin
cd ~/.local/stow/fossil-$VER
curl -O https://fossil-scm.org/home/uv/fossil-linux-x64-$VER.tar.gz
tar -xf fossil-$VER.*
ln -fns ../stow/fossil-$VER/fossil
Server

Fossil: Serving via CGI

CGIで実行するにはいくつか手順がある。

CGIディレクトリーに以下の内容のCGIスクリプトを用意する。

#!/usr/bin/fossil
repository: /home/fossil/repo.fossil

repositoryの部分は指定方法がいろいろある。単一リポジトリーのホストなら上記でいいが、複数のリポジトリーを取り扱いたければ、リポジトリー群の格納ディレクトリーをdirectory: で指定する。

また、リポジトリーが不在の場合のリダイレクト先を指定するnotfound:もある。

#!/usr/bin/fossil
directory: /home/fossil/repos
notfound: http://url-to-go-to-if-repo-not-found/

CGIスクリプトをcgi-bin/repoとした場合、展開後は [http: //mydomain.org/cgi-bin/repo/XYZ] のようなURLで [/home/fossil/repos/XYZ.fossil] にアクセス可能。

CGIで展開されると。

fossil.cgiにする。

https://chatgpt.com/c/674e38de-a8c0-800b-8991-e0d68a2f0d86

fossilのweb uiではリポジトリーの新規作成ができない。新規作成だけはコマンドラインから行う必要がある。これだけがいまいち。保留。

Phorge

Home

PhorgeはPhabricatorのフォーク。

About

Introduction

◉ Introduction

以下が主な機能。

  • コードレビューツール=Differential
  • リポジトリーブラウザー=Diffusion
  • バグトラッカー=Maniphest
  • ウィキ=Phiriction

GitHubの自己ホスト。

Phabricator

Phabricator - Wikipedia

PhabricatorはもともとFacebook社内のBTSシステム。PHP製。2021-06-01に開発終了。

主なユーザー。

  • AngularJS
  • Discord
  • Facebook

Install

Requirement

LAMP環境で動作する。

共用ホストでも動作するが、一部機能しない。通常コンピューターを推奨している。

  • MySQL: 5.5以上。
  • PHP 7.2以上
  • git: 2.5.0以上。
  • PHP extension: mbstring, iconv, mysql (or mysqli), curl, pcntl

ドメインはサブディレクトリーはだめで、サブドメインじゃないとダメ。

Download

以下のコマンドで取得する。

$ cd somewhere/ # pick some install directory
somewhere/ $ git clone https://we.phorge.it/source/arcanist.git
somewhere/ $ git clone https://we.phorge.it/source/phorge.git

gitの設定。

$ sudo git config --system --add safe.directory somewhere/arcanist
$ sudo git config --system --add safe.directory somewhere/phorge

phorge用のDBを作っておく。

cp /var/www/html/phorge/phabricator/conf/local/local.json.example /var/www/html/phorge/phabricator/conf/local/local.json
"mysql.host": "localhost", "mysql.user": "phorge", "mysql.pass": "password", "mysql.port": 3306, "mysql.charset": "utf8", "mysql.database": "phorgedb"

後は開くだけ。

実操作。

こういうディレクトリー構成想定。

public_html
+ phorge.gnusocial.jp 公開ディレクトリー。
+ phorge phorge関係の格納場所。
  + phorge
  + arcanist

取得。

TAG=2024.35
mkdir phorge
cd phorge
PKG=phorge
git clone --depth 1 https://we.phorge.it/source/$PKG.git
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..
PKG=arcanist
git clone --depth 1 https://we.phorge.it/source/$PKG.git
cd $PKG; git fetch --depth 1 origin tag $TAG; git checkout $TAG; cd ..
git config --add safe.directory arcanist
git config --add safe.directory phorge

phorge/webrootが公開ディレクトリーになるので、これをシンボリックリンクで公開ディレクトリーにリンクする。

DOMAIN=phorge.gnusocial.jp
ln -fns phorge/phorge/webroot ../$DOMAIN

◉ Configuration Guide」に記載のあるリダイレクト設定をする。

以下相当の設定を行う。

<VirtualHost *>
  # Change this to the domain which points to your host.
  ServerName phorge.example.com

  # Change this to the path where you put 'phorge' when you checked it
  # out from the upstream when following the Installation Guide.
  #
  # Make sure you include "/webroot" at the end!
  DocumentRoot /path/to/phorge/webroot

  RewriteEngine on
  RewriteRule ^(.*)$          /index.php?__path__=$1  [B,L,QSA]
</VirtualHost>


<Directory "/path/to/phorge/webroot">
  Require all granted
</Directory>

具体的には、phorge/webroot/.htaccessに以下を記載して、ファイルがなければ作成する。

cat >phorge/webroot/.htaccess <<-'EOT'
RewriteEngine on
RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA]
EOT

上記設定後phorge.gnusocial.jpにアクセスすると以下のエラーになる。

Request parameter '__path__' is not set. Your rewrite rules are not configured correctly.

上記が少し参考になる。require指令を指定していないのが問題。

うーん。この問題を解決できない。調べても解決例が出てこない。断念する。他のソフトにする。

Config

◉ Configuration Guide

以下のコマンドでユーザーを認識させる。

phorge/ $ ./bin/storage upgrade --user <user> --password <password>

Diffusion

Hosting

◉ Diffusion User Guide: Repository Hosting

Kallithea

Kallithea

https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869

Python 3.6でCGIでも動作する管理ソフト。

Kallithea Documentation — Kallithea 0.7.0 documentation

Administrator guide

Installation on Unix/Linux

Installation on Unix/Linux — Kallithea 0.7.0 documentation

Installing a released version in a virtualenv

いくつか方法があるが、virtualenvが推奨されている。

coreserver v1のpythonはpython 3.6だった。

cd public_html/
DOMAIN=kallithea.gnusocial.jp
cd $DOMAIN
python3 -m venv venv

python3 -m venv venvの実行時に以下のエラー。

Error: Command '['/virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 2.

cimg/pythonでvenvによる仮想環境の作成がエラーになる #Python - Qiita

pipが見つからないのが原因の模様。--without-pipでインストールして、仮想環境内にpipを直接インストールする。

python3 -m venv --without-pip venv
. venv/bin/activate
curl https://bootstrap.pypa.io/pip/$(python3 -V | grep -o '[0-9].[0-9]')/get-pip.py -o get-pip.py
python3 get-pip.py
pip install --upgrade pip

OK。以下のコマンドで基本要件を確実にする。

pip install --upgrade pip "setuptools<67"

Kallitheaをインストール。

pip install --upgrade kallithea

なんかエラーが出る。

  ERROR: Command errored out with exit status 1:
   command: /virtual/senooken/public_html/kallithea.gnusocial.jp/venv/bin/python3 -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"'; __file__='"'"'/export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /export/tmp/pip-pip-egg-info-kjtbdngw
       cwd: /export/tmp/pip-install-4k2ozlqh/formencode_9f25a10925bf49da975ba94c0fbba946/
  Complete output (3 lines):
  /usr/lib64/python3.6/distutils/dist.py:261: UserWarning: Unknown distribution option: 'convert_2to3_doctests'
    warnings.warn(msg)
  error in FormEncode setup command: use_2to3 is invalid.
  ----------------------------------------
WARNING: Discarding https://files.pythonhosted.org/packages/2f/53/707c2b9b65ea6bedde67c21cbf7c71394f4a198620d4e9c1771214b91dcc/FormEncode-1.3.1.tar.gz#sha256=ada2f51792b1b484e5bb7b6cc14acfc1bc11fafc967cf015cd57e856053ca7f6 (from https://pypi.org/simple/formencode/). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
Collecting kallithea

[error in FormEncode setup command: use_2to3 is invalid.]

急にpip installで一部のライブラリのインストールが失敗するようになった件 #Python3 - Qiita

setuptoolsを58.0.0未満にすればいいらしい。

pip install setuptools==57.4.0

この実行後pip install --upgrade kallitheaが成功。

Prepare front-end files

以下のコマンドでフロントエンドを用意。

kallithea-cli front-end-build

事前にnpmが必要な模様。

FileNotFoundError: [Errno 2] No such file or directory: 'npm': 'npm'

npmをインストールしたら解決。

Setup

Setup — Kallithea 0.7.0 documentation

Setting up a Kallithea instance

まず以下のコマンドでmy.iniを作成する。

kallithea-cli config-create my.ini http_server=waitress

http_serverのところで使用するHTTPサーバー種別を指定する。waitress, gearbox, gevent, gunicorn, or uwsgi.を指定可能。

ひとまずデフォルトのこれで。

続いてDBを作成する。PostgreSQL/SQLIte/MariaDB/MySQLに対応。最初はSQLiteを使用しておいて、後で他のDBへのアクセスが推奨されている。

が、共用サーバーだと書き込みでプロセス削除されると嫌なので最初からMariaDBにする。まず以下のコマンドでドライバーを取得。

 pip install mysqlclient
 OSError: mysql_config not found

mariadbは違う模様。以下の開発パッケージが必要らしい。

 sudo apt-get install libmysqlclient-dev

不明。一旦スキップ。

SQLite以外を使う場合、my.iniでsqlalchemy.urlのコメントアウトを解除してDBのユーザー名とパスワードを記入しておく。

#########################
##      DB CONFIG      ##
#########################

#sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
#sqlalchemy.url = postgresql://kallithea:password@localhost/kallithea
#sqlalchemy.url = mysql://kallithea:password@localhost/kallithea?charset=utf8mb4
sqlalchemy.url = mysql://[username]:[password]@localhost/kallithea?charset=utf8mb4
## Note: the mysql:// prefix should also be used for MariaDB

https://chatgpt.com/c/674f8938-8590-800b-9a4c-f1ec04fc5869

次回、ディレクトリー構成を整理。

Shell

Shell Command Language

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を最初に書き込んで、後は追記する。

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 

Other

binary

POSIX準拠のシェルスクリプトでバイナリデータを扱う #Bash - Qiita

バイナリーデータの読込はodコマンド。なければhexdump。

書込はprintf。

head/tailの-cはPOSIXで使えたか?

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 のような制御が移るコマンドを実行してしばらくすると、操作できなくなる。

[□挿入モード] にすると回避できる模様。

Web

URL

クエリー配列

やり方がいくつかある。

  1. CSV文字列で受取後分割: https://www.sakdor.net/test/?var=1,2,3 explode(",",$_GET[var]);
  2. 配列添字
    1. http://www.sakdor.net/test/?var%5B%5D=1&var%5B%5D=2&var%5B%5D=3
    2. http://www.sakdor.net/test/?var%5Ba%5D=1&var%5Bb%5D=2&var%5Bc%5D=3
    3. http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3

データが決まっているならcsvがシンプル。

HTTP

RFC 9110: HTTP Semantics

Content-Disposition

Content-Disposition - HTTP | MDN

RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

filenameでファイル名を指定する。ここの値は二重引用符で囲む。スペースを含む場合に必須になる。

multipart/form-data

rfc7578

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

リクエストヘッダー

Content-Type: multipart/form-data; boundary=--hogehoge

リクエストボディー

--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を明記して、ボディーでデータを指定する。

curlコマンドでPOSTする, 様々な形式別メモ |

curlでの送信理由。

-Fで送信データをname=data形式で指定する。ファイルの内容を指定する場合、@filenameで指定する。これを指定すると、リクエストボディーのfilename扱いにしてくれる模様。-Fを指定すると、-H 'Content-Type: multipart/form-data'が自動付与される。たぶん、-dと同様に-X POSTもつく。

curl -X POST -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

データとテキストを同時送信したい場合、-Fで複数指定する。

curl -X POST -F 'age=30' -F file1=@/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

curlだと上記のboundaryなどをうまくやってくれるのだと思う。

リクエストボディー全体をファイルデータにする場合。

curl -X POST -H 'Content-Type: image/jpeg' --data-binary @/var/tmp/sample.jpg https://xxxxx.net/xxxxxx

IP address

出典: 固定IPアドレスの取得方法 ~実は簡単!フリーランスの方も必見です~|VPN活用日記|トピックス|グローカルネットの快適VPN【公式】| 株式会社グローカルネット

自宅サーバーを行う際、固定IPアドレスが必要になる。

取得方法がいくつかある。

  • 契約しているプロバイダでオプションとして申し込む方法
  • 固定IPアドレスに対応しているSIMを契約する方法
  • VPNを利用した固定IPアドレスの提供会社を利用する方法

VPNの固定IPアドレスが安いらしい。ryoかsuwakoが解説していた気がする。

Authentication

認証方式がいくつかある。HTTPで定義される認証方式 (HTTP認証) が有名。

Basic認証

出典: Basic認証 - Wikipedia

Authorization HTTPヘッダーにBasicのあとに [username:password] をBASE64でエンコードして送信する認証方式。

GET /private/index.html HTTP/1.1
Host: example.com
Authorization: Basic cm9vdDpwYXNzd29yZA==

盗聴や改ざんが簡単だが、シンプルという利点がある。

OAuth

Ref

OAuth (オーオース) 権限の認可のための標準。OAuth 2.0が最新の標準。

以下が登場人物。

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

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

処理の流れ。

  1. client->resource owner: Authorization Request。ここでユーザーが手操作でアクセスを承認する。
  2. client<-resource owner: Authorization Grant。
  3. client->authorization server: Authorization Grant。承認された情報でアクセストークンを要求。
  4. client<-authorization server: Access Token
  5. client->resource server: Access Token。アクセストークンでアクセス。
  6. client<-resource server: Access Token

Consumer Key/Secret: アプリ識別用のID/PW。

Access Token: サイトにアクセスするためのパスワード。

API

複数レコードの登録

複数レコードの登録・更新・削除のREST APIについて調べてみた話(+@ Graph API) - junode | 個人開発ブログ

既存のAPIは単一リソースの処理しかないことが多い。JavaScriptなどで単一リソースを何回も呼べばいいというのはそうだけど、JavaScriptなしでは動作しない。一括処理用のAPIを作るしかなくないか?

REST WebAPIのプラクティス | yamarkz.com

delete_bulkなどのような一括処理用のAPIを作るしかない。内部的には単一処理のAPIを作る感じだったとしても。

パラメーター

json - REST API Best practices: args in query string vs in request body - Stack Overflow

パラメーターの指定に3種類ある。

  1. リクエストボディー
  2. クエリー
  3. パス

パスはIDなどを指定する場合だけわかりやすい。それ以外のオプションはクエリーのほうがいい。

ボディーは、通常サーバーのアップロード・ダウンロードデータとして使われる。クエリーはデータの指定に使う。

この原則に従うとシンプルだろう。

  • URIには長さの制限がある。
  • ボディー
    • 引数が非常に多い場合。
    • 画像などバイナリーデータ。
    • キー・値構造を持たない場合。
  • クエリー文字列
    • 引数を簡単に確認できる。
    • 共通の引数の場合。

検索機能のGET/POST

検索機能にGETとPOSTのどちらを使うか?という議論がある。

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

POSTだと、JSONをそのまま送れるので、複雑なケースに対応できる。特に、配列の送信が重要。

GETのほうが検索条件をブックマークにできたり、URLを共有できるので、基本は便利。

ただし、検索などのパラメーターが長くなる場合、使用できない。そもそも検索でそんなに長いパラメーターというのがまずいかもしれない。2000文字あれば十分という説がある。

レート制限対策

いろいろ方法がある。

  • cronなどでデータをサーバー上 (DBなど) に定期保存して、保存データを表示させる。
  • 配列を利用して、1回のリクエストでまとめて取得する。
  • インターバルを設ける。
  • HTTP 429/413を検知して、リトライする。

指数関数的バックオフ

wait_interval = base * 2^n +/- jitter
  • wait_interval は、API が HTTP 429 で応答した場合に、システムがリクエストを再試行するまでの時間となります。
  • base は最初の間隔、つまり最初の再試行までの待ち時間です。この値には3000msを使用することをお勧めします。
  • n は、現在の呼び出しの前にリクエストが通らなかった数です。複数のスレッドやプロセスを使用して並行してAPIを呼び出している場合、nの値は現在のスレッド/プロセスにスコープされます。この値は、現在のスレッド/プロセスが、最後に成功した応答から何回 429 "Too Many Requests" エラーに遭遇したかを表します。
  • jitter は 0 から base の間の乱数です。これは、複数のスレッド/プロセスが全く同時にAPIを呼び出さないように、リクエストを少しずつ分散させるために使用されます。システムが待機するたびに、この乱数値を再計算し wait_interval の合計に加算するか減算するか、ランダムで選択してください。

バックエンドとフロントエンドの分離

https://chatgpt.com/c/6747e923-6174-800b-8816-dd741721de45

SPA (Single Page Application) やJAMStackの影響で、バックエンドはデータを返すだけで、画面描画はフロントエンドが全部するというのが最近の流行。

SSR (Server Side Rendering) とCSR (Client Side Rendering) の違い。フロントエンドの高度化や分業などが理由とのこと。

SSRの利点。

  • SEO
  • 初期表示。
  • 匿名。

SSRの課題。

  • サーバー負荷: データとHTML作成を同時に行うから。
  • 分散困難:

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

curl

HTTPの通信のコマンドラインでの確認でよく使う。

Basic

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

JSONで送信する場合、ヘッダー指定が必須。

*-F: multipart/formのform指定。

curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html"
  http://www.example.com/postit.cgi

@でfilename相当の指定。;でmime typeも指定できる。

@/</;type=自体を送信したい場合、-Fではなく、--form-stringを指定する。

curl: (60) SSL certificate problem: self-signed certificate

Ref: curlで「自己署名証明書」を受け入れるには【curl: (60) SSL certificate problem: self signed certificate】 | LFI.

--insecureオプションを指定すると、localhostなどでの自己署名証明書を許可する。

curl: Failed writing body

pipe - Right After piping to "head"/"tail": "curl: (23) Failure writing output to destination" - Ask Ubuntu

以下のようにhead -n 1を指定するとcurlがエラーを出力する。

curl -H "Content-Type: application/json; charset=utf-8" -H "X-HD-apitoken:$TOKEN"         -d "{\"dbSchemaId\":$dbSchemaId, \"limit\":1, \"offset\":$offset}"         https://$DOMAIN/$ACCOUNT/api/csvexport/version/1.0 | head -n 1
curl: Failed writing body

curlは標準出力に全部書き込めたかチェックしているようで、head -n 1で切り捨てたらcurlはエラーになる。

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

Wireshark

TLS

Ref: SSL/TLSの復号#1 ~Wiresharkの設定~ | 東陽テクニカ | “はかる”技術で未来を創る | ワン・テクノロジーズ・カンパニー.

Wiresharkで通信パケットを確認する場合、デフォルトでTLSで暗号化されているので、内容がわからない。WiresharkでTLSに対応しておく必要がある。

[Preferences]-[Protocols]-[TCP] を選ぶ。

  • ☑Allow subdissector to reassemble TCP stream
  • ☑Reassemble out-of-order semgemnts

上記をチェックしておく。デフォルトでチェックされていた。

続いて、セッションごとのPre-Master Secretを登録する。

Chrome/Firefoxだと、環境変数SSLKEYLOGFILEを設定すれば、このファイルにTLSセッションキーを出力するので、これをWiresharkで読み込むことで、復号対応する。

以下のコマンド相当で、任意のファイル・場所にログファイルを指定する。

export SSLKEYLOGFILE=/tmp/sslkey.log

Macだとlaunchctlで設定しておくといい。これでWebブラウザー経由の場合は見えるようになる。

Security

DoS攻撃

いくつか対策方法がある。

サーバーログにIPアドレスが残るから、それで攻撃元の国を特定して、該当国を一括アクセス拒否。これが効果あるかもしれない。

攻撃元の国は途上国とかが多いだろうから。IPアドレスは簡単に変更できるが、国を変えるのはたいへんだろう。

バリデーションの実装

基本的に、バックエンドで主にチェックして、フロントエンドはUXの向上目的で実装する。データの重複チェックはDBアクセスが必要だったりするから。また、API経由などフロントがそもそもないケースもある。

ただ、社内システムのような、画面経由でしか使わない。悪者がほぼいないと思われるケースは、フロントエンドでの検証だけでも十分に感じる。

二重送信

submitボタンのダブルクリック、リロード、ブラウザーバック・フォワードなど、フォーム周りで注意が必要な保安要素がある。

  1. ボタン連打
  2. ブラウザーバック
  3. リロード (PRG)

項目ごとにすべき対策が異なる。

連打

基本は、ボタンのsubmitのイベント内でdisabled=trueでの無効化。

似た考え方で、スプラッシュのモーダル表示もあり。これがわかりやすいかもしれない。

$("form").submit(function() {
  var self = this;
  $(":submit", self).prop("disabled", true);
  setTimeout(function() {
    $(":submit", self).prop("disabled", false);
  }, 10000);
});

停止にしたら、二度通せなくなるので、タイムアウトで戻すとよい。

Browser

Chromium

Extension

Chromme系で愛用拡張機能を列挙する。

devtool/開発者ツール

イベントリスナー

要素に設定されているイベントを調べよう - ゆずめも

[Elements]-[Event Listeners]-[handler]-右クリック-[Show function definition] でイベントリスナー関数の定義を確認できる。

イベント監視

How to find out which JavaScript events fired? - Stack Overflow

monitorEvent関数で監視できるらしい。他に、FirefoxのFirebugのlog eventsでも監視できるらしい。

Other

Windows Safari

一応ある。2012-05-09のSafari 5.1.7までWindows版が提供されていた。DL1531。

Other

Tool

いくつかWeb関係の開発で役立つツール集を公開しているサイトがある。

localhost

RFC 6761 で規定。RFC 2606で予約。DNSに登録されることはないため、テスト目的で使用可能。ループバック (送信元にそのまま返す) インターフェイス。

IPv4=127.0.0.1/IPv6=::1とされている。

Shared Host

Free

無料で使用可能な共用ホスティングサービスがある。

スタードメイン無料サーバー

ドメインをセットで利用する必要があるものの、スタードメインのスタードメイン無料サーバーがけっこういい。

無料レンタルサーバー | スタードメイン - ドメイン取得 100円(税込)~

jpドメインの金額が相場の中では安い方で、それに無料サーバーがついていくる点。

  • ディスク容量 20GB
  • DB 1GB

ただし、SSHやコマンドは使えないので、FTPでWordPressを展開して設置するとか、そういう簡単な使い方だけ。ただ、それでもWordPressでWebサイトを構築するくらいなら十分だと思う。

CORESERVER

メール

情報

ルールが特殊なので注意する。

ゴミ箱に振り分ける場合。

順1 で[./.Trash] を指定

順2

  • 条件:  [.*]
  • 処理:  ./、に振り分ける

条件部分には正規表現が使えるように見える。

破棄にしないといけない。転送する場合、カスタムフィルターの中に転送を入れる。条件を.*にする。

カスタムフィルターにくせがある。

  • エスケープ(\を前置する)が必要な文字は「'」「"」「|」「`」「~」「?」「!」

Value Domain ネットde診断 byGMO

2024-06-07 Friからバリュードメイン系の利用者に無料で提供しているセキュリティー診断ツール。

Analytics

Exam

## About

https://gnusocial.jp/notice/4506679

### 全般

- マーケティング・ビジネス実務検定

- IMA検定

- Web検定

- ネットマーケティング検定

### 解析系

- ウェブ解析士

- GAIQ

- 統計検定

- Webアナリスト検定

GAIQが無料だしどうせ使うからいいかな。

https://wacul-ai.com/blog/access-analysis/google-analytics-method/gaiq/

https://www.plan-b.co.jp/blog/seo/12792/

## URL

- https://ceres-inc.jp/business-tips/recommended-webmarketing-shikaku/

- https://mynavi-creator.jp/blog/article/qualification-for-web-marketer

- https://www.icloud.co.jp/article/exam/features-and-5-acquisition-benefits.html

- https://digitor.jp/textbook/web-analytical-qualification/

Tool

サイト分析用のツールがいくつかある (2023年ブログランキング!おすすめブログランキングサイト比較【一般人向け】)。

  • SimilarWeb
  • Ubersuggest
  • ahrefs
  • Googleキーワードプランナー

閲覧数取得

出典: GoogleAnalyticsで自サイトの人気記事ランキングを表示する方法 | アフィリエイトJAPAN

  • [行動]-[サイトコンテンツ]-[全てのページ]
  • [表示する行数]=5000
  • [エクスポート]=TSV

流入元特定

会員登録画面の流入元探索方法について - Google アナリティクス コミュニティ」どのページから会員登録があったか、会員登録に結びつく記事は非常に重要。

こんにちは。

探索レポートでユーザーセグメントを作成する集計方法はいかがでしょうか。

・自由形式レポートを作成

・セグメント作成 > ユーザーセグメント

・条件は page_view > パラメータ page_location > 含む:会員登録画面のURL を指定

・「会員登録画面閲覧ユーザー」などセグメント名をセットして保存

・探索レポートにセグメントを適用

・ディメンション:セッションの参照元 / メディア、ランディング ページ + クエリ文字列

・指標:セッション

ご確認よろしくお願いいたします。

※ページ閲覧の発生しなかったセッションはランディングページが (not set)になります。

 開きっぱなしのタブから再訪問するセッションなどが該当します。ご参考までに。

PMProでも似たような回答。

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.

Server

httpd

Apache HTTP Server

Access Control

DoS攻撃対策などで重要な設定。

mod_authz_core/mod_authz_hostがコアモジュール。mod_rewriteも関係ある。

基本構文は以下。

Require host <address>
Require ip <ip address>

1番目の形式はドメイン名。2番目はIPアドレス。部分マッチする。マッチしたもののアクセスを許可する。

Requireの直後にnotを指定してアクセス禁止にできる。こちらが重要。

E-mail

[サーバーIPがブラックリストに載ってメール送信エラーになるのを解除する方法]

MailHog: Go言語製のメールサーバーソフト。

Debian

PHP8

[How To Install PHP 8.0 on Debian 11/10/9 | ComputingForGeeks](https://computingforgeeks.com/how-to-install-php-on-debian-linux/)

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 https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/sury-php.list

wget -qO - https://packages.sury.org/php/apt.gpg | 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](https://tecadmin.net/switch-between-multiple-php-version-on-debian/)

インストールしたら、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で起動を試みましたが、同じくトップ画面を開くと同じエラーになります。

<https://notabug.org/gnusocialjp/gnusocial/src/main/docker/development> にDockerでの起動方法があります。`docker compose up -d` を実行するだけでlocalhostでアクセスできます。

私とあなたとの環境の違いを排除したいので、dockerのインストールだけ頑張って、それでdockerでも簡単に動作確認してくれませんか?

alternative

Ref: DebianAlternatives - Debian Wiki.

OS内でバージョン違いのプログラムを管理するための仕組みがある。それがupdate-alternativesコマンド。

sudo update-alternatives --display vi
sudo update-alternatives --config vi

オプションとコマンド名を指定することで、現在の実体と更新ができる。

XAMPP

ポート番号変更

Xamppでポート競合を防ぐ方法 #PHP - Qiita

XAMPP Control PanelのConfigから変更可能。

phpmyadminはConfigのphpmyadminで、Servers.portを追加する。

Vim

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ファイルがあれば、関連付けを追加するとか。

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();
}

ローカル変数も型名を指定する。これをしないと、インスタンスでコード補完が効かない。

PIM

Personal Information Manager - Wikipedia

PIMという個人情報管理用アプリの分類がある。

  • カレンダー
  • アドレス帳
  • 電子メール
  • タスク管理
  • メモ帳
  • 音声メモ
  • 電卓
  • 時計
  • 電子辞書

E-mail

General

Naming
RFC
  • webmaster
  • support
  • info
  • service
  • pr
  • billing
  • 氏名

売上をアップするメールアドレス、商機を失うメールアドレス | マイナビニュース

infoやwebmasterなど企業サイトが備えるべきメールボックスのルール、ご存じですか? | 編集長ブログ―安田英久 | Web担当者Forum

rfc-jp.nic.ad.jp/rfc-jp/RFC2142-JP.txt

SuperTAINS News No.23 [Page.5]

【Mail】メールアドレス作成のガイドライン(RFC2142) – fumidzuki

公開用のメールアドレス。何にしようか考えていた。

RFC 2142でいくつか推奨されている。

info@ support@ answer@ inquery@ contact@ pubic@

contact@がやっぱり一番しっくりくる。info@ support@はRFC 2142にあるけど,これはビジネスより,サービスに紐付いたもの。個人でやる分にはサービス関係ないから,これは違う。publicも悪くはないのだけど,あまり一般的ではないか。

develop

GNU social JP管理人 (gnusocialjp@gnusocial.jp)'s status on Saturday, 08-Oct-2022 23:13:28 JSTGNU social JP管理人GNU social JP管理人
使用するメールアドレスに悩みます。GitのメールアドレスはGitのホスティングサービスに掲載され一般公開されます。

メーリングリストのメールアドレスも、返信方法によって引用されアーカイブで一般公開されます。

どう使い分けるのがよいでしょうか?案↓
GNU social JP管理人 (gnusocialjp@gnusocial.jp)'s status on Saturday, 08-Oct-2022 23:20:04 JSTGNU social JP管理人GNU social JP管理人
  1. develop@domainのようなアドレスで共有
  2. develop@, ml@ で用途別
  3. contact@ で一般公開用で共有
開発用のメールなので、1がいいですかね。仮に漏洩しても開発関係経由というのがわかるので。

1がいいと思う。

category

目的に応じて使い分けたほうがよさそう。

メールアドレスを何個ぐらい使い分けたら安全・快適に過ごせるのか - Dr.ウーパのコンピュータ備忘録

メールアドレス流出時の被害防止

不審なメールの検知

必要な数

  • 銀行・証券会社
  • 知り合い
  • ショッピングサイト

その他

  • Webサイトなどの公開用
  • 本名でのやり取り
  • ニックネーム
  • 金銭のやり取りのないサービス登録
  • 金銭のやり取りのあるサービス登録
  • 登録にメールアドレスが必要だけど,そんなに使っていないメール

メールアドレスの種類

  • フリーメール
  • プロバイダーメール
  • 独自ドメイン

メールアドレスの種類とアフィリエイトにおける3つの使い分け方法 | アフィリエイト

  • サービス登録用
  • メルマガ購読用(捨てアド)
  • メインアドレス

メールアドレスの使い分けかた(前編) - 学習する機械、学習しない人間

メールアドレスの使い分けかた(後編) - 学習する機械、学習しない人間

これらを考えてどういう名前で何個用意するかを考える。

とりあえずメインで使うmainというアドレスを一つ用意する。残りをどうするか。

Webサイト公開用にcontact

  • main: メインで使うメール。人に直接教えるときや,お金が絡む場合,ショッピングサイトなど実名が求められるような重要な内容にはこれ。こちらから送信するときもこれ。相手の顔が見えているとき。
  • contact:受信専用,公開用。問い合わせ用。なんかフォーラムやブログのコメント欄やcontact usなどにこちらから問い合わせる時なども。相手の顔が見えないときなど。
  • service: 基本的に受信専用,たまに返信。Webサービス登録用。
  • recruit:就職活動用。就職サイトとか転職エージェント,企業とやりとりするときはけっこうメール来るから。
  • job: 個人事業、仕事用、不動産は事業なのでこちら。
  • money: 金融機関登録用。銀行、証券会社、クレジットカード会社、決済会社・サービス。
  • shop/store: ショッピングサイト、個人間売買サイト。
  • ユーザー名: メールアドレスの@以前はユーザー名とみなされることがあるので、ユーザー名のアドレスも用意しておくとよさそうだ。


こちらから送信するときのメールアドレス。

Webサービスに登録するときどうするか。不動産屋さんとか人に教えるときはどうするか。アフィリエイトとかドメインとか実名が求められるときはどうするか。

gmailの+を考える。gmailでは+や.をつけると無限にアドレスをつけられる。ただし,受信は+のないメール。

ただし,gmailの+は使えないときがある。@以前の部分をユーザー名とみなして,+を無効な文字とみなすサービスがある模様。

ネットではがきが印刷~郵送できるポスコミ【1枚から注文OK】

https://www.tomtop.com/もだめ。

今まで使ってきたメールとはどうやりくりするか。

Thunderbirdでやる場合,Archiveするときに既読とメールのコピーを行う。

他のアドレスのメールはmainに転送するようにしておいて,mainのメールアドレスで確認。

最終的にThunderbirdでArchiveを実行したら,宛先のメールのフォルダーに同じ内容が既読状態でコピーされることにする。

このようなフィルターを作っておく。受信時にコピーしてしまうと,未読状態でコピーされてしまうか,受信した瞬間に既読状態になってしまい,見逃す可能性が高い。

Manage Identitiesで返信時に受信したアドレスで返信できるように登録しておく。

Mozilla Thunderbird

プロファイルの統合

ImportExportToolsでデータ移行するというのが手堅い。一括操作を念頭に置いた機能になっている。数が少ないならば、emlファイルをドラッグドロップで取り込むこともできる。