プロトタイプ拡張せずメソッド追加する
プロトタイプを追加してメソッドや getter を追加すれば便利なシーンは多いけど なんかプロトタイプ拡張は抵抗もあって積極的にはやってない
ふと クラスの extend で割といい感じになるんじゃないのって思ったのでやってみた

class SuperArray extends Array {
get first() { return this[0] }
get last() {return this[this.length - 1] }
}

const sa = SuperArray.from([1,2,3])
sa.last
// 3

sa.map(e => e + 10).last
// 13

作るときはリテラルじゃ書けずに変換必要で面倒だけど Uint8Array みたいなものと考えたらありといえばありかも
map とかで返ってくる配列も SuperArray になってるし

と思ったけど使えるのはオブジェクトのみで プリミティブ値の String などではダメだった
クラス構文なので new が必須になるけど new にするとオブジェクト版になってしまう
プリミティブ値に対してメソッド追加するのはやっぱりビルトインプロトタイプの拡張しかなさそう
Koa のラッパー
この記事見直してて もうちょっと改造したくなったのでやってみたもの
今 routes ではルーティング設定として各ルートの設定の配列だけをオプションで受け取るけど オブジェクトを受け取ってその一つの routes プロパティで今の配列にしたほうがいいかなって思う
そこで routes プロパティ以外に何を設定できるのか だけど ルーティングってサーバのメインみたいなものでその他ミドルウェアはそこでの処理をするためのおまけの前処理みたいな感じがするし サーバ設定や前段ミドルウェアをそこに書いてしまえば Koa 自体のインスタンス作ったり app.use したりという手間もなくなりそう
ルーティングだけじゃなくて Koa 自体のラッパーにする感じ
使い方はこんなイメージ

const koaServer = require("./path/to/koa-sever.js")
const static = require("koa-static")
const koaBody = require("koa-body")

koaServer({
server: {
keys: ["koakey"],
},
context: {
data: { x: 10 },
},
pre: [
static("."),
koaBody(),
],
routes: [
{
path: "/",
method: "GET",
handler(ctx) {
ctx.body = "ok"
},
},
],
})(8000)

server に app のプロパティ設定で context に app.context の設定
pre がミドルウェアで routes がルーティングの設定
これだけで困らない気がする
思いつくのであるとしたら https/http2 くらいだけど最後の関数呼び出しを http2 みたいなメソッド呼び出しでできるようにすれば十分そうだけど基本 http でいいし

作ってみるとすごく短く書けて感じこうなった(動作確認はしてない)

const Koa = require("koa")
const compose = require("koa-compose")
const routes = require("./path/to/routes.js")

export default options => {
options = options || {}
const app = new Koa()
Object.assign(app.context, options.context)
Object.assign(app, options.server)
app.use(compose([...pre, routes(options.routes)]))

const start = (...a) => app.listen(...a)
start.app = app
return start
}
Document の adoptedStyleSheets は全体に反映して欲しい
ShadowRoot のならその ShadowDOM の中で良いけど Document に設定したならすべての ShadowRoot にも反映して欲しい
ドキュメントなんだからコンポーネントも含めてグローバルでいいと思う
WebComponents 使ってると body 直下にルートコンポーネントを置いて ShadowRoot 外の要素なんてないことが普通
それだと Document に対する adoptedStyleSheets なんていらないし

一応こういう風に document.adoptedStyleSheets を継承させるベースクラスを作っておくことはできるけど毎回は面倒

class CustomHTMLElement extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: "open" }).adoptedStyleSheets = [
...document.adoptedStyleSheets,
this.cssstylesheet,
]
}

static css = ``

get cssstylesheet() {
if (!this.constructor.cssstylesheet) {
const cssss = new CSSStyleSheet()
cssss.replaceSync(this.constructor.css)
this.constructor.cssstylesheet = cssss
}
return this.constructor.cssstylesheet
}
}

使用例⇩

const cssss = new CSSStyleSheet()
cssss.replaceSync(`
button { background: black; color: white; border: 0; border-radius; 5px; padding: 3px 15px; }
`)
document.adoptedStyleSheets = [cssss]

customElements.define("ex-ample", class extends CustomHTMLElement {
static css = "button:hover { background: darkgray; }"

constructor() {
super()
this.shadowRoot.innerHTML = `<button>in component</button>`
}
})

document.body.innerHTML = `
<button>in document</button>
<ex-ample></ex-ample>
`
koa-body はファイルは絶対ローカルディスクに保存されるみたい
Koa の multipart パーサの @koa/multer 系は busboy を中で使ってる
これはファイルを stream として扱えるもの
ファイルにしたいなら pipe でファイルに保存するなど
multer では指定しない場合は MemoryStorage になって変数上に Buffer として持ってる
オプションでディスクへの書き込みもできる

koa-body は multipart も json も x-www-urlencoded も対応してる
けどファイル部分は Formidable 任せになってて ctx.request.files で取得できるデータも formidable の File インスタンス
formidable 自体が自動でディスクに書き込むアップロード用ツールみたいなので koa-body でファイルを受け取ると絶対ディスクに書き込まれる

ローカルに保存する必要はなくて変数上で操作するくらいなら koa-body より @koa/multer のほうが良さそう
アップロードされたファイルを read して delete する必要もあるのを考えると面倒そう
some, every の配列が空の時に逆になる版がほしい
どれかが true なら true が結果となる some で配列が空ということはどれも true じゃないので false という結果は正しいと言えば正しいです
しかし 条件を指定した場合にフィルタする目的の場合に 指定なしということは true という扱いは少なくないです
なので some と every に配列が空の場合に逆の値を返すバージョンがあると便利です
配列を取得してから一旦変数に入れて もし空ならと判断するより取得してからそのままメソッドに渡せたほうがいいですから
なので any, all メソッドを作りました
名前は .NET で some, every に当たるものです
.NET とは結果が違うので混乱しそうでもありますが JavaScript ですし some, every があるので別にいいかなと

Object.assign(Array.prototype, {
any(...a) {
if (this.length === 0) return true
return this.some(...a)
},
all(...a) {
if (this.length === 0) return false
return this.every(...a)
},
})

[1].some(e => true)
// true

[1].some(e => false)
// false

[].some(e => true)
// false

[].some(e => false)
// false

[1].any(e => true)
// true

[1].any(e => false)
// false

[].any(e => true)
// true

[].any(e => false)
// true

[1].every(e => true)
// true

[1].every(e => false)
// false

[].every(e => true)
// true

[].every(e => false)
// true

[1].all(e => true)
// true

[1].all(e => false)
// false

[].all(e => true)
// false

[].all(e => false)
// false
@koa/router で複数のメソッドのルートを登録する
router の get や post メソッドだとひとつずつの登録なので この方法にするとミドルウェア関数を別に作って get と post に同じミドルウェアを設定することになる
他と同じように登録する流れで直接ミドルウェア関数を定義したい場合は register メソッドが使える

const Koa = require("koa")
const Router = require("@koa/router")

const app = new Koa()
const router = new Router()

router.register("/getorpost", ["get", "post"], ctx => {
ctx.body = "get or post request"
})

app.use(router.routes())
app.listen(4000)
ブラウザからリクエストした結果
const res = await fetch("/getorpost", { method: "GET" })
const body = await res.text()
console.log(body)
// get or post request

const res = await fetch("/getorpost", { method: "POST" })
const body = await res.text()
console.log(body)
// get or post request

const res = await fetch("/getorpost", { method: "DELETE" })
const body = await res.text()
console.log(body)
// DELETE http://localhost:4000/getorpost 404 (Not Found)
// Not Found
クラスのインスタンスを関数に bind してる
class C {}
function c() {}
something(c.bind(new C))

っていうコードを見かけた
もちろん C や c の中はちゃんといろいろ処理があるし 名前もちゃんとしてる
「c.bind(new C)」 のところが気になるけど どういう目的のときに使いみちあるんだろう
c の中で this が C のインスタンスを参照することになるけど C のコンストラクタで十分な気がする
new なしで呼び出せるけど そのためだけにこんなことするかな って思うし
見つけたのは Chrome の一部のコードで JavaScript よくわかってない個人のコードではないのでなんか深い理由ありそうだけどよくわかんない
Event は Node でも起こせる
Event ってテキストをクリックしてもそれを含む Element が target (発生元) になります
なので TextNode などではイベントを発生させられないと思っていたのですが

document.body.innerHTML = `
<div></div>
`

window.onclick = console.log
document.body.firstChild.dispatchEvent(new Event("click", { bubbles: true }))
// Event {isTrusted: false, type: "click", target: text, currentTarget: Window, eventPhase: 3, …}

TextNode でも dispatchEvent があり発生元にできました
firstChild は改行とスペースの TextNode です
出力も 「target: text」 になってます

同じように CommentNode でも dispatch 可能です

document.body.innerHTML = `<!-- comment -->`

window.onclick = console.log
document.body.firstChild.dispatchEvent(new Event("click", { bubbles: true }))
// Event {isTrusted: false, type: "click", target: comment, currentTarget: Window, eventPhase: 3, …}
ssh 鍵作る
秘密鍵と公開鍵

ssh-keygen -t rsa

Windows のソフト用 ppk

puttygen id_rsa -O private -o id_rsa.ppk

WSL (Ubuntu) の場合の puttygen インストール

apt install putty-tools
Basic 認証でコロン使いたい
前の記事の続き

Node.js だとフレームワークとか使ってないと自分でユーザ名とパスワードを分解して認証処理をすることになるので 工夫すればできそう

1 つめは総当たり
「a:b:c:d」だと ユーザ名とパスワードの区切りを / で表すと

a / b:c:d
a:b / c:d
a:b:c / d

の 3 パターン
全部に対してマッチするユーザ情報がないか試してみてマッチするのがあればそのユーザとして認証

ユーザに a / b:c:d と a:b:c / d の 2 つが存在すると意図しない方にログインしてしまうのでマッチするのが複数ある場合はエラーにする
ただ これだと重複するユーザができたらエラーになって絶対ログインできない

2 つめはエスケープ
標準で用意されてないなら自分ですればいいじゃない ということで
「a:b / c:d」 みたいなユーザ名にコロンがあるとダブルクオート必要にする
ユーザはユーザ名に 「"a:b"」 って入力する必要があるようにする
サーバ側ではユーザ名がダブルクオートで囲まれてたら除去する
ユーザ名にダブルクオートを含む場合のエスケープも考える必要あり
「"a:b"」 ってユーザ名なら 「"""a:b"""」 が入力になる

サーバ側で対応してる必要あるし 標準の Basic 認証とは違ってしまうので特にオススメはしない
限られたユーザのみでどうしてもコロン使いたいと言われたときの最終手段?

Basic 認証でコロン使うと
Node.js だと Basic 認証の認証情報はこうすればとれます

http.createServer((req, res) => {
const auth = req.headers.authorization
console.log(auth)
})

auth は通常のアクセスだと undefined ですが
レスポンスヘッダに WWW-Authenticate が設定されていて 出てきたダイアログにユーザが入力するとここに値が入ります
user と pass をいれると 「Basic dXNlcjpwYXNz」 になります
「Basic 」 の後ろは base64 エンコードされたものなので デコードすると 「user:pass」 になります

これを見るとユーザ名やパスワードに「:」を使うとどうなるのか気になります
エスケープされるのかなーと ユーザ名とパスワードにコロンいっぱい入れると

Basic YTpiOmM6ZDplOmY=

atob("YTpiOmM6ZDplOmY=")
// "a:b:c:d:e:f"

コロンがいっぱい
区切りの場所がわからないですね

ググってみてもコロンをエスケープする方法はなくてユーザ名にコロン入れられないと書いた Stackoverflow のページが見つかりました
仕様的にも不可能みたい

最初のコロンで分割されるのでパスワードの方にはあっても大丈夫みたいです
xlwings も良いところばかりじゃない
続き
一応 xlwings 使ってみたけど エクセルを使う分ロードは遅めだし エラーが起きたら finally でちゃんとエクセルを終了するような処理を作っておかないとエクセルが開きっぱなしになるなど気を使わないといけない部分もあって そこまで使いやすいわけでもないです
ただのスクリプトならまだしも ウェブサーバで使うとまた別の問題もあったし

スレッド関係のものみたいで

CoInitialize has not been called.

というエラーがでます

import xlwings
import pythoncom

def edit_excel(path):
pythoncom.CoInitialize()
exapp = xlwings.App(visible=False)
book = exapp.books.open(path)
...

といった感じで pythoncom.CoInitialize() を実行する必要があるみたいです
各リクエスト中の処理で edit_excel を実行します

マルチスレッドで起きるらしいので ここだけは同時に実行されないようにしてるのかなって思ったのですけどスレッドを待機とかそういう系でもなさそう
COM の初期化みたいだけど結局よくわからなかった
こういうのがあると動かなくなったときの対処に困るしやっぱりエクセル使わずやりたいな
ExcelJS もだめだった
に openpyxl を試したときは罫線が壊れて使えませんでした
あれこれ探してみてもいい感じでエクセルファイルをいじれるフリーのライブラリってあまりなくて比較的良さそうな exceljs を試してみました

openpyxl みたいにマージしたセルの罫線が壊れることはなかったのですが
書き込んだセルの下罫線が消えたり アラインが変わったり 自動で計算されないなど やっぱり実用は無理でした

アラインはマージしたセルのどこに値を設定するかで左揃えが中央揃えに変わったりのように見えます
自動計算は大変そうですし 内部でエクセルを使わないタイプのライブラリだと対応してるのがあまりなさそうです
でもそれだと事前にエクセルファイルに式をいっぱい作っておいて 元データ用のセルを書き換えたら それを元に色々計算されたデータを見れるということができません
毎回作ったファイルをエクセルで開いてセルの再計算を押さないとダメって不便すぎです

やっぱり 内部でエクセル使うツールしかないのかなぁ
続く
ライブドアブログのエディタ
普段 markdown のような 自作の独自フォーマットの記法から HTML 生成したのをブログエディタに貼り付けて最終的な見た目調整だけして記事公開してるけど一度 HTML 化したらあとから編集が面倒だし 改善したいなーと思うことも多め

ライブドアブログのエディタ自体の仕組みがわかれば拡張機能権限でいろいろ改造して機能追加や変更してカスタマイズできるけどいまいちなんの wysiwyg ツールなのかもわからない

ソース見てみると punymce というのが使われてるみたいだけど
ググってもあんまり情報なくて github には Java のプロジェクトがあるくらい
Star も 50 ないくらいだし本当にこれ?と思うようなもの
見た感じ昔からある古いやつみたいだし 時代を考えるとサーバ側で JavaScript 出力まで全部管理してるようなものでもなんか納得はできるけど……

と思ったのにサーバのレスポンス見たら 「Server: Plack::Handler::Starlet」 ってヘッダが
見たことなかったけど調べてみたら Perl のサーバで使われるみたい
やっぱりよくわからない

類似っぽいので tinymce というのがあってこっちは github で 7000 近くスターがあって npm でインストールもできて デモを見ても割と今風
https://github.com/tinymce/tinymce
https://www.tiny.cloud/docs/demo/full-featured/

もうこれにしてくれたらいいのに

結局 古すぎるのかまともに情報もなかったので 実体の textarea を元に自分で wysiwyg 部分を作って 標準の wysiwyg には触れないというのが一番楽になりそう
それなら好きなライブラリにできるし……
標準機能もフォントサイズやカラーくらいの基本機能しか使ってないからあんまり困らないと思う
ただ画像の追加だけが困りどころだなぁ
JavaScript のわかりづらい {}
これはそれぞれどんな結果を出力するでしょう?

<script>
let x = "arr"
if(x){
{arr: {forEach: function forEach(fn, a){for(const [k, v] of a.entries()){fn(v, k)}}}}[x].forEach(e => console.log(e), [1, 2, 3])
}
if(x) {arr: {forEach: function forEach(fn, a){for(const [k, v] of a.entries()){fn(v, k)}}}}[x].forEach(e => console.log(e), [1, 2, 3])
</script>


上は if の中だから {} がオブジェクトで x に入った "arr" プロパティをとりだしてるから forEach プロパティの入ったオブジェクトになって それの forEach プロパティを取り出しているので 実行する関数はその場で定義してる forEach で 1, 2, 3 がそれぞれ console.log で表示される

下は {} が if の {} になるから arr: はラベル扱い
次の {} はただのブロック扱いで中の forEach: もまたラベル扱い
forEach 関数を定義してるけどそれは使われず無視されて [x] の配列に対する組み込みの forEach になって 2 つ目の引数は意味ないから無視されて 配列の要素の "arr" だけ表示される


……と思いがちですが そうじゃないんです
上側の {} もブロック扱いで arr や forEach はラベル扱いです
結果 上下どちらも "arr" と表示されます


⇩ でも 1 とは表示されず ["x"] は関数ではないとエラーになります

<script>
{x: () => console.log(1)}["x"]()
</script>

Chrome に限らず IE や Firefox などでもです
何度見てもよくハマるんですよね
文が ( や [ から始まるときはセミコロンを前に書くのと同じように { から始まるときは () で囲むか ! や ~ などの単項演算子で始めると気をつけたほうが良さそうです
どっちかというとセミコロンより function(){} と同じで式とみなさせないといけないやつです

SPA じゃないけど SPA ぽくしたいとき
SPA になってないけど ページのロードじゃなくて SPA みたいな遷移したいとき
行き先の HTML を fetch して document.write で全書き換えすれば行けるんじゃないかなって思った

条件として customElements.define だったり setInterval だったりグローバルに影響することはいっさいしないこと
古い DOM が消えて GC されれば完全に消えるような作りが必要

URL は history.push で書き換えて back したときに元の URL の HTML を再 fetch して document.write する
メモリ的に余裕あれば捨てないでおいて back のときにもとに戻せば bfcache (ページバックで戻ったときに JavaScript で処理したものも残ってる) になっていい感じ?

暇な時に試してみよう
深いネストで全部自動で広げたい
こういう構造で

<div class="a">
<div class="b1">message</div>
<div class="b2">
<div class="c1">message</div>
<div class="c2">
<div class="d1">message</div>
<div class="d2">
<div class="e1">message</div>
<div class="e2">
spread max
</div>
</div>
</div>
</div>
</div>

外側の a はサイドバーみたいなもので ウィンドウサイズに応じて高さが変わって 子孫要素の大きさは関係なく親に応じてサイズが変わる
そのときに一番深い e2 の div が下の隙間いっぱいに広がってほしい

高さ固定は無理だし JavaScript でリサイズごとに高さ指定もしたくない
となると CSS で全部 flexbox 化するしかなさそう

.a, .b2, .c2, .d2 {
display: flex;
flex-flow: column nowrap;
}

.b2, .c2, .d2, .e2 {
flex: 1 1 auto;
}

むやみに flexbox 増やすと思わぬ動きしたり困ること多いし もっと楽で良い方法ってないものかなー
e2 を広げる以外に b2, c2, d2 を flexbox にする必要ないんだけど
openpyxl は罫線消えるのがけっこう致命的
Excel を自動で操作したくて C# より Python のほうが楽でいいかなと Python のツールを探して見るとフリーだと xlwings か openpyxl が人気みたい
xlwings は C# の標準の Excel 操作みたいに Excel が必要でマクロ風に Excel 自体を操作できるものらしい
openpyxl のほうはバイナリファイル(といっても xml)を処理するもので Excel 不要

Linux のサーバで動かす予定なので openpyxl を選んで使ってみたらけっこう使いやすくていい感じ
Excel 直接操作にありそうな範囲全体のコピペができないのは不便だけど for でループしてセルごとに処理しても対して遅くない

だけど保存してみたら 罫線が壊れてた
けっこう有名な既知の問題らしくて何年も議論されてるのに直ってない

対処法に openpyxl で全部の罫線を引き直すというのがあるみたいだけど 例を見るとコード中に太さや色等を指定してる
これを見る限りは正しい罫線情報を openpyxl 中で取得もできなそう
ただデータを出力するだけのものならともかく見た目を調整して罫線もいっぱいあるものだと全部手動でやるなんてやってられないので結局使えなかった

openpyxl 中で引いた罫線は残るなら テンプレートを使わず 1 から openpyxl でフォーマット作ればできそうだけどそれはそれで大変すぎるし
罫線使わずただデータを出力するだけなら問題なさそうだけどそれなら pandas とかでもできそうだし あえてこれ使う必要もなさそう
CodeSandbox で表示されないときがある
StackBlitz とか CodeSandbox とか高機能で便利なブラウザ上で HTML や JavaScript の編集・実行ができるツールがあるけどなんだかんだシンプルな昔ながらのが安定かも

CodeSandbox はリロードしたり共有した URL を開いたりしたときに何も表示されないときがある
HTML 部分は何もレンダリングされず画面は真っ白
なのに JavaScript は実行されてるようで 要素が見つからなくてエラーが起きる

<div>
<div id="a"></a>
<script src="src/index.js"></script>
</div>

みたいに最後に JavaScript をロードしてるのでスクリプトが実行されてるならありそうなのに
devtools でみた感じでは csb-loading-screen という id の div と CodeSandbox 関係らしき script タグが複数あるくらい

構文エラーとかは出てないし なぜか数値や文字列を適当に変えたり 使わない変数を追加など何かの変更をして再保存するとかで表示されたりする

他のコード見てみるとフレームワークなどで document.body の内側は全部 JavaScript で作ってるのとか多いし気づかれてないか そもそも HTML は使う想定じゃない?(それならなんで HTML 書けるんだっていいたいけど)
git ですべてのメタ情報を表示する
git ではデフォルトだとメタデータは Author と Date くらいしか表示されません

$ git show --quiet
commit 3baa0b76cea3d44cdc72e6de322dffb55ef627e1 (HEAD -> master)
Author: NER <mail@address>
Date: Mon May 20 23:18:25 2019 +0900

test

GUI ツールでもこれくらいしか表示してないのもよく見ます
ですが実際は Author と Committer の 2 つのユーザ情報があります
通常見えないものも含めて全部の情報を表示するには --pretty=raw を指定します
raw 以外に full と fuller もあります
full は Committer が出る代わりに時刻が出ません
fuller では時刻も出ます
raw になると tree のハッシュ値も増えます

$ git show --quiet --pretty=full
commit 3baa0b76cea3d44cdc72e6de322dffb55ef627e1 (HEAD -> master)
Author: NER <mail@address>
Commit: NER <mail@address>

test

$ git show --quiet --pretty=fuller
commit 3baa0b76cea3d44cdc72e6de322dffb55ef627e1 (HEAD -> master)
Author: NER <mail@address>
AuthorDate: Mon May 20 23:18:25 2019 +0900
Commit: NER <mail@address>
CommitDate: Mon May 20 23:18:25 2019 +0900

test

$ git show --quiet --pretty=raw
commit 3baa0b76cea3d44cdc72e6de322dffb55ef627e1
tree 2ce1eef76631e82282e0f7f0cf9e6f3e9a4a0b1e
author NER <mail@address> 1558361905 +0900
committer NER <mail@address> 1558361905 +0900

test
イメージプレビュー系ライブラリ
Fancybox3
https://fancyapps.com/fancybox/3/
jQuery
良い感じだけど jQuery 依存なのだけがネック
モバイル対応や GPU アクセラレーションやマルチインスタンス対応など高機能なのでもったいない

Fullscreen Lightbox
https://fslightbox.com/javascript
VanillaJS
jQuery 依存ないし良い感じだけど無料版は基本機能だけ
ズーム・サムネ・キャプション・ツールバー など便利機能は有料版の PRO 必要

Lightbox2
https://lokeshdhakar.com/projects/lightbox2/
jQuery
これがこの系統ライブラリのスタンダード?
lightbox 系と呼ばれたりもするし元になったらライブラリぽい
jQuery 必要だし機能もシンプルで最低限だけみたいなので あえて選択はしなくていいかも

WA MediaBox
https://jiri.hybek.cz/wa-mediabox/
VanillaJS
ドキュメントみても情報少なめ(機能が自体が少なめ?)
DEMO の感じだと ZOOM とかキャプションなど高機能なものはなさそう
画像ロード遅め(DEMO の画像が重いだけかも)

PhotoSwipe
https://photoswipe.com/
VanillaJS
ツールバーやキャプションにズームなど 基本機能以上の機能があるしモバイルも対応
さらに VanillaJS ととても良さそうなのに特に聞かない名前だし ウェブサイトもシンプルでちょっと古めなイメージの見た目

lightgallery.js
https://sachinchoolur.github.io/lightgallery.js/
VanillaJS
VanillaJS ですごく高機能
ツールバーやキャプション・ズームに加えて サムネ表示やサムネにカーソル合わせたときのアニメーションもある
ウェブサイトもきれいでアニメーションやロード画面などあって PhotoSwipe よりできる感ある
久々に古い JavaScript で非同期処理を書いた
async/await ないのけっこうつらい

async function main(){
let x = 100
console.log(1)
x += 200
await new Promise(r => setTimeout(r, 1000))
console.log(2)
x += 300
await new Promise(r => setTimeout(r, 2000))
console.log(x)
}
main()
// 1
// 2
// 600

これをするのがこうなる

function main(){
var x = 100
seq([
function(n){
console.log(1)
x += 200
setTimeout(n, 1000)
},
function(n){
console.log(2)
x += 300
setTimeout(n, 2000)
},
function(n){
console.log(x)
n()
}
])
}

function seq(a){
var i = 0
function next(end){
if(end) return
var fn = a[i++]
var args = Array.prototype.slice.call(arguments)
args[0] = next
if(fn) fn.apply(null, args)
}
next()
}

main()
// 1
// 2
// 600

非同期処理用の関数を順番に実行する seq 関数を事前に準備しておく
await したい非同期処理の場所でコードを分割してそれぞれを関数にする
その関数の配列を seq に渡して実行

seq から実行される関数には引数で次の実行のための関数と前の処理から渡された値を受け取る
非同期処理のコールバック関数として 引数で受け取った次の処理を行うための関数を設定すれば await 代わりになる
途中で return したいこともあるので引数で渡される関数の第一引数に true を渡せば途中も終了できる

ローカル変数は引き継がないので seq を実行するスコープで宣言しておく
もしくは引数で受け取る関数の 2 つ目以降の引数で渡す

パッと見騙されそうな変数宣言
ネット上のコード見てたらこういうのがありました

let x, y = 100, data

⇩ のように読んでから

let x = 100
let y = data

「え JavaScript でそんな代入できたっけ?」 と二度見
⇩ みたいにする必要があったはずだけどいつのまにか新機能できてた?

let [x, y] = [100, data]

10 秒くらい考えてから x と y と data を宣言して y に 100 を代入してるだけだと理解しました
自分では宣言をまとめて書くなんてしないからパッと見では脳内パースが正しくできませんでした
Python 書いた後だと特に紛らわしいですよね
マウス乗せたときだけスクロールバーを出す
:hover で overflow を切り替えるだけ
スクロールバーデザインも変えてモバイル風味にしてみた

webkit-scrollbar 系には opacity 効かないし 背景を透明にしても裏側は見れない
-webkit-scrollbar-thumb の background は設定できるけど transition でアニメーションしない
JavaScript で徐々に背景色の alpha 値変えればいけそうだけど CSS で収めたかったのでやってない

<!doctype html>

<style>
* {
box-sizing: border-box;
}

.box {
width: 200px;
height: 300px;
border: 2px solid #c4cf8a;
overflow: hidden;
}

.box:hover {
overflow: overlay;
}

.box::-webkit-scrollbar {
width: 6px;
height: 6px;
}

.box::-webkit-scrollbar-thumb {
background: #aaa;
border-radius: 5px;
}
</style>

<div class="box"></div>

<script>
const b = document.querySelector(".box")
b.innerHTML += ("12345".repeat(10) + "<br/>").repeat(100)
</script>
lit-html でリスナの this は eventContext で設定できる
カスタムエレメント中で render にこんなオプション付きで実行

    render() {
return render(this.template, this.shadowRoot, { eventContext: this })
}

eventContext: this を render の 3 つ目の引数に設定しておくと テンプレートの HTML に @XXXX で設定したリスナ実行時の this がそのカスタムエレメントになる
なにも設定しないと this はイベントが起きた要素

    get template() {
return html`
<div @click=${this.onClickDiv}>click me</div>
`
}

onClickDiv(eve) {
console.log(this)
}

こう書いたときの this が他メソッドと同じようにカスタムエレメント自身なので見やすい

テンプレート側でこうも書けるけど見づらいし忘れがちなので render で設定するほうがおすすめ

html`<div @click=${this.onClickDiv.bind(this)}></div>`

この方法だと render のたびに bind で作った新しい関数を設定してるから毎回リスナを再設定することにもなるしね
Python でクリップボードの REPL 出力を実行できる形式に変換する
import pyperclip

text = pyperclip.paste()
lines = text.splitlines()
lines = [line[4:] if line.startswith(">>>") or line.startswith("...") else "# " + line for line in lines]
pyperclip.copy("\n".join(lines))

⇩のような REPL の出力を

>>> class A: pass
...
>>> def x():
... return 1
...
>>> x()
1
>>> A()
<__main__.A object at 0x7f64c810be48>

⇩に変換する

class A: pass

def x():
return 1

x()
# 1
A()
# <__main__.A object at 0x7f64c810be48>

現在のクリップボードのテキストを変換するので REPL 出力をコピペするときに貼り付けの前にこれを実行する
REPL のフォーマットじゃなくて実行できる正しい Python 構文にしたいときに便利
複数文まとめて再実行するときにも使える
実行にはライブラリ pyperclip が必要

これまで web ページで変換ツールにしていたけど
1)ページ開いて
2)入力ボックスに貼り付けて
3)出力ボックスをコピーして
という手順が面倒でクリップボードのデータをそのまま変更したほうが楽そうなのでやってみた

クリップボード履歴管理ツールを使ってると変更前のも残るので便利
初回表示時にアニメーションしてしまう
表示の ON/OFF で CSS でスライドアニメーションするつくり
クラスのトグルで表示を切り替え
初期状態は localStorage の値次第

初期状態が ON のときにクラスをつけても初回表示の場合はアニメーションせず初期状態として表示や非表示になってるはず
なのになぜかアニメーションする

調べてみたら 別の箇所の初期化の途中で offsetHeight を参照してた
これがあるとその時点でレイアウト計算が行われるので それ以降にクラスを切り替えてtransition が設定されたプロパティが変更されるとアニメーションする

しかたないので アニメーション OFF の状態でレイアウト計算させるようにした

elem.classList.remove("animation")
elem.getClientRects()
elem.classList.add("animation")

アニメーションが OFF の状態でクラス変更なのでアニメーションは起きない
その後 アニメーションを ON にしてもそれ以降に変化はないのでアニメーションしない

ページ準備完了後に body に ready クラスをつけて transition は 「.ready some-elem」 みたいなロード後にのみ有効になるようにしたほうがいいかも

Chrome Extension の background scripts で module を使いたい
Chrome Extension の background scripts は通常こういう風に指定します

  "background": {
"scripts": ["bg.js"]
}

しかし これだと自動で作られた HTML に通常の JavaScript として実行されます
module ではないので import や export は syntax error です
今のところ module としてロードする機能はなさそうなので 自分で HTML ページを作って module としてロードする必要があります

  "background": {
"page": "bg.html"
}

<!doctype html>
<meta charset="utf-8"/>
<script src="bg.js" type="module"></script>
open と close だけ window がある
open や close は window.open や window.close ってよく書くけど
alert とか confirm とか parseInt とか fetch とか atob とか print とかは window はつけない

window を開いたり閉じたりするから必要そうな雰囲気あるけど 実際は window はグローバルオブジェクトなので alert などと扱いは一緒
open も alert も window あってもなくてもいい

だけどなぜかつい書いてしまうし 書いてる例が多い気がする
使えそうな Windows の環境変数
set

コマンドで環境変数リストが見れる
(たぶん)デフォルトで存在して どこかで使えそうな変数のまとめ
値はあくまでサンプル 設定によって変わるものもある

HOMEDRIVE=C:
HOMEPATH=\Users\testuser
SystemDrive=C:
SystemRoot=C:\WINDOWS
windir=C:\WINDOWS
USERNAME=testuser
USERPROFILE=C:\Users\testuser
PUBLIC=C:\Users\Public
ALLUSERSPROFILE=C:\ProgramData
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
ProgramFiles(x86)=C:\Program Files (x86)
ProgramW6432=C:\Program Files
CommonProgramFiles=C:\Program Files\Common Files
CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
CommonProgramW6432=C:\Program Files\Common Files
TEMP=C:\Users\testuser\AppData\Local\Temp
TMP=C:\Users\testuser\AppData\Local\Temp
APPDATA=C:\Users\testuser\AppData\Roaming
LOCALAPPDATA=C:\Users\testuser\AppData\Local
DriverData=C:\Windows\System32\Drivers\DriverData
ComSpec=C:\WINDOWS\system32\cmd.exe
COMPUTERNAME=FRONTIER
USERDOMAIN=FRONTIER
LOGONSERVER=\\FRONTIER
OS=Windows_NT
PROMPT=$P$G
VisualStudioCode の Untitled-X の保存場所
ファイルに保存する前の Untitled-X (X は連番) が保存されてる場所

C:\Users\USER\AppData\Roaming\Code\Backups\XXXXX\untitled

ちゃんとファイルに保存されてるので 強制終了とかがあっても復元できる

Code フォルダが VSCode のデータがあるフォルダ
Electron だからこのフォルダを見つければ Mac や Linux でも中身の構造は同じだと思う

USER はユーザ名

XXXXX は unixtime かハッシュ値
たぶんハッシュ値はフォルダを開いたりワークスペースを開いたりした場合の ID で unixtime はフォルダなどを開いてないときのもの

untitled フォルダ内にはハッシュ値のファイル名になっていて Untilted-X 形式の名前じゃない
ただのテキストなので開いてみればわかる
JavaScript のグローバルオブジェクトのプロパティ
グローバルに存在する関数などを見てると機能が増えたことがわかりやすいので Chrome と Firefox で window のプロパティ一覧

{
let target = window
let name = "window"
while(target){
const keys = Object.keys(Object.getOwnPropertyDescriptors(target))
console.log(name, keys.sort())
target = target.__proto__
name = name + ".__proto__"
}
}

Chrome 73

window (820) [
"$",
"$$",
"$0",
"$1",
"$2",
"$3",
"$4",
"$_",
"$x",
"AbortController",
"AbortSignal",
"AnalyserNode",
"AnimationEvent",
"Array",
"ArrayBuffer",
"Atomics",
"Attr",
"Audio",
"AudioBuffer",
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioListener",
"AudioNode",
"AudioParam",
"AudioParamMap",
"AudioProcessingEvent",
"AudioScheduledSourceNode",
"AudioWorkletNode",
"BarProp",
"BaseAudioContext",
"BatteryManager",
"BeforeInstallPromptEvent",
"BeforeUnloadEvent",
"BigInt",
"BigInt64Array",
"BigUint64Array",
"BiquadFilterNode",
"Blob",
"BlobEvent",
"Boolean",
"BroadcastChannel",
"ByteLengthQueuingStrategy",
"CDATASection",
"CSS",
"CSSConditionRule",
"CSSFontFaceRule",
"CSSGroupingRule",
"CSSImageValue",
"CSSImportRule",
"CSSKeyframeRule",
"CSSKeyframesRule",
"CSSKeywordValue",
"CSSMathInvert",
"CSSMathMax",
"CSSMathMin",
"CSSMathNegate",
"CSSMathProduct",
"CSSMathSum",
"CSSMathValue",
"CSSMatrixComponent",
"CSSMediaRule",
"CSSNamespaceRule",
"CSSNumericArray",
"CSSNumericValue",
"CSSPageRule",
"CSSPerspective",
"CSSPositionValue",
"CSSRotate",
"CSSRule",
"CSSRuleList",
"CSSScale",
"CSSSkew",
"CSSSkewX",
"CSSSkewY",
"CSSStyleDeclaration",
"CSSStyleRule",
"CSSStyleSheet",
"CSSStyleValue",
"CSSSupportsRule",
"CSSTransformComponent",
"CSSTransformValue",
"CSSTranslate",
"CSSUnitValue",
"CSSUnparsedValue",
"CSSVariableReferenceValue",
"CanvasCaptureMediaStreamTrack",
"CanvasGradient",
"CanvasPattern",
"CanvasRenderingContext2D",
"ChannelMergerNode",
"ChannelSplitterNode",
"CharacterData",
"ClipboardEvent",
"CloseEvent",
"Comment",
"CompositionEvent",
"ConstantSourceNode",
"ConvolverNode",
"CountQueuingStrategy",
"Crypto",
"CryptoKey",
"CustomElementRegistry",
"CustomEvent",
"DOMError",
"DOMException",
"DOMImplementation",
"DOMMatrix",
"DOMMatrixReadOnly",
"DOMParser",
"DOMPoint",
"DOMPointReadOnly",
"DOMQuad",
"DOMRect",
"DOMRectList",
"DOMRectReadOnly",
"DOMStringList",
"DOMStringMap",
"DOMTokenList",
"DataTransfer",
"DataTransferItem",
"DataTransferItemList",
"DataView",
"Date",
"DelayNode",
"DeviceMotionEvent",
"DeviceOrientationEvent",
"Document",
"DocumentFragment",
"DocumentType",
"DragEvent",
"DynamicsCompressorNode",
"Element",
"EnterPictureInPictureEvent",
"Error",
"ErrorEvent",
"EvalError",
"Event",
"EventSource",
"EventTarget",
"External",
"File",
"FileList",
"FileReader",
"Float32Array",
"Float64Array",
"FocusEvent",
"FontFace",
"FontFaceSetLoadEvent",
"FormData",
"Function",
"GainNode",
"Gamepad",
"GamepadButton",
"GamepadEvent",
"GamepadHapticActuator",
"HTMLAllCollection",
"HTMLAnchorElement",
"HTMLAreaElement",
"HTMLAudioElement",
"HTMLBRElement",
"HTMLBaseElement",
"HTMLBodyElement",
"HTMLButtonElement",
"HTMLCanvasElement",
"HTMLCollection",
"HTMLContentElement",
"HTMLDListElement",
"HTMLDataElement",
"HTMLDataListElement",
"HTMLDetailsElement",
"HTMLDialogElement",
"HTMLDirectoryElement",
"HTMLDivElement",
"HTMLDocument",
"HTMLElement",
"HTMLEmbedElement",
"HTMLFieldSetElement",
"HTMLFontElement",
"HTMLFormControlsCollection",
"HTMLFormElement",
"HTMLFrameElement",
"HTMLFrameSetElement",
"HTMLHRElement",
"HTMLHeadElement",
"HTMLHeadingElement",
"HTMLHtmlElement",
"HTMLIFrameElement",
"HTMLImageElement",
"HTMLInputElement",
"HTMLLIElement",
"HTMLLabelElement",
"HTMLLegendElement",
"HTMLLinkElement",
"HTMLMapElement",
"HTMLMarqueeElement",
"HTMLMediaElement",
"HTMLMenuElement",
"HTMLMetaElement",
"HTMLMeterElement",
"HTMLModElement",
"HTMLOListElement",
"HTMLObjectElement",
"HTMLOptGroupElement",
"HTMLOptionElement",
"HTMLOptionsCollection",
"HTMLOutputElement",
"HTMLParagraphElement",
"HTMLParamElement",
"HTMLPictureElement",
"HTMLPreElement",
"HTMLProgressElement",
"HTMLQuoteElement",
"HTMLScriptElement",
"HTMLSelectElement",
"HTMLShadowElement",
"HTMLSlotElement",
"HTMLSourceElement",
"HTMLSpanElement",
"HTMLStyleElement",
"HTMLTableCaptionElement",
"HTMLTableCellElement",
"HTMLTableColElement",
"HTMLTableElement",
"HTMLTableRowElement",
"HTMLTableSectionElement",
"HTMLTemplateElement",
"HTMLTextAreaElement",
"HTMLTimeElement",
"HTMLTitleElement",
"HTMLTrackElement",
"HTMLUListElement",
"HTMLUnknownElement",
"HTMLVideoElement",
"HashChangeEvent",
"Headers",
"History",
"IDBCursor",
"IDBCursorWithValue",
"IDBDatabase",
"IDBFactory",
"IDBIndex",
"IDBKeyRange",
"IDBObjectStore",
"IDBOpenDBRequest",
"IDBRequest",
"IDBTransaction",
"IDBVersionChangeEvent",
"IIRFilterNode",
"IdleDeadline",
"Image",
"ImageBitmap",
"ImageBitmapRenderingContext",
"ImageCapture",
"ImageData",
"Infinity",
"InputDeviceCapabilities",
"InputDeviceInfo",
"InputEvent",
"Int16Array",
"Int32Array",
"Int8Array",
"IntersectionObserver",
"IntersectionObserverEntry",
"Intl",
"JSON",
"KeyboardEvent",
"Location",
"MIDIAccess",
"MIDIConnectionEvent",
"MIDIInput",
"MIDIInputMap",
"MIDIMessageEvent",
"MIDIOutput",
"MIDIOutputMap",
"MIDIPort",
"Map",
"Math",
"MediaCapabilities",
"MediaDeviceInfo",
"MediaDevices",
"MediaElementAudioSourceNode",
"MediaEncryptedEvent",
"MediaError",
"MediaList",
"MediaMetadata",
"MediaQueryList",
"MediaQueryListEvent",
"MediaRecorder",
"MediaSession",
"MediaSettingsRange",
"MediaSource",
"MediaStream",
"MediaStreamAudioDestinationNode",
"MediaStreamAudioSourceNode",
"MediaStreamEvent",
"MediaStreamTrack",
"MediaStreamTrackEvent",
"MessageChannel",
"MessageEvent",
"MessagePort",
"MimeType",
"MimeTypeArray",
"MouseEvent",
"MutationEvent",
"MutationObserver",
"MutationRecord",
"NaN",
"NamedNodeMap",
"Navigator",
"NetworkInformation",
"Node",
"NodeFilter",
"NodeIterator",
"NodeList",
"Notification",
"Number",
"Object",
"OfflineAudioCompletionEvent",
"OfflineAudioContext",
"OffscreenCanvas",
"OffscreenCanvasRenderingContext2D",
"Option",
"OscillatorNode",
"OverconstrainedError",
"PageTransitionEvent",
"PannerNode",
"Path2D",
"PaymentInstruments",
"PaymentManager",
"PaymentRequestUpdateEvent",
"Performance",
"PerformanceEntry",
"PerformanceLongTaskTiming",
"PerformanceMark",
"PerformanceMeasure",
"PerformanceNavigation",
"PerformanceNavigationTiming",
"PerformanceObserver",
"PerformanceObserverEntryList",
"PerformancePaintTiming",
"PerformanceResourceTiming",
"PerformanceServerTiming",
"PerformanceTiming",
"PeriodicWave",
"PermissionStatus",
"Permissions",
"PhotoCapabilities",
"PictureInPictureWindow",
"Plugin",
"PluginArray",
"PointerEvent",
"PopStateEvent",
"ProcessingInstruction",
"ProgressEvent",
"Promise",
"PromiseRejectionEvent",
"Proxy",
"PushManager",
"PushSubscription",
"PushSubscriptionOptions",
"RTCCertificate",
"RTCDTMFSender",
"RTCDTMFToneChangeEvent",
"RTCDataChannel",
"RTCDataChannelEvent",
"RTCIceCandidate",
"RTCPeerConnection",
"RTCPeerConnectionIceEvent",
"RTCRtpReceiver",
"RTCRtpSender",
"RTCRtpTransceiver",
"RTCSessionDescription",
"RTCStatsReport",
"RTCTrackEvent",
"RadioNodeList",
"Range",
"RangeError",
"ReadableStream",
"ReferenceError",
"Reflect",
"RegExp",
"RemotePlayback",
"ReportingObserver",
"Request",
"ResizeObserver",
"ResizeObserverEntry",
"Response",
"SVGAElement",
"SVGAngle",
"SVGAnimateElement",
"SVGAnimateMotionElement",
"SVGAnimateTransformElement",
"SVGAnimatedAngle",
"SVGAnimatedBoolean",
"SVGAnimatedEnumeration",
"SVGAnimatedInteger",
"SVGAnimatedLength",
"SVGAnimatedLengthList",
"SVGAnimatedNumber",
"SVGAnimatedNumberList",
"SVGAnimatedPreserveAspectRatio",
"SVGAnimatedRect",
"SVGAnimatedString",
"SVGAnimatedTransformList",
"SVGAnimationElement",
"SVGCircleElement",
"SVGClipPathElement",
"SVGComponentTransferFunctionElement",
"SVGDefsElement",
"SVGDescElement",
"SVGDiscardElement",
"SVGElement",
"SVGEllipseElement",
"SVGFEBlendElement",
"SVGFEColorMatrixElement",
"SVGFEComponentTransferElement",
"SVGFECompositeElement",
"SVGFEConvolveMatrixElement",
"SVGFEDiffuseLightingElement",
"SVGFEDisplacementMapElement",
"SVGFEDistantLightElement",
"SVGFEDropShadowElement",
"SVGFEFloodElement",
"SVGFEFuncAElement",
"SVGFEFuncBElement",
"SVGFEFuncGElement",
"SVGFEFuncRElement",
"SVGFEGaussianBlurElement",
"SVGFEImageElement",
"SVGFEMergeElement",
"SVGFEMergeNodeElement",
"SVGFEMorphologyElement",
"SVGFEOffsetElement",
"SVGFEPointLightElement",
"SVGFESpecularLightingElement",
"SVGFESpotLightElement",
"SVGFETileElement",
"SVGFETurbulenceElement",
"SVGFilterElement",
"SVGForeignObjectElement",
"SVGGElement",
"SVGGeometryElement",
"SVGGradientElement",
"SVGGraphicsElement",
"SVGImageElement",
"SVGLength",
"SVGLengthList",
"SVGLineElement",
"SVGLinearGradientElement",
"SVGMPathElement",
"SVGMarkerElement",
"SVGMaskElement",
"SVGMatrix",
"SVGMetadataElement",
"SVGNumber",
"SVGNumberList",
"SVGPathElement",
"SVGPatternElement",
"SVGPoint",
"SVGPointList",
"SVGPolygonElement",
"SVGPolylineElement",
"SVGPreserveAspectRatio",
"SVGRadialGradientElement",
"SVGRect",
"SVGRectElement",
"SVGSVGElement",
"SVGScriptElement",
"SVGSetElement",
"SVGStopElement",
"SVGStringList",
"SVGStyleElement",
"SVGSwitchElement",
"SVGSymbolElement",
"SVGTSpanElement",
"SVGTextContentElement",
"SVGTextElement",
"SVGTextPathElement",
"SVGTextPositioningElement",
"SVGTitleElement",
"SVGTransform",
"SVGTransformList",
"SVGUnitTypes",
"SVGUseElement",
"SVGViewElement",
"Screen",
"ScreenOrientation",
"ScriptProcessorNode",
"SecurityPolicyViolationEvent",
"Selection",
"Set",
"ShadowRoot",
"SharedArrayBuffer",
"SharedWorker",
"SourceBuffer",
"SourceBufferList",
"SpeechSynthesisErrorEvent",
"SpeechSynthesisEvent",
"SpeechSynthesisUtterance",
"StaticRange",
"StereoPannerNode",
"Storage",
"StorageEvent",
"String",
"StylePropertyMap",
"StylePropertyMapReadOnly",
"StyleSheet",
"StyleSheetList",
"SubtleCrypto",
"Symbol",
"SyncManager",
"SyntaxError",
"TaskAttributionTiming",
"Text",
"TextDecoder",
"TextDecoderStream",
"TextEncoder",
"TextEncoderStream",
"TextEvent",
"TextMetrics",
"TextTrack",
"TextTrackCue",
"TextTrackCueList",
"TextTrackList",
"TimeRanges",
"Touch",
"TouchEvent",
"TouchList",
"TrackEvent",
"TransformStream",
"TransitionEvent",
"TreeWalker",
"TypeError",
"UIEvent",
"URIError",
"URL",
"URLSearchParams",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"UserActivation",
"VTTCue",
"ValidityState",
"VisualViewport",
"WaveShaperNode",
"WeakMap",
"WeakSet",
"WebAssembly",
"WebGL2RenderingContext",
"WebGLActiveInfo",
"WebGLBuffer",
"WebGLContextEvent",
"WebGLFramebuffer",
"WebGLProgram",
"WebGLQuery",
"WebGLRenderbuffer",
"WebGLRenderingContext",
"WebGLSampler",
"WebGLShader",
"WebGLShaderPrecisionFormat",
"WebGLSync",
"WebGLTexture",
"WebGLTransformFeedback",
"WebGLUniformLocation",
"WebGLVertexArrayObject",
"WebKitCSSMatrix",
"WebKitMutationObserver",
"WebSocket",
"WheelEvent",
"Window",
"Worker",
"WritableStream",
"XMLDocument",
"XMLHttpRequest",
"XMLHttpRequestEventTarget",
"XMLHttpRequestUpload",
"XMLSerializer",
"XPathEvaluator",
"XPathExpression",
"XPathResult",
"XSLTProcessor",
"alert",
"atob",
"blur",
"btoa",
"cancelAnimationFrame",
"cancelIdleCallback",
"captureEvents",
"chrome",
"clear",
"clearInterval",
"clearTimeout",
"clientInformation",
"close",
"closed",
"confirm",
"console",
"copy",
"createImageBitmap",
"crypto",
"customElements",
"debug",
"decodeURI",
"decodeURIComponent",
"defaultStatus",
"defaultstatus",
"devicePixelRatio",
"dir",
"dirxml",
"document",
"encodeURI",
"encodeURIComponent",
"escape",
"eval",
"event",
"external",
"fetch",
"find",
"focus",
"frameElement",
"frames",
"getComputedStyle",
"getEventListeners",
"getSelection",
"globalThis",
"history",
"indexedDB",
"innerHeight",
"innerWidth",
"inspect",
"isFinite",
"isNaN",
"isSecureContext",
"keys",
"length",
"localStorage",
"location",
"locationbar",
"matchMedia",
"menubar",
"monitor",
"monitorEvents",
"moveBy",
"moveTo",
"name",
"navigator",
"offscreenBuffering",
"onabort",
"onafterprint",
"onanimationend",
"onanimationiteration",
"onanimationstart",
"onappinstalled",
"onauxclick",
"onbeforeinstallprompt",
"onbeforeprint",
"onbeforeunload",
"onblur",
"oncancel",
"oncanplay",
"oncanplaythrough",
"onchange",
"onclick",
"onclose",
"oncontextmenu",
"oncuechange",
"ondblclick",
"ondevicemotion",
"ondeviceorientation",
"ondeviceorientationabsolute",
"ondrag",
"ondragend",
"ondragenter",
"ondragleave",
"ondragover",
"ondragstart",
"ondrop",
"ondurationchange",
"onemptied",
"onended",
"onerror",
"onfocus",
"ongotpointercapture",
"onhashchange",
"oninput",
"oninvalid",
"onkeydown",
"onkeypress",
"onkeyup",
"onlanguagechange",
"onload",
"onloadeddata",
"onloadedmetadata",
"onloadstart",
"onlostpointercapture",
"onmessage",
"onmessageerror",
"onmousedown",
"onmouseenter",
"onmouseleave",
"onmousemove",
"onmouseout",
"onmouseover",
"onmouseup",
"onmousewheel",
"onoffline",
"ononline",
"onpagehide",
"onpageshow",
"onpause",
"onplay",
"onplaying",
"onpointercancel",
"onpointerdown",
"onpointerenter",
"onpointerleave",
"onpointermove",
"onpointerout",
"onpointerover",
"onpointerup",
"onpopstate",
"onprogress",
"onratechange",
"onrejectionhandled",
"onreset",
"onresize",
"onscroll",
"onsearch",
"onseeked",
"onseeking",
"onselect",
"onselectionchange",
"onselectstart",
"onstalled",
"onstorage",
"onsubmit",
"onsuspend",
"ontimeupdate",
"ontoggle",
"ontransitionend",
"onunhandledrejection",
"onunload",
"onvolumechange",
"onwaiting",
"onwebkitanimationend",
"onwebkitanimationiteration",
"onwebkitanimationstart",
"onwebkittransitionend",
"onwheel",
"open",
"openDatabase",
"opener",
"origin",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"parseFloat",
"parseInt",
"performance",
"personalbar",
"postMessage",
"print",
"profile",
"profileEnd",
"prompt",
"queryObjects",
"queueMicrotask",
"releaseEvents",
"requestAnimationFrame",
"requestIdleCallback",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollBy",
"scrollTo",
"scrollX",
"scrollY",
"scrollbars",
"self",
"sessionStorage",
"setInterval",
"setTimeout",
"speechSynthesis",
"status",
"statusbar",
"stop",
"styleMedia",
"table",
"toolbar",
"top",
"undebug",
"undefined",
"unescape",
"unmonitor",
"unmonitorEvents",
"values",
"visualViewport",
"webkitCancelAnimationFrame",
"webkitMediaStream",
"webkitRTCPeerConnection",
"webkitRequestAnimationFrame",
"webkitRequestFileSystem",
"webkitResolveLocalFileSystemURL",
"webkitSpeechGrammar",
"webkitSpeechGrammarList",
"webkitSpeechRecognition",
"webkitSpeechRecognitionError",
"webkitSpeechRecognitionEvent",
"webkitStorageInfo",
"webkitURL",
"window"
]
window.__proto__ (3)
["PERSISTENT", "TEMPORARY", "constructor"]
window.__proto__.__proto__
["constructor"]
window.__proto__.__proto__.__proto__ (4)
["addEventListener", "constructor", "dispatchEvent", "removeEventListener"]
window.__proto__.__proto__.__proto__.__proto__ (12)
["__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__",
"__proto__", "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
"toLocaleString", "toString", "valueOf"]

Firefox 66

window Array(771) [
"AbortController",
"AbortSignal",
"AnalyserNode",
"Animation",
"AnimationEffect",
"AnimationEvent",
"AnimationPlaybackEvent",
"Array",
"ArrayBuffer",
"Attr",
"Audio",
"AudioBuffer",
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioListener",
"AudioNode",
"AudioParam",
"AudioProcessingEvent",
"AudioScheduledSourceNode",
"BarProp",
"BaseAudioContext",
"BatteryManager",
"BeforeUnloadEvent",
"BiquadFilterNode",
"Blob",
"BlobEvent",
"Boolean",
"BroadcastChannel",
"ByteLengthQueuingStrategy",
"CDATASection",
"CSS",
"CSS2Properties",
"CSSConditionRule",
"CSSCounterStyleRule",
"CSSFontFaceRule",
"CSSFontFeatureValuesRule",
"CSSGroupingRule",
"CSSImportRule",
"CSSKeyframeRule",
"CSSKeyframesRule",
"CSSMediaRule",
"CSSMozDocumentRule",
"CSSNamespaceRule",
"CSSPageRule",
"CSSRule",
"CSSRuleList",
"CSSStyleDeclaration",
"CSSStyleRule",
"CSSStyleSheet",
"CSSSupportsRule",
"Cache",
"CacheStorage",
"CanvasCaptureMediaStream",
"CanvasGradient",
"CanvasPattern",
"CanvasRenderingContext2D",
"CaretPosition",
"ChannelMergerNode",
"ChannelSplitterNode",
"CharacterData",
"ClipboardEvent",
"CloseEvent",
"Comment",
"CompositionEvent",
"ConstantSourceNode",
"ConvolverNode",
"CountQueuingStrategy",
"Crypto",
"CryptoKey",
"CustomElementRegistry",
"CustomEvent",
"DOMError",
"DOMException",
"DOMImplementation",
"DOMMatrix",
"DOMMatrixReadOnly",
"DOMParser",
"DOMPoint",
"DOMPointReadOnly",
"DOMQuad",
"DOMRect",
"DOMRectList",
"DOMRectReadOnly",
"DOMRequest",
"DOMStringList",
"DOMStringMap",
"DOMTokenList",
"DataTransfer",
"DataTransferItem",
"DataTransferItemList",
"DataView",
"Date",
"DelayNode",
"DeviceMotionEvent",
"DeviceOrientationEvent",
"Directory",
"Document",
"DocumentFragment",
"DocumentType",
"DragEvent",
"DynamicsCompressorNode",
"Element",
"Error",
"ErrorEvent",
"EvalError",
"Event",
"EventSource",
"EventTarget",
"File",
"FileList",
"FileReader",
"FileSystem",
"FileSystemDirectoryEntry",
"FileSystemDirectoryReader",
"FileSystemEntry",
"FileSystemFileEntry",
"Float32Array",
"Float64Array",
"FocusEvent",
"FontFace",
"FontFaceSet",
"FontFaceSetLoadEvent",
"FormData",
"Function",
"GainNode",
"Gamepad",
"GamepadButton",
"GamepadEvent",
"GamepadHapticActuator",
"GamepadPose",
"HTMLAllCollection",
"HTMLAnchorElement",
"HTMLAreaElement",
"HTMLAudioElement",
"HTMLBRElement",
"HTMLBaseElement",
"HTMLBodyElement",
"HTMLButtonElement",
"HTMLCanvasElement",
"HTMLCollection",
"HTMLDListElement",
"HTMLDataElement",
"HTMLDataListElement",
"HTMLDetailsElement",
"HTMLDirectoryElement",
"HTMLDivElement",
"HTMLDocument",
"HTMLElement",
"HTMLEmbedElement",
"HTMLFieldSetElement",
"HTMLFontElement",
"HTMLFormControlsCollection",
"HTMLFormElement",
"HTMLFrameElement",
"HTMLFrameSetElement",
"HTMLHRElement",
"HTMLHeadElement",
"HTMLHeadingElement",
"HTMLHtmlElement",
"HTMLIFrameElement",
"HTMLImageElement",
"HTMLInputElement",
"HTMLLIElement",
"HTMLLabelElement",
"HTMLLegendElement",
"HTMLLinkElement",
"HTMLMapElement",
"HTMLMarqueeElement",
"HTMLMediaElement",
"HTMLMenuElement",
"HTMLMenuItemElement",
"HTMLMetaElement",
"HTMLMeterElement",
"HTMLModElement",
"HTMLOListElement",
"HTMLObjectElement",
"HTMLOptGroupElement",
"HTMLOptionElement",
"HTMLOptionsCollection",
"HTMLOutputElement",
"HTMLParagraphElement",
"HTMLParamElement",
"HTMLPictureElement",
"HTMLPreElement",
"HTMLProgressElement",
"HTMLQuoteElement",
"HTMLScriptElement",
"HTMLSelectElement",
"HTMLSlotElement",
"HTMLSourceElement",
"HTMLSpanElement",
"HTMLStyleElement",
"HTMLTableCaptionElement",
"HTMLTableCellElement",
"HTMLTableColElement",
"HTMLTableElement",
"HTMLTableRowElement",
"HTMLTableSectionElement",
"HTMLTemplateElement",
"HTMLTextAreaElement",
"HTMLTimeElement",
"HTMLTitleElement",
"HTMLTrackElement",
"HTMLUListElement",
"HTMLUnknownElement",
"HTMLVideoElement",
"HashChangeEvent",
"Headers",
"History",
"IDBCursor",
"IDBCursorWithValue",
"IDBDatabase",
"IDBFactory",
"IDBFileHandle",
"IDBFileRequest",
"IDBIndex",
"IDBKeyRange",
"IDBMutableFile",
"IDBObjectStore",
"IDBOpenDBRequest",
"IDBRequest",
"IDBTransaction",
"IDBVersionChangeEvent",
"IIRFilterNode",
"IdleDeadline",
"Image",
"ImageBitmap",
"ImageBitmapRenderingContext",
"ImageData",
"Infinity",
"InputEvent",
"InstallTrigger",
"Int16Array",
"Int32Array",
"Int8Array",
"InternalError",
"IntersectionObserver",
"IntersectionObserverEntry",
"Intl",
"JSON",
"KeyEvent",
"KeyboardEvent",
"KeyframeEffect",
"Location",
"Map",
"Math",
"MediaCapabilities",
"MediaCapabilitiesInfo",
"MediaDeviceInfo",
"MediaDevices",
"MediaElementAudioSourceNode",
"MediaEncryptedEvent",
"MediaError",
"MediaKeyError",
"MediaKeyMessageEvent",
"MediaKeySession",
"MediaKeyStatusMap",
"MediaKeySystemAccess",
"MediaKeys",
"MediaList",
"MediaQueryList",
"MediaQueryListEvent",
"MediaRecorder",
"MediaRecorderErrorEvent",
"MediaSource",
"MediaStream",
"MediaStreamAudioDestinationNode",
"MediaStreamAudioSourceNode",
"MediaStreamEvent",
"MediaStreamTrack",
"MediaStreamTrackEvent",
"MessageChannel",
"MessageEvent",
"MessagePort",
"MimeType",
"MimeTypeArray",
"MouseEvent",
"MouseScrollEvent",
"MutationEvent",
"MutationObserver",
"MutationRecord",
"NaN",
"NamedNodeMap",
"Navigator",
"Node",
"NodeFilter",
"NodeIterator",
"NodeList",
"Notification",
"NotifyPaintEvent",
"Number",
"Object",
"OfflineAudioCompletionEvent",
"OfflineAudioContext",
"Option",
"OscillatorNode",
"PageTransitionEvent",
"PaintRequest",
"PaintRequestList",
"PannerNode",
"Path2D",
"Performance",
"PerformanceEntry",
"PerformanceMark",
"PerformanceMeasure",
"PerformanceNavigation",
"PerformanceNavigationTiming",
"PerformanceObserver",
"PerformanceObserverEntryList",
"PerformanceResourceTiming",
"PerformanceTiming",
"PeriodicWave",
"PermissionStatus",
"Permissions",
"Plugin",
"PluginArray",
"PointerEvent",
"PopStateEvent",
"PopupBlockedEvent",
"ProcessingInstruction",
"ProgressEvent",
"Promise",
"Proxy",
"PushManager",
"PushSubscription",
"PushSubscriptionOptions",
"RTCCertificate",
"RTCDTMFSender",
"RTCDTMFToneChangeEvent",
"RTCDataChannel",
"RTCDataChannelEvent",
"RTCIceCandidate",
"RTCPeerConnection",
"RTCPeerConnectionIceEvent",
"RTCRtpReceiver",
"RTCRtpSender",
"RTCRtpTransceiver",
"RTCSessionDescription",
"RTCStatsReport",
"RTCTrackEvent",
"RadioNodeList",
"Range",
"RangeError",
"ReadableStream",
"ReferenceError",
"Reflect",
"RegExp",
"Request",
"Response",
"SVGAElement",
"SVGAngle",
"SVGAnimateElement",
"SVGAnimateMotionElement",
"SVGAnimateTransformElement",
"SVGAnimatedAngle",
"SVGAnimatedBoolean",
"SVGAnimatedEnumeration",
"SVGAnimatedInteger",
"SVGAnimatedLength",
"SVGAnimatedLengthList",
"SVGAnimatedNumber",
"SVGAnimatedNumberList",
"SVGAnimatedPreserveAspectRatio",
"SVGAnimatedRect",
"SVGAnimatedString",
"SVGAnimatedTransformList",
"SVGAnimationElement",
"SVGCircleElement",
"SVGClipPathElement",
"SVGComponentTransferFunctionElement",
"SVGDefsElement",
"SVGDescElement",
"SVGElement",
"SVGEllipseElement",
"SVGFEBlendElement",
"SVGFEColorMatrixElement",
"SVGFEComponentTransferElement",
"SVGFECompositeElement",
"SVGFEConvolveMatrixElement",
"SVGFEDiffuseLightingElement",
"SVGFEDisplacementMapElement",
"SVGFEDistantLightElement",
"SVGFEDropShadowElement",
"SVGFEFloodElement",
"SVGFEFuncAElement",
"SVGFEFuncBElement",
"SVGFEFuncGElement",
"SVGFEFuncRElement",
"SVGFEGaussianBlurElement",
"SVGFEImageElement",
"SVGFEMergeElement",
"SVGFEMergeNodeElement",
"SVGFEMorphologyElement",
"SVGFEOffsetElement",
"SVGFEPointLightElement",
"SVGFESpecularLightingElement",
"SVGFESpotLightElement",
"SVGFETileElement",
"SVGFETurbulenceElement",
"SVGFilterElement",
"SVGForeignObjectElement",
"SVGGElement",
"SVGGeometryElement",
"SVGGradientElement",
"SVGGraphicsElement",
"SVGImageElement",
"SVGLength",
"SVGLengthList",
"SVGLineElement",
"SVGLinearGradientElement",
"SVGMPathElement",
"SVGMarkerElement",
"SVGMaskElement",
"SVGMatrix",
"SVGMetadataElement",
"SVGNumber",
"SVGNumberList",
"SVGPathElement",
"SVGPathSegList",
"SVGPatternElement",
"SVGPoint",
"SVGPointList",
"SVGPolygonElement",
"SVGPolylineElement",
"SVGPreserveAspectRatio",
"SVGRadialGradientElement",
"SVGRect",
"SVGRectElement",
"SVGSVGElement",
"SVGScriptElement",
"SVGSetElement",
"SVGStopElement",
"SVGStringList",
"SVGStyleElement",
"SVGSwitchElement",
"SVGSymbolElement",
"SVGTSpanElement",
"SVGTextContentElement",
"SVGTextElement",
"SVGTextPathElement",
"SVGTextPositioningElement",
"SVGTitleElement",
"SVGTransform",
"SVGTransformList",
"SVGUnitTypes",
"SVGUseElement",
"SVGViewElement",
"SVGZoomAndPan",
"Screen",
"ScreenOrientation",
"ScriptProcessorNode",
"ScrollAreaEvent",
"SecurityPolicyViolationEvent",
"Selection",
"ServiceWorker",
"ServiceWorkerRegistration",
"Set",
"ShadowRoot",
"SharedWorker",
"SourceBuffer",
"SourceBufferList",
"SpeechSynthesis",
"SpeechSynthesisErrorEvent",
"SpeechSynthesisEvent",
"SpeechSynthesisUtterance",
"SpeechSynthesisVoice",
"StereoPannerNode",
"Storage",
"StorageEvent",
"String",
"StyleSheet",
"StyleSheetList",
"SubtleCrypto",
"Symbol",
"SyntaxError",
"Text",
"TextDecoder",
"TextEncoder",
"TextMetrics",
"TextTrack",
"TextTrackCue",
"TextTrackCueList",
"TextTrackList",
"TimeEvent",
"TimeRanges",
"TrackEvent",
"TransitionEvent",
"TreeWalker",
"TypeError",
"UIEvent",
"URIError",
"URL",
"URLSearchParams",
"Uint16Array",
"Uint32Array",
"Uint8Array",
"Uint8ClampedArray",
"VRDisplay",
"VRDisplayCapabilities",
"VRDisplayEvent",
"VREyeParameters",
"VRFieldOfView",
"VRFrameData",
"VRPose",
"VRStageParameters",
"VTTCue",
"VTTRegion",
"ValidityState",
"VideoPlaybackQuality",
"VisualViewport",
"WaveShaperNode",
"WeakMap",
"WeakSet",
"WebAssembly",
"WebGL2RenderingContext",
"WebGLActiveInfo",
"WebGLBuffer",
"WebGLContextEvent",
"WebGLFramebuffer",
"WebGLProgram",
"WebGLQuery",
"WebGLRenderbuffer",
"WebGLRenderingContext",
"WebGLSampler",
"WebGLShader",
"WebGLShaderPrecisionFormat",
"WebGLSync",
"WebGLTexture",
"WebGLTransformFeedback",
"WebGLUniformLocation",
"WebGLVertexArrayObject",
"WebKitCSSMatrix",
"WebSocket",
"WheelEvent",
"Window",
"Worker",
"XMLDocument",
"XMLHttpRequest",
"XMLHttpRequestEventTarget",
"XMLHttpRequestUpload",
"XMLSerializer",
"XPathEvaluator",
"XPathExpression",
"XPathResult",
"XSLTProcessor",
"alert",
"atob",
"blur",
"btoa",
"caches",
"cancelAnimationFrame",
"cancelIdleCallback",
"captureEvents",
"clearInterval",
"clearTimeout",
"close",
"closed",
"confirm",
"console",
"content",
"createImageBitmap",
"crypto",
"customElements",
"decodeURI",
"decodeURIComponent",
"devicePixelRatio",
"document",
"dump",
"encodeURI",
"encodeURIComponent",
"escape",
"eval",
"event",
"external",
"fetch",
"find",
"focus",
"frameElement",
"frames",
"fullScreen",
"getComputedStyle",
"getDefaultComputedStyle",
"getSelection",
"history",
"indexedDB",
"innerHeight",
"innerWidth",
"isFinite",
"isNaN",
"isSecureContext",
"length",
"localStorage",
"location",
"locationbar",
"matchMedia",
"menubar",
"moveBy",
"moveTo",
"mozInnerScreenX",
"mozInnerScreenY",
"mozPaintCount",
"mozRTCIceCandidate",
"mozRTCPeerConnection",
"mozRTCSessionDescription",
"name",
"navigator",
"netscape",
"onabort",
"onabsolutedeviceorientation",
"onafterprint",
"onanimationcancel",
"onanimationend",
"onanimationiteration",
"onanimationstart",
"onauxclick",
"onbeforeprint",
"onbeforeunload",
"onblur",
"oncanplay",
"oncanplaythrough",
"onchange",
"onclick",
"onclose",
"oncontextmenu",
"ondblclick",
"ondevicelight",
"ondevicemotion",
"ondeviceorientation",
"ondeviceproximity",
"ondrag",
"ondragend",
"ondragenter",
"ondragexit",
"ondragleave",
"ondragover",
"ondragstart",
"ondrop",
"ondurationchange",
"onemptied",
"onended",
"onerror",
"onfocus",
"ongotpointercapture",
"onhashchange",
"oninput",
"oninvalid",
"onkeydown",
"onkeypress",
"onkeyup",
"onlanguagechange",
"onload",
"onloadeddata",
"onloadedmetadata",
"onloadend",
"onloadstart",
"onlostpointercapture",
"onmessage",
"onmessageerror",
"onmousedown",
"onmouseenter",
"onmouseleave",
"onmousemove",
"onmouseout",
"onmouseover",
"onmouseup",
"onmozfullscreenchange",
"onmozfullscreenerror",
"onoffline",
"ononline",
"onpagehide",
"onpageshow",
"onpause",
"onplay",
"onplaying",
"onpointercancel",
"onpointerdown",
"onpointerenter",
"onpointerleave",
"onpointermove",
"onpointerout",
"onpointerover",
"onpointerup",
"onpopstate",
"onprogress",
"onratechange",
"onreset",
"onresize",
"onscroll",
"onseeked",
"onseeking",
"onselect",
"onselectstart",
"onshow",
"onstalled",
"onstorage",
"onsubmit",
"onsuspend",
"ontimeupdate",
"ontoggle",
"ontransitioncancel",
"ontransitionend",
"ontransitionrun",
"ontransitionstart",
"onunload",
"onuserproximity",
"onvolumechange",
"onvrdisplayactivate",
"onvrdisplayconnect",
"onvrdisplaydeactivate",
"onvrdisplaydisconnect",
"onvrdisplaypresentchange",
"onwaiting",
"onwebkitanimationend",
"onwebkitanimationiteration",
"onwebkitanimationstart",
"onwebkittransitionend",
"onwheel",
"open",
"opener",
"origin",
"outerHeight",
"outerWidth",
"pageXOffset",
"pageYOffset",
"parent",
"parseFloat",
"parseInt",
"performance",
"personalbar",
"postMessage",
"print",
"prompt",
"releaseEvents",
"requestAnimationFrame",
"requestIdleCallback",
"resizeBy",
"resizeTo",
"screen",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scroll",
"scrollBy",
"scrollByLines",
"scrollByPages",
"scrollMaxX",
"scrollMaxY",
"scrollTo",
"scrollX",
"scrollY",
"scrollbars",
"self",
"sessionStorage",
"setInterval",
"setResizable",
"setTimeout",
"sidebar",
"sizeToContent",
"speechSynthesis",
"status",
"statusbar",
"stop",
"toolbar",
"top",
"undefined",
"unescape",
"uneval",
"updateCommands",
"window"
]
window.__proto__
Array [ "constructor" ]
window.__proto__.__proto__
Array []
window.__proto__.__proto__.__proto__
Array(4) [ "addEventListener", "constructor", "dispatchEvent", "removeEventListener" ]
window.__proto__.__proto__.__proto__.__proto__
Array(13) [ "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__",
"__proto__", "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable",
"toLocaleString", "toSource", "toString", "valueOf" ]
EC2 サーバの ssh 接続を自動切断されないようにする
サーバ側で自動切断設定してるのかと sshd の設定を切断されないローカル VM と見比べても特に違いはなし

調べても日本語の個人サイトでは人によって書いてることが違ってどれが正しいかわかりません
設定は Server と Client どっちでもいいと書いてたり 理由や説明もなく動いたからと貼り付けてるだけでよくわからなかったので StackOveflow に行くといい回答がありました
やっぱり技術系の調べ物は英語のほうがいいですね

https://stackoverflow.com/questions/7210011/amazon-ec2-ssh-timeout-due-inactivity

EC2 サーバの設定ではなく AWS が一定時間通信がないと自動で切断するようです
それも リージョンによって間隔が違って短いと 1 分の通信なしで切られるそうです
ということで 50 秒ごとにサーバと疎通確認の通信を送っていればサーバから通信がないからと切断されることがなくなるようです

ServerAliveInterval 50

これをクライアントの ~/.ssh/config に追記します

JavaScript で if 式
あってほしいと思ってるのに JavaScript には if 式がありません
ただ eval は最後に評価した値が返ってくることを利用すれば

const x = eval(`
if(1) 1
else 2
`)
console.log(x)
// 1

const y = eval(`
if(0) 1
else 2
`)
console.log(y)
// 2
簡単に別タイムゾーンの日本時間を調べる
ネットを見てて 「20:00 UTC」 「15:30 PDT」 とか書いてても日本で何時なのかがぱっとわかりません
UTC ならよく扱うので 9 時間進めたのが日本だとわかりますがそれ以外はわかる気がしません
ググって何時間の時間差かを確認して計算ってするのも面倒です

JavaScript の Date 型でいけるんじゃない?と思ってやってみると

new Date("1/1/1 15:30 PDT")
// Tue Jan 02 2001 07:30:00 GMT+0900 (日本標準時)

とできました

基本ブラウザ使ってる最中なので F12 → 上のように調べたい時刻とタイムゾーンを入力 ですぐわかるのが便利ですね
日付はいらないのですが必須なので楽にかける 1/1/1 にしてます

最近の Chrome は実行前に結果プレビューしてくれるのでいちいちエンター押して複数回実行しなくても 日付の文字を変えるとその場で結果も変わるのもいいところです
util.promisify(child_process.exec)
> node -e "util.promisify(child_process.exec)(`node -e 'console.log(1);console.error(2)'`).then((...x) => console.log('T', x), (...x) => console.log('F', x))"
T [ { stdout: '1\n', stderr: '2\n' } ]

正常終了 exitcode が 0 のときは stdout, stderr がプロパティのオブジェクトを then の引数で受け取れる
それぞれに出力が入ってる
基本行末に改行があるので === するときは trim 必要なのに注意

> node -e "util.promisify(child_process.exec)(`node -e 'console.log(1);console.error(2);process.exit(1)'`).then((...x) => console.log('T', x), (...x) => console.log('F', x))"
F [ { Error: Command failed: node -e 'console.log(1);console.error(2);process.exit(1)'
2


at ChildProcess.exithandler (child_process.js:294:12)
at ChildProcess.emit (events.js:189:13)
at maybeClose (internal/child_process.js:970:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
killed: false,
code: 1,
signal: null,
cmd:
'node -e \'console.log(1);console.error(2);process.exit(1)\'',
stdout: '1\n',
stderr: '2\n' } ]

エラー終了 exitcode が 0 でないときは エラーオブジェクトを catch の引数で受け取れる
code プロパティに exitcode
stdout/stderr に各出力が入ってる
エラーのメッセージは stderr が使われる
コンソールで const などで宣言したときは返り値が undefined
const x = 10
// undefined

その前に値を評価しておくと

10 * 10
const v = 10
// 100

undefined で上書きされない

明示的に undefined を評価すると

1 + 1
undefined
// undefined

undefined になる

関数定義だと

1 + 1
function f(){}
// 2

変数宣言と同じくその前の評価結果

評価する式がなにもないと

/**/
// undefined

ということは

変数宣言や関数の定義の場合は無視して最後に評価した結果の値
最後の値がない場合は undefined

Chrome だけじゃなく Firefox もおなじみたい
GoogleMaps API で開発用のみモードも使えない時がある?
ちょうど GoogleMaps がゼンリンと契約やめたと噂になってた頃
API キーなしで使うと for development purposes only と表示されて暗い画面がでていて見づらいなりにも使えていたのですが 全部灰色の画面で全く見えなくなりました

衛星写真を画像処理したものから自動生成してるらしいことも言われてましたし 大きく変わったみたいなので API 周りも変わって開発用でも API キー必要になるのかと思ったのですが 今見たら暗い画面で表示できていました
なにか条件があるのかな

ところで 新しい GoogleMaps は世間的に不評みたいですが個人的には見やすくなってる部分も多いと思うので良いと思ってます
機械による自動化はどんどんすべきだと思うので 衛星画像からの自動検出で道路を判断するとか先進的で期待です
変わったばかりの最初で完璧できるわけはないと思いますしここからの進化が期待ですね

確かこの変更がある前の GoogleMaps が変わる予定 みたいな発表ではユーザが情報を投稿したり修正できるみたいな OpenStreetMap に近そうなことを言ってたと思うので 完全自動では難しいところはユーザ任せなのかもですね
OpenStreetMap とか Wikipedia とかユーザ任せなものでもうまく言ってるのは多いですし 規模が大きいのはユーザ任せのほうがいいのかも
当たり前のように使ってましたが そもそもお金払ってるわけでもない無料サービスですし 過剰なサービスを要求するほうがおかしくて 地図会社と契約してるクオリティじゃなくて画像から自動検出したものでも本来十分なところですよね
(API のクレカ設定しないと無料範囲すら使わせてくれないのはどうにかしてほしいですけど)
くるくる回る loading アイコンの WebComponent
customElements.define(
"spin-loading",
class extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: "open" }).innerHTML = `
<style>
#loading {
display: block;
box-sizing: border-box;
width: var(--size, 100px);
height: var(--size, 100px);
border: 0 solid transparent;
border-bottom-width: calc(var(--size) / 2);
border-right: var(--width, 6px) solid var(--color, #d4ba00);
border-radius: 50%;
animation: loading var(--speed, 0.6s) linear 0s infinite;
}

@keyframes loading{
0% {transform: rotate(0deg);}
100% {transform: rotate(360deg);}
}
</style>
<div id="loading"></div>
`
}
}
)

使用例

<!doctype html>

<script src="loading.js"></script>

<style>
body {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
width: 100vw;
height: 100vh;
background: #333;
}
spin-loading{
--size: 100px;
--speed: 0.6s;
--width: 6px;
--color: #d4ba00;
}
</style>

<spin-loading></spin-loading>
ベクトルの次元って?
◯次元ベクトルとかいう言葉をネットで見かけて 「あれ?ベクトルの次元ってなんだっけ」 とよくわからなくなりました

2 次元なら (10, -3) みたいに 2 数字があって二次元平面上の任意の座標を表せるやつだっけ?
つまり 1 次元は単純な数字 1 つだけで通常の数値と一緒?

ただ配列のことを言語によっては Vector と表現してたはず
Hack とか C++ とか

そう考えると 2 次元ベクトル= 2次元配列で [[1, 2], [3, 4], [5, 6]] とかのこと?
ただ 2 次元になると Matrix と呼ばれる気もします
1 次元だから Vector で Vector (配列) の要素数=次元と考えるのがあってるようにも思えます

数学っぽい話は難しいですね
文字列を N 文字ごとに分割したい 他
文字列を N 文字ごとに分割したい

const splitNchars = (str, n) => str.split(new RegExp(`(.{${~~n}})`)).filter(e => e)

splitNchars("abcdefg", 2)
// ["ab", "cd", "ef", "g"]

文字列を N 文字ごとに改行したい

splitNchars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", 13).join("\n")
// abcdefghijklm
// nopqrstuvwxyz
// ABCDEFGHIJKLM
// NOPQRSTUVWXYZ
// 1234567890

文字列を N 個に分割したい

const splitNstrings = (str, n) => {
const arr = splitNchars(str, Math.ceil(str.length / n))
return [...arr, ...Array(n - arr.length).fill("")]
}

splitNstrings("abcdefg", 2)
// ["abcd", "efg"]
Nodist で yarn 使うときのパス
Windows に Nodist で Node.js を入れて yarn でパッケージをグローバルインストールすると自分でパスを通さないといけません
普通に Nodist をインストールすると 「C:\Program Files (x86)\Nodist」 にインストールされます
node.exe や npm.exe は 「C:\Program Files (x86)\Nodist\bin」 に保存されます
npm でグローバルにインストールしたパッケージのコマンドもここに配置されます
npm で yarn を入れたあとに確認してみると

user1@pc MINGW64 /c/Program Files (x86)/Nodist/bin
$ ls -1
bin/
etc/
node.exe*
node_modules/
nodist*
nodist.cmd
nodist.ps1
nodist.sh*
nodist_bash_profile_content.sh
npm.cmd
npm.exe*
yarn*
yarn.cmd
yarnpkg*

ここにはパスが通ってるので yarn コマンドは使えます
yarn でパッケージをグローバルインストールしたものはこのフォルダではなくそのさらに内側の bin フォルダにコマンドが配置されます
yarn で parcel をグローバルインストールしてみると

user1@pc MINGW64 /c/Program Files (x86)/Nodist/bin
$ ls bin -1
parcel*
parcel.cmd
parcel.cmd.ps1*
parcel.ps1*
parcel.ps1.cmd
parcel.ps1.ps1*

parcel はパスが通ってないのでそのままでは使えません
「C:\Program Files (x86)\Nodist\bin\bin」 にパスを通せばどこでも yarn でインストールしたツールが使えるようになります
Python のクラスの継承
クラス名のあとのカッコに親クラス名をいれる

class X:
def __init__(self):
self.a = 10

def method():
return 1

class Y(X):
def __init__(self):
self.b = 20

print(vars(Y()))
# {'b': 20}

print(Y().method())
# 1

それだけだと親クラスの初期化処理が行われなくて vars の結果に a が存在しない
初期化されてないだけで継承されてるので method メソッドは使える

他言語で言う super の実行が必要
なくてもエラーはないけど初期化されない

super() は親コンストラクタを表してるわけじゃないので super() で取得できるインスタンスの __init__ メソッド呼び出しが必要

class X:
def __init__(self):
self.a = 10

class Y(X):
def __init__(self):
super().__init__()
self.b = 20

print(vars(Y()))
# {'a': 10, 'b': 20}

子クラスの方で __init__ を書かなければ自動で親クラスが実行される
子クラスで __init__ を定義して初期化するなら 必要あるときだけ親クラスの初期化メソッドを実行できる
実行したくないならしないことができる

class X:
def __init__(self):
self.a = 10

class Y(X):
pass

print(vars(Y()))
# {'a': 10}

実行タイミングも自由に指定できる
self を使う前とか最初じゃなくていい

class X:
def __init__(self):
self.a = 10

class Y(X):
def __init__(self):
self.a = 100
super().__init__()
print(self.a)

Y()
# 10
Liri OS
なんとなく fedora の派生ディストリを眺めたら Hawaii OS というのを発見
なんでハワイ?
ハワイっぽいデザインなのかなと見てみたら

Hawaii is now Liri OS
Hawaii merged with Papyros and is now Liri OS.

http://hawaiios.org/

Liri OS にマージされたみたい
これもはじめて聞いたけど UI のデザインがよさそう
スクリーンショット一覧を見てみてもモダンな感じ
ロゴは折り紙でや名前もわりと好きでちょっと興味あり

Hawaii OS が fedora 派生だったんだからこれも fedora 派生?と思ったのに調べてみると Arch ベースらしい
fedora 以上に新しいのをすぐに取り込む分問題も多いらしいし迷うところ

UI を揃えるために独自にいろいろなソフトウェアも用意してるみたいでリポジトリがいっぱい
https://github.com/lirios
liri ブラウザなんてのもある
VS Code の Python 拡張がメモリ使いすぎ
VS Code の Python 拡張を使うとメモリが使用どんどん増えていく
制限なく増えて 10GB 超え
この辺からは物理メモリに乗らなくなってきて PC の動きが重くなってくるから強制的にプロセス落としてるけど自動で再起動するし しばらくしたらまたメモリが 10GB くらい使ってる
さすがに 10GB 使うのが正常とは思えないし 定義ジャンプ機能使ったらずっとロード中になってるしバグっぽい
バージョンは最新の (2019.1.0) だし しばらくは無効にして使うしかないかなぁ
バイナリファイル中の文字列が半角スペース区切りになってる理由
exe とかのバイナリファイル中でテキストを探すとよく目にするのが半角スペース区切りになってる文字列
"abcd" が "a b c d" という感じ

ビルドしたファイルにローカルのパスが入ってたりしないか探したりするのですが探しづらくて困ります

バイナリファイル中のテキストはそういうふうに入ってるものとなんとなく思ってましたがなんでこんな面倒なことしてるんだろう?
わざわざ検索対策にそんなことするというのは考えにくいです

考えていてひらめいたのが Unicode (UTF-16) だからというもの
バイナリファイル中に見つかる文字はアルファベットばかりで日本語はほぼ見つからないです
あってもちゃんとした意味のある文字列になってないです
UTF-16 ではアルファベットなどは sjis や utf-8 と同じ数値を 0 パディングしたものです
U+0061 が a で U+0041 が A です
1 バイトずつ保存したら 00 と 61 のようになるので エディタで見ると 00 の部分はスペースで 61 の部分が a と表示されて半角スペース区切りというふうに見えると考えられます

試しにエディタで開いてそれぞれの文字コードを見てみると半角スペースは普通の半角スペース (U+0020) ではなく U+0000 になってました
U+0000 は NUL であって半角スペース文字じゃないのでエディタによっては別表示かもしれません

日本語が表示されないのは「あ」は U+3042 ですが 30 と 42 は 0B になってしまうからです
エディタで UTF-16 として開くを実行すれば半角スペースなく表示されますし日本語も表示されます
これで検索しやすくなりました

一応最初にバイナリファイルをエディタで開いたときにエンコーディングをいろいろ試してはいたのですが UTF-16 にすると UTF-8 に比べて文字化けのような変な漢字が大量に出てきて これは違うなと思っていたのですが本当のバイナリデータの部分がそう見えるせいでテキスト部分はちゃんと表示されていました
Python で「,」で終わると
dictionary だったのを個別の変数にコードを修正したときに「,」を消し忘れてたのですが動いてました

こういうの⇩
a = 1,
b = "foo",

Python ってカンマあっても動くんだ
複文みたいな機能があって カンマのあと何もないから何も処理しないってことかな
JavaScript などで ; をいっぱい書いても動くのと同じようなものかな

と思ってたら あっても意味がないというのじゃなく別の意味になってました
カンマで終わるとタプルになります

a
// (1,)
b
// ('foo',)

という感じです
一時的に動かすだけのコードだったのであってもいいならそのままでのつもりだったのですが ちゃんと消さないとダメですね
product ジェネレータ
複数の配列の掛け算的な組み合わせを出力
2 つの配列で 2 重ループで回すようなやつ
任意個数の配列に対応してる
速度求めるなら N 重ループしたほうがいい

function* product(...args) {
if (args.some(e => !Array.isArray(e) || !e.length)) throw new Error("Each argument must be an array.")

function* sub(state, args) {
const [arr, ...subargs] = args

if (!Array.isArray(arr)) {
yield state
return
}

for (const item of arr) {
yield* sub([...state, item], subargs)
}
}
yield* sub([], args)
}

例)
[...product([1, 2], [3, 4], [4], [10, 20, 30])]

// (12) [Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4), Array(4)]
// 0: (4) [1, 3, 4, 10]
// 1: (4) [1, 3, 4, 20]
// 2: (4) [1, 3, 4, 30]
// 3: (4) [1, 4, 4, 10]
// 4: (4) [1, 4, 4, 20]
// 5: (4) [1, 4, 4, 30]
// 6: (4) [2, 3, 4, 10]
// 7: (4) [2, 3, 4, 20]
// 8: (4) [2, 3, 4, 30]
// 9: (4) [2, 4, 4, 10]
// 10: (4) [2, 4, 4, 20]
// 11: (4) [2, 4, 4, 30]

for(const [a, b] of product([1, 2], [3, 4])){
console.log(`a = ${a}, b = ${b}`)
}
// a = 1, b = 3
// a = 1, b = 4
// a = 2, b = 3
// a = 2, b = 4