変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

2025 / 5月

[node.js]セキュリティアップデート

またやらかしたらしいのでアップデート。

一番のお勧めは、公式HPからのダウンロードです。

但し、このページにwinget等を使って「ダウンロードする(ダケ)」のコマンドが載ってますが、

C:\Users\{ユーザ名}\AppData\Roaming\fnm\node-versions\v22.15.1\installation

にダウンロードするダケで、手元のPCでは、node -v が表示するバージョンは古いままでした。

node.jsが使えない状態ではバージョン管理ツール(fnm)も使えないので、設定をミスれば即使用不可になると思うので、機能しなかったダケならマシかもしれませんね。

そもそも

セキュリティパッチが必要な旧モジュールを残す必要はまず無いですから・・・

※再現テストのために、ファイルサーバーに旧インスト.EXEが残しておく程度でいいかと

無視して下の

からダウンロード&インストし

c;\Program Files\nodejsに配置してしまいましょう。

ps.2025/5/16

Windows高度な設定」が勝手にインストされたりしなかったけど、Win11でPIN入力エラー。別画面がポップし指示通りコード入力して、先の画面に戻り同じPIN入力したら通った。非ロボット確認処理が混じってきたか何か設定をぶっ壊されたみたいだ。

ps.2025/5/17

今日はスマホが起動画面のまま無反応になった。

SIMスロットを外すと再起動するのを思い出し、外すが無反応。

ググると、たまに起きる現象らしい。

デバイスを再起動するには、10~20秒間電源キーを長押しします。

とあるけど、再起動しなかったし(気が短かったかもしれない)しょうがないのでコッチでリセットを試みる。音量下げ電源ボタンを押してみるが無反応。

仕方なく音量上げ音量下げを同時押し+電源ボタン押しを試みる(勿論そんな説明は無いが昔のAndroidはそんな感じだった)と10秒くらいで、振動があり暫くするとちょっと画面が真っ暗になった後に起動画面。つまり元に戻っただけだが、今度は電源ボタン長押しで再起動でき、普通にアイコンのある画面になった。

ここんとこトラブル続きだな

あ、INTELのBluetoothも無反応になった。

いつもの様に再認識させようとBluethoothのキーボードの削除してみると失敗する

他のキーボードやマウスは外れるのにコレだけ失敗する

「設定」の「Bluetooth」でBluethooth無効判定。

キーボードを非BluethoothのTK-FDM063に切替て続けBluethoothデバイスが無効化されていることに気が付く。※このPCではよくあるコト

とりあえずVisualStudioCodeとかNodejsとか何たらRUNTIMEとか無くてもいいものは全てアンスコしたが無駄。

「デバイスの追加」「Winヘルプ問い合わせ」で

しかし、「設定」の「Bluetooth」では無効のまま、再起動後も「設定」の「Bluetooth」では無効。

でも、デバイスマネージャーにはBluetoothのマークが出ていたので全部アンスコして、再び「設定」の「Bluetooth」」「デバイスの追加」「Winヘルプ問い合わせ」へ

「WindowsUpdateが自動実行できない」から「手動」でとか

Bluetoothラジオが設定できない」とか

何度も嘆いた後、やっとBluethoothの設定が空回りしてる事に気が付いたのか?

コールドスタートアップ」を提案してきた。

  • 10秒電源ボタンを押してモニターが真っ暗になるのを待つ
    • 普段ならCPUの水冷ヘッドの赤いランプが消えるのに
      • 今回は点いたまま
        • 明らかに「おかしな状態」
          • もうi9-9900はHP0なのか?
  • 電源ケーブルを外して30秒以上待つ
    • ノートだったらバッテリーも外すのかな?
      • CPUがまだONのままなのに電源ケーブルを抜くけとか外道
  • 電源ケーブルを戻し起動
    • いきなり電源を抜くショック療法でCPUが少しマシになった様だ

やっとシステムトレイにBluethoothのマークが復活。

ps.2025/5/22

画面が真っ暗状態でマウスクリック無反応なのでキーボードのENTERキーを押したら

ほどなくCPUの水冷ポンプの赤いランプが消えた。サスペンドしたらしい。(このPCではあるある現象

電源ボタンを押して起こした。

ps.2025/5/25

昨日の13時過ぎにNASが不調になり、このブログも落ちていたようです。

/etc/fstab でiscsiの接続がブログ用ではないディスクに接続しようとしてエラっていたのでiSCSIの設定をやり直し。※ -m はmodifyの省略形です

# iscsiadm -m session -o show
{NASの全iscsiターゲットにログインしてた。}
# iscsiadm -m node --logout ※一旦NASのiSCSIターゲットをログアウト
# lsblk -S
NAME HCTL       TYPE VENDOR   MODEL                      REV SERIAL          TRAN
sda  1:0:0:0    disk ATA      ****           ****       sata
※ SSDのみ認識の状態に戻る
# iscsiadm -m node -T{NASのブログ用iSCSIターゲット} -p {NASのIPアドレス}:3260 -l
Logging in to [iface: default, target: {NASのブログ用iSCSIターゲット}, portal: {NASのIPアドレス},3260]
Login to [iface: default, target: {NASのブログ用iSCSIターゲット}, portal: {NASのIPアドレス},3260] successful.
# lsblk -S
NAME HCTL       TYPE VENDOR   MODEL                      REV SERIAL           TRAN
sda  1:0:0:0    disk ATA      ****           ****         sata
sdb  2:0:0:0    disk LIO-ORG  FILEIO                    4.0  ********* iscsi
# reboot ※再起動して/etc/fstabの設定でマウントしてもらう

ReadyNASマニュアルではWindowsのイニシエータならCHAPシークレット付きでログイン可否判定させされるのですが、NASにCHAP用のアカウントの設定が見当たらなかったのでLinuxのイニシエータでは名のみ(CHAPシークレット無し)で接続っぽいです。

同日AlmaLinuxで大量のBugFixが溜まっていたので更新。

すると、cockpitが上がりません。仕方がないのでVScodeでリモート接続してみるとCPU負荷は1%程度

cockpitサービスの状況はinactiveでしたがstartしたら即動きました。

$ sudo systemctl status cockpit
○ cockpit.service - Cockpit Web Service
     Loaded: loaded (/usr/lib/systemd/system/cockpit.service; static)
     Active: inactive (dead) since Sun 2025-05-25 19:12:38 JST; 9min ago
   Duration: 17min 29.153s
TriggeredBy: × cockpit.socket
       Docs: man:cockpit-ws(8)
   Main PID: 3347 (code=killed, signal=TERM)
        CPU: 7.981s

May 25 18:59:29 {サーバ名} cockpit-tls[3347]: cockpit-tls: gnutls_handshake failed: A TLS fatal alert has been received.

/usr/lib/systemd/system/cockpit.serviceも特に異常は無かったですが、タイムアウトをデフォルトの90秒から180秒に伸ばしてみました。

ExecStart=/usr/libexec/cockpit-tls --idle-timeout 180

後、ブラウザからhttp指定でcockpit画面にアクセスするとhttpsにリダイレクトして使えますが、urlがhttps指定のブックマークで開くとアクセス不可に変わったっぽいです。※https未設定の場合

また、アップデート直後の再起動ではブログのゲスト側が自動起動しなかったので手動で起動。

とりあえず2度ホスト側を再起動した感じでは以降は自動起動してる。

ここのところ、数日間遊ばないと拗ねる猫みたいなOSになってる感じがする。

Win11ー24H2もAlmaLinux9もNASも今日も平運転です。



[考察]ヒッグス場

ヒッグス場との相互作用により素粒子に質量が与えられえる。

とされる。

短い動画で「動きにくい」ヒッグス場で素粒子がもがいている様子を伝えるものが多い、それは素粒子の「動きにくさ」を単純に表現するには都合が良いが実際の「ヒッグス場」の働きとはまるで違う。

「ヒッグス場」では「素粒子の運動量の変化」を抑制する要因としての「質量反応」を引き起こす力場あるいは中間子であって、それ自体は「素粒子の運動量の変化」を引き起こさないからだ。あくまでも反応を仲介する場でしかない。

ブラックホールの重力場もブラックホールと対象があって「発現する場」でブラックホールしか存在しないなら「発現しない」のと同じだ。※厳密にはブラックホールを観測する視点をどこかに移動すればどこからか光が通過する可能性はおおありなので「対象」が全く無い状況はそう多くないと思う。

またヒッグス場で起きる「質量」も、一般に観測する「質量」の1要因でしかない。

というのも素粒子が持つ多様な運動で引き起こされるモーメントの影響を差し引くと「ヒッグス場反応で発生する質量」は小銭程度になってしまうのだ。

観測された質量

=モノ本の質量(ヒッグス場によるもの)×多様な運動(素粒子反応)によるモーメント

=モノ本の質量(ヒッグス場によるもの)×(運動1によるモーメント+運動2によるモーメント×・・・×運動Nによるモーメント)

と概ねそうなっており観測された質量の総量は変わらなので、

素粒子の運動(エネルギー順位とか色々)が分類されるほどに

素粒子の構造が階層化され多様な運動を付加されるほどに

ヒッグス場によって発生したモノ本の質量は小さくなってしまうのである。

素粒子ってかなりヤンチャだが質量は普通の小心者なのである。

そして、現在の解釈では1%程度ではあるが、式の右辺に

モノ本の質量(ヒッグス場によるもの)×

がある限り、ヒッグス場がなければ「観測できる質量は0」になるのも確かなので、

たかが1%されど1%なヒッグス場なのである。

ではどこまで小さくなるのだろうか?

予想としては、質量に対応する重力場が他の力場と比較して非常に弱いとされているので、最終的にはその比率程度まで小さくなる様な気がするので1%程度と考えられているということは・・・

素粒子の大元にたどり着くまでの道程はまだまだ長そうである。

仮に「常に質量0」なら「時間」は存在しない。

なぜなら運動量やエネルギーを緻密に計算しても質量=0であれば常に運動量やエネルギーは0になるから、その観測系に変化は無く、実質的に「時間を感じ取れない」から「時間が存在しない」のだ。

ところが、エネルギーは持ってるけど質量0とされるものに光があり、実際に振動数で現れる波動エネルギーを持つが光同士は衝突せず互いを素通りするのでヒッグス場の影響を受けないみたいで「質量も無さそう」な「よく解らないシロモノ」になっている。

光同士は素通りするが、質量をもつ対象にエネルギーを伝達すると、途端にヒッグス場の影響を受けて質量をもつ対象は色々な反応を引き起こすがこれは質量をもっているモノのせい



[javascript]クラスやメソッドの名前を表示する

処理中にクラス名を表示するのはコンストラクタのnameを表示するのが簡単です。

console.log(this.constructor.name);

クラスでは無いトコで使うと

Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'constructor')

になります。

メソッド名が表示したい時はメソッドのnameプロパティが使えます。

class foo {
  xxxx() {
  const methodName = this.xxxx.name;
    console.log(methodName);  /* xxxx になる */
  }
}

ベタでmethodName = ‘xxxx’で良さそうですが、リファクタリングするとボロボロです。

厄介なのは派生クラスから基底クラスのメソッドを利用している時です。

class hoge extends foo {
  className = this.constructor.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  className = this.constructor.className;
  yyyy() {
    console.log(this.className); /* hoge になる */
  }
}

大抵はこれで満足ですが、クラスfooのyyyならfooになって欲しい場合に

class hoge extends foo {
  /* className = new hoge().constructor.name; ではループするので、一旦staticなメンバーに入れます */
  static className = new hoge().constructor.name;
  className = hoge.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  yyyy() {
    console.log(this.className); /* hoge になる */
  }
}

と書き込んでも、thisのコンストラクタのnameでは派生クラスの名前が出てきます。

そんな時はクラスのメンバーにclassName=クラス名を書けば解決しそうですが、

class hoge extends foo {
  static className = new hoge().constructor.name;
  className = hoge.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  xxxx() {
    console.log(this.className); /* hoge になる */
  }
}

やはり、thisが強いので、派生クラスの名前が出てしまいますので、自分以外には見えない#classNameを使うと

class hoge extends foo {
  static className = new hoge().constructor.name;
  className = hoge.className;
  #className = hoge.className;
  xxxx() {
    console.log(this.className);  /* hoge になる */
    console.log(this.#className); /* hoge になる */
    this.yyyy();
  }
}

class foo {
  static className = new foo().constructor.name;
  className = foo.className;
  #className = foo.className;
  xxxx() {
    console.log(this.className);  /* hoge になる */
    console.log(this.#className); /* foo になる */
  }
}

やっと希望どおりになりますが、メンドクサイですし、new すると困る場合には向きません。

クラス名でコンストラクタの名前を取得すると・・・

class hoge {
   #className = hoge.constructor.name;
   xxxx() {
      console.log(this.#className); /* Function になる残念 */
   }
}

new した時にコンストラクタが名付けられるっぽい。



[spreadSheet7]デバッグ

ES-moduleにしたせいで、サーバに上げないと使えなくなってる。

index.htmlを開いて「Open with live server」でchromeでspreadSheet7を開き

chromeのDevToolでチマチマするのも面倒なので

VScodeの「chrome アタッチ」はchromeにデバッグオプションを付けないのでアタッチに失敗するので改造。urlはliveServerに合わせる。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome",
            "url": "http://127.0.0.1:5500",
            "webRoot": "${workspaceFolder}",
            "runtimeArgs": [
                "--remote-debugging-port=9222"
            ]
        }
    ]
}

これで無事live serverで表示しながらVScodeのデバッガが使えるようになる。

問題点は、やはりspreadSheet7がローカルで動かないことかな



[VScode]勝手に別のファイルをデバッグしたがる

簡単なソースならソースコードをエディタで開いだ状態で「実行」⇒「デバッグの開始」でデバッグしてくれるが、マレに違うソースをデバッグしだすことがある。

.vscodeフォルダが無いので見えないトコで記憶しているらしくVScodeを再起動してもそのまんま。

※setting.jsonに

デバッガのlaunch.jsonに「実行」⇒「構成の追加」で「その他のNode.js…」⇒「現在のファイルの実行」デバッグするファイルを個別に登録し”name”を書き換えるのも面倒すぎ

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "name": "現在のファイルの実行", 👈複数作ったら、書き換えないと訳が分からなくなる
            "request": "launch",
            "program": "・・・\\index.js"
        }
    ]
}

configurationsにハイライト部分を追記して、デバッガのプルダウンに”表示中のファイルを起動”が出る様にした。時々ブラウザで確認したい時もあるけどね。

{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "表示中のJSファイルを起動",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}\\${relativeFile}"
        }
    ]
}

開発環境のプロジェクト設定にはC言語のようなコンパイラ(EXE作る君)向けだと、デバッグの設定が1つしかないか、デバッグを切替える為にサブ・プロジェクトに分ける必要があったりする。

スクリプト系は、ブラウザ上のjavascript、サーバーサイドのphp、保守コマンドの.shとか色々混ざる時もあるので、デバッガの設定を切り替えられる様にできるのはとても助かる。



[EBNF+]リテラルの記述

SpreadSheetでちょっと拡張したEBNFをベースに計算式等を評価させていたけど、

やはり顔文字にしか見えない正規表現とかメンドクサイ(ちょっと変えると拗ねるので)

特にリテラルの記述が面倒で、BNFっぽく

wq string   =   (*$ NO SPACE SKIP $*) '"', /(?!\\\\)[^"]*/, '"' ;

と苦し紛れだったので

wq string   =   '"' ・・・ '"' ;

BNFにこんな感じで書けると、とても楽そう

内部では

const encloseParser = parser.enclose(parser.token('"'), parser.search('"', true));

な感じで[ ” ]と[ ” ]で囲まれた文字リテラルを判定できる(ハズ

encloseはこんな感じで、囲まれたテキストを返す

/**
 * 記号で囲むリテラル用のパーサを作成する
 * @param {Function} leftParser   左囲みtoken
 * @param {Function} rightParser  右囲みsearch
 * @return {Function} 			  生成した連結パーサ
 */
enclose(leftParser, rightParser) {
  const methodName = 'enclose';
  const encloseParser = () => {
    const bkPosition = this.position;
    const leftParsed = leftParser();
    if (!leftParsed.status) {
      return new ParserResult(false, null, bkPosition);
    }
    const rightParsed = rightParser();
    if (!rightParsed.status) {
      return new ParserResult(false, null, bkPosition);
    }
    const encloseText = this.target.substring(leftParsed.position, rightParsed.position - rightParsed.result.length);
    return new ParserResult(true, encloseText, this.position);
  };
  encloseParser.type = methodName;
  return this.parserWraper(encloseParser;
};

見慣れないsearchパーサは、

/**
 * 一致するパターンを検索するパーサを生成する
 * yオプションを付けないregExpバージョン
 * @param {string} text       検索パターン
 * @param {boolean} fEscape   エスケープ処理
 * @return {Function}         生成したパーサ
 */
search(text, fEscape = undefined) {
  const methodName = 'token';
  const len = text.length;
  // エスケープ処理の指定が無い場合
  if (fEscape === undefined) { fEscape = this.fEscape; }
  const rePat = `(${(fEscape) ? '?<!\\\\)(' : ''}${regExpEscape(text)})`;
  const re = new RegExp(rePat, '');
  const searchParser = this.regexp(re, 'gm'); // yオプションを付けないregExpバージョン
  searchParser.type = methodName;
  return searchParser;  // regexpParserでparserWraper済
};

ほぼyオプションの無いパターンを探しにいってしまうregexp処理になっているので

regexpもちょっと変更

/**
  *  正規表現パーサを作成する
  * @param {RegExp} re  正規表現
  * @param {*} options  オプション  ※未設定の場合は、正規表現のオプション+gmyオプション
  * @return {Function}  生成したパーサ
  */
regexp(re, options) { // g:lastIndexから開始、m:複数行、y:lastIndexでのみ判定
  const methodName = 'regexp';
  const source = re.source;
  if (options === undefined) {
    options = (re.hasIndices ? 'd' : '')
      + (re.global ? 'g' : 'g')     /* lastIndex利用が必須なため、常時gオプションを付加 */
      + (re.ignoreCase ? 'i' : '')
      + (re.multiline ? 'm' : 'm')  /* 改行を跨いで処理すたい場合もあるので、常時mオプションを付加 */
      + (re.dotAll ? 's' : '')
      + (re.unicode ? 'u' : '')
      + (re.unicodeSets ? 'v' : '')
      + (re.sticky ? 'y' : 'y')     /* regexpは index=0 のみ判定する方が都合が良いので、常時yオプションを付加 */
      ;
  }
  try {
    re = new RegExp(source, options);
  } catch (ex) {
    const msg = `${rgis.className}.${methodName}: new RegExp fail, ex:'${ex}'`;
    console.error(msg);
    throw new Error(msg);
  }
  /**
   *  生成した正規表現パーサ
   * @return {ParserResult}       パースした結果
   */
  const regexpParser = () => {/* regexp */
    re.lastIndex = this.position;                                       // 再利用時のため
    const result = re.exec(this.target);                        // とりあえず正規表現で実行
    if (result) {
      // 読取りに成功した場合
      const foundText = result[0];
      // ログに追記
      this.mapLog.addSuccessToken(foundText);
      // 読取り位置を更新
      this.position = result.index + foundText.length;
      return new ParserResult(true, foundText, this.position);
    } else {
      // 読取りに失敗した場合
      // ログに追記
      this.mapLog.addFailToken(source);
      return new ParserResult(false, null, this.position);
    }
  };
  regexpParser.type = methodName;
  return this.parserWraper(regexpParser, true, false);
};

普通は、こんなBNF表記を挟まずに直接パーサコンビネーションを作りはじめるハズだが・・・

最終的には「湯出たてのスパゲッティー」にソースや香辛料をかけて、食べやすく「フォークで絡めて」食べる訳で、文法をちょっとイジるにも脳内のイメージを頼りにパーサコンビネーションをイジるから

バグると「脳内のイメージが間違ってる場合」と「勘違いしてコードしている場合」を切り分けるのが非常に難しい。

あと、パーサはまとめてクラス化してるので各パーサにテキストや読込位置をパラメータで渡すのを止めてみたから、SpreadSheetに組み込むのは完成した後になる。

今は、

    {
        title: "sequenceメソッド:正常パターン4",
        testCase: () => {
            const parser = new CoreParser('abc=defghijklmnopqrstuvwxyz')
            const sequenceParser1 = parser.sequence([parser.token('abc'), parser.token('='), parser.token('def')]);
            const rc = [];
            rc.push(sequenceParser1());
            return rc;
        },
        expectedResult: [
            { status: true, result: ['abc', '=', 'def'], position: 7, },
        ],
    },
test[4:sequenceメソッド:正常パターン4] success. => [ 0:{ "status": true, result:[ "0": "abc", "1": "=", "2": "def", ], "position": 7, }, ], 

単体テストを消化中。

これがいっぱい修正漏れが出るんだなぁ(笑

後になって、実行するパーサや結果がどのパーサが作ったのか判るようにtypeを追加してみたり

※用途未定

テスト結果の判定経過を出力させたり

[ 0:{ "status": true, result:[ "0": "abc", "1": "=", "2": "def", ], "position": 7, }, ], 

とか、出来てしまえば不要に思えるけど、バグったら必須な機能をパーサ本体の外においても

パーサ本体が600行にもなってしまう。

ps.2025/5/12

「?」最小マッチングで

/'.*?'/
👉 / ' .* ? ' /          ※見やすいように空白を挟んでみた

と’…..’をお手軽にマッチングできるけど、エスケープ(\’)が混ざるとどうして良いのか判らなかったけど、

'(.*?\\')*.*?'
👉 ' (.* ? \\' )* .* ? '   ※見やすいように空白を挟んでみた

の様に「エスケープ(\’)を0回以上繰り返す」を挟めばOKだった。

気づけば簡単すぎ。(大笑

だがどうやってうまく処理できてるのか?

.* ? \’ から .* ? ‘ に遷移するには

先回りして「\\’」や「’」の位置を把握し存在を確認し、「\\’」や「’」の直後に切り詰めてマッチングし、存在しなければ左部のマッチングをしないのかな?

※\\’が存在しない長いテキストを渡すと重そうだけど

正規表現も

/ .* /
こんなザックリとした表現は意味は読み取れるけど使い物にならないが
👉 / .* ? /
でちょっとは使えるので、
正規表現内で/が出現する状況を挟み込んで
👉 / ((.* ? \/)|(.* ? [/)|(.* ?(/)|(.* ?{/))* .* ? /  ※ / に 4連の (.* ? を仕掛けるぞ(的な
で良いのかもしれない。
※とても十分な検証をする気にはならないががが

で済むのかな?

顔文字表現より見やすい気がするけど、ジェットストリームっぽくドムだから処理が重いかも。



[spreadsheet6]組込関数の登録

functionsディレクトリィの組込関数の登録にはHTMLにscriptタグをいっぱい書かないと処理しないのでfunctionsディレクトリィのjsファイルの一覧をfunctions.jsonに手書きで作成し起動時に読込でimport() ×jsファイル数で関数を登録させてた

手書きしなくても

  • ファイル一覧を取得
  • jsonテキストに変換
  • ファイルに出力

をググってサンプルを探し

// 組込関数まとめ.js
//
// path変数が示すディレクトリィに存在する拡張子がjsのファイルの一覧を
// fname変数で指定したファイルにJSON形式で出力する
//
import { default as fs } from "fs";

const path = './js/spreadSheet/functions/';
// ディレクトリィのファイルリストを取得
const files = fs.readdirSync(path)
    .filter((fname) => {
        // 拡張子がjsのファイルのみ残す
        const [name, ext] = fname.split('.');
        return (ext === 'js');
    })
    ;

// ファイル一覧(型:配列)をJSON形式のテキストに変換する
const text = JSON.stringify(files, "", 2);

// 非同期にファイルに書き込む
const fname = "functions.json";
fs.writeFile(`${path}${fname}`, text, (err) => {
    if (err) {
        console.log(`'${path}${fname}' file write err\n${err.message}\n${err.stack.split('\\n')}`);
    } else {
        console.log(`'${path}${fname}' file write\n'${text}'\n`);
    }
});
// end of 関数集計.js/

繋げたら出来ました。

たまにはこんなこともあるんだなぁ~

ただし、実行してみると

[MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type ・・・

と長い注意書きがコンソールに出てきた。

package.jsonにtype=’model’を書いて無いから、common jsだと思って実行したけど、import文があるからES-moduleのハズだからやっといたよ?的な内容だった。

やっぱり、何事も無く無事に完了するワケがなかった。(合掌



[AlmaLinux]wasmerって何?

wasmerは色々な言語のソースコードをWebAssemblyに変換して実行環境を作成し実行してみせるパッケージ。WebAssemblyしか動かない軽量なコンテナっぽいモノは外部とは実行時にパラメータとして与えるCallBackしかなさげなので安全性は高め。

また、jsモジュール化したパッケージがあり、ブラウザで動作するためコンテナっぽいモノはドコでも動く感じ。しかし普通に考えればHTMLにコンテナのソース数分つまり大量の<script>タグを書かないと動かない気もするが、wasmerを利用する自前のJSファイルをESモジュール化し、

<script type="module" src="xxxxx.js">

そのjs1行目にwasmer/sdkをimportすれば、

import { init, Wasmer } from "@wasmer/sdk";

後はwasmer/sdkが必要な分のimportをしてくれるので、ブラウザで容易に動作できそうな感じ。

勿論、直接指示しなくて良くても、大量のアクセスが起きうるので、以降のコードも同期が取れるまで待機する様にawait指示が必須になる。

import { init, Wasmer } from "@wasmer/sdk";
await init();
const pkg = await Wasmer.fromRegistry("python/python");

一応外部とはオフラインでもfromFileで利用可能だが、他プロジェクトへ提供しているパッケージではテストスイートが数GBにもなっているモノもあるのが難

※ パッケージを/path/にダウンロード済みなら
Wasmer.fromFile(/path/);
※も可。

無理と思いつつ、wordpressをwasmerでコンパイルする方法をググってみたが、

WordPressをWasmerでコンパイルするというのは、WordPressの主要な言語であるPHPをWebAssembly(WASM)に変換し、
WasmerというWASMランタイム環境で実行するという意味です。しかし、WordPressの構造がPHPに依存しているため、
WordPress全体をWasmerで動かすことは現実的ではありません。Wasmerは主にC/C++、Rustなどの言語で記述された
コードをWASMに変換し、ブラウザの外でも実行できる環境を提供するもので、WordPressのような動的なウェブアプリ
ケーションを直接コンパイルするような仕組みではありません。

やはり無理っぽいが作ってる人もいるが全部ブラウザ上で動くみたいでプラグイン作成者向けらしい。

ふと、spreadsheet5のscriptタグが多すぎなのに気が付いたのでESモジュール化してHTMLを短くし、CSSや処理中表示もカスタムエレメントに組込んだ。jsスクリプトファイルはネームスペースを圧縮した後だったのでごっそりと圧縮前に戻した。HTMLは短くなるけど、1ファイル毎にしっかりimport/exportしないとエラるので大変で、実行時にエラる時もあるのがとてもメンドイ。数値、文字を入力し計算式も結果が出るからOKかな?

本題に戻りwasmerインストの通りにインストしてみる。

$ curl https://get.wasmer.io -sSfL | sh
/usr/bin/which: no wasmer in (/home/***/.local/bin:/home/***/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)
Welcome to the Wasmer bash installer!

               ww
               wwwww
        ww     wwwwww  w
        wwwww      wwwwwwwww
ww      wwwwww  w     wwwwwww
wwwww      wwwwwwwwww   wwwww
wwwwww  w      wwwwwww  wwwww
wwwwwwwwwwwwww   wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww  wwwww
wwwwwwwwwwwwwww  wwwww   wwww
wwwwwwwwwwwwwww  wwwww
   wwwwwwwwwwww   wwww
       wwwwwwww
           wwww

downloading: wasmer-linux-amd64
Latest release: v6.0.0
/usr/bin/which: no wasmer in (/home/***/.wasmer/bin)
Downloading archive from https://github.com/wasmerio/wasmer/releases/download/v6.0.0/wasmer-linux-amd64.tar.gz
######################################################################## 100.0%
installing: /home/***/.wasmer
Updating bash profile /home/***/.bashrc
we've added the following to your /home/***/.bashrc
If you have a different profile please add the following:

# Wasmer
export WASMER_DIR="/home/***/.wasmer"
[ -s "$WASMER_DIR/wasmer.sh" ] && source "$WASMER_DIR/wasmer.sh"
check: wasmer 6.0.0 installed successfully ✓
wasmer will be available the next time you open the terminal.
If you want to have the commands available now please execute:

source /home/***/.wasmer/wasmer.sh
$

「すぐ使うなら・・・」と書いてある様に上のsourceコマンドを手打ちすると即使える。

wasmerのtemplatesでserverを検索すると静的WebServerがあったのでインストしてみた。

$ curl --proto '=https' --tlsv1.2 -sSfL https://get.static-web-server.net | sh
info: platform 'x86_64-unknown-linux-gnu' supported
info: downloading the 'static-web-server v2.36.1' pre-compiled binary...
info: installing pre-compiled binary in /usr/local/bin...
Copying SWS pre-compiled binary to /usr/local/bin...
[sudo] password for ***: 
info: pre-compiled binary installed on /usr/local/bin/static-web-server
Version:      2.36.1
Built:        2025-04-01 22:00:32 +00:00
Git commit:   ab44158182e4e29dcece4c3b10068dc596bf9e03
Build target: x86_64-unknown-linux-gnu
Rust version: rustc 1.85.1 (4eb161250 2025-03-15)
License:      MIT OR Apache-2.0
Homepage:     https://static-web-server.net
Author:       Jose Quintana <https://joseluisq.net>
SWS was installed successfully!
To uninstall SWS just remove it from its location.
$
$ static-web-server
Caused by:
    path ./public was not found or inaccessible
$ mkdir public
$ static-web-server
・・・
INFO static_web_server::info: cache control headers: enabled=true
INFO static_web_server::info: security headers: enabled=false
INFO static_web_server::info: http1 server is listening on http://[::]:80
INFO static_web_server::info: press ctrl+c to shut down the server
^C WARN static_web_server::warn: termination signal caught, shutting down the server execution
$ 

デフォルトでは”./public”らしいので、swsの設定ファイルは~/.wasmer/sws/config.tomlに変更し、

# Wasmer config
export WASMER_DIR="/home/***/.wasmer"
export WASMER_CACHE_DIR="$WASMER_DIR/cache"
export PATH="$WASMER_DIR/bin:$PATH"
# for sws
export SERVER_CONFIG_FILE="$WASMER_DIR/sws/config.toml"
# end of wasmer.sh.

その中で、rootフォルダは~/.wasmer/sws/publicに、ポートも8080に変更してみた。

設定のデフォルト値はこちら

[general]

#### Address & Root dir
host = "::"
port = 8080
root = "${WASMER_DIR}/sws/public"

#### Logging
log-level = "error"
・・・



top