変奏現実

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

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

インターネット

[MS-Access]ODBC接続先変更

接続先データベースのIPアドレスが変わってしまった場合、WindowsのODBCマネージャでIPアドレスを変更すると概ねOKだったが、MS-Accessで外部データベースをODBC接続でリンクした場合だけ、MS-Access内部でIPアドレスをコピっているらしく変更前のIPアドレスに繋ごうとする。

リンクテーブルマネジャを使用してもIPアドレスを書き換えれない様なので、リンクテーブルを2-3個作り直すハメになった。

しかし、VBAを使えばリンクテーブルが1000個あっても泣かずに済みそうだ。

Public Sub ODBC接続先更新(strConnect As String)
  For Each tableDef In CurrentDb.TableDefs
    If tableDef.Attributes = dbAttachedODBC Then   'リンクテーブルならば、
      tableDef.Connect = connectString       'ODBCの接続テキストを書換える
      tableDef.RefreshLink                         '書き換えた内容で動く様にする
    End If
  Next tdf
End Sub

短く読みやすい記事に載せるコードとしては最良だ。

しかし、今時のMS-Office365の中のAccess2007の中で保持しているODBC接続テキストが

ODBC;DATABASE=xxxxxx;DSN=xxxxxx;OPTION=0;PORT=xxxx;SERVER=192.168.1.xxx;CHARSET=xxxxx;

だったりするので、Connectプロパティを直に書換えるのはバージョンの依存度がかなり高そう。

※CHARSETを正しく指定しないと環境文字(㈱等)が?になったりするので地味に痛い。

実際にはこんな感じで使ってみた。

Public Sub ODBC接続先個別更新(SERVER_IP_ADR As String, UID As String,  PWD As String)
  For Each tableDef In CurrentDb.TableDefs
    If tableDef.Attributes = dbAttachedODBC Then   'リンクテーブルならば、dbAttachedODBC=536870912
        con = tbldef.Connect
        If con <> "" Then   '  一応、conが""の場合、をsplit(con,";") すると ubound() = -1になってしまうため除外する
            Dim a() As String
            a = Split(con, ";")
            Select Case a(0)
            Case "":    ' MDB
            Case "ODBC":    ' ODBC
                Dim fff As Boolean
                fff = False
                Dim b() As String
                Dim i As Integer
                Dim fUID As Boolean
                fUID = True
                Dim fPWD As Boolean
                fPWD = True
                For i = 1 To UBound(a)
                    If a(i) <> "" Then
                        b = Split(a(i), "=")
                        Select Case b(0)
                            Case "DATABASE":  '特に何もしない
                            Case "UID":
                                fUID = False
                                If b(1) <> UID Then
                                    Debug.Print "SERVER='" & b(1) & "' を 'SERVER=" & SERVER_IP_ADR & "'に更新します。"
                                    fUID = True
                                    b(1) = UID
                                    a(i) = Join(b, "=")
                                End If
                            Case "PWD":
                                fPWD = False
                                If b(1) <> PWD Then
                                    Debug.Print "SERVER='" & b(1) & "' を 'SERVER=" & SERVER_IP_ADR & "'に更新します。"
                                    fPWD = True
                                    b(1) = PWD
                                    a(i) = Join(b, "=")
                                End If
                            Case "DSN":     '特に何もしない
                            Case "OPTION":  '特に何もしない
                            Case "PORT":    '特に何もしない
                            Case "SERVER":
                                If b(1) <> SERVER_IP_ADR Then
                                    Debug.Print "SERVER='" & b(1) & "' を 'SERVER=" & SERVER_IP_ADR & "'に更新します。"
                                    fff = True
                                    b(1) = SERVER_IP_ADR
                                    a(i) = Join(b, "=")
                                End If
                            Case "CHARSET":  '特に何もしない
                            Case Else:       '特に何もしない
                        End Select
                    End If
                Next
                ' UIDが未設定の場合、追記する
                If fUID Then
                    ReDim Preserve a(UBound(a) + 1)
                    a(UBound(a)) = "UID=" & UID
                    fff = True
                End If
                ' PWDが未設定の場合、追記する
                If fPWD Then
                    ReDim Preserve a(UBound(a) + 1)
                    a(UBound(a)) = "PWD=" & PWD
                    fff = True
                End If
                ' 何か変更されていた場合は、接続テキストを再構成する
                If fff Then
                    con = Join(a, ";")
                    tbldef.Connect = con
                    tbldef.RefreshLink
                    Debug.Print "設定を更新しました。" & vbCrLf & "'" & con & "'"
                End If
            End Select
        End If
    End If
  Next tdf
End Sub

どうやらリンクテーブルには

  • TableDefAttributeEnum.dbAttachedODBC
    MS SQLServer など、ODBC を使うリンクテーブル
  • TableDefAttributeEnum.dbAttachedTable
    MS Access などの非ODBCのリンクテーブル

の2種類があるらしいけど、ググってもどんな動作環境なのかは判らなかったので、

  • Enumクラスを指定しないと遺憾な場合
  • Enumクラスがそもそも無い場合

がありそうで、この辺は実際に動かして調整するしか無さそうだ。

それとPORTなんかが違う場合もありそうだ。

※デフォは学習用、xxxxはデバッグ用、yyyyはテスト用、zzzzは実機とかね。

他のデータベースの場合は、コードページの設定やオプション等も違うだろうし、データベース・ディクショナリ名とか実行時ロール名とか独特な何かを指定しないとダメな場合もあるだろう。

そんな風にDATABASEが違うだけでテキストが全く異なる場合には最初のコードの方が良さそうだから、

MS-ACCESSのVBAのBASファイルには両方を置いておいた方が安心かな。



[Windows11]ブラックアウト

例のゲーム画面が真っ暗になる中国ブラゲーのPC版を遊んでいるうちに

ふと気が付くと、デスクトップのショートカットが全て消えていた。

観えるのは初期設定のままの壁紙だけ。

画面の下ではアプリ、通知、時計その他一切のアイコンが空っぽになったタスクバーが点滅していた。

サインアウト。

ログイン。

壁紙そして空っぽのタクスバーが点滅。

何も変化なし。

ALT+CTRL+DELキー操作でタスクモニタを起動すると

Expolore.exeが出たり消えたりしてうっとおしい。

スクロールしていくとその下に大量の通信(VHOST)の形跡が続く。

グラフに切り替え、動きを眺めると通信だけがいつまでも繰り返されている。

ログイン直後にタスクバーから通知か何かを表示するために通信している最中にExplore.exeがクラッシュ&リブートしている様な感じ。

どうやら、またログイン直後のトラブルにしハマった様だ。

シャットダウン。

ログインすると画面は隅から隅まで真っ暗になった。

使えるのはマウスとALT+CTRL+DELのキー操作だけ。

再起動前は壁紙が映っていたがVRAMに残っていた残骸だったのかもしれない。

空っぽのタスクバーすらもVRAMに残っていた残骸だったのかもしれない。

とりあえずタスクバーであるexplore.exeが何か表示しようとしたらクラッシュ。

タクスマネージャーが何も考えず消えたexplore.exeを起動しなおしている。

そういうことだ。

もう一度再起動しログインしても画面は真っ暗。

(と、ここまで書いたらWindowsUpdateが勝手に再起動した。

こうならないようになっているハズなんだが・・・

まだ不調なのかな?)

USBの回復ドライブを挿して起動するもSSDから起動してしまう。

再起動。

DELキーを押し続けUEFIに切り替える。

ブート画面からUSBメモリを指定して起動。

ログイン。

すると、普段どおりに戻った。

WindowsUpdateを行うと

  • (KB5010414)
  • (KB5010474)と.Net4.8

の更新が入った。

KB5010474は、4.8 で導入された IRawElementProviderSimple オブジェクトのリーク.NET Frameworkします。だそうだ。

注記には

NET ライブラリ– TLS 1.3 のネゴシエート時にクライアント証明書が使用されている場合に Ssl ネゴシエーションが無期限にハングする可能性がある問題に対応します。 変更の再ネゴシエーション (PostHandshakeAuthentiction) が失敗する前に、SslStream または HttpWebRequest でタイムアウトが観察されます。

と書いてあった。

まさにそんな感じになっていた。

多分、治ったんだろう。

とは云え気になるので回復ドライブを更新しようとしたら16GB以上を要求された。

(前もそうだったのかな?)

で、作成中にさっきの強制再起動。

もう一回作り直し。

16GB以上推奨だからUSB2タイプのメモリではコピー時間が長すぎる。

USB2の転送レートは480Mbpsだから、理論値でも

16[GB] * (480[Mbps]/1000[G/M]/10(bit/byte))≒333秒≒6分

ファイルがいっぱいあれば、ファイルを管理する情報の書き換えもいっぱい発生するので1時間ぐらいかかりそうだ。

本当に1時間ほどかかってしまった後・・・

8GBしか使ってないw

山ほどファイルがあったのかな?

ファイルの総数:
             226 個のファイル       7,845,198,033 バイト
             271 個のディレクトリ  25,963,888,640 バイトの空き領域

ファイル数もそんなに多くない。

USBメモリが熱ダレ(過熱防止)してたのか?

イミフに長~く待たされてる間に

F8でセーフティモードで起動する設定は無効になってた様なので有効にしておいた。

> bcdedit  /set {default} bootmenupolicy legacy

戻す時は最後のlegacyをstandardに差し替える。

例のゲームのタチの悪さが増した様な気がするなぁ。



[Windows11] ペイントの場所

WinSCPで画像をイジろうとしたらmspaint.exeが行方不明になっていた。

Windows10までは、

C:\Windows\System32\mspaint.exe

だったハズだけど、Windows11になったら、見当たらない。

以前はアイコンを右クリック&プロパティでインストール先が判ったけど、

Windows11では徹底的にその辺は隠蔽する方針らしく無理なので、コマンドラインからwhereコマンドでファイル検索してみる。

C:\>where /R C:\ mspaint.exe
C:\Users\${ユーザ名}\AppData\Local\Microsoft\WindowsApps\mspaint.exe
C:\Users\${ユーザ名}\AppData\Local\Microsoft\WindowsApps\Microsoft.Paint_*************\mspaint.exe
C:\Windows\servicing\LCU\Package_for_RollupFix~****************~*****~~*****.***.*.*\amd64_microsoft-windows-mspaint_****************_**.*.*****.**_none_****************\*\mspaint.exe

といくつか候補が出てきたけど、最初のものが短くてよさそう。他は乱数っぽい文字列が沢山付いてて流用が難しそう。

C:\Users\${ユーザ名}\AppData\Localは、SETコマンドで見つけた環境変数LOCALAPPDATAで代替すれば

%LOCALAPPDATA%\Microsoft\WindowsApps\mspaint.exe

になる。

コマンドラインからmspaint.exeダケでも実行できるから、

%LOCALAPPDATA%\Microsoft\WindowsApps

がパスに追加されてるのかな?

C:\WINDOWS\system32
C:\WINDOWS
C:\WINDOWS\System32\Wbem
C:\WINDOWS\System32\WindowsPowerShell\v1.0\
C:\WINDOWS\System32\OpenSSH\
C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common
C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR
C:\Program Files\Git\cmd
C:\Program Files\dotnet\
C:\PROGRA~1\JPKI
C:\Program Files (x86)\dotnet\
C:\WINDOWS\system32
C:\WINDOWS
C:\WINDOWS\System32\Wbem
C:\WINDOWS\System32\WindowsPowerShell\v1.0\
C:\WINDOWS\System32\OpenSSH\
C:\Program Files\nodejs\
C:\Users\${ユーザ名}\AppData\Local\Microsoft\WindowsApps
C:\Users\${ユーザ名}\AppData\Local\Programs\Microsoft VS Code\bin
C:\Users\${ユーザ名}\AppData\Roaming\npm
C:\Users\${ユーザ名}\.dotnet\tools

色々インストしたから色々とパスに追加され過ぎな気がする。

WinSCPの環境設定のエディタに追加してあったMspaintの外部エディタの設定を

"%LOCALAPPDATA%\Microsoft\WindowsApps\mspaint.exe" !.!

に変えてみると、

また画像を直接編集できるようになった。

しかし大型アップデートが来たら、また編集できなくなるかもしれない。

あれ?WordPressで文字単位で色が変えられない!

と思ったら「A テキスト色」が「A ハイライト」に変わったダケだった。

背景色もつけられるから便利だけど、文字の下に色指定のパレットが出てくるのでパレットが切れ気味。



[三国英雄の夜明け]いまいち

12 million power

戦力は順調に増強中。

しかし周囲も順調に増強中につき、1月はずーっと勢力内29位、ワールド内85位のままピクリとも動かず。

但し、シーズンイベントの職業限定の限定挑戦の為に装備や副将を調整している時は戦力が200万くらい下がってしまうこともままある。主に文民が一強状態のせい。貂蝉を200万まで上げるのに手間取り、馬超、趙雲の強化が出遅れ、小喬、甄姫以下はほとんど放置気味だったので今になって強化中。

大した戦力でもないのに慢性的な食料不足で9英雄の同時運用は難しい。部隊数が必要な時は副将を外して兵力を減らしていかないと続かない。

今は4兵舎に兵士48万づつを待機させられるが兵士1人に付き食料8.4が必要なので、最大兵士192万を作成するには食料1,612万8千が必要で甕陽戦の後にはそれがほぼ空っぽになってしまうのが食糧難の主な原因。

空っぽの兵舎の様子

対戦時にパワーアップする幕府要員の強化はもっと遅れてて、特に逸材、弓兵が66%と低い、弓兵は70%に上げたけど、逸材はそのまま。

資材と黄金を放り込む兵舎の技術は歩兵技術だけランク80に他もボチモチ上げたい。

砂盤演技は30章の序盤で 馬超、趙雲 が戦力200万未満なせいか負け続けてて、英雄の装甲の強化が止まってる。

魂玉は全6品質、八宝獣霊は全紫色を目標に強化中だけど日々の黄金探索と朝廷の密使クエストを潰していくしかないから地味。戦力が弱いから密使で「プレイヤー部隊の撃破」が出ると影響が大きすぎ。今日も2つ目のお題が4/7と未了になりそう。

・・・

パラメータ・・・

多すぎ。

ps.2022/2/2

貿易がうまくいかず、特産品の集まりが一番悪く、

李代桃僵 あと一つ
火事場泥棒はさっぱり進まない

そんな訳で、趙雲に定計を付くのはまだまだ先。

戦力1250万

戦力増強はあまり進んでいない。

ps.2022/03/13

戦力1410万
とてもゆっくりな進捗の定計

やっていること。

  • 領地の官邸の幕府のレベル上げ(今レベル35前後、対戦時の強化率は82~86%)
    • 珍宝商店で文書を買うのがメインなので黄金の消耗が激しい
      • 採掘の黄金狙いだけでは全く足りないので、建設で賄賂ボタンを押下する様になった。
  • 幕府出陣キャラのSクラス維持
    • 基礎パラメータの補助スキルアップで評価が上がりやすいがカードは出にくい
  • 兵舎の技術ランクアップ(今ランク74~88)
    • 資源(木材、金属)の消耗より失敗時の黄金の消耗が激しい
  • ミニゲーム(竜金探索)で得る魂玉の品質アップ(今の最高品質は7)
    • 竜金探索の採掘レベルがMax40になったのでペースは一定
  • 獣霊のレベルアップ
    • LV20までは獣霊元気、それ以上は獣霊元神を消費してレベルアップ
    • アイテムは朝廷の密旨のお題次第(ランダム)
  • 基礎パラメータ(武力、知力、魅力、統率)アップ
    • 補助スキル(勇武、才学、修養、兵法)のアップ
      • 訪問や狩場を補助スキルが出るキャラ(甘寧、筍或、法正、呂蒙)に集中
        • 毎日の任務で拝帳(訪問時に消耗)や角笛(狩場で消耗)を得る
          • ランダムなのでコンスタントに得るのは難しい
  • 定計のスキルの入手と★アップ
    • 貿易でアイテム交換して入手
      • 相手が欲しがるアイテムは大抵領地外の港の名物
    • 4★までアップすると、キャラに定計スキルを付加できる
      • 4★にアップ直前になると大枚の黄金を要求されることが多い

そんな感じで毎日、黄金千枚と銀両600万を使い込んでいる。

ps.2022.4.9

戦力増強は停滞気味。

戦力1500万

引き続き「砂盤演義 第30章 檮杌と遭遇」のため、2番手3番手を優先。

ps.2022/6/19

昨日、FORTEを買ったらCAMELのクーポンが出たけど品切れだったので今日引き換えに行ってFORTEを買い忘れたスラです。

このゲーム内でもクーポンが出ます。

クーポン(タダ券)続出中

チャットの見た感じでは無料でクーポン7枚をゲットしたかの様に観えますが、

クーポンを引き当てるまで黄金500枚(5回分)を消費してるので実質59%、6割引きでした。

なので、見た目ほど美味しい訳ではありません。

今の勢力の進捗は・・・

主に、

  • 八門獣霊狙いで、密使シーズンイベント
  • 魂玉狙いで、竜金探索
  • 幕府文書狙いで、珍宝商店

がメインとなっています。

マップでの無謀な振る舞いは主に密使の悪だくみかシーズンイベントの限定挑戦のポイント稼ぎの勢。

密使とシーズンイベントの攻略は、兵士の消耗が著しく食糧難が続き黄金の備蓄も厳しいですが、戦力強化のメインなのでサボれません。年度報酬で戦力消耗も倍率に加算されるので建設も頑張り年度報酬の倍率を8~9倍にしたい。しかし、8倍で4000枚越える時もあれば9倍で3000枚を下回る時もあるのが悩ましい。

PC対戦で影響が大きい幕府レベルを上げる為に必要なアイテムはレベルに応じて増える。しかも幕府に所属する英雄の戦力もレベル成りに引き上げないと幕府の応援効果が上昇しない。その一方で英雄の戦力(スキル)レベルを上げる度に消費するカード数や銀銭も増えるから、金欠まっしぐらです。

なのに、

自戦力全体で100万UPする頃には、課金勢は単騎で100万UPしてたみたいな感じで戦力差が拡大している様にしか思えない状況w



[JavaScript]Promise

Promiseオブジェクトの作り方には大きく2つある。

  1. new Promise( )
  2. Promise.resolve( )

new Promise( ) は、新たにオブジェクトを作るけど、Promise.resolve( ) の方はstaticなPromiseオブジェクトを使いまわししているだろう。

class Promise {
    constractor () {
    ・・・
    }
    static staticResolve = new Promise().resolve(undefined);
    resolve() {
      if (typeof(this) === "undefined") {
        return Promise.staticResolve;
      ・・・
    }
}

と考えると、Promise.resolve( ) はpromise状態が履行 (fulfilled)に確定しているところから始まるから

Promise.resolve().then( (a)=>{
    /* なんたら */ 
}).then( (b)=>{
   /* かんたら */
}).then( (c)=>{
   /* それから */
}).then( (d)=>{
   /* こうして */
}).then( (e)=>{
   /* こうなった */
}).catch((e)=>{
   /* どうして、そうなった? */
});

と書いても、「なんたら」部の最後まで進めば、直ぐに「かんたら」に突入し、ストレートに「こうなった」まで進んで一気に進むので、完全な同期処理である。

単に、try…catch…finally なんて美しくないという人向けでしかない。

ただ、ドコが壊れているのかイミフなコードを切り分けた状況のエビデンスを作る時には非常に便利である。

実際には<% try { %><% throw(“ココか?”); %> <%} catch(e) {consol.log(e); } %>式に

プローブ針を垂らすけど、エビデンスとしては判りにくいからね。

強いて言えば、「なんたら」「かんたら」「それから」「こうして」「こうなった」の全てにawaitで強制的にワーカースレッドを停止させる箇所が無いと意味が無いのだ。

そんな訳で、非同期で処理したいものを1つづつ、「非同期化」するしかないが、そう難しくはない。

class hoge {
    // 非同期型 同期型と同じ数だけ作成する
    asyncFunc(params) {
    return new Promise((resolve, reject) => {
        try {
            let result = syncFunc(params);
            resolve(result);
        } catch(e) {
            reject(e);
        }
    });
    }
    // 同期型
    syncFunc(params) {
        return foo;
    }
    ・・・ 
}

と非同期呼び出し口を用意するだけ、

しかし、async接頭子のメソッドがいっぱい増えるのが嫌なら

class hoge {
    // 非同期型 1つだけ作って使いまわし。※毎回 new Promise しなくていいのが嬉しい。
    asyncCall(syncFunc,params) {
    return new Promise((resolve, reject) => {
        try {
            let result = syncFunc(params);
            resolve(result);
        } catch(e) {
            reject(e);
        }
    });
    }
    // 同期型
    syncFunc1(params) {
        return foo;
    }
    ・・・ 
    // 同期型
    syncFuncN(params) {
        return foo;
    }
}

と、非同期化メソッドを用意しておくといいだろう。

引き渡すパラメータはthenチェインする前に確定してしまうから、後々トラブりそうなのが難点で、

しかも、下のコードを見て判るように、各処理に引き渡すパラメータは事前に用意することになるけど

paramを変数宣言しておいて使用すれば、各処理が動き出す前に調整は可能だし、何よりデバッグが楽だ。

ちゃんとデバッグが済んでから、試作型に実処理を埋め込めばいいだろう。

とりあえず、

// 非同期処理を準備する
let param1;
let param2;
let param3;
let param4;
let param5;
let promFunc1 = asyncFunc1(param1);
let promFunc2 = asyncFunc2(param2);
let promFunc3 = asyncFunc3(param3);
let promFunc4 = asyncFunc4(param4);
let promFunc5 = asyncFunc5(param5);
//
promFunc1.then(()=>{              /* なんたら param2を最新化 */ 
    promFunc2.then(()=>{          /* かんたら param3を最新化 */
      promFunc3.then(()=>{        /* それから param4を最新化 */
        promFunc4().then(()=>{    /* こうして param5を最新化 */
          promFunc5().then(()=>{  /* こうなった */
});});});});}).catch((e)=>{      /* どうして、そうなった? */
});

とコードすることで完全に非同期になると思う。

でも、thenチェインって云われているものは普通コレではない。

//同期っぽい書いてある非同期処理 ※パラメータは暗黙の了解で繋がっている
promFunc1(a)       /* なんたら 暗黙のparam2を最新化 */
.then(promFunc2)     /* かんたら 暗黙のparam3を最新化 */
.then(promFunc3)     /* それから 暗黙のparam4を最新化 */
.then(promFunc4)     /* こうして 暗黙のparam5を最新化 */
.then(promFunc5)     /* こうなった */
.catch((e)=>{
   /* どうして、そうなった? */
});

あるいは

//同期っぽく書いてある非同期処理
promFunc1(a).then( (b)=>{        /* なんたら */    
    let b = await promFunc2(b);  /* かんたら */
    return b;
}).then( (b)=>{   
    let c = await promFunc3(b);  /* それから */
    return c;
}).then( (c)=>{
    let d = await promFunc4(c);  /* こうして */
    return d;
}).then( (d)=>{
    let e = await promFunc5(d);   /* こうなった */
    return e;
}).catch((e)=>{
   /* どうして、そうなった? */
});

のハズだ。この書き方の最大の問題点はawaitが本当に動作してくれるかどうかだ。

awaitはドコかのPromiseオブジェクトが「履行 (fulfilled): 処理が成功して完了」になるのを待つせいで、

ワーカースレッド内で同時に使用できるのはたったの1回だけ。

ネストできないから、上のコードを参照する処理や各async内でawaitしてるとawaitした途端にエラってしまう。

ので、

awaitを使ってエレガントなコードに酔いしれることができるのは「お一人様」つまり「貴族様仕様」なのだ。

つまり、awaitのaは、「とあるドコかの何か」ではなく「お一人様」の意味なのだ。

※試験には出ないけど重要です。

流石、文化が違うよね。ボクらはネストしてるthenチェーンか綺麗になおしたらデバッグ困難なコードに立ち向かう事になる。

だから、「ボタンをクリック」した直後に一回くらいに限定した方がいい。

サーバーと通信する際に使うと、画面隅に通知機能を搭載した途端にケンカ沙汰になってしまう。

というのが、ググった結果から得られた感想。

本当にこうなっているのかコードしてみると予想が結構ハズれているような気がする。

何せ、数年経てば、仕様書上は全く変わらないのに、全く違う動作になっている世界だけに。

実際、new Promiseのコールバックは今では即実行されてしまうので、

Promiseのthenの設定を全て終えメインスレッドが完了してから動いてくれると思ったら大間違い。

Promise.thenのコードを見つけると即実行するので、全く非同期ではない。

正確には、new Promiseのコールバックの中だけ、resolveかrejectを呼ぶまで非同期になってるダケで

Promise.resolveは、非同期に見える振りをしているだけ。

非同期にしたいなら

//同期っぽい書いてある非同期処理 ※パラメータは暗黙の了解で繋がっている
promFunc1(a)       /* なんたら 暗黙のparam2を最新化 */
.then(promFunc2)     /* かんたら 暗黙のparam3を最新化 */
.then(promFunc3)     /* それから 暗黙のparam4を最新化 */
.then(promFunc4)     /* こうして 暗黙のparam5を最新化 */
.then(promFunc5)     /* こうなった */
.catch((e)=>{
   /* どうして、そうなった? */
});

の書き方以外は意味が無い。

正解を引き当てたると後々面倒なことになるのはいつもの事。(大笑

「非同期な処理」≒「後でやって欲しい処理」を書くには、

各promFuncNの中でsetTimeoutしてresolveする以外に方法は無い。

ps.2021/12/13

サンプル追加。

thenチェインする処理を関数化すると、returnした値が引き継がれないのは痛いね。

thenチェインでreturnした値は、thisにぶら下げて引き渡しているんだろう。

1つの関数の中で閉じ籠って then チェイン して

うまく動いてるけど、ゴチャゴチャしているので

リファクタリングして美しいthenチェインにすると・・・

壊れます。(痛すぎ



[JavaScript]finallyが壊れている様な気がする

イミフなスタックオーバーフローに悩まされた。

static dataDumpNest = [];
static DATADUMPNEXT_MAX = 100;
static dataDump(objectName, obj, pOptions) {
  try {
    ・・・
    Helper.dataDumpNest.push(obj);
    rc = true;
    ・・・
    return true;
    ・・・
    //  再帰呼び出し時はtrueを返す
    if (Helper.dataDumpNest.length > 1) {
      return true;
    }
    //  それ以外は result を結合し返す
    return Helper.result.join("\n");
  } catch (e) {
    throw e;
  } finally {
    Helper.dataDumpNest.pop();
  }
}

finallyで無条件でpopしているので、

重複チェックで弾かれてpushしてない時に

無駄にjoinしてしまうのが気になり

執拗にF10でトレースしていると・・・

finallyブロックの終わりで呼び出し元のメソッドに戻るべきところが、

  1. ソース画面が何行か戻ってしまう。
  2. スタックトレースが妙に長くなっていた。

という摩訶不可解な現象にぶち当たった。

どうやら、return文無しで、finallyブロックの末尾にぶち当たると、ヤバイ事が起きている。

1万個の配列を何度もjoinさせ、しかも結果は捨てているのでブチ切れさせてしまったかもね。(大笑

普通、ドコかのreturn文の後に処理するハズのfinally句なのに。

延々と待たされた挙句にスタックオーバーフローになるソースを

finally句でtryの外の変数rcをreturnする様にしてみた。

static dataDumpNest = [];
static DATADUMPNEXT_MAX = 100;
static dataDump(objectName, obj, pOptions) {
  let rc = false;
  try {
    ・・・
    Helper.dataDumpNest.push(obj);
    rc = true;
    ・・・
    rc = true;
    return rc;
    ・・・
    //  再帰呼び出し時はtrueを返す
    if (Helper.dataDumpNest.length > 1) {
      rc = true;
      return rc;
    }
    //  それ以外は result を結合し返す
    rc = Helper.result.join("\n");
    return rc;
  } catch (e) {
    throw e;
  } finally {
  if (rc != false) {
    Helper.dataDumpNest.pop();
  }
    return rc;
  }
}

と変えたら、即終わったった

setTimeoutでワーカースレッドっぽい状態なんで、

finallyが、Promiseと勘違いしてスタックを遡ってみると配列がいっぱい積んであるので

Array[ Array[1], Array[2] ] あたりが、

new Promise((resolve, reject) {
・・・
}

に、そっくりだったのかもしれない。

しかし、違うと気が付いて、throw new Error(“Don’t mind.”);

して、普通のfinally になるつもりが、ソコのfinallyでまた躓いて、無限ループしてそう。

でも、そのうち治るでしょ?

やっと、本題の文法解析に戻れそう。

ん?三国英雄たちの夜明けがフリーズしやすいのは

もしやコレなのか?



[Visual Studio Code]「フォルダを指定して検索」が動かない

JavaScriptは型が無い。とは云え、全く無視するのは辛いので。マメにJSDocなコメントを入れている。

VisualStudioCodeでは関数や変数の名前をクリックして2回(Ctl+Alt+D)すると、テンプレが書き込まれるので簡単だ。

しかし、コード中に型チェックすると typeof を羅列するより switch case で書きたい時もある。

そんな時はObject.prototype.toString()が、

[Object ${ObjectTypeName}]の様な文字列を返してくれるので、 switch case 風に処理できる。

/**
 * オブジェクトの型名を調べる
 *
 * @param {Any} obj   オブジェクト
 * @return {string}      型名
 */
const getTypeName= (obj) => {
  if (typeof (obj) === "undefined") {
    return "undefined";
  }
  var toString = Object.prototype.toString;
  // [object typeName] のハズなので、typeName部分を抽出してみる
  let typeName = toString.call(obj).match(/^\[\w+\s+(\w+)\]$/);
  return typeName[1];
}

各オブジェクトのtoStringメソッドは、一番OverWriteしまくっているメソッドなので、

ココでは確実な動作を狙って、Object.prototype. toString をCall呼び出しで参照してみた。

でも名前がgetTypeNameなのがイマイチなんでObjectTypeNameにリファクタリングしたら、

他のファイルでUndefinedになってた。

JavScriptだから仕方が無いけど。

置換機能で書き換えようとしたら・・・

(サッパリ

検索すらしない。

ググっても、それっぽい記事は無い。

試しに「検索エディタ」を開いてみた。

赤線で囲んだアイコンをクリック

するとちゃんと検索しだした。

MSCodeを再起動しても、結果は良好。

つまり、裏側でこっそり設定ファイルが出来た様だ。

※この手の自動設定の不具合は、インストーラのテスト同様に見つけにくいものだ。

昔の映画で「xx製は叩けば治る!」というセリフがあったけど、MSCodeも同じらしい。

初回ダメなら「新規xx」とかをぶったたけば、初期設定ができるかも。

しかし、今後はどうなるか予断を許さない。(と思う。



[javascript]パーサ・コンビネータって

Java パーサコンビネータ 超入門というのを見つけた。

使い方を説明してくれるのでとても助かるけど、

JavaScriptでパーサコンビネータのコンセプトを理解する(「正規表現だけに頼ってはいけない」の続き)

の方がパーサ・コンビネータの仕組みを理解でき、且つ、使わなくなったけどJavascriptの便利な手法を思い出させてくれた。

function 関数(...) {
  return [1,2,3,4, ...];
}

と配列等で容易に複数の値を変えすことができるし、そんな関数を

let [a, b, c, d, ...] = 関数(...)

と呼び出すと、すんなり配列中の a, b, c, d, … に値を入れてくれるトコが地味に嬉しい。

いつのまにかいっぱい返す事になる未来が待っていそうな気がするから new classを返すことが多いけど。

また

function token(str) {
  var len = str.length;
  return function(target, position) {
    if (target.substr(position, len) === str) {
      return [true, str, position + len];
    } else {
      return [false, null, position];
    }
  };
}

の様にreturn function {…} することで、関数ジェネレータを簡易に記述できるのは便利、

但し、呼び出す側が、

token('foobar')('foobar', 0); // => [true, 'foobar', 6]を返す

な感じになってしまうとワークスペース内のファイルの関数を全部チェックする開発環境ではなく、

sakuraエディタで チョコ チョコ叩いている場合は、【見た目文法エラー!】なのが難点。

やはり、

const func = token('foobar');
func('foobar', 0); // => [true, 'foobar', 6]を返す

と書いて関数が戻ってくる雰囲気を醸し出した方が無難な気がする。

many(token('hoge'))('hogehoge', 0); // => [true, ['hoge', 'hoge'], 8] を返す

も、token(‘hoge’)部分がmanyな場合は、あーもーな感じになりそうなんで

let parsers = [];
parsers.push(token('hoge1'));
...
parsers.push(token('hogeN'));
let text = 'hoge1hoge2...hogeN';
let myParser =seq(parsers);
myParser(text, 0); // => [true, ['hoge1', ['hoge2', ...['hogeN']...]]], 8] を返す

と1行がいっぱい膨れ上がってしまいそう。

てか、実際に’hoge1hoge2’と直書きすることは滅多に無いから

もっと、もっと膨れ上がる。

先の記事のソースは「あくまで説明しやすく表記」したものなのは明白だけど、

テストコードってこんな風に書いてたりするよね?。(笑

ps.

先の「理解する」のページのコードをまとめてみた。

簡易のテストケースもパーサーの種類ごとに1つダケ書いてみたら、結構長くなってしまった。

作りかけだからFalseしまくってるのはいいとして

Errorオブジェクトから発生原因を判りやすくしてほしいなぁ。

字句解析とか構文解析は、「,」1つの修正だけでも

見えないところがトンデモない結果になり果ててしまいがちなので、テストはガチでやった方がいいからね。

ソースの説明

  • index.html   テスト画面
  • parcom.js パーサの記事からコードをコピペしてチョコっと加工したもの
  • sample.js パーサのテストパターンを起動し、結果を表示するスクリプト
  • testparcom.js  パーサのテストパターン
  • testbase.js    テストパターンを多少楽にするための testparcom.js の基底クラス
  • libs.js オブジェクトのダンプやErrorオブジェクトから情報を引き出したりするD級パーツ群
  • sample.css テスト画面用CSS

※ん-。まだまだな感じがする。

そもそも、各パーサはサブクラス化した方が良いんじゃにのかな?

更にパーサ コンテナ クラスで括った方が・・・。

アカン。どんどん膨れ上がる一方だ。

ps.2021/12/3

BNFっぽい文法”Call = [ Call ] procedureName [ (argumentList) ] ”と書かれたテキストを

解析するコードを作成中。やっと単純な文法をクリアしたものの、2つ目の文法に進まない。

デバッグでハマりすぎ長いログをスクロールするのが大変。

  • 機能を大幅改善
    • ログ末尾のstartとendを検出しリストタグ(UL,OL,LIとか)で手軽にインデント
      • 以前見つけたTreeViewのコードは流用できた
      • FIXTED:cssは全部見直しするハメになった
      • TODO:try…catch…filannyで確実にendを出力させないと右雪崩が発生する
    • TreeView風に[+][ーで折りたためる
      • TODO: +、ー小さすぎた!
      • TODO: endの行に+を配置するのは良くない。
    • trueやfalseを色分け
      • FIXED: あるあるな後付けデグレードと既存バグ発覚
        • objDumpで処理済みのテキストを再度objDumpしてが気が付かなかった
        • replaceで単語にタグ付けする場合は二度漬け禁止のハズが・・・
          • <span> ⇒ &lt;span> 的な出来事
    • FOXED:ログが雪だまり式に増えていた
      • Case2にCase1のログが
      • Case3にCase2とCase1のログが
      • 以下、増殖
        • 各テストCaseでログクリアする
    • TODO:typeof xxx === “undefined”はしてるけど、xxx === null チェックが甘い

コードの見直しが多すぎて、メソッド単体テストが壊滅状態。

修正してみたら、半壊状態。←いまこのへん。

全文法(287行中7行)をクリアするのはまだまだ先の話。

本当に終わりが見えないなぁ(大笑

            //      syntax = [ rule ]  ;
            setSyntax("syntax", many(refSyntax("defsymbol")));
            // defsymbol: { "\n" } IDENTIFIER "=" rule
            //###setSyntax("defsymbol", seq(optEol,  identifire,  asign,  refSyntax("rule")));
            setSyntax("defsymbol", seq(optEolWs, identifire, asign, refSyntax("rule")));
            // rule: list { "|" list }
            setSyntax("rule", seq(refSyntax("list"), repeat(seq(vl, refSyntax("list")))));
            // list: { seq | block | repeat | option }  "\n" { notes }
            // TODO: repeat(...)の中にoption系が挟まると無限ループするので、何か対策案を考える
            setSyntax("list", seq(repeat(choice(refSyntax("seqList"), refSyntax("block"), refSyntax("repeat"), refSyntax("option"))), eol, opt(refSyntax("notes"))));
            // seqList = seq { seqList }
            setSyntax("seqList", seq(refSyntax("seq"), repeat(seq(/*ws,*/ refSyntax("seqList")))));
            // seq = (regExp | IDENTIFIER | STRING | INTEGER | , )
            setSyntax("seq", choice(reExFmt, identifire, string, number, comma));
            // block: "(" rule ")"
            setSyntax("block", seq(lpr, refSyntax("rule"), rpr));
            // repeat: "{" rule "}"
            setSyntax("repeat", seq(lbr, refSyntax("rule"), rbr));
            // option: "[" rule "]"
            setSyntax("option", seq(lbk, refSyntax("rule"), rbk));
            // notes: "#Notes" "Syntax" eol rule "}}" "#Notes" "End" eol
            setSyntax("notes", seq(notes, ws, syntax, eol, refSyntax("syntax"), notes, ws, end, eol));

見直すのはコレだけなのに。

  • ログの大半がホワイトスペースだから何とかしたい
    • パーサから空白を読み飛ばす字句解析結果のを参照する?
    • パーサで作成したtoken(文字と正規表現)を適切な順に並べる
      • 勝手に空白を読み飛ばすので楽なハズ

クリアしたら、

  • 残りのテストを・・・
  • パーサコンテナを作る
  • 各パーサをサブクラス化
  • コードを読む部分を作る
  • 何かの言語に変換する部分を作る

先はまだまだ長い。

ps.2021/12/6

サブクラス化したもののソースは1000行を越えた。何か間違えている様だ。

サブクラス化 の過程で

  • リテラルにはプロパティが付けられない
    • String(“hohegoge”)ではダメ。
    • new String(“hohegoge”) でOK.
    • その辺は throw Error(“hogehoge”);も同じなんだろう。
  • RegExpにgオプションを付けlastIndexプロパティに位置を指定しても文字列の最初から検索する
    • 一度素振り(検索)させ自力でlastIndexを初期化しないとダメ
    • gは空振り(null)すると、とても機嫌が悪い。
  • RegExpのinputプロパティにオリジナルの文字列のコピーが作られる
    • メモリが心配
  • Refer.call を使ってみた
    • 横に長くなる
      • 伸びた部分だけ見れば良いので見やすいと思う人もいるかも
      • 元に戻す
  • super.メソッドみたいな呼び方ができる
    • なんちゃってオーバーライド風に書いてみると、無限ループする

18行1列まで読めた。 行末の _ 結合演算子がムズイ。

ps.2021/12/7

事前にザックリと空白、改行、その他でトークン化したついでにコメント文を空白化。後は _ かな。

全文からワード単位で字句解析するようになってブラウザの動作は軽くなった気がする。

ワード単位で取り出す時に、文末が” _”なら、次の改行を無視すればいいのかな?

ps.2021/12/8

手直しをしたら余計悪化。

0回ループOKなRepeatがネストしたら無限ループしてしまうので、Sequenceで評価がTrueでもpositionが進まない時は、評価をFalseにしたけど、まだループ。

仕方が無いので、catch exceptionで強制停止。300万行とか凄い行数になってたので、1000行までに制限。

やっと途中経過が可視化できた。ログのネストを深く掘り下げると

ParserInfo (ParserInfo)で、字句解析まで見れるけど。文法解析まで見れない。

ps.2021/12/9

手直し。 ダンプの仕方を見直し。

もう、本題を忘れてダンプに力が入る。

ps.2021/12/11

手直。 ダンプの仕方を見直し。  TreeView.markingをPromiseってみた。設定できてるけど、処理が終わったと返ってこない。

ps.2021/12/13

関数のダンプが修正漏れでエラっていたを訂正。



Windows11 更新あるいはお試し

1.Windows Update

「準備ができたしたーし」

かかか、噛みました的な。

2.手動アップグレード リンク先のページから以下を選択

(1)Windows 11 インストール アシスタント

(2)Windows 11 のインストール メディアを作成する

(3)Windows 11 ディスク イメージ (ISO) をダウンロードする

(4)その他のダウンロード 企業向け

3.お試し方法

Hyper-Vで、手軽にお試しできる。

「新規」より楽そう
ISOファイルダウンロードとかは勝手にやってくれる
できた
何だこれは・・・

とりあえず

を押してみる
もう何がなんだが

やっぱりPCで動かしたいなら




top