docker コンテナからネットにつながらなくなった
新しく docker run で起動したコンテナで dnf を使うと全然進まない
Ctrl-C で停止したら名前解決失敗してるようなエラーが出てきた
curl で Google にアクセスしてもホスト名が解決できないとか
一旦コンテナを出て ホストから curl すると名前解決できてる

SELinux や firewalld など通信部分に影響しそうなものはホストもコンテナも止まってる
コンテナを新しく起動し直しても一緒

その他いろいろ試したけど全部ダメで最終的に docker デーモンの再起動したら動くようになった
なんだったんだろう
Python のパッケージの場所
site パッケージを使う

WSL の例

>>> import site
>>> site.getsitepackages()
['/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages',
'/usr/lib/python3.6/dist-packages']
>>> site.getuserbase()
'/home/wsluser/.local'
>>> site.getusersitepackages()
'/home/wsluser/.local/lib/python3.6/site-packages'

実際にインポートされるのは sys.path の場所から

>>> import sys
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload',
'/home/wsluser/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages',
'/usr/lib/python3/dist-packages']

-m site を使うとまとめて見れる

~> python3 -m site
sys.path = [
'/home/wsluser',
'/usr/lib/python36.zip',
'/usr/lib/python3.6',
'/usr/lib/python3.6/lib-dynload',
'/home/wsluser/.local/lib/python3.6/site-packages',
'/usr/local/lib/python3.6/dist-packages',
'/usr/lib/python3/dist-packages',
]
USER_BASE: '/home/wsluser/.local' (exists)
USER_SITE: '/home/wsluser/.local/lib/python3.6/site-packages' (exists)
ENABLE_USER_SITE: True

msys2 の場合

$ python -m site
sys.path = [
'/home/msysuser',
'/usr/lib/python37.zip',
'/usr/lib/python3.7',
'/usr/lib/python3.7/lib-dynload',
'/usr/lib/python3.7/site-packages',
]
USER_BASE: '/home/msysuser/.local' (exists)
USER_SITE: '/home/msysuser/.local/lib/python3.7/site-packages' (doesn't exist)
ENABLE_USER_SITE: True

msys2 (mingw64) の場合

$ python -m site
sys.path = [
'C:/softwares/msys2-x86_64/home/mingwuser',
'C:/softwares/msys2-x86_64/mingw64/lib/python38.zip',
'C:/softwares/msys2-x86_64/mingw64/lib/python3.8',
'C:/softwares/msys2-x86_64/mingw64/lib/python3.8/lib-dynload',
'C:/softwares/msys2-x86_64/mingw64/lib/python3.8/site-packages',
]
USER_BASE: 'C:\\Users\\mingwuser/.local' (doesn't exist)
USER_SITE: 'C:\\Users\\mingwuser/.local/lib/python3.8/site-packages' (doesn't exist)
ENABLE_USER_SITE: True

Windows (Anaconda3) の場合

>py -m site
sys.path = [
'C:\\Users\\winuser',
'C:\\Users\\winuser\\Anaconda3\\python37.zip',
'C:\\Users\\winuser\\Anaconda3\\DLLs',
'C:\\Users\\winuser\\Anaconda3\\lib',
'C:\\Users\\winuser\\Anaconda3',
'C:\\Users\\winuser\\Anaconda3\\lib\\site-packages',
'C:\\Users\\winuser\\Anaconda3\\lib\\site-packages\\win32',
'C:\\Users\\winuser\\Anaconda3\\lib\\site-packages\\win32\\lib',
'C:\\Users\\winuser\\Anaconda3\\lib\\site-packages\\Pythonwin',
]
USER_BASE: 'C:\\Users\\winuser\\AppData\\Roaming\\Python' (doesn't exist)
USER_SITE: 'C:\\Users\\winuser\\AppData\\Roaming\\Python\\Python37\\site-packages' (doesn't exist)
ENABLE_USER_SITE: True

Windows (CPython インストーラでユーザインストールの場合)

>py -m site
sys.path = [
'C:\\Users\\winuser',
'C:\\Users\\winuser\\AppData\\Local\\Programs\\Python\\Python38-32\\python38.zip',
'C:\\Users\\winuser\\AppData\\Local\\Programs\\Python\\Python38-32\\DLLs',
'C:\\Users\\winuser\\AppData\\Local\\Programs\\Python\\Python38-32\\lib',
'C:\\Users\\winuser\\AppData\\Local\\Programs\\Python\\Python38-32',
'C:\\Users\\winuser\\AppData\\Local\\Programs\\Python\\Python38-32\\lib\\site-packages',
]
USER_BASE: 'C:\\Users\\winuser\\AppData\\Roaming\\Python' (doesn't exist)
USER_SITE: 'C:\\Users\\winuser\\AppData\\Roaming\\Python\\Python38\\site-packages' (doesn't exist)
ENABLE_USER_SITE: True

fedora 31 の場合

~> python -m site
sys.path = [
'/home/fedorauser',
'/usr/lib64/python37.zip',
'/usr/lib64/python3.7',
'/usr/lib64/python3.7/lib-dynload',
'/home/fedorauser/.local/lib/python3.7/site-packages',
'/usr/lib64/python3.7/site-packages',
'/usr/lib/python3.7/site-packages',
]
USER_BASE: '/home/fedorauser/.local' (exists)
USER_SITE: '/home/fedorauser/.local/lib/python3.7/site-packages' (exists)
ENABLE_USER_SITE: True


Windows だと DLLs に .pyd ファイル
Linux は lib-dynload に .so ファイル (dyn は dynamic)

ここのフォルダは _ から始まるファイルばかり
.py ファイルからインポートされる内部モジュールばかりでユーザが直接 import するのはなさそう

Windows
>>> import site
>>> site
<module 'site' from 'C:\\Users\\winuser\\Anaconda3\\lib\\site.py'>
>>> import _tkinter
>>> _tkinter
<module '_tkinter' from 'C:\\Users\\winuser\\Anaconda3\\DLLs\\_tkinter.pyd'>

Linux
>>> import _sqlite3
>>> _sqlite3
<module '_sqlite3' from '/usr/lib64/python3.7/lib-dynload/_sqlite3.cpython-37m-x86_64-linux-gnu.so'>
Python の -m
-m pip
-m http.server

とか

あまり気にせず使ってたけど -m に指定するのは import で指定するモジュールと同じもの
「.」 区切りで拡張子の .py はつけない
フォルダの場合もあるし

import と違ってメインのモジュールとして扱われる
「python3 foo.py」 で実行した foo.py みたいなもの

if __name__ == "__main__":
pass

の if 文が実行される

http.server だとここの処理で 引数からポートなどの設定を受け取ってサーバを起動するようにしてる
https://github.com/python/cpython/blob/3.8/Lib/http/server.py#L1262
パーティションルートはシステムフォルダ属性ついてる
「C:\userfiles」 フォルダをバックアップしようと robocopy で 「G:\backups\userfiles」 にコピーしたときのこと
コピー中はコピー先に userfiles フォルダがあって途中経過も見えていました
長時間かかる量だったのでしばらく待って完了してから見てみました
すると……
userfiles フォルダがありません
ログではエラーはなく正常終了しています
消した覚えはないけど一応ゴミ箱を見てみるも見つかりません

またコピーし直しかぁと思いつつ なんとなくフォルダのプロパティを見てみると
データがあるようなサイズです
Windows バグったのかなと再起動しようとしたとき もしかして と思ってシステムフォルダを表示するようにしてみると……
userfiles フォルダが出てきました

「C:\userfiles」 は少し特殊でパーティションのルートです
基本は D: や E: などのドライブレターを割り当てますが Linux 風にフォルダにマウントしています
内部的にはボリュームへのジャンクションみたいです
この場合は普通にエクスプローラで見えているのでシステムフォルダとは思いもしませんでした
しかし attrib で見てみると SH 属性 (システムフォルダと隠しフォルダ) を持っていました

C:\>attrib userfiles
SH C:\userfiles

なので robocopy で属性も含めてコピーしていると 「G:\backups\userfiles」 もシステムフォルダと隠しフォルダ属性を持ちます
こっちは普通のフォルダなので属性の効果で見えなくなっていたようです
途中まで見えていたのは robocopy が属性をセットするのがフォルダの中身のコピーを終えてからだからのようです
「G:\backups\usefiles」 はシステムフォルダの必要がないので属性を削除します

attrib -S -H userfiles

これで無事完了
robocopy でコピーするときにルートフォルダのみ A 属性外せないのかな
PostgreSQL で EXPLAIN ANALYZE を JSON で取得
EXPLAIN するとき ANALYZE と FORMAT JSON を両方かけないと思ってたけど構文調べたら 「()」を使ってカンマ区切りにすれば両方指定できた

test1=# explain (analyze true, format json) select * from table1 where id = 1;
QUERY PLAN
------------------------------------------
[ +
{ +
"Plan": { +
"Node Type": "Index Scan", +
"Parallel Aware": false, +
"Scan Direction": "Forward", +
"Index Name": "table1_pkey", +
"Relation Name": "table1", +
"Alias": "table1", +
"Startup Cost": 0.28, +
"Total Cost": 16.30, +
"Plan Rows": 1, +
"Plan Width": 1049, +
"Actual Startup Time": 0.048, +
"Actual Total Time": 0.048, +
"Actual Rows": 0, +
"Actual Loops": 1, +
"Index Cond": "(id = 1)", +
"Rows Removed by Index Recheck": 0+
}, +
"Planning Time": 0.475, +
"Triggers": [ +
], +
"Execution Time": 0.114 +
} +
]
ログインと SPA
ログイン前後でもページの読み込みはしない SPA にしようとしてるのを見て そこ SPA にする必要あるの?って思ってた
ログイン成功時にログイン済みユーザ用 SPA に切り替えればいいじゃん と言う感じ
でも考えてみるとログインしなくても色々見えるサービスってけっこうある (例えば StackOverflow とか Github とか)
自分の場合 そういうのを作ることが全くなくて ログイン機能があるものならログインするまではログイン画面くらいしか見えないものばかり
そんなのだとログイン画面は単体 HTML で済む程度
だけど 未ログインでも色々見えるのならログイン前後で共通コード多いし ひとつの SPA アプリのほうが良いかなと思った
Node.js 14.0 リリース
https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V14.md#14.0.0

そこまで大きな変更はなさそう

ESModules は警告なくなったけど まだ experimental で互換性のない変更はあるかもしれない状態

以前あった fs/promises が復活した
ESModules の書き方だと promises という名前付き export じゃないから default の promises プロパティを取り出す必要があって使いづらいみたい
2 行になるよりは fs/promises を import できるほうがいいとか
existsSync がなかったりするし fs なしで fs.promises の部分だけを import したいことってあんまりと思うけど

V8 はバージョンは 8.1 (Chrome 81 のバージョン) になった
?? と ?: が使える
ファイル名に連番つけないで
ファイルやフォルダ名に無意味に番号つけたがる人いますよね

01 foo.txt
02 bar.jpg

みたいなの
あれがすごく迷惑です

音楽 CD のトラック番号みたいに意味のある順番なら全然問題ないと思います
私もそういうものであれば番号をつけます

しかし その並びに意味があるわけでもないのに番号をつけられてるのもあります
個人の PC 内に限れば使う人が並べたいように番号をつけるのは好きにすれば良いと思います
でもそれを共有フォルダなんかでもやる人がいるんです

余計な番号がなければ 名前でソートすればアルファベット順なので目的のものがすぐ見つけられます
ファイルがない場合でもここにあるはずと場所がわかります
t から始まるものは s と u の間です
そこに無いならファイルはないと判断できます
しかし番号のせいでどこにあるかわからないと全体を何度もみることになります
エクスプローラならキーボードで最初の文字を入れるとそこに移動してくれる機能もあります
しかし 番号があるとその番号を知らないとその機能を使えません

番号に規則性があって統一性もあってドキュメント化されているならマシです
例えば github とかにありそうなフォルダ構成だと

- project1/
- 00 bin/
- 01 src/
- 02 lib/
- project2/
- 00 bin/
- 01 src/
- project3
- 01 src/
- 02 lib/
- 03 dist/

のように 00 は bin で 01 は src みたいなものです
番号に対応するものが決まっていて全部のプロジェクトフォルダで統一でその情報がどこかにまとまってるならいいんです
なのに実際は 01 が src だったり lib だったりするし 対応表みたいなものもありません
他の人が見るところで作った人の脳内にしかない番号を勝手につけるのはホントやめてほしいです

日本語の漢字であれば名前の順にして並びがわかりづらいのもあります
しかし普段から PC 使ってればなんとなくどの辺か見当つくこともあります
少なくともドキュメント化されてない番号がついてことに比べると何倍もマシです

日本語の並びのためだけにムダな番号をつけるくらいなら全部半角文字でいいと思います
私自身 分類するためのフォルダを作るときに日本語はまず使ってないですが対して困ってません
最近では減りつつあると思いますが 日本語ユーザ名だと使えないプログラムもあるくらいです
使わなくて済むならフォルダやファイルに日本語を使わないほうがいいと思います

高機能なエクスプローラならフォルダ内でフィルタ機能があるので助かります
番号を無視してフォルダやファイル名の一部を入れるとマッチするものだけ残ります
でも標準のエクスプローラだと検索になって再帰的にフォルダ内のフォルダ内のファイルなども見てしまうんですよね
さらには エクセルや PDF の本文まで見たりする高機能ぶりです
要らないものまで候補に出すぎて探しづらいです

標準ツールしかない場合はアドレスバーに cmd と打ってコマンドプロンプトを表示して
「dir | find "ファイル名の一部"」 コマンドで番号付きファイル名を調べるのが一番早いかもしれません

また これ関連で 「ファイル名は周りに合わせてつけろ」 と言われたみたいな話を聞いたことがあります
「いやそれ無理だろ」 と思いました
規則性もなく並んだ番号にどう合わせるのでしょうか
別のフォルダで同名のものについた番号を探してもその番号が使われてるかもしれないです
適当に番号をつけて見た目だけ ◯桁の番号が付いていて揃ってるようにしてるんだとしたら最悪ですね
どんどん意味不明な番号が増えて探しづらくなります

もしかして日本語の読みとして 50 音順になるように番号つけてるとしたら 間に新しいのが入るとそれ以降を全部ずらさないといけないと考えると……恐ろしい

==ちょっと追記==

上の方の例で 01, 02 のような隙間のない連番を出したので これだと新しいファイルが来たらとりあえず次の数字にすれば良さそうとも思えます
今 13 まであるなら 14 みたいに
作った時期や順番に意味があるところなら 数字を増やすだけの連番だったり日付をプレフィックスにする意味もわからなくはないです

ですが 実際には 10, 20, 30 だったり 100, 200, 250 のような間に何かが入る可能性を考慮した数字だったりするんですよね
さらに 01, 02, 05, 07, 08, 11, 12 みたいに欠番があったり
もう 「連番」 と呼ぶのがおかしいのかもしれませんが こういう状況だったら新しく作ったファイルの番号を何にするかわかったものじゃないですよね
関数呼び出してそうな URL
珍しい URL を見つけました
オリジン部分は省略してます

/foo/bar.baz/Something(123)/Something2(arg1=text,arg2=12345)

こういう感じです
拡張子があってファイル名ぽいのの後に / 区切りが続いてそれぞれで関数呼び出しみたいなものが書かれています
クエリパラメータなどを使わず / 区切りで関数呼び出しを URL のパスで指定は斬新です

こう書いても標準機能でパースできなくて自力になるので このフォーマットを採用してるフレームワークとかあるのでしょうか
パターンはほぼ同じのしかなかったので全部の機能はわかりませんが キーワード引数もあって意外と高機能そうです

使われていたのは直接ユーザが開く html ページではなく xhr でバックグラウンド通信してるところでした
SNS などで不具合報告してるのは
ブログや SNS で●●が動かない バグってる こんなメッセージが出る とか書いてるのって ウェブとかサーバと通信するものだと中の人に特定される可能性ありそう
多くの人に発生して書かれてるものならともかく 発生原因が特殊でケースがほとんど無い場合 サーバ側の調査で該当が数アカウントだとあの人はこのアカウントなのかって特定できそう
まぁ まともなところなら知ってもそれを公開したりはしないだろうけど
Python の数値の参照は途中から同じ値でも変わる
文字列は結合した結果一緒でも id が別になるのは(たぶん)有名
数値の場合は計算結果が同じ値だったら一緒だったのでそういうものだと思ってたら 256 までだった
整数のみで小数なら 0.5 でも別

a = 10
print(a is (a + 0))
# True

b = 1024
print(b is (b + 0))
# False

c = 256
print(c is (c + 0))
# True

d = 257
print(d is (d + 0))
# False

e = 0.5
print(e is (e + 0))
# False

そういえば前に よく使われる小さい数は最初からオブジェクトの参照を保持していてそれを使う みたいなこと聞いたような気もする

ソースコード中のリテラルは全部同じ id で異なるのは計算した結果 動的に作られた値だけ

a = 1000
b = 1000
c = 1000

d = [2000, 2000, 2000]

print(id(a))
# 1457936

print(id(b))
# 1457936

print(id(c))
# 1457936

for x in d:
print(id(x))

# 1457968
# 1457968
# 1457968
npm の Github に join が完了した
https://github.blog/2020-04-15-npm-has-joined-github/

以前もニュースになってましたが 完了したみたいですね

それにしても Github も npm もマイクロソフトですかー
以前はマイクロソフトは IE と Bing のせいで Web はダメなイメージだったのですが
最近では TypeScript や VSCode もありますし それに加えて Github と npm
いつのまにか Web の開発関係はほぼマイクロソフトツールになりつつありますねー
AWS や GCP に比べるとマイナー感ありますが Azure もやってますし

Web といえば Google のイメージでしたが Google の大きなサービスだと
検索 / Chrome / 地図 / Youtube / 翻訳 などです
開発者的には関係が強いのはやっぱり Chrome です
しかしそれも Edge が Chromium ベースになったのでマイクロソフトも開発に参加してます

一般のウェブユーザが直接関わるものだとやっぱり Google のほうが多そうですが
開発者向けだとマイクロソフトのほうが多いですね
その勢いで IE もどうにかしてほしいものですけど
関数で WebComponents を作るライブラリ
こんなライブラリ見つけました
https://github.com/michael-klein/funcy.js

WebComponents を使う場合 通常は CustomElements を使って HTMLElement を継承したクラス定義を書きます
このライブラリでは関数定義でかけるようにしてくれています
もちろん内部ではクラスを作って customElements.define を使ってます

関数は React の関数コンポーネントのような hook があり useXXX で使う仕組みです
シンプルなものだと関数が要素を返すだけです

usePreactHtm という hook もあって Preact と htm を使うこともできます

CustomElements の定義はムダに書くことが多くて面倒な上 属性とかも扱えてしまう分 その辺りもちゃんと対応しておきたい気がしてどんどん面倒になるのでそういうことを一切気にしなくていいライブラリを使うのもありかなと思いました
フォーム作るのに便利かも
https://nosir.github.io/cleave.js/

クレカ番号でどの会社か表示してくれたり 電話番号でスペース開けてくれたり
日本指定したら固定電話と携帯でスペースの位置が変わったりとすごく親切

日付や時刻もあるし ユーザがフォーマットの指定もできる
法則性のあるテキストを入力してもらうときに入れとく便利かも
CustomElements の初期化はいつすべき?
CustomElement を初期化するタイミング
普通のクラスだと初期化 constructor
だけど Custom Element の場合は connectedCallback が推奨されてる
このメソッドは document のツリーにアタッチされたときに実行される

constructor で初期化すると作っただけで使われない場合や メソッド呼び出すだけでに無駄が多い
div を作って textContent に代入して innerHTML を取り出したり
template を作って innerHTML に代入して content をクローンしたり
form を作って JavaScript から直接 POST したり
HTMLElement は document のツリーにアタッチするとは限らない
表示が必要になって初めて shadow dom の中を作ると無駄が少ない

でもそうすると メソッド実行やプロパティ代入時の setter で困ることがある
初期化されてなくて shadow dom の中がないのでアクセスしてエラーになる
ツリーにアタッチしないと使えないのは不便だし メソッド呼び出し時に初期化することになる
でも全部のメソッドや setter に未初期化を判断して初期化するコードをいれるのは面倒すぎ
結局初期化するし 最初から constructor 呼び出し時に全部作ってしまったほうがいいと思う

connectedCallback のほうがいいケースもある
未初期化でも使えるメソッドがあって それを使うためだけに要素を作ることが多そうな Custom Element
form みたいな標準機能ならともかく ユーザレベルで作れるものでそういうのはほとんどなさそう
単にメソッドに便利機能があるからくらいなら それは別モジュールに切り出しておくべきな気がする
static プロパティへのアクセス
JavaScript のクラス構文は static プロパティへのアクセスが面倒です
this.constructor.foo のような感じになります

this.constructor を使わなくてもクラス名でのアクセスはできます
ただ クラスごとに名前が違ってコピペすると修正しないといけません
さらにクラス名を変えたときにクラス内のコードまでチェックして修正が必要になります
それを避けるために常に同じ名前でクラスのコンストラクタを取得できる仕組みが欲しいです
それが this.constructor になります

でも長くて書くのが面倒なんですよね
それを楽にするためにこういうことしてみました

const $ = class {
static foo = 1
bar() {
return $.foo + 1
}
}

export { $ as Class1 }
import { Class1 } from "./module.js"

console.log(new Class1().bar())
// 2

クラス名を使ってアクセスするのですがそれを常に $ にします
特殊な変数名ぽいので丁度いいと思います
ただクラス名が $ になってしまうと使うときに困るので エクスポートするときに適切な名前にします

モジュールに分けていると 1 つのモジュールファイルの中でクラスをいくつも定義してエクスポートすることはそうないと思いますし わりとありかなと思います
シンプルで使いやすいですし
elm の =
elm の = は一見代入してるようだけど 関数が定義されてて評価時に実行されてるみたい

> a = 10
10 : number
> b = a + 1
11 : number
> b
11 : number
> a = 11
11 : number
> b
12 : number

b が 11 になった後に計算に使ってる a を変えると b も変わる

a = a + 1

っていうインクリメント的な物を書いたら a の結果を取得するときに

a + 1
(a + 1) + 1
((a + 1) + 1) + 1

みたいに無限ループになる

なのでこれを実行すると cyclic definition のエラーメッセージが表示される

-- CYCLIC DEFINITION ------------------------------------------------------ REPL


The `a` value is defined directly in terms of itself, causing an infinite loop.

2| a = a + 1
^
Are you are trying to mutate a variable? Elm does not have mutation, so when I
see a defined in terms of a, I treat it as a recursive definition. Try giving
the new value a new name!

(略)

メッセージの 「Are you are」 はすでに修正済みだったので まだ修正版が npm の最新版になってないだけみたい
https://github.com/elm/compiler/issues/2046
systemctl 使わず Apache を操作する
動かしたい PHP のページがあるけど ちょうど使える環境がない
Docker に CentOS のイメージ入ってたしこれでいいか

みたいな感じで試してみたら systemctl が動かない!


Docker だと PID 1 が systemd じゃなくて systemd が起動していません
そのせいで systemctl コマンドは使えません

Apache の場合 httpd コマンドを実行するだけでバックグラウンドで動作します
再起動や停止するには httpd -k に stop などのコマンドを指定します

httpd -k stop
httpd -k restart

また systemd が使えないと apachectl も同様に使えません

System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
edge://surf
Edge で edge://surf を開くとゲームができる
Chrome の chrome://dino みたいな感じの隠し機能?
Python で引数を分割して受け取れない
引数で受け取るタプルを受取時に分解したくてこういうコードを書いてみましたが エラーでした

def fun(foo, (bar, baz)):
return bar + baz

JavaScript みたいにできてくれればいいのに

記法違うだけで機能はあったりしないのかなとググってみるとこんなページが

https://www.python.org/dev/peps/pep-3113/

Python2 の頃にはあったのに Python3 でなくなったようです
JavaScript ではできるようになったのに逆ですね

引数で受け取るときに指定できるほうが便利だと思うのですけど
***ctl コマンド
systemctl や timedatectl や hostnamectl みたいなの

他になにあるんだろうと bin と sbin フォルダで検索してみた結果

環境は fedora 31 で 追加で入れたパッケージに入ってたものもあるし (pg_ctl など) 入れてないパッケージのものは含まれてないから網羅できてるわけでもない

~> ls /usr/bin | grep ctl
bluetoothctl
bootctl
busctl
coredumpctl
evmctl
hostnamectl
journalctl
kdumpctl
keyctl
localectl
loginctl
networkctl
pg_ctl
portablectl
resolvectl
systemctl
teamdctl
timedatectl
udisksctl
wdctl
~> ls /usr/sbin | grep ctl
apachectl
auditctl
brctl
cupsctl
remotectl
smartctl
sysctl
usernetctl
zramctl
属性も slot みたいに使えたらいいのに
custom element の子要素は slot を使って shadow dom 内に配置できます
その場合 custom element の子要素を変更すると即時に shadow dom 内の要素に反映されます

これが便利なのですが 自由にタグを書けるのでテキストだけ受け取りたいときには向いていません
そういうときには custom element の属性を使いたいのですが そうなると slot みたいな便利機能はありません

自分で JavaScript の処理で shadow dom 内の要素に属性の文字列を入れる必要があります
さらに変更されたときに shadow dom 内にも反映したいなら 属性の変更を監視して 変更時に自分で shadow dom 内の要素の更新が必要です

Framework なしの WebComponents を使うと この辺りが面倒なのですよね
slot のように自動で反映してくれる仕組みがあるといいのですけど
Node.js で HTML 取得して DOM 操作
ふとローカルのスニペット管理ツール使ってよく使うのは選んでコピペするだけで済むようにしようと思いました
言語指定でちゃんとやるなら VSCode の機能があるけど もっとゆるくグローバルで使うもの
コード対応で軽量のメモツールってあまりないからとりあえず markdown 系メモの適当なやつ

それにこのブログの「コード」カテゴリのも登録しとこうかと思って自動で登録するためのところを作ったのでメモ

const fetch = require("node-fetch")
const { JSDOM } = require("jsdom")
const { add } = require("./add.js")

const main = async (url) => {
const res = await fetch(url)
const html = await res.text()
const dom = new JSDOM(html)
const articles = dom.window.document.querySelectorAll("main article")

for(const article of articles) {
const title = article.querySelector(".article-header .article-title").textContent
const body = Array.from(
article.querySelectorAll(".article-body pre code"),
code => {
for(const br of code.querySelectorAll("br")) {
br.replaceWith("\n")
}
const type = code.dataset.lang || ""
const c = code.textContent.trimEnd()
return "```" + type + "\n" + c + "\n```"
}
).join("\n\n")

add(title, body)
}
}

main("http://let.blog.jp/category/%E3%82%B3%E3%83%BC%E3%83%89")
yarn add node-fetch jsdom
node <script>.js

add.js はパースされた title と body を登録する処理

title は記事のタイトル
body はテキストで本文のコードブロックをマークダウン形式にしたもの
複数あるなら空行挟んで複数個のコードブロック

Node.js でもブラウザと同じように DOM 操作できる jsdom 便利
throw の仕方いろいろ
◯ 詳細なし

単純に Error のインスタンスを作って throw

throw new Error("aa")

◯ assign

エラー処理などに使う補足のデータを含めたいとき
プロパティとして Error オブジェクトに追加する 

throw Object.assign(new Error("aa"), { detail: "xxxx" })

◯ object

Error オブジェクトと補足情報を別々にもつオブジェクトを throw する
throw 対象は Error オブジェクトじゃなくてもいい

throw { error: new Error("aa"), detail: "xxxx" }

◯ custom error type

ちゃんとした作りにするなら Error を継承したそれ用の型を作るのがたぶん適切
異なる型なので特別なプロパティを持ってそうということが伝わるし instanceof で種別判定もできる

class AaError extends Error {
constructor(message, detail) {
super(message)
this.detail = detail
}
}

throw new AaError("aa", "xxxx")

◯ no error object

Error オブジェクトは特に必須じゃない
スタックトレースが要らないなら省いてもいい

throw { error: "aa", detail: "aa-error" }
Node.js でも console.table できる
罫線をうまく使って表が表示される
さすがにブラウザみたいにヘッダクリックでソートは無理

Linux だと問題なくキレイに表示されてるけど Windows だとずれて表示された
フォントの問題みたい
横線が半角でいいのに全角表示されるのが原因
Linux での表示もコピペしてエディタで見るとずれる

console.table([{x: 1, y: 2}, {x: 3, y: 0}, {x: 4, y: 4}])
┌─────────┬───┬───┐
│ (index) │ x │ y │
├─────────┼───┼───┤
│ 0 │ 1 │ 2 │
│ 1 │ 3 │ 0 │
│ 2 │ 4 │ 4 │
└─────────┴───┴───┘

半角ハイフンに置換してみると

┌---------┬---┬---┐
│ (index) │ x │ y │
├---------┼---┼---┤
│ 0 │ 1 │ 2 │
│ 1 │ 3 │ 0 │
│ 2 │ 4 │ 4 │
└---------┴---┴---┘
連番なしに◯回ループ
◯回ループするだけならこれでよかった

for (const k of Array(3)) console.log(1)
// 1
// 1
// 1

Array コンストラクタで作った empty 要素でも for-of ならループ対象
Array.from(Array()) や [...Array()] と一緒でイテレータ使ってるんだからよく考えたらできて当たり前
いったん中身のある配列化しなくてよかった

ちなみに for-in ではキーがないので非対象

for (const i in Array(3)) console.log(1)
// (no output)
IntersectionObserver v2
https://developers.google.com/web/updates/2019/02/intersectionobserver-v2

IntersectionObserver を使っていて VSCode の補完に出てこない isVisible ってプロパティがあるけどずっと false なのが気になって調べてみると上のページが出てきました
v2 の機能みたいです

v2 では実際に見えているかをチェックできるみたいです
ただ 単純な位置計算だけでできなくて重くなるので気軽に使うものではなさそうです

IntersectionObserver コンストラクタのオプションに delay と trackVisibility が追加されて trackVisibility が true だと v2 の機能が使えるようになるようです

isVisible の「見える」というのは「対象の要素が他の要素に完全に遮られておらず スクリーン上で変更や歪めるようなエフェクトを受けてないことを強く保証するもの」だそうです
逆に 「見えない」はその保証ができないということのようです

仕様では isVisible は false negatives は許可されてて false positives は許可されてないそうです
見えてるのに false になることはあるけど 見えてないのに true になることはない ということですね
yarn install で install されない
node_modules 内のパッケージのフォルダを直接消した場合は yarn install してもインストールされません

node_modules フォルダ中の .yarn-integrity ファイルにインストール関連の情報が保存されていて lockfileEntries にインストール済みパッケージとバージョンが書かれています
ここを見て更新の必要があるかを判断するので 実際にフォルダがなくても .yarn-integrity の情報と yarn.lock の情報が一致していれば最新状態と判断されます

フォルダを消してしまった場合は .yarn-integrity の中から再インストールしたいパッケージの行を削除すると yarn install でインストールできるようになります
探すのが面倒なら このファイルごと消してしまっても全部インストールされるので大丈夫です


直接ライブラリのソースをいじっていろいろ試して もとに戻したいからフォルダ消して再インストールしたかったのですが そういう場合は注意が必要です
npm のバージョンリストに日付を表示する
npm の Version History のところは相対日付しか表示されていなくて 2 years ago とかが並んでてもあまり嬉しくないです
具体的にいつ頃なのかわからないですし このバージョンとこのバージョンの間はどれくらい空いてたのかを知りたい時とか不便すぎです

一応マウスを乗せるとツールチップで表示されますが ひとつひとつ乗せないとダメなのは面倒です
同時に見れないですし

そこで title 属性(ツールチップのテキスト)を表示するような CSS を用意しました

time:before {
content: attr(title);
color: #d0841e;
font-size: 11px;
margin-right: 20px;
}

このスタイルを npm のページで表示するようにすれば相対日付の左側に完全な日付が表示されます
配列のシャッフル
わりと普通にやると

const values = [...Array(100).keys()]

const shuffle = a => {
const size = a.length
for (let i = 0; i < size; i++) {
const j = ~~(Math.random() * size)
const t = a[i]
a[i] = a[j]
a[j] = t
}
}

shuffle(values)

長いし サッとやりたいときに書くのも面倒

これでいいかも
ランダムに 1 つ取り出して 最後に push を要素数だけ繰り返し

const shuffle = a => {
const size = a.length
for (let i = 0; i < size; i++) a.push(...a.splice(Math.random() * (size - i), 1))
}

速度は上のよりかなり遅いのでその場限りで短く書きたい時向け
よく見ると 言うほど文字数は変わってない気もする
モバイルのマウスイベント
タップで click イベントが起きる

◯ Android
長押しで contextmenu イベントが起きる
ダブルタップしても dblclick イベントは起きない

◯ iOS
長押ししても contextmenu イベントは起きない
ダブルタップで dblclick イベントが起きる
Let's Encrypt 事件のバグ
https://jovi0608.hatenablog.com/entry/2020/03/09/094737
Let's Encrypt の証明書失効の原因は Go を使ったループ時の参照の扱いだったみたいですね

JavaScript でも var 時代にループ内で関数を作るとありがちだった問題です

const fns = []
for(var i = 0; i < 3; i++) {
fns.push(() => console.log(i))
}
fns[0]()
fns[1]()
fns[2]()

// 3
// 3
// 3

ニュースで見かけたときは何があったんだろうと思ってたらこんな基本的なミスが原因だったんですね

Go は詳しくないですが for の中で確保された i ってブロックスコープじゃないのでしょうか
i の参照を保持して out[0] でアクセスするときに解放された場所にアクセスしてそうに見えます
それでコンパイル時にエラー出れば防げそうなのに

この記事に対するコメントをみてみると Rust なら大丈夫だったみたいなのがありますし Rust だとこういうところも安全のようですね

そもそも Let's Encrypt って Go で動いてたんだ
ローカルにデータを残す GitHack は注意したほうがいいかも
GitHackGist に投稿したデータをホスティングしてくれるサービスです
Gist に保存したHTML ファイルをウェブページとして見ることができます
RawGit の後継みたいなもの
サーバ側での処理が不要なツール・アプリを公開する目的で使えます

GitHack に限るものではないですが HTML をホスティングしてくれるサービスではオリジンに注意したほうが良さそうです
こういったサービスは URL が Gist の URL に関連していて単純にファイルを text/html などの content-type で送信してます
その結果オリジンはみんな一緒です
localStorage などはオリジンごとに異なる領域になりますが オリジンが一緒なら共有です
つまり保存した情報は他人のページからでも見れます

GitHack でホスティングされてるローカルメモツールを使っていたとしたらデータは localStorage などに保存されます
その後悪意あるユーザの GitHack を開くと そのメモが全部どこかに送信される……ということもありえます

悪意がなくても保存する名前が被っていたら上書きされてデータが消えます
もちろん他人とだけじゃなく 自分のツール同士でもありえます
全部のツールで保存するキーを data に統一していたら 別のページを開いたらそっちのデータで上書きされます

投稿している Gist サービスではそれぞれが別の git リポジトリなので独立してそうに思ってしまうのですがホスティングするサービス上は全部いっしょなんですよね
Github Pages などのホスティングサービスはユーザごとにサブドメインなのでオリジンは異なります
自分のリポジトリ同士では保存領域が共有ですが 他人のは別なので盗み見られる心配はないです

そう考えると ウェブページとして表示するツール系は Gist よりもリポジトリのほうがいいのかもしれませんね
個人的には git クライアントで push とかはほぼせずに ブラウザ使ってフォームにテキスト貼りつけて更新したいのでフォルダ構造不要で数ファイル程度なら Gist のほうが気楽に使えていいのですけど
≡メニュー
≡メニューをどう実装するかというのを見かけたので
その時の気分でよく変わるけど最近はこういう感じ

<div class="hover-target">
<div class="face">≡</div>
<ul class="menus">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
</div>

<style>
.hover-target {
display: inline-block;
}
.hover-target:not(:hover) .menus {
display: none;
}
.face {
display: flex;
width: 1.5em;
height: 1.5em;
justify-content: center;
align-items: center;
cursor: default;
box-shadow: 0 0 2px 1px #0003;
}
.menus {
border: 1px solid #bbb;
margin: 5px 0;
padding: 0;
list-style: none;
}
.menus li {
border-bottom: 1px solid #ddd;
padding: 5px 15px;
margin: 0;
cursor: pointer;
}
</style>
ウェブアプリって思ったほどキーボード操作が考えられてない
◯ 操作できないはずの input 系が操作できる
まとめて disabled が面倒なのか上に透明要素が乗ってるだけや pointer-events: none してるだけ
マウスで操作できなくして CSS で操作できない風に見せてる
マウスじゃ操作できないけどキーボード操作でフォーカス合わせて入力できてしまう

◯ 隠れてるだけ
タブ切り替えなどの見える部分と見えない部分がある UI
アニメーションの都合なのか見えていない要素は削除されずに残ってる
overflow: hidden の外側など見えない場所にはちゃんと存在する
タブキーで見えてない input にフォーカス移すと それが画面内にくるように中途半端なスクロールされる
そのせいで画面壊れる


そんな感じの見た目とマウス操作前提だけで考えてるのが多めな印象

そういう自分も面倒なのでマイナーユーザのためにわざわざ考慮しないけど
動的型付け言語でまで静的型付け言語みたいなことしないでほしい
あるプロパティ mode には "includes" か "equals" を文字列で指定するものとします
こういうのがあると一々 enum だったり定数だったりを作る人がいますよね

enum 等の型がすでにあって mode プロパティを受け取る側がその型を指定するようになっているならそれでいいです
しかし そうでもなく最終的に文字列を入れるのであれば それをわざわざ定数化したりとかムダなことはしたいとは思いません

文字列で 2 種類入れるからそういう事を考えるわけであって プロパティが mode_includes という名前で true か false を指定するのであればどうするのでしょう?
普通に true/false を使いますよね
"includes" の文字列だった部分はプロパティ名として扱うことになりましたがプロパティ名を定数や enum として扱うのでしょうか?
さすがにそんなことはしないと思います

プロパティ名であればそのまま文字列として扱うのであれば mode に入れる "includes" なども文字列としてソースコード上で扱えばいいのです
正規表現の Unicode Property
new RegExp(/\p{sc=Hiragana}/u)

みたいなの
他言語だと 「sc=」 がいらないようでそれを参考にしたらエラーが出る

JavaScript の Unicode Property の指定方法はこれ

// Non-binary values
\p{UnicodePropertyValue}
\p{UnicodePropertyName=UnicodePropertyValue}

// Binary and non-binary values
\p{UnicodeBinaryPropertyName}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes

「For most values, the UnicodePropertyName part and equals sign may be omitted.」(ほとんどの値で UnicodePropertyName とイコール記号は省略できる)って書いてるのに Hiragana はだめらしい

その他指定できるプロパティの一覧
https://www.ecma-international.org/ecma-262/10.0/index.html#sec-runtime-semantics-unicodematchproperty-p

ECMAScript のスペックは whatwg みたいに分割版がなくて ES2019 が全部入りのページなせいでかなり重い
今後更新されないはずだけどそう変わるものでもないので 提案時のスペック見るのもあり

https://tc39.es/proposal-regexp-unicode-property-escapes/#sec-runtime-semantics-unicodematchproperty-p
mac にデフォルトのスクリプト言語なくなるんだ
mac でスクリプト言語がデフォルトで入らなくなるというのを見かけて気になったので調べてみました

https://developer.apple.com/documentation/macos_release_notes/macos_catalina_10_15_release_notes
「Scripting Language Runtimes」 のところ

Python, Ruby, and Perl がデフォルトで含まれなくなるようです
Python や Perl ならともかく Ruby まで入ってたんですね
Ruby あるのに Node.js はないんだ……

デフォルトで使えるスクリプト言語がなくなるって結構つらそうですが 最近は多いのでしょうか
CentOS8 もデフォルトだとなにもないです
正確には Python3 がシステム用に入ってますが ユーザが使うべきじゃないという扱いでパスも通されずわかりづらい場所にあります

読んでてもう一つ気になったのが 「あなたのソフトウェアがスクリプト言語に依存するなら ランタイムをアプリと一緒にバンドルすることをおすすめします」って部分
各ソフトウェアが Python や Ruby のランタイムを独自に持ってたらすごく重くなりそうです
Electron みたいなことになりそう
ただ 言語仕様の追加変更が速くなると想定バージョンも色々あって独自に持ってるのがなんだかんだユーザには一番便利なのかもしれません
Node.js (V8) パフォーマンス比較
普段プログラムを実行してるとき ソフトやブラウザのタブをあれこれ開いてても重くならないくらいのスペックの PC (Windows) で動かしたり VM の最低限度の環境で動かしたりしてもあまり速度差を感じません
感じるときといえばディスク速度が遅い場合に npm ライブラリの初期ロードが遅いくらいです

CPU だけに依存する処理なら意外とどこでも変わらないのかと思って⇩のコードをいくつかの環境で実行してみました

node -e "for(let x=0;x<5;x++){console.time(x); for(let i=0,j=0;i<1000000;i++) j+=i; console.timeEnd(x);}"

VM 上の Fedora 31 (Node.js 13.5)

0: 16.607ms
1: 8.044ms
2: 0.962ms
3: 0.949ms
4: 0.99ms

VM 上の Fedora 31 (Node.js 12.16.1)

0: 13.867ms
1: 5.012ms
2: 0.960ms
3: 0.953ms
4: 0.954ms

メインの Windows 10 (Node.js 12.13)

0: 4.398ms
1: 3.273ms
2: 1.232ms
3: 1.186ms
4: 1.192ms

メインの Windows 10 (Chrome 80)

0: 4.19091796875ms
1: 3.22216796875ms
2: 1.18603515625ms
3: 1.219970703125ms
4: 1.222900390625ms

ノート PC Windows 7 (Node.js 12.6)

0: 5.465ms
1: 4.070ms
2: 0.975ms
3: 0.976ms
4: 0.962ms

Fedora と同じホストに置いてる CentOS (Node.js 10.14)

0: 5.388ms
1: 3.839ms
2: 1.214ms
3: 1.200ms
4: 1.201ms

結果は数回実行して結果が特別外れたものじゃないことを確認してから適当に 1 つ取り出してます

同じ Windows だと Node.js も Chrome もほぼ一緒
Windows と Fedora を比べると Fedora は最初 2 回は遅めで以降は少し Windows よりも高速です
いまいちよくわからない結果です
CentOS のものは Windows よりでした

特別スペックが高い(低い)CPU のマシン使ったりしなければあんまり差はでないようです
Node.js のバージョン差のほうが大きいかも
コマンドラインで JSON 表示 (Node.js 編)
これの Node.js 版

node -p "require('./dump.json')"

node コマンドを普通に実行して REPL で require すればいいだけで Node.js インストール済み環境ならそもそも困らないと思う
Python のと違って .foo みたいなプロパティアクセスでほしいとこだけ取れるのが使いやすい
MDN にくまがいた
https://github.com/mdn/kuma

恐竜でもきつねでもなくて くま
MDN のサイトを作ってるものみたい?
KumaScript なるものもあった
こういう MDN のページはこのスクリプトで書かれてるのかな
Wiki みたいな一般的な記法かと思ってた


よく考えたら kuma って日本語じゃん
Sushi Browser
なんか見つけた謎のブラウザ
https://sushib.me/ja/

Chromium 系ブラウザは色々あっても基本は Chromium なのですがこれは Electron ベースのようです
Node.js が使えるということはローカルアクセスなどブラウザではできない機能が豊富そうです
特にターミナルが使えているのが特徴的

コンセプトは 通常のブラウザでは画面がもったいないから最大限効率化したいということみたいです
効率化しすぎた結果なのかサンプル画面を見てもレイアウトがどうなってるのかよくわからないくらいレベルです
renderer プロセスの HTML で Grid 使ってコントロールや webview いっぱい配置した感じなのでしょうか

思いつきで作ったまま放置されてそうな予感はしたのですがそれなりの期間更新されてるようですし 新しいタイプのブラウザとして使ってみるのはありなのかも?
fs/promises は使えなくなってた
以前 fs のメソッドの Promise 版は fs/promises を require してました
いつのまにか fs.promises ができてて fs をインポートしたら一緒に使えるからこっちを使ってましたが fs/promises はどうなってるんだろうと require したら見つかりませんでした

調べてみたら
https://github.com/nodejs/node/pull/20504

どっちも使えるわけではなく fs.promises に変更だったみたいです

ちなみに fs.promises のインポートでたまに見かけるこれですが

import { promises as fs } from "fs"

fs.existsSync など promises にないメソッドが使えないので fs 自体を変数に持ってたほうがいいと思います